Skip to content

Commit

Permalink
Fix module __getattr__ in incremental mode (#5306)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ilevkivskyi authored Jul 3, 2018
1 parent 9ab6936 commit 44e789d
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
10 changes: 6 additions & 4 deletions mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,8 @@ def __init__(self,
self.dep_line_map = {id: line
for id, line in zip(all_deps, self.meta.dep_lines)}
self.child_modules = set(self.meta.child_modules)
if temporary:
self.load_tree(temporary=True)
else:
# When doing a fine-grained cache load, pretend we only
# know about modules that have cache information and defer
Expand Down Expand Up @@ -1952,16 +1954,16 @@ def load_fine_grained_deps(self) -> None:
# TODO: Assert deps file wasn't changed.
self.fine_grained_deps = {k: set(v) for k, v in deps.items()}

def load_tree(self) -> None:
def load_tree(self, temporary: bool = False) -> None:
assert self.meta is not None, "Internal error: this method must be called only" \
" for cached modules"
with open(self.meta.data_json) as f:
data = json.load(f)
# TODO: Assert data file wasn't changed.
self.tree = MypyFile.deserialize(data)

self.manager.modules[self.id] = self.tree
self.manager.add_stats(fresh_trees=1)
if not temporary:
self.manager.modules[self.id] = self.tree
self.manager.add_stats(fresh_trees=1)

def fix_cross_refs(self) -> None:
assert self.tree is not None, "Internal error: method must be called on parsed file only"
Expand Down
36 changes: 36 additions & 0 deletions test-data/unit/check-incremental.test
Original file line number Diff line number Diff line change
Expand Up @@ -4754,3 +4754,39 @@ def f(): pass
[file a.py.2]
[out]
[out2]

[case testModuleGetattrInitIncremental]
import c
[file c.py]
import a.b
x = a.b.f()
[file c.py.2]
import a.b
x = a.b.f()
# touch
[file a/__init__.pyi]
from typing import Any
def __getattr__(attr: str) -> Any: ...
[builtins fixtures/module.pyi]
[out]
[out2]

[case testModuleGetattrInitIncremental2]
import c
[file c.py]
import a.b.c
[file c.py.2]
import a.b.c
# touch
[file a/__init__.pyi]
from typing import Any
def __getattr__(attr: str) -> Any: ...
[file a/b.pyi]
# empty
[builtins fixtures/module.pyi]
[out]
tmp/c.py:1: error: Cannot find module named 'a.b.c'
tmp/c.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
[out2]
tmp/c.py:1: error: Cannot find module named 'a.b.c'
tmp/c.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)

0 comments on commit 44e789d

Please sign in to comment.