diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index ab8adb2acd92..83d2983472be 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -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 ``[]`` to error messages. The error + This flag will hide the error 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] diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index 97913c99dd58..60d0137c5506 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -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 diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst index ccbe81a157b7..aabedf87f73a 100644 --- a/docs/source/error_codes.rst +++ b/docs/source/error_codes.rst @@ -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 ` -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 ` +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. diff --git a/docs/source/type_inference_and_annotations.rst b/docs/source/type_inference_and_annotations.rst index 7e993bcb2ff5..5c58d56d85a1 100644 --- a/docs/source/type_inference_and_annotations.rst +++ b/docs/source/type_inference_and_annotations.rst @@ -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 `: +By default, mypy displays an error code for each error: .. code-block:: text diff --git a/mypy/build.py b/mypy/build.py index 5ca2f9490991..fd9feb348d44 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -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), diff --git a/mypy/config_parser.py b/mypy/config_parser.py index f019ae9ad8ad..52f8182220c1 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -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: diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py index c9b622c768b9..799b94d5a20b 100644 --- a/mypy/dmypy_server.py +++ b/mypy/dmypy_server.py @@ -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]}" diff --git a/mypy/errors.py b/mypy/errors.py index 00f715a0c4d6..53c00a8b368b 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -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, @@ -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 @@ -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}]" diff --git a/mypy/fastparse.py b/mypy/fastparse.py index a5bd152a643c..a5c51c72934e 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -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: diff --git a/mypy/main.py b/mypy/main.py index 8a30139a96a6..d0d3e3182f2e 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -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. @@ -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 = [] @@ -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( diff --git a/mypy/options.py b/mypy/options.py index 3898d78dec32..0b470db9f907 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -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 diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index cd3ae4b71071..8bee8073bd16 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -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): diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py index f62c5a8fe0f7..80475efbe68f 100644 --- a/mypy/test/testcheck.py +++ b/mypy/test/testcheck.py @@ -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 diff --git a/mypy/test/testcmdline.py b/mypy/test/testcmdline.py index 684b082021de..00818871a1c3 100644 --- a/mypy/test/testcmdline.py +++ b/mypy/test/testcmdline.py @@ -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() diff --git a/mypy/test/testdaemon.py b/mypy/test/testdaemon.py index 04a9c387b68a..e3cdf44d89f2 100644 --- a/mypy/test/testdaemon.py +++ b/mypy/test/testdaemon.py @@ -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 "): diff --git a/mypy/test/testerrorstream.py b/mypy/test/testerrorstream.py index bae26b148a79..4b98f10fc9ca 100644 --- a/mypy/test/testerrorstream.py +++ b/mypy/test/testerrorstream.py @@ -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] = [] diff --git a/mypy/test/testparse.py b/mypy/test/testparse.py index f8990897d072..6a2d1e145251 100644 --- a/mypy/test/testparse.py +++ b/mypy/test/testparse.py @@ -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) diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py index e4123bfdff17..1602bae6a51f 100644 --- a/mypy/test/testpep561.py +++ b/mypy/test/testpep561.py @@ -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}") diff --git a/mypy/test/testpythoneval.py b/mypy/test/testpythoneval.py index a5eaea769515..ec99f9c83f4e 100644 --- a/mypy/test/testpythoneval.py +++ b/mypy/test/testpythoneval.py @@ -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))}") diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index d74949fde783..5a6904bfaaf4 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -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: diff --git a/mypy/util.py b/mypy/util.py index 13d0a311ccb6..582800621e4d 100644 --- a/mypy/util.py +++ b/mypy/util.py @@ -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 @@ -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) ) diff --git a/mypy_self_check.ini b/mypy_self_check.ini index 0852fd82cf47..39eea5d1516c 100644 --- a/mypy_self_check.ini +++ b/mypy_self_check.ini @@ -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 diff --git a/mypyc/errors.py b/mypyc/errors.py index 2fb07c10827a..1dd269fe25f3 100644 --- a/mypyc/errors.py +++ b/mypyc/errors.py @@ -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) def error(self, msg: str, path: str, line: int) -> None: self._errors.report(line, None, msg, severity="error", file=path) diff --git a/mypyc/test/testutil.py b/mypyc/test/testutil.py index dc771b00551d..871dce79664e 100644 --- a/mypyc/test/testutil.py +++ b/mypyc/test/testutil.py @@ -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) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 401407c9d426..c796ac90215d 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -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 diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index cc1e46d86caa..1c58b0ebb8bd 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -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() @@ -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] @@ -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] @@ -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") diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index 370413ee774b..3295ef01885a 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -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 @@ -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): @@ -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]