13
13
from typing import Generic
14
14
from typing import no_type_check
15
15
from typing_extensions import NoReturn , ClassVar , Final , IntVar , Literal , Type , NewType , TypedDict
16
- from typing_extensions import TypeAlias
16
+ from typing_extensions import TypeAlias , ParamSpec , Concatenate
17
+
17
18
try :
18
19
from typing_extensions import Protocol , runtime , runtime_checkable
19
20
except ImportError :
@@ -1898,6 +1899,118 @@ def test_cannot_subscript(self):
1898
1899
with self .assertRaises (TypeError ):
1899
1900
TypeAlias [int ]
1900
1901
1902
+ class ParamSpecTests (BaseTestCase ):
1903
+
1904
+ def test_basic_plain (self ):
1905
+ P = ParamSpec ('P' )
1906
+ self .assertEqual (P , P )
1907
+ self .assertIsInstance (P , ParamSpec )
1908
+ # Should be hashable
1909
+ hash (P )
1910
+
1911
+ def test_repr (self ):
1912
+ P = ParamSpec ('P' )
1913
+ P_co = ParamSpec ('P_co' , covariant = True )
1914
+ P_contra = ParamSpec ('P_contra' , contravariant = True )
1915
+ P_2 = ParamSpec ('P_2' )
1916
+ self .assertEqual (repr (P ), '~P' )
1917
+ self .assertEqual (repr (P_2 ), '~P_2' )
1918
+
1919
+ # Note: PEP 612 doesn't require these to be repr-ed correctly, but
1920
+ # just follow CPython.
1921
+ self .assertEqual (repr (P_co ), '+P_co' )
1922
+ self .assertEqual (repr (P_contra ), '-P_contra' )
1923
+
1924
+ def test_valid_uses (self ):
1925
+ P = ParamSpec ('P' )
1926
+ T = TypeVar ('T' )
1927
+ C1 = typing .Callable [P , int ]
1928
+ C2 = typing .Callable [P , T ]
1929
+
1930
+ # Note: no tests for Callable.__args__ and Callable.__parameters__ here
1931
+ # because pre-3.10 Callable sees ParamSpec as a plain list, not a
1932
+ # TypeVar.
1933
+
1934
+ # Test collections.abc.Callable too.
1935
+ if sys .version_info [:2 ] >= (3 , 9 ):
1936
+ C3 = collections .abc .Callable [P , int ]
1937
+ C4 = collections .abc .Callable [P , T ]
1938
+
1939
+ # ParamSpec instances should also have args and kwargs attributes.
1940
+ self .assertIn ('args' , dir (P ))
1941
+ self .assertIn ('kwargs' , dir (P ))
1942
+ P .args
1943
+ P .kwargs
1944
+
1945
+ # Note: ParamSpec doesn't work for pre-3.10 user-defined Generics due
1946
+ # to type checks inside Generic.
1947
+
1948
+ def test_pickle (self ):
1949
+ global P , P_co , P_contra
1950
+ P = ParamSpec ('P' )
1951
+ P_co = ParamSpec ('P_co' , covariant = True )
1952
+ P_contra = ParamSpec ('P_contra' , contravariant = True )
1953
+ for proto in range (pickle .HIGHEST_PROTOCOL ):
1954
+ with self .subTest ('Pickle protocol {proto}' .format (proto = proto )):
1955
+ for paramspec in (P , P_co , P_contra ):
1956
+ z = pickle .loads (pickle .dumps (paramspec , proto ))
1957
+ self .assertEqual (z .__name__ , paramspec .__name__ )
1958
+ self .assertEqual (z .__covariant__ , paramspec .__covariant__ )
1959
+ self .assertEqual (z .__contravariant__ , paramspec .__contravariant__ )
1960
+ self .assertEqual (z .__bound__ , paramspec .__bound__ )
1961
+
1962
+ def test_eq (self ):
1963
+ P = ParamSpec ('P' )
1964
+ self .assertEqual (P , P )
1965
+ self .assertEqual (hash (P ), hash (P ))
1966
+ # ParamSpec should compare by id similar to TypeVar in CPython
1967
+ self .assertNotEqual (ParamSpec ('P' ), P )
1968
+ self .assertIsNot (ParamSpec ('P' ), P )
1969
+ # Note: normally you don't test this as it breaks when there's
1970
+ # a hash collision. However, ParamSpec *must* guarantee that
1971
+ # as long as two objects don't have the same ID, their hashes
1972
+ # won't be the same.
1973
+ self .assertNotEqual (hash (ParamSpec ('P' )), hash (P ))
1974
+
1975
+
1976
+ class ConcatenateTests (BaseTestCase ):
1977
+ def test_basics (self ):
1978
+ P = ParamSpec ('P' )
1979
+
1980
+ class MyClass : ...
1981
+
1982
+ c = Concatenate [MyClass , P ]
1983
+ self .assertNotEqual (c , Concatenate )
1984
+
1985
+ def test_valid_uses (self ):
1986
+ P = ParamSpec ('P' )
1987
+ T = TypeVar ('T' )
1988
+ C1 = typing .Callable [Concatenate [int , P ], int ]
1989
+ C2 = typing .Callable [Concatenate [int , T , P ], T ]
1990
+
1991
+ # Test collections.abc.Callable too.
1992
+ if sys .version_info [:2 ] >= (3 , 9 ):
1993
+ C3 = collections .abc .Callable [Concatenate [int , P ], int ]
1994
+ C4 = collections .abc .Callable [Concatenate [int , T , P ], T ]
1995
+
1996
+ def test_basic_introspection (self ):
1997
+ P = ParamSpec ('P' )
1998
+ C1 = Concatenate [int , P ]
1999
+ C2 = Concatenate [int , T , P ]
2000
+ self .assertEqual (C1 .__origin__ , Concatenate )
2001
+ self .assertEqual (C1 .__args__ , (int , P ))
2002
+ self .assertEqual (C2 .__origin__ , Concatenate )
2003
+ self .assertEqual (C2 .__args__ , (int , T , P ))
2004
+
2005
+ def test_eq (self ):
2006
+ P = ParamSpec ('P' )
2007
+ C1 = Concatenate [int , P ]
2008
+ C2 = Concatenate [int , P ]
2009
+ C3 = Concatenate [int , T , P ]
2010
+ self .assertEqual (C1 , C2 )
2011
+ self .assertEqual (hash (C1 ), hash (C2 ))
2012
+ self .assertNotEqual (C1 , C3 )
2013
+
1901
2014
1902
2015
class AllTests (BaseTestCase ):
1903
2016
@@ -1914,6 +2027,10 @@ def test_typing_extensions_includes_standard(self):
1914
2027
self .assertIn ('overload' , a )
1915
2028
self .assertIn ('Text' , a )
1916
2029
self .assertIn ('TYPE_CHECKING' , a )
2030
+ self .assertIn ('TypeAlias' , a )
2031
+ self .assertIn ('ParamSpec' , a )
2032
+ self .assertIn ("Concatenate" , a )
2033
+
1917
2034
if TYPING_3_5_3 :
1918
2035
self .assertIn ('Annotated' , a )
1919
2036
if PEP_560 :
0 commit comments