diff --git a/mypy/plugins/attrs.py b/mypy/plugins/attrs.py index b7b3821576ea..86dc27cb72d0 100644 --- a/mypy/plugins/attrs.py +++ b/mypy/plugins/attrs.py @@ -1022,7 +1022,7 @@ def add_method( ) -def _get_attrs_init_type(typ: Instance) -> CallableType | None: +def _get_attrs_init_type(typ: Instance) -> CallableType | None | AnyType: """ If `typ` refers to an attrs class, get the type of its initializer method. """ @@ -1030,9 +1030,18 @@ def _get_attrs_init_type(typ: Instance) -> CallableType | None: if magic_attr is None or not magic_attr.plugin_generated: return None init_method = typ.type.get_method("__init__") or typ.type.get_method(ATTRS_INIT_NAME) - if not isinstance(init_method, FuncDef) or not isinstance(init_method.type, CallableType): + if init_method is None: return None - return init_method.type + + # case 1: normal FuncDef + if isinstance(init_method, FuncDef) and isinstance(init_method.type, CallableType): + return init_method.type + + # case 2: overloaded method + if isinstance(init_method, OverloadedFuncDef) and isinstance(init_method.type, Overloaded): + return AnyType(TypeOfAny.special_form) + + return None def _fail_not_attrs_class(ctx: mypy.plugin.FunctionSigContext, t: Type, parent_t: Type) -> None: @@ -1086,6 +1095,8 @@ def _get_expanded_attr_types( if init_func is None: _fail_not_attrs_class(ctx, display_typ, parent_typ) return None + if isinstance(init_func, AnyType): + return None init_func = expand_type_by_instance(init_func, typ) # [1:] to skip the self argument of AttrClass.__init__ field_names = cast(list[str], init_func.arg_names[1:]) diff --git a/test-data/unit/check-plugin-attrs.test b/test-data/unit/check-plugin-attrs.test index 6415b5104296..1375329add31 100644 --- a/test-data/unit/check-plugin-attrs.test +++ b/test-data/unit/check-plugin-attrs.test @@ -31,8 +31,10 @@ class A: reveal_type(A) # N: Revealed type is "def (a: builtins.int, b: builtins.list[builtins.int], c: builtins.str =, d: builtins.int =) -> __main__.A" A(1, [2]) A(1, [2], '3', 4) -A(1, 2, 3, 4) # E: Argument 2 to "A" has incompatible type "int"; expected "list[int]" # E: Argument 3 to "A" has incompatible type "int"; expected "str" +A(1, 2, 3, 4) # E: Argument 2 to "A" has incompatible type "int"; expected "list[int]" \ + # E: Argument 3 to "A" has incompatible type "int"; expected "str" A(1, [2], '3', 4, 5) # E: Too many arguments for "A" + [builtins fixtures/list.pyi] [case testAttrsTypeComments] @@ -49,8 +51,10 @@ class A: reveal_type(A) # N: Revealed type is "def (a: builtins.int, b: builtins.list[builtins.int], c: builtins.str =, d: builtins.int =) -> __main__.A" A(1, [2]) A(1, [2], '3', 4) -A(1, 2, 3, 4) # E: Argument 2 to "A" has incompatible type "int"; expected "list[int]" # E: Argument 3 to "A" has incompatible type "int"; expected "str" +A(1, 2, 3, 4) # E: Argument 2 to "A" has incompatible type "int"; expected "list[int]" \ + # E: Argument 3 to "A" has incompatible type "int"; expected "str" A(1, [2], '3', 4, 5) # E: Too many arguments for "A" + [builtins fixtures/list.pyi] [case testAttrsAutoAttribs] @@ -67,8 +71,10 @@ class A: reveal_type(A) # N: Revealed type is "def (a: builtins.int, b: builtins.list[builtins.int], c: builtins.str =, d: builtins.int =) -> __main__.A" A(1, [2]) A(1, [2], '3', 4) -A(1, 2, 3, 4) # E: Argument 2 to "A" has incompatible type "int"; expected "list[int]" # E: Argument 3 to "A" has incompatible type "int"; expected "str" +A(1, 2, 3, 4) # E: Argument 2 to "A" has incompatible type "int"; expected "list[int]" \ + # E: Argument 3 to "A" has incompatible type "int"; expected "str" A(1, [2], '3', 4, 5) # E: Too many arguments for "A" + [builtins fixtures/list.pyi] [case testAttrsUntypedNoUntypedDefs] @@ -1577,7 +1583,9 @@ takes_attrs_cls(A) takes_attrs_instance(A(1, "")) takes_attrs_cls(A(1, "")) # E: Argument 1 to "takes_attrs_cls" has incompatible type "A"; expected "type[AttrsInstance]" -takes_attrs_instance(A) # E: Argument 1 to "takes_attrs_instance" has incompatible type "type[A]"; expected "AttrsInstance" # N: ClassVar protocol member AttrsInstance.__attrs_attrs__ can never be matched by a class object +takes_attrs_instance(A) # E: Argument 1 to "takes_attrs_instance" has incompatible type "type[A]"; expected "AttrsInstance" \ + # N: ClassVar protocol member AttrsInstance.__attrs_attrs__ can never be matched by a class object + [builtins fixtures/plugin_attrs.pyi] [case testAttrsFields] @@ -2496,3 +2504,29 @@ Parent(run_type = None) c = Child(run_type = None) reveal_type(c.run_type) # N: Revealed type is "Union[builtins.int, None]" [builtins fixtures/plugin_attrs.pyi] + +[case testAttrsInitOverload] +# flags: --python-version 3.10 +from typing import overload + +import attrs + +@attrs.frozen(init=False) +class C: + x: "int | str" + + @overload + def __init__(self, x: int) -> None: ... + + @overload + def __init__(self, x: str) -> None: ... + + def __init__(self, x: "int | str") -> None: + self.__attrs_init__(x) + + +obj = C(1) +attrs.evolve(obj, x=1, y=1) +attrs.evolve(obj, x=[]) +attrs.evolve(obj, x="1") +[builtins fixtures/plugin_attrs.pyi]
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: