From 1382b7c3755c7b5696aadfc6af7362aa6862aaad Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 06:22:08 +0700 Subject: [PATCH 01/20] Update check-errorcodes.test: add xfail test case for https://github.com/python/mypy/issues/19840 --- test-data/unit/check-errorcodes.test | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index bb5f658ebb50..f6dd7a307164 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -1,6 +1,11 @@ -- Tests for error codes and ignoring errors using error codes -- --- These implicitly use --show-error-codes. +-- These implicitly use --show-error-codes. # TODO: isn't this statement redundant now that this flag defaults to true? + +[case testErrorCodeMiscDoesntSuppressRevealType-xfail] +# Prevent regression on https://github.com/python/mypy/issues/19840 +from typing import reveal_type +reveal_type(1) #type: ignore[misc] # N: Revealed type is "Literal[1]?" [case testErrorCodeNoAttribute] import m From dbbba52a4ea772faed13287b0ae7a7aec6a46085 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 06:31:43 +0700 Subject: [PATCH 02/20] Update check-errorcodes.test: add reveal_locals --- test-data/unit/check-errorcodes.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index f6dd7a307164..61ce36b3e464 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -7,6 +7,9 @@ from typing import reveal_type reveal_type(1) #type: ignore[misc] # N: Revealed type is "Literal[1]?" +[case testErrorCodeMiscDoesntSuppressRevealLocals-xfail] +reveal_locals() #type:ignore[misc] # N: There are no locals to reveal + [case testErrorCodeNoAttribute] import m m.x # E: Module has no attribute "x" [attr-defined] From 5fc0ccdc41854500cb99e2cf8d12c92c66cacd29 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 06:36:08 +0700 Subject: [PATCH 03/20] Update errors.py: allow error codes to be None and not default to misc --- mypy/errors.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index f1b2faf67401..5a995c9d6e2c 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -509,7 +509,7 @@ def report( line: line number of error column: column number of error message: message to report - code: error code (defaults to 'misc'; not shown for notes) + code: error code (not shown for notes), may be None blocker: if True, don't continue analysis after this error severity: 'error' or 'note' file: if non-None, override current file as context @@ -548,7 +548,6 @@ def report( end_line = line code = code or (parent_error.code if parent_error else None) - code = code or (codes.MISC if not blocker else None) info = ErrorInfo( import_ctx=self.import_context(), From a366c8065ed32d33894fb5754dd3c250d4db0f72 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 07:04:20 +0700 Subject: [PATCH 04/20] Update errors.py: try only defaulting to None for notes --- mypy/errors.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index 5a995c9d6e2c..877caa9a7a9a 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -6,7 +6,7 @@ from collections import defaultdict from collections.abc import Iterable, Iterator from itertools import chain -from typing import Callable, Final, NoReturn, Optional, TextIO, TypeVar +from typing import Callable, Final, Literal, NoReturn, Optional, TextIO, TypeVar from typing_extensions import Literal, Self, TypeAlias as _TypeAlias from mypy import errorcodes as codes @@ -494,7 +494,7 @@ def report( code: ErrorCode | None = None, *, blocker: bool = False, - severity: str = "error", + severity: Literal["note", "error"] = "error", file: str | None = None, only_once: bool = False, origin_span: Iterable[int] | None = None, @@ -509,7 +509,7 @@ def report( line: line number of error column: column number of error message: message to report - code: error code (not shown for notes), may be None + code: error code (defaults to misc; or None for notes), not shown for notes blocker: if True, don't continue analysis after this error severity: 'error' or 'note' file: if non-None, override current file as context @@ -548,6 +548,11 @@ def report( end_line = line code = code or (parent_error.code if parent_error else None) + if code is None: + if blocker or (severity=='note'): + code = None # do we even need to do this for blockers? + else: + code = codes.MISC info = ErrorInfo( import_ctx=self.import_context(), From 3a4d7c625c9cb83e141fe9dd4b5f09d64c053df9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 00:06:11 +0000 Subject: [PATCH 05/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/errors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index 877caa9a7a9a..23cc499600fe 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -549,8 +549,8 @@ def report( code = code or (parent_error.code if parent_error else None) if code is None: - if blocker or (severity=='note'): - code = None # do we even need to do this for blockers? + if blocker or (severity == "note"): + code = None # do we even need to do this for blockers? else: code = codes.MISC From ad715ec8dc1556fe3db17d32932b0cc93740bfcd Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 07:06:56 +0700 Subject: [PATCH 06/20] remove xfails --- test-data/unit/check-errorcodes.test | 4 ++-- test-requirements.txt | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 61ce36b3e464..c353b7c0c475 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -2,12 +2,12 @@ -- -- These implicitly use --show-error-codes. # TODO: isn't this statement redundant now that this flag defaults to true? -[case testErrorCodeMiscDoesntSuppressRevealType-xfail] +[case testErrorCodeMiscDoesntSuppressRevealType] # Prevent regression on https://github.com/python/mypy/issues/19840 from typing import reveal_type reveal_type(1) #type: ignore[misc] # N: Revealed type is "Literal[1]?" -[case testErrorCodeMiscDoesntSuppressRevealLocals-xfail] +[case testErrorCodeMiscDoesntSuppressRevealLocals] reveal_locals() #type:ignore[misc] # N: There are no locals to reveal [case testErrorCodeNoAttribute] diff --git a/test-requirements.txt b/test-requirements.txt index 521208c5aa27..ca7127b31fc5 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -21,8 +21,6 @@ filelock==3.19.1 identify==2.6.13 # via pre-commit iniconfig==2.1.0 - # via pytest -lxml==6.0.1 ; python_version < "3.15" # via -r test-requirements.in mypy-extensions==1.1.0 # via -r mypy-requirements.txt From 756a5c148f7e7dc1933289e9df3c0031db6d09f2 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 07:10:48 +0700 Subject: [PATCH 07/20] restore --- test-requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-requirements.txt b/test-requirements.txt index ca7127b31fc5..521208c5aa27 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -21,6 +21,8 @@ filelock==3.19.1 identify==2.6.13 # via pre-commit iniconfig==2.1.0 + # via pytest +lxml==6.0.1 ; python_version < "3.15" # via -r test-requirements.in mypy-extensions==1.1.0 # via -r mypy-requirements.txt From 6cff29db3736725e2a66f709c2f0910604bdb845 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 07:13:58 +0700 Subject: [PATCH 08/20] whoops --- mypy/errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/errors.py b/mypy/errors.py index 23cc499600fe..53664a83e7c2 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -6,7 +6,7 @@ from collections import defaultdict from collections.abc import Iterable, Iterator from itertools import chain -from typing import Callable, Final, Literal, NoReturn, Optional, TextIO, TypeVar +from typing import Callable, Final, NoReturn, Optional, TextIO, TypeVar from typing_extensions import Literal, Self, TypeAlias as _TypeAlias from mypy import errorcodes as codes From 0cc5db3f9d1fbbd76b1e86148a731d90b63c69ad Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 07:53:13 +0700 Subject: [PATCH 09/20] Update errors.py: make Severity a type --- mypy/errors.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index 53664a83e7c2..3771fb41147f 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -21,6 +21,8 @@ T = TypeVar("T") +Severity = Literal["note", "warning", "error"] + # Show error codes for some note-level messages (these usually appear alone # and not as a comment for a previous error-level message). SHOW_NOTE_CODES: Final = {codes.ANNOTATION_UNCHECKED, codes.DEPRECATED} @@ -79,8 +81,8 @@ class ErrorInfo: # The end column number related to this error with file. end_column = 0 # -1 if unknown - # Either 'error' or 'note' - severity = "" + # A set string indicating the badness of the info + severity: Severity = "" # The error message. message = "" @@ -494,7 +496,7 @@ def report( code: ErrorCode | None = None, *, blocker: bool = False, - severity: Literal["note", "error"] = "error", + severity: Severity = "error", file: str | None = None, only_once: bool = False, origin_span: Iterable[int] | None = None, @@ -511,7 +513,7 @@ def report( message: message to report code: error code (defaults to misc; or None for notes), not shown for notes blocker: if True, don't continue analysis after this error - severity: 'error' or 'note' + severity: a Severity like "note" or "error" file: if non-None, override current file as context only_once: if True, only report this exact message once per build origin_span: if non-None, override current context as origin From af86853424bc7439e628f86fcc5ef3b5daea8048 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 07:57:56 +0700 Subject: [PATCH 10/20] Update errors.py: put the severity in the bag bro --- mypy/errors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index 3771fb41147f..161496c53d9f 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -82,7 +82,7 @@ class ErrorInfo: end_column = 0 # -1 if unknown # A set string indicating the badness of the info - severity: Severity = "" + severity: Severity # The error message. message = "" @@ -123,7 +123,7 @@ def __init__( column: int, end_line: int, end_column: int, - severity: str, + severity: Severity, message: str, code: ErrorCode | None, blocker: bool, From 14e165df54edcd2afafee1e5f55c08c1766985ea Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 08:05:43 +0700 Subject: [PATCH 11/20] mop up remaining severities --- mypy/messages.py | 3 ++- mypy/semanal_classprop.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mypy/messages.py b/mypy/messages.py index 6329cad687f6..67606bd7fc47 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -29,6 +29,7 @@ ErrorWatcher, IterationDependentErrors, IterationErrorWatcher, + Severity, ) from mypy.nodes import ( ARG_NAMED, @@ -233,7 +234,7 @@ def report( self, msg: str, context: Context | None, - severity: str, + severity: Severity, *, code: ErrorCode | None = None, file: str | None = None, diff --git a/mypy/semanal_classprop.py b/mypy/semanal_classprop.py index c5ad34122f6c..a35359715047 100644 --- a/mypy/semanal_classprop.py +++ b/mypy/semanal_classprop.py @@ -7,7 +7,7 @@ from typing import Final -from mypy.errors import Errors +from mypy.errors import Errors, Severity from mypy.nodes import ( IMPLICITLY_ABSTRACT, IS_ABSTRACT, @@ -102,7 +102,7 @@ def calculate_class_abstract_status(typ: TypeInfo, is_stub_file: bool, errors: E return if abstract and not abstract_in_this_class: - def report(message: str, severity: str) -> None: + def report(message: str, severity: Severity) -> None: errors.report(typ.line, typ.column, message, severity=severity) attrs = ", ".join(f'"{attr}"' for attr, _ in sorted(abstract)) From fa2e72b6564150b51e31d3a183da8878f153ac9b Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 08:06:28 +0700 Subject: [PATCH 12/20] try out a fix for this common code, that i will probably remove later as a special case --- mypy/plugins/proper_plugin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mypy/plugins/proper_plugin.py b/mypy/plugins/proper_plugin.py index 0189bfbd22fc..15a846ddfa35 100644 --- a/mypy/plugins/proper_plugin.py +++ b/mypy/plugins/proper_plugin.py @@ -12,6 +12,7 @@ from typing import Callable from mypy.checker import TypeChecker +from mypy.errorcodes import MISC from mypy.nodes import TypeInfo from mypy.plugin import FunctionContext, Plugin from mypy.subtypes import is_proper_subtype @@ -72,6 +73,7 @@ def isinstance_proper_hook(ctx: FunctionContext) -> Type: "If you pass on the original type" " after the check, always use its unexpanded version", ctx.context, + code=MISC, ) return ctx.default_return_type From 9be5dc32e09757374227a11d8bbad5dac6bf3826 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 08:08:05 +0700 Subject: [PATCH 13/20] Revert "try out a fix for this common code, that i will probably remove later as a special case" This reverts commit fa2e72b6564150b51e31d3a183da8878f153ac9b. --- mypy/plugins/proper_plugin.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mypy/plugins/proper_plugin.py b/mypy/plugins/proper_plugin.py index 15a846ddfa35..0189bfbd22fc 100644 --- a/mypy/plugins/proper_plugin.py +++ b/mypy/plugins/proper_plugin.py @@ -12,7 +12,6 @@ from typing import Callable from mypy.checker import TypeChecker -from mypy.errorcodes import MISC from mypy.nodes import TypeInfo from mypy.plugin import FunctionContext, Plugin from mypy.subtypes import is_proper_subtype @@ -73,7 +72,6 @@ def isinstance_proper_hook(ctx: FunctionContext) -> Type: "If you pass on the original type" " after the check, always use its unexpanded version", ctx.context, - code=MISC, ) return ctx.default_return_type From 57b50818b7fd89894793e98e7a6943af56017d66 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 08:21:50 +0700 Subject: [PATCH 14/20] allow notes to inherit codes --- mypy/errors.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mypy/errors.py b/mypy/errors.py index 161496c53d9f..98bd88b13cc4 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -551,8 +551,13 @@ def report( code = code or (parent_error.code if parent_error else None) if code is None: - if blocker or (severity == "note"): + if blocker: code = None # do we even need to do this for blockers? + elif (severity == "note"): + if parent_error is not None: + code = parent_error.code # this might be None, btw + else: + code = None else: code = codes.MISC From 3874155d85a981431cb47c71acb9a77300f4862c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 03:27:11 +0000 Subject: [PATCH 15/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/errors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index 98bd88b13cc4..f2dea47008d9 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -553,9 +553,9 @@ def report( if code is None: if blocker: code = None # do we even need to do this for blockers? - elif (severity == "note"): + elif severity == "note": if parent_error is not None: - code = parent_error.code # this might be None, btw + code = parent_error.code # this might be None, btw else: code = None else: From c42c817df59c012a41d241d2c3484cde6c011a4d Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 15:05:35 +0700 Subject: [PATCH 16/20] add test case for misc silencing redefinition notes this is found in mypy_primer's corpus, but wasn't in our local tests. This covers silencing associated notes --- test-data/unit/check-errorcodes.test | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index c353b7c0c475..61d8f9673f24 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -10,6 +10,14 @@ reveal_type(1) #type: ignore[misc] # N: Revealed type is "Literal[1]?" [case testErrorCodeMiscDoesntSuppressRevealLocals] reveal_locals() #type:ignore[misc] # N: There are no locals to reveal +[case testErrorCodeMiscRedefinitionNotes] +# flags: --strict +if x: #type: ignore[name-defined] + def y() -> None: pass +else: + def y() -> bool: return True # type: ignore[misc] + + [case testErrorCodeNoAttribute] import m m.x # E: Module has no attribute "x" [attr-defined] From 27c851764d197e3e82f863318f13eb09c3a1b3cc Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 15:27:49 +0700 Subject: [PATCH 17/20] Revert "start making Severity a type instead of str" This reverts commit 18ca5cfd968dc33eac802169c4132f40f3a19250. This will allow the PR that fixes this problem to be more focused. --- mypy/errors.py | 12 +++++------- mypy/messages.py | 3 +-- mypy/semanal_classprop.py | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index f2dea47008d9..11d1cbbec207 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -21,8 +21,6 @@ T = TypeVar("T") -Severity = Literal["note", "warning", "error"] - # Show error codes for some note-level messages (these usually appear alone # and not as a comment for a previous error-level message). SHOW_NOTE_CODES: Final = {codes.ANNOTATION_UNCHECKED, codes.DEPRECATED} @@ -81,8 +79,8 @@ class ErrorInfo: # The end column number related to this error with file. end_column = 0 # -1 if unknown - # A set string indicating the badness of the info - severity: Severity + # Either 'error' or 'note' + severity = "" # The error message. message = "" @@ -123,7 +121,7 @@ def __init__( column: int, end_line: int, end_column: int, - severity: Severity, + severity: str, message: str, code: ErrorCode | None, blocker: bool, @@ -496,7 +494,7 @@ def report( code: ErrorCode | None = None, *, blocker: bool = False, - severity: Severity = "error", + severity: str = "error", file: str | None = None, only_once: bool = False, origin_span: Iterable[int] | None = None, @@ -513,7 +511,7 @@ def report( message: message to report code: error code (defaults to misc; or None for notes), not shown for notes blocker: if True, don't continue analysis after this error - severity: a Severity like "note" or "error" + severity: 'error' or 'note' file: if non-None, override current file as context only_once: if True, only report this exact message once per build origin_span: if non-None, override current context as origin diff --git a/mypy/messages.py b/mypy/messages.py index 67606bd7fc47..6329cad687f6 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -29,7 +29,6 @@ ErrorWatcher, IterationDependentErrors, IterationErrorWatcher, - Severity, ) from mypy.nodes import ( ARG_NAMED, @@ -234,7 +233,7 @@ def report( self, msg: str, context: Context | None, - severity: Severity, + severity: str, *, code: ErrorCode | None = None, file: str | None = None, diff --git a/mypy/semanal_classprop.py b/mypy/semanal_classprop.py index a35359715047..c5ad34122f6c 100644 --- a/mypy/semanal_classprop.py +++ b/mypy/semanal_classprop.py @@ -7,7 +7,7 @@ from typing import Final -from mypy.errors import Errors, Severity +from mypy.errors import Errors from mypy.nodes import ( IMPLICITLY_ABSTRACT, IS_ABSTRACT, @@ -102,7 +102,7 @@ def calculate_class_abstract_status(typ: TypeInfo, is_stub_file: bool, errors: E return if abstract and not abstract_in_this_class: - def report(message: str, severity: Severity) -> None: + def report(message: str, severity: str) -> None: errors.report(typ.line, typ.column, message, severity=severity) attrs = ", ".join(f'"{attr}"' for attr, _ in sorted(abstract)) From 1ba24c53997fd08b341f2e4b046d275c41407b36 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Thu, 18 Sep 2025 21:26:54 +0700 Subject: [PATCH 18/20] add an unsuppressed example as well --- test-data/unit/check-errorcodes.test | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 61d8f9673f24..75a4e5d80efa 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -10,12 +10,17 @@ reveal_type(1) #type: ignore[misc] # N: Revealed type is "Literal[1]?" [case testErrorCodeMiscDoesntSuppressRevealLocals] reveal_locals() #type:ignore[misc] # N: There are no locals to reveal -[case testErrorCodeMiscRedefinitionNotes] +[case testErrorCodeMiscSuppressesAccompanyingNotes] # flags: --strict if x: #type: ignore[name-defined] def y() -> None: pass else: def y() -> bool: return True # type: ignore[misc] + def y() -> str: return "hmm" # All conditional function variants must have identical signatures [misc] # E: All conditional function variants must have identical signatures [misc] \ + # N: Original: \ + # N: def y() -> None \ + # N: Redefinition: \ + # N: def y() -> str [case testErrorCodeNoAttribute] From a64f74e5b519dcad513c79245ade52d2d6572ab1 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sat, 20 Sep 2025 15:21:25 +0700 Subject: [PATCH 19/20] parent all redefinition notes correctly --- mypy/messages.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/messages.py b/mypy/messages.py index 6329cad687f6..ff9c9dcd48f9 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -1516,9 +1516,9 @@ def incompatible_conditional_function_def( if isinstance(old_type, (CallableType, Overloaded)) and isinstance( new_type, (CallableType, Overloaded) ): - self.note("Original:", defn) + self.note("Original:", defn, parent_error=error) self.pretty_callable_or_overload(old_type, defn, offset=4, parent_error=error) - self.note("Redefinition:", defn) + self.note("Redefinition:", defn, parent_error=error) self.pretty_callable_or_overload(new_type, defn, offset=4, parent_error=error) def cannot_instantiate_abstract_class( From b22e1d647d6f710993327a293a323a1ea01571ac Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sat, 20 Sep 2025 17:58:04 +0700 Subject: [PATCH 20/20] reparent proper_plugin note --- mypy/checker.py | 8 ++++---- mypy/plugins/proper_plugin.py | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 96b55f321a73..d93dab43b0b4 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -7734,7 +7734,7 @@ def fail( ) -> ErrorInfo: """Produce an error message.""" if isinstance(msg, ErrorMessage): - return self.msg.fail(msg.value, context, code=msg.code) + msg, code = msg.value, msg.code # type: ignore[attr-defined] #TODO: https://github.com/python/mypy/issues/19891 return self.msg.fail(msg, context, code=code) def note( @@ -7744,12 +7744,12 @@ def note( offset: int = 0, *, code: ErrorCode | None = None, + parent_error: ErrorInfo | None = None, ) -> None: """Produce a note.""" if isinstance(msg, ErrorMessage): - self.msg.note(msg.value, context, code=msg.code) - return - self.msg.note(msg, context, offset=offset, code=code) + msg, code = msg.value, msg.code # type: ignore[attr-defined] #TODO: https://github.com/python/mypy/issues/19891 + self.msg.note(msg, context, offset=offset, code=code, parent_error=parent_error) def iterable_item_type( self, it: Instance | CallableType | TypeType | Overloaded, context: Context diff --git a/mypy/plugins/proper_plugin.py b/mypy/plugins/proper_plugin.py index 0189bfbd22fc..1c7d7c55756d 100644 --- a/mypy/plugins/proper_plugin.py +++ b/mypy/plugins/proper_plugin.py @@ -63,7 +63,7 @@ def isinstance_proper_hook(ctx: FunctionContext) -> Type: ) and is_dangerous_target(right): if is_special_target(right): return ctx.default_return_type - ctx.api.fail( + parent_error = ctx.api.fail( "Never apply isinstance() to unexpanded types;" " use mypy.types.get_proper_type() first", ctx.context, @@ -72,6 +72,7 @@ def isinstance_proper_hook(ctx: FunctionContext) -> Type: "If you pass on the original type" " after the check, always use its unexpanded version", ctx.context, + parent_error=parent_error, ) return ctx.default_return_type