diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 510658c..52d84ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,15 +14,11 @@ jobs: os: [ubuntu-latest] python-version: [ - 3.8, - 3.9, "3.10", "3.11", "3.12", "3.13", "3.14", - "pypy3.8", - "pypy3.9", "pypy3.10", "pypy3.11", ] diff --git a/CHANGES b/CHANGES index 31c0456..ae5df99 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ Injector Change Log =================== +0.25.0 +------ + +- Dropped support for Python 3.8 and 3.9. Python 3.10+ is now required. + 0.24.0 ------ diff --git a/README.md b/README.md index db4a131..1b81f96 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ The core values of Injector are: * Documentation: https://injector.readthedocs.org * Change log: https://injector.readthedocs.io/en/latest/changelog.html -Injector works with CPython 3.8+ and PyPy 3 implementing Python 3.8+. +Injector works with CPython 3.10+ and PyPy 3 implementing Python 3.10+. A Quick Example --------------- diff --git a/docs/index.rst b/docs/index.rst index 4d993de..0673a40 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -21,7 +21,7 @@ PyPI (installable, stable distributions): https://pypi.org/project/injector. You pip install injector -Injector works with CPython 3.6+ and PyPy 3 implementing Python 3.6+. +Injector works with CPython 3.10+ and PyPy 3 implementing Python 3.10+. Introduction ------------ diff --git a/injector/__init__.py b/injector/__init__.py index 705ad44..55f7ab2 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -24,7 +24,6 @@ from abc import ABCMeta, abstractmethod from dataclasses import dataclass from typing import ( - TYPE_CHECKING, Any, Callable, Collection, @@ -45,24 +44,7 @@ overload, ) -try: - from typing import NoReturn -except ImportError: - from typing_extensions import NoReturn - -# This is a messy, type-wise, because we not only have two potentially conflicting imports here -# The easiest way to make mypy happy here is to tell it the versions from typing_extensions are -# canonical. Since this typing_extensions import is only for mypy it'll work even without -# typing_extensions actually installed so all's good. -if TYPE_CHECKING: - from typing_extensions import Annotated, _AnnotatedAlias, get_type_hints -else: - # Ignoring errors here as typing_extensions stub doesn't know about those things yet - try: - from typing import Annotated, _AnnotatedAlias, get_type_hints - except ImportError: - from typing_extensions import Annotated, _AnnotatedAlias, get_type_hints - +from typing import Annotated, NoReturn, _AnnotatedAlias, get_type_hints # type: ignore[attr-defined] __author__ = 'Alec Thomas ' __version__ = '0.24.0' @@ -108,7 +90,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: InjectT = TypeVar('InjectT') Inject = Annotated[InjectT, _inject_marker] """An experimental way to declare injectable dependencies utilizing a `PEP 593`_ implementation -in Python 3.9 and backported to Python 3.7+ in `typing_extensions`. +in Python 3.9. Those two declarations are equivalent:: @@ -136,19 +118,18 @@ def fun(t: Inject[SomeType], s: SomeOtherType) -> None: A way to inspect how various injection declarations interact with each other. .. versionadded:: 0.18.0 -.. note:: Requires Python 3.7+. +.. note:: Requires Python 3.9+. .. note:: If you're using mypy you need the version 0.750 or newer to fully type-check code using this construct. .. _PEP 593: https://www.python.org/dev/peps/pep-0593/ -.. _typing_extensions: https://pypi.org/project/typing-extensions/ """ NoInject = Annotated[InjectT, _noinject_marker] """An experimental way to declare noninjectable dependencies utilizing a `PEP 593`_ implementation -in Python 3.9 and backported to Python 3.7+ in `typing_extensions`. +in Python 3.9. Since :func:`inject` declares all function's parameters to be injectable there needs to be a way to opt out of it. This has been provided by :func:`noninjectable` but `noninjectable` suffers from @@ -175,14 +156,13 @@ def fun(a: TypeA, b: NoInject[TypeB]) -> None: A way to inspect how various injection declarations interact with each other. .. versionadded:: 0.18.0 -.. note:: Requires Python 3.7+. +.. note:: Requires Python 3.9+. .. note:: If you're using mypy you need the version 0.750 or newer to fully type-check code using this construct. .. _PEP 593: https://www.python.org/dev/peps/pep-0593/ -.. _typing_extensions: https://pypi.org/project/typing-extensions/ """ @@ -791,13 +771,7 @@ def _ensure_iterable(item_or_list: Union[T, List[T]]) -> List[T]: def _punch_through_alias(type_: Any) -> type: - if ( - sys.version_info < (3, 10) - and getattr(type_, '__qualname__', '') == 'NewType..new_type' - or sys.version_info >= (3, 10) - and type(type_).__module__ == 'typing' - and type(type_).__name__ == 'NewType' - ): + if type(type_).__module__ == 'typing' and type(type_).__name__ == 'NewType': return type_.__supertype__ elif isinstance(type_, _AnnotatedAlias) and getattr(type_, '__metadata__', None) is not None: return type_.__origin__ diff --git a/injector_test.py b/injector_test.py index 9ee3f35..917f34e 100644 --- a/injector_test.py +++ b/injector_test.py @@ -11,7 +11,6 @@ """Functional tests for the "Injector" dependency injection framework.""" import abc -import sys import threading import traceback import warnings @@ -19,10 +18,7 @@ from dataclasses import dataclass from typing import Any, Literal, NewType, Optional, Union -if sys.version_info >= (3, 9): - from typing import Annotated -else: - from typing_extensions import Annotated +from typing import Annotated from typing import Dict, List, NewType @@ -2031,7 +2027,6 @@ def function(a: Inject[Inject[int]]) -> None: # Tests https://github.com/alecthomas/injector/issues/202 -@pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10+") def test_get_bindings_for_pep_604(): @inject def function1(a: int | None) -> None: @@ -2255,7 +2250,6 @@ def provide_second(self) -> Annotated[str, 'second']: # Test for https://github.com/alecthomas/injector/issues/303 -@pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10+") def test_can_inject_dataclass_with_literal_value(): @dataclass(slots=True) class ServiceConfig: diff --git a/pyproject.toml b/pyproject.toml index 23fca96..a865d61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,4 @@ [tool.black] line-length = 110 -target_version = ['py36', 'py37'] +target_version = ['py310'] skip_string_normalization = true diff --git a/requirements-dev.in b/requirements-dev.in index dbe389d..1be0253 100644 --- a/requirements-dev.in +++ b/requirements-dev.in @@ -11,4 +11,3 @@ pytest-cov>=2.5.1 mypy;implementation_name=="cpython" black;implementation_name=="cpython" check-manifest -typing_extensions>=3.7.4;python_version<"3.9" diff --git a/requirements-dev.txt b/requirements-dev.txt index 1ba6dd7..e24fcdc 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,20 +1,45 @@ -black==24.3.0 ; implementation_name == "cpython" +# This file was autogenerated by uv via the following command: +# uv pip compile requirements-dev.in --output-file requirements-dev.txt +black==26.3.1 + # via -r requirements-dev.in build==1.0.3 + # via check-manifest check-manifest==0.49 + # via -r requirements-dev.in click==8.1.7 -coverage[toml]==7.3.2 -exceptiongroup==1.2.0 -importlib-metadata==7.0.0 + # via black +coverage==7.3.2 + # via pytest-cov iniconfig==2.0.0 -mypy==1.7.1 ; implementation_name == "cpython" + # via pytest +mypy==1.7.1 + # via -r requirements-dev.in mypy-extensions==1.0.0 + # via + # black + # mypy packaging==25.0 -pathspec==0.12.1 + # via + # black + # build + # pytest +pathspec==1.0.4 + # via black platformdirs==4.1.0 + # via black pluggy==1.3.0 + # via pytest pyproject-hooks==1.0.0 + # via build pytest==7.4.3 + # via + # -r requirements-dev.in + # pytest-cov pytest-cov==4.1.0 -tomli==2.0.1 -typing-extensions==4.9.0 ; python_version < "3.9" -zipp==3.19.1 + # via -r requirements-dev.in +pytokens==0.4.1 + # via black +setuptools==82.0.1 + # via check-manifest +typing-extensions==4.15.0 + # via mypy diff --git a/requirements.txt b/requirements.txt index bcc17af..e69de29 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +0,0 @@ -typing_extensions>=3.7.4;python_version<"3.9" diff --git a/setup.py b/setup.py index af17271..558ae56 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,6 @@ import sys import warnings - warnings.filterwarnings("always", module=__name__)