typing icon indicating copy to clipboard operation
typing copied to clipboard

Can't have an alias that just targets a type variable

Open eric-wieser opened this issue 7 years ago • 4 comments

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?

eric-wieser avatar Mar 13 '18 19:03 eric-wieser

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.

ilevkivskyi avatar Mar 14 '18 21:03 ilevkivskyi

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;

eric-wieser avatar Mar 14 '18 21:03 eric-wieser

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

eric-wieser avatar Mar 14 '18 21:03 eric-wieser

Hm, it looks like an experimental mypy_extensions.FlexibleAlias is exactly what can help in this case.

ilevkivskyi avatar Jun 20 '19 09:06 ilevkivskyi

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): ...

JelleZijlstra avatar May 22 '23 00:05 JelleZijlstra