From 6d4bb06217dee863eca798ea292df49b0d579b95 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 15 Jul 2023 19:51:25 -0700 Subject: [PATCH] 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