Skip to content

Commit

Permalink
general: python3.9 reached EOL, switch min version
Browse files Browse the repository at this point in the history
also enable 3.13 on CI
  • Loading branch information
karlicoss committed Oct 19, 2024
1 parent a8f86e3 commit 25a6bcd
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 54 deletions.
11 changes: 7 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,20 @@ on:
jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
exclude: [
# windows runners are pretty scarce, so let's only run lowest and highest python version
{platform: windows-latest, python-version: '3.9' },
{platform: windows-latest, python-version: '3.10'},
{platform: windows-latest, python-version: '3.11'},
{platform: windows-latest, python-version: '3.12'},

# same, macos is a bit too slow and ubuntu covers python quirks well
{platform: macos-latest , python-version: '3.9' },
{platform: macos-latest , python-version: '3.10' },
{platform: macos-latest , python-version: '3.11' },
{platform: macos-latest , python-version: '3.12' },
]

runs-on: ${{ matrix.platform }}
Expand Down Expand Up @@ -63,11 +64,13 @@ jobs:
- if: matrix.platform == 'ubuntu-latest' # no need to compute coverage for other platforms
uses: actions/upload-artifact@v4
with:
include-hidden-files: true
name: .coverage.mypy-misc_${{ matrix.platform }}_${{ matrix.python-version }}
path: .coverage.mypy-misc/
- if: matrix.platform == 'ubuntu-latest' # no need to compute coverage for other platforms
uses: actions/upload-artifact@v4
with:
include-hidden-files: true
name: .coverage.mypy-core_${{ matrix.platform }}_${{ matrix.python-version }}
path: .coverage.mypy-core/

Expand All @@ -81,7 +84,7 @@ jobs:

- uses: actions/setup-python@v5
with:
python-version: '3.8'
python-version: '3.10'

- uses: actions/checkout@v4
with:
Expand Down
4 changes: 1 addition & 3 deletions my/core/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,6 @@ def config_ok() -> bool:
# use a temporary directory, useful because
# - compileall ignores -B, so always craps with .pyc files (annoyng on RO filesystems)
# - compileall isn't following symlinks, just silently ignores them
# note: ugh, annoying that copytree requires a non-existing dir before 3.8.
# once we have min version 3.8, can use dirs_exist_ok=True param
tdir = Path(td) / 'cfg'
# NOTE: compileall still returns code 0 if the path doesn't exist..
# but in our case hopefully it's not an issue
Expand All @@ -181,7 +179,7 @@ def config_ok() -> bool:
try:
# this will resolve symlinks when copying
# should be under try/catch since might fail if some symlinks are missing
shutil.copytree(cfg_path, tdir)
shutil.copytree(cfg_path, tdir, dirs_exist_ok=True)
check_call(cmd)
info('syntax check: ' + ' '.join(cmd))
except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion my/core/_deprecated/kompress.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def __truediv__(self, key) -> ZipPath:

def iterdir(self) -> Iterator[ZipPath]:
for s in self._as_dir().iterdir():
yield ZipPath(s.root, s.at) # type: ignore[attr-defined]
yield ZipPath(s.root, s.at)

@property
def stem(self) -> str:
Expand Down
24 changes: 9 additions & 15 deletions my/core/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,19 @@ def sqlite_backup(*, source: sqlite3.Connection, dest: sqlite3.Connection, **kwa
# TODO warn here?
source.backup(dest, **kwargs)

# keeping for runtime backwards compatibility (added in 3.9)
@deprecated('use .removeprefix method on string directly instead')
def removeprefix(text: str, prefix: str) -> str:
return text.removeprefix(prefix)

## 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
@deprecated('use .removesuffix method on string directly instead')
def removesuffix(text: str, suffix: str) -> str:
return text.removesuffix(suffix)
##

def removesuffix(text: str, suffix: str) -> str:
if text.endswith(suffix):
return text[:-len(suffix)]
return text
##

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


Expand Down
2 changes: 1 addition & 1 deletion my/core/pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def _to_jsons(it: Iterable[Res[Any]]) -> Iterable[Json]:
def _as_columns(s: Schema) -> Dict[str, Type]:
# todo would be nice to extract properties; add tests for this as well
if dataclasses.is_dataclass(s):
return {f.name: f.type for f in dataclasses.fields(s)}
return {f.name: f.type for f in dataclasses.fields(s)} # type: ignore[misc] # ugh, why mypy thinks f.type can return str??
# else must be NamedTuple??
# todo assert my.core.common.is_namedtuple?
return getattr(s, '_field_types')
Expand Down
40 changes: 14 additions & 26 deletions my/core/utils/concurrent.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sys
from concurrent.futures import Executor, Future
from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar
from typing import Any, Callable, Optional, TypeVar

from ..compat import ParamSpec

Expand All @@ -19,33 +19,21 @@ def __init__(self, max_workers: Optional[int] = 1) -> None:
self._shutdown = False
self._max_workers = max_workers

if TYPE_CHECKING:
if sys.version_info[:2] <= (3, 8):
# 3.8 doesn't support ParamSpec as Callable arg :(
# and any attempt to type results in incompatible supertype.. so whatever
def submit(self, fn, *args, **kwargs): ...

def submit(self, fn: Callable[_P, _T], /, *args: _P.args, **kwargs: _P.kwargs) -> Future[_T]:
if self._shutdown:
raise RuntimeError('cannot schedule new futures after shutdown')

f: Future[Any] = Future()
try:
result = fn(*args, **kwargs)
except KeyboardInterrupt:
raise
except BaseException as e:
f.set_exception(e)
else:
f.set_result(result)

def submit(self, fn: Callable[_P, _T], /, *args: _P.args, **kwargs: _P.kwargs) -> Future[_T]: ...

else:

def submit(self, fn, *args, **kwargs):
if self._shutdown:
raise RuntimeError('cannot schedule new futures after shutdown')

f: Future[Any] = Future()
try:
result = fn(*args, **kwargs)
except KeyboardInterrupt:
raise
except BaseException as e:
f.set_exception(e)
else:
f.set_result(result)

return f
return f

def shutdown(self, wait: bool = True, **kwargs) -> None: # noqa: FBT001,FBT002,ARG002
self._shutdown = True
6 changes: 3 additions & 3 deletions my/youtube/takeout.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import TYPE_CHECKING, Any, Iterable, Iterator

from my.core import Res, Stats, datetime_aware, make_logger, stat, warnings
from my.core.compat import deprecated, removeprefix, removesuffix
from my.core.compat import deprecated

logger = make_logger(__name__)

Expand Down Expand Up @@ -117,10 +117,10 @@ def _watched() -> Iterator[Res[Watched]]:

# all titles contain it, so pointless to include 'Watched '
# also compatible with legacy titles
title = removeprefix(title, 'Watched ')
title = title.removeprefix('Watched ')

# watches originating from some activity end with this, remove it for consistency
title = removesuffix(title, ' - YouTube')
title = title.removesuffix(' - YouTube')

if YOUTUBE_VIDEO_LINK not in url:
if 'youtube.com/post/' in url:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def main() -> None:
author_email='karlicoss@gmail.com',
description='A Python interface to my life',

python_requires='>=3.8',
python_requires='>=3.9',
install_requires=INSTALL_REQUIRES,
extras_require={
'testing': [
Expand Down

0 comments on commit 25a6bcd

Please sign in to comment.