2020# Show error codes for some note-level messages (these usually appear alone
2121# and not as a comment for a previous error-level message).
2222SHOW_NOTE_CODES : Final = {codes .ANNOTATION_UNCHECKED }
23+
24+ # Do not add notes with links to error code docs to errors with these codes.
25+ # We can tweak this set as we get more experience about what is helpful and what is not.
26+ HIDE_LINK_CODES : Final = {
27+ # This is a generic error code, so it has no useful docs
28+ codes .MISC ,
29+ # These are trivial and have some custom notes (e.g. for list being invariant)
30+ codes .ASSIGNMENT ,
31+ codes .ARG_TYPE ,
32+ codes .RETURN_VALUE ,
33+ # Undefined name/attribute errors are self-explanatory
34+ codes .ATTR_DEFINED ,
35+ codes .NAME_DEFINED ,
36+ # Overrides have a custom link to docs
37+ codes .OVERRIDE ,
38+ }
39+
2340allowed_duplicates : Final = ["@overload" , "Got:" , "Expected:" ]
2441
42+ BASE_RTD_URL : Final = "https://mypy.rtfd.io/en/stable/_refs.html#code"
43+
2544# Keep track of the original error code when the error code of a message is changed.
2645# This is used to give notes about out-of-date "type: ignore" comments.
2746original_error_codes : Final = {codes .LITERAL_REQ : codes .MISC , codes .TYPE_ABSTRACT : codes .MISC }
@@ -107,6 +126,7 @@ def __init__(
107126 allow_dups : bool ,
108127 origin : tuple [str , Iterable [int ]] | None = None ,
109128 target : str | None = None ,
129+ priority : int = 0 ,
110130 ) -> None :
111131 self .import_ctx = import_ctx
112132 self .file = file
@@ -125,6 +145,7 @@ def __init__(
125145 self .allow_dups = allow_dups
126146 self .origin = origin or (file , [line ])
127147 self .target = target
148+ self .priority = priority
128149
129150
130151# Type used internally to represent errors:
@@ -530,6 +551,35 @@ def add_error_info(self, info: ErrorInfo) -> None:
530551 allow_dups = False ,
531552 )
532553 self ._add_error_info (file , note )
554+ if (
555+ self .options .show_error_code_links
556+ and not self .options .hide_error_codes
557+ and info .code is not None
558+ and info .code not in HIDE_LINK_CODES
559+ ):
560+ message = f"See { BASE_RTD_URL } -{ info .code .code } for more info"
561+ if message in self .only_once_messages :
562+ return
563+ self .only_once_messages .add (message )
564+ info = ErrorInfo (
565+ import_ctx = info .import_ctx ,
566+ file = info .file ,
567+ module = info .module ,
568+ typ = info .type ,
569+ function_or_member = info .function_or_member ,
570+ line = info .line ,
571+ column = info .column ,
572+ end_line = info .end_line ,
573+ end_column = info .end_column ,
574+ severity = "note" ,
575+ message = message ,
576+ code = info .code ,
577+ blocker = False ,
578+ only_once = True ,
579+ allow_dups = False ,
580+ priority = 20 ,
581+ )
582+ self ._add_error_info (file , info )
533583
534584 def has_many_errors (self ) -> bool :
535585 if self .options .many_errors_threshold < 0 :
@@ -1041,6 +1091,34 @@ def sort_messages(self, errors: list[ErrorInfo]) -> list[ErrorInfo]:
10411091
10421092 # Sort the errors specific to a file according to line number and column.
10431093 a = sorted (errors [i0 :i ], key = lambda x : (x .line , x .column ))
1094+ a = self .sort_within_context (a )
1095+ result .extend (a )
1096+ return result
1097+
1098+ def sort_within_context (self , errors : list [ErrorInfo ]) -> list [ErrorInfo ]:
1099+ """For the same location decide which messages to show first/last.
1100+
1101+ Currently, we only compare within the same error code, to decide the
1102+ order of various additional notes.
1103+ """
1104+ result = []
1105+ i = 0
1106+ while i < len (errors ):
1107+ i0 = i
1108+ # Find neighbouring errors with the same position and error code.
1109+ while (
1110+ i + 1 < len (errors )
1111+ and errors [i + 1 ].line == errors [i ].line
1112+ and errors [i + 1 ].column == errors [i ].column
1113+ and errors [i + 1 ].end_line == errors [i ].end_line
1114+ and errors [i + 1 ].end_column == errors [i ].end_column
1115+ and errors [i + 1 ].code == errors [i ].code
1116+ ):
1117+ i += 1
1118+ i += 1
1119+
1120+ # Sort the messages specific to a given error by priority.
1121+ a = sorted (errors [i0 :i ], key = lambda x : x .priority )
10441122 result .extend (a )
10451123 return result
10461124
0 commit comments