@@ -1681,12 +1681,16 @@ class C(Generic[T]): pass
1681
1681
# In 3.9 and lower we use typing_extensions's hacky implementation
1682
1682
# of ParamSpec, which gets incorrectly wrapped in a list
1683
1683
self .assertIn (get_args (Callable [P , int ]), [(P , int ), ([P ], int )])
1684
- self .assertEqual (get_args (Callable [Concatenate [int , P ], int ]),
1685
- (Concatenate [int , P ], int ))
1686
1684
self .assertEqual (get_args (Required [int ]), (int ,))
1687
1685
self .assertEqual (get_args (NotRequired [int ]), (int ,))
1688
1686
self .assertEqual (get_args (Unpack [Ts ]), (Ts ,))
1689
1687
self .assertEqual (get_args (Unpack ), ())
1688
+ self .assertEqual (get_args (Callable [Concatenate [int , P ], int ]),
1689
+ (Concatenate [int , P ], int ))
1690
+ if sys .version_info >= (3 , 9 ):
1691
+ # Cannot construct Callable[Concatenate[int, ...] with non-types
1692
+ self .assertEqual (get_args (Callable [Concatenate [int , ...], int ]),
1693
+ (Concatenate [int , ...], int ))
1690
1694
1691
1695
1692
1696
class CollectionsAbcTests (BaseTestCase ):
@@ -5228,6 +5232,10 @@ class Y(Protocol[T, P]):
5228
5232
self .assertEqual (G2 .__args__ , (int , Concatenate [int , P_2 ]))
5229
5233
self .assertEqual (G2 .__parameters__ , (P_2 ,))
5230
5234
5235
+ G3 = klass [int , Concatenate [int , ...]]
5236
+ self .assertEqual (G3 .__args__ , (int , Concatenate [int , ...]))
5237
+ self .assertEqual (G3 .__parameters__ , ())
5238
+
5231
5239
# The following are some valid uses cases in PEP 612 that don't work:
5232
5240
# These do not work in 3.9, _type_check blocks the list and ellipsis.
5233
5241
# G3 = X[int, [int, bool]]
@@ -5312,7 +5320,7 @@ def run():
5312
5320
5313
5321
# The actual test:
5314
5322
self .assertEqual (result1 , result2 )
5315
-
5323
+
5316
5324
5317
5325
class ConcatenateTests (BaseTestCase ):
5318
5326
def test_basics (self ):
@@ -5322,6 +5330,11 @@ class MyClass: ...
5322
5330
5323
5331
c = Concatenate [MyClass , P ]
5324
5332
self .assertNotEqual (c , Concatenate )
5333
+
5334
+ # Test Ellipsis Concatenation
5335
+ d = Concatenate [MyClass , ...]
5336
+ self .assertNotEqual (d , c )
5337
+ self .assertNotEqual (d , Concatenate )
5325
5338
5326
5339
def test_valid_uses (self ):
5327
5340
P = ParamSpec ('P' )
@@ -5339,6 +5352,21 @@ def test_valid_uses(self):
5339
5352
self .assertEqual (C3 .__origin__ , C4 .__origin__ )
5340
5353
self .assertNotEqual (C3 , C4 )
5341
5354
5355
+ # Callable with Ellipsis cannot be constructed in Python3.8
5356
+ if sys .version_info [:2 ] <= (3 , 8 ):
5357
+ return
5358
+
5359
+ C5 = Callable [Concatenate [int , ...], int ]
5360
+ C6 = Callable [Concatenate [int , T , ...], T ]
5361
+ self .assertEqual (C5 .__origin__ , C6 .__origin__ )
5362
+ self .assertNotEqual (C5 , C6 )
5363
+
5364
+ # Test collections.abc.Callable too.
5365
+ C7 = collections .abc .Callable [Concatenate [int , ...], int ]
5366
+ C8 = collections .abc .Callable [Concatenate [int , T , ...], T ]
5367
+ self .assertEqual (C7 .__origin__ , C8 .__origin__ )
5368
+ self .assertNotEqual (C7 , C8 )
5369
+
5342
5370
def test_invalid_uses (self ):
5343
5371
P = ParamSpec ('P' )
5344
5372
T = TypeVar ('T' )
@@ -5351,25 +5379,58 @@ def test_invalid_uses(self):
5351
5379
5352
5380
with self .assertRaisesRegex (
5353
5381
TypeError ,
5354
- 'The last parameter to Concatenate should be a ParamSpec variable' ,
5382
+ 'The last parameter to Concatenate should be a ParamSpec variable or ellipsis ' ,
5355
5383
):
5356
5384
Concatenate [P , T ]
5385
+
5386
+
5387
+ if sys .version_info [:2 ] >= (3 , 9 ):
5388
+ # Cannot construct a Callable with Ellipsis in Python3.8 as args must be types
5389
+ with self .assertRaisesRegex (
5390
+ TypeError ,
5391
+ 'is not a generic class' ,
5392
+ ):
5393
+ Callable [Concatenate [int , ...], Any ][T ]
5394
+
5357
5395
5358
5396
if not TYPING_3_11_0 :
5359
5397
with self .assertRaisesRegex (
5360
5398
TypeError ,
5361
5399
'each arg must be a type' ,
5362
5400
):
5363
5401
Concatenate [1 , P ]
5402
+
5403
+ with self .assertRaisesRegex (
5404
+ TypeError ,
5405
+ 'each arg must be a type.' ,
5406
+ ):
5407
+ Concatenate [1 , ..., P ]
5408
+
5409
+ @skipUnless (TYPING_3_11_0 , "Cannot be backported to <=3.9"
5410
+ "Cannot use typing._ConcatenateGenericAlias in 3.10" )
5411
+ def test_alias (self ):
5412
+ P = ParamSpec ("P" )
5413
+ C1 = Callable [Concatenate [int , P ], Any ]
5414
+ # Python <= 3.9 fails because parameters to generic types must be types.
5415
+ # For Python 3.10 & typing._ConcatenateGenericAlias will
5416
+ # as Ellipsis is not supported for ParamSpec
5417
+ # Fallback to 3.10 & typing_extensions._ConcatenateGenericAlias not implemented
5418
+ C1 [...]
5364
5419
5365
5420
def test_basic_introspection (self ):
5366
5421
P = ParamSpec ('P' )
5367
5422
C1 = Concatenate [int , P ]
5368
5423
C2 = Concatenate [int , T , P ]
5424
+ C3 = Concatenate [int , ...]
5425
+ C4 = Concatenate [int , T , ...]
5369
5426
self .assertEqual (C1 .__origin__ , Concatenate )
5370
5427
self .assertEqual (C1 .__args__ , (int , P ))
5371
5428
self .assertEqual (C2 .__origin__ , Concatenate )
5372
5429
self .assertEqual (C2 .__args__ , (int , T , P ))
5430
+ self .assertEqual (C3 .__origin__ , Concatenate )
5431
+ self .assertEqual (C3 .__args__ , (int , Ellipsis ))
5432
+ self .assertEqual (C4 .__origin__ , Concatenate )
5433
+ self .assertEqual (C4 .__args__ , (int , T , Ellipsis ))
5373
5434
5374
5435
def test_eq (self ):
5375
5436
P = ParamSpec ('P' )
@@ -5379,6 +5440,13 @@ def test_eq(self):
5379
5440
self .assertEqual (C1 , C2 )
5380
5441
self .assertEqual (hash (C1 ), hash (C2 ))
5381
5442
self .assertNotEqual (C1 , C3 )
5443
+
5444
+ C4 = Concatenate [int , ...]
5445
+ C5 = Concatenate [int , ...]
5446
+ C6 = Concatenate [int , T , ...]
5447
+ self .assertEqual (C4 , C5 )
5448
+ self .assertEqual (hash (C4 ), hash (C5 ))
5449
+ self .assertNotEqual (C4 , C6 )
5382
5450
5383
5451
5384
5452
class TypeGuardTests (BaseTestCase ):
@@ -6050,7 +6118,7 @@ def test_typing_extensions_defers_when_possible(self):
6050
6118
if sys .version_info < (3 , 10 , 1 ):
6051
6119
exclude |= {"Literal" }
6052
6120
if sys .version_info < (3 , 11 ):
6053
- exclude |= {'final' , 'Any' , 'NewType' , 'overload' }
6121
+ exclude |= {'final' , 'Any' , 'NewType' , 'overload' , 'Concatenate' }
6054
6122
if sys .version_info < (3 , 12 ):
6055
6123
exclude |= {
6056
6124
'SupportsAbs' , 'SupportsBytes' ,
0 commit comments