Skip to content

Commit da43c91

Browse files
authored
Show error codes by default (#13542)
Part of the effort to nudge users into using specific type ignores. See #13541 This PR enables `show-error-codes` by default. Without knowing the code, users will always choose to use a bare `type: ignore` instead.
1 parent 00d547f commit da43c91

27 files changed

+68
-39
lines changed

Diff for: docs/source/command_line.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -691,9 +691,9 @@ in error messages.
691691
``file:line:column:end_line:end_column``. This option implies
692692
``--show-column-numbers``.
693693

694-
.. option:: --show-error-codes
694+
.. option:: --hide-error-codes
695695

696-
This flag will add an error code ``[<code>]`` to error messages. The error
696+
This flag will hide the error code ``[<code>]`` from error messages. By default, the error
697697
code is shown after each error message::
698698

699699
prog.py:1: error: "str" has no attribute "trim" [attr-defined]

Diff for: docs/source/config_file.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -717,12 +717,12 @@ These options may only be set in the global section (``[mypy]``).
717717

718718
Shows column numbers in error messages.
719719

720-
.. confval:: show_error_codes
720+
.. confval:: hide_error_codes
721721

722722
:type: boolean
723723
:default: False
724724

725-
Shows error codes in error messages. See :ref:`error-codes` for more information.
725+
Hides error codes in error messages. See :ref:`error-codes` for more information.
726726

727727
.. confval:: pretty
728728

Diff for: docs/source/error_codes.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ Error codes may change in future mypy releases.
2323
Displaying error codes
2424
----------------------
2525

26-
Error codes are not displayed by default. Use :option:`--show-error-codes <mypy --show-error-codes>`
27-
or config ``show_error_codes = True`` to display error codes. Error codes are shown inside square brackets:
26+
Error codes are displayed by default. Use :option:`--hide-error-codes <mypy --hide-error-codes>`
27+
or config ``hide_error_codes = True`` to hide error codes. Error codes are shown inside square brackets:
2828

2929
.. code-block:: text
3030
31-
$ mypy --show-error-codes prog.py
31+
$ mypy prog.py
3232
prog.py:1: error: "str" has no attribute "trim" [attr-defined]
3333
3434
It's also possible to require error codes for ``type: ignore`` comments.

Diff for: docs/source/type_inference_and_annotations.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,7 @@ short explanation of the bug. To do that, use this format:
229229
app.run(8000) # type: ignore # `run()` in v2.0 accepts an `int`, as a port
230230
231231
232-
Mypy displays an error code for each error if you use
233-
:option:`--show-error-codes <mypy --show-error-codes>`:
232+
By default, mypy displays an error code for each error:
234233

235234
.. code-block:: text
236235

Diff for: mypy/build.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def _build(
237237
errors = Errors(
238238
options.show_error_context,
239239
options.show_column_numbers,
240-
options.show_error_codes,
240+
options.hide_error_codes,
241241
options.pretty,
242242
options.show_error_end,
243243
lambda path: read_py_file(path, cached_read),

Diff for: mypy/config_parser.py

+3
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@ def parse_section(
431431
elif key.startswith("disallow") and hasattr(template, key[3:]):
432432
options_key = key[3:]
433433
invert = True
434+
elif key.startswith("show_") and hasattr(template, "hide_" + key[5:]):
435+
options_key = "hide_" + key[5:]
436+
invert = True
434437
elif key == "strict":
435438
pass # Special handling below
436439
else:

Diff for: mypy/dmypy_server.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ def __init__(self, options: Options, status_file: str, timeout: int | None = Non
197197

198198
# Since the object is created in the parent process we can check
199199
# the output terminal options here.
200-
self.formatter = FancyFormatter(sys.stdout, sys.stderr, options.show_error_codes)
200+
self.formatter = FancyFormatter(sys.stdout, sys.stderr, options.hide_error_codes)
201201

202202
def _response_metadata(self) -> dict[str, str]:
203203
py_version = f"{self.options.python_version[0]}_{self.options.python_version[1]}"

Diff for: mypy/errors.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ def __init__(
257257
self,
258258
show_error_context: bool = False,
259259
show_column_numbers: bool = False,
260-
show_error_codes: bool = False,
260+
hide_error_codes: bool = False,
261261
pretty: bool = False,
262262
show_error_end: bool = False,
263263
read_source: Callable[[str], list[str] | None] | None = None,
@@ -267,7 +267,7 @@ def __init__(
267267
) -> None:
268268
self.show_error_context = show_error_context
269269
self.show_column_numbers = show_column_numbers
270-
self.show_error_codes = show_error_codes
270+
self.hide_error_codes = hide_error_codes
271271
self.show_absolute_path = show_absolute_path
272272
self.pretty = pretty
273273
self.show_error_end = show_error_end
@@ -782,7 +782,7 @@ def format_messages(
782782
s = f"{srcloc}: {severity}: {message}"
783783
else:
784784
s = message
785-
if self.show_error_codes and code and severity != "note":
785+
if not self.hide_error_codes and code and severity != "note":
786786
# If note has an error code, it is related to a previous error. Avoid
787787
# displaying duplicate error codes.
788788
s = f"{s} [{code.code}]"

Diff for: mypy/fastparse.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,11 @@ def parse(
258258
on failure. Otherwise, use the errors object to report parse errors.
259259
"""
260260
raise_on_error = False
261-
if errors is None:
262-
errors = Errors()
263-
raise_on_error = True
264261
if options is None:
265262
options = Options()
263+
if errors is None:
264+
errors = Errors(hide_error_codes=options.hide_error_codes)
265+
raise_on_error = True
266266
errors.set_file(fnam, module, options=options)
267267
is_stub_file = fnam.endswith(".pyi")
268268
if is_stub_file:

Diff for: mypy/main.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def main(
6767
if clean_exit:
6868
options.fast_exit = False
6969

70-
formatter = util.FancyFormatter(stdout, stderr, options.show_error_codes)
70+
formatter = util.FancyFormatter(stdout, stderr, options.hide_error_codes)
7171

7272
if options.install_types and (stdout is not sys.stdout or stderr is not sys.stderr):
7373
# Since --install-types performs user input, we want regular stdout and stderr.
@@ -151,7 +151,7 @@ def run_build(
151151
stdout: TextIO,
152152
stderr: TextIO,
153153
) -> tuple[build.BuildResult | None, list[str], bool]:
154-
formatter = util.FancyFormatter(stdout, stderr, options.show_error_codes)
154+
formatter = util.FancyFormatter(stdout, stderr, options.hide_error_codes)
155155

156156
messages = []
157157

@@ -871,9 +871,9 @@ def add_invertible_flag(
871871
group=error_group,
872872
)
873873
add_invertible_flag(
874-
"--show-error-codes",
874+
"--hide-error-codes",
875875
default=False,
876-
help="Show error codes in error messages",
876+
help="Hide error codes in error messages",
877877
group=error_group,
878878
)
879879
add_invertible_flag(

Diff for: mypy/options.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ def __init__(self) -> None:
276276
self.shadow_file: list[list[str]] | None = None
277277
self.show_column_numbers: bool = False
278278
self.show_error_end: bool = False
279-
self.show_error_codes = False
279+
self.hide_error_codes = False
280280
# Use soft word wrap and show trimmed source snippets with error location markers.
281281
self.pretty = False
282282
self.dump_graph = False

Diff for: mypy/test/helpers.py

+3
Original file line numberDiff line numberDiff line change
@@ -369,12 +369,15 @@ def parse_options(
369369
if targets:
370370
# TODO: support specifying targets via the flags pragma
371371
raise RuntimeError("Specifying targets via the flags pragma is not supported.")
372+
if "--show-error-codes" not in flag_list:
373+
options.hide_error_codes = True
372374
else:
373375
flag_list = []
374376
options = Options()
375377
# TODO: Enable strict optional in test cases by default (requires *many* test case changes)
376378
options.strict_optional = False
377379
options.error_summary = False
380+
options.hide_error_codes = True
378381

379382
# Allow custom python version to override testfile_pyversion.
380383
if all(flag.split("=")[0] not in ["--python-version", "-2", "--py2"] for flag in flag_list):

Diff for: mypy/test/testcheck.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def run_case_once(
119119
if "columns" in testcase.file:
120120
options.show_column_numbers = True
121121
if "errorcodes" in testcase.file:
122-
options.show_error_codes = True
122+
options.hide_error_codes = False
123123

124124
if incremental_step and options.incremental:
125125
# Don't overwrite # flags: --no-incremental in incremental test cases

Diff for: mypy/test/testcmdline.py

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ def test_python_cmdline(testcase: DataDrivenTestCase, step: int) -> None:
5757
args.append("--show-traceback")
5858
if "--error-summary" not in args:
5959
args.append("--no-error-summary")
60+
if "--show-error-codes" not in args:
61+
args.append("--hide-error-codes")
6062
# Type check the program.
6163
fixed = [python3_path, "-m", "mypy"]
6264
env = os.environ.copy()

Diff for: mypy/test/testdaemon.py

+2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ def parse_script(input: list[str]) -> list[list[str]]:
8181

8282

8383
def run_cmd(input: str) -> tuple[int, str]:
84+
if input[1:].startswith("mypy run --") and "--show-error-codes" not in input:
85+
input += " --hide-error-codes"
8486
if input.startswith("dmypy "):
8587
input = sys.executable + " -m mypy." + input
8688
if input.startswith("mypy "):

Diff for: mypy/test/testerrorstream.py

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def test_error_stream(testcase: DataDrivenTestCase) -> None:
2525
"""
2626
options = Options()
2727
options.show_traceback = True
28+
options.hide_error_codes = True
2829

2930
logged_messages: list[str] = []
3031

Diff for: mypy/test/testparse.py

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def test_parser(testcase: DataDrivenTestCase) -> None:
3232
The argument contains the description of the test case.
3333
"""
3434
options = Options()
35+
options.hide_error_codes = True
3536

3637
if testcase.file.endswith("python310.test"):
3738
options.python_version = (3, 10)

Diff for: mypy/test/testpep561.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def test_pep561(testcase: DataDrivenTestCase) -> None:
107107
f.write(f"{s}\n")
108108
cmd_line.append(program)
109109

110-
cmd_line.extend(["--no-error-summary"])
110+
cmd_line.extend(["--no-error-summary", "--hide-error-codes"])
111111
if python_executable != sys.executable:
112112
cmd_line.append(f"--python-executable={python_executable}")
113113

Diff for: mypy/test/testpythoneval.py

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def test_python_evaluation(testcase: DataDrivenTestCase, cache_dir: str) -> None
5252
"--no-strict-optional",
5353
"--no-silence-site-packages",
5454
"--no-error-summary",
55+
"--hide-error-codes",
5556
]
5657
interpreter = python3_path
5758
mypy_cmdline.append(f"--python-version={'.'.join(map(str, PYTHON3_VERSION))}")

Diff for: mypy/test/teststubtest.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1559,13 +1559,13 @@ def test_mypy_build(self) -> None:
15591559
output = run_stubtest(stub="+", runtime="", options=[])
15601560
assert remove_color_code(output) == (
15611561
"error: not checking stubs due to failed mypy compile:\n{}.pyi:1: "
1562-
"error: invalid syntax\n".format(TEST_MODULE_NAME)
1562+
"error: invalid syntax [syntax]\n".format(TEST_MODULE_NAME)
15631563
)
15641564

15651565
output = run_stubtest(stub="def f(): ...\ndef f(): ...", runtime="", options=[])
15661566
assert remove_color_code(output) == (
15671567
"error: not checking stubs due to mypy build errors:\n{}.pyi:2: "
1568-
'error: Name "f" already defined on line 1\n'.format(TEST_MODULE_NAME)
1568+
'error: Name "f" already defined on line 1 [no-redef]\n'.format(TEST_MODULE_NAME)
15691569
)
15701570

15711571
def test_missing_stubs(self) -> None:

Diff for: mypy/util.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,8 @@ class FancyFormatter:
522522
This currently only works on Linux and Mac.
523523
"""
524524

525-
def __init__(self, f_out: IO[str], f_err: IO[str], show_error_codes: bool) -> None:
526-
self.show_error_codes = show_error_codes
525+
def __init__(self, f_out: IO[str], f_err: IO[str], hide_error_codes: bool) -> None:
526+
self.hide_error_codes = hide_error_codes
527527
# Check if we are in a human-facing terminal on a supported platform.
528528
if sys.platform not in ("linux", "darwin", "win32", "emscripten"):
529529
self.dummy_term = True
@@ -690,7 +690,7 @@ def colorize(self, error: str) -> str:
690690
"""Colorize an output line by highlighting the status and error code."""
691691
if ": error:" in error:
692692
loc, msg = error.split("error:", maxsplit=1)
693-
if not self.show_error_codes:
693+
if self.hide_error_codes:
694694
return (
695695
loc + self.style("error:", "red", bold=True) + self.highlight_quote_groups(msg)
696696
)

Diff for: mypy_self_check.ini

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ warn_no_return = True
55
strict_optional = True
66
disallow_any_unimported = True
77
show_traceback = True
8-
show_error_codes = True
98
pretty = True
109
always_false = MYPYC
1110
plugins = misc/proper_plugin.py

Diff for: mypyc/errors.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class Errors:
77
def __init__(self) -> None:
88
self.num_errors = 0
99
self.num_warnings = 0
10-
self._errors = mypy.errors.Errors()
10+
self._errors = mypy.errors.Errors(hide_error_codes=True)
1111

1212
def error(self, msg: str, path: str, line: int) -> None:
1313
self._errors.report(line, None, msg, severity="error", file=path)

Diff for: mypyc/test/testutil.py

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def build_ir_for_single_file2(
105105
compiler_options = compiler_options or CompilerOptions(capi_version=(3, 5))
106106
options = Options()
107107
options.show_traceback = True
108+
options.hide_error_codes = True
108109
options.use_builtins_fixtures = True
109110
options.strict_optional = True
110111
options.python_version = (3, 6)

Diff for: test-data/unit/check-errorcodes.test

+9
Original file line numberDiff line numberDiff line change
@@ -922,3 +922,12 @@ def f(d: D, s: str) -> None:
922922
[case testRecommendErrorCode]
923923
# type: ignore[whatever] # E: type ignore with error code is not supported for modules; use `# mypy: disable-error-code=...` [syntax]
924924
1 + "asdf"
925+
926+
[case testShowErrorCodesInConfig]
927+
# flags: --config-file tmp/mypy.ini
928+
# Test 'show_error_codes = True' in config doesn't raise an exception
929+
var: int = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
930+
931+
[file mypy.ini]
932+
\[mypy]
933+
show_error_codes = True

Diff for: test-data/unit/check-flags.test

+13-5
Original file line numberDiff line numberDiff line change
@@ -2023,12 +2023,12 @@ x = 'should be fine'
20232023
x.trim()
20242024

20252025
[case testDisableDifferentErrorCode]
2026-
# flags: --disable-error-code name-defined --show-error-code
2026+
# flags: --disable-error-code name-defined --show-error-codes
20272027
x = 'should not be fine'
20282028
x.trim() # E: "str" has no attribute "trim" [attr-defined]
20292029

20302030
[case testDisableMultipleErrorCode]
2031-
# flags: --disable-error-code attr-defined --disable-error-code return-value --show-error-code
2031+
# flags: --disable-error-code attr-defined --disable-error-code return-value --show-error-codes
20322032
x = 'should be fine'
20332033
x.trim()
20342034

@@ -2038,12 +2038,12 @@ def bad_return_type() -> str:
20382038
bad_return_type('no args taken!') # E: Too many arguments for "bad_return_type" [call-arg]
20392039

20402040
[case testEnableErrorCode]
2041-
# flags: --disable-error-code attr-defined --enable-error-code attr-defined --show-error-code
2041+
# flags: --disable-error-code attr-defined --enable-error-code attr-defined --show-error-codes
20422042
x = 'should be fine'
20432043
x.trim() # E: "str" has no attribute "trim" [attr-defined]
20442044

20452045
[case testEnableDifferentErrorCode]
2046-
# flags: --disable-error-code attr-defined --enable-error-code name-defined --show-error-code
2046+
# flags: --disable-error-code attr-defined --enable-error-code name-defined --show-error-codes
20472047
x = 'should not be fine'
20482048
x.trim()
20492049
y.trim() # E: Name "y" is not defined [name-defined]
@@ -2054,7 +2054,7 @@ y.trim() # E: Name "y" is not defined [name-defined]
20542054
--disable-error-code return-value \
20552055
--disable-error-code call-arg \
20562056
--enable-error-code attr-defined \
2057-
--enable-error-code return-value --show-error-code
2057+
--enable-error-code return-value --show-error-codes
20582058
x = 'should be fine'
20592059
x.trim() # E: "str" has no attribute "trim" [attr-defined]
20602060

@@ -2109,3 +2109,11 @@ enable_error_code = ignore-without-code, truthy-bool
21092109

21102110
\[mypy-tests.*]
21112111
disable_error_code = ignore-without-code
2112+
2113+
[case testShowErrorCodes]
2114+
# flags: --show-error-codes
2115+
x: int = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
2116+
2117+
[case testHideErrorCodes]
2118+
# flags: --hide-error-codes
2119+
x: int = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int")

Diff for: test-data/unit/daemon.test

+3-3
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ Daemon started
185185
$ dmypy check foo.py bar.py
186186
$ dmypy recheck
187187
$ dmypy recheck --update foo.py --remove bar.py sir_not_appearing_in_this_film.py
188-
foo.py:1: error: Import of "bar" ignored
188+
foo.py:1: error: Import of "bar" ignored [misc]
189189
foo.py:1: note: (Using --follow-imports=error, module not passed on command line)
190190
== Return code: 1
191191
$ dmypy recheck --update bar.py
@@ -277,7 +277,7 @@ $ dmypy suggest foo.foo
277277
(str) -> int
278278
$ {python} -c "import shutil; shutil.copy('foo2.py', 'foo.py')"
279279
$ dmypy check foo.py bar.py
280-
bar.py:3: error: Incompatible types in assignment (expression has type "int", variable has type "str")
280+
bar.py:3: error: Incompatible types in assignment (expression has type "int", variable has type "str") [assignment]
281281
== Return code: 1
282282
[file foo.py]
283283
def foo(arg):
@@ -304,7 +304,7 @@ $ dmypy inspect foo:1:2:3:4
304304
Command "inspect" is only valid after a "check" command (that produces no parse errors)
305305
== Return code: 2
306306
$ dmypy check foo.py --export-types
307-
foo.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int")
307+
foo.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
308308
== Return code: 1
309309
$ dmypy inspect foo:1
310310
Format should be file:line:column[:end_line:end_column]

0 commit comments

Comments
 (0)