From 6d4bb06217dee863eca798ea292df49b0d579b95 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 15 Jul 2023 19:51:25 -0700 Subject: [PATCH 1/3] Fix inference for attrs.fields Fixes #15393 --- mypy/checker.py | 7 +++++++ test-data/unit/check-plugin-attrs.test | 3 +++ test-data/unit/fixtures/plugin_attrs.pyi | 11 +++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 5ed1c792778b..298b0a6a4b8d 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4592,8 +4592,15 @@ def analyze_iterable_item_type(self, expr: Expression) -> tuple[Type, Type]: if int_type: return iterator, int_type + if isinstance(iterable, TupleType): joined: Type = UninhabitedType() + if iterable.partial_fallback.type.fullname != "builtins.tuple": + # If we're some fancier tuple variant, join with the item type + item_type = echk.check_method_call_by_name("__next__", iterator, [], [], expr)[0] + if not isinstance(get_proper_type(item_type), AnyType): + joined = item_type + for item in iterable.items: joined = join_types(joined, item) return iterator, joined diff --git a/test-data/unit/check-plugin-attrs.test b/test-data/unit/check-plugin-attrs.test index 3d1e2d730af8..5a64d4aadef8 100644 --- a/test-data/unit/check-plugin-attrs.test +++ b/test-data/unit/check-plugin-attrs.test @@ -1570,6 +1570,9 @@ reveal_type(f(A)[0]) # N: Revealed type is "attr.Attribute[builtins.int]" reveal_type(f(A).b) # N: Revealed type is "attr.Attribute[builtins.int]" f(A).x # E: "____main___A_AttrsAttributes__" has no attribute "x" +for ff in f(A): + reveal_type(ff) # N: Revealed type is "attr.Attribute[Any]" + [builtins fixtures/plugin_attrs.pyi] [case testAttrsGenericFields] diff --git a/test-data/unit/fixtures/plugin_attrs.pyi b/test-data/unit/fixtures/plugin_attrs.pyi index f62104809e74..57e5ecd1b2bc 100644 --- a/test-data/unit/fixtures/plugin_attrs.pyi +++ b/test-data/unit/fixtures/plugin_attrs.pyi @@ -1,5 +1,5 @@ # Builtins stub used to support attrs plugin tests. -from typing import Union, overload +from typing import Union, overload, Generic, Sequence, TypeVar, Type, Iterable, Iterator class object: def __init__(self) -> None: pass @@ -24,6 +24,13 @@ class complex: class str: pass class ellipsis: pass -class tuple: pass class list: pass class dict: pass + +T = TypeVar("T") +Tco = TypeVar('Tco', covariant=True) +class tuple(Sequence[Tco], Generic[Tco]): + def __new__(cls: Type[T], iterable: Iterable[Tco] = ...) -> T: ... + def __iter__(self) -> Iterator[Tco]: pass + def __contains__(self, item: object) -> bool: pass + def __getitem__(self, x: int) -> Tco: pass From 8e2297e203711e84062e81f2613ca4372bbf577f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 16 Jul 2023 02:57:46 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/checker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 298b0a6a4b8d..c7910b6d723f 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4592,7 +4592,6 @@ def analyze_iterable_item_type(self, expr: Expression) -> tuple[Type, Type]: if int_type: return iterator, int_type - if isinstance(iterable, TupleType): joined: Type = UninhabitedType() if iterable.partial_fallback.type.fullname != "builtins.tuple": From 623f01f49ec32c7a126d3c9ef853f78e6b5601af Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 29 Jul 2023 14:16:42 -0700 Subject: [PATCH 3/3] code review --- mypy/checker.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index c7910b6d723f..2a9fdcb375ac 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4592,14 +4592,11 @@ def analyze_iterable_item_type(self, expr: Expression) -> tuple[Type, Type]: if int_type: return iterator, int_type - if isinstance(iterable, TupleType): + if ( + isinstance(iterable, TupleType) + and iterable.partial_fallback.type.fullname == "builtins.tuple" + ): joined: Type = UninhabitedType() - if iterable.partial_fallback.type.fullname != "builtins.tuple": - # If we're some fancier tuple variant, join with the item type - item_type = echk.check_method_call_by_name("__next__", iterator, [], [], expr)[0] - if not isinstance(get_proper_type(item_type), AnyType): - joined = item_type - for item in iterable.items: joined = join_types(joined, item) return iterator, joined