mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-101015: Fix typing.get_type_hints with unpacked *tuple (PEP 646) (GH-101031)
(cherry picked from commit 807d6b576f)
Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
This commit is contained in:
parent
69d12d868e
commit
29ff9daf82
3 changed files with 36 additions and 1 deletions
|
|
@ -1222,6 +1222,36 @@ class D(Generic[Unpack[Ts]]): pass
|
||||||
self.assertIs(D[T].__origin__, D)
|
self.assertIs(D[T].__origin__, D)
|
||||||
self.assertIs(D[Unpack[Ts]].__origin__, D)
|
self.assertIs(D[Unpack[Ts]].__origin__, D)
|
||||||
|
|
||||||
|
def test_get_type_hints_on_unpack_args(self):
|
||||||
|
Ts = TypeVarTuple('Ts')
|
||||||
|
|
||||||
|
def func1(*args: *Ts): pass
|
||||||
|
self.assertEqual(gth(func1), {'args': Unpack[Ts]})
|
||||||
|
|
||||||
|
def func2(*args: *tuple[int, str]): pass
|
||||||
|
self.assertEqual(gth(func2), {'args': Unpack[tuple[int, str]]})
|
||||||
|
|
||||||
|
class CustomVariadic(Generic[*Ts]): pass
|
||||||
|
|
||||||
|
def func3(*args: *CustomVariadic[int, str]): pass
|
||||||
|
self.assertEqual(gth(func3), {'args': Unpack[CustomVariadic[int, str]]})
|
||||||
|
|
||||||
|
def test_get_type_hints_on_unpack_args_string(self):
|
||||||
|
Ts = TypeVarTuple('Ts')
|
||||||
|
|
||||||
|
def func1(*args: '*Ts'): pass
|
||||||
|
self.assertEqual(gth(func1, localns={'Ts': Ts}),
|
||||||
|
{'args': Unpack[Ts]})
|
||||||
|
|
||||||
|
def func2(*args: '*tuple[int, str]'): pass
|
||||||
|
self.assertEqual(gth(func2), {'args': Unpack[tuple[int, str]]})
|
||||||
|
|
||||||
|
class CustomVariadic(Generic[*Ts]): pass
|
||||||
|
|
||||||
|
def func3(*args: '*CustomVariadic[int, str]'): pass
|
||||||
|
self.assertEqual(gth(func3, localns={'CustomVariadic': CustomVariadic}),
|
||||||
|
{'args': Unpack[CustomVariadic[int, str]]})
|
||||||
|
|
||||||
def test_tuple_args_are_correct(self):
|
def test_tuple_args_are_correct(self):
|
||||||
Ts = TypeVarTuple('Ts')
|
Ts = TypeVarTuple('Ts')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -363,10 +363,13 @@ def _eval_type(t, globalns, localns, recursive_guard=frozenset()):
|
||||||
ForwardRef(arg) if isinstance(arg, str) else arg
|
ForwardRef(arg) if isinstance(arg, str) else arg
|
||||||
for arg in t.__args__
|
for arg in t.__args__
|
||||||
)
|
)
|
||||||
|
is_unpacked = t.__unpacked__
|
||||||
if _should_unflatten_callable_args(t, args):
|
if _should_unflatten_callable_args(t, args):
|
||||||
t = t.__origin__[(args[:-1], args[-1])]
|
t = t.__origin__[(args[:-1], args[-1])]
|
||||||
else:
|
else:
|
||||||
t = t.__origin__[args]
|
t = t.__origin__[args]
|
||||||
|
if is_unpacked:
|
||||||
|
t = Unpack[t]
|
||||||
ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
|
ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
|
||||||
if ev_args == t.__args__:
|
if ev_args == t.__args__:
|
||||||
return t
|
return t
|
||||||
|
|
@ -820,7 +823,7 @@ def __init__(self, arg, is_argument=True, module=None, *, is_class=False):
|
||||||
# Unfortunately, this isn't a valid expression on its own, so we
|
# Unfortunately, this isn't a valid expression on its own, so we
|
||||||
# do the unpacking manually.
|
# do the unpacking manually.
|
||||||
if arg[0] == '*':
|
if arg[0] == '*':
|
||||||
arg_to_compile = f'({arg},)[0]' # E.g. (*Ts,)[0]
|
arg_to_compile = f'({arg},)[0]' # E.g. (*Ts,)[0] or (*tuple[int, int],)[0]
|
||||||
else:
|
else:
|
||||||
arg_to_compile = arg
|
arg_to_compile = arg
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix :func:`typing.get_type_hints` on ``'*tuple[...]'`` and ``*tuple[...]``.
|
||||||
|
It must not drop the ``Unpack`` part.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue