diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index d667fa0ff727..e305035ceb4a 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -813,8 +813,10 @@ of the above sections. strict will catch type errors as long as intentional methods like type ignore or casting were not used.) - Note: the :option:`--warn-unreachable` flag - is not automatically enabled by the strict flag. + Note: the :option:`--warn-unreachable` flag, among others, is not + enabled by the strict flag. If you are interested in enabling even more + useful checks, you may be interested in :option:`--enable-all-error-codes` + and/or :option:`--enable-error-code`. The strict flag does not take precedence over other strict-related flags. Directly specifying a flag of alternate behavior will override the @@ -835,7 +837,7 @@ of the above sections. .. option:: --disable-error-code - This flag allows disabling one or multiple error codes globally. + This flag disables one or multiple error codes globally. See :ref:`error-codes` for more information. .. code-block:: python @@ -850,7 +852,7 @@ of the above sections. .. option:: --enable-error-code - This flag allows enabling one or multiple error codes globally. + This flag enables one or multiple error codes globally. See :ref:`error-codes` for more information. Note: This flag will override disabled error codes from the @@ -866,6 +868,29 @@ of the above sections. x = 'a string' x.trim() # error: "str" has no attribute "trim" [attr-defined] +.. option:: --enable-all-error-codes + + This flag enables all of the error codes for mypy, + including the optional ones that are off by default. + See :ref:`error-codes` and :ref:`error-codes-optional` + for more information. + + (Unlike the other flag for error code enablement, these can be countermanded + with :option:`--disable-error-code`.) + + Note that future releases of mypy will likely introduce more error codes, + so the effective result of using this flag will change from release to + release. + + While often useful, keep in mind that this flag will enable **all** error + codes, including any that may be experimental, wrongheaded, or + contradictory. + + Enabling all codes is not the same as enabling all checks that mypy could + perform; for example, :option:`--strict-bytes` is not enabled by this flag. + However, :option:`--strict` and :option:`--enable-all-error-codes` used in + tandem should be sufficient to get you virtually every useful check mypy + can perform. .. _configuring-error-messages: diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index 7abd1f02db68..af44997fa178 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -800,6 +800,15 @@ section of the command line docs. Note: This option will override disabled error codes from the disable_error_code option. +.. confval:: enable_all_error_codes + + :type: boolean + :default: False + + Enables all mypy error codes. + + Note: This option will be overridden by disabled error codes from the disable_error_code option. + .. confval:: extra_checks :type: boolean diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst index 485d70cb59bc..91c956d73702 100644 --- a/docs/source/error_codes.rst +++ b/docs/source/error_codes.rst @@ -50,6 +50,10 @@ and :option:`--disable-error-code ` to enable or disable specific error codes that don't have a dedicated command-line flag or config file setting. +:option:`--enable-all-error-codes ` enables +all optional error codes. (Unlike the other flag for error code enablement, +these can be countermanded with :option:`--disable-error-code `.) + Per-module enabling/disabling error codes ----------------------------------------- diff --git a/mypy/main.py b/mypy/main.py index 9ebbf78ded09..4eb558747789 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -955,6 +955,12 @@ def add_invertible_flag( default=[], help="Enable a specific error code", ) + strictness_group.add_argument( + "--enable-all-error-codes", + action="store_true", + help="Enable all error codes. Unlike the other flag for error code enablement," + + " these can be countermanded by --disable-error-code", + ) error_group = parser.add_argument_group( title="Configuring error messages", diff --git a/mypy/options.py b/mypy/options.py index b1456934c6c9..0468012550ee 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -261,6 +261,7 @@ def __init__(self) -> None: # Error codes to enable self.enable_error_code: list[str] = [] self.enabled_error_codes: set[ErrorCode] = set() + self.enable_all_error_codes = False # Use script name instead of __main__ self.scripts_are_modules = False @@ -468,6 +469,13 @@ def process_error_codes(self, *, error_callback: Callable[[str], Any]) -> None: # Enabling an error code always overrides disabling self.disabled_error_codes -= self.enabled_error_codes + # enable_all_error_codes codes can be countermanded by disabled_error_codes, which + # can in turn be countermanded by enabled_error_codes. But we've just computed the + # latter countermanding, so we can use the set of disabled_error_codes that weren't + # countermanded to figure out what to really turn off. + if self.enable_all_error_codes: + self.enabled_error_codes = set(error_codes.values()) - self.disabled_error_codes + def process_incomplete_features( self, *, error_callback: Callable[[str], Any], warning_callback: Callable[[str], Any] ) -> None: diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 8eec979029d0..eb0f78fa30b8 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2515,3 +2515,103 @@ A = Union[C, List] # OK -- check_untyped_defs is False by default. def f(): x: int = "no" # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs + +[case testSpotCheckEnableAllErrorCodes] +# flags: --enable-all-error-codes +# It would be annoying to check every error here, so let's just check a couple. +from typing_extensions import override + +class Parent: + def f(self, x: int) -> None: + pass + + def g(self, y: int) -> None: + pass + +class Child(Parent): + def f(self, x: int) -> None: # E: Method "f" is not using @override but is overriding a method in class "__main__.Parent" + pass + + @override + def g(self, y: int) -> None: #type: ignore # E: Unused "type: ignore" comment # E: "type: ignore" comment without error code + pass +[builtins fixtures/tuple-simple.pyi] + +[case testSpotCheckEnableAllErrorCodesNot] +# This test case exists purely to ensure that the testSpotCheckErrorCodeAll test does not become obsolete. +# (For example, if all the errors expected by testSpotCheckErrorCodeAll get turned on by default, then +# the testSpotCheckErrorCodeAll test would fail to guarantee the enablement of any additional errors! +# (hint: if that does happen, breaking this test, then consider changing these two tests to pick *different*, +# not-enabled-by-default, error codes. Also, testSpotCheckEnableAllErrorCodesConfig.)) +from typing_extensions import override + +class Parent: + def f(self, x: int) -> None: + pass + + def g(self, y: int) -> None: + pass + +class Child(Parent): + def f(self, x: int) -> None: + pass + + @override + def g(self, y: int) -> None: #type: ignore + pass +[builtins fixtures/tuple-simple.pyi] + +[case testSpotCheckEnableAllErrorCodesConfig] +# flags: --config-file tmp/mypy.ini +# This test just makes sure that the user can still countermand +# enable_all_error_codes on a more-specific level. +import tests.foo +import bar +[file bar.py] +def foo() -> int: ... +if foo: ... # E: Function "foo" could always be true in boolean context +42 + "no" # type: ignore # E: "type: ignore" comment without error code (consider "type: ignore[operator]" instead) +[file tests/__init__.py] +[file tests/foo.py] +def foo() -> int: ... +if foo: ... # E: Function "foo" could always be true in boolean context +42 + "no" # type: ignore +[file mypy.ini] +\[mypy] +enable_all_error_codes = True + +\[mypy-tests.*] +disable_error_code = ignore-without-code + +[case testSpotCheckEnableAllErrorCodesConfigCountermand-xfail] +# flags: --config-file tmp/mypy.ini +# This test makes sure that the user can still countermand error codes disables +# by *using* enable_all_error_codes on a more-specific level. +# This test would work if enable-all-error-codes was also a per-module option, +# which I guess it isn't. +import tests.foo +import bar +[file bar.py] +def foo() -> int: ... +if foo: ... # E: Function "foo" could always be true in boolean context +42 + "no" # type: ignore +[file tests/__init__.py] +[file tests/foo.py] +def foo() -> int: ... +if foo: ... # E: Function "foo" could always be true in boolean context +42 + "no" # type: ignore # E: "type: ignore" comment without error code (consider "type: ignore[operator]" instead) +[file mypy.ini] +\[mypy] +disable_error_code = ignore-without-code + +\[mypy-tests.*] +enable_all_error_codes = True + + +[case testSpotCheckEnableAllErrorCodesCountermand] +# flags: --enable-all-error-codes --disable-error-code unused-ignore +x = 2 # type: ignore # E: "type: ignore" comment without error code + +[case testSpotCheckEnableAllErrorCodesCountermandCountermand] +# flags: --enable-all-error-codes --disable-error-code ignore-without-code --disable-error-code unused-ignore --enable-error-code ignore-without-code +x = 2 # type: ignore # E: "type: ignore" comment without error code diff --git a/test-data/unit/fixtures/tuple-simple.pyi b/test-data/unit/fixtures/tuple-simple.pyi index 07f9edf63cdd..6a16fbd510bc 100644 --- a/test-data/unit/fixtures/tuple-simple.pyi +++ b/test-data/unit/fixtures/tuple-simple.pyi @@ -19,3 +19,6 @@ class function: pass class int: pass class str: pass # For convenience class dict: pass + +# Had to define this for testSpotCheckErrorCodeAll*, for whatever reason: +class ellipsis: pass