diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 6c8d03319893..df1ad347a176 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -571,9 +571,23 @@ def verify_typeinfo( # If it came from the metaclass, consider the runtime_attr to be MISSING # for a more accurate message - if runtime_attr is not MISSING and type(runtime) is not runtime: - if getattr(runtime_attr, "__objclass__", None) is type(runtime): - runtime_attr = MISSING + if ( + runtime_attr is not MISSING + and type(runtime) is not runtime + and getattr(runtime_attr, "__objclass__", None) is type(runtime) + ): + runtime_attr = MISSING + + # __setattr__ and __delattr__ on object are a special case, + # so if we only have these methods inherited from there, pretend that + # we don't have them. See python/typeshed#7385. + if ( + entry in ("__setattr__", "__delattr__") + and runtime_attr is not MISSING + and runtime is not object + and getattr(runtime_attr, "__objclass__", None) is object + ): + runtime_attr = MISSING # Do not error for an object missing from the stub # If the runtime object is a types.WrapperDescriptorType object @@ -1081,9 +1095,11 @@ def verify_funcitem( @verify.register(Missing) -def verify_none( +def verify_missing( stub: Missing, runtime: MaybeMissing[Any], object_path: list[str] ) -> Iterator[Error]: + if runtime is MISSING: + return yield Error(object_path, "is not present in stub", stub, runtime) diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index b16cb18ace21..25a992c230be 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -1470,6 +1470,24 @@ def __call__(*args, **kwds): ... runtime="class ClassWithMetaclassOverride: ...", error="ClassWithMetaclassOverride.__call__", ) + # Test that we ignore object.__setattr__ and object.__delattr__ inheritance + yield Case( + stub=""" + from typing import Any + class FakeSetattrClass: + def __setattr__(self, name: str, value: Any, /) -> None: ... + """, + runtime="class FakeSetattrClass: ...", + error="FakeSetattrClass.__setattr__", + ) + yield Case( + stub=""" + class FakeDelattrClass: + def __delattr__(self, name: str, /) -> None: ... + """, + runtime="class FakeDelattrClass: ...", + error="FakeDelattrClass.__delattr__", + ) @collect_cases def test_missing_no_runtime_all(self) -> Iterator[Case]: