python's TypeVar inference broken when using lru_cache decorator. For example, after applying mypy
the following example, only function with lru_cache
causes error like:
main.py:14: error: Incompatible types in assignment (expression has type "T", variable has type "int")
Found 1 error in 1 file (checked 1 source file)
and pyright's editor support also warn the same thing. Is this lru_cache
's own limitation or is there some good workaround?
from functools import lru_cache
from typing import TypeVar
T = TypeVar("T")
def working(foo: T) -> T:
return foo
@lru_cache(maxsize=None)
def not_working(foo: T) -> T:
return foo
a: int = working(1)
b: int = not_working(1)
Here's the relevant parts of the lru_cache
type hints
_T = TypeVar("_T")
class _lru_cache_wrapper(Generic[_T]):
__wrapped__: Callable[..., _T]
def __call__(self, *args: Hashable, **kwargs: Hashable) -> _T: ...
def lru_cache(
maxsize: int | None = ..., typed: bool = ...
) -> Callable[[Callable[..., _T]], _lru_cache_wrapper[_T]]: ...
so it appears that, in its attempts to allow for any argument set, it loses any connection between the input and output types and so is unable to refine T
to int
. You may have to wrap lru_cache
locally to fix this. You may be able to use ParamSpec
, but you might find difficulties with that, see the note below. If you only need it for a small set of function types (unary, binary, ternary), you could wrap it for those.
Apparently they did actually fix this with ParamSpec
but from a cursory reading it appears to break other things so they reverted it. This issue also discusses it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With