5050
5151from .testutils import subprocess_pickle_echo
5252from .testutils import assert_run_python_script
53+ from .testutils import subprocess_worker
5354
5455
5556_TEST_GLOBAL_VARIABLE = "default_value"
@@ -2121,6 +2122,12 @@ def test_pickle_dynamic_typevar(self):
21212122 for attr in attr_list :
21222123 assert getattr (T , attr ) == getattr (depickled_T , attr )
21232124
2125+ def test_pickle_dynamic_typevar_memoization (self ):
2126+ T = typing .TypeVar ('T' )
2127+ depickled_T1 , depickled_T2 = pickle_depickle ((T , T ),
2128+ protocol = self .protocol )
2129+ assert depickled_T1 is depickled_T2
2130+
21242131 def test_pickle_importable_typevar (self ):
21252132 from .mypkg import T
21262133 T1 = pickle_depickle (T , protocol = self .protocol )
@@ -2130,6 +2137,61 @@ def test_pickle_importable_typevar(self):
21302137 from typing import AnyStr
21312138 assert AnyStr is pickle_depickle (AnyStr , protocol = self .protocol )
21322139
2140+ @unittest .skipIf (sys .version_info < (3 , 7 ),
2141+ "Pickling generics not supported below py37" )
2142+ def test_generic_type (self ):
2143+ T = typing .TypeVar ('T' )
2144+
2145+ class C (typing .Generic [T ]):
2146+ pass
2147+
2148+ assert pickle_depickle (C , protocol = self .protocol ) is C
2149+ assert pickle_depickle (C [int ], protocol = self .protocol ) is C [int ]
2150+
2151+ with subprocess_worker (protocol = self .protocol ) as worker :
2152+
2153+ def check_generic (generic , origin , type_value ):
2154+ assert generic .__origin__ is origin
2155+ assert len (generic .__args__ ) == 1
2156+ assert generic .__args__ [0 ] is type_value
2157+
2158+ assert len (origin .__orig_bases__ ) == 1
2159+ ob = origin .__orig_bases__ [0 ]
2160+ assert ob .__origin__ is typing .Generic
2161+ assert len (ob .__parameters__ ) == 1
2162+
2163+ return "ok"
2164+
2165+ assert check_generic (C [int ], C , int ) == "ok"
2166+ assert worker .run (check_generic , C [int ], C , int ) == "ok"
2167+
2168+ @unittest .skipIf (sys .version_info < (3 , 7 ),
2169+ "Pickling type hints not supported below py37" )
2170+ def test_locally_defined_class_with_type_hints (self ):
2171+ with subprocess_worker (protocol = self .protocol ) as worker :
2172+ for type_ in _all_types_to_test ():
2173+ # The type annotation syntax causes a SyntaxError on Python 3.5
2174+ code = textwrap .dedent ("""\
2175+ class MyClass:
2176+ attribute: type_
2177+
2178+ def method(self, arg: type_) -> type_:
2179+ return arg
2180+ """ )
2181+ ns = {"type_" : type_ }
2182+ exec (code , ns )
2183+ MyClass = ns ["MyClass" ]
2184+
2185+ def check_annotations (obj , expected_type ):
2186+ assert obj .__annotations__ ["attribute" ] is expected_type
2187+ assert obj .method .__annotations__ ["arg" ] is expected_type
2188+ assert obj .method .__annotations__ ["return" ] is expected_type
2189+ return "ok"
2190+
2191+ obj = MyClass ()
2192+ assert check_annotations (obj , type_ ) == "ok"
2193+ assert worker .run (check_annotations , obj , type_ ) == "ok"
2194+
21332195
21342196class Protocol2CloudPickleTest (CloudPickleTest ):
21352197
@@ -2161,5 +2223,28 @@ def test_lookup_module_and_qualname_stdlib_typevar():
21612223 assert name == 'AnyStr'
21622224
21632225
2226+ def _all_types_to_test ():
2227+ T = typing .TypeVar ('T' )
2228+
2229+ class C (typing .Generic [T ]):
2230+ pass
2231+
2232+ return [
2233+ C , C [int ],
2234+ T , typing .Any , typing .NoReturn , typing .Optional ,
2235+ typing .Generic , typing .Union , typing .ClassVar ,
2236+ typing .Optional [int ],
2237+ typing .Generic [T ],
2238+ typing .Callable [[int ], typing .Any ],
2239+ typing .Callable [..., typing .Any ],
2240+ typing .Callable [[], typing .Any ],
2241+ typing .Tuple [int , ...],
2242+ typing .Tuple [int , C [int ]],
2243+ typing .ClassVar [C [int ]],
2244+ typing .List [int ],
2245+ typing .Dict [int , str ],
2246+ ]
2247+
2248+
21642249if __name__ == '__main__' :
21652250 unittest .main ()
0 commit comments