From f5ba26cc63f4069473cf322c1b1c1924dec941de Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 11 Oct 2024 15:42:07 -0500 Subject: [PATCH] Drop Python 3.8 support (#57) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .codecov.yml | 2 +- .github/workflows/ci-cd.yml | 5 ----- .github/workflows/reusable-linters.yml | 5 +++-- .mypy.ini | 2 +- .pre-commit-config.yaml | 26 +++++++++++++------------- CHANGES/57.breaking.rst | 1 + README.rst | 2 +- setup.cfg | 3 +-- src/propcache/__init__.py | 4 ++-- src/propcache/_helpers_c.pyx | 10 +--------- src/propcache/_helpers_py.py | 21 +++++---------------- tests/conftest.py | 26 ++++---------------------- tests/test_cached_property.py | 4 ++-- tests/test_under_cached_property.py | 12 ++++++------ 14 files changed, 41 insertions(+), 82 deletions(-) create mode 100644 CHANGES/57.breaking.rst diff --git a/.codecov.yml b/.codecov.yml index 6911a7b..d8a1d3f 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -2,7 +2,7 @@ codecov: notify: - after_n_builds: 24 # The number of test matrix+lint jobs uploading coverage + after_n_builds: 23 # The number of test matrix+lint jobs uploading coverage wait_for_ci: false require_ci_to_pass: false diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 7f22b08..c38f0cb 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -174,7 +174,6 @@ jobs: - >- 3.10 - 3.9 - - 3.8 no-extensions: ['', 'Y'] os: - ubuntu-latest @@ -195,10 +194,6 @@ jobs: no-extensions: Y experimental: false os: ubuntu-latest - - pyver: pypy-3.8 - no-extensions: Y - experimental: false - os: ubuntu-latest fail-fast: false runs-on: ${{ matrix.os }} timeout-minutes: 5 diff --git a/.github/workflows/reusable-linters.yml b/.github/workflows/reusable-linters.yml index 1f51216..7a6435d 100644 --- a/.github/workflows/reusable-linters.yml +++ b/.github/workflows/reusable-linters.yml @@ -63,9 +63,10 @@ jobs: with: token: ${{ secrets.codecov-token }} files: >- + .tox/.tmp/.mypy/python-3.13/cobertura.xml, .tox/.tmp/.mypy/python-3.12/cobertura.xml, - .tox/.tmp/.mypy/python-3.10/cobertura.xml, - .tox/.tmp/.mypy/python-3.8/cobertura.xml + .tox/.tmp/.mypy/python-3.11/cobertura.xml, + .tox/.tmp/.mypy/python-3.9/cobertura.xml flags: >- CI-GHA, MyPy diff --git a/.mypy.ini b/.mypy.ini index a396b02..5bd5c19 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -1,5 +1,5 @@ [mypy] -python_version = 3.8 +python_version = 3.9 color_output = true error_summary = true files = diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 11953dc..002e243 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -74,7 +74,7 @@ repos: rev: 'v3.17.0' hooks: - id: pyupgrade - args: ['--py38-plus'] + args: ['--py39-plus'] - repo: https://github.com/PyCQA/flake8 rev: '7.1.1' hooks: @@ -138,8 +138,8 @@ repos: - --html-report=.tox/.tmp/.mypy/python-3.12 pass_filenames: false - id: mypy - alias: mypy-py310 - name: MyPy, for Python 3.10 + alias: mypy-py311 + name: MyPy, for Python 3.11 additional_dependencies: - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - pytest @@ -148,14 +148,14 @@ repos: - types-Pygments - types-colorama args: - - --python-version=3.10 - - --txt-report=.tox/.tmp/.mypy/python-3.10 - - --cobertura-xml-report=.tox/.tmp/.mypy/python-3.10 - - --html-report=.tox/.tmp/.mypy/python-3.10 + - --python-version=3.11 + - --txt-report=.tox/.tmp/.mypy/python-3.11 + - --cobertura-xml-report=.tox/.tmp/.mypy/python-3.11 + - --html-report=.tox/.tmp/.mypy/python-3.11 pass_filenames: false - id: mypy - alias: mypy-py38 - name: MyPy, for Python 3.8 + alias: mypy-py39 + name: MyPy, for Python 3.9 additional_dependencies: - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - pytest @@ -164,10 +164,10 @@ repos: - types-Pygments - types-colorama args: - - --python-version=3.8 - - --txt-report=.tox/.tmp/.mypy/python-3.8 - - --cobertura-xml-report=.tox/.tmp/.mypy/python-3.8 - - --html-report=.tox/.tmp/.mypy/python-3.8 + - --python-version=3.9 + - --txt-report=.tox/.tmp/.mypy/python-3.9 + - --cobertura-xml-report=.tox/.tmp/.mypy/python-3.9 + - --html-report=.tox/.tmp/.mypy/python-3.9 pass_filenames: false - repo: https://github.com/rhysd/actionlint.git diff --git a/CHANGES/57.breaking.rst b/CHANGES/57.breaking.rst new file mode 100644 index 0000000..aa65aed --- /dev/null +++ b/CHANGES/57.breaking.rst @@ -0,0 +1 @@ +Removed support for Python 3.8 as it has reached end of life -- by :user:`bdraco`. diff --git a/README.rst b/README.rst index d23a028..a88e38b 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ propcache ========= -The module provides a fast implementation of cached properties for Python 3.8+. +The module provides a fast implementation of cached properties for Python 3.9+. .. image:: https://github.com/aio-libs/propcache/actions/workflows/ci-cd.yml/badge.svg :target: https://github.com/aio-libs/propcache/actions?query=workflow%3ACI diff --git a/setup.cfg b/setup.cfg index 1db317d..f2f8969 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,7 +38,6 @@ classifiers = Programming Language :: Cython Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 @@ -53,7 +52,7 @@ keywords = propcache [options] -python_requires = >=3.8 +python_requires = >=3.9 # Ref: # https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#using-a-src-layout # (`src/` layout) diff --git a/src/propcache/__init__.py b/src/propcache/__init__.py index ffbd3e9..379d165 100644 --- a/src/propcache/__init__.py +++ b/src/propcache/__init__.py @@ -1,6 +1,6 @@ """propcache: An accelerated property cache for Python classes.""" -from typing import TYPE_CHECKING, List +from typing import TYPE_CHECKING _PUBLIC_API = ("cached_property", "under_cached_property") @@ -23,7 +23,7 @@ def _import_facade(attr: str) -> object: raise AttributeError(f"module '{__package__}' has no attribute '{attr}'") -def _dir_facade() -> List[str]: +def _dir_facade() -> list[str]: """Include the public API in the module's dir() output.""" return [*_PUBLIC_API, *globals().keys()] diff --git a/src/propcache/_helpers_c.pyx b/src/propcache/_helpers_c.pyx index 3999a67..5369e12 100644 --- a/src/propcache/_helpers_c.pyx +++ b/src/propcache/_helpers_c.pyx @@ -1,13 +1,5 @@ # cython: language_level=3 -import sys -import types - -if sys.version_info >= (3, 9): - GenericAlias = types.GenericAlias -else: - - def GenericAlias(cls): - return cls +from types import GenericAlias cdef _sentinel = object() diff --git a/src/propcache/_helpers_py.py b/src/propcache/_helpers_py.py index 8ab5f80..2f3e688 100644 --- a/src/propcache/_helpers_py.py +++ b/src/propcache/_helpers_py.py @@ -2,18 +2,7 @@ import sys from functools import cached_property -from typing import ( - Any, - Callable, - Dict, - Generic, - Optional, - Protocol, - Type, - TypeVar, - Union, - overload, -) +from typing import Any, Callable, Generic, Optional, Protocol, TypeVar, Union, overload __all__ = ("under_cached_property", "cached_property") @@ -27,7 +16,7 @@ class _TSelf(Protocol, Generic[_T]): - _cache: Dict[str, _T] + _cache: dict[str, _T] class under_cached_property(Generic[_T]): @@ -46,13 +35,13 @@ def __init__(self, wrapped: Callable[..., _T]) -> None: self.name = wrapped.__name__ @overload - def __get__(self, inst: None, owner: Optional[Type[object]] = None) -> Self: ... + def __get__(self, inst: None, owner: Optional[type[object]] = None) -> Self: ... @overload - def __get__(self, inst: _TSelf[_T], owner: Optional[Type[object]] = None) -> _T: ... + def __get__(self, inst: _TSelf[_T], owner: Optional[type[object]] = None) -> _T: ... def __get__( - self, inst: Optional[_TSelf[_T]], owner: Optional[Type[object]] = None + self, inst: Optional[_TSelf[_T]], owner: Optional[type[object]] = None ) -> Union[_T, Self]: if inst is None: return self diff --git a/tests/conftest.py b/tests/conftest.py index 1963e95..f52513d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,14 +2,11 @@ from dataclasses import dataclass from functools import cached_property from importlib import import_module -from sys import version_info as _version_info from types import ModuleType -from typing import List, Type, Union import pytest C_EXT_MARK = pytest.mark.c_extension -PY_38_AND_BELOW = _version_info < (3, 9) @dataclass(frozen=True) @@ -77,34 +74,19 @@ def pytest_addoption( version of the ``propcache`` implementation. """ del pluginmanager - - arg_parse_action: Union[str, Type[argparse.Action]] - if PY_38_AND_BELOW: - arg_parse_action = "store_true" - else: - arg_parse_action = argparse.BooleanOptionalAction # type: ignore[attr-defined, unused-ignore] # noqa - parser.addoption( "--c-extensions", # disabled with `--no-c-extensions` - action=arg_parse_action, + action=argparse.BooleanOptionalAction, default=True, dest="c_extensions", help="Test C-extensions (on by default)", ) - if PY_38_AND_BELOW: - parser.addoption( - "--no-c-extensions", - action="store_false", - dest="c_extensions", - help="Skip testing C-extensions (on by default)", - ) - def pytest_collection_modifyitems( session: pytest.Session, config: pytest.Config, - items: List[pytest.Item], + items: list[pytest.Item], ) -> None: """Deselect tests against C-extensions when requested via CLI.""" test_c_extensions = config.getoption("--c-extensions") is True @@ -112,8 +94,8 @@ def pytest_collection_modifyitems( if test_c_extensions: return - selected_tests: List[pytest.Item] = [] - deselected_tests: List[pytest.Item] = [] + selected_tests: list[pytest.Item] = [] + deselected_tests: list[pytest.Item] = [] for item in items: c_ext = item.get_closest_marker(C_EXT_MARK.name) is not None diff --git a/tests/test_cached_property.py b/tests/test_cached_property.py index 06cf2a8..a02b023 100644 --- a/tests/test_cached_property.py +++ b/tests/test_cached_property.py @@ -1,5 +1,5 @@ from operator import not_ -from typing import Protocol, Type +from typing import Protocol import pytest @@ -8,7 +8,7 @@ class APIProtocol(Protocol): - cached_property: Type[cached_property] + cached_property: type[cached_property] def test_cached_property(propcache_module: APIProtocol) -> None: diff --git a/tests/test_under_cached_property.py b/tests/test_under_cached_property.py index 4511443..3e9e9d0 100644 --- a/tests/test_under_cached_property.py +++ b/tests/test_under_cached_property.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Protocol, Type +from typing import Any, Protocol import pytest @@ -7,13 +7,13 @@ class APIProtocol(Protocol): - under_cached_property: Type[under_cached_property] + under_cached_property: type[under_cached_property] def test_under_cached_property(propcache_module: APIProtocol) -> None: class A: def __init__(self) -> None: - self._cache: Dict[str, int] = {} + self._cache: dict[str, int] = {} @propcache_module.under_cached_property def prop(self) -> int: @@ -39,7 +39,7 @@ def prop(self) -> None: def test_under_cached_property_assignment(propcache_module: APIProtocol) -> None: class A: def __init__(self) -> None: - self._cache: Dict[str, Any] = {} + self._cache: dict[str, Any] = {} @propcache_module.under_cached_property def prop(self) -> None: @@ -55,7 +55,7 @@ def test_under_cached_property_without_cache(propcache_module: APIProtocol) -> N class A: def __init__(self) -> None: """Init.""" - self._cache: Dict[str, int] = {} + self._cache: dict[str, int] = {} @propcache_module.under_cached_property def prop(self) -> None: @@ -88,7 +88,7 @@ def prop(self) -> None: def test_under_cached_property_caching(propcache_module: APIProtocol) -> None: class A: def __init__(self) -> None: - self._cache: Dict[str, int] = {} + self._cache: dict[str, int] = {} @propcache_module.under_cached_property def prop(self) -> int: