Python Type Hints - How to Manage “type: ignore” Comments with Mypy

It seems inevitable that large projects need some # type: ignore
comments, to work around type checking in tricky cases. I’ve found Mypy has a couple of opt-in flags to make such ignore comments more precise and manageable.
These flags are:
show_error_codes
, which tells Mypy to identify error messages with their codes, which we can then use in ignore comments.warn_unused_ignores
, which tells Mypy to log errors for unnecessary ignore comments.
We can activate these flags for a whole project in setup.cfg
like so:
[mypy]
show_error_codes = True
warn_unused_ignores = True
Let’s look at each flag in more detail.
show_error_codes
This first flag helps us write focused ignore comments that only disable the checks we want to ignore. When show_error_codes
is enabled, Mypy identifies errors not only with messages but also codes. We can use these codes in ignore comments, reducing the risk of other errors being introduced on such lines.
Take this example code:
x: int
x: str
Mypy logs an error when we redefine the type of a variable like this. This is normally a reason to change our code, but let’s roll with it for this example.
Let’s run Mypy on this example, with show_error_codes = True
:
$ mypy example.py
example.py:2: error: Name 'x' already defined on line 1 [no-redef]
Found 1 error in 1 file (checked 1 source file)
The error message is followed by the error code in square brackets: [no-redef]
. We can use this bracketed error code in an ignore comment to silence only that error:
x: int
x: str # type: ignore [no-redef]
Running Mypy now shows no errors:
$ mypy --show-error-codes example.py
Success: no issues found in 1 source file
Great.
We can introduce a different error on the ignored line and Mypy will still detect it. For example, we can add a reference to an undefined variable y
:
x: int
x: str = y # type: ignore [no-redef]
Mypy finds the bug:
$ mypy example.py
example.py:2: error: Name 'y' is not defined [name-defined]
Found 1 error in 1 file (checked 1 source file)
This error would be ignore if the line used a generic ignore comment, without the bracketed error code.
If we ever need it, we can ignore two errors by combining their codes in a comma-separated list:
x: int
x: str = y # type: ignore [name-defined,no-redef]
But this may also be a signal to split the line, or fix the causes of the errors!
warn_unused_ignores
This second flag helps us manage ignore comments as our code changes. When warn_unused_ignores
is enabled, Mypy will log an error (not a warning) for each unnecessary ignore comment. Such redundancy can appear as our code evolves, such as when our type hints become more accurate.
For example, imagine if we changed our previous example to remove the first line:
x: str # type: ignore [no-redef]
Now x
is only defined once. Running Mypy with warn_unused_ignores = True
:
$ mypy --warn-unused-ignores example.py
example.py:1: error: unused 'type: ignore' comment
Found 1 error in 1 file (checked 1 source file)
We get an error telling us that we can remove that ignore comment. Neat!
Make your development more pleasant with Boost Your Django DX.
One summary email a week, no spam, I pinky promise.
Related posts: