Skip to content

Commit fdae42f

Browse files
hauntsaninjaIvan Levkivskyi
authored and
Ivan Levkivskyi
committed
Fix crash involving explicit reexport, import cycle, wildcard (#11632)
Fixes #8481 Fixes #9941 Fixes #11025 Fixes #11038 This is the unresolved crash that's been reported the most times, e.g., it's as easy to repro as `mypy --no-implicit-reexport -c 'import pytorch_lightning'` (or even `import torch`, with the right PyTorch version). I know of multiple popular Python packages that have made changes just to work around this crash. I would love to see this released, potentially along with #11630. Thanks to @rraval for making a minimal repro! The fix ended up being a one-liner, but it took me a bit to track down :-) Since things worked with implicit reexport, I differentially patched in explicit reexport logic to narrow things down. This let me observe that if I hardcoded pkg.a.B to get reexported, we hit this branch, which clobbers the PlaceholderNode for pkg.c.B, which fixes things: https://github.com/python/mypy/blob/f79e7afec2c863c34d7a9b41ebb732dc26128fff/mypy/semanal.py#L2028 Which is a little weird — we shouldn't have a PlaceholderNode for pkg.c.B at all. But with a breakpoint in that branch, it was easy to notice that with `--no-implicit-reexport` pkg.a.B was first created with `module_public=True` (resulting in creation of a PlaceholderNode in pkg.c.B) and only on a later pass acquired `module_public=False`. So tracking down where pkg.a.B symbol was first created with `module_public=True` led me to this "obvious" bug.
1 parent dd086bc commit fdae42f

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

Diff for: mypy/semanal.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1887,7 +1887,9 @@ def report_missing_module_attribute(
18871887
if self.is_incomplete_namespace(import_id):
18881888
# We don't know whether the name will be there, since the namespace
18891889
# is incomplete. Defer the current target.
1890-
self.mark_incomplete(imported_id, context)
1890+
self.mark_incomplete(
1891+
imported_id, context, module_public=module_public, module_hidden=module_hidden
1892+
)
18911893
return
18921894
message = 'Module "{}" has no attribute "{}"'.format(import_id, source_id)
18931895
# Suggest alternatives, if any match is found.

Diff for: test-data/unit/check-incremental.test

+25
Original file line numberDiff line numberDiff line change
@@ -5585,3 +5585,28 @@ bar.x + 0
55855585
x = 0
55865586
[rechecked]
55875587
[stale]
5588+
5589+
[case testExplicitReexportImportCycleWildcard]
5590+
# flags: --no-implicit-reexport
5591+
import pkg.a
5592+
[file pkg/__init__.pyi]
5593+
5594+
[file pkg/a.pyi]
5595+
MYPY = False
5596+
if MYPY:
5597+
from pkg.b import B
5598+
5599+
[file pkg/b.pyi]
5600+
import pkg.a
5601+
MYPY = False
5602+
if MYPY:
5603+
from pkg.c import C
5604+
class B:
5605+
pass
5606+
5607+
[file pkg/c.pyi]
5608+
from pkg.a import *
5609+
class C:
5610+
pass
5611+
[rechecked]
5612+
[stale]

0 commit comments

Comments
 (0)