Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/source/error_codes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ thinks is undefined:
# definition.
from foolib import foo # type: ignore[attr-defined]

If you are using multiple type checkers, you can optionally prefix
mypy-specific error codes with ``mypy:``. By default, mypy ignores unknown
error codes (as they may be intended for other type checkers). However, error
codes prefixed with ``mypy:`` will be validated:

.. code-block:: python

# mypy: warn-unused-ignores

# Error: Unrecognized error code "attr-undefined"
x = 1 # type: ignore[mypy:attr-undefined]

# OK: error code may be used by other type checker.
y = 2 # type: ignore[something-else]

Enabling/disabling specific error codes globally
------------------------------------------------

Expand Down
4 changes: 3 additions & 1 deletion mypy/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,9 @@ def generate_unused_ignore_errors(self, file: str, is_typeshed: bool = False) ->
if codes.UNUSED_IGNORE.code in ignored_codes:
continue
used_ignored_codes = set(used_ignored_lines[line])
unused_ignored_codes = [c for c in ignored_codes if c not in used_ignored_codes]
unused_ignored_codes = [
c for c in ignored_codes if c not in used_ignored_codes and c in codes.error_codes
]
# `ignore` is used
if not ignored_codes and used_ignored_codes:
continue
Expand Down
30 changes: 30 additions & 0 deletions mypy/nativeparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
read_str_opt,
read_tag,
)
from mypy.errorcodes import error_codes
from mypy.errors import CompileError
from mypy.nodes import (
ARG_KINDS,
Expand Down Expand Up @@ -240,6 +241,8 @@ def native_parse(
source_hash,
mypy_comments,
) = parse_to_binary_ast(filename, options, source, skip_function_bodies)
ignores, extra_errors = normalize_error_codes(ignores)
errors.extend(extra_errors)
node = MypyFile([], [])
node.path = filename
node.raw_data = FileRawData(
Expand All @@ -255,6 +258,33 @@ def native_parse(
return node, errors, ignores


def normalize_error_codes(ignores: TypeIgnores) -> tuple[TypeIgnores, list[ParseError]]:
"""Remove mypy: prefix from error codes (if present)."""
normalized = []
extra_errors: list[ParseError] = []
for line, codes in ignores:
new_codes = []
for c in codes:
if not c.startswith("mypy:"):
new_codes.append(c)
continue
c = c.removeprefix("mypy:")
if c in error_codes:
new_codes.append(c)
continue
extra_errors.append(
{
"line": line,
"column": -1,
"message": f'Unrecognized error code "{c}"',
"blocker": False,
"code": "misc",
}
)
normalized.append((line, new_codes))
return normalized, extra_errors


def native_parse_type_string(
expr_string: str, line: int, column: int, end_line: int, end_column: int, options: Options
) -> ProperType:
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-errorcodes.test
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,15 @@ x # type: ignore[name-defined, attr-defined] # E: Unused "type: ignore[attr-defi

[case testErrorCodeWarnUnusedIgnores3]
# flags: --warn-unused-ignores
"x".foobar(y) # type: ignore[name-defined, attr-defined, xyz] # E: Unused "type: ignore[xyz]" comment [unused-ignore]
"x".foobar(y) # type: ignore[name-defined, attr-defined, xyz]

[case testErrorCodeWarnUnusedIgnores4]
# flags: --warn-unused-ignores
"x".foobar(y) # type: ignore[name-defined, attr-defined, valid-type] # E: Unused "type: ignore[valid-type]" comment [unused-ignore]

[case testErrorCodeWarnUnusedIgnores5]
# flags: --warn-unused-ignores
"x".foobar(y) # type: ignore[name-defined, attr-defined, valid-type, xyz] # E: Unused "type: ignore[valid-type, xyz]" comment [unused-ignore]
"x".foobar(y) # type: ignore[name-defined, attr-defined, valid-type, xyz] # E: Unused "type: ignore[valid-type]" comment [unused-ignore]

[case testErrorCodeWarnUnusedIgnores6_NoDetailWhenSingleErrorCode]
# flags: --warn-unused-ignores
Expand Down
17 changes: 13 additions & 4 deletions test-data/unit/check-ignore.test
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,13 @@ class CD(six.with_metaclass(M)): # E: Multiple metaclass definitions

[case testUnusedIgnoreCodeOrder]
# flags: --warn-unused-ignores
5 # type: ignore[import, steven] # E: Unused "type: ignore[import, steven]" comment
5 # type: ignore[import, valid-type] # E: Unused "type: ignore[import, valid-type]" comment
-- User ordering of codes is preserved
5 # type: ignore[steven, import] # E: Unused "type: ignore[steven, import]" comment
5 # type: ignore[valid-type, import] # E: Unused "type: ignore[valid-type, import]" comment
-- Spacing is not preserved
5 # type: ignore[ steven, import ] # E: Unused "type: ignore[steven, import]" comment
5 # type: ignore[ valid-type, import ] # E: Unused "type: ignore[valid-type, import]" comment
-- Make sure it works as intended in more complex situations
1 + "ok" + "ok".foo # type: ignore[ operator,steven,attr-defined, import] # E: Unused "type: ignore[steven, import]" comment
1 + "ok" + "ok".foo # type: ignore[ operator,valid-type,attr-defined, import] # E: Unused "type: ignore[valid-type, import]" comment

[case testUnusedIgnoreTryExcept]
# flags: --warn-unused-ignores
Expand All @@ -300,3 +300,12 @@ except Exception:
[file foobar.py]
[file barfoo.py]
[builtins fixtures/exception.pyi]

[case testNamespaceErrorCodes]
x: str = 42 # type: ignore[mypy:assignment, other:foobar]
y: str = 42 # type: ignore[mypy:arg-type, other:foobar]
x = 1 # type: ignore[mypy:foobar]
[out]
main:2: error: Incompatible types in assignment (expression has type "int", variable has type "str")
main:2: note: Error code "assignment" not covered by "type: ignore[arg-type, other:foobar]" comment
main:3: error: Unrecognized error code "foobar"
Loading