Description
Title
@cache breaks type checking when used with @classmethod and typing.Self
Bug description
Using @functools.cache
on a @classmethod
that returns typing.Self
breaks type inference in mypy and IntelliSense. mypy either falls back to Any
or fails type inference entirely.
Illustrative repro
from functools import cache
from typing import Self
class MyProvider:
@classmethod
@cache
def get_by_name(cls, name: str) -> Self:
...
provider = MyProvider.get_by_name("foo")
reveal_type(provider) # mypy: Revealed type is "Any"
Without @cache (works as expected)
class MyProvider:
@classmethod
def get_by_name(cls, name: str) -> Self:
...
provider = MyProvider.get_by_name("foo")
reveal_type(provider) # mypy: Revealed type is "MyProvider"
With @cache and concrete return type (also works)
class MyProvider:
@classmethod
@cache
def get_by_name(cls, name: str) -> MyProvider:
...
provider = MyProvider.get_by_name("foo")
reveal_type(provider) # mypy: Revealed type is "MyProvider"
Summary
This shows that Self return types on cached classmethods are not handled correctly by mypy. Replacing Self with the concrete class is a workaround, but sacrifices subclassing flexibility.
Environment
Python: 3.11 (per pyproject.toml)
mypy: 1.8+ (as specified in poetry.lock)
Flags: --strict
Editor: VSCode (optional, but IntelliSense also affected)
Related
Possibly related: python/typeshed#11280 (but that focuses on general decorator signature issues — this case seems specific to Self + @classmethod + @cache)