diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index df4b2253..4a221a93 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -156,7 +156,6 @@ jobs: - 3.11 - "3.10" - 3.9 - - 3.8 no-extensions: ['', 'Y'] os: [ubuntu, macos, windows] exclude: @@ -169,7 +168,7 @@ jobs: - os: windows pyver: 3.13-freethreading # this is still tested within cibuildwheel include: - - pyver: pypy-3.8 + - pyver: pypy-3.9 no-extensions: Y os: ubuntu fail-fast: false diff --git a/.github/workflows/reusable-linters.yml b/.github/workflows/reusable-linters.yml index 5df7b9ca..5b98b9da 100644 --- a/.github/workflows/reusable-linters.yml +++ b/.github/workflows/reusable-linters.yml @@ -66,9 +66,9 @@ jobs: 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.11/cobertura.xml, .tox/.tmp/.mypy/python-3.9/cobertura.xml, - .tox/.tmp/.mypy/python-3.8/cobertura.xml flags: >- CI-GHA, MyPy diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8ab162d4..84ba292b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -114,7 +114,7 @@ repos: - types-docutils - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - pytest - - pytest_codspeed + - pytest-codspeed == 2.2.1 - Sphinx >= 5.3.0 args: - --python-version=3.13 @@ -122,6 +122,21 @@ repos: - --cobertura-xml-report=.tox/.tmp/.mypy/python-3.13 - --html-report=.tox/.tmp/.mypy/python-3.13 pass_filenames: false + - id: mypy + alias: mypy-py312 + name: MyPy, for Python 3.12 + additional_dependencies: + - types-docutils + - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` + - pytest + - pytest-codspeed == 2.2.1 + - Sphinx >= 5.3.0 + args: + - --python-version=3.12 + - --txt-report=.tox/.tmp/.mypy/python-3.12 + - --cobertura-xml-report=.tox/.tmp/.mypy/python-3.12 + - --html-report=.tox/.tmp/.mypy/python-3.12 + pass_filenames: false - id: mypy alias: mypy-py311 name: MyPy, for Python 3.11 @@ -129,7 +144,7 @@ repos: - types-docutils - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - pytest - - pytest_codspeed + - pytest-codspeed == 2.2.1 - Sphinx >= 5.3.0 args: - --python-version=3.11 @@ -144,7 +159,7 @@ repos: - types-docutils - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - pytest - - pytest_codspeed + - pytest-codspeed == 2.2.1 - Sphinx >= 5.3.0 args: - --python-version=3.9 @@ -152,20 +167,5 @@ repos: - --cobertura-xml-report=.tox/.tmp/.mypy/python-3.9 - --html-report=.tox/.tmp/.mypy/python-3.9 pass_filenames: false - - id: mypy - alias: mypy-py38 - name: MyPy, for Python 3.8 - additional_dependencies: - - types-docutils - - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - - pytest - - pytest_codspeed - - Sphinx >= 5.3.0 - 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 - pass_filenames: false ... diff --git a/CHANGES/1036.breaking.rst b/CHANGES/1036.breaking.rst new file mode 100644 index 00000000..b01af153 --- /dev/null +++ b/CHANGES/1036.breaking.rst @@ -0,0 +1 @@ +Dropped Python 3.8 support as it has reached EOL -- by :user:`bdraco`. diff --git a/multidict/_abc.py b/multidict/_abc.py index 0603cdd2..718f86f9 100644 --- a/multidict/_abc.py +++ b/multidict/_abc.py @@ -1,5 +1,4 @@ import abc -import sys import types from collections.abc import Mapping, MutableMapping @@ -9,15 +8,8 @@ class _TypingMeta(abc.ABCMeta): # basically MultiMapping[str] and other generic-like type instantiations # are emulated. # Note: real type hints are provided by __init__.pyi stub file - if sys.version_info >= (3, 9): - - def __getitem__(self, key): - return types.GenericAlias(self, key) - - else: - - def __getitem__(self, key): - return self + def __getitem__(self, key): + return types.GenericAlias(self, key) class MultiMapping(Mapping, metaclass=_TypingMeta): diff --git a/multidict/_multidict.c b/multidict/_multidict.c index 1507d7b7..100509bd 100644 --- a/multidict/_multidict.c +++ b/multidict/_multidict.c @@ -775,21 +775,13 @@ static inline void multidict_tp_dealloc(MultiDictObject *self) { PyObject_GC_UnTrack(self); -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9 Py_TRASHCAN_BEGIN(self, multidict_tp_dealloc) -#else - Py_TRASHCAN_SAFE_BEGIN(self); -#endif if (self->weaklist != NULL) { PyObject_ClearWeakRefs((PyObject *)self); }; pair_list_dealloc(&self->pairs); Py_TYPE(self)->tp_free((PyObject *)self); -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9 Py_TRASHCAN_END // there should be no code after this -#else - Py_TRASHCAN_SAFE_END(self); -#endif } static inline int @@ -1236,16 +1228,7 @@ PyDoc_STRVAR(multidict_update_doc, "Update the dictionary from *other*, overwriting existing keys."); -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9 #define multidict_class_getitem Py_GenericAlias -#else -static inline PyObject * -multidict_class_getitem(PyObject *self, PyObject *arg) -{ - Py_INCREF(self); - return self; -} -#endif PyDoc_STRVAR(sizeof__doc__, @@ -1947,9 +1930,7 @@ getversion(PyObject *self, PyObject *md) static inline void module_free(void *m) { -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9 Py_CLEAR(multidict_str_lower); -#endif Py_CLEAR(collections_abc_mapping); Py_CLEAR(collections_abc_mut_mapping); Py_CLEAR(collections_abc_mut_multi_mapping); @@ -1978,12 +1959,10 @@ static PyModuleDef multidict_module = { PyMODINIT_FUNC PyInit__multidict(void) { -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9 multidict_str_lower = PyUnicode_InternFromString("lower"); if (multidict_str_lower == NULL) { goto fail; } -#endif PyObject *module = NULL, *reg_func_call_result = NULL; @@ -2122,9 +2101,7 @@ PyInit__multidict(void) return module; fail: -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9 Py_XDECREF(multidict_str_lower); -#endif Py_XDECREF(collections_abc_mapping); Py_XDECREF(collections_abc_mut_mapping); Py_XDECREF(collections_abc_mut_multi_mapping); diff --git a/multidict/_multidict_py.py b/multidict/_multidict_py.py index dc26a3ea..b9e16b09 100644 --- a/multidict/_multidict_py.py +++ b/multidict/_multidict_py.py @@ -7,13 +7,6 @@ _marker = object() -if sys.version_info >= (3, 9): - GenericAlias = types.GenericAlias -else: - - def GenericAlias(cls): - return cls - class istr(str): """Case insensitive str.""" @@ -140,7 +133,7 @@ def __repr__(self): body = ", ".join("'{}': {!r}".format(k, v) for k, v in self.items()) return "<{}({})>".format(self.__class__.__name__, body) - __class_getitem__ = classmethod(GenericAlias) + __class_getitem__ = classmethod(types.GenericAlias) class MultiDictProxy(_Base, MultiMapping): diff --git a/setup.cfg b/setup.cfg index c3b7cab5..7d642fa6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,7 +34,6 @@ classifiers = 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 @@ -42,7 +41,7 @@ classifiers = Programming Language :: Python :: 3.13 [options] -python_requires = >= 3.8 +python_requires = >= 3.9 install_requires = typing-extensions >= 4.1.0; python_version < '3.11' packages = diff --git a/tests/conftest.py b/tests/conftest.py index c7b266d8..77670636 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,6 @@ 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 Callable, Type @@ -14,7 +13,6 @@ from multidict import MultiMapping, MutableMultiMapping C_EXT_MARK = pytest.mark.c_extension -PY_38_AND_BELOW = _version_info < (3, 9) @dataclass(frozen=True) @@ -163,20 +161,12 @@ def pytest_addoption( parser.addoption( "--c-extensions", # disabled with `--no-c-extensions` - action="store_true" if PY_38_AND_BELOW else argparse.BooleanOptionalAction, + 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, diff --git a/tests/test_types.py b/tests/test_types.py index ceaa391e..6d84f72e 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,4 +1,3 @@ -import sys import types import pytest @@ -85,19 +84,6 @@ def test_create_ci_multidict_proxy_from_multidict(multidict_module): multidict_module.CIMultiDictProxy(d) -@pytest.mark.skipif( - sys.version_info >= (3, 9), reason="Python 3.9 uses GenericAlias which is different" -) -def test_generic_exists(multidict_module) -> None: - assert multidict_module.MultiDict[int] is multidict_module.MultiDict - assert multidict_module.MultiDictProxy[int] is multidict_module.MultiDictProxy - assert multidict_module.CIMultiDict[int] is multidict_module.CIMultiDict - assert multidict_module.CIMultiDictProxy[int] is multidict_module.CIMultiDictProxy - - -@pytest.mark.skipif( - sys.version_info < (3, 9), reason="Python 3.9 is required for GenericAlias" -) def test_generic_alias(multidict_module) -> None: assert multidict_module.MultiDict[int] == types.GenericAlias( multidict_module.MultiDict, (int,)