Skip to content

Show error codes by default #13542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 27, 2022
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
4 changes: 2 additions & 2 deletions docs/source/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -691,9 +691,9 @@ in error messages.
``file:line:column:end_line:end_column``. This option implies
``--show-column-numbers``.

.. option:: --show-error-codes
.. option:: --hide-error-codes

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

prog.py:1: error: "str" has no attribute "trim" [attr-defined]
Expand Down
4 changes: 2 additions & 2 deletions docs/source/config_file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -717,12 +717,12 @@ These options may only be set in the global section (``[mypy]``).

Shows column numbers in error messages.

.. confval:: show_error_codes
.. confval:: hide_error_codes

:type: boolean
:default: False

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

.. confval:: pretty

Expand Down
6 changes: 3 additions & 3 deletions docs/source/error_codes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ Error codes may change in future mypy releases.
Displaying error codes
----------------------

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

.. code-block:: text

$ mypy --show-error-codes prog.py
$ mypy prog.py
prog.py:1: error: "str" has no attribute "trim" [attr-defined]

It's also possible to require error codes for ``type: ignore`` comments.
Expand Down
3 changes: 1 addition & 2 deletions docs/source/type_inference_and_annotations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,7 @@ short explanation of the bug. To do that, use this format:
app.run(8000) # type: ignore # `run()` in v2.0 accepts an `int`, as a port


Mypy displays an error code for each error if you use
:option:`--show-error-codes <mypy --show-error-codes>`:
By default, mypy displays an error code for each error:

.. code-block:: text

