diff --git a/mypy/subtypes.py b/mypy/subtypes.py index d9c1b47c317f..10e9ecddaf04 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1581,7 +1581,6 @@ def get_member_flags(name: str, itype: Instance, class_obj: bool = False) -> set """ info = itype.type method = info.get_method(name) - setattr_meth = info.get_method("__setattr__") if method: if isinstance(method, Decorator): if method.var.is_staticmethod or method.var.is_classmethod: @@ -1592,7 +1591,11 @@ def get_member_flags(name: str, itype: Instance, class_obj: bool = False) -> set assert isinstance(method, OverloadedFuncDef) dec = method.items[0] assert isinstance(dec, Decorator) - if dec.var.is_settable_property or setattr_meth: + if ( + dec.var.is_settable_property + or (setattr_meth := info.get_method("__setattr__")) + and (setattr_meth.info.fullname != "builtins.object") + ): flags = {IS_VAR, IS_SETTABLE} if dec.var.setter_type is not None: flags.add(IS_EXPLICIT_SETTER) @@ -1602,7 +1605,9 @@ def get_member_flags(name: str, itype: Instance, class_obj: bool = False) -> set return set() # Just a regular method node = info.get(name) if not node: - if setattr_meth: + if (setattr_meth := info.get_method("__setattr__")) and ( + setattr_meth.info.fullname != "builtins.object" + ): return {IS_SETTABLE} if itype.extra_attrs and name in itype.extra_attrs.attrs: flags = set() diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 75a0dfe2f5f4..1ccb664e8755 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -1228,6 +1228,32 @@ x = C(42) y = CF(42) # E: Incompatible types in assignment (expression has type "CF", variable has type "P") \ # N: Protocol member P.x expected settable variable, got read-only attribute +[case testDeletablePropertyProtocolWithSetattr] +from typing import Protocol + +class P(Protocol): + attr: int + +class Deletable: + @property + def attr(self) -> int: + return 1 + @attr.deleter + def attr(self) -> None: + pass + +class Settable(Deletable): + def __setattr__(self, name: str, value: int) -> None: + pass + +def consume(value: P) -> None: + pass + +consume(Deletable()) # E: Argument 1 to "consume" has incompatible type "Deletable"; expected "P" \ + # N: Protocol member P.attr expected settable variable, got read-only attribute +consume(Settable()) +[builtins fixtures/property.pyi] + [case testStaticAndClassMethodsInProtocols] from typing import Protocol, Type, TypeVar