From 12012b2b281f3abcab313af76b29b8d69d7ae153 Mon Sep 17 00:00:00 2001 From: Andrey Rakhmatullin Date: Wed, 16 Oct 2024 13:09:12 +0500 Subject: [PATCH] Add Python 3.13, drop Python 3.8, update tool versions (#32) --- .github/workflows/publish.yml | 2 +- .github/workflows/test.yml | 4 ++-- README.rst | 9 ++++----- andi/typeutils.py | 12 +++--------- setup.py | 4 ++-- tests/test_dataclasses_support.py | 16 ---------------- tests/test_inspect.py | 6 +----- tests/test_plan.py | 9 +-------- tests/test_typeutils.py | 6 +----- tox.ini | 14 +++++++------- 10 files changed, 22 insertions(+), 60 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ee23561..f481791 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,7 +17,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.12' + python-version: '3.13' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ed80c57..31596ef 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 @@ -40,7 +40,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.10'] + python-version: ['3.13'] tox-job: ["mypy", "twinecheck"] steps: diff --git a/README.rst b/README.rst index f302af6..3773d06 100644 --- a/README.rst +++ b/README.rst @@ -34,7 +34,7 @@ Installation pip install andi -andi requires Python >= 3.8.1. +andi requires Python >= 3.9. Goal ==== @@ -402,10 +402,9 @@ Union Annotated --------- -On Python 3.9+ ``Annotated`` type annotations can be used to attach arbitrary -metadata that will be preserved in the plan. Occurrences of the same type -annotated with different metadata will not be considered duplicates. For -example: +``Annotated`` type annotations can be used to attach arbitrary metadata that +will be preserved in the plan. Occurrences of the same type annotated with +different metadata will not be considered duplicates. For example: .. code-block:: python diff --git a/andi/typeutils.py b/andi/typeutils.py index 81353e1..dabb33d 100644 --- a/andi/typeutils.py +++ b/andi/typeutils.py @@ -2,7 +2,7 @@ import inspect import types import functools -from typing import Union, List, Callable, Dict, Container, cast, Type, get_type_hints +from typing import Annotated, Union, List, Callable, Dict, Container, cast, Type, get_args, get_origin, get_type_hints def is_union(tp) -> bool: @@ -23,10 +23,8 @@ def is_union(tp) -> bool: def get_type_hints_with_extras(obj, *args, **kwargs): """ Like get_type_hints, but sets include_extras=True - for Python versions which support Annotated """ - if sys.version_info >= (3, 9): - kwargs["include_extras"] = True + kwargs["include_extras"] = True return get_type_hints(obj, *args, **kwargs) @@ -156,17 +154,13 @@ def get_callable_func_obj(class_or_func: Callable) -> Callable: def is_typing_annotated(o: Callable) -> bool: - """Return True if the input is typing.Annotated and Python is 3.9+""" - if sys.version_info < (3, 9): - return False - from typing import Annotated, get_origin + """Return True if the input is typing.Annotated""" return get_origin(o) == Annotated def strip_annotated(o: Callable) -> Callable: """Return the underlying type for Annotated, the input itself otherwise.""" if is_typing_annotated(o): - from typing import get_args return get_args(o)[0] else: return o diff --git a/setup.py b/setup.py index 6c5b73a..d606052 100755 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ packages=find_packages(exclude=['tests']), package_data={"andi": ["py.typed"]}, zip_safe=False, - python_requires='>=3.8.1', + python_requires='>=3.9', classifiers=[ 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', @@ -21,10 +21,10 @@ 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', ], ) diff --git a/tests/test_dataclasses_support.py b/tests/test_dataclasses_support.py index d42a7c8..aa827e4 100644 --- a/tests/test_dataclasses_support.py +++ b/tests/test_dataclasses_support.py @@ -1,8 +1,3 @@ -import sys -from typing import ForwardRef - -import pytest - import andi from tests.types import ADCnp, BDCnp from tests.types_pep563 import ADC, ADCStrRef, BDC @@ -18,16 +13,5 @@ def test_dataclasses_forward_refs(): assert andi.inspect(ADCnp.__init__) == {'b': [BDCnp]} -@pytest.mark.skipif(sys.version_info >= (3, 9, 0), - reason="Tests pre-3.9 behavior of forward refs.") -def test_dataclasses_py37_str_ref(): - """ String annotations are returned as ForwardRef when - ``from __future__ import annotations`` is used. Just don declare them as string. """ - assert type(andi.inspect(ADCStrRef.__init__)['b'][0]) == ForwardRef - - -@pytest.mark.skipif(sys.version_info < (3, 9, 0), - reason="Dataclasses with string forward references in " - "Python >= 3.9 are resolved as types :-)") def test_dataclasses_py39_str_ref(): assert andi.inspect(ADCStrRef.__init__) == {'b': [BDC]} diff --git a/tests/test_inspect.py b/tests/test_inspect.py index e3db204..72027f8 100644 --- a/tests/test_inspect.py +++ b/tests/test_inspect.py @@ -1,6 +1,5 @@ -import sys from functools import wraps, partial -from typing import Union, Optional, TypeVar, Type +from typing import Union, Optional, TypeVar, Type, Annotated import pytest @@ -136,10 +135,7 @@ def __call__(self, x: Bar): assert andi.inspect(obj) == {'x': [Bar]} -@pytest.mark.skipif(sys.version_info < (3, 9), reason="No Annotated support in Python < 3.9") def test_annotations(): - from typing import Annotated - def f(x: Annotated[int, 42]) -> None: pass diff --git a/tests/test_plan.py b/tests/test_plan.py index 46e3075..aa69af9 100644 --- a/tests/test_plan.py +++ b/tests/test_plan.py @@ -1,6 +1,5 @@ -import sys from functools import partial -from typing import Union, Optional, Dict, Callable +from typing import Union, Optional, Dict, Callable, Annotated import pytest @@ -462,10 +461,7 @@ def test_plan_overrides(recursive_overrides): plan == [(B, {}), (A, {}), (C, {'a': A, 'b': B}), (D, {'a': A, 'c': C})]) -@pytest.mark.skipif(sys.version_info < (3, 9), reason="No Annotated support in Python < 3.9") def test_plan_annotations(): - from typing import Annotated - class MyFunc: def __call__(self, b: Annotated[B, 42]): pass @@ -475,10 +471,7 @@ def __call__(self, b: Annotated[B, 42]): assert plan == [(Annotated[B, 42], {}), (func, {'b': Annotated[B, 42]})] -@pytest.mark.skipif(sys.version_info < (3, 9), reason="No Annotated support in Python < 3.9") def test_plan_annotations_duplicate(): - from typing import Annotated - class MyFunc: def __call__(self, b: Annotated[B, 42], diff --git a/tests/test_typeutils.py b/tests/test_typeutils.py index c643d20..eed3458 100644 --- a/tests/test_typeutils.py +++ b/tests/test_typeutils.py @@ -1,5 +1,4 @@ -import sys -from typing import Union, Optional, get_type_hints +from typing import Union, Optional, get_type_hints, Annotated import pytest @@ -82,10 +81,7 @@ def meth(self): assert get_callable_func_obj(foo) == foo.__call__ -@pytest.mark.skipif(sys.version_info < (3, 9), reason="No Annotated support in Python < 3.9") def test_get_hint_extras(): - from typing import Annotated - def f(x: Annotated[int, 42]) -> None: pass diff --git a/tox.ini b/tox.ini index 932a2a2..edab2f2 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38,py39,py310,py311,py312,mypy,twinecheck +envlist = py39,py310,py311,py312,py313,mypy,twinecheck [testenv] deps = @@ -17,17 +17,17 @@ commands = [testenv:mypy] deps = - mypy==0.971 - types-attrs + mypy==1.11.2 + attrs>=18.2.0 + pytest -commands = mypy --show-error-codes --ignore-missing-imports --no-warn-no-return \ - andi tests +commands = mypy andi tests [testenv:twinecheck] basepython = python3 deps = - twine==4.0.2 - build==1.0.3 + twine==5.1.1 + build==1.2.2 commands = python -m build --sdist twine check dist/*