@@ -36,7 +36,8 @@ def clear_executors(func):
3636
3737@requires_specialization
3838@unittest .skipIf (Py_GIL_DISABLED , "optimizer not yet supported in free-threaded builds" )
39- @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ),
39+ @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ) and
40+ hasattr (_testinternalcapi , "new_counter_optimizer" ),
4041 "Requires optimizer infrastructure" )
4142class TestOptimizerAPI (unittest .TestCase ):
4243
@@ -140,89 +141,8 @@ def get_opnames(ex):
140141
141142@requires_specialization
142143@unittest .skipIf (Py_GIL_DISABLED , "optimizer not yet supported in free-threaded builds" )
143- @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ),
144- "Requires optimizer infrastructure" )
145- class TestExecutorInvalidation (unittest .TestCase ):
146-
147- def setUp (self ):
148- self .old = _testinternalcapi .get_optimizer ()
149- self .opt = _testinternalcapi .new_counter_optimizer ()
150- _testinternalcapi .set_optimizer (self .opt )
151-
152- def tearDown (self ):
153- _testinternalcapi .set_optimizer (self .old )
154-
155- def test_invalidate_object (self ):
156- # Generate a new set of functions at each call
157- ns = {}
158- func_src = "\n " .join (
159- f"""
160- def f{ n } ():
161- for _ in range(1000):
162- pass
163- """ for n in range (5 )
164- )
165- exec (textwrap .dedent (func_src ), ns , ns )
166- funcs = [ ns [f'f{ n } ' ] for n in range (5 )]
167- objects = [object () for _ in range (5 )]
168-
169- for f in funcs :
170- f ()
171- executors = [get_first_executor (f ) for f in funcs ]
172- # Set things up so each executor depends on the objects
173- # with an equal or lower index.
174- for i , exe in enumerate (executors ):
175- self .assertTrue (exe .is_valid ())
176- for obj in objects [:i + 1 ]:
177- _testinternalcapi .add_executor_dependency (exe , obj )
178- self .assertTrue (exe .is_valid ())
179- # Assert that the correct executors are invalidated
180- # and check that nothing crashes when we invalidate
181- # an executor multiple times.
182- for i in (4 ,3 ,2 ,1 ,0 ):
183- _testinternalcapi .invalidate_executors (objects [i ])
184- for exe in executors [i :]:
185- self .assertFalse (exe .is_valid ())
186- for exe in executors [:i ]:
187- self .assertTrue (exe .is_valid ())
188-
189- def test_uop_optimizer_invalidation (self ):
190- # Generate a new function at each call
191- ns = {}
192- exec (textwrap .dedent ("""
193- def f():
194- for i in range(1000):
195- pass
196- """ ), ns , ns )
197- f = ns ['f' ]
198- opt = _testinternalcapi .new_uop_optimizer ()
199- with temporary_optimizer (opt ):
200- f ()
201- exe = get_first_executor (f )
202- self .assertIsNotNone (exe )
203- self .assertTrue (exe .is_valid ())
204- _testinternalcapi .invalidate_executors (f .__code__ )
205- self .assertFalse (exe .is_valid ())
206-
207- def test_sys__clear_internal_caches (self ):
208- def f ():
209- for _ in range (1000 ):
210- pass
211- opt = _testinternalcapi .new_uop_optimizer ()
212- with temporary_optimizer (opt ):
213- f ()
214- exe = get_first_executor (f )
215- self .assertIsNotNone (exe )
216- self .assertTrue (exe .is_valid ())
217- sys ._clear_internal_caches ()
218- self .assertFalse (exe .is_valid ())
219- exe = get_first_executor (f )
220- self .assertIsNone (exe )
221-
222-
223- @requires_specialization
224- @unittest .skipIf (Py_GIL_DISABLED , "optimizer not yet supported in free-threaded builds" )
225- @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ),
144+ @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ) and
145+ hasattr (_testinternalcapi , "new_counter_optimizer" ),
226146 "Requires optimizer infrastructure" )
227147class TestExecutorInvalidation (unittest .TestCase ):
228148
0 commit comments