Description
from typing import TypeVar
import functools
T = TypeVar('T')
@functools.lru_cache()
def f(x: T) -> T: pass
reveal_type(f) # E: Revealed type is 'functools._lru_cache_wrapper[T`-1]'
reveal_type(f(1)) # E: Revealed type is 'T`-1'
These types are wrong: types are not allowed to contain unbound type variables.
There isn't really a clearly correct thing to do here though. The stubs for lru_cache
are defined in a way that does not retain the relationship between the input and output types of the function being decorated. Options here include
-
Find a way to retain the entire Callable type of the decorated function while having the result of
lru_cache
's__call__
simultaneously be an instance of_lru_cache_wrapper
. As far as I can tell, this is currently impossible, but would be the ideal long-term outcome. -
Give up on
_lru_cache_wrapper
andCacheInfo
(for now?) and just givelru_cache
the typedef lru_cache(f: _TC, maxsize: int = ..., typed: bool = ...) -> _TC: ...
where
_TC = TypeVar(_TC, bound=Callable)
, basically reverting python/typeshed@a40418e. -
Have mypy infer the type
_lru_cache_wrapper[Any]
for thisf
on the grounds that the type variable_T
is undetermined. But normally in this situation (where an undetermined type variable appears in an inferred type)mypy
either uses'None'
or complains about being unable to infer a type. What makes this case special?
This kind of situation occurs in stdlib-samples/3.2/fnmatch.py
:
@functools.lru_cache(maxsize=250)
def _compile_pattern(pat: AnyStr,
is_bytes: bool = False) -> Callable[[AnyStr],
Match[AnyStr]]:
...
It accidentally happens to not cause an error at the uses of _compile_pattern
because of another issue, #1261.