Skip to content

Commit a1a74fe

Browse files
authored
Fix import following issue in daemon (#10032)
A special case for dealing with blocking errors caused false positives when following imports. Narrowed down the special casing to only trigger when there is blocking errors. The logic is still quite convoluted, but at least this fixes some issues with following imports to stub packages. Fixes #10022.
1 parent 82dd59e commit a1a74fe

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

mypy/server/update.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -232,15 +232,17 @@ def update(self,
232232
self.manager.log_fine_grained('previous targets with errors: %s' %
233233
sorted(self.previous_targets_with_errors))
234234

235+
blocking_error = None
235236
if self.blocking_error:
236237
# Handle blocking errors first. We'll exit as soon as we find a
237238
# module that still has blocking errors.
238239
self.manager.log_fine_grained('existing blocker: %s' % self.blocking_error[0])
239240
changed_modules = dedupe_modules([self.blocking_error] + changed_modules)
241+
blocking_error = self.blocking_error[0]
240242
self.blocking_error = None
241243

242244
while True:
243-
result = self.update_one(changed_modules, initial_set, removed_set)
245+
result = self.update_one(changed_modules, initial_set, removed_set, blocking_error)
244246
changed_modules, (next_id, next_path), blocker_messages = result
245247

246248
if blocker_messages is not None:
@@ -289,9 +291,10 @@ def trigger(self, target: str) -> List[str]:
289291
def update_one(self,
290292
changed_modules: List[Tuple[str, str]],
291293
initial_set: Set[str],
292-
removed_set: Set[str]) -> Tuple[List[Tuple[str, str]],
293-
Tuple[str, str],
294-
Optional[List[str]]]:
294+
removed_set: Set[str],
295+
blocking_error: Optional[str]) -> Tuple[List[Tuple[str, str]],
296+
Tuple[str, str],
297+
Optional[List[str]]]:
295298
"""Process a module from the list of changed modules.
296299
297300
Returns:
@@ -303,9 +306,17 @@ def update_one(self,
303306
"""
304307
t0 = time.time()
305308
next_id, next_path = changed_modules.pop(0)
306-
if next_id not in self.previous_modules and next_id not in initial_set:
307-
self.manager.log_fine_grained('skip %r (module not in import graph)' % next_id)
309+
310+
# If we have a module with a blocking error that is no longer
311+
# in the import graph, we must skip it as otherwise we'll be
312+
# stuck with the blocking error.
313+
if (next_id == blocking_error
314+
and next_id not in self.previous_modules
315+
and next_id not in initial_set):
316+
self.manager.log_fine_grained(
317+
'skip %r (module with blocking error not in import graph)' % next_id)
308318
return changed_modules, (next_id, next_path), None
319+
309320
result = self.update_module(next_id, next_path, next_id in removed_set)
310321
remaining, (next_id, next_path), blocker_messages = result
311322
changed_modules = [(id, path) for id, path in changed_modules

test-data/unit/fine-grained-follow-imports.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,3 +719,23 @@ def f() -> None: pass
719719
[out]
720720
==
721721
main.py:2: error: Too many arguments for "f"
722+
723+
[case testFollowImportsNormalMultipleImportedModulesSpecialCase]
724+
# flags: --follow-imports=normal
725+
# cmd: mypy main.py
726+
727+
[file main.py]
728+
import pkg
729+
730+
[file pkg/__init__.py.2]
731+
from . import mod1
732+
733+
[file pkg/mod1.py.2]
734+
from . import mod2
735+
736+
[file pkg/mod2.py.2]
737+
738+
[out]
739+
main.py:1: error: Cannot find implementation or library stub for module named "pkg"
740+
main.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
741+
==

0 commit comments

Comments
 (0)