Skip to content

Commit 44e789d

Browse files
authored
Fix module __getattr__ in incremental mode (#5306)
For module `__getattr__` to work correctly in incremental mode, we need to de-serialise potential parent package files during an attempt to find a partial package. Otherwise there will be spurious "Module not found" errors during the second and subsequent runs.
1 parent 9ab6936 commit 44e789d

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

mypy/build.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1870,6 +1870,8 @@ def __init__(self,
18701870
self.dep_line_map = {id: line
18711871
for id, line in zip(all_deps, self.meta.dep_lines)}
18721872
self.child_modules = set(self.meta.child_modules)
1873+
if temporary:
1874+
self.load_tree(temporary=True)
18731875
else:
18741876
# When doing a fine-grained cache load, pretend we only
18751877
# know about modules that have cache information and defer
@@ -1952,16 +1954,16 @@ def load_fine_grained_deps(self) -> None:
19521954
# TODO: Assert deps file wasn't changed.
19531955
self.fine_grained_deps = {k: set(v) for k, v in deps.items()}
19541956

1955-
def load_tree(self) -> None:
1957+
def load_tree(self, temporary: bool = False) -> None:
19561958
assert self.meta is not None, "Internal error: this method must be called only" \
19571959
" for cached modules"
19581960
with open(self.meta.data_json) as f:
19591961
data = json.load(f)
19601962
# TODO: Assert data file wasn't changed.
19611963
self.tree = MypyFile.deserialize(data)
1962-
1963-
self.manager.modules[self.id] = self.tree
1964-
self.manager.add_stats(fresh_trees=1)
1964+
if not temporary:
1965+
self.manager.modules[self.id] = self.tree
1966+
self.manager.add_stats(fresh_trees=1)
19651967

19661968
def fix_cross_refs(self) -> None:
19671969
assert self.tree is not None, "Internal error: method must be called on parsed file only"

test-data/unit/check-incremental.test

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4754,3 +4754,39 @@ def f(): pass
47544754
[file a.py.2]
47554755
[out]
47564756
[out2]
4757+
4758+
[case testModuleGetattrInitIncremental]
4759+
import c
4760+
[file c.py]
4761+
import a.b
4762+
x = a.b.f()
4763+
[file c.py.2]
4764+
import a.b
4765+
x = a.b.f()
4766+
# touch
4767+
[file a/__init__.pyi]
4768+
from typing import Any
4769+
def __getattr__(attr: str) -> Any: ...
4770+
[builtins fixtures/module.pyi]
4771+
[out]
4772+
[out2]
4773+
4774+
[case testModuleGetattrInitIncremental2]
4775+
import c
4776+
[file c.py]
4777+
import a.b.c
4778+
[file c.py.2]
4779+
import a.b.c
4780+
# touch
4781+
[file a/__init__.pyi]
4782+
from typing import Any
4783+
def __getattr__(attr: str) -> Any: ...
4784+
[file a/b.pyi]
4785+
# empty
4786+
[builtins fixtures/module.pyi]
4787+
[out]
4788+
tmp/c.py:1: error: Cannot find module named 'a.b.c'
4789+
tmp/c.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
4790+
[out2]
4791+
tmp/c.py:1: error: Cannot find module named 'a.b.c'
4792+
tmp/c.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)

0 commit comments

Comments
 (0)