Repository navigation
Make --no-implicit-reexport friendlier #13965
Copy link
Copy link
Closed
Labels
Description
Currently, users have to pay double jeopardy if they rely on an implicit reexport. First, they get an error "module does not explicitly export attribute [attr-defined]", but then the type of the thing also becomes Any.
I think it would be friendlier to have mypy just use the type of the hidden thing. This is useful in cases where you can't change the module you're importing from. In some cases, you can have a per-module implicit_reexport config (although I'd argue most users would struggle to find that solution), but in some "consenting adults" situations this isn't quite what you want.
Here's what the patch could look like for the semanal portion of this (edit: merged!). We'd also need to modify attribute access logic.
Details
diff --git a/mypy/semanal.py b/mypy/semanal.py
index b37c9b2a5..06d648a16 100644
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -2242,10 +2242,20 @@ class SemanticAnalyzer(
)
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(
@@ -2333,6 +2343,7 @@ class SemanticAnalyzer(
module_public: bool,
module_hidden: bool,
context: Node,
+ add_unknown_imported_symbol: bool = True,
) -> None:
# Missing attribute.
if self.is_incomplete_namespace(import_id):
@@ -2357,13 +2368,14 @@ class SemanticAnalyzer(
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 5a075dd6e..9beffd2f9 100644
--- a/test-data/unit/check-flags.test
+++ b/test-data/unit/check-flags.test
@@ -1606,14 +1606,18 @@ 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
+reveal_type(other_module_2.a) # E: "object" does not explicitly export attribute "a" [attr-defined] \
+ # N: Revealed type is "builtins.int"
+
[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
Reactions are currently unavailable
Activity
erictraut commentedon Oct 30, 2022
This is the same thought process we went through in pyright. In earlier versions, all implicitly re-exported symbols from a "py.typed" library evaluated to
Unknown(which is what pyright calls an implicitAny). Pyright users and library authors complained about this behavior, so we modified it to work the way that you're proposing above. The imported type is now resolved to its hidden type, but an error is emitted indicating that it is a private symbol.JelleZijlstra commentedon Oct 30, 2022
#13933 is a good example of the perils of the current behavior. I agree with your suggestion.
Preserve (some) implicitly exported types
Preserve (some) implicitly exported types (#13967)
emirkmo commentedon Nov 16, 2022
Out of curiosity, is it a recent behavior that
--implicit-reexportdoes not work onfrom .<file> import <attr>. It says not explictly exported even though I would low to ignore that.hauntsaninja commentedon Nov 16, 2022
@emirkmo please file a separate issue with details about what you're doing
Preserve implicitly exported types via attribute access
Preserve implicitly exported types via attribute access (#16129)