From ca6ce8c00e45862a2e08b860d0b28e60dc08b73f Mon Sep 17 00:00:00 2001 From: layday Date: Tue, 16 Aug 2022 08:20:32 +0300 Subject: [PATCH] Use `TypeGuard` for `has` in Python 3.10 and above (#997) * Use `TypeGuard` for `has` in Python 3.10 and above * fixup! Use `TypeGuard` for `has` in Python 3.10 and above * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Test the negative case * Add type guard example Co-authored-by: Hynek Schlawack Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/attr/__init__.pyi | 7 ++++++- tests/test_mypy.yml | 12 ++++++++++++ tests/typing_example.py | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/attr/__init__.pyi b/src/attr/__init__.pyi index 03cc4c82d..42d48e8e6 100644 --- a/src/attr/__init__.pyi +++ b/src/attr/__init__.pyi @@ -27,6 +27,11 @@ from . import validators as validators from ._cmp import cmp_using as cmp_using from ._version_info import VersionInfo +if sys.version_info >= (3, 10): + from typing import TypeGuard +else: + from typing_extensions import TypeGuard + __version__: str __version_info__: VersionInfo __title__: str @@ -470,7 +475,7 @@ def astuple( tuple_factory: Type[Sequence[Any]] = ..., retain_collection_types: bool = ..., ) -> Tuple[Any, ...]: ... -def has(cls: type) -> bool: ... +def has(cls: type) -> TypeGuard[Type[AttrsInstance]]: ... def assoc(inst: _T, **changes: Any) -> _T: ... def evolve(inst: _T, **changes: Any) -> _T: ... diff --git a/tests/test_mypy.yml b/tests/test_mypy.yml index 6759dc1a8..cdbb8e8b3 100644 --- a/tests/test_mypy.yml +++ b/tests/test_mypy.yml @@ -1371,3 +1371,15 @@ b: str fields(A) # E: Argument 1 to "fields" has incompatible type "Type[A]"; expected "Type[AttrsInstance]" + +- case: testHasTypeGuard + main: | + from attrs import define, has + + @define + class A: + pass + + reveal_type(A) # N: Revealed type is "def () -> main.A" + if has(A): + reveal_type(A) # N: Revealed type is "Type[attr.AttrsInstance]" diff --git a/tests/typing_example.py b/tests/typing_example.py index 1c6691f75..c7ff5fb8d 100644 --- a/tests/typing_example.py +++ b/tests/typing_example.py @@ -416,3 +416,9 @@ def accessing_from_attrs() -> None: attrs.setters.frozen attrs.validators.and_ attrs.cmp_using + + +def has_typeguard() -> None: + foo = object + if attrs.has(foo): + foo.__attrs_attrs__