@@ -1681,12 +1681,16 @@ class C(Generic[T]): pass
16811681 # In 3.9 and lower we use typing_extensions's hacky implementation
16821682 # of ParamSpec, which gets incorrectly wrapped in a list
16831683 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 ))
16861684 self .assertEqual (get_args (Required [int ]), (int ,))
16871685 self .assertEqual (get_args (NotRequired [int ]), (int ,))
16881686 self .assertEqual (get_args (Unpack [Ts ]), (Ts ,))
16891687 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 ))
16901694
16911695
16921696class CollectionsAbcTests (BaseTestCase ):
@@ -5228,6 +5232,10 @@ class Y(Protocol[T, P]):
52285232 self .assertEqual (G2 .__args__ , (int , Concatenate [int , P_2 ]))
52295233 self .assertEqual (G2 .__parameters__ , (P_2 ,))
52305234
5235+ G3 = klass [int , Concatenate [int , ...]]
5236+ self .assertEqual (G3 .__args__ , (int , Concatenate [int , ...]))
5237+ self .assertEqual (G3 .__parameters__ , ())
5238+
52315239 # The following are some valid uses cases in PEP 612 that don't work:
52325240 # These do not work in 3.9, _type_check blocks the list and ellipsis.
52335241 # G3 = X[int, [int, bool]]
@@ -5312,7 +5320,7 @@ def run():
53125320
53135321 # The actual test:
53145322 self .assertEqual (result1 , result2 )
5315-
5323+
53165324
53175325class ConcatenateTests (BaseTestCase ):
53185326 def test_basics (self ):
@@ -5322,6 +5330,11 @@ class MyClass: ...
53225330
53235331 c = Concatenate [MyClass , P ]
53245332 self .assertNotEqual (c , Concatenate )
5333+
5334+ # Test Ellipsis Concatenation
5335+ d = Concatenate [MyClass , ...]
5336+ self .assertNotEqual (d , c )
5337+ self .assertNotEqual (d , Concatenate )
53255338
53265339 def test_valid_uses (self ):
53275340 P = ParamSpec ('P' )
@@ -5339,6 +5352,32 @@ def test_valid_uses(self):
53395352 self .assertEqual (C3 .__origin__ , C4 .__origin__ )
53405353 self .assertNotEqual (C3 , C4 )
53415354
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+
53425381 def test_invalid_uses (self ):
53435382 P = ParamSpec ('P' )
53445383 T = TypeVar ('T' )
@@ -5351,25 +5390,53 @@ def test_invalid_uses(self):
53515390
53525391 with self .assertRaisesRegex (
53535392 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 ' ,
53555394 ):
53565395 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+
53575406
53585407 if not TYPING_3_11_0 :
53595408 with self .assertRaisesRegex (
53605409 TypeError ,
53615410 'each arg must be a type' ,
53625411 ):
53635412 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 [...]
53645425
53655426 def test_basic_introspection (self ):
53665427 P = ParamSpec ('P' )
53675428 C1 = Concatenate [int , P ]
53685429 C2 = Concatenate [int , T , P ]
5430+ C3 = Concatenate [int , ...]
5431+ C4 = Concatenate [int , T , ...]
53695432 self .assertEqual (C1 .__origin__ , Concatenate )
53705433 self .assertEqual (C1 .__args__ , (int , P ))
53715434 self .assertEqual (C2 .__origin__ , Concatenate )
53725435 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 ))
53735440
53745441 def test_eq (self ):
53755442 P = ParamSpec ('P' )
@@ -5379,6 +5446,13 @@ def test_eq(self):
53795446 self .assertEqual (C1 , C2 )
53805447 self .assertEqual (hash (C1 ), hash (C2 ))
53815448 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 )
53825456
53835457
53845458class TypeGuardTests (BaseTestCase ):
@@ -6050,7 +6124,7 @@ def test_typing_extensions_defers_when_possible(self):
60506124 if sys .version_info < (3 , 10 , 1 ):
60516125 exclude |= {"Literal" }
60526126 if sys .version_info < (3 , 11 ):
6053- exclude |= {'final' , 'Any' , 'NewType' , 'overload' }
6127+ exclude |= {'final' , 'Any' , 'NewType' , 'overload' , 'Concatenate' }
60546128 if sys .version_info < (3 , 12 ):
60556129 exclude |= {
60566130 'SupportsAbs' , 'SupportsBytes' ,
0 commit comments