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

Clamp down on them comments!

Update (2022-09-07): Added enable_error_code = ['ignore-without-code'] to the post.

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 few options to make such ignore comments more precise and manageable.

These options are:

You can activate these flags for a whole project in pyproject.toml like so:

[tool.mypy]
enable_error_code = [
    "ignore-without-code"
]
show_error_codes = True
warn_unused_ignores = True

Let’s look at each flag in more detail.

show_error_codes

Update (2022-11-08): Mypy 0.900 changed to enable this option by default. So, you don’t need to add it to your configuration any more.

This first flag helps you write focused ignore comments that only disable the checks we want to ignore. When show_error_codes is enabled, Mypy identifies errors with both a messages and an error code. You can use these codes in ignore comments, reducing the risk of other errors being introduced on commented lines.

Take this example code:

x: int
x: str

Mypy logs an error when you redefine the type of a variable like this. This is normally a reason to use a second variable, but let’s roll with it for this example.

Let’s run Mypy on this example, with show_error_codes on:

$ 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.

By restricting the error code, if you later introduce a different error on the ignored line, Mypy will still report it. For example, you might 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 ignored if the line used an ignore comment without any error code.

If you ever need to, you can ignore two (or more) 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 errors!

enable_error_code = ['ignore-without-code']

This second option makes Mypy report errors for # type: ignore comments without specific error codes. ignore-without-code is one of several optional error codes that need explicitly enabling in the enable_error_code option.

For example, take the first example again, with the reassignment error ignored with a non-specific comment:

x: int
x: str  # type: ignore

When you run Mypy with ignore-without-code enabled, it will disallow this comment:

$ mypy example.py
example.py:2: error: "type: ignore" comment without error code (consider "type: ignore[no-redef]" instead)
Found 1 error in 1 file (checked 1 source file)

The hint tells you how to change the comment:

x: int
x: str  # type: ignore [no-redef]

(Mypy suggests without the optional space before [, but I prefer to add it.)

Enabling ignore-without-code on a project will thus require you to rewrite all existing non-specific comments, but it does tell you how to change them!

warn_unused_ignores

This third flag helps you manage ignore comments as your 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 your code evolves, such as when imported type hints become more accurate.

For example, imagine if you changed the previous example to remove the first line:

x: str  # type: ignore [no-redef]

Now x is only defined once. If you run Mypy with warn_unused_ignores enabled:

$ mypy --warn-unused-ignores example.py
example.py:1: error: unused 'type: ignore' comment
Found 1 error in 1 file (checked 1 source file)

…you get an error saying that you can remove the ignore comment. Neat!

Fin

May your ignorance be ever reduced,

—Adam


Learn how to make your tests run quickly in my book Speed Up Your Django Tests.


Subscribe via RSS, Twitter, Mastodon, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: ,