Search code examples
pythontype-hintingmypy

How to type hint a staticmethod+abstractmethod+property using Mypy in Python?


Given this code:

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING

class Foo(ABC):
    
    @property
    @staticmethod
    @abstractmethod
    def name() -> str:
        pass

class Bar(Foo):
    name = "bar"

class Baz(Foo):
    name = "baz"

instances = [Bar(), Baz()]

print(instances[0].name)

if TYPE_CHECKING:
    reveal_type(instances[0].name)

Ran by the python interpreter, it prints (as expected):

bar

However, ran by mypy type checker, it prints (unexpectedly):

main.py:23: note: Revealed type is "def () -> builtins.str"

It looks like the type is wrongly inferred (see playground). Is it possible to fix that somehow?

If possible, I would like to fix it "once and for all" (like in the Foo class) because I'm accessing .name in multiple places.


Solution

  • Python 3.11 disallowed wrapping of @property using class decorators such as @classmethod and @staticmethod (see GH#89519).

    This means the provided snippet shouldn't be considered as valid Python code, and latest versions of Mypy actually warns about it:

    main.py:6: error: Only instance methods can be decorated with @property  [misc]
    main.py:23: note: Revealed type is "def () -> builtins.str"
    Found 1 error in 1 file (checked 1 source file)
    

    The easiest workaround is simply to use an instance method like so:

    class Foo(ABC):
        
        @property
        @abstractmethod
        def name(self) -> str:
            pass
    

    See also: GH#13035.