Skip to content

Commit

Permalink
Fix inference for attrs.fields
Browse files Browse the repository at this point in the history
Fixes #15393
  • Loading branch information
hauntsaninja committed Jul 16, 2023
1 parent 235a3bb commit ecc00ef
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 2 deletions.
8 changes: 8 additions & 0 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4594,6 +4594,14 @@ def analyze_iterable_item_type(self, expr: Expression) -> tuple[Type, 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 fallback type
proper_iterator = get_proper_type(iterator)
if isinstance(proper_iterator, Instance) and not isinstance(
get_proper_type(proper_iterator.args[0]), AnyType
):
joined = proper_iterator.args[0]

for item in iterable.items:
joined = join_types(joined, item)
return iterator, joined
Expand Down
3 changes: 3 additions & 0 deletions test-data/unit/check-plugin-attrs.test
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
11 changes: 9 additions & 2 deletions test-data/unit/fixtures/plugin_attrs.pyi
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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

0 comments on commit ecc00ef

Please sign in to comment.