Hi there! I think I found a minor issue when using the default values with TypeVars
.
I have a class that uses 2 typevars, and I’d like users of the class to be able to pass 0, 1 or all of the variables, unfortunately when using this code:
from __future__ import annotations
from typing import Any, Generic, Tuple, Type, Union
from typing_extensions import TypeVar
ContextType = TypeVar("ContextType", default=Any)
RootValueType = TypeVar("RootValueType", default=Any)
class Info(Generic[ContextType, RootValueType]):
...
print(Info)
print(Info[int])
print(Info[int, str])
I get the following error:
<class '__main__.Info'>
Traceback (most recent call last):
File "/Users/patrick/github/strawberry-graphql/strawberry/typevardemo.py", line 20, in <module>
print(Info[int])
~~~~^^^^^
File "/Users/patrick/.local/share/rtx/installs/python/3.12.0/lib/python3.12/typing.py", line 377, in inner
return func(*args, **kwds)
^^^^^^^^^^^^^^^^^^^
File "/Users/patrick/.local/share/rtx/installs/python/3.12.0/lib/python3.12/typing.py", line 1059, in _generic_class_getitem
_check_generic(cls, params, len(cls.__parameters__))
File "/Users/patrick/.local/share/rtx/installs/python/3.12.0/lib/python3.12/typing.py", line 297, in _check_generic
raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};"
TypeError: Too few arguments for <class '__main__.Info'>; actual 1, expected 2
I’ve solved this by adding a custom __class_getitem__
, like this:
from __future__ import annotations
from typing import Any, Generic, Tuple, Type, Union
from typing_extensions import TypeVar
ContextType = TypeVar("ContextType", default=Any)
RootValueType = TypeVar("RootValueType", default=Any)
class Info(Generic[ContextType, RootValueType]):
def __class_getitem__(cls, types: Union[type, Tuple[type, ...]]) -> Type[Info]:
if not isinstance(types, tuple):
types = (types, Any)
return super().__class_getitem__(types)
print(Info)
print(Info[int])
print(Info[int, str])
Seems a bit of a hack, but it works Do you see anything wrong with it?
If that’s correct, should we create a new Generic
class inside typing extensions that does something like this? Should we do this in the next version of python itself (I guess in that case we’d change the check generic function)?
I’d be happy to contribute this if it makes sense