From 3f952b97d5da25e33af91d2b1b6bdd0605b7d158 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 13:20:07 -0700 Subject: [PATCH 01/20] add all error code --- docs/source/error_code_list.rst | 10 ++++++++++ docs/source/error_codes.rst | 6 ++++++ mypy/errorcodes.py | 7 ++++++- mypy/options.py | 6 +++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index 49cb8a0c06c1..d4da63a2bbb0 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -8,6 +8,16 @@ with default options. See :ref:`error-codes` for general documentation about error codes. :ref:`error-codes-optional` documents additional error codes that you can enable. +.. _code-all: + +Enable all error codes +---------------------- + +While not really an error code mypy will ever display, providing ``all`` +as an error code to be enabled (via the command-line) enables +all optional error codes. (Remember that enabling takes priority over +disabling, so other --disable-error-code flags will not countermand this.) + .. _code-attr-defined: Check that attribute exists [attr-defined] diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst index 485d70cb59bc..02e670372584 100644 --- a/docs/source/error_codes.rst +++ b/docs/source/error_codes.rst @@ -50,6 +50,11 @@ 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. +While not really an error code mypy will ever display, providing ``all`` +as an error code to be enabled (via the command-line) enables +all optional error codes. (Remember that enabling takes priority over +disabling, so other --disable-error-code flags will not countermand this.) + Per-module enabling/disabling error codes ----------------------------------------- @@ -99,6 +104,7 @@ So one can e.g. enable some code globally, disable it for all tests in the corresponding config section, and then re-enable it with an inline comment in some specific test. + Subcodes of error codes ----------------------- diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 8f650aa30605..06d065c383c1 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -45,7 +45,6 @@ def __eq__(self, other: object) -> bool: def __hash__(self) -> int: return hash((self.code,)) - ATTR_DEFINED: Final = ErrorCode("attr-defined", "Check that attribute exists", "General") NAME_DEFINED: Final = ErrorCode("name-defined", "Check that name is defined", "General") CALL_ARG: Final[ErrorCode] = ErrorCode( @@ -156,6 +155,12 @@ def __hash__(self) -> int: "await-not-async", 'Warn about "await" outside coroutine ("async def")', "General" ) # These error codes aren't enabled by default. +ALL: Final[ErrorCode] = ErrorCode( + "all", + "Enable all error codes for mypy (although not necessarily for plugins), including the optional ones that are off by default", + "General", + default_enabled=False, +) NO_UNTYPED_DEF: Final[ErrorCode] = ErrorCode( "no-untyped-def", "Check that every function has an annotation", "General" ) diff --git a/mypy/options.py b/mypy/options.py index 52afd27211ed..054abfa8606a 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -451,7 +451,11 @@ def process_error_codes(self, *, error_callback: Callable[[str], Any]) -> None: error_callback(f"Invalid error code(s): {', '.join(sorted(invalid_codes))}") self.disabled_error_codes |= {error_codes[code] for code in disabled_codes} - self.enabled_error_codes |= {error_codes[code] for code in enabled_codes} + #TODO: does this also apply for configuration files as well, or just the command line? + if "all" in enabled_codes: + self.enabled_error_codes = set(error_codes.values()) + else: + self.enabled_error_codes |= {error_codes[code] for code in enabled_codes} # Enabling an error code always overrides disabling self.disabled_error_codes -= self.enabled_error_codes From 31e2b7266848252330226be36a98c4d1fbc57560 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 13:26:25 -0700 Subject: [PATCH 02/20] formatting fixes --- mypy/errorcodes.py | 1 + mypy/options.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 06d065c383c1..b73a6808e6ac 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -45,6 +45,7 @@ def __eq__(self, other: object) -> bool: def __hash__(self) -> int: return hash((self.code,)) + ATTR_DEFINED: Final = ErrorCode("attr-defined", "Check that attribute exists", "General") NAME_DEFINED: Final = ErrorCode("name-defined", "Check that name is defined", "General") CALL_ARG: Final[ErrorCode] = ErrorCode( diff --git a/mypy/options.py b/mypy/options.py index 054abfa8606a..c2dd1ac74597 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -451,7 +451,7 @@ def process_error_codes(self, *, error_callback: Callable[[str], Any]) -> None: error_callback(f"Invalid error code(s): {', '.join(sorted(invalid_codes))}") self.disabled_error_codes |= {error_codes[code] for code in disabled_codes} - #TODO: does this also apply for configuration files as well, or just the command line? + # TODO: does this also apply for configuration files as well, or just the command line? if "all" in enabled_codes: self.enabled_error_codes = set(error_codes.values()) else: From c0e6aebe460454a11ccee10be1b347930da8577c Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 14:37:15 -0700 Subject: [PATCH 03/20] manual experimentation reveals that this code only works for the command line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit although I actually have no idea why that would be the case, as the error for using it in configuration seems inexplicable, since it consults the same list of error codes in the end 🤷 --- mypy/options.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypy/options.py b/mypy/options.py index c2dd1ac74597..31f43b92fefc 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -451,7 +451,6 @@ def process_error_codes(self, *, error_callback: Callable[[str], Any]) -> None: error_callback(f"Invalid error code(s): {', '.join(sorted(invalid_codes))}") self.disabled_error_codes |= {error_codes[code] for code in disabled_codes} - # TODO: does this also apply for configuration files as well, or just the command line? if "all" in enabled_codes: self.enabled_error_codes = set(error_codes.values()) else: From 469de6191583b13f97e625f4484554c5e6bbb31c Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 18:37:09 -0700 Subject: [PATCH 04/20] add a spotcheck test for error code all --- test-data/unit/check-flags.test | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 2a75b465099b..cfc55aa89964 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2467,3 +2467,45 @@ 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 testSpotCheckErrorCodeAll] +# flags: --enable-error-code all +# It would be annoying to check every error here, so let's just check a couple. +from typing import override + +class Parent: + def f(self, x: int) -> None: + pass + + def g(self, y: int) -> bool: + return True + +class Child(Parent): + def f(self, x: int) -> None: # E: Missing @override decorator + pass + + @override + def g(self, y: int) -> bool: #type: ignore # E: Unused "type: ignore" comment # E: "type: ignore" comment without error code + return True + +[case testSpotCheckErrorCodeAllNotUsed] +# 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!) + +from typing import override + +class Parent: + def f(self, x: int) -> None: + pass + + def g(self, y: int) -> bool: + return True + +class Child(Parent): + def f(self, x: int) -> None: + pass + + @override + def g(self, y: int) -> bool: #type: ignore + return True From ccb62cb1845312fb5028de9e0a8e303a00e555ef Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 18:55:34 -0700 Subject: [PATCH 05/20] oh, right, overrides is in typing_extensions --- test-data/unit/check-flags.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index cfc55aa89964..d4a358fdf57b 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2471,7 +2471,7 @@ def f(): [case testSpotCheckErrorCodeAll] # flags: --enable-error-code all # It would be annoying to check every error here, so let's just check a couple. -from typing import override +from typing_extensions import override class Parent: def f(self, x: int) -> None: @@ -2493,7 +2493,7 @@ class Child(Parent): # (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!) -from typing import override +from typing_extensions import override class Parent: def f(self, x: int) -> None: From 34d218e37a830394a71e6c92ee288a5114fdf384 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 19:24:24 -0700 Subject: [PATCH 06/20] I guess these need tuples --- test-data/unit/check-flags.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index d4a358fdf57b..504663570e30 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2487,6 +2487,7 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore # E: Unused "type: ignore" comment # E: "type: ignore" comment without error code return True +[builtins fixtures/tuple.pyi] [case testSpotCheckErrorCodeAllNotUsed] # This test case exists purely to ensure that the testSpotCheckErrorCodeAll test does not become obsolete. @@ -2509,3 +2510,4 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore return True +[builtins fixtures/tuple.pyi] From 035d4d63c72367e4fc61e64964c456883962b4f2 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 20:06:20 -0700 Subject: [PATCH 07/20] since I'm getting more weird errors, let's try builtins fixtures/primitives.pyi instead my plan after this, if this doesn't work, is to go to [typing fixtures/typing-full.pyi] ; I'm just blindly trying things --- test-data/unit/check-flags.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 504663570e30..38b02eaf8c58 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2487,7 +2487,7 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore # E: Unused "type: ignore" comment # E: "type: ignore" comment without error code return True -[builtins fixtures/tuple.pyi] +[builtins fixtures/primitives.pyi] [case testSpotCheckErrorCodeAllNotUsed] # This test case exists purely to ensure that the testSpotCheckErrorCodeAll test does not become obsolete. @@ -2510,4 +2510,4 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore return True -[builtins fixtures/tuple.pyi] +[builtins fixtures/primitives.pyi] From 0d50f97fcc5c171f3a4ffe0759e014645e5fc1c8 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 22:37:23 -0700 Subject: [PATCH 08/20] ...try typing fixtures/typing-full.pyi --- test-data/unit/check-flags.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 38b02eaf8c58..178026ce7f02 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2487,7 +2487,7 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore # E: Unused "type: ignore" comment # E: "type: ignore" comment without error code return True -[builtins fixtures/primitives.pyi] +[typing fixtures/typing-full.pyi] [case testSpotCheckErrorCodeAllNotUsed] # This test case exists purely to ensure that the testSpotCheckErrorCodeAll test does not become obsolete. @@ -2510,4 +2510,4 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore return True -[builtins fixtures/primitives.pyi] +[typing fixtures/typing-full.pyi] From b8fbb3489a989aae4d2e027f22878452a3a243a7 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Wed, 7 May 2025 23:07:02 -0700 Subject: [PATCH 09/20] ok now tuple is missing again. so let's try both --- test-data/unit/check-flags.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 178026ce7f02..1cf46abaf3c0 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2487,6 +2487,7 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore # E: Unused "type: ignore" comment # E: "type: ignore" comment without error code return True +[builtins fixtures/primitives.pyi] [typing fixtures/typing-full.pyi] [case testSpotCheckErrorCodeAllNotUsed] @@ -2510,4 +2511,5 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore return True +[builtins fixtures/primitives.pyi] [typing fixtures/typing-full.pyi] From dd4a34338c1ecfb219fbf20e63099fa660fdad82 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 8 May 2025 01:06:20 -0700 Subject: [PATCH 10/20] try tuple simple --- test-data/unit/check-flags.test | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 1cf46abaf3c0..6a773e4dae06 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2481,14 +2481,13 @@ class Parent: return True class Child(Parent): - def f(self, x: int) -> None: # E: Missing @override decorator + 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) -> bool: #type: ignore # E: Unused "type: ignore" comment # E: "type: ignore" comment without error code return True -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-full.pyi] +[builtins fixtures/tuple-simple.pyi] [case testSpotCheckErrorCodeAllNotUsed] # This test case exists purely to ensure that the testSpotCheckErrorCodeAll test does not become obsolete. @@ -2511,5 +2510,4 @@ class Child(Parent): @override def g(self, y: int) -> bool: #type: ignore return True -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-full.pyi] +[builtins fixtures/tuple-simple.pyi] From 787c680e6f84aeb5af17bcc02213c6f35c12d377 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 8 May 2025 14:01:58 -0700 Subject: [PATCH 11/20] fix all of the test fixture complaints --- test-data/unit/check-flags.test | 20 +++++++++++--------- test-data/unit/fixtures/tuple-simple.pyi | 3 +++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 6a773e4dae06..2268cbb86297 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2477,22 +2477,24 @@ class Parent: def f(self, x: int) -> None: pass - def g(self, y: int) -> bool: - return True + 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) -> bool: #type: ignore # E: Unused "type: ignore" comment # E: "type: ignore" comment without error code - return True + 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 testSpotCheckErrorCodeAllNotUsed] # 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!) +# 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.)) from typing_extensions import override @@ -2500,14 +2502,14 @@ class Parent: def f(self, x: int) -> None: pass - def g(self, y: int) -> bool: - return True + def g(self, y: int) -> None: + pass class Child(Parent): def f(self, x: int) -> None: pass @override - def g(self, y: int) -> bool: #type: ignore - return True + def g(self, y: int) -> None: #type: ignore + pass [builtins fixtures/tuple-simple.pyi] diff --git a/test-data/unit/fixtures/tuple-simple.pyi b/test-data/unit/fixtures/tuple-simple.pyi index 07f9edf63cdd..2ea6f14be2a9 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 testSpotCheckErrorCodeAll*, for whatever reason: +class ellipsis: pass From 07710bf8df32e70cf39f3687e7e51719d5631e15 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sun, 11 May 2025 05:53:21 -0700 Subject: [PATCH 12/20] begin pivoting to --enable-all-error-codes --- docs/source/error_code_list.rst | 10 ---------- docs/source/error_codes.rst | 4 +--- mypy/errorcodes.py | 6 ------ 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index d4da63a2bbb0..49cb8a0c06c1 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -8,16 +8,6 @@ with default options. See :ref:`error-codes` for general documentation about error codes. :ref:`error-codes-optional` documents additional error codes that you can enable. -.. _code-all: - -Enable all error codes ----------------------- - -While not really an error code mypy will ever display, providing ``all`` -as an error code to be enabled (via the command-line) enables -all optional error codes. (Remember that enabling takes priority over -disabling, so other --disable-error-code flags will not countermand this.) - .. _code-attr-defined: Check that attribute exists [attr-defined] diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst index 02e670372584..304e0e5828f2 100644 --- a/docs/source/error_codes.rst +++ b/docs/source/error_codes.rst @@ -50,8 +50,7 @@ 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. -While not really an error code mypy will ever display, providing ``all`` -as an error code to be enabled (via the command-line) enables +:option:`--enable-all-error-codes ` enables all optional error codes. (Remember that enabling takes priority over disabling, so other --disable-error-code flags will not countermand this.) @@ -104,7 +103,6 @@ So one can e.g. enable some code globally, disable it for all tests in the corresponding config section, and then re-enable it with an inline comment in some specific test. - Subcodes of error codes ----------------------- diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index b73a6808e6ac..8f650aa30605 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -156,12 +156,6 @@ def __hash__(self) -> int: "await-not-async", 'Warn about "await" outside coroutine ("async def")', "General" ) # These error codes aren't enabled by default. -ALL: Final[ErrorCode] = ErrorCode( - "all", - "Enable all error codes for mypy (although not necessarily for plugins), including the optional ones that are off by default", - "General", - default_enabled=False, -) NO_UNTYPED_DEF: Final[ErrorCode] = ErrorCode( "no-untyped-def", "Check that every function has an annotation", "General" ) From 672804073d60190a011df7997e294b9e9c9bd249 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sun, 11 May 2025 06:28:40 -0700 Subject: [PATCH 13/20] pivot to --enable-all-error-codes flag per the advice of the discussors of the github issue --- mypy/main.py | 5 +++++ mypy/options.py | 3 ++- test-data/unit/check-flags.test | 7 +++---- test-data/unit/fixtures/tuple-simple.pyi | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/mypy/main.py b/mypy/main.py index b2abf06897de..c5f1e79b8087 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -953,6 +953,11 @@ 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", + ) error_group = parser.add_argument_group( title="Configuring error messages", diff --git a/mypy/options.py b/mypy/options.py index 31f43b92fefc..a0291b2d904e 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -254,6 +254,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 @@ -451,7 +452,7 @@ def process_error_codes(self, *, error_callback: Callable[[str], Any]) -> None: error_callback(f"Invalid error code(s): {', '.join(sorted(invalid_codes))}") self.disabled_error_codes |= {error_codes[code] for code in disabled_codes} - if "all" in enabled_codes: + if self.enable_all_error_codes: self.enabled_error_codes = set(error_codes.values()) else: self.enabled_error_codes |= {error_codes[code] for code in enabled_codes} diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 2268cbb86297..a210f64280fc 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2468,8 +2468,8 @@ A = Union[C, List] # OK def f(): x: int = "no" # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs -[case testSpotCheckErrorCodeAll] -# flags: --enable-error-code all +[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 @@ -2489,13 +2489,12 @@ class Child(Parent): pass [builtins fixtures/tuple-simple.pyi] -[case testSpotCheckErrorCodeAllNotUsed] +[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.)) - from typing_extensions import override class Parent: diff --git a/test-data/unit/fixtures/tuple-simple.pyi b/test-data/unit/fixtures/tuple-simple.pyi index 2ea6f14be2a9..6a16fbd510bc 100644 --- a/test-data/unit/fixtures/tuple-simple.pyi +++ b/test-data/unit/fixtures/tuple-simple.pyi @@ -20,5 +20,5 @@ class int: pass class str: pass # For convenience class dict: pass -# Had to define this testSpotCheckErrorCodeAll*, for whatever reason: +# Had to define this for testSpotCheckErrorCodeAll*, for whatever reason: class ellipsis: pass From 465ea8cddad402ab5233cbb2d1757fd5d8ecc142 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sun, 11 May 2025 07:10:45 -0700 Subject: [PATCH 14/20] document, and add a new test --- docs/source/command_line.rst | 18 ++++++++++++++++++ docs/source/config_file.rst | 9 +++++++++ test-data/unit/check-flags.test | 24 +++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index b455e287017e..b2d6509c0fdf 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -799,6 +799,24 @@ 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` for more information. + + This flag will override disabled error codes from the + :option:`--disable-error-code ` flag. + + Note that future releases of mypy will likely introduce more error codes, + so the effective behavior of this flag will change from release to release. + + While often useful, this flag will enable **all** error codes, + including those that may be experimental, wrongheaded, or contradictory. + + It is not the same as enabling all checks that mypy could perform; + for example, :option:`--strict-bytes` is not enabled by this flag. + .. _configuring-error-messages: Configuring error messages diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index de51f0c796fd..8d707f906b9d 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -761,6 +761,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 override disabled error codes from the disable_error_code option. + .. confval:: extra_checks :type: boolean diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index a210f64280fc..32b35a623802 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2494,7 +2494,7 @@ class Child(Parent): # (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.)) +# not-enabled-by-default, error codes. Also, testSpotCheckEnableAllErrorCodesConfig.)) from typing_extensions import override class Parent: @@ -2512,3 +2512,25 @@ class Child(Parent): 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 From 9e98209c45d528ed861929f07d47fc91d90192a2 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sun, 11 May 2025 07:42:16 -0700 Subject: [PATCH 15/20] fix some typos / confusing language I found along the way --- docs/source/command_line.rst | 4 ++-- docs/source/error_code_list.rst | 4 ++-- docs/source/error_code_list2.rst | 9 ++++++--- docs/source/mypy_daemon.rst | 6 +++--- mypy/traverser.py | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index b2d6509c0fdf..2601938ef177 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -372,7 +372,7 @@ definitions or calls. .. option:: --untyped-calls-exclude - This flag allows to selectively disable :option:`--disallow-untyped-calls` + This flag allows one to selectively disable :option:`--disallow-untyped-calls` for functions and methods defined in specific packages, modules, or classes. Note that each exclude entry acts as a prefix. For example (assuming there are no type annotations for ``third_party_lib`` available): @@ -562,7 +562,7 @@ potentially problematic or redundant in some way. .. option:: --deprecated-calls-exclude - This flag allows to selectively disable :ref:`deprecated` warnings + This flag allows one to selectively disable :ref:`deprecated` warnings for functions and methods defined in specific packages, modules, or classes. Note that each exclude entry acts as a prefix. For example (assuming ``foo.A.func`` is deprecated): diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index 49cb8a0c06c1..7e8dd445c584 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -1003,8 +1003,8 @@ Warn about top level await expressions [top-level-await] This error code is separate from the general ``[syntax]`` errors, because in some environments (e.g. IPython) a top level ``await`` is allowed. In such environments a user may want to use ``--disable-error-code=top-level-await``, -that allows to still have errors for other improper uses of ``await``, for -example: +which allows one to still have errors for other improper uses of ``await``, +for example: .. code-block:: python diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst index dfe2e30874f7..6dee37c595b9 100644 --- a/docs/source/error_code_list2.rst +++ b/docs/source/error_code_list2.rst @@ -458,9 +458,12 @@ Example: # Error: unused "type: ignore" comment return a + b # type: ignore -Note that due to a specific nature of this comment, the only way to selectively -silence it, is to include the error code explicitly. Also note that this error is -not shown if the ``# type: ignore`` is not used due to code being statically +Mypy errors can typically be silenced by putting a ``# type: ignore`` comment after them, +but because this is *already* a ``# type: ignore`` comment, the only way to selectively +silence it is to include the error code explicitly, making the comment +``# type: ignore[unused-ignore]``. + +This error is not shown if the ``# type: ignore`` is not used due to code being statically unreachable (e.g. due to platform or version checks). Example: diff --git a/docs/source/mypy_daemon.rst b/docs/source/mypy_daemon.rst index 6c511e14eb95..e0fc8129a0b8 100644 --- a/docs/source/mypy_daemon.rst +++ b/docs/source/mypy_daemon.rst @@ -252,16 +252,16 @@ command. Statically inspect expressions ****************************** -The daemon allows to get declared or inferred type of an expression (or other +The daemon allows one to get the declared or inferred type of an expression (or other information about an expression, such as known attributes or definition location) -using ``dmypy inspect LOCATION`` command. The location of the expression should be +using the ``dmypy inspect LOCATION`` command. The location of the expression should be specified in the format ``path/to/file.py:line:column[:end_line:end_column]``. Both line and column are 1-based. Both start and end position are inclusive. These rules match how mypy prints the error location in error messages. If a span is given (i.e. all 4 numbers), then only an exactly matching expression is inspected. If only a position is given (i.e. 2 numbers, line and column), mypy -will inspect all *expressions*, that include this position, starting from the +will inspect all expressions that include this position, starting from the innermost one. Consider this Python code snippet: diff --git a/mypy/traverser.py b/mypy/traverser.py index 7d7794822396..3c249391bdf8 100644 --- a/mypy/traverser.py +++ b/mypy/traverser.py @@ -504,7 +504,7 @@ class ExtendedTraverserVisitor(TraverserVisitor): In addition to the base traverser it: * has visit_ methods for leaf nodes * has common method that is called for all nodes - * allows to skip recursing into a node + * allows skipping recursing into a node Note that this traverser still doesn't visit some internal mypy constructs like _promote expression and Var. From 0b32309cb075e5f2a37465550967f4161aec395b Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sun, 11 May 2025 07:54:19 -0700 Subject: [PATCH 16/20] improve documentation --- docs/source/command_line.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index 2601938ef177..bbb9e24b5479 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -768,7 +768,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 @@ -783,7 +783,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 @@ -803,19 +803,22 @@ of the above sections. This flag enables all of the error codes for mypy, including the optional ones that are off by default. - See :ref:`error-codes` for more information. + See :ref:`error-codes` and :ref:`error-codes-optional` + for more information. This flag will override disabled error codes from the :option:`--disable-error-code ` flag. Note that future releases of mypy will likely introduce more error codes, - so the effective behavior of this flag will change from release to release. + so the effective result of using this flag will change from release to + release. - While often useful, this flag will enable **all** error codes, - including those that may be experimental, wrongheaded, or contradictory. + While often useful, keep in mind that this flag will enable **all** error + codes, including any that may be experimental, wrongheaded, or + contradictory. - It is not the same as enabling all checks that mypy could perform; - for example, :option:`--strict-bytes` is not enabled by this flag. + 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. .. _configuring-error-messages: From ad5dac35c6dc27af3a17dc146fbbc9793493a635 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 14:55:50 +0000 Subject: [PATCH 17/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/main.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mypy/main.py b/mypy/main.py index c5f1e79b8087..4ab778cfabe1 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -954,9 +954,7 @@ def add_invertible_flag( help="Enable a specific error code", ) strictness_group.add_argument( - "--enable-all-error-codes", - action="store_true", - help="Enable all error codes", + "--enable-all-error-codes", action="store_true", help="Enable all error codes" ) error_group = parser.add_argument_group( From 80667872107a13c7fb55283ac47bababd30c61da Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sun, 11 May 2025 08:05:02 -0700 Subject: [PATCH 18/20] remember that I was supposed to mention this in --strict --- docs/source/command_line.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index bbb9e24b5479..ff9dfe30b2bc 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -754,8 +754,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 @@ -819,6 +821,9 @@ of the above sections. 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: From 7bae5105b03f400c169d6b857221bc2d27928beb Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sun, 11 May 2025 09:22:57 -0700 Subject: [PATCH 19/20] allow --enable-all-error-codes to be countermanded --- docs/source/command_line.rst | 4 ++-- docs/source/config_file.rst | 2 +- docs/source/error_codes.rst | 4 ++-- mypy/main.py | 5 ++++- mypy/options.py | 12 ++++++++---- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index ff9dfe30b2bc..dab4d6885159 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -808,8 +808,8 @@ of the above sections. See :ref:`error-codes` and :ref:`error-codes-optional` for more information. - This flag will override disabled error codes from the - :option:`--disable-error-code ` flag. + (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 diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index 8d707f906b9d..be3d3721dd21 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -768,7 +768,7 @@ section of the command line docs. Enables all mypy error codes. - Note: This option will override disabled error codes from the disable_error_code option. + Note: This option will be overridden by disabled error codes from the disable_error_code option. .. confval:: extra_checks diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst index 304e0e5828f2..91c956d73702 100644 --- a/docs/source/error_codes.rst +++ b/docs/source/error_codes.rst @@ -51,8 +51,8 @@ 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. (Remember that enabling takes priority over -disabling, so other --disable-error-code flags will not countermand this.) +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 4ab778cfabe1..26fcfbe8a2e2 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -954,7 +954,10 @@ def add_invertible_flag( help="Enable a specific error code", ) strictness_group.add_argument( - "--enable-all-error-codes", action="store_true", help="Enable all error codes" + "--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( diff --git a/mypy/options.py b/mypy/options.py index a0291b2d904e..91014e3b5ebb 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -452,14 +452,18 @@ def process_error_codes(self, *, error_callback: Callable[[str], Any]) -> None: error_callback(f"Invalid error code(s): {', '.join(sorted(invalid_codes))}") self.disabled_error_codes |= {error_codes[code] for code in disabled_codes} - if self.enable_all_error_codes: - self.enabled_error_codes = set(error_codes.values()) - else: - self.enabled_error_codes |= {error_codes[code] for code in enabled_codes} + self.enabled_error_codes |= {error_codes[code] for code in enabled_codes} # 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: From bf1fc81ffb672bbfa5a93dcbaf1ef1e081c02315 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sun, 11 May 2025 09:34:42 -0700 Subject: [PATCH 20/20] new tests for countermanding --- test-data/unit/check-flags.test | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 32b35a623802..e0fa52ed1126 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2534,3 +2534,11 @@ enable_all_error_codes = True \[mypy-tests.*] disable_error_code = ignore-without-code + +[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