Skip to content

Commit 78339b9

Browse files
authored
Use error subcodes to differentiate import errors (#14740)
Resolves #9789 Users could use `--disable-error-code=import-untyped` to only ignore errors about libraries not having stubs, but continue to get errors about e.g. typos in an import name. The error subcode mechanism is new from #14570. Note that users will now get a different error code depending on whether or not a package is installed, and may not know that they can use the parent error code to ignore the issue regardless. I think this is okay, in general type checking results can change if you run them in two different environments. Note also that with `--warn-unused-ignore` / `--strict` mypy will complain about not having the most specific error code
1 parent 8c21953 commit 78339b9

File tree

4 files changed

+29
-10
lines changed

4 files changed

+29
-10
lines changed

mypy/build.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -2780,7 +2780,16 @@ def module_not_found(
27802780
else:
27812781
daemon = manager.options.fine_grained_incremental
27822782
msg, notes = reason.error_message_templates(daemon)
2783-
errors.report(line, 0, msg.format(module=target), code=codes.IMPORT)
2783+
if reason == ModuleNotFoundReason.NOT_FOUND:
2784+
code = codes.IMPORT_NOT_FOUND
2785+
elif (
2786+
reason == ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS
2787+
or reason == ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED
2788+
):
2789+
code = codes.IMPORT_UNTYPED
2790+
else:
2791+
code = codes.IMPORT
2792+
errors.report(line, 0, msg.format(module=target), code=code)
27842793
top_level, second_level = get_top_two_prefixes(target)
27852794
if second_level in legacy_bundled_packages or second_level in non_bundled_packages:
27862795
top_level = second_level

mypy/errorcodes.py

+6
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ def __hash__(self) -> int:
107107
IMPORT: Final = ErrorCode(
108108
"import", "Require that imported module can be found or has stubs", "General"
109109
)
110+
IMPORT_NOT_FOUND: Final = ErrorCode(
111+
"import-not-found", "Require that imported module can be found", "General", sub_code_of=IMPORT
112+
)
113+
IMPORT_UNTYPED: Final = ErrorCode(
114+
"import-untyped", "Require that imported module has stubs", "General", sub_code_of=IMPORT
115+
)
110116
NO_REDEF: Final = ErrorCode("no-redef", "Check that each name is defined once", "General")
111117
FUNC_RETURNS_VALUE: Final = ErrorCode(
112118
"func-returns-value", "Check that called function returns a value in value context", "General"

mypy/errors.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from typing_extensions import Literal, TypeAlias as _TypeAlias
99

1010
from mypy import errorcodes as codes
11-
from mypy.errorcodes import IMPORT, ErrorCode
11+
from mypy.errorcodes import IMPORT, IMPORT_NOT_FOUND, IMPORT_UNTYPED, ErrorCode
1212
from mypy.message_registry import ErrorMessage
1313
from mypy.options import Options
1414
from mypy.scope import Scope
@@ -510,7 +510,11 @@ def add_error_info(self, info: ErrorInfo) -> None:
510510
if info.message in self.only_once_messages:
511511
return
512512
self.only_once_messages.add(info.message)
513-
if self.seen_import_error and info.code is not IMPORT and self.has_many_errors():
513+
if (
514+
self.seen_import_error
515+
and info.code not in (IMPORT, IMPORT_UNTYPED, IMPORT_NOT_FOUND)
516+
and self.has_many_errors()
517+
):
514518
# Missing stubs can easily cause thousands of errors about
515519
# Any types, especially when upgrading to mypy 0.900,
516520
# which no longer bundles third-party library stubs. Avoid

test-data/unit/check-errorcodes.test

+7-7
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ from defusedxml import xyz # type: ignore[import]
183183

184184
[case testErrorCodeBadIgnore]
185185
import nostub # type: ignore xyz # E: Invalid "type: ignore" comment [syntax] \
186-
# E: Cannot find implementation or library stub for module named "nostub" [import] \
186+
# E: Cannot find implementation or library stub for module named "nostub" [import-not-found] \
187187
# N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
188188
import nostub # type: ignore[ # E: Invalid "type: ignore" comment [syntax]
189189
import nostub # type: ignore[foo # E: Invalid "type: ignore" comment [syntax]
@@ -211,7 +211,7 @@ def f(x, # type: int # type: ignore[
211211
pass
212212
[out]
213213
main:2: error: Invalid "type: ignore" comment [syntax]
214-
main:2: error: Cannot find implementation or library stub for module named "nostub" [import]
214+
main:2: error: Cannot find implementation or library stub for module named "nostub" [import-not-found]
215215
main:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
216216
main:3: error: Invalid "type: ignore" comment [syntax]
217217
main:4: error: Invalid "type: ignore" comment [syntax]
@@ -522,12 +522,12 @@ if int() is str(): # E: Non-overlapping identity check (left operand type: "int
522522
[builtins fixtures/primitives.pyi]
523523

524524
[case testErrorCodeMissingModule]
525-
from defusedxml import xyz # E: Cannot find implementation or library stub for module named "defusedxml" [import]
526-
from nonexistent import foobar # E: Cannot find implementation or library stub for module named "nonexistent" [import]
527-
import nonexistent2 # E: Cannot find implementation or library stub for module named "nonexistent2" [import]
528-
from nonexistent3 import * # E: Cannot find implementation or library stub for module named "nonexistent3" [import]
525+
from defusedxml import xyz # E: Cannot find implementation or library stub for module named "defusedxml" [import-not-found]
526+
from nonexistent import foobar # E: Cannot find implementation or library stub for module named "nonexistent" [import-not-found]
527+
import nonexistent2 # E: Cannot find implementation or library stub for module named "nonexistent2" [import-not-found]
528+
from nonexistent3 import * # E: Cannot find implementation or library stub for module named "nonexistent3" [import-not-found]
529529
from pkg import bad # E: Module "pkg" has no attribute "bad" [attr-defined]
530-
from pkg.bad2 import bad3 # E: Cannot find implementation or library stub for module named "pkg.bad2" [import] \
530+
from pkg.bad2 import bad3 # E: Cannot find implementation or library stub for module named "pkg.bad2" [import-not-found] \
531531
# N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
532532
[file pkg/__init__.py]
533533

0 commit comments

Comments
 (0)