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.
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
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
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!
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]
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.
- Python Type Hints - Mypy doesn’t allow variables to change type
- Python Type Hints - How to Upgrade Syntax with pyupgrade
- Python Type Hints - How to use Mypy’s unreachable code detection
Tags: mypy, python