From 8c81703b158b08142da108e8ae5f54d1601c4be0 Mon Sep 17 00:00:00 2001 From: Ryan Soklaski Date: Sat, 23 Mar 2024 12:22:59 -0400 Subject: [PATCH] drop 3.7, add 3.12, bump pyright --- .github/workflows/tox_run.yml | 6 ++-- .pre-commit-config.yaml | 12 +++---- deps/requirements-pyright.txt | 2 +- pyproject.toml | 23 +++++++------- src/phantom_tensors/_internals/dim_binding.py | 4 +-- src/phantom_tensors/_internals/parse.py | 29 ++++++----------- src/phantom_tensors/_internals/utils.py | 10 +++--- src/phantom_tensors/array.py | 6 ++-- src/phantom_tensors/numpy.py | 3 +- src/phantom_tensors/torch.py | 3 +- tests/annotations.py | 23 +++++--------- tests/arrlike.py | 3 +- tests/test_prototype.py | 31 ++++++++++--------- tests/test_third_party.py | 30 ++++++++---------- tests/test_type_properties.py | 2 +- 15 files changed, 80 insertions(+), 107 deletions(-) diff --git a/.github/workflows/tox_run.yml b/.github/workflows/tox_run.yml index fdd8f40..5ec8f6c 100644 --- a/.github/workflows/tox_run.yml +++ b/.github/workflows/tox_run.yml @@ -19,7 +19,7 @@ jobs: strategy: max-parallel: 5 matrix: - python-version: [3.7, 3.8, 3.9, "3.10", 3.11] + python-version: [3.8, 3.9, "3.10", 3.11, 3.12] fail-fast: false steps: @@ -39,10 +39,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Python 3.9 + - name: Set up Python 3.11 uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index acd5ccb..6026d0a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,15 +1,13 @@ repos: - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 24.3.0 hooks: - id: black -- repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 +- repo: https://github.com/PyCQA/flake8 + rev: 7.0.0 hooks: - id: flake8 - args: [--ignore, "F811,D1,D205,D209,D213,D400,D401,D999,D202,E203,E501,W503,E721,F403,F405", - --exclude, "versioneer.py,docs/*,tests/annotations/*, tests/test_py310.py"] -- repo: https://github.com/pre-commit/mirrors-isort - rev: v5.10.1 +- repo: https://github.com/pycqa/isort + rev: 5.13.2 hooks: - id: isort \ No newline at end of file diff --git a/deps/requirements-pyright.txt b/deps/requirements-pyright.txt index 16e9e95..0e6a7d9 100644 --- a/deps/requirements-pyright.txt +++ b/deps/requirements-pyright.txt @@ -1 +1 @@ -pyright==1.1.309 +pyright==1.1.355 diff --git a/pyproject.toml b/pyproject.toml index 82f24df..e80e9f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,9 +10,9 @@ build-backend = "setuptools.build_meta" [project] name = "phantom_tensors" dynamic = ["version"] -description = "Configurable, reproducible, and scalable workflows in Python, via Hydra" +description = "Tensor-like types – with variadic shapes – that support both static and runtime type checking, and convenient parsing." readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.8" dependencies = ["typing-extensions >= 4.1.0"] license = { text = "MIT" } keywords = [ @@ -37,11 +37,11 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Intended Audience :: Science/Research", - "Programming Language :: Python :: 3.7", "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", "Topic :: Scientific/Engineering", "Programming Language :: Python :: 3 :: Only", ] @@ -121,15 +121,15 @@ skip = 'docs/build/*' legacy_tox_ini = """ [tox] isolated_build = True -envlist = py37, py38, py39, py310, py311 +envlist = py38, py39, py310, py311, py312 [gh-actions] python = - 3.7: py37 3.8: py38 3.9: py39 3.10: py310 3.11: py311 + 3.12: py312 [testenv] description = Runs test suite parallelized in the specified python enviornment and @@ -162,7 +162,7 @@ commands = pytest --cov-report term-missing --cov-config=pyproject.toml --cov-fa description = Runs test suite against optional 3rd party packages that phantom-tensors provides specialized support for. install_command = pip install --upgrade --upgrade-strategy eager {opts} {packages} -basepython = python3.9 +basepython = python3.11 deps = {[testenv]deps} beartype torch @@ -183,10 +183,11 @@ deps = numpy phantom-types -commands = pyright --lib tests/ src/ --pythonversion=3.8 - pyright --lib tests/ src/ --pythonversion=3.9 - pyright --lib tests/ src/ --pythonversion=3.10 - pyright --lib tests/ src/ --pythonversion=3.11 +commands = pyright tests/ src/ --pythonversion=3.8 + pyright tests/ src/ --pythonversion=3.9 + pyright tests/ src/ --pythonversion=3.10 + pyright tests/ src/ --pythonversion=3.11 + pyright tests/ src/ --pythonversion=3.12 pyright --ignoreexternal --verifytypes phantom_tensors @@ -209,7 +210,7 @@ commands = description = Ensures that source materials code and docs and test suite adhere to formatting and code-quality standards. skip_install=true -basepython=python3.9 +basepython=python3.11 deps=black isort flake8 diff --git a/src/phantom_tensors/_internals/dim_binding.py b/src/phantom_tensors/_internals/dim_binding.py index 3bec56a..882b072 100644 --- a/src/phantom_tensors/_internals/dim_binding.py +++ b/src/phantom_tensors/_internals/dim_binding.py @@ -116,7 +116,7 @@ def check(shape_type: Tuple[ShapeDimType, ...], shape: Tuple[int, ...]) -> bool: f"int or subclass of int. shape-type {shape_type} contains a " f"NewType of supertype {_supertype}" ) - validators[dim_symbol] = lambda x, sp=_supertype: isinstance(x, sp) # type: ignore + validators[dim_symbol] = lambda x, sp=_supertype: isinstance(x, sp) _match_list.append(CURRENT_INDEX) del _supertype elif isinstance(dim_symbol, TypeVar): @@ -131,7 +131,7 @@ def check(shape_type: Tuple[ShapeDimType, ...], shape: Tuple[int, ...]) -> bool: del _expected_literals elif isinstance(dim_symbol, type) and issubclass(dim_symbol, int): - validators[dim_symbol] = lambda x, type_=dim_symbol: isinstance(x, type_) # type: ignore + validators[dim_symbol] = lambda x, type_=dim_symbol: isinstance(x, type_) _validate_list.append(CURRENT_INDEX) else: raise TypeError( diff --git a/src/phantom_tensors/_internals/parse.py b/src/phantom_tensors/_internals/parse.py index c2efe4f..fbb5d2d 100644 --- a/src/phantom_tensors/_internals/parse.py +++ b/src/phantom_tensors/_internals/parse.py @@ -33,8 +33,7 @@ class _Phantom(Protocol): class HasShape(Protocol): @property - def shape(self) -> Any: - ... + def shape(self) -> Any: ... TupleInt: TypeAlias = Tuple[int, ...] @@ -127,8 +126,7 @@ def __call__( __d: Tuple[HasShape, Type[S4]], __e: Tuple[HasShape, Type[S5]], __f: Tuple[HasShape, Type[S6]], - ) -> Tuple[S1, S2, S3, S4, S5, S6]: - ... + ) -> Tuple[S1, S2, S3, S4, S5, S6]: ... @overload def __call__( @@ -138,8 +136,7 @@ def __call__( __c: Tuple[HasShape, Type[S3]], __d: Tuple[HasShape, Type[S4]], __e: Tuple[HasShape, Type[S5]], - ) -> Tuple[S1, S2, S3, S4, S5]: - ... + ) -> Tuple[S1, S2, S3, S4, S5]: ... @overload def __call__( @@ -148,8 +145,7 @@ def __call__( __b: Tuple[HasShape, Type[S2]], __c: Tuple[HasShape, Type[S3]], __d: Tuple[HasShape, Type[S4]], - ) -> Tuple[S1, S2, S3, S4]: - ... + ) -> Tuple[S1, S2, S3, S4]: ... @overload def __call__( @@ -157,35 +153,30 @@ def __call__( __a: Tuple[HasShape, Type[S1]], __b: Tuple[HasShape, Type[S2]], __c: Tuple[HasShape, Type[S3]], - ) -> Tuple[S1, S2, S3]: - ... + ) -> Tuple[S1, S2, S3]: ... @overload def __call__( self, __a: HasShape, __b: Type[S1], - ) -> S1: - ... + ) -> S1: ... @overload def __call__( self, __a: Tuple[HasShape, Type[S1]], __b: Tuple[HasShape, Type[S2]], - ) -> Tuple[S1, S2]: - ... + ) -> Tuple[S1, S2]: ... @overload - def __call__(self, __a: Tuple[HasShape, Type[S1]]) -> S1: - ... + def __call__(self, __a: Tuple[HasShape, Type[S1]]) -> S1: ... @overload def __call__( self, *tensor_type_pairs: Tuple[HasShape, Type[HasShape]] | HasShape | Type[HasShape], - ) -> HasShape | Tuple[HasShape, ...]: - ... + ) -> HasShape | Tuple[HasShape, ...]: ... @dim_binding_scope def __call__( @@ -198,7 +189,7 @@ def __call__( tensor_type_pairs = (tensor_type_pairs,) # type: ignore pairs = cast( - Tuple[Tuple[HasShape, Type[HasShape]], ...], _to_tuple(tensor_type_pairs) + Tuple[Tuple[HasShape, Type[HasShape]], ...], _to_tuple(tensor_type_pairs) # type: ignore ) out: List[HasShape] = [] diff --git a/src/phantom_tensors/_internals/utils.py b/src/phantom_tensors/_internals/utils.py index e19373c..ba20331 100644 --- a/src/phantom_tensors/_internals/utils.py +++ b/src/phantom_tensors/_internals/utils.py @@ -20,22 +20,20 @@ class NewTypeLike(Protocol): __name__: str __supertype__: Type[Any] - def __call__(self, x: Any) -> int: - ... + def __call__(self, x: Any) -> int: ... class NewTypeInt(Protocol): __name__: str __supertype__: Type[int] - def __call__(self, x: Any) -> int: - ... + def __call__(self, x: Any) -> int: ... class UnpackLike(Protocol): _inst: Literal[True] _name: Literal[None] - __origin__: Type[Any] = Unpack + __origin__: Type[Any] = Unpack # type: ignore __args__: Tuple[TypeVarTuple] __parameters__: Tuple[TypeVarTuple] __module__: str @@ -44,7 +42,7 @@ class UnpackLike(Protocol): class LiteralLike(Protocol): _inst: Literal[True] _name: Literal[None] - __origin__: Type[Any] = Literal + __origin__: Type[Any] = Literal # type: ignore __args__: Tuple[Any, ...] __parameters__: Tuple[()] __module__: str diff --git a/src/phantom_tensors/array.py b/src/phantom_tensors/array.py index 513cb67..35d86bd 100644 --- a/src/phantom_tensors/array.py +++ b/src/phantom_tensors/array.py @@ -12,9 +12,7 @@ @runtime_checkable class SupportsArray(Protocol[_te.Unpack[Shape]]): - def __array__(self) -> Any: - ... + def __array__(self) -> Any: ... @property - def shape(self) -> Tuple[_te.Unpack[Shape]]: - ... + def shape(self) -> Tuple[_te.Unpack[Shape]]: ... diff --git a/src/phantom_tensors/numpy.py b/src/phantom_tensors/numpy.py index 240d286..923a7cb 100644 --- a/src/phantom_tensors/numpy.py +++ b/src/phantom_tensors/numpy.py @@ -49,5 +49,4 @@ def shape(self) -> Tuple[_te.Unpack[Shape]]: # type: ignore ... @shape.setter - def shape(self, value: Union[SupportsIndex, Sequence[SupportsIndex]]) -> None: - ... + def shape(self, value: Union[SupportsIndex, Sequence[SupportsIndex]]) -> None: ... diff --git a/src/phantom_tensors/torch.py b/src/phantom_tensors/torch.py index a32dc62..a5af082 100644 --- a/src/phantom_tensors/torch.py +++ b/src/phantom_tensors/torch.py @@ -19,8 +19,7 @@ Shape = _te.TypeVarTuple("Shape") -class _NewMeta(CustomInstanceCheck, type(_Tensor)): - ... +class _NewMeta(CustomInstanceCheck, type(_Tensor)): ... class Tensor(Generic[_te.Unpack[Shape]], _Tensor): diff --git a/tests/annotations.py b/tests/annotations.py index befc61e..25d41f5 100644 --- a/tests/annotations.py +++ b/tests/annotations.py @@ -110,14 +110,11 @@ def check_readme2(): from phantom_tensors.alphabet import A, B # these are just NewType(..., int) types from phantom_tensors.numpy import NDArray - def func_on_2d(x: NDArray[Any, Any]): - ... + def func_on_2d(x: NDArray[Any, Any]): ... - def func_on_3d(x: NDArray[Any, Any, Any]): - ... + def func_on_3d(x: NDArray[Any, Any, Any]): ... - def func_on_any_arr(x: np.ndarray[Any, Any]): - ... + def func_on_any_arr(x: np.ndarray[Any, Any]): ... if sys.version_info < (3, 8): return @@ -203,11 +200,9 @@ def check_readme4(): assert_type(t2, Tensor[B]) assert_type(w, Tensor[A]) - def vanilla_numpy(x: np.ndarray[Any, Any]): - ... + def vanilla_numpy(x: np.ndarray[Any, Any]): ... - def vanilla_torch(x: tr.Tensor): - ... + def vanilla_torch(x: tr.Tensor): ... vanilla_numpy(arr) # type checker: OK vanilla_torch(t1) # type checker: OK @@ -218,13 +213,12 @@ def check_phantom_example(): from typing import Any import torch as tr - from phantom import Phantom + from phantom import Phantom from phantom_tensors import parse from phantom_tensors.torch import Tensor - class EvenOnly(int, Phantom[Any], predicate=lambda x: x % 2 == 0): - ... + class EvenOnly(int, Phantom[Any], predicate=lambda x: x % 2 == 0): ... assert_type(parse(tr.ones(1, 0), Tensor[int, EvenOnly]), Tensor[int, EvenOnly]) assert_type(parse(tr.ones(1, 2), Tensor[int, EvenOnly]), Tensor[int, EvenOnly]) @@ -255,8 +249,7 @@ def matrix_multiply(x: Tensor[A, B], y: Tensor[B, C]) -> Tensor[A, C]: return parse(tr.rand(a, c), Tensor[A, C]) @beartype - def needs_vector(x: Tensor[Any]): - ... + def needs_vector(x: Tensor[Any]): ... x, y = parse( (tr.rand(3, 4), Tensor[A, B]), diff --git a/tests/arrlike.py b/tests/arrlike.py index 3bb117c..583831c 100644 --- a/tests/arrlike.py +++ b/tests/arrlike.py @@ -10,8 +10,7 @@ def __init__(self, shape: Tuple[int, ...]) -> None: def shape(self) -> Tuple[int, ...]: return self._shape - def __array__(self) -> Any: - ... + def __array__(self) -> Any: ... def arr(*shape: int) -> ImplementsArray: diff --git a/tests/test_prototype.py b/tests/test_prototype.py index 280dd80..cd24cce 100644 --- a/tests/test_prototype.py +++ b/tests/test_prototype.py @@ -13,6 +13,7 @@ T = TypeVar("T") Ts = TypeVarTuple("Ts") + A = NewType("A", int) B = NewType("B", int) C = NewType("C", int) @@ -29,28 +30,28 @@ def test_parse_error_msg(): ParseError, match=re.escape("shape-(2, 1) doesn't match shape-type ([...], A=2, A=2)"), ): - parse(arr(2, 1), Array[U[Ts], A, A]) + parse(arr(2, 1), Array[U[Ts], A, A]) # type: ignore @pytest.mark.parametrize( "tensor_type_pairs", [ # (arr(), Array[()]), - (arr(), Array[U[Ts]]), + (arr(), Array[U[Ts]]), # type: ignore (arr(2), Array[A]), (arr(2), Array[int]), (arr(2), Array[Any]), - (arr(2), Array[U[Ts]]), - (arr(2), Array[U[Ts], A]), - (arr(2), Array[A, U[Ts]]), + (arr(2), Array[U[Ts]]), # type: ignore + (arr(2), Array[U[Ts], A]), # type: ignore + (arr(2), Array[A, U[Ts]]), # type: ignore (arr(2, 2), Array[A, A]), - (arr(2, 2), Array[U[Ts], A, A]), - (arr(2, 2), Array[A, U[Ts], A]), - (arr(2, 2), Array[A, A, U[Ts]]), - (arr(1, 3, 2, 2), Array[U[Ts], A, A]), - (arr(2, 1, 3, 2), Array[A, U[Ts], A]), - (arr(2, 2, 1, 3), Array[A, A, U[Ts]]), - (arr(1, 2, 1, 3, 2), Array[A, B, U[Ts], B]), + (arr(2, 2), Array[U[Ts], A, A]), # type: ignore + (arr(2, 2), Array[A, U[Ts], A]), # type: ignore + (arr(2, 2), Array[A, A, U[Ts]]), # type: ignore + (arr(1, 3, 2, 2), Array[U[Ts], A, A]), # type: ignore + (arr(2, 1, 3, 2), Array[A, U[Ts], A]), # type: ignore + (arr(2, 2, 1, 3), Array[A, A, U[Ts]]), # type: ignore + (arr(1, 2, 1, 3, 2), Array[A, B, U[Ts], B]), # type: ignore (arr(1, 2, 3), Array[Any, Any, Any]), (arr(1, 2, 3), Array[int, int, int]), (arr(2, 1, 2), Array[A, B, A]), @@ -64,12 +65,12 @@ def test_parse_error_msg(): (arr(1, 2), Array[L[1], L[2]]), (arr(1, 2, 1), Array[L[1], L[2], L[1]]), param((arr(), Array[int]), marks=parse_xfail), - param((arr(), Array[int, U[Ts]]), marks=parse_xfail), + param((arr(), Array[int, U[Ts]]), marks=parse_xfail), # type: ignore param((arr(2), Array[int, int]), marks=parse_xfail), param((arr(2, 4), Array[A, A]), marks=parse_xfail), param((arr(2, 1, 1), Array[A, B, A]), marks=parse_xfail), param((arr(1, 1, 2), Array[A, A, A]), marks=parse_xfail), - param((arr(2, 1, 1), Array[A, U[Ts], A]), marks=parse_xfail), + param((arr(2, 1, 1), Array[A, U[Ts], A]), marks=parse_xfail), # type: ignore param((arr(1), Array[A, B, C]), marks=parse_xfail), param(((arr(2, 4), Array[A, A]),), marks=parse_xfail), param( @@ -157,7 +158,7 @@ def test_parse_bind_multiple(): Array[AStr], Array[str], Array[int, str], - Array[U[Ts], str], + Array[U[Ts], str], # type: ignore ], ) def test_bad_type_validation(bad_type): diff --git a/tests/test_third_party.py b/tests/test_third_party.py index 332d429..4b695bb 100644 --- a/tests/test_third_party.py +++ b/tests/test_third_party.py @@ -9,9 +9,9 @@ BeartypeCallHintParamViolation, BeartypeCallHintReturnViolation, ) -from phantom import Phantom from typing_extensions import TypeVarTuple, Unpack as U +from phantom import Phantom from phantom_tensors import dim_binding_scope, parse from phantom_tensors.alphabet import A, B, C from phantom_tensors.array import SupportsArray as Array @@ -24,16 +24,13 @@ Ts = TypeVarTuple("Ts") -class One_to_Three(int, Phantom, predicate=lambda x: 0 < x < 4): - ... +class One_to_Three(int, Phantom, predicate=lambda x: 0 < x < 4): ... -class Ten_or_Eleven(int, Phantom, predicate=lambda x: 10 <= x <= 11): - ... +class Ten_or_Eleven(int, Phantom, predicate=lambda x: 10 <= x <= 11): ... -class EvenOnly(int, Phantom, predicate=lambda x: x % 2 == 0): - ... +class EvenOnly(int, Phantom, predicate=lambda x: x % 2 == 0): ... NewOneToThree = NewType("NewOneToThree", One_to_Three) @@ -65,10 +62,10 @@ def test_Tensor(): (arr(10, 2, 10), Array[One_to_Three, int, Ten_or_Eleven]), (arr(10, 2, 10), Array[NewOneToThree, int, Ten_or_Eleven]), (arr(2, 2, 8), Array[NewOneToThree, int, Ten_or_Eleven]), - (arr(0, 10), Array[One_to_Three, U[Ts], Ten_or_Eleven]), - (arr(2, 2, 0), Array[One_to_Three, U[Ts], Ten_or_Eleven]), - (arr(2, 0, 0, 0), Array[One_to_Three, U[Ts], Ten_or_Eleven]), - (arr(0, 0, 2, 0), Array[U[Ts], One_to_Three, Ten_or_Eleven]), + (arr(0, 10), Array[One_to_Three, U[Ts], Ten_or_Eleven]), # type: ignore + (arr(2, 2, 0), Array[One_to_Three, U[Ts], Ten_or_Eleven]), # type: ignore + (arr(2, 0, 0, 0), Array[One_to_Three, U[Ts], Ten_or_Eleven]), # type: ignore + (arr(0, 0, 2, 0), Array[U[Ts], One_to_Three, Ten_or_Eleven]), # type: ignore ], ) def test_parse_inconsistent_types(tensor_type_pairs): @@ -124,8 +121,7 @@ def matrix_multiply(x: Tensor[A, B], y: Tensor[B, C]) -> Tensor[A, C]: return cast(Tensor[A, C], tr.ones(a, c)) @beartype - def needs_vector(x: Tensor[int]): - ... + def needs_vector(x: Tensor[int]): ... x, y = parse( (tr.ones(3, 4), Tensor[A, B]), @@ -182,11 +178,11 @@ def test_isinstance_works(): "tensor_type_pairs", [ (arr(2, 2, 10), Array[One_to_Three, int, Ten_or_Eleven]), - (arr(2, 10), Array[One_to_Three, U[Ts], Ten_or_Eleven]), - (arr(2, 2, 10), Array[One_to_Three, U[Ts], Ten_or_Eleven]), - (arr(2, 0, 0, 10), Array[One_to_Three, U[Ts], Ten_or_Eleven]), + (arr(2, 10), Array[One_to_Three, U[Ts], Ten_or_Eleven]), # type: ignore + (arr(2, 2, 10), Array[One_to_Three, U[Ts], Ten_or_Eleven]), # type: ignore + (arr(2, 0, 0, 10), Array[One_to_Three, U[Ts], Ten_or_Eleven]), # type: ignore (arr(2, 2, 10), Array[NewOneToThree, int, Ten_or_Eleven]), - (arr(0, 0, 2, 11), Array[U[Ts], One_to_Three, Ten_or_Eleven]), + (arr(0, 0, 2, 11), Array[U[Ts], One_to_Three, Ten_or_Eleven]), # type: ignore ], ) def test_parse_consistent_types(tensor_type_pairs): diff --git a/tests/test_type_properties.py b/tests/test_type_properties.py index 09e347a..74c54d5 100644 --- a/tests/test_type_properties.py +++ b/tests/test_type_properties.py @@ -29,7 +29,7 @@ def test_literals_can_check_by_identity(a: Tuple[int, ...], b: Tuple[int, ...]): def test_literal_hashes_consistently(): - assert {Literal[1]: 1}[Literal[1]] == 1 + assert {Literal[1]: 1}[Literal[1]] == 1 # type: ignore assert hash(Literal[1, 2]) == hash(Literal[1, 2])