Skip to content

Commit 57311e0

Browse files
committed
Add an option to require ignore comments have error codes
Fixes #11509
1 parent e557ec2 commit 57311e0

File tree

6 files changed

+55
-0
lines changed

6 files changed

+55
-0
lines changed

docs/source/command_line.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,15 @@ in error messages.
680680

681681
See :ref:`error-codes` for more information.
682682

683+
.. option:: --disallow-ignore-without-code
684+
685+
This flag will disallow ``type: ignore`` comments which do not have
686+
error codes::
687+
688+
prog.py:1: error: "type: ignore" comment without error code
689+
690+
See :ref:`error-codes` for more information.
691+
683692
.. option:: --pretty
684693

685694
Use visually nicer output in error messages: use soft word wrap,

mypy/build.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,6 +2369,13 @@ def generate_unused_ignore_notes(self) -> None:
23692369
self.verify_dependencies(suppressed_only=True)
23702370
self.manager.errors.generate_unused_ignore_errors(self.xpath)
23712371

2372+
def generate_ignore_without_code_notes(self) -> None:
2373+
if self.options.disallow_ignore_without_code:
2374+
self.manager.errors.generate_ignore_without_code_errors(
2375+
self.xpath,
2376+
self.options.warn_unused_ignores,
2377+
)
2378+
23722379

23732380
# Module import and diagnostic glue
23742381

@@ -3155,6 +3162,7 @@ def process_stale_scc(graph: Graph, scc: List[str], manager: BuildManager) -> No
31553162
graph[id].finish_passes()
31563163
for id in stale:
31573164
graph[id].generate_unused_ignore_notes()
3165+
graph[id].generate_ignore_without_code_notes()
31583166
if any(manager.errors.is_errors_for_file(graph[id].xpath) for id in stale):
31593167
for id in stale:
31603168
graph[id].transitive_error = True

mypy/errors.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,28 @@ def generate_unused_ignore_errors(self, file: str) -> None:
485485
None, False, False, False)
486486
self._add_error_info(file, info)
487487

488+
def generate_ignore_without_code_errors(self,
489+
file: str,
490+
is_warning_unused_ignores: bool) -> None:
491+
if is_typeshed_file(file) or file in self.ignored_files:
492+
return
493+
494+
used_ignored_lines = self.used_ignored_lines[file]
495+
for line, ignored_codes in self.ignored_lines[file].items():
496+
if ignored_codes:
497+
continue
498+
499+
# If the ignore is itself unused and that would be warned about, let
500+
# that error stand alone
501+
if is_warning_unused_ignores and not used_ignored_lines[line]:
502+
continue
503+
504+
# Don't use report since add_error_info will ignore the error!
505+
info = ErrorInfo(self.import_context(), file, self.current_module(), None,
506+
None, line, -1, 'error', '"type: ignore" comment without error code',
507+
None, False, False, False)
508+
self._add_error_info(file, info)
509+
488510
def num_messages(self) -> int:
489511
"""Return the number of generated messages."""
490512
return sum(len(x) for x in self.error_info_map.values())

mypy/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,10 @@ def add_invertible_flag(flag: str,
677677
" non-overlapping types",
678678
group=strictness_group)
679679

680+
add_invertible_flag('--disallow-ignore-without-code', default=False, strict_flag=True,
681+
help="Disallow 'type: ignore' comments which do not have error codes",
682+
group=strictness_group)
683+
680684
strict_help = "Strict mode; enables the following flags: {}".format(
681685
", ".join(strict_flag_names))
682686
strictness_group.add_argument(

mypy/options.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ def __init__(self) -> None:
143143
# Warn about unused '# type: ignore' comments
144144
self.warn_unused_ignores = False
145145

146+
# Warn about '# type: ignore' comments without error codes
147+
self.disallow_ignore_without_code = False
148+
146149
# Warn about unused '[mypy-<pattern>]' or '[[tool.mypy.overrides]]' config sections
147150
self.warn_unused_configs = False
148151

test-data/unit/check-errorcodes.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,15 @@ x # type: ignore[name-defined, attr-defined] # E: Unused "type: ignore[attr-defi
135135
# flags: --warn-unused-ignores
136136
"x" # type: ignore[name-defined] # E: Unused "type: ignore" comment
137137

138+
[case testErrorCodeMissingWhenRequired]
139+
# flags: --disallow-ignore-without-code
140+
"x" # type: ignore # E: "type: ignore" comment without error code
141+
y # type: ignore # E: "type: ignore" comment without error code
142+
143+
[case testErrorCodeMissingDoesntTrampleUnusedIgnoresWarning]
144+
# flags: --disallow-ignore-without-code --warn-unused-ignores
145+
"x" # type: ignore # E: Unused "type: ignore" comment
146+
138147
[case testErrorCodeIgnoreWithExtraSpace]
139148
x # type: ignore [name-defined]
140149
x2 # type: ignore [ name-defined ]

0 commit comments

Comments
 (0)