Skip to content
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

Support for variadic type aliases #15219

Merged
merged 11 commits into from May 21, 2023
Merged

Conversation

ilevkivskyi
Copy link
Member

Fixes #15062

Implementing "happy path" took like couple dozen lines, but there are a lot of edge cases, e.g. where we need to fail gracefully. Also of course I checked my implementation (mostly) works for recursive variadic aliases :-) see test.

It looks like several pieces of support for proper variadic types (i.e. non-aliases, instances etc) are still missing, so I tried to fill in something where I needed it for type aliases, but not everywhere, some notable examples:

  • Type variable bound checks for instances are still broken, see TODO item in semanal_typeargs.py
  • I think type argument count check is still broken for instances (I think I fixed it for type aliases), there can be fewer than len(type_vars) - 1 type arguments, e.g. if one of them is an unpack.
  • We should only prohibit multiple variadic unpacks in a type list, multiple fixed length unpacks are fine (I think I fixed this both for aliases and instances)

Btw I was thinking about an example below, what should we do in such cases?

from typing import Tuple, TypeVar
from typing_extensions import TypeVarTuple, Unpack

T = TypeVar("T")
S = TypeVar("S")
Ts = TypeVarTuple("Ts")

Alias = Tuple[T, S, Unpack[Ts], S]

def foo(*x: Unpack[Ts]) -> None:
    y: Alias[Unpack[Ts], int, str]
    reveal_type(y)  # <-- what is this type?

# Ts = () => Tuple[int, str, str]
# Ts = (bool) => Tuple[bool, int, str, int]
# Ts = (bool, float) => Tuple[bool, float, int, str, float]

Finally, I noticed there is already some code duplication, and I am not improving it. I am open to suggestions on how to reduce the code duplication.

@ilevkivskyi ilevkivskyi requested review from jhance and JukkaL May 10, 2023 23:01
@github-actions

This comment has been minimized.

@tmke8
Copy link
Contributor

tmke8 commented May 12, 2023

Nevermind, it works in Python 3.10.11


It seems that variadic type aliases don't really work at runtime in Python versions before 3.11; even if you use Unpack.

This works fine in Python 3.10 at runtime:

from typing import TypeAlias, TypeVar

T = TypeVar("T")

IntTuple: TypeAlias = tuple[int, T]

IntTuple[float]

but this throws a runtime error in Python 3.10:

from typing import TypeAlias
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")

IntTuple: TypeAlias = tuple[int, Unpack[Ts]]

IntTuple[float]

error:

Traceback (most recent call last):
  File "variadic_aliases.py", line 8, in <module>
    IntTuple[float]
  File "/home/tmk/.conda/envs/py10/lib/python3.10/typing.py", line 312, in inner
    return func(*args, **kwds)
  File "/home/tmk/.conda/envs/py10/lib/python3.10/typing.py", line 1081, in __getitem__
    return self.copy_with(tuple(new_args))
  File "/home/tmk/.conda/envs/py10/lib/python3.10/typing.py", line 1084, in copy_with
    return self.__class__(self.__origin__, params, name=self._name, inst=self._inst,
TypeError: TypeVar.__init__() got multiple values for argument 'name'

Of course, if you prevent evaluation with from __future__ import annotations then it works.

Should mypy warn about this?

@AlexWaygood
Copy link
Member

@tmke8 there's an open typing_extensions issue for the imperfect backport of Unpack: python/typing_extensions#103. I'm sure a PR would be welcome, if you can see a way to improve the behaviour at runtime there ;)

@ilevkivskyi
Copy link
Member Author

OK, I added handling for few more edge cases for type aliases as per PEP 646. Btw, I noticed that PEP explicitly allows Callable[[T, *Ts, S], int], but mypy currently prohibits it with an error like "Positional arg cannot follow var arg".

@jhance Is there a chance you can look at this PR? I would prefer if you confirm everything looks OK to you before I merge.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

mypy/expandtype.py Show resolved Hide resolved
@github-actions
Copy link
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

@ilevkivskyi
Copy link
Member Author

I am assuming there are no more comments on this PR, if there are no objections I will merge it later today.

@ilevkivskyi ilevkivskyi merged commit 0334ebc into python:master May 21, 2023
20 checks passed
@ilevkivskyi ilevkivskyi deleted the variadic-aliases branch May 21, 2023 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot create generic type aliases with TypeVarTuple
4 participants