Describe the bug
This is easiest illustrated with the repro-case below. In short, if you decorate an invariant generic method, the type-var unification doesn't seem to propagate across the LRU wrapped method. In the following code, the store_of method works fine but cached_store_of's type is still captured as the "T@cached_store_of" fresh Ty var instead of being unified with the Account type.
Note that in this case, the type var T must be invariant but that's incidental to this example. Custom decorators seem to work properly. I also believe I've confidently rule out that this is unrelated to TypeForm and any of the improvements that might bring to the table.
Code
import typing
from functools import lru_cache
from typing import Any, Generic, TypeVar
T = TypeVar("T")
class Store(Generic[T]):
def __init__(self, entity_cls: type[T], db_session: Any):
super().__init__()
self._entity_cls = entity_cls
self._db_session = db_session
def get(self, pkey: str) -> T:
...
def create(self, value: T) -> T:
...
class DB:
def __init__(self, db_session: Any):
super().__init__()
self._db_session = db_session
def store_of(self, entity_cls: type[T]) -> Store[T]:
return Store(entity_cls=entity_cls, db_session=self._db_session)
@my_decorator
def my_decorated_store_of(self, entity_cls: type[T]) -> Store[T]:
return Store(entity_cls=entity_cls, db_session=self._db_session)
@lru_cache
def cached_store_of(self, entity_cls: type[T]) -> Store[T]:
return Store(entity_cls=entity_cls, db_session=self._db_session)
class Account:
...
typing.reveal_type(DB(db_session="connection").store_of(entity_cls=Account))
account_store_1: Store[Account] = DB(db_session="connection").store_of(
entity_cls=Account,
)
typing.reveal_type(DB(db_session="connection").my_decorated_store_of(entity_cls=Account))
account_store_2: Store[Account] = DB(db_session="connection").my_decorated_store_of(
entity_cls=Account,
)
typing.reveal_type(DB(db_session="connection").cached_store_of(entity_cls=Account))
account_store_3: Store[Account] = DB(db_session="connection").cached_store_of(
entity_cls=Account,
)
Version
❯ pyright --version
pyright 1.1.356
Output
❯ pyright generic_bug.py
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py:51:20 - information: Type of "DB(db_session="connection").store_of(entity_cls=Account)" is "Store[Account]"
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py:54:20 - information: Type of "DB(db_session="connection").my_decorated_store_of(entity_cls=Account)" is "Store[Account]"
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py:59:20 - information: Type of "DB(db_session="connection").cached_store_of(entity_cls=Account)" is "Store[T@cached_store_of]"
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py:60:35 - error: Expression of type "Store[T@cached_store_of]" cannot be assigned to declared type "Store[Account]"
"Store[T@cached_store_of]" is incompatible with "Store[Account]"
Type parameter "T@Store" is invariant, but "T@cached_store_of" is not the same as "Account" (reportAssignmentType)
1 error, 0 warnings, 3 informations
Describe the bug
This is easiest illustrated with the repro-case below. In short, if you decorate an invariant generic method, the type-var unification doesn't seem to propagate across the LRU wrapped method. In the following code, the
store_ofmethod works fine butcached_store_of's type is still captured as the"T@cached_store_of"fresh Ty var instead of being unified with theAccounttype.Note that in this case, the type var
Tmust be invariant but that's incidental to this example. Custom decorators seem to work properly. I also believe I've confidently rule out that this is unrelated toTypeFormand any of the improvements that might bring to the table.Code
Version
Output
❯ pyright generic_bug.py
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py:51:20 - information: Type of "DB(db_session="connection").store_of(entity_cls=Account)" is "Store[Account]"
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py:54:20 - information: Type of "DB(db_session="connection").my_decorated_store_of(entity_cls=Account)" is "Store[Account]"
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py:59:20 - information: Type of "DB(db_session="connection").cached_store_of(entity_cls=Account)" is "Store[T@cached_store_of]"
/Users/shawn/Code/instance-bio/instance/services/web/generic_bug.py:60:35 - error: Expression of type "Store[T@cached_store_of]" cannot be assigned to declared type "Store[Account]"
"Store[T@cached_store_of]" is incompatible with "Store[Account]"
Type parameter "T@Store" is invariant, but "T@cached_store_of" is not the same as "Account" (reportAssignmentType)
1 error, 0 warnings, 3 informations