packaging on enriched-metadata [!⇡] via 🐍 v3.11.4 (.venv)
❯ PYTHONPATH=/mnt/c/Users/brcan/.vscode-insiders/extensions/ms-python.mypy-type-checker-2023.1.11921011/bundled/libs /hom
e/brettcannon/Repositories/pypa/packaging/.venv/bin/python -m mypy --no-color-output --no-error-summary --show-absolute-p
ath --show-column-numbers --show-error-code --no-pretty --follow-imports=normal --show-error-end /home/brettcannon/Reposi
tories/pypa/packaging/src/packaging/metadata.py
/home/brettcannon/Repositories/pypa/packaging/src/packaging/metadata.py:303:18:303:24: error: Item "None" of "list[Any] | None" has no attribute "__iter__" (not iterable) [union-attr]
/home/brettcannon/Repositories/pypa/packaging/src/packaging/metadata.py:604:5:624:86: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
⏎
packaging on enriched-metadata [+⇡] via 🐍 v3.11.4 (.venv)
❯ PYTHONPATH=/mnt/c/Users/brcan/.vscode-insiders/extensions/ms-python.mypy-type-checker-2023.1.11921011/bundled/libs
/home/brettcannon/Repositories/pypa/packaging/.venv/bin/python -m mypy.dmypy --status-file /tmp/.vscode.dmypy_statu
s/status-55f8413f-94ce-437f-9911-110647253f9d.json run -- --no-color-output --no-error-summary --show-absolute-path
--show-column-numbers --show-error-code --no-pretty --follow-imports=normal --show-error-end /home/brettcannon/Repos
itories/pypa/packaging/src/packaging/metadata.py
packaging on enriched-metadata [+⇡] via 🐍 v3.11.4 (.venv)
To Reproduce
See above.
Expected Behavior
Issues reported by mypy to also be reported by dmypy.
I think I have found the underlying cause, though I am not sure what the correct solution is. I tested, and adding --follow-imports=skip makes this issue disappear, but is not helpful if you do want to follow imports in general. I may be over-explaining the issue here, but hopefully it can help fix it.
Test project setup (was using an existing project when I came across the issue):
Main test file: /Users/cpnielsen/code/jsonnotate/jsonnotate/base.py
I tested both with entire code base and individual "base.py" as input to the following command:
poetry run python -m mypy.dmypy --status-file test.json run -- --no-color-output --no-error-summary --show-absolute-path --show-column-numbers --show-error-code --no-pretty --show-error-end [input]
I also tested this by activating the virtualenv and running it without poetry run, same results
In the initial run when the daemon loads, it does a full build (calling mypy.build.build) and caching it using the FineGrainedManager for later updates. Running it repeatedly without file updates just returns a cached response and does not reveal the issue. Changing any affected file(s), invalidating the cache, causes all errors to disappear for the changed file.
When run with --follow-imports=normal (the default), the dmypy_server.Server.fine_grained_increment_follow_imports method handles the heavy lifting. It has the side-effect that all changed modules are marked as followed (all calls to fine_grained_manager.update is given followed = True.
The calls from there are: FineGrainedManager.update -> FineGrainedManager.update_one -> FineGrainedManager.update_module-> update_module_isolated. Here it creates a new 1-item BuildSource list, with followed=True (passed down the call chain). It then removes the given module from the graph and calls load_graph with the single source and the old graph and an empty list of new modules.
Root cause
At this point a State instance is created with the module name ("id"), path, source, and crucially root_source=not bs.followed (bs being the BuildSource). When it is initialised, we hit the error where it sets ignore_all to True, which makes all errors for the file disappear.
In my case, this is the mix of things causing this:
The source is given with an absolute path (ie. /Users/cpnielsen/code/jsonnotate/jsonnotate/base.py)
The SearchPaths.package_path includes the project folder (/Users/cpnielsen/code/jsonnotate). It seems poetry install adds the project folder to sys.path, which in turn causes it to be included in the package_path list.
The source is marked as followed, even though it is what you would call a "root source".
In short, mypy marks it as a "silently imported module that is not a root source" and instructs it to ignore all errors.
It looks like this was discovered and fixed in this PR previously: #14060.
Note: I am not sure what the cause is for @karthiknadig as he is using relative paths, but I can only assume it's related.
Suggested fix
It seems like the initial section of fine_grained_increment_follow_imports need to detect changed modules that match the input sources, and update them with followed=False initially, and then the remaining modules (if any) from find_reachable_changed_modules can be updated with followed=True. However, I am not sure of the exact implications, so hopefully someone more knowledgable can pitch in.
@JukkaL You did the initial fix, I hope this might make sense to you and that you might have a good idea of how this could be fixed. It is breaking the mypy-type-checker in VS Code currently (it always passes in files with their absolute path, so it breaks for any Poetry projects at least), which is how I discovered this issue.
Reacted by Brett Cannon, richteaclue, Shantanu, Paul Rademacher, Ivan Desiatov, Peter Yu, Guillaume Desforges and Kai Zhang
Still running into this one, any updates? We're also using Poetry and it adds the project folder to sys.path, which in turn causes it to be included in the package_path list.
As of 1.18, this now crashes. Crash bisects to #15043
File "/Users/shantanu/dev/mypy/mypy/server/update.py", line 671, in update_module_isolated
state.generate_unused_ignore_notes()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/Users/shantanu/dev/mypy/mypy/build.py", line 2582, in generate_unused_ignore_notes
self.manager.errors.generate_unused_ignore_errors(self.xpath)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
File "/Users/shantanu/dev/mypy/mypy/errors.py", line 814, in generate_unused_ignore_errors
if line in self.skipped_lines[file]:
~~~~~~~~~~~~~~~~~~^^^^^^
(if you patch the crash in the obvious way, you get back to the original behaviour here)
TBH I am surprised. In my recent PRs on incremental mode I actually intentionally skipped the daemon parts (unless they are very easy) to limit the scope. In any case, later this year I am going to do a similar overhaul for the daemon in terms of consistency.
Activity
hauntsaninja commented on Jul 15, 2023
Hmm, I wasn't able to reproduce. I ran several variants of:
(Also curious that you're using uncompiled mypy, don't expect that to make a difference, but I'll try with that later)
karthiknadig commented on Jul 16, 2023
You need to first run it on a file that does not have any reported problems:
cpnielsen commented on Aug 9, 2023
I think I have found the underlying cause, though I am not sure what the correct solution is. I tested, and adding --follow-imports=skip makes this issue disappear, but is not helpful if you do want to follow imports in general. I may be over-explaining the issue here, but hopefully it can help fix it.
Test project setup (was using an existing project when I came across the issue):
I tested both with entire code base and individual "base.py" as input to the following command:
In the initial run when the daemon loads, it does a full build (calling mypy.build.build) and caching it using the FineGrainedManager for later updates. Running it repeatedly without file updates just returns a cached response and does not reveal the issue. Changing any affected file(s), invalidating the cache, causes all errors to disappear for the changed file.
When run with --follow-imports=normal (the default), the dmypy_server.Server.fine_grained_increment_follow_imports method handles the heavy lifting. It has the side-effect that all changed modules are marked as followed (all calls to fine_grained_manager.update is given followed = True.
The calls from there are: FineGrainedManager.update -> FineGrainedManager.update_one -> FineGrainedManager.update_module-> update_module_isolated. Here it creates a new 1-item BuildSource list, with followed=True (passed down the call chain). It then removes the given module from the graph and calls load_graph with the single source and the old graph and an empty list of new modules.
Root cause
At this point a State instance is created with the module name ("id"), path, source, and crucially root_source=not bs.followed (bs being the BuildSource). When it is initialised, we hit the error where it sets ignore_all to True, which makes all errors for the file disappear.
In my case, this is the mix of things causing this:
In short, mypy marks it as a "silently imported module that is not a root source" and instructs it to ignore all errors.
It looks like this was discovered and fixed in this PR previously: #14060.
Suggested fix
It seems like the initial section of fine_grained_increment_follow_imports need to detect changed modules that match the input sources, and update them with followed=False initially, and then the remaining modules (if any) from find_reachable_changed_modules can be updated with followed=True. However, I am not sure of the exact implications, so hopefully someone more knowledgable can pitch in.
@JukkaL You did the initial fix, I hope this might make sense to you and that you might have a good idea of how this could be fixed. It is breaking the mypy-type-checker in VS Code currently (it always passes in files with their absolute path, so it breaks for any Poetry projects at least), which is how I discovered this issue.
Set mypy-type-checker.preferDaemon to false
hauntsaninja commented on Nov 3, 2024
To repro with latest mypy master:
Gives:
Wimonder commented on Jun 27, 2025
Still running into this one, any updates? We're also using Poetry and it adds the project folder to sys.path, which in turn causes it to be included in the package_path list.
hauntsaninja commented on Dec 15, 2025
As of 1.18, this now crashes. Crash bisects to #15043
File "/Users/shantanu/dev/mypy/mypy/server/update.py", line 671, in update_module_isolated state.generate_unused_ignore_notes() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^ File "/Users/shantanu/dev/mypy/mypy/build.py", line 2582, in generate_unused_ignore_notes self.manager.errors.generate_unused_ignore_errors(self.xpath) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^ File "/Users/shantanu/dev/mypy/mypy/errors.py", line 814, in generate_unused_ignore_errors if line in self.skipped_lines[file]: ~~~~~~~~~~~~~~~~~~^^^^^^(if you patch the crash in the obvious way, you get back to the original behaviour here)
hauntsaninja commented on Feb 24, 2026
It looks like #20822 from @ilevkivskyi fixed the crash + the runs are now consistent. Should be out in the 1.20 release
ilevkivskyi commented on Feb 24, 2026
TBH I am surprised. In my recent PRs on incremental mode I actually intentionally skipped the daemon parts (unless they are very easy) to limit the scope. In any case, later this year I am going to do a similar overhaul for the daemon in terms of consistency.