Error codes for optional checks#

This section documents various errors codes that mypy generates only if you enable certain options. See Error codes for general documentation about error codes. Error codes enabled by default documents error codes that are enabled by default.

Note

The examples in this section use inline configuration to specify mypy options. You can also set the same options by using a configuration file or command-line options.

Check that type arguments exist [type-arg]#

If you use --disallow-any-generics, mypy requires that each generic type has values for each type argument. For example, the types list or dict would be rejected. You should instead use types like list[int] or dict[str, int]. Any omitted generic type arguments get implicit Any values. The type list is equivalent to list[Any], and so on.

Example:

# mypy: disallow-any-generics

# Error: Missing type parameters for generic type "list"  [type-arg]
def remove_dups(items: list) -> list:
    ...

Check that every function has an annotation [no-untyped-def]#

If you use --disallow-untyped-defs, mypy requires that all functions have annotations (either a Python 3 annotation or a type comment).

Example:

# mypy: disallow-untyped-defs

def inc(x):  # Error: Function is missing a type annotation  [no-untyped-def]
    return x + 1

def inc_ok(x: int) -> int:  # OK
    return x + 1

class Counter:
     # Error: Function is missing a type annotation  [no-untyped-def]
     def __init__(self):
         self.value = 0

class CounterOk:
     # OK: An explicit "-> None" is needed if "__init__" takes no arguments
     def __init__(self) -> None:
         self.value = 0

Check that cast is not redundant [redundant-cast]#

If you use --warn-redundant-casts, mypy will generate an error if the source type of a cast is the same as the target type.

Example:

# mypy: warn-redundant-casts

from typing import cast

Count = int

def example(x: Count) -> int:
    # Error: Redundant cast to "int"  [redundant-cast]
    return cast(int, x)

Check that comparisons are overlapping [comparison-overlap]#

If you use --strict-equality, mypy will generate an error if it thinks that a comparison operation is always true or false. These are often bugs. Sometimes mypy is too picky and the comparison can actually be useful. Instead of disabling strict equality checking everywhere, you can use # type: ignore[comparison-overlap] to ignore the issue on a particular line only.

Example:

# mypy: strict-equality

def is_magic(x: bytes) -> bool:
    # Error: Non-overlapping equality check (left operand type: "bytes",
    #        right operand type: "str")  [comparison-overlap]
    return x == 'magic'

We can fix the error by changing the string literal to a bytes literal:

# mypy: strict-equality

def is_magic(x: bytes) -> bool:
    return x == b'magic'  # OK

Check that no untyped functions are called [no-untyped-call]#

If you use --disallow-untyped-calls, mypy generates an error when you call an unannotated function in an annotated function.

Example:

# mypy: disallow-untyped-calls

def do_it() -> None:
    # Error: Call to untyped function "bad" in typed context  [no-untyped-call]
    bad()

def bad():
    ...

Check that function does not return Any value [no-any-return]#

If you use --warn-return-any, mypy generates an error if you return a value with an Any type in a function that is annotated to return a non-Any value.

Example:

# mypy: warn-return-any

def fields(s):
     return s.split(',')

def first_field(x: str) -> str:
    # Error: Returning Any from function declared to return "str"  [no-any-return]
    return fields(x)[0]

Check that types have no Any components due to missing imports [no-any-unimported]#

If you use --disallow-any-unimported, mypy generates an error if a component of a type becomes Any because mypy couldn’t resolve an import. These “stealth” Any types can be surprising and accidentally cause imprecise type checking.

In this example, we assume that mypy can’t find the module animals, which means that Cat falls back to Any in a type annotation:

# mypy: disallow-any-unimported

from animals import Cat  # type: ignore

# Error: Argument 1 to "feed" becomes "Any" due to an unfollowed import  [no-any-unimported]
def feed(cat: Cat) -> None:
    ...

Check that statement or expression is unreachable [unreachable]#

If you use --warn-unreachable, mypy generates an error if it thinks that a statement or expression will never be executed. In most cases, this is due to incorrect control flow or conditional checks that are accidentally always true or false.

# mypy: warn-unreachable

def example(x: int) -> None:
    # Error: Right operand of "or" is never evaluated  [unreachable]
    assert isinstance(x, int) or x == 'unused'

    return
    # Error: Statement is unreachable  [unreachable]
    print('unreachable')

Check that expression is redundant [redundant-expr]#

If you use --enable-error-code redundant-expr, mypy generates an error if it thinks that an expression is redundant.

# Use "mypy --enable-error-code redundant-expr ..."

def example(x: int) -> None:
    # Error: Left operand of "and" is always true  [redundant-expr]
    if isinstance(x, int) and x > 0:
        pass

    # Error: If condition is always true  [redundant-expr]
    1 if isinstance(x, int) else 0

    # Error: If condition in comprehension is always true  [redundant-expr]
    [i for i in range(x) if isinstance(i, int)]

Check that expression is not implicitly true in boolean context [truthy-bool]#

Warn when an expression whose type does not implement __bool__ or __len__ is used in boolean context, since unless implemented by a sub-type, the expression will always evaluate to true.

# Use "mypy --enable-error-code truthy-bool ..."

class Foo:
  pass
foo = Foo()
# Error: "foo" has type "Foo" which does not implement __bool__ or __len__ so it could always be true in boolean context
if foo:
   ...

This check might falsely imply an error. For example, Iterable does not implement __len__ and so this code will be flagged:

# Use "mypy -enable-error-code truthy-bool ..."

from typing import Iterable

def transform(items: Iterable[int]) -> Iterable[int]:
    # Error: "items" has type "Iterable[int]" which does not implement __bool__ or __len__ so it could always be true in boolean context  [truthy-bool]
    if not items:
        return [42]
    return [x + 1 for x in items]

If called as transform((int(s) for s in [])), this function would not return [42] unlike what the author might have intended. Of course it’s possible that transform is only passed list objects, and so there is no error in practice. In such case, it might be prudent to annotate items: Sequence[int].

This is similar in concept to ensuring that an expression’s type implements an expected interface (e.g. Sized), except that attempting to invoke an undefined method (e.g. __len__) results in an error, while attempting to evaluate an object in boolean context without a concrete implementation results in a truthy value.

Check that # type: ignore include an error code [ignore-without-code]#

Warn when a # type: ignore comment does not specify any error codes. This clarifies the intent of the ignore and ensures that only the expected errors are silenced.

Example:

# Use "mypy --enable-error-code ignore-without-code ..."

class Foo:
    def __init__(self, name: str) -> None:
        self.name = name

f = Foo('foo')

# This line has a typo that mypy can't help with as both:
# - the expected error 'assignment', and
# - the unexpected error 'attr-defined'
# are silenced.
# Error: "type: ignore" comment without error code (consider "type: ignore[attr-defined]" instead)
f.nme = 42  # type: ignore

# This line warns correctly about the typo in the attribute name
# Error: "Foo" has no attribute "nme"; maybe "name"?
f.nme = 42  # type: ignore[assignment]

Check that awaitable return value is used [unused-awaitable]#

If you use --enable-error-code unused-awaitable, mypy generates an error if you don’t use a returned value that defines __await__.

Example:

# Use "mypy --enable-error-code unused-awaitable ..."

import asyncio

async def f() -> int: ...

async def g() -> None:
    # Error: Value of type "Task[int]" must be used
    #        Are you missing an await?
    asyncio.create_task(f())

You can assign the value to a temporary, otherwise unused to variable to silence the error:

async def g() -> None:
    _ = asyncio.create_task(f())  # No error