Expand Down
2 changes: 1 addition & 1 deletion mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ def _build(
errors = Errors(
options.show_error_context,
options.show_column_numbers,
options.show_error_codes,
options.hide_error_codes,
options.pretty,
options.show_error_end,
lambda path: read_py_file(path, cached_read),
Expand Down
3 changes: 3 additions & 0 deletions mypy/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,9 @@ def parse_section(
elif key.startswith("disallow") and hasattr(template, key[3:]):
options_key = key[3:]
invert = True
elif key.startswith("show_") and hasattr(template, "hide_" + key[5:]):
options_key = "hide_" + key[5:]
invert = True
elif key == "strict":
pass # Special handling below
else:
Expand Down
2 changes: 1 addition & 1 deletion mypy/dmypy_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def __init__(self, options: Options, status_file: str, timeout: int | None = Non

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

def _response_metadata(self) -> dict[str, str]:
py_version = f"{self.options.python_version[0]}_{self.options.python_version[1]}"
Expand Down
6 changes: 3 additions & 3 deletions mypy/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def __init__(
self,
show_error_context: bool = False,
show_column_numbers: bool = False,
show_error_codes: bool = False,
hide_error_codes: bool = False,
pretty: bool = False,
show_error_end: bool = False,
read_source: Callable[[str], list[str] | None] | None = None,
Expand All @@ -267,7 +267,7 @@ def __init__(
) -> None:
self.show_error_context = show_error_context
self.show_column_numbers = show_column_numbers
self.show_error_codes = show_error_codes
self.hide_error_codes = hide_error_codes
self.show_absolute_path = show_absolute_path
self.pretty = pretty
self.show_error_end = show_error_end
Expand Down Expand Up @@ -782,7 +782,7 @@ def format_messages(
s = f"{srcloc}: {severity}: {message}"
else:
s = message
if self.show_error_codes and code and severity != "note":
if not self.hide_error_codes and code and severity != "note":
# If note has an error code, it is related to a previous error. Avoid
# displaying duplicate error codes.
s = f"{s} [{code.code}]"
Expand Down
6 changes: 3 additions & 3 deletions mypy/fastparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,11 @@ def parse(
on failure. Otherwise, use the errors object to report parse errors.
"""
raise_on_error = False
if errors is None:
errors = Errors()
raise_on_error = True
if options is None:
options = Options()
if errors is None:
errors = Errors(hide_error_codes=options.hide_error_codes)
raise_on_error = True
errors.set_file(fnam, module, options=options)
is_stub_file = fnam.endswith(".pyi")
if is_stub_file:
Expand Down
8 changes: 4 additions & 4 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def main(
if clean_exit:
options.fast_exit = False

formatter = util.FancyFormatter(stdout, stderr, options.show_error_codes)
formatter = util.FancyFormatter(stdout, stderr, options.hide_error_codes)

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

messages = []

Expand Down Expand Up @@ -871,9 +871,9 @@ def add_invertible_flag(
group=error_group,
)
add_invertible_flag(
"--show-error-codes",
"--hide-error-codes",
default=False,
help="Show error codes in error messages",
help="Hide error codes in error messages",
group=error_group,
)
add_invertible_flag(
Expand Down
2 changes: 1 addition & 1 deletion mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ def __init__(self) -> None:
self.shadow_file: list[list[str]] | None = None
self.show_column_numbers: bool = False
self.show_error_end: bool = False
self.show_error_codes = False
self.hide_error_codes = False
# Use soft word wrap and show trimmed source snippets with error location markers.
self.pretty = False
self.dump_graph = False
Expand Down
3 changes: 3 additions & 0 deletions mypy/test/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,12 +369,15 @@ def parse_options(
if targets:
# TODO: support specifying targets via the flags pragma
raise RuntimeError("Specifying targets via the flags pragma is not supported.")
if "--show-error-codes" not in flag_list:
options.hide_error_codes = True
else:
flag_list = []
options = Options()
# TODO: Enable strict optional in test cases by default (requires *many* test case changes)
options.strict_optional = False
options.error_summary = False
options.hide_error_codes = True

# Allow custom python version to override testfile_pyversion.
if all(flag.split("=")[0] not in ["--python-version", "-2", "--py2"] for flag in flag_list):
Expand Down
2 changes: 1 addition & 1 deletion mypy/test/testcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def run_case_once(
if "columns" in testcase.file:
options.show_column_numbers = True
if "errorcodes" in testcase.file:
options.show_error_codes = True
options.hide_error_codes = False

if incremental_step and options.incremental:
# Don't overwrite # flags: --no-incremental in incremental test cases
Expand Down
2 changes: 2 additions & 0 deletions mypy/test/testcmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ def test_python_cmdline(testcase: DataDrivenTestCase, step: int) -> None:
args.append("--show-traceback")
if "--error-summary" not in args:
args.append("--no-error-summary")
if "--show-error-codes" not in args:
args.append("--hide-error-codes")
# Type check the program.
fixed = [python3_path, "-m", "mypy"]
env = os.environ.copy()
Expand Down
2 changes: 2 additions & 0 deletions mypy/test/testdaemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ def parse_script(input: list[str]) -> list[list[str]]:


def run_cmd(input: str) -> tuple[int, str]:
if input[1:].startswith("mypy run --") and "--show-error-codes" not in input:
input += " --hide-error-codes"
if input.startswith("dmypy "):
input = sys.executable + " -m mypy." + input
if input.startswith("mypy "):
Expand Down
1 change: 1 addition & 0 deletions mypy/test/testerrorstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def test_error_stream(testcase: DataDrivenTestCase) -> None:
"""
options = Options()
options.show_traceback = True
options.hide_error_codes = True

logged_messages: list[str] = []

Expand Down
1 change: 1 addition & 0 deletions mypy/test/testparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def test_parser(testcase: DataDrivenTestCase) -> None:
The argument contains the description of the test case.
"""
options = Options()
options.hide_error_codes = True

if testcase.file.endswith("python310.test"):
options.python_version = (3, 10)
Expand Down
2 changes: 1 addition & 1 deletion mypy/test/testpep561.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def test_pep561(testcase: DataDrivenTestCase) -> None:
f.write(f"{s}\n")
cmd_line.append(program)

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

Expand Down
1 change: 1 addition & 0 deletions mypy/test/testpythoneval.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def test_python_evaluation(testcase: DataDrivenTestCase, cache_dir: str) -> None
"--no-strict-optional",
"--no-silence-site-packages",
"--no-error-summary",
"--hide-error-codes",
]
interpreter = python3_path
mypy_cmdline.append(f"--python-version={'.'.join(map(str, PYTHON3_VERSION))}")
Expand Down
4 changes: 2 additions & 2 deletions mypy/test/teststubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1559,13 +1559,13 @@ def test_mypy_build(self) -> None:
output = run_stubtest(stub="+", runtime="", options=[])
assert remove_color_code(output) == (
"error: not checking stubs due to failed mypy compile:\n{}.pyi:1: "
"error: invalid syntax\n".format(TEST_MODULE_NAME)
"error: invalid syntax [syntax]\n".format(TEST_MODULE_NAME)
)

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

def test_missing_stubs(self) -> None:
Expand Down
6 changes: 3 additions & 3 deletions mypy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,8 @@ class FancyFormatter:
This currently only works on Linux and Mac.
"""

def __init__(self, f_out: IO[str], f_err: IO[str], show_error_codes: bool) -> None:
self.show_error_codes = show_error_codes
def __init__(self, f_out: IO[str], f_err: IO[str], hide_error_codes: bool) -> None:
self.hide_error_codes = hide_error_codes
# Check if we are in a human-facing terminal on a supported platform.
if sys.platform not in ("linux", "darwin", "win32", "emscripten"):
self.dummy_term = True
Expand Down Expand Up @@ -690,7 +690,7 @@ def colorize(self, error: str) -> str:
"""Colorize an output line by highlighting the status and error code."""
if ": error:" in error:
loc, msg = error.split("error:", maxsplit=1)
if not self.show_error_codes:
if self.hide_error_codes:
return (
loc + self.style("error:", "red", bold=True) + self.highlight_quote_groups(msg)
)
Expand Down
1 change: 0 additions & 1 deletion mypy_self_check.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ warn_no_return = True
strict_optional = True
disallow_any_unimported = True
show_traceback = True
show_error_codes = True
pretty = True
always_false = MYPYC
plugins = misc/proper_plugin.py
Expand Down
2 changes: 1 addition & 1 deletion mypyc/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Errors:
def __init__(self) -> None:
self.num_errors = 0
self.num_warnings = 0
self._errors = mypy.errors.Errors()
self._errors = mypy.errors.Errors(hide_error_codes=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this change? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR would have enabled error codes for mypyc as well which resulted in a lot of failing tests. I'm not sure if we should do that too. The main focus was to enable it for mypy runs which is why I added hide_error_codes=True here.


def error(self, msg: str, path: str, line: int) -> None:
self._errors.report(line, None, msg, severity="error", file=path)
Expand Down
1 change: 1 addition & 0 deletions mypyc/test/testutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def build_ir_for_single_file2(
compiler_options = compiler_options or CompilerOptions(capi_version=(3, 5))
options = Options()
options.show_traceback = True
options.hide_error_codes = True
options.use_builtins_fixtures = True
options.strict_optional = True
options.python_version = (3, 6)
Expand Down
9 changes: 9 additions & 0 deletions test-data/unit/check-errorcodes.test
Original file line number Diff line number Diff line change
Expand Up @@ -922,3 +922,12 @@ def f(d: D, s: str) -> None:
[case testRecommendErrorCode]
# type: ignore[whatever] # E: type ignore with error code is not supported for modules; use `# mypy: disable-error-code=...` [syntax]
1 + "asdf"

[case testShowErrorCodesInConfig]
# flags: --config-file tmp/mypy.ini
# Test 'show_error_codes = True' in config doesn't raise an exception
var: int = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]

[file mypy.ini]
\[mypy]
show_error_codes = True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a test for hide_error_code = False / True?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've already added one in check-flags.test right at the end.

18 changes: 13 additions & 5 deletions test-data/unit/check-flags.test
Original file line number Diff line number Diff line change
Expand Up @@ -2023,12 +2023,12 @@ x = 'should be fine'
x.trim()

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

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

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

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

[case testEnableDifferentErrorCode]
# flags: --disable-error-code attr-defined --enable-error-code name-defined --show-error-code
# flags: --disable-error-code attr-defined --enable-error-code name-defined --show-error-codes
x = 'should not be fine'
x.trim()
y.trim() # E: Name "y" is not defined [name-defined]
Expand All @@ -2054,7 +2054,7 @@ y.trim() # E: Name "y" is not defined [name-defined]
--disable-error-code return-value \
--disable-error-code call-arg \
--enable-error-code attr-defined \
--enable-error-code return-value --show-error-code
--enable-error-code return-value --show-error-codes
x = 'should be fine'
x.trim() # E: "str" has no attribute "trim" [attr-defined]

Expand Down Expand Up @@ -2109,3 +2109,11 @@ enable_error_code = ignore-without-code, truthy-bool

\[mypy-tests.*]
disable_error_code = ignore-without-code

[case testShowErrorCodes]
# flags: --show-error-codes
x: int = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]

[case testHideErrorCodes]
# flags: --hide-error-codes
x: int = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int")
6 changes: 3 additions & 3 deletions test-data/unit/daemon.test
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ Daemon started
$ dmypy check foo.py bar.py
$ dmypy recheck
$ dmypy recheck --update foo.py --remove bar.py sir_not_appearing_in_this_film.py
foo.py:1: error: Import of "bar" ignored
foo.py:1: error: Import of "bar" ignored [misc]
foo.py:1: note: (Using --follow-imports=error, module not passed on command line)
== Return code: 1
$ dmypy recheck --update bar.py
Expand Down Expand Up @@ -277,7 +277,7 @@ $ dmypy suggest foo.foo
(str) -> int
$ {python} -c "import shutil; shutil.copy('foo2.py', 'foo.py')"
$ dmypy check foo.py bar.py
bar.py:3: error: Incompatible types in assignment (expression has type "int", variable has type "str")
bar.py:3: error: Incompatible types in assignment (expression has type "int", variable has type "str") [assignment]
== Return code: 1
[file foo.py]
def foo(arg):
Expand All @@ -304,7 +304,7 @@ $ dmypy inspect foo:1:2:3:4
Command "inspect" is only valid after a "check" command (that produces no parse errors)
== Return code: 2
$ dmypy check foo.py --export-types
foo.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int")
foo.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
== Return code: 1
$ dmypy inspect foo:1
Format should be file:line:column[:end_line:end_column]
Expand Down