Python: make subclass of generic class generic by default

Question:

I want to be able to define what the contents of a subclass of a subclass of typing.Iterable have to be.
Type hints are critical for this project so I have to find a working solution

Here is a snip code of what I’ve already tried and what I want:


# The code I'm writing:
from typing import TypeVar, Iterable

T = TypeVar('T')


class Data:
    pass


class GeneralPaginatedCursor(Iterable[T]):
    """
    If this type pf cursor is used by an EDR a specific implementation has to be created
    Handle paginated lists, exposes hooks to simplify retrieval and parsing of paginated data
    """
    # Implementation
    pass


###########
# This part is supposed to be written by different developers on a different place:


class PaginatedCursor(GeneralPaginatedCursor):
    pass


def foo() -> GeneralPaginatedCursor[Data]:
    """
    Works great
    """
    pass


def bar() -> PaginatedCursor[Data]:
    """
    Raises
    Traceback (most recent call last):
    .
    .
    .
        def bar(self) -> PaginatedCursor[Data]:
    File "****PythonPython38-32libtyping.py", line 261, in inner
        return func(*args, **kwds)
    File "****PythonPython38-32libtyping.py", line 894, in __class_getitem__
        _check_generic(cls, params)
    File "****PythonPython38-32libtyping.py", line 211, in _check_generic
        raise TypeError(f"{cls} is not a generic class")
    """
    pass

I don’t want to leave it to the other developers in the future to inherit from Iterable because if someone will miss it everything will break.


I found the exact same issue here:
https://github.com/python/cpython/issues/82640
But there is no answer.

Asked By: Neriya

||

Answers:

The only requirements are that GeneralPaginatedCursor define __iter__ to return an Iterable value (namely, something with a __next__ method).

The error you see occurs because, since GeneralPaginatedCursor is generic in T, PaginatedCursor should be as well.

class PaginatedCursor(GeneralPaginatedCursor[T]):
    pass
Answered By: chepner