core: remove vendorized py37 isoformat code
This commit is contained in:
parent
03dd1271f4
commit
7493770d4d
8 changed files with 7 additions and 146 deletions
|
@ -358,12 +358,11 @@ def isoparse(s: str) -> tzdatetime:
|
|||
"""
|
||||
Parses timestamps formatted like 2020-05-01T10:32:02.925961Z
|
||||
"""
|
||||
from .compat import fromisoformat
|
||||
# TODO could use dateutil? but it's quite slow as far as I remember..
|
||||
# TODO support non-utc.. somehow?
|
||||
assert s.endswith('Z'), s
|
||||
s = s[:-1] + '+00:00'
|
||||
return fromisoformat(s)
|
||||
return datetime.fromisoformat(s)
|
||||
|
||||
from .compat import Literal
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ Some backwards compatibility stuff/deprecation helpers
|
|||
'''
|
||||
from types import ModuleType
|
||||
from typing import Callable
|
||||
from datetime import datetime
|
||||
|
||||
from . import warnings
|
||||
from .common import LazyLogger
|
||||
|
@ -12,16 +11,6 @@ from .common import LazyLogger
|
|||
logger = LazyLogger('my.core.compat')
|
||||
|
||||
|
||||
fromisoformat: Callable[[str], datetime]
|
||||
import sys
|
||||
if sys.version_info[:2] >= (3, 7):
|
||||
# prevent mypy on py3.6 from complaining...
|
||||
fromisoformat_real = datetime.fromisoformat
|
||||
fromisoformat = fromisoformat_real
|
||||
else:
|
||||
from .py37 import fromisoformat
|
||||
|
||||
|
||||
def pre_pip_dal_handler(
|
||||
name: str,
|
||||
e: ModuleNotFoundError,
|
||||
|
|
|
@ -127,8 +127,8 @@ def attach_dt(e: Exception, *, dt: Optional[datetime]) -> Exception:
|
|||
|
||||
# todo it might be problematic because might mess with timezones (when it's converted to string, it's converted to a shift)
|
||||
def extract_error_datetime(e: Exception) -> Optional[datetime]:
|
||||
from .compat import fromisoformat
|
||||
import re
|
||||
from datetime import datetime
|
||||
for x in reversed(e.args):
|
||||
if isinstance(x, datetime):
|
||||
return x
|
||||
|
@ -139,7 +139,7 @@ def extract_error_datetime(e: Exception) -> Optional[datetime]:
|
|||
continue
|
||||
ss = m.group(0)
|
||||
# todo not sure if should be defensive??
|
||||
return fromisoformat(ss)
|
||||
return datetime.fromisoformat(ss)
|
||||
return None
|
||||
|
||||
|
||||
|
|
122
my/core/py37.py
122
my/core/py37.py
|
@ -1,122 +0,0 @@
|
|||
# borrowed from /usr/lib/python3.7/datetime.py
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
def _parse_isoformat_date(dtstr):
|
||||
# It is assumed that this function will only be called with a
|
||||
# string of length exactly 10, and (though this is not used) ASCII-only
|
||||
year = int(dtstr[0:4])
|
||||
if dtstr[4] != '-':
|
||||
raise ValueError('Invalid date separator: %s' % dtstr[4])
|
||||
|
||||
month = int(dtstr[5:7])
|
||||
|
||||
if dtstr[7] != '-':
|
||||
raise ValueError('Invalid date separator')
|
||||
|
||||
day = int(dtstr[8:10])
|
||||
|
||||
return [year, month, day]
|
||||
|
||||
|
||||
def _parse_hh_mm_ss_ff(tstr):
|
||||
# Parses things of the form HH[:MM[:SS[.fff[fff]]]]
|
||||
len_str = len(tstr)
|
||||
|
||||
time_comps = [0, 0, 0, 0]
|
||||
pos = 0
|
||||
for comp in range(0, 3):
|
||||
if (len_str - pos) < 2:
|
||||
raise ValueError('Incomplete time component')
|
||||
|
||||
time_comps[comp] = int(tstr[pos:pos+2])
|
||||
|
||||
pos += 2
|
||||
next_char = tstr[pos:pos+1]
|
||||
|
||||
if not next_char or comp >= 2:
|
||||
break
|
||||
|
||||
if next_char != ':':
|
||||
raise ValueError('Invalid time separator: %c' % next_char)
|
||||
|
||||
pos += 1
|
||||
|
||||
if pos < len_str:
|
||||
if tstr[pos] != '.':
|
||||
raise ValueError('Invalid microsecond component')
|
||||
else:
|
||||
pos += 1
|
||||
|
||||
len_remainder = len_str - pos
|
||||
if len_remainder not in (3, 6):
|
||||
raise ValueError('Invalid microsecond component')
|
||||
|
||||
time_comps[3] = int(tstr[pos:])
|
||||
if len_remainder == 3:
|
||||
time_comps[3] *= 1000
|
||||
|
||||
return time_comps
|
||||
|
||||
|
||||
def _parse_isoformat_time(tstr):
|
||||
# Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
|
||||
len_str = len(tstr)
|
||||
if len_str < 2:
|
||||
raise ValueError('Isoformat time too short')
|
||||
|
||||
# This is equivalent to re.search('[+-]', tstr), but faster
|
||||
tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1)
|
||||
timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr
|
||||
|
||||
time_comps = _parse_hh_mm_ss_ff(timestr)
|
||||
|
||||
tzi = None
|
||||
if tz_pos > 0:
|
||||
tzstr = tstr[tz_pos:]
|
||||
|
||||
# Valid time zone strings are:
|
||||
# HH:MM len: 5
|
||||
# HH:MM:SS len: 8
|
||||
# HH:MM:SS.ffffff len: 15
|
||||
|
||||
if len(tzstr) not in (5, 8, 15):
|
||||
raise ValueError('Malformed time zone string')
|
||||
|
||||
tz_comps = _parse_hh_mm_ss_ff(tzstr)
|
||||
if all(x == 0 for x in tz_comps):
|
||||
tzi = timezone.utc
|
||||
else:
|
||||
tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
|
||||
|
||||
td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
|
||||
seconds=tz_comps[2], microseconds=tz_comps[3])
|
||||
|
||||
tzi = timezone(tzsign * td)
|
||||
|
||||
time_comps.append(tzi)
|
||||
|
||||
return time_comps
|
||||
|
||||
def fromisoformat(date_string, cls=datetime):
|
||||
"""Construct a datetime from the output of datetime.isoformat()."""
|
||||
if not isinstance(date_string, str):
|
||||
raise TypeError('fromisoformat: argument must be str')
|
||||
|
||||
# Split this at the separator
|
||||
dstr = date_string[0:10]
|
||||
tstr = date_string[11:]
|
||||
|
||||
try:
|
||||
date_components = _parse_isoformat_date(dstr)
|
||||
except ValueError:
|
||||
raise ValueError('Invalid isoformat string: %s' % date_string)
|
||||
|
||||
if tstr:
|
||||
try:
|
||||
time_components = _parse_isoformat_time(tstr)
|
||||
except ValueError:
|
||||
raise ValueError('Invalid isoformat string: %s' % date_string)
|
||||
else:
|
||||
time_components = [0, 0, 0, 0, None]
|
||||
|
||||
return cls(*(date_components + time_components))
|
|
@ -24,7 +24,6 @@ from .query import (
|
|||
ET,
|
||||
)
|
||||
|
||||
from .compat import fromisoformat
|
||||
from .common import isoparse
|
||||
|
||||
|
||||
|
@ -74,7 +73,7 @@ def parse_datetime_float(date_str: str) -> float:
|
|||
return ds_float
|
||||
try:
|
||||
# isoformat - default format when you call str() on datetime
|
||||
return fromisoformat(ds).timestamp()
|
||||
return datetime.fromisoformat(ds).timestamp()
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
|
|
|
@ -6,8 +6,6 @@ from datetime import datetime, date, time, timezone
|
|||
from functools import lru_cache
|
||||
from typing import Sequence, Tuple, Union, cast
|
||||
|
||||
from ..core.compat import fromisoformat
|
||||
|
||||
from my.config import location as user_config
|
||||
|
||||
|
||||
|
@ -44,7 +42,7 @@ class Config(user_config):
|
|||
for x, loc in home2:
|
||||
dt: datetime
|
||||
if isinstance(x, str):
|
||||
dt = fromisoformat(x)
|
||||
dt = datetime.fromisoformat(x)
|
||||
elif isinstance(x, datetime):
|
||||
dt = x
|
||||
else:
|
||||
|
|
|
@ -6,7 +6,6 @@ from datetime import datetime
|
|||
from typing import NamedTuple, Dict, Optional, Iterable
|
||||
|
||||
from .core import get_files
|
||||
from .core.compat import fromisoformat
|
||||
|
||||
from my.config import taplog as user_config
|
||||
|
||||
|
@ -41,7 +40,7 @@ class Entry(NamedTuple):
|
|||
ts = self.row['timestamp']
|
||||
# already with timezone apparently
|
||||
# TODO not sure if should stil localize though? it only kept tz offset, not real tz
|
||||
return fromisoformat(ts)
|
||||
return datetime.fromisoformat(ts)
|
||||
# TODO also has gps info!
|
||||
|
||||
|
||||
|
|
|
@ -141,7 +141,6 @@ def localize(dt: datetime) -> tzdatetime:
|
|||
|
||||
from ...core import stat, Stats
|
||||
def stats() -> Stats:
|
||||
from ...core.compat import fromisoformat
|
||||
# TODO not sure what would be a good stat() for this module...
|
||||
# might be nice to print some actual timezones?
|
||||
# there aren't really any great iterables to expose
|
||||
|
@ -150,6 +149,6 @@ def stats() -> Stats:
|
|||
# note: deliberately take + 2 years, so the iterator exhausts. otherwise stuff might never get cached
|
||||
# need to think about it...
|
||||
for Y in range(1990, last):
|
||||
dt = fromisoformat(f'{Y}-01-01 01:01:01')
|
||||
dt = datetime.fromisoformat(f'{Y}-01-01 01:01:01')
|
||||
yield localize(dt)
|
||||
return stat(localized_years)
|
||||
|
|
Loading…
Add table
Reference in a new issue