From 5f8fd6a76353fd1bc7b9383c62b3aa4c549d2da3 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Fri, 11 Apr 2025 01:47:28 +0200 Subject: [PATCH 1/3] Traverse module ancestors when traversing reachable graph nodes during dmypy update --- mypy/dmypy_server.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py index d73487efe3bc..37ccd5b09ed1 100644 --- a/mypy/dmypy_server.py +++ b/mypy/dmypy_server.py @@ -756,7 +756,8 @@ def find_reachable_changed_modules( changed.append((nxt.module, nxt.path)) elif nxt.module in graph: state = graph[nxt.module] - for dep in state.dependencies: + ancestors = state.ancestors or [] + for dep in state.dependencies + ancestors: if dep not in seen: seen.add(dep) worklist.append(BuildSource(graph[dep].path, graph[dep].id, followed=True)) From 1e716bbd6c74f16576466afe63a3e15a017ab3ec Mon Sep 17 00:00:00 2001 From: STerliakov Date: Fri, 11 Apr 2025 23:44:22 +0200 Subject: [PATCH 2/3] Add a reproducible testcase. Sorry, I do not see the exact reason why xml.etree.ElementTree is so special --- test-data/unit/daemon.test | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index 7dfddd8f74df..19ffce0927ab 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -647,3 +647,21 @@ b: str from demo.test import a [file demo/test.py] a: int + +[case testDaemonImportAncestors] +$ dmypy run test.py +Daemon started +test.py:2: error: Unsupported operand types for + ("int" and "str") [operator] +Found 1 error in 1 file (checked 1 source file) +== Return code: 1 +$ dmypy run test.py +test.py:2: error: Unsupported operand types for + ("int" and "str") [operator] +Found 1 error in 1 file (checked 1 source file) +== Return code: 1 +$ dmypy run test.py +test.py:2: error: Unsupported operand types for + ("int" and "str") [operator] +Found 1 error in 1 file (checked 1 source file) +== Return code: 1 +[file test.py] +from xml.etree.ElementTree import Element +1 + 'a' From 3734d2727436378f54ff812ae8569307e22e4993 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Fri, 11 Apr 2025 23:53:37 +0200 Subject: [PATCH 3/3] Add a comment to mention `seen` role in deleted modules detection --- mypy/dmypy_server.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py index 37ccd5b09ed1..33e9e07477ca 100644 --- a/mypy/dmypy_server.py +++ b/mypy/dmypy_server.py @@ -620,6 +620,9 @@ def fine_grained_increment_follow_imports( t1 = time.time() manager.log(f"fine-grained increment: find_changed: {t1 - t0:.3f}s") + # Track all modules encountered so far. New entries for all dependencies + # are added below by other module finding methods below. All dependencies + # in graph but not in `seen` are considered deleted at the end of this method. seen = {source.module for source in sources} # Find changed modules reachable from roots (or in roots) already in graph. @@ -736,7 +739,9 @@ def find_reachable_changed_modules( Args: roots: modules where to start search from graph: module graph to use for the search - seen: modules we've seen before that won't be visited (mutated here!!) + seen: modules we've seen before that won't be visited (mutated here!!). + Needed to accumulate all modules encountered during update and remove + everything that no longer exists. changed_paths: which paths have changed (stop search here and return any found) Return (encountered reachable changed modules, @@ -776,7 +781,9 @@ def find_added_suppressed( """Find suppressed modules that have been added (and not included in seen). Args: - seen: reachable modules we've seen before (mutated here!!) + seen: reachable modules we've seen before (mutated here!!). + Needed to accumulate all modules encountered during update and remove + everything that no longer exists. Return suppressed, added modules. """