7

I'm using class decorators in Python and cannot figure out which type annotation to give to my class to make mypy happy.

My code is the following:

from typing import Type
from pprint import pformat


def betterrepr(cls:Type[object]):
    """Improve representation of a class"""

    class improved_class(cls):  # line 12
        def __repr__(self) -> str:
            return f"Instance of {cls.__name__}, vars = {pformat(vars(self))}"

    return improved_class

I'm currently having the 2 following errors:

myprog.py:12: error: Invalid type "cls"

myprog.py:12: error: Invalid base class

What shall I use for the type of cls (and by the way, is it Pythonic to use this keyword for a class used as argument?)?

Thanks

Jean-Francois T.
  • 11,549
  • 7
  • 68
  • 107
  • Note that you can just *modify* ``cls`` instead of inheriting from it. – MisterMiyagi Jul 02 '19 at 15:44
  • 1
    ``cls`` is the canonical name for classes, e.g. as the first argument to a ``classmethod``. "[...] 'cls' is the preferred spelling for any variable or argument which is known to be a class, especially the first argument to a class method." from [PEP8](https://www.python.org/dev/peps/pep-0008/) – MisterMiyagi Jul 02 '19 at 16:04
  • 1
    For typical class decorators that just modify the class and do not create new type: Mypy uses plugins for this kind of behavior. For class decorators you can use the [dataclass plugin](https://github.com/python/mypy/blob/master/mypy/plugins/dataclasses.py) as reference. For Pyright (fast type checker by Microsoft) you can use [dataclass transforms](https://github.com/microsoft/pyright/blob/main/specs/dataclass_transforms.md). – Jaakkonen Aug 20 '21 at 18:08

1 Answers1

6

Using function arguments as base classes is currently not supported by mypy. Your only option is to silence the error, either with a type: ignore comment or a dummy alias like base: Any = cls.

Even without annotating cls, mypy will correctly infer the type of a class decorated with betterrepr. To document that your decorator returns a class similar to the decorated class, use a TypeVar.

from typing import Type, TypeVar
from pprint import pformat

T = TypeVar('T')


def betterrepr(cls: Type[T]) -> Type[T]:
    """Improve representation of a class"""
    class IClass(cls):  # type: ignore
        def __repr__(self) -> str:
            return f"Instance of {cls.__name__}, vars = {pformat(vars(self))}"
    return IClass
MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119