Skip to content

generic-not-last-base-class (PYI059)

Derived from the flake8-pyi linter.

Fix is sometimes available.

This rule is unstable and in preview. The --preview flag is required for use.

What it does

Checks for classes inheriting from typing.Generic[] where Generic[] is not the last base class in the bases tuple.

Why is this bad?

If Generic[] is not the final class in the bases tuple, unexpected behaviour can occur at runtime (See this CPython issue for an example).

The rule is also applied to stub files, where it won't cause issues at runtime. This is because type checkers may not be able to infer an accurate MRO for the class, which could lead to unexpected or inaccurate results when they analyze your code.

For example:

class LinkedList(Generic[T], Sized):
    def push(self, item: T) -> None:
        self._items.append(item)

class MyMapping(
    Generic[K, V],
    Iterable[Tuple[K, V]],
    Container[Tuple[K, V]],
):
    ...

Use instead:

class LinkedList(Sized, Generic[T]):
    def push(self, item: T) -> None:
        self._items.append(item)

class MyMapping(
    Iterable[Tuple[K, V]],
    Container[Tuple[K, V]],
    Generic[K, V],
):
    ...

Fix safety

This rule's fix is always unsafe because reordering base classes can change the behavior of the code by modifying the class's MRO. The fix will also delete trailing comments after the Generic base class in multi-line base class lists, if any are present.

Fix availability

This rule's fix is only available when there are no *args present in the base class list.

References