Skip to content

Commit

Permalink
core: cleanup deprecations, exclude from type checking and show runti…
Browse files Browse the repository at this point in the history
…me warnings

among affected things:

- core.common.assert_never
- core.common.cproperty
- core.common.isoparse
- core.common.mcachew
- core.common.the
- core.common.tzdatetime
- core.compat.sqlite_backup
  • Loading branch information
karlicoss committed Aug 12, 2024
1 parent 8834001 commit 918e8ee
Show file tree
Hide file tree
Showing 24 changed files with 117 additions and 102 deletions.
2 changes: 1 addition & 1 deletion my/bluemaestro.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
Stats,
influxdb,
)
from my.core.common import mcachew
from my.core.cachew import mcachew
from my.core.error import unwrap
from my.core.pandas import DataFrameT, as_dataframe
from my.core.sqlite import sqlite_connect_immutable
Expand Down
2 changes: 1 addition & 1 deletion my/browser/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
make_logger,
stat,
)
from my.core.common import mcachew
from my.core.cachew import mcachew

from browserexport.merge import read_and_merge, Visit

Expand Down
3 changes: 1 addition & 2 deletions my/coding/commits.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@


from my.core import PathIsh, LazyLogger, make_config
from my.core.cachew import cache_dir
from my.core.common import mcachew
from my.core.cachew import cache_dir, mcachew
from my.core.warnings import high


Expand Down
62 changes: 34 additions & 28 deletions my/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
Iterable,
Iterator,
List,
NoReturn,
Optional,
Sequence,
TYPE_CHECKING,
Expand Down Expand Up @@ -70,17 +69,6 @@ def import_dir(path: PathIsh, extra: str='') -> types.ModuleType:
K = TypeVar('K')
V = TypeVar('V')

# TODO deprecate? more_itertools.one should be used
def the(l: Iterable[T]) -> T:
it = iter(l)
try:
first = next(it)
except StopIteration:
raise RuntimeError('Empty iterator?')
assert all(e == first for e in it)
return first


# TODO more_itertools.bucket?
def group_by_key(l: Iterable[T], key: Callable[[T], K]) -> Dict[K, List[T]]:
res: Dict[K, List[T]] = {}
Expand Down Expand Up @@ -322,14 +310,6 @@ def __get__(self, obj, cls) -> _R:
datetime_aware = datetime


# TODO deprecate
tzdatetime = datetime_aware


# TODO deprecate (although could be used in modules)
from .compat import fromisoformat as isoparse


import re
# https://stackoverflow.com/a/295466/706389
def get_valid_filename(s: str) -> str:
Expand Down Expand Up @@ -554,7 +534,7 @@ def test_guess_datetime() -> None:
from dataclasses import dataclass
from typing import NamedTuple

dd = isoparse('2021-02-01T12:34:56Z')
dd = compat.fromisoformat('2021-02-01T12:34:56Z')

