Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
eric-wieser opened this issue Mar 13, 2018 · 5 comments
Closed

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

eric-wieser opened this issue Mar 13, 2018 · 5 comments
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@eric-wieser
Copy link

eric-wieser commented Mar 13, 2018

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?

@ilevkivskyi
Copy link
Member

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.

@eric-wieser
Copy link
Author

eric-wieser commented Mar 14, 2018

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
Copy link
Author

eric-wieser commented Mar 14, 2018

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

@ilevkivskyi
Copy link
Member

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

@ilevkivskyi ilevkivskyi changed the title TypeVars should support indexing Can't have an alias that just targets a type variable Jun 20, 2019
@srittau srittau added the topic: feature Discussions about new features for Python's type annotations label Nov 4, 2021
@JelleZijlstra
Copy link
Member

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

4 participants