From 67d1b265ba8dcd2f65194caf1751f9d916f36ccf Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Fri, 22 Jan 2021 13:43:56 -0800 Subject: [PATCH 1/2] stubtest: import submodules mentioned in __all__ This kind of helps resolve #9935 --- mypy/stubtest.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index aa86b3b887df8..19b0b8758d62a 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -171,6 +171,10 @@ def test_module(module_name: str) -> Iterator[Error]: with warnings.catch_warnings(): warnings.simplefilter("ignore") runtime = importlib.import_module(module_name) + # Also run the equivalent of `from module import *` + # This could have the additional effect of loading not-yet-loaded submodules + # mentioned in __all__ + __import__(module_name, fromlist=["*"]) except Exception as e: yield Error([module_name], "failed to import: {}".format(e), stub, MISSING) return @@ -216,18 +220,18 @@ def verify_mypyfile( m for m in dir(runtime) if not m.startswith("_") - # Ensure that the object's module is `runtime`, e.g. so that we don't pick up reexported - # modules and infinitely recurse. Unfortunately, there's no way to detect an explicit - # reexport missing from the stubs (that isn't specified in __all__) - and getattr(getattr(runtime, m), "__module__", None) == runtime.__name__ ] # Check all things declared in module's __all__, falling back to runtime_public_contents to_check.update(getattr(runtime, "__all__", runtime_public_contents)) to_check.difference_update({"__file__", "__doc__", "__name__", "__builtins__", "__package__"}) for entry in sorted(to_check): + stub_entry = stub.names[entry].node if entry in stub.names else MISSING + if isinstance(stub_entry, nodes.MypyFile): + # Don't recursively check exported modules, since that leads to infinite recursion + continue yield from verify( - stub.names[entry].node if entry in stub.names else MISSING, + stub_entry, getattr(runtime, entry, MISSING), object_path + [entry], ) From f4ee7954e0afd73cb4b1c0fbe215b8f5c0123607 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sat, 23 Jan 2021 11:53:44 -0800 Subject: [PATCH 2/2] fix --- mypy/stubtest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 19b0b8758d62a..3e52eb8be1989 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -214,12 +214,16 @@ def verify_mypyfile( to_check = set( m for m, o in stub.names.items() + # TODO: change `o.module_public` to `not o.module_hidden` if o.module_public and (not m.startswith("_") or hasattr(runtime, m)) ) runtime_public_contents = [ m for m in dir(runtime) if not m.startswith("_") + # Ensure that the object's module is `runtime`, since in the absence of __all__ we don't + # have a good way to detect re-exports at runtime. + and getattr(getattr(runtime, m), "__module__", None) == runtime.__name__ ] # Check all things declared in module's __all__, falling back to runtime_public_contents to_check.update(getattr(runtime, "__all__", runtime_public_contents))