| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2024-03-05 08:54:46 -07:00
										 |  |  | import pickle | 
					
						
							| 
									
										
										
										
											2024-06-17 21:04:58 +02:00
										 |  |  | from textwrap import dedent | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  | import threading | 
					
						
							|  |  |  | import types | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | import unittest | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from test import support | 
					
						
							|  |  |  | from test.support import import_helper | 
					
						
							|  |  |  | # Raise SkipTest if subinterpreters not supported. | 
					
						
							| 
									
										
										
										
											2024-04-24 10:18:24 -06:00
										 |  |  | _interpreters = import_helper.import_module('_interpreters') | 
					
						
							| 
									
										
										
										
											2024-04-11 15:00:54 -04:00
										 |  |  | from test.support import Py_GIL_DISABLED | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | from test.support import interpreters | 
					
						
							| 
									
										
										
										
											2024-04-24 21:25:22 +01:00
										 |  |  | from test.support import force_not_colorized | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | from test.support.interpreters import ( | 
					
						
							|  |  |  |     InterpreterError, InterpreterNotFoundError, ExecutionFailed, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | from .utils import ( | 
					
						
							|  |  |  |     _captured_script, _run_output, _running, TestBase, | 
					
						
							|  |  |  |     requires_test_modules, _testinternalcapi, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  | WHENCE_STR_UNKNOWN = 'unknown' | 
					
						
							|  |  |  | WHENCE_STR_RUNTIME = 'runtime init' | 
					
						
							|  |  |  | WHENCE_STR_LEGACY_CAPI = 'legacy C-API' | 
					
						
							|  |  |  | WHENCE_STR_CAPI = 'C-API' | 
					
						
							|  |  |  | WHENCE_STR_XI = 'cross-interpreter C-API' | 
					
						
							|  |  |  | WHENCE_STR_STDLIB = '_interpreters module' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | class ModuleTests(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_queue_aliases(self): | 
					
						
							|  |  |  |         first = [ | 
					
						
							|  |  |  |             interpreters.create_queue, | 
					
						
							|  |  |  |             interpreters.Queue, | 
					
						
							|  |  |  |             interpreters.QueueEmpty, | 
					
						
							|  |  |  |             interpreters.QueueFull, | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         second = [ | 
					
						
							|  |  |  |             interpreters.create_queue, | 
					
						
							|  |  |  |             interpreters.Queue, | 
					
						
							|  |  |  |             interpreters.QueueEmpty, | 
					
						
							|  |  |  |             interpreters.QueueFull, | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         self.assertEqual(second, first) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CreateTests(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_in_main(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         self.assertIsInstance(interp, interpreters.Interpreter) | 
					
						
							|  |  |  |         self.assertIn(interp, interpreters.list_all()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_in_thread(self): | 
					
						
							|  |  |  |         lock = threading.Lock() | 
					
						
							|  |  |  |         interp = None | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             nonlocal interp | 
					
						
							|  |  |  |             interp = interpreters.create() | 
					
						
							|  |  |  |             lock.acquire() | 
					
						
							|  |  |  |             lock.release() | 
					
						
							|  |  |  |         t = threading.Thread(target=f) | 
					
						
							|  |  |  |         with lock: | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |         t.join() | 
					
						
							|  |  |  |         self.assertIn(interp, interpreters.list_all()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_in_subinterpreter(self): | 
					
						
							|  |  |  |         main, = interpreters.list_all() | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         out = _run_output(interp, dedent("""
 | 
					
						
							|  |  |  |             from test.support import interpreters | 
					
						
							|  |  |  |             interp = interpreters.create() | 
					
						
							|  |  |  |             print(interp.id) | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         interp2 = interpreters.Interpreter(int(out)) | 
					
						
							|  |  |  |         self.assertEqual(interpreters.list_all(), [main, interp, interp2]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_after_destroy_all(self): | 
					
						
							|  |  |  |         before = set(interpreters.list_all()) | 
					
						
							|  |  |  |         # Create 3 subinterpreters. | 
					
						
							|  |  |  |         interp_lst = [] | 
					
						
							|  |  |  |         for _ in range(3): | 
					
						
							|  |  |  |             interps = interpreters.create() | 
					
						
							|  |  |  |             interp_lst.append(interps) | 
					
						
							|  |  |  |         # Now destroy them. | 
					
						
							|  |  |  |         for interp in interp_lst: | 
					
						
							|  |  |  |             interp.close() | 
					
						
							|  |  |  |         # Finally, create another. | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), before | {interp}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_after_destroy_some(self): | 
					
						
							|  |  |  |         before = set(interpreters.list_all()) | 
					
						
							|  |  |  |         # Create 3 subinterpreters. | 
					
						
							|  |  |  |         interp1 = interpreters.create() | 
					
						
							|  |  |  |         interp2 = interpreters.create() | 
					
						
							|  |  |  |         interp3 = interpreters.create() | 
					
						
							|  |  |  |         # Now destroy 2 of them. | 
					
						
							|  |  |  |         interp1.close() | 
					
						
							|  |  |  |         interp2.close() | 
					
						
							|  |  |  |         # Finally, create another. | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), before | {interp3, interp}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GetMainTests(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_id(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         self.assertEqual(main.id, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_current(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         current = interpreters.get_current() | 
					
						
							|  |  |  |         self.assertIs(main, current) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_idempotent(self): | 
					
						
							|  |  |  |         main1 = interpreters.get_main() | 
					
						
							|  |  |  |         main2 = interpreters.get_main() | 
					
						
							|  |  |  |         self.assertIs(main1, main2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GetCurrentTests(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_main(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         current = interpreters.get_current() | 
					
						
							|  |  |  |         self.assertEqual(current, main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_subinterpreter(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         out = _run_output(interp, dedent("""
 | 
					
						
							|  |  |  |             from test.support import interpreters | 
					
						
							|  |  |  |             cur = interpreters.get_current() | 
					
						
							|  |  |  |             print(cur.id) | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         current = interpreters.Interpreter(int(out)) | 
					
						
							|  |  |  |         self.assertEqual(current, interp) | 
					
						
							|  |  |  |         self.assertNotEqual(current, main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_idempotent(self): | 
					
						
							|  |  |  |         with self.subTest('main'): | 
					
						
							|  |  |  |             cur1 = interpreters.get_current() | 
					
						
							|  |  |  |             cur2 = interpreters.get_current() | 
					
						
							|  |  |  |             self.assertIs(cur1, cur2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('subinterpreter'): | 
					
						
							|  |  |  |             interp = interpreters.create() | 
					
						
							|  |  |  |             out = _run_output(interp, dedent("""
 | 
					
						
							|  |  |  |                 from test.support import interpreters | 
					
						
							|  |  |  |                 cur = interpreters.get_current() | 
					
						
							|  |  |  |                 print(id(cur)) | 
					
						
							|  |  |  |                 cur = interpreters.get_current() | 
					
						
							|  |  |  |                 print(id(cur)) | 
					
						
							|  |  |  |                 """))
 | 
					
						
							|  |  |  |             objid1, objid2 = (int(v) for v in out.splitlines()) | 
					
						
							|  |  |  |             self.assertEqual(objid1, objid2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('per-interpreter'): | 
					
						
							|  |  |  |             interp = interpreters.create() | 
					
						
							|  |  |  |             out = _run_output(interp, dedent("""
 | 
					
						
							|  |  |  |                 from test.support import interpreters | 
					
						
							|  |  |  |                 cur = interpreters.get_current() | 
					
						
							|  |  |  |                 print(id(cur)) | 
					
						
							|  |  |  |                 """))
 | 
					
						
							|  |  |  |             id1 = int(out) | 
					
						
							|  |  |  |             id2 = id(interp) | 
					
						
							|  |  |  |             self.assertNotEqual(id1, id2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     @requires_test_modules | 
					
						
							|  |  |  |     def test_created_with_capi(self): | 
					
						
							|  |  |  |         expected = _testinternalcapi.next_interpreter_id() | 
					
						
							|  |  |  |         text = self.run_temp_from_capi(f"""
 | 
					
						
							|  |  |  |             import {interpreters.__name__} as interpreters | 
					
						
							|  |  |  |             interp = interpreters.get_current() | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             print((interp.id, interp.whence)) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             """)
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         interpid, whence = eval(text) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         self.assertEqual(interpid, expected) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         self.assertEqual(whence, WHENCE_STR_CAPI) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ListAllTests(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_initial(self): | 
					
						
							|  |  |  |         interps = interpreters.list_all() | 
					
						
							|  |  |  |         self.assertEqual(1, len(interps)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_after_creating(self): | 
					
						
							|  |  |  |         main = interpreters.get_current() | 
					
						
							|  |  |  |         first = interpreters.create() | 
					
						
							|  |  |  |         second = interpreters.create() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ids = [] | 
					
						
							|  |  |  |         for interp in interpreters.list_all(): | 
					
						
							|  |  |  |             ids.append(interp.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(ids, [main.id, first.id, second.id]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_after_destroying(self): | 
					
						
							|  |  |  |         main = interpreters.get_current() | 
					
						
							|  |  |  |         first = interpreters.create() | 
					
						
							|  |  |  |         second = interpreters.create() | 
					
						
							|  |  |  |         first.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ids = [] | 
					
						
							|  |  |  |         for interp in interpreters.list_all(): | 
					
						
							|  |  |  |             ids.append(interp.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(ids, [main.id, second.id]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_idempotent(self): | 
					
						
							|  |  |  |         main = interpreters.get_current() | 
					
						
							|  |  |  |         first = interpreters.create() | 
					
						
							|  |  |  |         second = interpreters.create() | 
					
						
							|  |  |  |         expected = [main, first, second] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         actual = interpreters.list_all() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(actual, expected) | 
					
						
							|  |  |  |         for interp1, interp2 in zip(actual, expected): | 
					
						
							|  |  |  |             self.assertIs(interp1, interp2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     def test_created_with_capi(self): | 
					
						
							|  |  |  |         mainid, *_ = _interpreters.get_main() | 
					
						
							|  |  |  |         interpid1 = _interpreters.create() | 
					
						
							|  |  |  |         interpid2 = _interpreters.create() | 
					
						
							|  |  |  |         interpid3 = _interpreters.create() | 
					
						
							|  |  |  |         interpid4 = interpid3 + 1 | 
					
						
							|  |  |  |         interpid5 = interpid4 + 1 | 
					
						
							|  |  |  |         expected = [ | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             (mainid, WHENCE_STR_RUNTIME), | 
					
						
							|  |  |  |             (interpid1, WHENCE_STR_STDLIB), | 
					
						
							|  |  |  |             (interpid2, WHENCE_STR_STDLIB), | 
					
						
							|  |  |  |             (interpid3, WHENCE_STR_STDLIB), | 
					
						
							|  |  |  |             (interpid4, WHENCE_STR_CAPI), | 
					
						
							|  |  |  |             (interpid5, WHENCE_STR_STDLIB), | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         ] | 
					
						
							|  |  |  |         expected2 = expected[:-2] | 
					
						
							|  |  |  |         text = self.run_temp_from_capi(f"""
 | 
					
						
							|  |  |  |             import {interpreters.__name__} as interpreters | 
					
						
							|  |  |  |             interp = interpreters.create() | 
					
						
							|  |  |  |             print( | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 [(i.id, i.whence) for i in interpreters.list_all()]) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             """)
 | 
					
						
							|  |  |  |         res = eval(text) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         res2 = [(i.id, i.whence) for i in interpreters.list_all()] | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         self.assertEqual(res, expected) | 
					
						
							|  |  |  |         self.assertEqual(res2, expected2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class InterpreterObjectTests(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_init_int(self): | 
					
						
							|  |  |  |         interpid = interpreters.get_current().id | 
					
						
							|  |  |  |         interp = interpreters.Interpreter(interpid) | 
					
						
							|  |  |  |         self.assertEqual(interp.id, interpid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_init_interpreter_id(self): | 
					
						
							|  |  |  |         interpid = interpreters.get_current()._id | 
					
						
							|  |  |  |         interp = interpreters.Interpreter(interpid) | 
					
						
							|  |  |  |         self.assertEqual(interp._id, interpid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_init_unsupported(self): | 
					
						
							|  |  |  |         actualid = interpreters.get_current().id | 
					
						
							|  |  |  |         for interpid in [ | 
					
						
							|  |  |  |             str(actualid), | 
					
						
							|  |  |  |             float(actualid), | 
					
						
							|  |  |  |             object(), | 
					
						
							|  |  |  |             None, | 
					
						
							|  |  |  |             '', | 
					
						
							|  |  |  |         ]: | 
					
						
							|  |  |  |             with self.subTest(repr(interpid)): | 
					
						
							|  |  |  |                 with self.assertRaises(TypeError): | 
					
						
							|  |  |  |                     interpreters.Interpreter(interpid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_idempotent(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         interp = interpreters.Interpreter(main.id) | 
					
						
							|  |  |  |         self.assertIs(interp, main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_init_does_not_exist(self): | 
					
						
							|  |  |  |         with self.assertRaises(InterpreterNotFoundError): | 
					
						
							|  |  |  |             interpreters.Interpreter(1_000_000) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_init_bad_id(self): | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             interpreters.Interpreter(-1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_id_type(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         current = interpreters.get_current() | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         self.assertIsInstance(main.id, int) | 
					
						
							|  |  |  |         self.assertIsInstance(current.id, int) | 
					
						
							|  |  |  |         self.assertIsInstance(interp.id, int) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_id_readonly(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         with self.assertRaises(AttributeError): | 
					
						
							|  |  |  |             interp.id = 1_000_000 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |     def test_whence(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('main'): | 
					
						
							|  |  |  |             self.assertEqual(main.whence, WHENCE_STR_RUNTIME) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from _interpreters'): | 
					
						
							|  |  |  |             self.assertEqual(interp.whence, WHENCE_STR_STDLIB) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API'): | 
					
						
							|  |  |  |             text = self.run_temp_from_capi(f"""
 | 
					
						
							|  |  |  |                 import {interpreters.__name__} as interpreters | 
					
						
							|  |  |  |                 interp = interpreters.get_current() | 
					
						
							|  |  |  |                 print(repr(interp.whence)) | 
					
						
							|  |  |  |                 """)
 | 
					
						
							|  |  |  |             whence = eval(text) | 
					
						
							|  |  |  |             self.assertEqual(whence, WHENCE_STR_CAPI) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('readonly'): | 
					
						
							|  |  |  |             for value in [ | 
					
						
							|  |  |  |                 None, | 
					
						
							|  |  |  |                 WHENCE_STR_UNKNOWN, | 
					
						
							|  |  |  |                 WHENCE_STR_RUNTIME, | 
					
						
							|  |  |  |                 WHENCE_STR_STDLIB, | 
					
						
							|  |  |  |                 WHENCE_STR_CAPI, | 
					
						
							|  |  |  |             ]: | 
					
						
							|  |  |  |                 with self.assertRaises(AttributeError): | 
					
						
							|  |  |  |                     interp.whence = value | 
					
						
							|  |  |  |                 with self.assertRaises(AttributeError): | 
					
						
							|  |  |  |                     main.whence = value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |     def test_hashable(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         expected = hash(interp.id) | 
					
						
							|  |  |  |         actual = hash(interp) | 
					
						
							|  |  |  |         self.assertEqual(actual, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_equality(self): | 
					
						
							|  |  |  |         interp1 = interpreters.create() | 
					
						
							|  |  |  |         interp2 = interpreters.create() | 
					
						
							|  |  |  |         self.assertEqual(interp1, interp1) | 
					
						
							|  |  |  |         self.assertNotEqual(interp1, interp2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-05 08:54:46 -07:00
										 |  |  |     def test_pickle(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         data = pickle.dumps(interp) | 
					
						
							|  |  |  |         unpickled = pickle.loads(data) | 
					
						
							|  |  |  |         self.assertEqual(unpickled, interp) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TestInterpreterIsRunning(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_main(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         self.assertTrue(main.is_running()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     # XXX Is this still true? | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |     @unittest.skip('Fails on FreeBSD') | 
					
						
							|  |  |  |     def test_subinterpreter(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         self.assertFalse(interp.is_running()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with _running(interp): | 
					
						
							|  |  |  |             self.assertTrue(interp.is_running()) | 
					
						
							|  |  |  |         self.assertFalse(interp.is_running()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_finished(self): | 
					
						
							|  |  |  |         r, w = self.pipe() | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interp.exec(f"""if True:
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             import os | 
					
						
							|  |  |  |             os.write({w}, b'x') | 
					
						
							|  |  |  |             """)
 | 
					
						
							|  |  |  |         self.assertFalse(interp.is_running()) | 
					
						
							|  |  |  |         self.assertEqual(os.read(r, 1), b'x') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_from_subinterpreter(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         out = _run_output(interp, dedent(f"""
 | 
					
						
							| 
									
										
										
										
											2024-04-24 10:18:24 -06:00
										 |  |  |             import _interpreters | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             if _interpreters.is_running({interp.id}): | 
					
						
							|  |  |  |                 print(True) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 print(False) | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         self.assertEqual(out.strip(), 'True') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_already_destroyed(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         interp.close() | 
					
						
							|  |  |  |         with self.assertRaises(InterpreterNotFoundError): | 
					
						
							|  |  |  |             interp.is_running() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_with_only_background_threads(self): | 
					
						
							|  |  |  |         r_interp, w_interp = self.pipe() | 
					
						
							|  |  |  |         r_thread, w_thread = self.pipe() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         DONE = b'D' | 
					
						
							|  |  |  |         FINISHED = b'F' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interp.exec(f"""if True:
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             import os | 
					
						
							|  |  |  |             import threading | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def task(): | 
					
						
							|  |  |  |                 v = os.read({r_thread}, 1) | 
					
						
							|  |  |  |                 assert v == {DONE!r} | 
					
						
							|  |  |  |                 os.write({w_interp}, {FINISHED!r}) | 
					
						
							|  |  |  |             t = threading.Thread(target=task) | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |             """)
 | 
					
						
							|  |  |  |         self.assertFalse(interp.is_running()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         os.write(w_thread, DONE) | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interp.exec('t.join()') | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |         self.assertEqual(os.read(r_interp, 1), FINISHED) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     def test_created_with_capi(self): | 
					
						
							|  |  |  |         script = dedent(f"""
 | 
					
						
							|  |  |  |             import {interpreters.__name__} as interpreters | 
					
						
							|  |  |  |             interp = interpreters.get_current() | 
					
						
							|  |  |  |             print(interp.is_running()) | 
					
						
							|  |  |  |             """)
 | 
					
						
							|  |  |  |         def parse_results(text): | 
					
						
							|  |  |  |             self.assertNotEqual(text, "") | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 return eval(text) | 
					
						
							|  |  |  |             except Exception: | 
					
						
							|  |  |  |                 raise Exception(repr(text)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('running __main__ (from self)'): | 
					
						
							|  |  |  |             with self.interpreter_from_capi() as interpid: | 
					
						
							|  |  |  |                 text = self.run_from_capi(interpid, script, main=True) | 
					
						
							|  |  |  |             running = parse_results(text) | 
					
						
							|  |  |  |             self.assertTrue(running) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('running, but not __main__ (from self)'): | 
					
						
							|  |  |  |             text = self.run_temp_from_capi(script) | 
					
						
							|  |  |  |             running = parse_results(text) | 
					
						
							|  |  |  |             self.assertFalse(running) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('running __main__ (from other)'): | 
					
						
							|  |  |  |             with self.interpreter_obj_from_capi() as (interp, interpid): | 
					
						
							|  |  |  |                 before = interp.is_running() | 
					
						
							|  |  |  |                 with self.running_from_capi(interpid, main=True): | 
					
						
							|  |  |  |                     during = interp.is_running() | 
					
						
							|  |  |  |                 after = interp.is_running() | 
					
						
							|  |  |  |             self.assertFalse(before) | 
					
						
							|  |  |  |             self.assertTrue(during) | 
					
						
							|  |  |  |             self.assertFalse(after) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('running, but not __main__ (from other)'): | 
					
						
							|  |  |  |             with self.interpreter_obj_from_capi() as (interp, interpid): | 
					
						
							|  |  |  |                 before = interp.is_running() | 
					
						
							|  |  |  |                 with self.running_from_capi(interpid, main=False): | 
					
						
							|  |  |  |                     during = interp.is_running() | 
					
						
							|  |  |  |                 after = interp.is_running() | 
					
						
							|  |  |  |             self.assertFalse(before) | 
					
						
							|  |  |  |             self.assertFalse(during) | 
					
						
							|  |  |  |             self.assertFalse(after) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('not running (from other)'): | 
					
						
							|  |  |  |             with self.interpreter_obj_from_capi() as (interp, _): | 
					
						
							|  |  |  |                 running = interp.is_running() | 
					
						
							|  |  |  |             self.assertFalse(running) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TestInterpreterClose(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_basic(self): | 
					
						
							|  |  |  |         main = interpreters.get_main() | 
					
						
							|  |  |  |         interp1 = interpreters.create() | 
					
						
							|  |  |  |         interp2 = interpreters.create() | 
					
						
							|  |  |  |         interp3 = interpreters.create() | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), | 
					
						
							|  |  |  |                          {main, interp1, interp2, interp3}) | 
					
						
							|  |  |  |         interp2.close() | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), | 
					
						
							|  |  |  |                          {main, interp1, interp3}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_all(self): | 
					
						
							|  |  |  |         before = set(interpreters.list_all()) | 
					
						
							|  |  |  |         interps = set() | 
					
						
							|  |  |  |         for _ in range(3): | 
					
						
							|  |  |  |             interp = interpreters.create() | 
					
						
							|  |  |  |             interps.add(interp) | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), before | interps) | 
					
						
							|  |  |  |         for interp in interps: | 
					
						
							|  |  |  |             interp.close() | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), before) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_main(self): | 
					
						
							|  |  |  |         main, = interpreters.list_all() | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.assertRaises(InterpreterError): | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             main.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             with self.assertRaises(InterpreterError): | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |                 main.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         t = threading.Thread(target=f) | 
					
						
							|  |  |  |         t.start() | 
					
						
							|  |  |  |         t.join() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_already_destroyed(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         interp.close() | 
					
						
							|  |  |  |         with self.assertRaises(InterpreterNotFoundError): | 
					
						
							|  |  |  |             interp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_from_current(self): | 
					
						
							|  |  |  |         main, = interpreters.list_all() | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         out = _run_output(interp, dedent(f"""
 | 
					
						
							|  |  |  |             from test.support import interpreters | 
					
						
							|  |  |  |             interp = interpreters.Interpreter({interp.id}) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 interp.close() | 
					
						
							| 
									
										
										
										
											2024-04-03 10:58:39 -06:00
										 |  |  |             except interpreters.InterpreterError: | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |                 print('failed') | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         self.assertEqual(out.strip(), 'failed') | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), {main, interp}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_from_sibling(self): | 
					
						
							|  |  |  |         main, = interpreters.list_all() | 
					
						
							|  |  |  |         interp1 = interpreters.create() | 
					
						
							|  |  |  |         interp2 = interpreters.create() | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), | 
					
						
							|  |  |  |                          {main, interp1, interp2}) | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interp1.exec(dedent(f"""
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             from test.support import interpreters | 
					
						
							|  |  |  |             interp2 = interpreters.Interpreter({interp2.id}) | 
					
						
							|  |  |  |             interp2.close() | 
					
						
							|  |  |  |             interp3 = interpreters.create() | 
					
						
							|  |  |  |             interp3.close() | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         self.assertEqual(set(interpreters.list_all()), {main, interp1}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_from_other_thread(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             interp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         t = threading.Thread(target=f) | 
					
						
							|  |  |  |         t.start() | 
					
						
							|  |  |  |         t.join() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     # XXX Is this still true? | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |     @unittest.skip('Fails on FreeBSD') | 
					
						
							|  |  |  |     def test_still_running(self): | 
					
						
							|  |  |  |         main, = interpreters.list_all() | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         with _running(interp): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             with self.assertRaises(InterpreterError): | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |                 interp.close() | 
					
						
							|  |  |  |             self.assertTrue(interp.is_running()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_subthreads_still_running(self): | 
					
						
							|  |  |  |         r_interp, w_interp = self.pipe() | 
					
						
							|  |  |  |         r_thread, w_thread = self.pipe() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         FINISHED = b'F' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interp.exec(f"""if True:
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             import os | 
					
						
							|  |  |  |             import threading | 
					
						
							|  |  |  |             import time | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             done = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def notify_fini(): | 
					
						
							|  |  |  |                 global done | 
					
						
							|  |  |  |                 done = True | 
					
						
							|  |  |  |                 t.join() | 
					
						
							|  |  |  |             threading._register_atexit(notify_fini) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def task(): | 
					
						
							|  |  |  |                 while not done: | 
					
						
							|  |  |  |                     time.sleep(0.1) | 
					
						
							|  |  |  |                 os.write({w_interp}, {FINISHED!r}) | 
					
						
							|  |  |  |             t = threading.Thread(target=task) | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |             """)
 | 
					
						
							|  |  |  |         interp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(os.read(r_interp, 1), FINISHED) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     def test_created_with_capi(self): | 
					
						
							|  |  |  |         script = dedent(f"""
 | 
					
						
							|  |  |  |             import {interpreters.__name__} as interpreters | 
					
						
							|  |  |  |             interp = interpreters.get_current() | 
					
						
							|  |  |  |             interp.close() | 
					
						
							|  |  |  |             """)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('running __main__ (from self)'): | 
					
						
							|  |  |  |             with self.interpreter_from_capi() as interpid: | 
					
						
							|  |  |  |                 with self.assertRaisesRegex(ExecutionFailed, | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                                             'InterpreterError.*unrecognized'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                     self.run_from_capi(interpid, script, main=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('running, but not __main__ (from self)'): | 
					
						
							|  |  |  |             with self.assertRaisesRegex(ExecutionFailed, | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                                         'InterpreterError.*unrecognized'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 self.run_temp_from_capi(script) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('running __main__ (from other)'): | 
					
						
							|  |  |  |             with self.interpreter_obj_from_capi() as (interp, interpid): | 
					
						
							|  |  |  |                 with self.running_from_capi(interpid, main=True): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                     with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                         interp.close() | 
					
						
							|  |  |  |                     # Make sure it wssn't closed. | 
					
						
							|  |  |  |                     self.assertTrue( | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                         self.interp_exists(interpid)) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         # The rest would be skipped until we deal with running threads when | 
					
						
							|  |  |  |         # interp.close() is called.  However, the "whence" restrictions | 
					
						
							|  |  |  |         # trigger first. | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('running, but not __main__ (from other)'): | 
					
						
							|  |  |  |             with self.interpreter_obj_from_capi() as (interp, interpid): | 
					
						
							|  |  |  |                 with self.running_from_capi(interpid, main=False): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                     with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                         interp.close() | 
					
						
							|  |  |  |                     # Make sure it wssn't closed. | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                     self.assertTrue( | 
					
						
							|  |  |  |                         self.interp_exists(interpid)) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('not running (from other)'): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             with self.interpreter_obj_from_capi() as (interp, interpid): | 
					
						
							|  |  |  |                 with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                     interp.close() | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 self.assertTrue( | 
					
						
							|  |  |  |                     self.interp_exists(interpid)) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 11:06:06 -07:00
										 |  |  | class TestInterpreterPrepareMain(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_empty(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             interp.prepare_main() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict(self): | 
					
						
							|  |  |  |         values = {'spam': 42, 'eggs': 'ham'} | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         interp.prepare_main(values) | 
					
						
							|  |  |  |         out = _run_output(interp, dedent("""
 | 
					
						
							|  |  |  |             print(spam, eggs) | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         self.assertEqual(out.strip(), '42 ham') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_tuple(self): | 
					
						
							|  |  |  |         values = {'spam': 42, 'eggs': 'ham'} | 
					
						
							|  |  |  |         values = tuple(values.items()) | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         interp.prepare_main(values) | 
					
						
							|  |  |  |         out = _run_output(interp, dedent("""
 | 
					
						
							|  |  |  |             print(spam, eggs) | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         self.assertEqual(out.strip(), '42 ham') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_kwargs(self): | 
					
						
							|  |  |  |         values = {'spam': 42, 'eggs': 'ham'} | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         interp.prepare_main(**values) | 
					
						
							|  |  |  |         out = _run_output(interp, dedent("""
 | 
					
						
							|  |  |  |             print(spam, eggs) | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         self.assertEqual(out.strip(), '42 ham') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_and_kwargs(self): | 
					
						
							|  |  |  |         values = {'spam': 42, 'eggs': 'ham'} | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         interp.prepare_main(values, foo='bar') | 
					
						
							|  |  |  |         out = _run_output(interp, dedent("""
 | 
					
						
							|  |  |  |             print(spam, eggs, foo) | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         self.assertEqual(out.strip(), '42 ham bar') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_not_shareable(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         # XXX TypeError? | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             interp.prepare_main(spam={'spam': 'eggs', 'foo': 'bar'}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Make sure neither was actually bound. | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.assertRaises(ExecutionFailed): | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.exec('print(foo)') | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.assertRaises(ExecutionFailed): | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.exec('print(spam)') | 
					
						
							| 
									
										
										
										
											2023-12-12 11:06:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     def test_running(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         interp.prepare_main({'spam': True}) | 
					
						
							|  |  |  |         with self.running(interp): | 
					
						
							|  |  |  |             with self.assertRaisesRegex(InterpreterError, 'running'): | 
					
						
							|  |  |  |                 interp.prepare_main({'spam': False}) | 
					
						
							|  |  |  |         interp.exec('assert spam is True') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @requires_test_modules | 
					
						
							|  |  |  |     def test_created_with_capi(self): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         with self.interpreter_obj_from_capi() as (interp, interpid): | 
					
						
							|  |  |  |             with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							|  |  |  |                 interp.prepare_main({'spam': True}) | 
					
						
							|  |  |  |             with self.assertRaisesRegex(ExecutionFailed, 'NameError'): | 
					
						
							|  |  |  |                 self.run_from_capi(interpid, 'assert spam is True') | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 11:06:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  | class TestInterpreterExec(TestBase): | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_success(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         script, results = _captured_script('print("it worked!", end="")') | 
					
						
							|  |  |  |         with results: | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.exec(script) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         results = results.final() | 
					
						
							|  |  |  |         results.raise_if_failed() | 
					
						
							|  |  |  |         out = results.stdout | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(out, 'it worked!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_failure(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.assertRaises(ExecutionFailed): | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.exec('raise Exception') | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-24 21:25:22 +01:00
										 |  |  |     @force_not_colorized | 
					
						
							| 
									
										
										
										
											2023-12-12 17:00:54 -07:00
										 |  |  |     def test_display_preserved_exception(self): | 
					
						
							|  |  |  |         tempdir = self.temp_dir() | 
					
						
							|  |  |  |         modfile = self.make_module('spam', tempdir, text="""
 | 
					
						
							|  |  |  |             def ham(): | 
					
						
							|  |  |  |                 raise RuntimeError('uh-oh!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def eggs(): | 
					
						
							|  |  |  |                 ham() | 
					
						
							|  |  |  |             """)
 | 
					
						
							|  |  |  |         scriptfile = self.make_script('script.py', tempdir, text="""
 | 
					
						
							|  |  |  |             from test.support import interpreters | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def script(): | 
					
						
							|  |  |  |                 import spam | 
					
						
							|  |  |  |                 spam.eggs() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             interp = interpreters.create() | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.exec(script) | 
					
						
							| 
									
										
										
										
											2023-12-12 17:00:54 -07:00
										 |  |  |             """)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         stdout, stderr = self.assert_python_failure(scriptfile) | 
					
						
							|  |  |  |         self.maxDiff = None | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interpmod_line, = (l for l in stderr.splitlines() if ' exec' in l) | 
					
						
							|  |  |  |         #      File "{interpreters.__file__}", line 179, in exec | 
					
						
							| 
									
										
										
										
											2023-12-12 17:00:54 -07:00
										 |  |  |         self.assertEqual(stderr, dedent(f"""\
 | 
					
						
							|  |  |  |             Traceback (most recent call last): | 
					
						
							|  |  |  |               File "{scriptfile}", line 9, in <module> | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |                 interp.exec(script) | 
					
						
							|  |  |  |                 ~~~~~~~~~~~^^^^^^^^ | 
					
						
							| 
									
										
										
										
											2023-12-12 17:00:54 -07:00
										 |  |  |               {interpmod_line.strip()} | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |                 raise ExecutionFailed(excinfo) | 
					
						
							|  |  |  |             test.support.interpreters.ExecutionFailed: RuntimeError: uh-oh! | 
					
						
							| 
									
										
										
										
											2023-12-12 17:00:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             Uncaught in the interpreter: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Traceback (most recent call last): | 
					
						
							|  |  |  |               File "{scriptfile}", line 6, in script | 
					
						
							|  |  |  |                 spam.eggs() | 
					
						
							|  |  |  |                 ~~~~~~~~~^^ | 
					
						
							|  |  |  |               File "{modfile}", line 6, in eggs | 
					
						
							|  |  |  |                 ham() | 
					
						
							|  |  |  |                 ~~~^^ | 
					
						
							|  |  |  |               File "{modfile}", line 3, in ham | 
					
						
							|  |  |  |                 raise RuntimeError('uh-oh!') | 
					
						
							|  |  |  |             RuntimeError: uh-oh! | 
					
						
							|  |  |  |             """))
 | 
					
						
							|  |  |  |         self.assertEqual(stdout, '') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |     def test_in_thread(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         script, results = _captured_script('print("it worked!", end="")') | 
					
						
							|  |  |  |         with results: | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             def f(): | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |                 interp.exec(script) | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             t = threading.Thread(target=f) | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |             t.join() | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         results = results.final() | 
					
						
							|  |  |  |         results.raise_if_failed() | 
					
						
							|  |  |  |         out = results.stdout | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(out, 'it worked!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @support.requires_fork() | 
					
						
							|  |  |  |     def test_fork(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         import tempfile | 
					
						
							|  |  |  |         with tempfile.NamedTemporaryFile('w+', encoding='utf-8') as file: | 
					
						
							|  |  |  |             file.write('') | 
					
						
							|  |  |  |             file.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             expected = 'spam spam spam spam spam' | 
					
						
							|  |  |  |             script = dedent(f"""
 | 
					
						
							|  |  |  |                 import os | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     os.fork() | 
					
						
							|  |  |  |                 except RuntimeError: | 
					
						
							|  |  |  |                     with open('{file.name}', 'w', encoding='utf-8') as out: | 
					
						
							|  |  |  |                         out.write('{expected}') | 
					
						
							|  |  |  |                 """)
 | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.exec(script) | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             file.seek(0) | 
					
						
							|  |  |  |             content = file.read() | 
					
						
							|  |  |  |             self.assertEqual(content, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     # XXX Is this still true? | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |     @unittest.skip('Fails on FreeBSD') | 
					
						
							|  |  |  |     def test_already_running(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         with _running(interp): | 
					
						
							|  |  |  |             with self.assertRaises(RuntimeError): | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |                 interp.exec('print("spam")') | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_bad_script(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.exec(10) | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_bytes_for_script(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.exec(b'print("spam")') | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_with_background_threads_still_running(self): | 
					
						
							|  |  |  |         r_interp, w_interp = self.pipe() | 
					
						
							|  |  |  |         r_thread, w_thread = self.pipe() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         RAN = b'R' | 
					
						
							|  |  |  |         DONE = b'D' | 
					
						
							|  |  |  |         FINISHED = b'F' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interp.exec(f"""if True:
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             import os | 
					
						
							|  |  |  |             import threading | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def task(): | 
					
						
							|  |  |  |                 v = os.read({r_thread}, 1) | 
					
						
							|  |  |  |                 assert v == {DONE!r} | 
					
						
							|  |  |  |                 os.write({w_interp}, {FINISHED!r}) | 
					
						
							|  |  |  |             t = threading.Thread(target=task) | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |             os.write({w_interp}, {RAN!r}) | 
					
						
							|  |  |  |             """)
 | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interp.exec(f"""if True:
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             os.write({w_interp}, {RAN!r}) | 
					
						
							|  |  |  |             """)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         os.write(w_thread, DONE) | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         interp.exec('t.join()') | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |         self.assertEqual(os.read(r_interp, 1), RAN) | 
					
						
							|  |  |  |         self.assertEqual(os.read(r_interp, 1), RAN) | 
					
						
							|  |  |  |         self.assertEqual(os.read(r_interp, 1), FINISHED) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     def test_created_with_capi(self): | 
					
						
							|  |  |  |         with self.interpreter_obj_from_capi() as (interp, _): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 interp.exec('raise Exception("it worked!")') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-24 10:18:24 -06:00
										 |  |  |     # test__interpreters covers the remaining | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |     # Interpreter.exec() behavior. | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  | def call_func_noop(): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def call_func_return_shareable(): | 
					
						
							|  |  |  |     return (1, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def call_func_return_not_shareable(): | 
					
						
							|  |  |  |     return [1, 2, 3] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def call_func_failure(): | 
					
						
							|  |  |  |     raise Exception('spam!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def call_func_ident(value): | 
					
						
							|  |  |  |     return value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_call_func_closure(value): | 
					
						
							|  |  |  |     def call_func_closure(): | 
					
						
							|  |  |  |         return value | 
					
						
							|  |  |  |     return call_func_closure | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Spam: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def noop(): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_values(cls, *values): | 
					
						
							|  |  |  |         return cls(values) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value): | 
					
						
							|  |  |  |         self.value = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __call__(self, *args, **kwargs): | 
					
						
							|  |  |  |         return (self.value, args, kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         if not isinstance(other, Spam): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         return self.value == other.value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def run(self, *args, **kwargs): | 
					
						
							|  |  |  |         return (self.value, args, kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def call_func_complex(op, /, value=None, *args, exc=None, **kwargs): | 
					
						
							|  |  |  |     if exc is not None: | 
					
						
							|  |  |  |         raise exc | 
					
						
							|  |  |  |     if op == '': | 
					
						
							|  |  |  |         raise ValueError('missing op') | 
					
						
							|  |  |  |     elif op == 'ident': | 
					
						
							|  |  |  |         if args or kwargs: | 
					
						
							|  |  |  |             raise Exception((args, kwargs)) | 
					
						
							|  |  |  |         return value | 
					
						
							|  |  |  |     elif op == 'full-ident': | 
					
						
							|  |  |  |         return (value, args, kwargs) | 
					
						
							|  |  |  |     elif op == 'globals': | 
					
						
							|  |  |  |         if value is not None or args or kwargs: | 
					
						
							|  |  |  |             raise Exception((value, args, kwargs)) | 
					
						
							|  |  |  |         return __name__ | 
					
						
							|  |  |  |     elif op == 'interpid': | 
					
						
							|  |  |  |         if value is not None or args or kwargs: | 
					
						
							|  |  |  |             raise Exception((value, args, kwargs)) | 
					
						
							|  |  |  |         return interpreters.get_current().id | 
					
						
							|  |  |  |     elif op == 'closure': | 
					
						
							|  |  |  |         if args or kwargs: | 
					
						
							|  |  |  |             raise Exception((args, kwargs)) | 
					
						
							|  |  |  |         return get_call_func_closure(value) | 
					
						
							|  |  |  |     elif op == 'custom': | 
					
						
							|  |  |  |         if args or kwargs: | 
					
						
							|  |  |  |             raise Exception((args, kwargs)) | 
					
						
							|  |  |  |         return Spam(value) | 
					
						
							|  |  |  |     elif op == 'custom-inner': | 
					
						
							|  |  |  |         if args or kwargs: | 
					
						
							|  |  |  |             raise Exception((args, kwargs)) | 
					
						
							|  |  |  |         class Eggs(Spam): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         return Eggs(value) | 
					
						
							|  |  |  |     elif not isinstance(op, str): | 
					
						
							|  |  |  |         raise TypeError(op) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         raise NotImplementedError(op) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestInterpreterCall(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # signature | 
					
						
							|  |  |  |     #  - blank | 
					
						
							|  |  |  |     #  - args | 
					
						
							|  |  |  |     #  - kwargs | 
					
						
							|  |  |  |     #  - args, kwargs | 
					
						
							|  |  |  |     # return | 
					
						
							|  |  |  |     #  - nothing (None) | 
					
						
							|  |  |  |     #  - simple | 
					
						
							|  |  |  |     #  - closure | 
					
						
							|  |  |  |     #  - custom | 
					
						
							|  |  |  |     # ops: | 
					
						
							|  |  |  |     #  - do nothing | 
					
						
							|  |  |  |     #  - fail | 
					
						
							|  |  |  |     #  - echo | 
					
						
							|  |  |  |     #  - do complex, relative to interpreter | 
					
						
							|  |  |  |     # scope | 
					
						
							|  |  |  |     #  - global func | 
					
						
							|  |  |  |     #  - local closure | 
					
						
							|  |  |  |     #  - returned closure | 
					
						
							|  |  |  |     #  - callable type instance | 
					
						
							|  |  |  |     #  - type | 
					
						
							|  |  |  |     #  - classmethod | 
					
						
							|  |  |  |     #  - staticmethod | 
					
						
							|  |  |  |     #  - instance method | 
					
						
							|  |  |  |     # exception | 
					
						
							|  |  |  |     #  - builtin | 
					
						
							|  |  |  |     #  - custom | 
					
						
							|  |  |  |     #  - preserves info (e.g. SyntaxError) | 
					
						
							|  |  |  |     #  - matching error display | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_call(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for i, (callable, args, kwargs) in enumerate([ | 
					
						
							|  |  |  |             (call_func_noop, (), {}), | 
					
						
							|  |  |  |             (call_func_return_shareable, (), {}), | 
					
						
							|  |  |  |             (call_func_return_not_shareable, (), {}), | 
					
						
							|  |  |  |             (Spam.noop, (), {}), | 
					
						
							|  |  |  |         ]): | 
					
						
							|  |  |  |             with self.subTest(f'success case #{i+1}'): | 
					
						
							|  |  |  |                 res = interp.call(callable) | 
					
						
							|  |  |  |                 self.assertIs(res, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for i, (callable, args, kwargs) in enumerate([ | 
					
						
							|  |  |  |             (call_func_ident, ('spamspamspam',), {}), | 
					
						
							|  |  |  |             (get_call_func_closure, (42,), {}), | 
					
						
							|  |  |  |             (get_call_func_closure(42), (), {}), | 
					
						
							|  |  |  |             (Spam.from_values, (), {}), | 
					
						
							|  |  |  |             (Spam.from_values, (1, 2, 3), {}), | 
					
						
							|  |  |  |             (Spam, ('???'), {}), | 
					
						
							|  |  |  |             (Spam(101), (), {}), | 
					
						
							|  |  |  |             (Spam(10101).run, (), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('ident', 'spam'), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('full-ident', 'spam'), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('full-ident', 'spam', 'ham'), {'eggs': '!!!'}), | 
					
						
							|  |  |  |             (call_func_complex, ('globals',), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('interpid',), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('closure',), {'value': '~~~'}), | 
					
						
							|  |  |  |             (call_func_complex, ('custom', 'spam!'), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('custom-inner', 'eggs!'), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('???',), {'exc': ValueError('spam')}), | 
					
						
							|  |  |  |         ]): | 
					
						
							|  |  |  |             with self.subTest(f'invalid case #{i+1}'): | 
					
						
							|  |  |  |                 with self.assertRaises(Exception): | 
					
						
							|  |  |  |                     if args or kwargs: | 
					
						
							|  |  |  |                         raise Exception((args, kwargs)) | 
					
						
							|  |  |  |                     interp.call(callable) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.assertRaises(ExecutionFailed): | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |             interp.call(call_func_failure) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_call_in_thread(self): | 
					
						
							|  |  |  |         interp = interpreters.create() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for i, (callable, args, kwargs) in enumerate([ | 
					
						
							|  |  |  |             (call_func_noop, (), {}), | 
					
						
							|  |  |  |             (call_func_return_shareable, (), {}), | 
					
						
							|  |  |  |             (call_func_return_not_shareable, (), {}), | 
					
						
							|  |  |  |             (Spam.noop, (), {}), | 
					
						
							|  |  |  |         ]): | 
					
						
							|  |  |  |             with self.subTest(f'success case #{i+1}'): | 
					
						
							|  |  |  |                 with self.captured_thread_exception() as ctx: | 
					
						
							|  |  |  |                     t = interp.call_in_thread(callable) | 
					
						
							|  |  |  |                     t.join() | 
					
						
							|  |  |  |                 self.assertIsNone(ctx.caught) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for i, (callable, args, kwargs) in enumerate([ | 
					
						
							|  |  |  |             (call_func_ident, ('spamspamspam',), {}), | 
					
						
							|  |  |  |             (get_call_func_closure, (42,), {}), | 
					
						
							|  |  |  |             (get_call_func_closure(42), (), {}), | 
					
						
							|  |  |  |             (Spam.from_values, (), {}), | 
					
						
							|  |  |  |             (Spam.from_values, (1, 2, 3), {}), | 
					
						
							|  |  |  |             (Spam, ('???'), {}), | 
					
						
							|  |  |  |             (Spam(101), (), {}), | 
					
						
							|  |  |  |             (Spam(10101).run, (), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('ident', 'spam'), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('full-ident', 'spam'), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('full-ident', 'spam', 'ham'), {'eggs': '!!!'}), | 
					
						
							|  |  |  |             (call_func_complex, ('globals',), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('interpid',), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('closure',), {'value': '~~~'}), | 
					
						
							|  |  |  |             (call_func_complex, ('custom', 'spam!'), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('custom-inner', 'eggs!'), {}), | 
					
						
							|  |  |  |             (call_func_complex, ('???',), {'exc': ValueError('spam')}), | 
					
						
							|  |  |  |         ]): | 
					
						
							|  |  |  |             with self.subTest(f'invalid case #{i+1}'): | 
					
						
							|  |  |  |                 if args or kwargs: | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 with self.captured_thread_exception() as ctx: | 
					
						
							|  |  |  |                     t = interp.call_in_thread(callable) | 
					
						
							|  |  |  |                     t.join() | 
					
						
							|  |  |  |                 self.assertIsNotNone(ctx.caught) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.captured_thread_exception() as ctx: | 
					
						
							|  |  |  |             t = interp.call_in_thread(call_func_failure) | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |             t.join() | 
					
						
							| 
									
										
										
										
											2024-02-28 16:08:08 -07:00
										 |  |  |         self.assertIsNotNone(ctx.caught) | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestIsShareable(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_default_shareables(self): | 
					
						
							|  |  |  |         shareables = [ | 
					
						
							|  |  |  |                 # singletons | 
					
						
							|  |  |  |                 None, | 
					
						
							|  |  |  |                 # builtin objects | 
					
						
							|  |  |  |                 b'spam', | 
					
						
							|  |  |  |                 'spam', | 
					
						
							|  |  |  |                 10, | 
					
						
							|  |  |  |                 -10, | 
					
						
							|  |  |  |                 True, | 
					
						
							|  |  |  |                 False, | 
					
						
							|  |  |  |                 100.0, | 
					
						
							|  |  |  |                 (), | 
					
						
							|  |  |  |                 (1, ('spam', 'eggs'), True), | 
					
						
							|  |  |  |                 ] | 
					
						
							|  |  |  |         for obj in shareables: | 
					
						
							|  |  |  |             with self.subTest(obj): | 
					
						
							|  |  |  |                 shareable = interpreters.is_shareable(obj) | 
					
						
							|  |  |  |                 self.assertTrue(shareable) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_not_shareable(self): | 
					
						
							|  |  |  |         class Cheese: | 
					
						
							|  |  |  |             def __init__(self, name): | 
					
						
							|  |  |  |                 self.name = name | 
					
						
							|  |  |  |             def __str__(self): | 
					
						
							|  |  |  |                 return self.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class SubBytes(bytes): | 
					
						
							|  |  |  |             """A subclass of a shareable type.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         not_shareables = [ | 
					
						
							|  |  |  |                 # singletons | 
					
						
							|  |  |  |                 NotImplemented, | 
					
						
							|  |  |  |                 ..., | 
					
						
							|  |  |  |                 # builtin types and objects | 
					
						
							|  |  |  |                 type, | 
					
						
							|  |  |  |                 object, | 
					
						
							|  |  |  |                 object(), | 
					
						
							|  |  |  |                 Exception(), | 
					
						
							|  |  |  |                 # user-defined types and objects | 
					
						
							|  |  |  |                 Cheese, | 
					
						
							|  |  |  |                 Cheese('Wensleydale'), | 
					
						
							|  |  |  |                 SubBytes(b'spam'), | 
					
						
							|  |  |  |                 ] | 
					
						
							|  |  |  |         for obj in not_shareables: | 
					
						
							|  |  |  |             with self.subTest(repr(obj)): | 
					
						
							|  |  |  |                 self.assertFalse( | 
					
						
							|  |  |  |                     interpreters.is_shareable(obj)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  | class LowLevelTests(TestBase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # The behaviors in the low-level module are important in as much | 
					
						
							|  |  |  |     # as they are exercised by the high-level module.  Therefore the | 
					
						
							|  |  |  |     # most important testing happens in the high-level tests. | 
					
						
							|  |  |  |     # These low-level tests cover corner cases that are not | 
					
						
							|  |  |  |     # encountered by the high-level module, thus they | 
					
						
							|  |  |  |     # mostly shouldn't matter as much. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_new_config(self): | 
					
						
							|  |  |  |         # This test overlaps with | 
					
						
							|  |  |  |         # test.test_capi.test_misc.InterpreterConfigTests. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default = _interpreters.new_config('isolated') | 
					
						
							|  |  |  |         with self.subTest('no arg'): | 
					
						
							|  |  |  |             config = _interpreters.new_config() | 
					
						
							|  |  |  |             self.assert_ns_equal(config, default) | 
					
						
							|  |  |  |             self.assertIsNot(config, default) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('default'): | 
					
						
							|  |  |  |             config1 = _interpreters.new_config('default') | 
					
						
							|  |  |  |             self.assert_ns_equal(config1, default) | 
					
						
							|  |  |  |             self.assertIsNot(config1, default) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             config2 = _interpreters.new_config('default') | 
					
						
							|  |  |  |             self.assert_ns_equal(config2, config1) | 
					
						
							|  |  |  |             self.assertIsNot(config2, config1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for arg in ['', 'default']: | 
					
						
							|  |  |  |             with self.subTest(f'default ({arg!r})'): | 
					
						
							|  |  |  |                 config = _interpreters.new_config(arg) | 
					
						
							|  |  |  |                 self.assert_ns_equal(config, default) | 
					
						
							|  |  |  |                 self.assertIsNot(config, default) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         supported = { | 
					
						
							|  |  |  |             'isolated': types.SimpleNamespace( | 
					
						
							|  |  |  |                 use_main_obmalloc=False, | 
					
						
							|  |  |  |                 allow_fork=False, | 
					
						
							|  |  |  |                 allow_exec=False, | 
					
						
							|  |  |  |                 allow_threads=True, | 
					
						
							|  |  |  |                 allow_daemon_threads=False, | 
					
						
							|  |  |  |                 check_multi_interp_extensions=True, | 
					
						
							|  |  |  |                 gil='own', | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             'legacy': types.SimpleNamespace( | 
					
						
							|  |  |  |                 use_main_obmalloc=True, | 
					
						
							|  |  |  |                 allow_fork=True, | 
					
						
							|  |  |  |                 allow_exec=True, | 
					
						
							|  |  |  |                 allow_threads=True, | 
					
						
							|  |  |  |                 allow_daemon_threads=True, | 
					
						
							| 
									
										
										
										
											2024-04-11 15:00:54 -04:00
										 |  |  |                 check_multi_interp_extensions=bool(Py_GIL_DISABLED), | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  |                 gil='shared', | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             'empty': types.SimpleNamespace( | 
					
						
							|  |  |  |                 use_main_obmalloc=False, | 
					
						
							|  |  |  |                 allow_fork=False, | 
					
						
							|  |  |  |                 allow_exec=False, | 
					
						
							|  |  |  |                 allow_threads=False, | 
					
						
							|  |  |  |                 allow_daemon_threads=False, | 
					
						
							|  |  |  |                 check_multi_interp_extensions=False, | 
					
						
							|  |  |  |                 gil='default', | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         gil_supported = ['default', 'shared', 'own'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for name, vanilla in supported.items(): | 
					
						
							|  |  |  |             with self.subTest(f'supported ({name})'): | 
					
						
							|  |  |  |                 expected = vanilla | 
					
						
							|  |  |  |                 config1 = _interpreters.new_config(name) | 
					
						
							|  |  |  |                 self.assert_ns_equal(config1, expected) | 
					
						
							|  |  |  |                 self.assertIsNot(config1, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 config2 = _interpreters.new_config(name) | 
					
						
							|  |  |  |                 self.assert_ns_equal(config2, config1) | 
					
						
							|  |  |  |                 self.assertIsNot(config2, config1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             with self.subTest(f'noop override ({name})'): | 
					
						
							|  |  |  |                 expected = vanilla | 
					
						
							|  |  |  |                 overrides = vars(vanilla) | 
					
						
							|  |  |  |                 config = _interpreters.new_config(name, **overrides) | 
					
						
							|  |  |  |                 self.assert_ns_equal(config, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             with self.subTest(f'override all ({name})'): | 
					
						
							|  |  |  |                 overrides = {k: not v for k, v in vars(vanilla).items()} | 
					
						
							|  |  |  |                 for gil in gil_supported: | 
					
						
							|  |  |  |                     if vanilla.gil == gil: | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     overrides['gil'] = gil | 
					
						
							|  |  |  |                     expected = types.SimpleNamespace(**overrides) | 
					
						
							|  |  |  |                     config = _interpreters.new_config(name, **overrides) | 
					
						
							|  |  |  |                     self.assert_ns_equal(config, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Override individual fields. | 
					
						
							|  |  |  |             for field, old in vars(vanilla).items(): | 
					
						
							|  |  |  |                 if field == 'gil': | 
					
						
							|  |  |  |                     values = [v for v in gil_supported if v != old] | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     values = [not old] | 
					
						
							|  |  |  |                 for val in values: | 
					
						
							|  |  |  |                     with self.subTest(f'{name}.{field} ({old!r} -> {val!r})'): | 
					
						
							|  |  |  |                         overrides = {field: val} | 
					
						
							|  |  |  |                         expected = types.SimpleNamespace( | 
					
						
							|  |  |  |                             **dict(vars(vanilla), **overrides), | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  |                         config = _interpreters.new_config(name, **overrides) | 
					
						
							|  |  |  |                         self.assert_ns_equal(config, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('extra override'): | 
					
						
							|  |  |  |             with self.assertRaises(ValueError): | 
					
						
							|  |  |  |                 _interpreters.new_config(spam=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Bad values for bool fields. | 
					
						
							|  |  |  |         for field, value in vars(supported['empty']).items(): | 
					
						
							|  |  |  |             if field == 'gil': | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             assert isinstance(value, bool) | 
					
						
							|  |  |  |             for value in [1, '', 'spam', 1.0, None, object()]: | 
					
						
							|  |  |  |                 with self.subTest(f'bad override ({field}={value!r})'): | 
					
						
							|  |  |  |                     with self.assertRaises(TypeError): | 
					
						
							|  |  |  |                         _interpreters.new_config(**{field: value}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Bad values for .gil. | 
					
						
							|  |  |  |         for value in [True, 1, 1.0, None, object()]: | 
					
						
							|  |  |  |             with self.subTest(f'bad override (gil={value!r})'): | 
					
						
							|  |  |  |                 with self.assertRaises(TypeError): | 
					
						
							|  |  |  |                     _interpreters.new_config(gil=value) | 
					
						
							|  |  |  |         for value in ['', 'spam']: | 
					
						
							|  |  |  |             with self.subTest(f'bad override (gil={value!r})'): | 
					
						
							|  |  |  |                 with self.assertRaises(ValueError): | 
					
						
							|  |  |  |                     _interpreters.new_config(gil=value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     def test_get_main(self): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         interpid, whence = _interpreters.get_main() | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         self.assertEqual(interpid, 0) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         self.assertEqual(whence, _interpreters.WHENCE_RUNTIME) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _interpreters.whence(interpid), | 
					
						
							|  |  |  |             _interpreters.WHENCE_RUNTIME) | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     def test_get_current(self): | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  |         with self.subTest('main'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             main, *_ = _interpreters.get_main() | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             interpid, whence = _interpreters.get_current() | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             self.assertEqual(interpid, main) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             self.assertEqual(whence, _interpreters.WHENCE_RUNTIME) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         script = f"""
 | 
					
						
							| 
									
										
										
										
											2024-04-24 10:18:24 -06:00
										 |  |  |             import _interpreters | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             interpid, whence = _interpreters.get_current() | 
					
						
							|  |  |  |             print((interpid, whence)) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             """
 | 
					
						
							|  |  |  |         def parse_stdout(text): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             interpid, whence = eval(text) | 
					
						
							|  |  |  |             return interpid, whence | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from _interpreters'): | 
					
						
							|  |  |  |             orig = _interpreters.create() | 
					
						
							|  |  |  |             text = self.run_and_capture(orig, script) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             interpid, whence = parse_stdout(text) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             self.assertEqual(interpid, orig) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             self.assertEqual(whence, _interpreters.WHENCE_STDLIB) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API'): | 
					
						
							|  |  |  |             last = 0 | 
					
						
							|  |  |  |             for id, *_ in _interpreters.list_all(): | 
					
						
							|  |  |  |                 last = max(last, id) | 
					
						
							|  |  |  |             expected = last + 1 | 
					
						
							|  |  |  |             text = self.run_temp_from_capi(script) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             interpid, whence = parse_stdout(text) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             self.assertEqual(interpid, expected) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             self.assertEqual(whence, _interpreters.WHENCE_CAPI) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_list_all(self): | 
					
						
							|  |  |  |         mainid, *_ = _interpreters.get_main() | 
					
						
							|  |  |  |         interpid1 = _interpreters.create() | 
					
						
							|  |  |  |         interpid2 = _interpreters.create() | 
					
						
							|  |  |  |         interpid3 = _interpreters.create() | 
					
						
							|  |  |  |         expected = [ | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             (mainid, _interpreters.WHENCE_RUNTIME), | 
					
						
							|  |  |  |             (interpid1, _interpreters.WHENCE_STDLIB), | 
					
						
							|  |  |  |             (interpid2, _interpreters.WHENCE_STDLIB), | 
					
						
							|  |  |  |             (interpid3, _interpreters.WHENCE_STDLIB), | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         ] | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.subTest('main'): | 
					
						
							|  |  |  |             res = _interpreters.list_all() | 
					
						
							|  |  |  |             self.assertEqual(res, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         with self.subTest('via interp from _interpreters'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             text = self.run_and_capture(interpid2, f"""
 | 
					
						
							| 
									
										
										
										
											2024-04-24 10:18:24 -06:00
										 |  |  |                 import _interpreters | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 print( | 
					
						
							|  |  |  |                     _interpreters.list_all()) | 
					
						
							|  |  |  |                 """)
 | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             res = eval(text) | 
					
						
							|  |  |  |             self.assertEqual(res, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         with self.subTest('via interp from C-API'): | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             interpid4 = interpid3 + 1 | 
					
						
							|  |  |  |             interpid5 = interpid4 + 1 | 
					
						
							|  |  |  |             expected2 = expected + [ | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 (interpid4, _interpreters.WHENCE_CAPI), | 
					
						
							|  |  |  |                 (interpid5, _interpreters.WHENCE_STDLIB), | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             ] | 
					
						
							|  |  |  |             expected3 = expected + [ | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 (interpid5, _interpreters.WHENCE_STDLIB), | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             ] | 
					
						
							|  |  |  |             text = self.run_temp_from_capi(f"""
 | 
					
						
							| 
									
										
										
										
											2024-04-24 10:18:24 -06:00
										 |  |  |                 import _interpreters | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 _interpreters.create() | 
					
						
							|  |  |  |                 print( | 
					
						
							|  |  |  |                     _interpreters.list_all()) | 
					
						
							|  |  |  |                 """)
 | 
					
						
							|  |  |  |             res2 = eval(text) | 
					
						
							|  |  |  |             res3 = _interpreters.list_all() | 
					
						
							|  |  |  |             self.assertEqual(res2, expected2) | 
					
						
							|  |  |  |             self.assertEqual(res3, expected3) | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_create(self): | 
					
						
							|  |  |  |         isolated = _interpreters.new_config('isolated') | 
					
						
							|  |  |  |         legacy = _interpreters.new_config('legacy') | 
					
						
							|  |  |  |         default = isolated | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.subTest('no args'): | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             config = _interpreters.get_config(interpid) | 
					
						
							|  |  |  |             self.assert_ns_equal(config, default) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.subTest('config: None'): | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  |             interpid = _interpreters.create(None) | 
					
						
							|  |  |  |             config = _interpreters.get_config(interpid) | 
					
						
							|  |  |  |             self.assert_ns_equal(config, default) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.subTest('config: \'empty\''): | 
					
						
							|  |  |  |             with self.assertRaises(InterpreterError): | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  |                 # The "empty" config isn't viable on its own. | 
					
						
							|  |  |  |                 _interpreters.create('empty') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for arg, expected in { | 
					
						
							|  |  |  |             '': default, | 
					
						
							|  |  |  |             'default': default, | 
					
						
							|  |  |  |             'isolated': isolated, | 
					
						
							|  |  |  |             'legacy': legacy, | 
					
						
							|  |  |  |         }.items(): | 
					
						
							|  |  |  |             with self.subTest(f'str arg: {arg!r}'): | 
					
						
							|  |  |  |                 interpid = _interpreters.create(arg) | 
					
						
							|  |  |  |                 config = _interpreters.get_config(interpid) | 
					
						
							|  |  |  |                 self.assert_ns_equal(config, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('custom'): | 
					
						
							|  |  |  |             orig = _interpreters.new_config('empty') | 
					
						
							|  |  |  |             orig.use_main_obmalloc = True | 
					
						
							| 
									
										
										
										
											2024-04-11 15:00:54 -04:00
										 |  |  |             orig.check_multi_interp_extensions = bool(Py_GIL_DISABLED) | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  |             orig.gil = 'shared' | 
					
						
							|  |  |  |             interpid = _interpreters.create(orig) | 
					
						
							|  |  |  |             config = _interpreters.get_config(interpid) | 
					
						
							|  |  |  |             self.assert_ns_equal(config, orig) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('missing fields'): | 
					
						
							|  |  |  |             orig = _interpreters.new_config() | 
					
						
							|  |  |  |             del orig.gil | 
					
						
							|  |  |  |             with self.assertRaises(ValueError): | 
					
						
							|  |  |  |                 _interpreters.create(orig) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('extra fields'): | 
					
						
							|  |  |  |             orig = _interpreters.new_config() | 
					
						
							|  |  |  |             orig.spam = True | 
					
						
							|  |  |  |             with self.assertRaises(ValueError): | 
					
						
							|  |  |  |                 _interpreters.create(orig) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         with self.subTest('whence'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             self.assertEqual( | 
					
						
							|  |  |  |                 _interpreters.whence(interpid), | 
					
						
							|  |  |  |                 _interpreters.WHENCE_STDLIB) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     @requires_test_modules | 
					
						
							|  |  |  |     def test_destroy(self): | 
					
						
							|  |  |  |         with self.subTest('from _interpreters'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             before = [id for id, *_ in _interpreters.list_all()] | 
					
						
							|  |  |  |             _interpreters.destroy(interpid) | 
					
						
							|  |  |  |             after = [id for id, *_ in _interpreters.list_all()] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.assertIn(interpid, before) | 
					
						
							|  |  |  |             self.assertNotIn(interpid, after) | 
					
						
							|  |  |  |             self.assertFalse( | 
					
						
							|  |  |  |                 self.interp_exists(interpid)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('main'): | 
					
						
							|  |  |  |             interpid, *_ = _interpreters.get_main() | 
					
						
							|  |  |  |             with self.assertRaises(InterpreterError): | 
					
						
							|  |  |  |                 # It is the current interpreter. | 
					
						
							|  |  |  |                 _interpreters.destroy(interpid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API'): | 
					
						
							|  |  |  |             interpid = _testinternalcapi.create_interpreter() | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							|  |  |  |                 _interpreters.destroy(interpid, restrict=True) | 
					
						
							|  |  |  |             self.assertTrue( | 
					
						
							|  |  |  |                 self.interp_exists(interpid)) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             _interpreters.destroy(interpid) | 
					
						
							|  |  |  |             self.assertFalse( | 
					
						
							|  |  |  |                 self.interp_exists(interpid)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_get_config(self): | 
					
						
							|  |  |  |         # This test overlaps with | 
					
						
							|  |  |  |         # test.test_capi.test_misc.InterpreterConfigTests. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('main'): | 
					
						
							|  |  |  |             expected = _interpreters.new_config('legacy') | 
					
						
							|  |  |  |             expected.gil = 'own' | 
					
						
							| 
									
										
										
										
											2024-04-11 15:00:54 -04:00
										 |  |  |             if Py_GIL_DISABLED: | 
					
						
							|  |  |  |                 expected.check_multi_interp_extensions = False | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             interpid, *_ = _interpreters.get_main() | 
					
						
							|  |  |  |             config = _interpreters.get_config(interpid) | 
					
						
							|  |  |  |             self.assert_ns_equal(config, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('isolated'): | 
					
						
							|  |  |  |             expected = _interpreters.new_config('isolated') | 
					
						
							|  |  |  |             interpid = _interpreters.create('isolated') | 
					
						
							|  |  |  |             config = _interpreters.get_config(interpid) | 
					
						
							|  |  |  |             self.assert_ns_equal(config, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('legacy'): | 
					
						
							|  |  |  |             expected = _interpreters.new_config('legacy') | 
					
						
							|  |  |  |             interpid = _interpreters.create('legacy') | 
					
						
							|  |  |  |             config = _interpreters.get_config(interpid) | 
					
						
							|  |  |  |             self.assert_ns_equal(config, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API'): | 
					
						
							|  |  |  |             orig = _interpreters.new_config('isolated') | 
					
						
							|  |  |  |             with self.interpreter_from_capi(orig) as interpid: | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							|  |  |  |                     _interpreters.get_config(interpid, restrict=True) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 config = _interpreters.get_config(interpid) | 
					
						
							|  |  |  |             self.assert_ns_equal(config, orig) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @requires_test_modules | 
					
						
							|  |  |  |     def test_whence(self): | 
					
						
							|  |  |  |         with self.subTest('main'): | 
					
						
							|  |  |  |             interpid, *_ = _interpreters.get_main() | 
					
						
							|  |  |  |             whence = _interpreters.whence(interpid) | 
					
						
							|  |  |  |             self.assertEqual(whence, _interpreters.WHENCE_RUNTIME) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('stdlib'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             whence = _interpreters.whence(interpid) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             self.assertEqual(whence, _interpreters.WHENCE_STDLIB) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for orig, name in { | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             _interpreters.WHENCE_UNKNOWN: 'not ready', | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             _interpreters.WHENCE_LEGACY_CAPI: 'legacy C-API', | 
					
						
							|  |  |  |             _interpreters.WHENCE_CAPI: 'C-API', | 
					
						
							|  |  |  |             _interpreters.WHENCE_XI: 'cross-interpreter C-API', | 
					
						
							|  |  |  |         }.items(): | 
					
						
							|  |  |  |             with self.subTest(f'from C-API ({orig}: {name})'): | 
					
						
							|  |  |  |                 with self.interpreter_from_capi(whence=orig) as interpid: | 
					
						
							|  |  |  |                     whence = _interpreters.whence(interpid) | 
					
						
							|  |  |  |                 self.assertEqual(whence, orig) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API, running'): | 
					
						
							|  |  |  |             text = self.run_temp_from_capi(dedent(f"""
 | 
					
						
							| 
									
										
										
										
											2024-04-24 10:18:24 -06:00
										 |  |  |                 import _interpreters | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 interpid, *_ = _interpreters.get_current() | 
					
						
							|  |  |  |                 print(_interpreters.whence(interpid)) | 
					
						
							|  |  |  |                 """),
 | 
					
						
							|  |  |  |                 config=True) | 
					
						
							|  |  |  |             whence = eval(text) | 
					
						
							|  |  |  |             self.assertEqual(whence, _interpreters.WHENCE_CAPI) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from legacy C-API, running'): | 
					
						
							|  |  |  |             ... | 
					
						
							|  |  |  |             text = self.run_temp_from_capi(dedent(f"""
 | 
					
						
							| 
									
										
										
										
											2024-04-24 10:18:24 -06:00
										 |  |  |                 import _interpreters | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 interpid, *_ = _interpreters.get_current() | 
					
						
							|  |  |  |                 print(_interpreters.whence(interpid)) | 
					
						
							|  |  |  |                 """),
 | 
					
						
							|  |  |  |                 config=False) | 
					
						
							|  |  |  |             whence = eval(text) | 
					
						
							|  |  |  |             self.assertEqual(whence, _interpreters.WHENCE_LEGACY_CAPI) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_is_running(self): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         def check(interpid, expected): | 
					
						
							|  |  |  |             with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							|  |  |  |                 _interpreters.is_running(interpid, restrict=True) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |             running = _interpreters.is_running(interpid) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |             self.assertIs(running, expected) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from _interpreters (running)'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             with self.running(interpid): | 
					
						
							|  |  |  |                 running = _interpreters.is_running(interpid) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 self.assertTrue(running) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from _interpreters (not running)'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             running = _interpreters.is_running(interpid) | 
					
						
							|  |  |  |             self.assertFalse(running) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |         with self.subTest('main'): | 
					
						
							|  |  |  |             interpid, *_ = _interpreters.get_main() | 
					
						
							|  |  |  |             check(interpid, True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |         with self.subTest('from C-API (running __main__)'): | 
					
						
							|  |  |  |             with self.interpreter_from_capi() as interpid: | 
					
						
							|  |  |  |                 with self.running_from_capi(interpid, main=True): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                     check(interpid, True) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API (running, but not __main__)'): | 
					
						
							|  |  |  |             with self.interpreter_from_capi() as interpid: | 
					
						
							|  |  |  |                 with self.running_from_capi(interpid, main=False): | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                     check(interpid, False) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API (not running)'): | 
					
						
							|  |  |  |             with self.interpreter_from_capi() as interpid: | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 check(interpid, False) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_exec(self): | 
					
						
							|  |  |  |         with self.subTest('run script'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             script, results = _captured_script('print("it worked!", end="")') | 
					
						
							|  |  |  |             with results: | 
					
						
							|  |  |  |                 exc = _interpreters.exec(interpid, script) | 
					
						
							|  |  |  |             results = results.final() | 
					
						
							|  |  |  |             results.raise_if_failed() | 
					
						
							|  |  |  |             out = results.stdout | 
					
						
							|  |  |  |             self.assertEqual(out, 'it worked!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('uncaught exception'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             script, results = _captured_script("""
 | 
					
						
							|  |  |  |                 raise Exception('uh-oh!') | 
					
						
							|  |  |  |                 print("it worked!", end="") | 
					
						
							|  |  |  |                 """)
 | 
					
						
							|  |  |  |             with results: | 
					
						
							|  |  |  |                 exc = _interpreters.exec(interpid, script) | 
					
						
							|  |  |  |                 out = results.stdout() | 
					
						
							|  |  |  |             self.assertEqual(out, '') | 
					
						
							|  |  |  |             self.assert_ns_equal(exc, types.SimpleNamespace( | 
					
						
							|  |  |  |                 type=types.SimpleNamespace( | 
					
						
							|  |  |  |                     __name__='Exception', | 
					
						
							|  |  |  |                     __qualname__='Exception', | 
					
						
							|  |  |  |                     __module__='builtins', | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 msg='uh-oh!', | 
					
						
							|  |  |  |                 # We check these in other tests. | 
					
						
							|  |  |  |                 formatted=exc.formatted, | 
					
						
							|  |  |  |                 errdisplay=exc.errdisplay, | 
					
						
							|  |  |  |             )) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API'): | 
					
						
							|  |  |  |             with self.interpreter_from_capi() as interpid: | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							|  |  |  |                     _interpreters.exec(interpid, 'raise Exception("it worked!")', | 
					
						
							|  |  |  |                                        restrict=True) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 exc = _interpreters.exec(interpid, 'raise Exception("it worked!")') | 
					
						
							|  |  |  |             self.assertIsNot(exc, None) | 
					
						
							|  |  |  |             self.assertEqual(exc.msg, 'it worked!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_call(self): | 
					
						
							|  |  |  |         with self.subTest('no args'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             exc = _interpreters.call(interpid, call_func_return_shareable) | 
					
						
							|  |  |  |             self.assertIs(exc, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('uncaught exception'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             exc = _interpreters.call(interpid, call_func_failure) | 
					
						
							|  |  |  |             self.assertEqual(exc, types.SimpleNamespace( | 
					
						
							|  |  |  |                 type=types.SimpleNamespace( | 
					
						
							|  |  |  |                     __name__='Exception', | 
					
						
							|  |  |  |                     __qualname__='Exception', | 
					
						
							|  |  |  |                     __module__='builtins', | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 msg='spam!', | 
					
						
							|  |  |  |                 # We check these in other tests. | 
					
						
							|  |  |  |                 formatted=exc.formatted, | 
					
						
							|  |  |  |                 errdisplay=exc.errdisplay, | 
					
						
							|  |  |  |             )) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |     @requires_test_modules | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |     def test_set___main___attrs(self): | 
					
						
							|  |  |  |         with self.subTest('from _interpreters'): | 
					
						
							|  |  |  |             interpid = _interpreters.create() | 
					
						
							|  |  |  |             before1 = _interpreters.exec(interpid, 'assert spam == \'eggs\'') | 
					
						
							|  |  |  |             before2 = _interpreters.exec(interpid, 'assert ham == 42') | 
					
						
							|  |  |  |             self.assertEqual(before1.type.__name__, 'NameError') | 
					
						
							|  |  |  |             self.assertEqual(before2.type.__name__, 'NameError') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             _interpreters.set___main___attrs(interpid, dict( | 
					
						
							|  |  |  |                 spam='eggs', | 
					
						
							|  |  |  |                 ham=42, | 
					
						
							|  |  |  |             )) | 
					
						
							|  |  |  |             after1 = _interpreters.exec(interpid, 'assert spam == \'eggs\'') | 
					
						
							|  |  |  |             after2 = _interpreters.exec(interpid, 'assert ham == 42') | 
					
						
							|  |  |  |             after3 = _interpreters.exec(interpid, 'assert spam == 42') | 
					
						
							|  |  |  |             self.assertIs(after1, None) | 
					
						
							|  |  |  |             self.assertIs(after2, None) | 
					
						
							|  |  |  |             self.assertEqual(after3.type.__name__, 'AssertionError') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subTest('from C-API'): | 
					
						
							|  |  |  |             with self.interpreter_from_capi() as interpid: | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 with self.assertRaisesRegex(InterpreterError, 'unrecognized'): | 
					
						
							|  |  |  |                     _interpreters.set___main___attrs(interpid, {'spam': True}, | 
					
						
							|  |  |  |                                                      restrict=True) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  |                 _interpreters.set___main___attrs(interpid, {'spam': True}) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:23:25 -06:00
										 |  |  |                 rc = _testinternalcapi.exec_interpreter( | 
					
						
							|  |  |  |                     interpid, | 
					
						
							|  |  |  |                     'assert spam is True', | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             self.assertEqual(rc, 0) | 
					
						
							| 
									
										
										
										
											2024-04-10 18:37:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 17:16:50 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     # Test needs to be a package, so we can do relative imports. | 
					
						
							|  |  |  |     unittest.main() |