@@ -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 (<
10000
span class=pl-en>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,32 @@ 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 , 9 ):
5357
+
5358
+ C5 = Callable [Concatenate [int , ...], int ]
5359
+ C6 = Callable [Concatenate [int , T , ...], T ]
5360
+ self .assertEqual (C5 .__origin__ , C6 .__origin__ )
5361
+ self .assertNotEqual (C5 , C6 )
5362
+
5363
+ # Test collections.abc.Callable too.
5364
+ C7 = collections .abc .Callable [Concatenate [int , ...], int ]
5365
+ C8 = collections .abc .Callable [Concatenate [int , T , ...], T ]
5366
+ self .assertEqual (C7 .__origin__ , C8 .__origin__ )
5367
+ self .assertNotEqual (C7 , C8 )
5368
+
5369
+
5370
+ @skipIf (TYPING_3_9_0 , "Python 3.8 does not support Callable non-type args, i.e. Ellipsis" )
5371
+ def test_callable_with_concat_3_8 (self ):
5372
+ # This will fail on Python 3.8
5373
+ try :
5374
+ Callable [Concatenate [int , ...], int ]
5375
+ except TypeError as e :
5376
+ if "each arg must be a type." in str (e ):
5377
+ self .fail ("Python 3.8 does not support Callable with non-type args, i.e. Ellipsis" )
5378
+ else :
5379
+ raise e
5380
+
5342
5381
def test_invalid_uses (self ):
5343
5382
P = ParamSpec ('P' )
5344
5383
T = TypeVar ('T' )
@@ -5351,25 +5390,53 @@ def test_invalid_uses(self):
5351
5390
5352
5391
with self .assertRaisesRegex (
5353
5392
TypeError ,
5354
- 'The last parameter to Concatenate should be a ParamSpec variable' ,
5393
+ 'The last parameter to Concatenate should be a ParamSpec variable or ellipsis ' ,
5355
5394
):
5356
5395
Concatenate [P , T ]
5396
+
5397
+
5398
+ if sys .version_info [:2 ] >= (3 , 9 ):
5399
+ # Cannot construct a Callable with Ellipsis in Python3.8 as args must be types
5400
+ with self .assertRaisesRegex (
5401
+ TypeError ,
5402
+ 'is not a generic class' ,
5403
+ ):
5404
+ Callable [Concatenate [int , ...], Any ][T ]
5405
+
5357
5406
5358
5407
if not TYPING_3_11_0 :
5359
5408
with self .assertRaisesRegex (
5360
5409
TypeError ,
5361
5410
'each arg must be a type' ,
5362
5411
):
5363
5412
Concatenate [1 , P ]
5413
+
5414
+ with self .assertRaisesRegex (
5415
+ TypeError ,
5416
+ 'each arg must be a type.' ,
5417
+ ):
5418
+ Concatenate [1 , ..., P ]
5419
+
5420
+ def test_alias (self ):
5421
+ P = ParamSpec ("P" )
5422
+ C1 = Callable [Concatenate [int , P ], Any ]
5423
+
5424
+ c1 : C1 [...]
5364
5425
5365
5426
def test_basic_introspection (self ):
5366
5427
P = ParamSpec ('P' )
5367
5428
C1 = Concatenate [int , P ]
5368
5429
C2 = Concatenate [int , T , P ]
5430
+ C3 = Concatenate [int , ...]
5431
+ C4 = Concatenate [int , T , ...]
5369
5432
self .assertEqual (C1 .__origin__ , Concatenate )
5370
5433
self .assertEqual (C1 .__args__ , (int , P ))
5371
5434
self .assertEqual (C2 .__origin__ , Concatenate )
5372
5435
self .assertEqual (C2 .__args__ , (int , T , P ))
5436
+ self .assertEqual (C3 .__origin__ , Concatenate )
5437
+ self .assertEqual (C3 .__args__ , (int , Ellipsis ))
5438
+ self .assertEqual (C4 .__origin__ , Concatenate )
5439
+ self .assertEqual (C4 .__args__ , (int , T , Ellipsis ))
5373
5440
5374
5441
def test_eq (self ):
5375
5442
P = ParamSpec ('P' )
@@ -5379,6 +5446,13 @@ def test_eq(self):
5379
5446
self .assertEqual (C1 , C2 )
5380
5447
self .assertEqual (hash (C1 ), hash (C2 ))
5381
5448
self .assertNotEqual (C1 , C3 )
5449
+
5450
+ C4 = Concatenate [int , ...]
5451
+ C5 = Concatenate [int , ...]
5452
+ C6 = Concatenate [int , T , ...]
5453
+ self .assertEqual (C4 , C5 )
5454
+ self .assertEqual (hash (C4 ), hash (C5 ))
5455
+ self .assertNotEqual (C4 , C6 )
5382
5456
5383
5457
5384
5458
class TypeGuardTests (BaseTestCase ):
@@ -6050,7 +6124,7 @@ def test_typing_extensions_defers_when_possible(self):
6050
6124
if sys .version_info < (3 , 10 , 1 ):
6051
6125
exclude |= {"Literal" }
6052
6126
if sys .version_info < (3 , 11 ):
6053
- exclude |= {'final' , 'Any' , 'NewType' , 'overload' }
6127
+ exclude |= {'final' , 'Any' , 'NewType' , 'overload' , 'Concatenate' }
6054
6128
if sys .version_info < (3 , 12 ):
6055
6129
exclude |= {
6056
6130
'SupportsAbs' , 'SupportsBytes' ,
0 commit comments