Skip to content

Commit b790539

Browse files
authored
Stop suggesting MYPYPATH on missing imports (#5950)
This pull request replaces the "Perhaps setting MYPYPATH..." note with a link to https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports It also updates the docs to make that page a little more actionable: it now clearly distinguishes between different scenarios a user might find themselves in and gives concrete suggestions to try for each step. It also modifies the docs to suggest that users try searching for or writing their stubs first and try silencing errors second. Resolves #5241.
1 parent 783297c commit b790539

15 files changed

+216
-168
lines changed

docs/source/running_mypy.rst

Lines changed: 97 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -131,60 +131,109 @@ Missing imports
131131
When you import a module, mypy may report that it is unable to
132132
follow the import.
133133

134-
This could happen if the code is importing a non-existent module
135-
or if the code is importing a library that does not use type hints.
136-
Specifically, the library is neither declared to be a
137-
:ref:`PEP 561 compliant package <installed-packages>` nor has registered
138-
any stubs on `typeshed <https://github.com/python/typeshed>`_, the
139-
repository of stubs for the standard library and popular 3rd party libraries.
140-
141134
This can cause a lot of errors that look like the following::
142135

143136
main.py:1: error: No library stub file for standard library module 'antigravity'
144137
main.py:2: error: No library stub file for module 'flask'
145138
main.py:3: error: Cannot find module named 'this_module_does_not_exist'
146139

147-
If the module genuinely does not exist, you should of course fix the
148-
import statement. If the module is a module within your codebase that mypy
149-
is somehow unable to discover, we recommend reading the :ref:`finding-imports`
150-
section below to help you debug the issue.
151-
152-
If the module is a library that does not use type hints, the easiest fix
153-
is to silence the error messages by adding a ``# type: ignore`` comment on
154-
each respective import statement.
155-
156-
If you have many of these errors from a specific library, it may be more
157-
convenient to silence all of those errors at once using the
158-
:ref:`mypy config file <config-file>`. For example, suppose your codebase
159-
makes heavy use of an (untyped) library named `foobar`. You can silence all
160-
import errors associated with that library and that library alone by adding
161-
the following section to your config file::
162-
163-
[mypy-foobar]
164-
ignore_missing_imports = True
165-
166-
Note: this option is equivalent to adding a ``# type: ignore`` to every
167-
import of ``foobar`` in your codebase. For more information, see the
168-
documentation about configuring
169-
:ref:`import discovery <config-file-import-discovery-per-module>` in config files.
170-
171-
If you would like to silence *all* missing import errors in your codebase,
172-
you can do so by using the ``--ignore-missing-imports`` flag. We recommend
173-
using this flag only as a last resort: it's equivalent to adding a
174-
``# type: ignore`` to all unresolved imports in your codebase.
175-
176-
A more involved solution would be to reverse-engineer how the library
177-
works, create type hints for the library, and point mypy at those
178-
type hints either by passing in in via the command line or by adding
179-
the location of your custom stubs to either the ``MYPYPATH`` environment
180-
variable or the ``mypy_path``
181-
:ref:`config file option <config-file-import-discovery-global>`.
182-
183-
If you want to share your work, you can try contributing your stubs back
184-
to the library -- see our documentation on creating
185-
:ref:`PEP 561 compliant packages <installed-packages>`.
186-
187-
140+
There are several different things you can try doing, depending on the exact
141+
nature of the module.
142+
143+
If the module is a part of your own codebase, try:
144+
145+
1. Making sure your import does not contain a typo.
146+
2. Reading the :ref:`finding-imports` section below to make sure you
147+
understand how exactly mypy searches for and finds modules and modify
148+
how you're invoking mypy accordingly.
149+
3. Adding the directory containing that module to either the ``MYPYPATH``
150+
environment variable or the ``mypy_path``
151+
:ref:`config file option <config-file-import-discovery-global>`.
152+
153+
Note: if the module you are trying to import is actually a *submodule* of
154+
some package, you should add the directory containing the *entire* package
155+
to ``MYPYPATH``. For example, suppose you are trying to add the module
156+
``foo.bar.baz``, which is located at ``~/foo-project/src/foo/bar/baz.py``.
157+
In this case, you should add ``~/foo-project/src`` to ``MYPYPATH``.
158+
159+
If the module is a third party library, you must make sure that there are
160+
type hints available for that library. Mypy by default will not attempt to
161+
infer the types of any 3rd party libraries you may have installed
162+
unless they either have declared themselves to be
163+
:ref:`PEP 561 compliant stub package <installed-packages>` or have registered
164+
themselves on `typeshed <https://github.com/python/typeshed>`_,
165+
the repository of types for the standard library and some 3rd party libraries.
166+
167+
If you are getting an import-related error, this means the library you
168+
are trying to use has done neither of these things. In that case, you can try:
169+
170+
1. Searching to see if there is a :ref:`PEP 561 compliant stub package <installed-packages>`.
171+
corresponding to your third party library. Stub packages let you install
172+
type hints independently from the library itself.
173+
174+
2. :ref:`Writing your own stub files <stub-files>` containing type hints for
175+
the library. You can point mypy at your type hints either by passing
176+
them in via the command line, by adding the location to the
177+
`MYPYPATH` environment variable, or by using the ``mypy_path``
178+
:ref:`config file option <config-file-import-discovery-global>`.
179+
180+
Note that if you decide to write your own stub files, they don't need
181+
to be complete! A good strategy is to add stubs for just the parts
182+
of the library you need and iterate on them over time.
183+
184+
If you want to share your work, you can try contributing your stubs back
185+
to the library -- see our documentation on creating
186+
:ref:`PEP 561 compliant packages <installed-packages>`.
187+
188+
If the module is a third party library, but you cannot find any existing
189+
type hints nor have to time to write your own, you can *silence* the errors:
190+
191+
1. To silence a *single* missing import error, add a `# type: ignore` at the end of the
192+
line containing the import.
193+
194+
2. To silence *all* missing import imports errors from a single library, add
195+
a section to your :ref:`mypy config file <config-file>` for that library setting
196+
``ignore_missing_imports`` to True. For example, suppose your codebase
197+
makes heavy use of an (untyped) library named ``foobar``. You can silence
198+
all import errors associated with that library and that library alone by
199+
adding the following section to your config file::
200+
201+
[mypy-foobar]
202+
ignore_missing_imports = True
203+
204+
Note: this option is equivalent to adding a ``# type: ignore`` to every
205+
import of ``foobar`` in your codebase. For more information, see the
206+
documentation about configuring
207+
:ref:`import discovery <config-file-import-discovery-per-module>` in config files.
208+
209+
3. To silence *all* missing import errors for *all* libraries in your codebase,
210+
invoke mypy with the ``--ignore-missing-imports`` command line flag or set
211+
the ``ignore_missing_imports``
212+
:ref:`config file option <config-file-import-discovery-per-module` to True
213+
in the *global* section of your mypy config file::
214+
215+
[mypy]
216+
ignore_missing_imports = True
217+
218+
We recommend using this approach only as a last resort: it's equivalent
219+
to adding a ``# type: ignore`` to all unresolved imports in your codebase.
220+
221+
If the module is a part of the standard library, try:
222+
223+
1. Updating mypy and re-running it. It's possible type hints for that corner
224+
of the standard library were added in a later version of mypy.
225+
226+
2. Filing a bug report on `typeshed <https://github.com/python/typeshed>`_,
227+
the repository of type hints for the standard library that comes bundled
228+
with mypy. You can expedite this process by also submitting a pull request
229+
fixing the bug.
230+
231+
Changes to typeshed will come bundled with mypy the next time it's released.
232+
In the meantime, you can add a ``# type: ignore`` to silence any relevant
233+
errors. After upgrading, we recommend running mypy using the
234+
``--warn-unused-ignores`` flag to help you find any ``# type: ignore``
235+
annotations you no longer need.
236+
188237
.. _follow-imports:
189238

190239
Following imports

mypy/build.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,10 +2131,9 @@ def module_not_found(manager: BuildManager, line: int, caller_state: State,
21312131
errors.report(line, 0, "No library stub file for module '{}'".format(target))
21322132
errors.report(line, 0, stub_msg, severity='note', only_once=True)
21332133
else:
2134+
note = "See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports"
21342135
errors.report(line, 0, "Cannot find module named '{}'".format(target))
2135-
errors.report(line, 0, '(Perhaps setting MYPYPATH '
2136-
'or using the "--ignore-missing-imports" flag would help)',
2137-
severity='note', only_once=True)
2136+
errors.report(line, 0, note, severity='note', only_once=True)
21382137
errors.set_import_context(save_import_context)
21392138

21402139

mypy/test/testpep561.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ class SimpleMsg(Enum):
5959
class NamespaceMsg(Enum):
6060
cfm_beta = ("{tempfile}:4: error: Cannot find module named "
6161
"'typedpkg_ns.ns.dne'")
62-
help_note = ('{tempfile}:4: note: (Perhaps setting MYPYPATH or using the '
63-
'"--ignore-missing-imports" flag would help)')
62+
help_note = ('{tempfile}:4: note: See https://mypy.readthedocs.io/en/latest/'
63+
'running_mypy.html#missing-imports')
6464
bool_str = ('{tempfile}:10: error: Argument 1 has incompatible type '
6565
'"bool"; expected "str"')
6666
int_bool = ('{tempfile}:11: error: Argument 1 has incompatible type '

test-data/unit/check-flags.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ main:2: note: (Using --follow-imports=error, module not passed on command line)
439439
from mod import x
440440
[out]
441441
main:1: error: Cannot find module named 'mod'
442-
main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
442+
main:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
443443

444444
[case testIgnoreMissingImportsTrue]
445445
# flags: --ignore-missing-imports
@@ -594,7 +594,7 @@ def f(x: MyType) -> None:
594594
pass
595595
[out]
596596
main:2: error: Cannot find module named 'missing'
597-
main:2: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
597+
main:2: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
598598
main:4: error: Argument 1 to "f" becomes "Any" due to an unfollowed import
599599

600600
[case testDisallowImplicitAnyVariableDefinition]

test-data/unit/check-incremental.test

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2082,7 +2082,7 @@ x = 1
20822082
[stale]
20832083
[out2]
20842084
tmp/n.py:1: error: Cannot find module named 'm'
2085-
tmp/n.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
2085+
tmp/n.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
20862086

20872087
[case testDeleteFileWithinCycle]
20882088
import a
@@ -2748,10 +2748,10 @@ a.f() # Comment change
27482748
[stale3 b]
27492749
[out2]
27502750
tmp/b.py:1: error: Cannot find module named 'a'
2751-
tmp/b.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
2751+
tmp/b.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
27522752
[out3]
27532753
tmp/b.py:1: error: Cannot find module named 'a'
2754-
tmp/b.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
2754+
tmp/b.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
27552755
[out4]
27562756

27572757
[case testQuickAndDirtyRenameModule]
@@ -4063,7 +4063,7 @@ import a
40634063

40644064
[out2]
40654065
main:2: error: Cannot find module named 'a'
4066-
main:2: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
4066+
main:2: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
40674067

40684068
[case testIncrementalInheritanceAddAnnotation]
40694069
# flags: --strict-optional
@@ -4206,7 +4206,7 @@ def f(x: int) -> None: pass
42064206
[out]
42074207
[out2]
42084208
main:1: error: Cannot find module named 'p.q'
4209-
main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
4209+
main:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
42104210
[out3]
42114211
main:2: error: Too few arguments for "f"
42124212

@@ -4808,10 +4808,10 @@ def __getattr__(attr: str) -> Any: ...
48084808
[builtins fixtures/module.pyi]
48094809
[out]
48104810
tmp/c.py:1: error: Cannot find module named 'a.b.c'
4811-
tmp/c.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
4811+
tmp/c.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
48124812
[out2]
48134813
tmp/c.py:1: error: Cannot find module named 'a.b.c'
4814-
tmp/c.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
4814+
tmp/c.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
48154815

48164816
[case testAddedMissingStubs]
48174817
# flags: --ignore-missing-imports

0 commit comments

Comments
 (0)