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 and CacheInfo (for now?) and just give lru_cache the type
def 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 this f 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.
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_cacheare defined in a way that does not retain the relationship between the input and output types of the function being decorated. Options here includeFind 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_wrapperandCacheInfo(for now?) and just givelru_cachethe typewhere
_TC = TypeVar(_TC, bound=Callable), basically reverting python/typeshed@a40418e.Have mypy infer the type
_lru_cache_wrapper[Any]for thisfon the grounds that the type variable_Tis undetermined. But normally in this situation (where an undetermined type variable appears in an inferred type)mypyeither 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:It accidentally happens to not cause an error at the uses of
_compile_patternbecause of another issue, #1261.