Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5401,6 +5401,18 @@ def test_invalid_uses(self):
):
Concatenate[1, P]

@skipUnless(TYPING_3_10_0, "Missing backported to <=3.9. See issue #48")
def test_alias_subscription_with_ellipsis(self):
P = ParamSpec('P')
X = Callable[Concatenate[int, P], Any]

C1 = X[...]
self.assertEqual(C1.__parameters__, ())
with self.subTest("Compare Concatenate[int, ...]"):
if sys.version_info[:2] == (3, 10):
self.skipTest("Needs Issue #110 | PR # 442: construct Concatenate with ...")
self.assertEqual(get_args(C1), (Concatenate[int, ...], Any))

def test_basic_introspection(self):
P = ParamSpec('P')
C1 = Concatenate[int, P]
Expand Down Expand Up @@ -6089,7 +6101,7 @@ def test_typing_extensions_defers_when_possible(self):
if sys.version_info < (3, 10, 1):
exclude |= {"Literal"}
if sys.version_info < (3, 11):
exclude |= {'final', 'Any', 'NewType', 'overload'}
exclude |= {'final', 'Any', 'NewType', 'overload', 'Concatenate'}
if sys.version_info < (3, 12):
exclude |= {
'SupportsAbs', 'SupportsBytes',
Expand Down
36 changes: 30 additions & 6 deletions src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1795,6 +1795,27 @@ def __parameters__(self):
return tuple(
tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec))
)
# 3.10+
else:
_ConcatenateGenericAlias = typing._ConcatenateGenericAlias

# 3.10
if sys.version_info < (3, 11):
_typing_ConcatenateGenericAlias = _ConcatenateGenericAlias

class _ConcatenateGenericAlias(_typing_ConcatenateGenericAlias, _root=True):
# needed for checks in collections.abc.Callable to accept this class
__module__ = "typing"

def copy_with(self, params):
if isinstance(params[-1], (list, tuple)):
return (*params[:-1], *params[-1])
if isinstance(params[-1], _ConcatenateGenericAlias):
params = (*params[:-1], *params[-1].__args__)
elif not (params[-1] is ... or isinstance(params[-1], ParamSpec)):
raise TypeError("The last parameter to Concatenate should be a "
"ParamSpec variable or ellipsis.")
return super(_typing_ConcatenateGenericAlias, self).copy_with(params)


# 3.8-3.9
Expand All @@ -1804,19 +1825,22 @@ def _concatenate_getitem(self, parameters):
raise TypeError("Cannot take a Concatenate of no types.")
if not isinstance(parameters, tuple):
parameters = (parameters,)
if not isinstance(parameters[-1], ParamSpec):
elif 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 = tuple(typing._type_check(p, msg) for p in parameters)
if (3, 10, 2) < sys.version_info < (3,11):
return _ConcatenateGenericAlias(self, parameters,
_typevar_types=(TypeVar, ParamSpec),
_paramspec_tvars=True)
return _ConcatenateGenericAlias(self, parameters)


# 3.10+
if hasattr(typing, 'Concatenate'):
# 3.11+
if hasattr(typing, 'Concatenate') and sys.version_info[:2] != (3, 10):
Concatenate = typing.Concatenate
_ConcatenateGenericAlias = typing._ConcatenateGenericAlias
# 3.9
# 3.9-3.10
elif sys.version_info[:2] >= (3, 9):
@_ExtensionsSpecialForm
def Concatenate(self, parameters):
Expand Down
Loading