Description
It would be handy to support error codes to allow ignoring only specific error messages on each line. For example, here we only ignore an error about an incompatible override in class B
:
class A:
def f(self) -> None:
...
class B(A):
def f(self, x: int) -> None: # type: ignore[override]
...
If there are any other errors on that line (such as "invalid type"), they will still be reported. Using the existing blanket # type: ignore
comment risks ignoring too many errors, resulting in false negatives.
For this we need these changes:
- Make it possible to display error codes with errors (either optionally or by default).
- Support ignoring specific errors using
# type: ignore[code1, ..., codeN]
. - Implement error codes for all common errors (at least).
This is potentially a pretty disruptive change, so we need to be careful about how to do this. Here are some ideas. There is an existing PR that implements some of this (#6472). My proposal differs in various details, but the end goal is the same.
Format of error codes. There are various options such as numeric codes, strings derived from messages (as in #6472), and short error identifiers that are chosen manually. I'm leaning towards the final option. I'd like error codes to be pretty short but still understandable, and perhaps even memorable. I'm proposing that most error codes are of the form foo
, foo-bar
or foo-bar-lulz
(one to three words separated by dashes).
Granularity of error codes. I think that not every error message needs a separate code, since this could mean hundreds of different codes. The number of codes should small enough that the list of all codes is easy enough to browse. I'm thinking of maybe having 20-50 distinct error codes in the long term. We don't need a unique error code for every rare message. We can either use a category code (such as indexing
for various errors related to x[y]
expressions) or a fallback misc/other category for all unclassified errors. The misc/other category also makes adoption easy -- we can initially have lots of errors in this category, and gradually migrate additional errors to more specific codes.
Displaying error codes. We could display error codes like this in mypy output:
foo.py:124: error: Some bad stuff going on here [bad-stuff]
The rationale is that the error code is usually not important, so we shouldn't make it too prominent. This is also one of the reasons why the error codes should be pretty short. This way we could probably enable error codes by default, as they are perhaps not too distracting.
Implementing error codes. My idea would be to have error codes totally separate from error messages. Each error reporting call would optionally include the error code (it would default to a generic other/misc category code). Error codes would defined with some metadata in a new error code registry module. The metadata could be used for grouping and help output. Here's a rough idea (this will need some iteration):
# Arguments are 1) error code 2) description in help output 3) category
BAD_STUFF = ErrorCode('bad-stuff', 'Bad stuff going on', 'General')
The motivation is that no dynamic magic is required, and everything is very explicit.
Errors from plugins. I haven't thought about this much, but plugins should be able to provide a list of error code objects. These could be shown in the error code help output. Maybe plugins should generally define relatively few error codes per plugin. It would be okay to just have a single error code for all errors from a plugin, and plugins can also reuse predefined error codes.
Sample error codes. Here are few actual error codes we might want to define (these are not final and may need iteration):
"x" has no attribute "y" [attr-defined]
Unexpected keyword argument "x" for "y" [call-arg]
Signature of "x" incompatible with supertype "x" [override]
Function is missing a type annotation [no-untyped-def]
The idea is that the name of the error code typically refers to what is being checked (whether an attribute is defined; whether an argument is valid in a call; validity of a method override). Short names are preferred, as long as they are sufficiently descriptive. For errors from optional strictness options we name the error code no-x
, where x
refers to what is being disallowed.
Postponed topics. We could also migrate some existing strictness flags to error codes, and to allow enabling and disabling particular errors globally or per file. These feel less important than being able to ignore specific errors on a line right now, but they would be nice features to have. We'll also want a way to display all available error codes through a command line option, but again this isn't required initially.
Next steps. I'm planning to implement this soon, since we have a use case which requires this feature at Dropbox. I can reuse some code and ideas from #6472 if @chadrik isn't opposed to it.
cc @chadrik