core/compat: move fromisoformat to .core.compat module

This commit is contained in:
Dima Gerasimov 2023-11-19 22:45:02 +00:00
parent 09e0f66892
commit 4072899295
8 changed files with 69 additions and 34 deletions

View file

@ -313,20 +313,18 @@ class classproperty(Generic[_R]):
# def __get__(self) -> _R:
# return self.f()
# TODO deprecate in favor of datetime_aware
tzdatetime = datetime
# for now just serves documentation purposes... but one day might make it statically verifiable where possible?
# TODO e.g. maybe use opaque mypy alias?
datetime_naive = datetime
datetime_aware = datetime
# TODO doctests?
def isoparse(s: str) -> tzdatetime:
"""
Parses timestamps formatted like 2020-05-01T10:32:02.925961Z
"""
# 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 datetime.fromisoformat(s)
# TODO deprecate
tzdatetime = datetime_aware
# TODO deprecate (although could be used in modules)
from .compat import fromisoformat as isoparse
import re
@ -590,12 +588,6 @@ def asdict(thing: Any) -> Json:
raise TypeError(f'Could not convert object {thing} to dict')
# for now just serves documentation purposes... but one day might make it statically verifiable where possible?
# TODO e.g. maybe use opaque mypy alias?
datetime_naive = datetime
datetime_aware = datetime
def assert_subpackage(name: str) -> None:
# can lead to some unexpected issues if you 'import cachew' which being in my/core directory.. so let's protect against it
# NOTE: if we use overlay, name can be smth like my.origg.my.core.cachew ...

View file

@ -76,3 +76,42 @@ if sys.version_info[:2] <= (3, 9):
return lo
else:
from bisect import bisect_left
from datetime import datetime
if sys.version_info[:2] >= (3, 11):
fromisoformat = datetime.fromisoformat
else:
def fromisoformat(date_string: str) -> datetime:
# didn't support Z as "utc" before 3.11
if date_string.endswith('Z'):
# NOTE: can be removed from 3.11?
# https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat
date_string = date_string[:-1] + '+00:00'
return datetime.fromisoformat(date_string)
def test_fromisoformat() -> None:
from datetime import timezone
# feedbin has this format
assert fromisoformat('2020-05-01T10:32:02.925961Z') == datetime(
2020, 5, 1, 10, 32, 2, 925961, timezone.utc,
)
# polar has this format
assert fromisoformat('2018-11-28T22:04:01.304Z') == datetime(
2018, 11, 28, 22, 4, 1, 304000, timezone.utc,
)
# stackexchange, runnerup has this format
assert fromisoformat('2020-11-30T00:53:12Z') == datetime(
2020, 11, 30, 0, 53, 12, 0, timezone.utc,
)
# arbtt has this format (sometimes less/more than 6 digits in milliseconds)
# TODO doesn't work atm, not sure if really should be supported...
# maybe should have flags for weird formats?
# assert isoparse('2017-07-18T18:59:38.21731Z') == datetime(
# 2017, 7, 18, 18, 59, 38, 217310, timezone.utc,
# )

View file

@ -24,7 +24,7 @@ from .query import (
ET,
)
from .common import isoparse
from .compat import fromisoformat
timedelta_regex = re.compile(r"^((?P<weeks>[\.\d]+?)w)?((?P<days>[\.\d]+?)d)?((?P<hours>[\.\d]+?)h)?((?P<minutes>[\.\d]+?)m)?((?P<seconds>[\.\d]+?)s)?$")
@ -78,7 +78,7 @@ def parse_datetime_float(date_str: str) -> float:
except ValueError:
pass
try:
return isoparse(ds).timestamp()
return fromisoformat(ds).timestamp()
except (AssertionError, ValueError):
pass