Skip to content

Commit da4796a

Browse files
authored
More robust fix for re-export of __all__ (#20487)
This allows to re-enable one test skipped in parallel mode. The previous solution for re-export of `__all__` (see #10382) didn't work on incremental runs (see added test).
1 parent 29766b2 commit da4796a

File tree

3 files changed

+39
-3
lines changed

3 files changed

+39
-3
lines changed

mypy/semanal.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ def __init__(
494494
self.incomplete_namespaces = incomplete_namespaces
495495
self.all_exports: list[str] = []
496496
# Map from module id to list of explicitly exported names (i.e. names in __all__).
497+
# This is used by stubgen/stubtest, DO NOT use for any other purposes as it is
498+
# not populated on incremental runs (nor in parallel mode).
497499
self.export_map: dict[str, list[str]] = {}
498500
self.plugin = plugin
499501
# If True, process function definitions. If False, don't. This is used
@@ -2967,8 +2969,13 @@ def visit_import_from(self, imp: ImportFrom) -> None:
29672969
# precedence, but doesn't seem to be important in most use cases.
29682970
node = SymbolTableNode(GDEF, self.modules[fullname])
29692971
else:
2970-
if id == as_id == "__all__" and module_id in self.export_map:
2971-
self.all_exports[:] = self.export_map[module_id]
2972+
if id == as_id == "__all__":
2973+
# For modules with __all__ public status of symbols is determined uniquely
2974+
# by contents of __all__, so we can recover the latter here, and avoid
2975+
# serializing this (redundant) information in MypyFile.
2976+
self.all_exports[:] = [
2977+
name for name, sym in module.names.items() if sym.module_public
2978+
]
29722979
node = module.names.get(id)
29732980

29742981
missing_submodule = False

test-data/unit/check-incremental.test

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7635,3 +7635,32 @@ def wrong() -> int:
76357635
main:2: error: Missing return statement
76367636
[out2]
76377637
{"file": "main", "line": 2, "column": 0, "message": "Missing return statement", "hint": null, "code": "return", "severity": "error"}
7638+
7639+
[case testReExportAllInStubIncremental]
7640+
from m1 import C
7641+
from m1 import D
7642+
C()
7643+
C(1)
7644+
[file m1.pyi]
7645+
from m2 import *
7646+
[file m2.pyi]
7647+
from m3 import *
7648+
from m3 import __all__ as __all__
7649+
class D: pass
7650+
[file m2.pyi.2]
7651+
from m3 import *
7652+
from m3 import __all__ as __all__
7653+
class D:
7654+
x = 1
7655+
[file m3.pyi]
7656+
from m4 import C as C
7657+
__all__ = ['C']
7658+
[file m4.pyi]
7659+
class C: pass
7660+
[builtins fixtures/list.pyi]
7661+
[out]
7662+
main:2: error: Module "m1" has no attribute "D"
7663+
main:4: error: Too many arguments for "C"
7664+
[out2]
7665+
main:2: error: Module "m1" has no attribute "D"
7666+
main:4: error: Too many arguments for "C"

test-data/unit/check-modules.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2960,7 +2960,7 @@ class Some:
29602960
name = __name__
29612961
reveal_type(Some.name) # N: Revealed type is "builtins.str"
29622962

2963-
[case testReExportAllInStub_no_parallel]
2963+
[case testReExportAllInStub]
29642964
from m1 import C
29652965
from m1 import D # E: Module "m1" has no attribute "D"
29662966
C()

0 commit comments

Comments
 (0)