Skip to content

Commit

Permalink
Fix multiple inheritance false positives in dataclasses and attrs cla…
Browse files Browse the repository at this point in the history
…sses

Multiple inheritance from dataclasses and attrs classes works at runtime,
so don't complain about `__match_args__` or `__attrs_attrs__` which tend
to have incompatible types in subclasses.

Fixes #12349. Fixes #12008. Fixes #12065.
  • Loading branch information
JukkaL committed Mar 21, 2022
1 parent 8427df1 commit 5ed1f00
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 4 deletions.
5 changes: 3 additions & 2 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2103,8 +2103,9 @@ class C(B, A[int]): ... # this is unsafe because...
self.msg.cant_override_final(name, base2.name, ctx)
if is_final_node(first.node):
self.check_if_final_var_override_writable(name, second.node, ctx)
# __slots__ and __deletable__ are special and the type can vary across class hierarchy.
if name in ('__slots__', '__deletable__'):
# Some attributes like __slots__ and __deletable__ are special, and the type can
# vary across class hierarchy.
if name in ('__slots__', '__deletable__', '__match_args__', '__attrs_attrs__'):
ok = True
if not ok:
self.msg.base_class_definitions_incompatible(name, base1, base2,
Expand Down
1 change: 0 additions & 1 deletion mypy/plugins/attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,6 @@ def _add_match_args(ctx: 'mypy.plugin.ClassDefContext',
cls=ctx.cls,
name='__match_args__',
typ=match_args,
final=True,
)


Expand Down
2 changes: 1 addition & 1 deletion mypy/plugins/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def transform(self) -> None:
literals: List[Type] = [LiteralType(attr.name, str_type)
for attr in attributes if attr.is_in_init]
match_args_type = TupleType(literals, ctx.api.named_type("builtins.tuple"))
add_attribute_to_class(ctx.api, ctx.cls, "__match_args__", match_args_type, final=True)
add_attribute_to_class(ctx.api, ctx.cls, "__match_args__", match_args_type)

self._add_dataclass_fields_magic_attribute()

Expand Down
16 changes: 16 additions & 0 deletions test-data/unit/check-attr.test
Original file line number Diff line number Diff line change
Expand Up @@ -1539,3 +1539,19 @@ n: NoMatchArgs
reveal_type(n.__match_args__) # E: "NoMatchArgs" has no attribute "__match_args__" \
# N: Revealed type is "Any"
[builtins fixtures/attr.pyi]

[case testAttrsMultipleInheritance]
# flags: --python-version 3.10
import attr

@attr.s
class A:
x = attr.ib(type=int)

@attr.s
class B:
y = attr.ib(type=int)

class AB(A, B):
pass
[builtins fixtures/attr.pyi]
16 changes: 16 additions & 0 deletions test-data/unit/check-dataclasses.test
Original file line number Diff line number Diff line change
Expand Up @@ -1536,3 +1536,19 @@ A(a=1, b=2)
A(1)
A(a="foo") # E: Argument "a" to "A" has incompatible type "str"; expected "int"
[builtins fixtures/dataclasses.pyi]

[case testDataclassMultipleInheritance]
# flags: --python-version 3.10
from dataclasses import dataclass

@dataclass
class A:
prop_a: str

@dataclass
class B:
prop_b: bool

class Derived(A, B):
pass
[builtins fixtures/dataclasses.pyi]

0 comments on commit 5ed1f00

Please sign in to comment.