Can't have an alias that just targets a type variable
Consider version 1 of my package, which defines
T = TypeVar('T', int, float)
MyType = Union[T, List[T]]
# in the user's code
U = TypeVar('U', int, float)
def myfunc(MyType[U], U): ...
In version 2, I decide to drop support for passing List[T]. However, this causes an error on the downstream type definitions
T = TypeVar('T', int, float)
MyType = Union[T] # or Generic[T], or T - all fail
# downstream code doesn't change - I want the freedom to change `MyType` again in future
U = TypeVar('U', int, float)
def myfunc(MyType[U], U): ... # fails due to missing __getitem__
Is there a way to write this? Does implementing TypeVar.__getitem__ seem reasonable? Or should we introduce Identity[T], which boxes a typevar into a generic?
This is the first time I see such request. TBH, I think it could be rather confusing for someone reading the code like this:
T = TypeVar('T', int, float)
U = TypeVar('U', int, float)
MyType = T
def func(arg: MyType[U]) -> U:
...
So I am strong -1 on this.
So one related problem at the moment is the result of Union depends on it's arguments. This succeeds
X = Union[T, int]
X[str]
Yet this fails
X = Union[T]
X[str]
Contrast this with the equivalent C++ code, which just works:
template<typename T>
using X = union<T>;
X<string> s;
template<typename T>
using X = union<T, int>;
X<string> s;
Note that I give a real application in the referenced issue above. In python 3, we have
T = TypeVar('T', *AnyStr.__constraints__)
PathType = Union[T, PathLike[T]]
# use PathType[str], PathType[bytes], PathType[AnyStr], etc
But there is no way to specify this type on python 2, where PathLike doesn't exist, and the definition is just
T = TypeVar('T', *AnyStr.__constraints__)
PathType = ???[T]
# PathType needs to be indexable just like in the py3 case
Hm, it looks like an experimental mypy_extensions.FlexibleAlias is exactly what can help in this case.
PEP 695 addresses this. (Not on Python 2, but we don't care about that any more.)
type MyType[T: (int, float)] = T
# Or
from typing_extensions import TypeAliasType, TypeVar
T = TypeVar("T", int, float)
MyType = TypeAliasType("MyType", T, type_params=(T,))
def myfunc[U: (int, float)](a: MyType[U], b: U): ...