# ugh.. https://github.com/python/mypy/issues/7281
A = NamedTuple('A', [('x', int)])
Expand Down Expand Up @@ -690,15 +670,41 @@ def unique_everseen(
return more_itertools.unique_everseen(iterable=iterable, key=key)


## legacy imports, keeping them here for backwards compatibility
### legacy imports, keeping them here for backwards compatibility
## hiding behind TYPE_CHECKING so it works in runtime
## in principle, warnings.deprecated decorator should cooperate with mypy, but doesn't look like it works atm?
## perhaps it doesn't work when it's used from typing_extensions
if not TYPE_CHECKING:
assert_never = deprecated('use my.core.compat.assert_never instead')(compat.assert_never)

# TODO wrap in deprecated decorator as well?
from functools import cached_property as cproperty
from typing import Literal
from .cachew import mcachew
##
@deprecated('use my.core.compat.assert_never instead')
def assert_never(*args, **kwargs):
return compat.assert_never(*args, **kwargs)

@deprecated('use my.core.compat.fromisoformat instead')
def isoparse(*args, **kwargs):
return compat.fromisoformat(*args, **kwargs)

@deprecated('use more_itertools.one instead')
def the(*args, **kwargs):
import more_itertools

return more_itertools.one(*args, **kwargs)

@deprecated('use functools.cached_property instead')
def cproperty(*args, **kwargs):
import functools

return functools.cached_property(*args, **kwargs)

# todo wrap these in deprecated decorator as well?
from .cachew import mcachew # noqa: F401

from typing import Literal # noqa: F401

# TODO hmm how to deprecate it in runtime? tricky cause it's actually a class?
tzdatetime = datetime_aware
else:
from .compat import Never

tzdatetime = Never # makes it invalid as a type while working in runtime
###
65 changes: 36 additions & 29 deletions my/core/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,58 @@
Contains backwards compatibility helpers for different python versions.
If something is relevant to HPI itself, please put it in .hpi_compat instead
'''
import os

import sys
from typing import TYPE_CHECKING


windows = os.name == 'nt'
if sys.version_info[:2] >= (3, 13):
from warnings import deprecated
else:
from typing_extensions import deprecated


# keeping just for backwards compatibility, used to have compat implementation for 3.6
import sqlite3
def sqlite_backup(*, source: sqlite3.Connection, dest: sqlite3.Connection, **kwargs) -> None:
source.backup(dest, **kwargs)
if not TYPE_CHECKING:
import sqlite3

@deprecated('use .backup method on sqlite3.Connection directly instead')
def sqlite_backup(*, source: sqlite3.Connection, dest: sqlite3.Connection, **kwargs) -> None:
# TODO warn here?
source.backup(dest, **kwargs)


# can remove after python3.9 (although need to keep the method itself for bwd compat)
def removeprefix(text: str, prefix: str) -> str:
if text.startswith(prefix):
return text[len(prefix):]
return text[len(prefix) :]
return text


## used to have compat function before 3.8 for these
from functools import cached_property
from typing import Literal, Protocol, TypedDict
## used to have compat function before 3.8 for these, keeping for runtime back compatibility
if not TYPE_CHECKING:
from functools import cached_property
from typing import Literal, Protocol, TypedDict
else:
from typing_extensions import Literal, Protocol, TypedDict
##


if sys.version_info[:2] >= (3, 10):
from typing import ParamSpec
else:
if TYPE_CHECKING:
from typing_extensions import ParamSpec
else:
from typing import NamedTuple, Any
# erm.. I guess as long as it's not crashing, whatever...
class _ParamSpec:
def __call__(self, args):
class _res:
args = None
kwargs = None
return _res
ParamSpec = _ParamSpec()
from typing_extensions import ParamSpec


# bisect_left doesn't have a 'key' parameter (which we use)
# till python3.10
if sys.version_info[:2] <= (3, 9):
from typing import List, TypeVar, Any, Optional, Callable

X = TypeVar('X')

# copied from python src
# fmt: off
def bisect_left(a: List[Any], x: Any, lo: int=0, hi: Optional[int]=None, *, key: Optional[Callable[..., Any]]=None) -> int:
if lo < 0:
raise ValueError('lo must be non-negative')
Expand All @@ -74,26 +76,30 @@ def bisect_left(a: List[Any], x: Any, lo: int=0, hi: Optional[int]=None, *, key:
else:
hi = mid
return lo
# fmt: on

else:
from bisect import bisect_left


from datetime import datetime

if sys.version_info[:2] >= (3, 11):
fromisoformat = datetime.fromisoformat
else:
# fromisoformat didn't support Z as "utc" before 3.11
# https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat

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

# fmt: off
# feedbin has this format
assert fromisoformat('2020-05-01T10:32:02.925961Z') == datetime(
2020, 5, 1, 10, 32, 2, 925961, timezone.utc,
Expand All @@ -108,6 +114,7 @@ def test_fromisoformat() -> None:
assert fromisoformat('2020-11-30T00:53:12Z') == datetime(
2020, 11, 30, 0, 53, 12, 0, timezone.utc,
)
# fmt: on

# arbtt has this format (sometimes less/more than 6 digits in milliseconds)
# TODO doesn't work atm, not sure if really should be supported...
Expand All @@ -123,13 +130,13 @@ def test_fromisoformat() -> None:
NoneType = type(None)


if sys.version_info[:2] >= (3, 13):
from warnings import deprecated
if sys.version_info[:2] >= (3, 11):
from typing import assert_never
else:
from typing_extensions import deprecated
from typing_extensions import assert_never


if sys.version_info[:2] >= (3, 11):
from typing import assert_never
from typing import Never
else:
from typing_extensions import assert_never
from typing_extensions import Never
4 changes: 2 additions & 2 deletions my/core/tests/test_cachew.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def test_cachew() -> None:

settings.ENABLE = True # by default it's off in tests (see conftest.py)

from my.core.common import mcachew
from my.core.cachew import mcachew

called = 0

Expand All @@ -36,7 +36,7 @@ def test_cachew_dir_none() -> None:
settings.ENABLE = True # by default it's off in tests (see conftest.py)

from my.core.cachew import cache_dir
from my.core.common import mcachew
from my.core.cachew import mcachew
from my.core.core_config import _reset_config as reset

with reset() as cc:
Expand Down
4 changes: 2 additions & 2 deletions my/core/tests/test_get_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import zipfile

from ..common import get_files
from ..compat import windows
from ..kompress import CPath, ZipPath

import pytest
Expand Down Expand Up @@ -56,8 +55,9 @@ def test_single_file() -> None:
'''
assert get_files('/tmp/hpi_test/file.ext') == (Path('/tmp/hpi_test/file.ext'),)

is_windows = os.name == 'nt'
"if the path starts with ~, we expand it"
if not windows: # windows doesn't have bashrc.. ugh
if not is_windows: # windows doesn't have bashrc.. ugh
assert get_files('~/.bashrc') == (Path('~').expanduser() / '.bashrc',)


Expand Down
3 changes: 1 addition & 2 deletions my/emfit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
Res,
Stats,
)
from my.core.common import mcachew
from my.core.cachew import cache_dir
from my.core.cachew import cache_dir, mcachew
from my.core.error import set_error_datetime, extract_error_datetime
from my.core.pandas import DataFrameT

