Skip to content

Commit b3d4398

Browse files
authored
stubtest: fix false negative with dunder methods, small changes (#8886)
* stubtest: use stub.name over runtime.__name__ Seems to be a little more reliable * stubtest: remove unnecessary code I can no longer repro any of the behaviour related to distutils.command. I found one case it can come up involving builtins, but overall I think this code is just simpler like this. * stubtest: fix false negatives If the stub doesn't list dunder methods, we wouldn't check them earlier. There are a lot of false negatives due to this. * teststubtest: add a test for the previous commit Also covers some of the MRO logic in verify_typeinfo Co-authored-by: hauntsaninja <>
1 parent 10195b8 commit b3d4398

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

mypy/stubtest.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,11 @@ def verify_typeinfo(
237237
return
238238

239239
to_check = set(stub.names)
240+
dunders_to_check = ("__init__", "__new__", "__call__")
240241
# cast to workaround mypyc complaints
241-
to_check.update(m for m in cast(Any, vars)(runtime) if not m.startswith("_"))
242+
to_check.update(
243+
m for m in cast(Any, vars)(runtime) if m in dunders_to_check or not m.startswith("_")
244+
)
242245

243246
for entry in sorted(to_check):
244247
mangled_entry = entry
@@ -254,7 +257,7 @@ def verify_typeinfo(
254257
def _verify_static_class_methods(
255258
stub: nodes.FuncItem, runtime: types.FunctionType, object_path: List[str]
256259
) -> Iterator[str]:
257-
if runtime.__name__ == "__new__":
260+
if stub.name == "__new__":
258261
# Special cased by Python, so never declared as staticmethod
259262
return
260263
if inspect.isbuiltin(runtime):
@@ -662,15 +665,6 @@ def verify_funcitem(
662665
def verify_none(
663666
stub: Missing, runtime: MaybeMissing[Any], object_path: List[str]
664667
) -> Iterator[Error]:
665-
if isinstance(runtime, Missing):
666-
try:
667-
# We shouldn't really get here since that would involve something not existing both in
668-
# the stub and the runtime, however, some modules like distutils.command have some
669-
# weird things going on. Try to see if we can find a runtime object by importing it,
670-
# otherwise crash.
671-
runtime = importlib.import_module(".".join(object_path))
672-
except ImportError:
673-
raise RuntimeError
674668
yield Error(object_path, "is not present in stub", stub, runtime)
675669

676670

mypy/test/teststubtest.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,38 @@ def __mangle_bad(self, text): pass
588588
error="X.__mangle_bad"
589589
)
590590

591+
@collect_cases
592+
def test_mro(self) -> Iterator[Case]:
593+
yield Case(
594+
stub="""
595+
class A:
596+
def foo(self, x: int) -> None: ...
597+
class B(A):
598+
pass
599+
class C(A):
600+
pass
601+
""",
602+
runtime="""
603+
class A:
604+
def foo(self, x: int) -> None: ...
605+
class B(A):
606+
def foo(self, x: int) -> None: ...
607+
class C(A):
608+
def foo(self, y: int) -> None: ...
609+
""",
610+
error="C.foo"
611+
)
612+
yield Case(
613+
stub="""
614+
class X: ...
615+
""",
616+
runtime="""
617+
class X:
618+
def __init__(self, x): pass
619+
""",
620+
error="X.__init__"
621+
)
622+
591623

592624
def remove_color_code(s: str) -> str:
593625
return re.sub("\\x1b.*?m", "", s) # this works!

0 commit comments

Comments
 (0)