Skip to content

Commit

Permalink
bpo-44791: Accept ellipsis as the last argument of typing.Concatenate (
Browse files Browse the repository at this point in the history
  • Loading branch information
serhiy-storchaka authored Apr 29, 2022
1 parent f665616 commit 81120b6
Show file tree
Hide file tree
Showing 4 changed files with 9 additions and 14 deletions.
3 changes: 2 additions & 1 deletion Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn
callable. Usage is in the form
``Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]``. ``Concatenate``
is currently only valid when used as the first argument to a :data:`Callable`.
The last parameter to ``Concatenate`` must be a :class:`ParamSpec`.
The last parameter to ``Concatenate`` must be a :class:`ParamSpec` or
ellipsis (``...``).

For example, to annotate a decorator ``with_lock`` which provides a
:class:`threading.Lock` to the decorated function, ``Concatenate`` can be
Expand Down
12 changes: 4 additions & 8 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1755,8 +1755,7 @@ def test_concatenate(self):
self.assertEqual(C[[], int], Callable[[int], int])
self.assertEqual(C[Concatenate[str, P2], int],
Callable[Concatenate[int, str, P2], int])
with self.assertRaises(TypeError):
C[..., int]
self.assertEqual(C[..., int], Callable[Concatenate[int, ...], int])

C = Callable[Concatenate[int, P], int]
self.assertEqual(repr(C),
Expand All @@ -1767,8 +1766,7 @@ def test_concatenate(self):
self.assertEqual(C[[]], Callable[[int], int])
self.assertEqual(C[Concatenate[str, P2]],
Callable[Concatenate[int, str, P2], int])
with self.assertRaises(TypeError):
C[...]
self.assertEqual(C[...], Callable[Concatenate[int, ...], int])

def test_errors(self):
Callable = self.Callable
Expand Down Expand Up @@ -6739,17 +6737,15 @@ def test_var_substitution(self):
self.assertEqual(C[int, []], (int,))
self.assertEqual(C[int, Concatenate[str, P2]],
Concatenate[int, str, P2])
with self.assertRaises(TypeError):
C[int, ...]
self.assertEqual(C[int, ...], Concatenate[int, ...])

C = Concatenate[int, P]
self.assertEqual(C[P2], Concatenate[int, P2])
self.assertEqual(C[[str, float]], (int, str, float))
self.assertEqual(C[str, float], (int, str, float))
self.assertEqual(C[[]], (int,))
self.assertEqual(C[Concatenate[str, P2]], Concatenate[int, str, P2])
with self.assertRaises(TypeError):
C[...]
self.assertEqual(C[...], Concatenate[int, ...])

class TypeGuardTests(BaseTestCase):
def test_basics(self):
Expand Down
7 changes: 2 additions & 5 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,9 +714,9 @@ def Concatenate(self, parameters):
raise TypeError("Cannot take a Concatenate of no types.")
if not isinstance(parameters, tuple):
parameters = (parameters,)
if not isinstance(parameters[-1], ParamSpec):
if not (parameters[-1] is ... or isinstance(parameters[-1], ParamSpec)):
raise TypeError("The last parameter to Concatenate should be a "
"ParamSpec variable.")
"ParamSpec variable or ellipsis.")
msg = "Concatenate[arg, ...]: each arg must be a type."
parameters = (*(_type_check(p, msg) for p in parameters[:-1]), parameters[-1])
return _ConcatenateGenericAlias(self, parameters,
Expand Down Expand Up @@ -1641,9 +1641,6 @@ def copy_with(self, params):
return (*params[:-1], *params[-1])
if isinstance(params[-1], _ConcatenateGenericAlias):
params = (*params[:-1], *params[-1].__args__)
elif not isinstance(params[-1], ParamSpec):
raise TypeError("The last parameter to Concatenate should be a "
"ParamSpec variable.")
return super().copy_with(params)


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Accept ellipsis as the last argument of :data:`typing.Concatenate`.

0 comments on commit 81120b6

Please sign in to comment.