Expand Down
5 changes: 3 additions & 2 deletions my/github/ghexport.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ def migration(attrs: Attrs) -> Attrs:
############################

from functools import lru_cache
from pathlib import Path
from typing import Tuple, Dict, Sequence, Optional

from my.core import get_files, Path, LazyLogger
from my.core.common import mcachew
from my.core import get_files, LazyLogger
from my.core.cachew import mcachew

from .common import Event, parse_dt, Results, EventIds

Expand Down
3 changes: 2 additions & 1 deletion my/google/takeout/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
from typing import List, Sequence, cast
from pathlib import Path
from my.core import make_config, dataclass
from my.core.common import Stats, LazyLogger, mcachew, get_files, Paths
from my.core.cachew import mcachew
from my.core.common import Stats, LazyLogger, get_files, Paths
from my.core.error import ErrorPolicy
from my.core.structure import match_structure

Expand Down
3 changes: 2 additions & 1 deletion my/lastfm.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class lastfm(user_config):
from pathlib import Path
from typing import NamedTuple, Sequence, Iterable

from my.core.common import mcachew, Json, get_files
from my.core.cachew import mcachew
from my.core.common import Json, get_files


def inputs() -> Sequence[Path]:
Expand Down
4 changes: 2 additions & 2 deletions my/location/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
# pip3 install geopy
import geopy # type: ignore

from ..core.common import LazyLogger, mcachew
from ..core.cachew import cache_dir
from my.core.common import LazyLogger
from my.core.cachew import cache_dir, mcachew

from my.core.warnings import high

Expand Down
7 changes: 3 additions & 4 deletions my/location/google_takeout.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from my.google.takeout.parser import events, _cachew_depends_on
from google_takeout_parser.models import Location as GoogleLocation

from my.core.common import mcachew, LazyLogger, Stats
from my.core.cachew import mcachew
from my.core.common import LazyLogger, stat, Stats
from .common import Location

logger = LazyLogger(__name__)
Expand All @@ -33,6 +34,4 @@ def locations() -> Iterator[Location]:


def stats() -> Stats:
from my.core import stat

return {**stat(locations)}
return stat(locations)
7 changes: 3 additions & 4 deletions my/location/google_takeout_semantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
from google_takeout_parser.models import PlaceVisit as SemanticLocation

from my.core import dataclass, make_config
from my.core.common import mcachew, LazyLogger, Stats
from my.core.cachew import mcachew
from my.core.common import LazyLogger, Stats, stat
from my.core.error import Res
from .common import Location

Expand Down Expand Up @@ -72,6 +73,4 @@ def locations() -> Iterator[Res[Location]]:


def stats() -> Stats:
from my.core import stat

return {**stat(locations)}
return stat(locations)
Loading

0 comments on commit 918e8ee

Please sign in to comment.