Skip to content

Commit

Permalink
gh-101015: Fix typing.get_type_hints with unpacked *tuple (PEP 64…
Browse files Browse the repository at this point in the history
…6) (#101031)
  • Loading branch information
sobolevn authored Jan 23, 2023
1 parent d717be0 commit 807d6b5
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 1 deletion.
30 changes: 30 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,36 @@ class D(Generic[Unpack[Ts]]): pass
self.assertIs(D[T].__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):
Ts = TypeVarTuple('Ts')

Expand Down
5 changes: 4 additions & 1 deletion Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,13 @@ def _eval_type(t, globalns, localns, recursive_guard=frozenset()):
ForwardRef(arg) if isinstance(arg, str) else arg
for arg in t.__args__
)
is_unpacked = t.__unpacked__
if _should_unflatten_callable_args(t, args):
t = t.__origin__[(args[:-1], args[-1])]
else:
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__)
if ev_args == t.__args__:
return t
Expand Down Expand Up @@ -828,7 +831,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
# do the unpacking manually.
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:
arg_to_compile = arg
try:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :func:`typing.get_type_hints` on ``'*tuple[...]'`` and ``*tuple[...]``.
It must not drop the ``Unpack`` part.

0 comments on commit 807d6b5

Please sign in to comment.