From 419557282acd6beb4d3342a80f91d126c010a6b4 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 28 Nov 2021 16:52:31 -0800 Subject: [PATCH 1/5] test --- mypy/test/teststubtest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 7275037a9246..cb525ddc2c9d 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -648,7 +648,7 @@ def h(x: str): ... runtime="", error="h", ) - yield Case("", "__all__ = []", None) # dummy case + yield Case(stub="", runtime="__all__ = []", error=None) # dummy case yield Case(stub="", runtime="__all__ += ['y']\ny = 5", error="y") yield Case(stub="", runtime="__all__ += ['g']\ndef g(): pass", error="g") # Here we should only check that runtime has B, since the stub explicitly re-exports it @@ -660,6 +660,7 @@ def h(x: str): ... def test_missing_no_runtime_all(self) -> Iterator[Case]: yield Case(stub="", runtime="import sys", error=None) yield Case(stub="", runtime="def g(): ...", error="g") + yield Case(stub="", runtime="CONSTANT = 0", error="CONSTANT") @collect_cases def test_special_dunders(self) -> Iterator[Case]: From f523170db93eaedc5ab0dbc4731eac772372c3a1 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 28 Nov 2021 17:25:43 -0800 Subject: [PATCH 2/5] test2 --- mypy/test/teststubtest.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index cb525ddc2c9d..8272bf77cf63 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -52,6 +52,8 @@ class bool(int): ... class str: ... class bytes: ... +class list(Sequence[T]): ... + def property(f: T) -> T: ... def classmethod(f: T) -> T: ... def staticmethod(f: T) -> T: ... @@ -662,6 +664,17 @@ def test_missing_no_runtime_all(self) -> Iterator[Case]: yield Case(stub="", runtime="def g(): ...", error="g") yield Case(stub="", runtime="CONSTANT = 0", error="CONSTANT") + @collect_cases + def test_missing_non_public_stub_1(self) -> Iterator[Case]: + yield Case(stub="__all__: list[str]", runtime="", error=None) # dummy case + yield Case(stub="_f: int", runtime="def _f(): ...", error="_f") + + @collect_cases + def test_missing_non_public_stub_2(self) -> Iterator[Case]: + yield Case(stub="__all__: list[str] = ['f']", runtime="__all__ = ['f']", error=None) # dummy case + yield Case(stub="f: int", runtime="def f(): ...", error="f") + yield Case(stub="g: int", runtime="def g(): ...", error="g") + @collect_cases def test_special_dunders(self) -> Iterator[Case]: yield Case( From c93faf8ff71cedc62e2b49e47daf7d930817cd5e Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 28 Nov 2021 16:55:30 -0800 Subject: [PATCH 3/5] fix --- mypy/stubtest.py | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 138f126c9d1a..8492b9bb7600 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -200,23 +200,34 @@ def verify_mypyfile( yield Error(object_path, "is not a module", stub, runtime) return - # Check things in the stub that are public + # Check things in the stub 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)) + if not o.module_hidden 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)) + + def _belongs_to_runtime(attr: str) -> bool: + runtime_attr = getattr(runtime, attr) + runtime_attr_module = getattr(runtime_attr, "__module__", None) + if runtime_attr_module is not None: + return runtime_attr_module == runtime.__name__ + return not isinstance(runtime_attr, types.ModuleType) + + def _runtime_public_contents() -> List[str]: + if hasattr(runtime, "__all__"): + return getattr(runtime, "__all__") + return [ + 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 _belongs_to_runtime(m) + ] + + # Check all things declared in module's __all__, falling back to our best guess + to_check.update(_runtime_public_contents()) to_check.difference_update({"__file__", "__doc__", "__name__", "__builtins__", "__package__"}) for entry in sorted(to_check): From 1adb6e284ad87f743ae09d4d425e45d486a414f1 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 28 Nov 2021 17:42:54 -0800 Subject: [PATCH 4/5] fix lint --- mypy/stubtest.py | 32 ++++++++++++++++---------------- mypy/test/teststubtest.py | 4 +++- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 8492b9bb7600..8fc3efd5936b 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -207,27 +207,27 @@ def verify_mypyfile( if not o.module_hidden and (not m.startswith("_") or hasattr(runtime, m)) ) - def _belongs_to_runtime(attr: str) -> bool: - runtime_attr = getattr(runtime, attr) - runtime_attr_module = getattr(runtime_attr, "__module__", None) - if runtime_attr_module is not None: - return runtime_attr_module == runtime.__name__ - return not isinstance(runtime_attr, types.ModuleType) - - def _runtime_public_contents() -> List[str]: - if hasattr(runtime, "__all__"): - return getattr(runtime, "__all__") - return [ + def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool: + obj = getattr(r, attr) + obj_mod = getattr(obj, "__module__", None) + if obj_mod is not None: + return obj_mod == r.__name__ + return not isinstance(obj, types.ModuleType) + + runtime_public_contents = ( + runtime.__all__ + if hasattr(runtime, "__all__") + else [ 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 _belongs_to_runtime(m) + # 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 _belongs_to_runtime(runtime, m) ] - + ) # Check all things declared in module's __all__, falling back to our best guess - to_check.update(_runtime_public_contents()) + to_check.update(runtime_public_contents) to_check.difference_update({"__file__", "__doc__", "__name__", "__builtins__", "__package__"}) for entry in sorted(to_check): diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 8272bf77cf63..e10343e2f0b3 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -671,7 +671,9 @@ def test_missing_non_public_stub_1(self) -> Iterator[Case]: @collect_cases def test_missing_non_public_stub_2(self) -> Iterator[Case]: - yield Case(stub="__all__: list[str] = ['f']", runtime="__all__ = ['f']", error=None) # dummy case + yield Case( + stub="__all__: list[str] = ['f']", runtime="__all__ = ['f']", error=None + ) yield Case(stub="f: int", runtime="def f(): ...", error="f") yield Case(stub="g: int", runtime="def g(): ...", error="g") From 22d8f5c4cf7178adb62c73df405d0da945844311 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 28 Nov 2021 17:46:28 -0800 Subject: [PATCH 5/5] change test names --- mypy/test/teststubtest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index e10343e2f0b3..e6eb8465c665 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -665,12 +665,12 @@ def test_missing_no_runtime_all(self) -> Iterator[Case]: yield Case(stub="", runtime="CONSTANT = 0", error="CONSTANT") @collect_cases - def test_missing_non_public_stub_1(self) -> Iterator[Case]: + def test_non_public_1(self) -> Iterator[Case]: yield Case(stub="__all__: list[str]", runtime="", error=None) # dummy case yield Case(stub="_f: int", runtime="def _f(): ...", error="_f") @collect_cases - def test_missing_non_public_stub_2(self) -> Iterator[Case]: + def test_non_public_2(self) -> Iterator[Case]: yield Case( stub="__all__: list[str] = ['f']", runtime="__all__ = ['f']", error=None )