From 129ba7712571834d68d72aa3e973fb09f51d9005 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 30 Oct 2022 18:01:27 -0700 Subject: [PATCH] Preserve (some) implicitly exported types Fixes some of #13965 We also need to modify attribute access logic (this is the TODO in the PR), which is a little trickier. But cases like #13933 convinced me it's worth making this change, even before I get around to figuring that out. --- mypy/semanal.py | 28 ++++++++++++++++++++-------- test-data/unit/check-flags.test | 13 +++++++++---- test-data/unit/check-modules.test | 2 +- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index b8f708b22a92..3a2caab41d3a 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2303,10 +2303,20 @@ def visit_import_from(self, imp: ImportFrom) -> None: ) continue - if node and not node.module_hidden: + if node: self.process_imported_symbol( node, module_id, id, imported_id, fullname, module_public, context=imp ) + if node.module_hidden: + self.report_missing_module_attribute( + module_id, + id, + imported_id, + module_public=module_public, + module_hidden=not module_public, + context=imp, + add_unknown_imported_symbol=False, + ) elif module and not missing_submodule: # Target module exists but the imported name is missing or hidden. self.report_missing_module_attribute( @@ -2394,6 +2404,7 @@ def report_missing_module_attribute( module_public: bool, module_hidden: bool, context: Node, + add_unknown_imported_symbol: bool = True, ) -> None: # Missing attribute. if self.is_incomplete_namespace(import_id): @@ -2418,13 +2429,14 @@ def report_missing_module_attribute( suggestion = f"; maybe {pretty_seq(matches, 'or')}?" message += f"{suggestion}" self.fail(message, context, code=codes.ATTR_DEFINED) - self.add_unknown_imported_symbol( - imported_id, - context, - target_name=None, - module_public=module_public, - module_hidden=not module_public, - ) + if add_unknown_imported_symbol: + self.add_unknown_imported_symbol( + imported_id, + context, + target_name=None, + module_public=module_public, + module_hidden=not module_public, + ) if import_id == "typing": # The user probably has a missing definition in a test fixture. Let's verify. diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 5a075dd6efef..33723b7fee76 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -1606,14 +1606,19 @@ strict_equality = false [case testNoImplicitReexport] -# flags: --no-implicit-reexport -from other_module_2 import a +# flags: --no-implicit-reexport --show-error-codes +from other_module_2 import a # E: Module "other_module_2" does not explicitly export attribute "a" [attr-defined] +reveal_type(a) # N: Revealed type is "builtins.int" + +import other_module_2 +# TODO: this should also reveal builtins.int, see #13965 +reveal_type(other_module_2.a) # E: "object" does not explicitly export attribute "a" [attr-defined] \ + # N: Revealed type is "Any" + [file other_module_1.py] a = 5 [file other_module_2.py] from other_module_1 import a -[out] -main:2: error: Module "other_module_2" does not explicitly export attribute "a" [case testNoImplicitReexportRespectsAll] # flags: --no-implicit-reexport diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index a8eced3959e5..0b64daaf5abe 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -1794,7 +1794,7 @@ from stub import C c = C() reveal_type(c.x) # N: Revealed type is "builtins.int" it: Iterable[int] -reveal_type(it) # N: Revealed type is "Any" +reveal_type(it) # N: Revealed type is "typing.Iterable[builtins.int]" [file stub.pyi] from typing import Iterable