17db96d56Sopenharmony_ci# Run the tests in Programs/_testembed.c (tests for the CPython embedding APIs) 27db96d56Sopenharmony_cifrom test import support 37db96d56Sopenharmony_cifrom test.support import import_helper 47db96d56Sopenharmony_cifrom test.support import os_helper 57db96d56Sopenharmony_ciimport unittest 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_cifrom collections import namedtuple 87db96d56Sopenharmony_ciimport contextlib 97db96d56Sopenharmony_ciimport json 107db96d56Sopenharmony_ciimport os 117db96d56Sopenharmony_ciimport os.path 127db96d56Sopenharmony_ciimport re 137db96d56Sopenharmony_ciimport shutil 147db96d56Sopenharmony_ciimport subprocess 157db96d56Sopenharmony_ciimport sys 167db96d56Sopenharmony_ciimport sysconfig 177db96d56Sopenharmony_ciimport tempfile 187db96d56Sopenharmony_ciimport textwrap 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ciif not support.has_subprocess_support: 217db96d56Sopenharmony_ci raise unittest.SkipTest("test module requires subprocess") 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ciMS_WINDOWS = (os.name == 'nt') 247db96d56Sopenharmony_ciMACOS = (sys.platform == 'darwin') 257db96d56Sopenharmony_ciPy_DEBUG = hasattr(sys, 'gettotalrefcount') 267db96d56Sopenharmony_ciPYMEM_ALLOCATOR_NOT_SET = 0 277db96d56Sopenharmony_ciPYMEM_ALLOCATOR_DEBUG = 2 287db96d56Sopenharmony_ciPYMEM_ALLOCATOR_MALLOC = 3 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_ci# _PyCoreConfig_InitCompatConfig() 317db96d56Sopenharmony_ciAPI_COMPAT = 1 327db96d56Sopenharmony_ci# _PyCoreConfig_InitPythonConfig() 337db96d56Sopenharmony_ciAPI_PYTHON = 2 347db96d56Sopenharmony_ci# _PyCoreConfig_InitIsolatedConfig() 357db96d56Sopenharmony_ciAPI_ISOLATED = 3 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ciINIT_LOOPS = 4 387db96d56Sopenharmony_ciMAX_HASH_SEED = 4294967295 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci# If we are running from a build dir, but the stdlib has been installed, 427db96d56Sopenharmony_ci# some tests need to expect different results. 437db96d56Sopenharmony_ciSTDLIB_INSTALL = os.path.join(sys.prefix, sys.platlibdir, 447db96d56Sopenharmony_ci f'python{sys.version_info.major}.{sys.version_info.minor}') 457db96d56Sopenharmony_ciif not os.path.isfile(os.path.join(STDLIB_INSTALL, 'os.py')): 467db96d56Sopenharmony_ci STDLIB_INSTALL = None 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_cidef debug_build(program): 497db96d56Sopenharmony_ci program = os.path.basename(program) 507db96d56Sopenharmony_ci name = os.path.splitext(program)[0] 517db96d56Sopenharmony_ci return name.casefold().endswith("_d".casefold()) 527db96d56Sopenharmony_ci 537db96d56Sopenharmony_ci 547db96d56Sopenharmony_cidef remove_python_envvars(): 557db96d56Sopenharmony_ci env = dict(os.environ) 567db96d56Sopenharmony_ci # Remove PYTHON* environment variables to get deterministic environment 577db96d56Sopenharmony_ci for key in list(env): 587db96d56Sopenharmony_ci if key.startswith('PYTHON'): 597db96d56Sopenharmony_ci del env[key] 607db96d56Sopenharmony_ci return env 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ciclass EmbeddingTestsMixin: 647db96d56Sopenharmony_ci def setUp(self): 657db96d56Sopenharmony_ci exename = "_testembed" 667db96d56Sopenharmony_ci builddir = os.path.dirname(sys.executable) 677db96d56Sopenharmony_ci if MS_WINDOWS: 687db96d56Sopenharmony_ci ext = ("_d" if debug_build(sys.executable) else "") + ".exe" 697db96d56Sopenharmony_ci exename += ext 707db96d56Sopenharmony_ci exepath = builddir 717db96d56Sopenharmony_ci else: 727db96d56Sopenharmony_ci exepath = os.path.join(builddir, 'Programs') 737db96d56Sopenharmony_ci self.test_exe = exe = os.path.join(exepath, exename) 747db96d56Sopenharmony_ci if not os.path.exists(exe): 757db96d56Sopenharmony_ci self.skipTest("%r doesn't exist" % exe) 767db96d56Sopenharmony_ci # This is needed otherwise we get a fatal error: 777db96d56Sopenharmony_ci # "Py_Initialize: Unable to get the locale encoding 787db96d56Sopenharmony_ci # LookupError: no codec search functions registered: can't find encoding" 797db96d56Sopenharmony_ci self.oldcwd = os.getcwd() 807db96d56Sopenharmony_ci os.chdir(builddir) 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci def tearDown(self): 837db96d56Sopenharmony_ci os.chdir(self.oldcwd) 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci def run_embedded_interpreter(self, *args, env=None, 867db96d56Sopenharmony_ci timeout=None, returncode=0, input=None, 877db96d56Sopenharmony_ci cwd=None): 887db96d56Sopenharmony_ci """Runs a test in the embedded interpreter""" 897db96d56Sopenharmony_ci cmd = [self.test_exe] 907db96d56Sopenharmony_ci cmd.extend(args) 917db96d56Sopenharmony_ci if env is not None and MS_WINDOWS: 927db96d56Sopenharmony_ci # Windows requires at least the SYSTEMROOT environment variable to 937db96d56Sopenharmony_ci # start Python. 947db96d56Sopenharmony_ci env = env.copy() 957db96d56Sopenharmony_ci env['SYSTEMROOT'] = os.environ['SYSTEMROOT'] 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci p = subprocess.Popen(cmd, 987db96d56Sopenharmony_ci stdout=subprocess.PIPE, 997db96d56Sopenharmony_ci stderr=subprocess.PIPE, 1007db96d56Sopenharmony_ci universal_newlines=True, 1017db96d56Sopenharmony_ci env=env, 1027db96d56Sopenharmony_ci cwd=cwd) 1037db96d56Sopenharmony_ci try: 1047db96d56Sopenharmony_ci (out, err) = p.communicate(input=input, timeout=timeout) 1057db96d56Sopenharmony_ci except: 1067db96d56Sopenharmony_ci p.terminate() 1077db96d56Sopenharmony_ci p.wait() 1087db96d56Sopenharmony_ci raise 1097db96d56Sopenharmony_ci if p.returncode != returncode and support.verbose: 1107db96d56Sopenharmony_ci print(f"--- {cmd} failed ---") 1117db96d56Sopenharmony_ci print(f"stdout:\n{out}") 1127db96d56Sopenharmony_ci print(f"stderr:\n{err}") 1137db96d56Sopenharmony_ci print(f"------") 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci self.assertEqual(p.returncode, returncode, 1167db96d56Sopenharmony_ci "bad returncode %d, stderr is %r" % 1177db96d56Sopenharmony_ci (p.returncode, err)) 1187db96d56Sopenharmony_ci return out, err 1197db96d56Sopenharmony_ci 1207db96d56Sopenharmony_ci def run_repeated_init_and_subinterpreters(self): 1217db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_repeated_init_and_subinterpreters") 1227db96d56Sopenharmony_ci self.assertEqual(err, "") 1237db96d56Sopenharmony_ci 1247db96d56Sopenharmony_ci # The output from _testembed looks like this: 1257db96d56Sopenharmony_ci # --- Pass 1 --- 1267db96d56Sopenharmony_ci # interp 0 <0x1cf9330>, thread state <0x1cf9700>: id(modules) = 139650431942728 1277db96d56Sopenharmony_ci # interp 1 <0x1d4f690>, thread state <0x1d35350>: id(modules) = 139650431165784 1287db96d56Sopenharmony_ci # interp 2 <0x1d5a690>, thread state <0x1d99ed0>: id(modules) = 139650413140368 1297db96d56Sopenharmony_ci # interp 3 <0x1d4f690>, thread state <0x1dc3340>: id(modules) = 139650412862200 1307db96d56Sopenharmony_ci # interp 0 <0x1cf9330>, thread state <0x1cf9700>: id(modules) = 139650431942728 1317db96d56Sopenharmony_ci # --- Pass 2 --- 1327db96d56Sopenharmony_ci # ... 1337db96d56Sopenharmony_ci 1347db96d56Sopenharmony_ci interp_pat = (r"^interp (\d+) <(0x[\dA-F]+)>, " 1357db96d56Sopenharmony_ci r"thread state <(0x[\dA-F]+)>: " 1367db96d56Sopenharmony_ci r"id\(modules\) = ([\d]+)$") 1377db96d56Sopenharmony_ci Interp = namedtuple("Interp", "id interp tstate modules") 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_ci numloops = 1 1407db96d56Sopenharmony_ci current_run = [] 1417db96d56Sopenharmony_ci for line in out.splitlines(): 1427db96d56Sopenharmony_ci if line == "--- Pass {} ---".format(numloops): 1437db96d56Sopenharmony_ci self.assertEqual(len(current_run), 0) 1447db96d56Sopenharmony_ci if support.verbose > 1: 1457db96d56Sopenharmony_ci print(line) 1467db96d56Sopenharmony_ci numloops += 1 1477db96d56Sopenharmony_ci continue 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci self.assertLess(len(current_run), 5) 1507db96d56Sopenharmony_ci match = re.match(interp_pat, line) 1517db96d56Sopenharmony_ci if match is None: 1527db96d56Sopenharmony_ci self.assertRegex(line, interp_pat) 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci # Parse the line from the loop. The first line is the main 1557db96d56Sopenharmony_ci # interpreter and the 3 afterward are subinterpreters. 1567db96d56Sopenharmony_ci interp = Interp(*match.groups()) 1577db96d56Sopenharmony_ci if support.verbose > 1: 1587db96d56Sopenharmony_ci print(interp) 1597db96d56Sopenharmony_ci self.assertTrue(interp.interp) 1607db96d56Sopenharmony_ci self.assertTrue(interp.tstate) 1617db96d56Sopenharmony_ci self.assertTrue(interp.modules) 1627db96d56Sopenharmony_ci current_run.append(interp) 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci # The last line in the loop should be the same as the first. 1657db96d56Sopenharmony_ci if len(current_run) == 5: 1667db96d56Sopenharmony_ci main = current_run[0] 1677db96d56Sopenharmony_ci self.assertEqual(interp, main) 1687db96d56Sopenharmony_ci yield current_run 1697db96d56Sopenharmony_ci current_run = [] 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ciclass EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase): 1737db96d56Sopenharmony_ci maxDiff = 100 * 50 1747db96d56Sopenharmony_ci 1757db96d56Sopenharmony_ci def test_subinterps_main(self): 1767db96d56Sopenharmony_ci for run in self.run_repeated_init_and_subinterpreters(): 1777db96d56Sopenharmony_ci main = run[0] 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_ci self.assertEqual(main.id, '0') 1807db96d56Sopenharmony_ci 1817db96d56Sopenharmony_ci def test_subinterps_different_ids(self): 1827db96d56Sopenharmony_ci for run in self.run_repeated_init_and_subinterpreters(): 1837db96d56Sopenharmony_ci main, *subs, _ = run 1847db96d56Sopenharmony_ci 1857db96d56Sopenharmony_ci mainid = int(main.id) 1867db96d56Sopenharmony_ci for i, sub in enumerate(subs): 1877db96d56Sopenharmony_ci self.assertEqual(sub.id, str(mainid + i + 1)) 1887db96d56Sopenharmony_ci 1897db96d56Sopenharmony_ci def test_subinterps_distinct_state(self): 1907db96d56Sopenharmony_ci for run in self.run_repeated_init_and_subinterpreters(): 1917db96d56Sopenharmony_ci main, *subs, _ = run 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ci if '0x0' in main: 1947db96d56Sopenharmony_ci # XXX Fix on Windows (and other platforms): something 1957db96d56Sopenharmony_ci # is going on with the pointers in Programs/_testembed.c. 1967db96d56Sopenharmony_ci # interp.interp is 0x0 and interp.modules is the same 1977db96d56Sopenharmony_ci # between interpreters. 1987db96d56Sopenharmony_ci raise unittest.SkipTest('platform prints pointers as 0x0') 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci for sub in subs: 2017db96d56Sopenharmony_ci # A new subinterpreter may have the same 2027db96d56Sopenharmony_ci # PyInterpreterState pointer as a previous one if 2037db96d56Sopenharmony_ci # the earlier one has already been destroyed. So 2047db96d56Sopenharmony_ci # we compare with the main interpreter. The same 2057db96d56Sopenharmony_ci # applies to tstate. 2067db96d56Sopenharmony_ci self.assertNotEqual(sub.interp, main.interp) 2077db96d56Sopenharmony_ci self.assertNotEqual(sub.tstate, main.tstate) 2087db96d56Sopenharmony_ci self.assertNotEqual(sub.modules, main.modules) 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ci def test_repeated_init_and_inittab(self): 2117db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_repeated_init_and_inittab") 2127db96d56Sopenharmony_ci self.assertEqual(err, "") 2137db96d56Sopenharmony_ci 2147db96d56Sopenharmony_ci lines = [f"--- Pass {i} ---" for i in range(1, INIT_LOOPS+1)] 2157db96d56Sopenharmony_ci lines = "\n".join(lines) + "\n" 2167db96d56Sopenharmony_ci self.assertEqual(out, lines) 2177db96d56Sopenharmony_ci 2187db96d56Sopenharmony_ci def test_forced_io_encoding(self): 2197db96d56Sopenharmony_ci # Checks forced configuration of embedded interpreter IO streams 2207db96d56Sopenharmony_ci env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape") 2217db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_forced_io_encoding", env=env) 2227db96d56Sopenharmony_ci if support.verbose > 1: 2237db96d56Sopenharmony_ci print() 2247db96d56Sopenharmony_ci print(out) 2257db96d56Sopenharmony_ci print(err) 2267db96d56Sopenharmony_ci expected_stream_encoding = "utf-8" 2277db96d56Sopenharmony_ci expected_errors = "surrogateescape" 2287db96d56Sopenharmony_ci expected_output = '\n'.join([ 2297db96d56Sopenharmony_ci "--- Use defaults ---", 2307db96d56Sopenharmony_ci "Expected encoding: default", 2317db96d56Sopenharmony_ci "Expected errors: default", 2327db96d56Sopenharmony_ci "stdin: {in_encoding}:{errors}", 2337db96d56Sopenharmony_ci "stdout: {out_encoding}:{errors}", 2347db96d56Sopenharmony_ci "stderr: {out_encoding}:backslashreplace", 2357db96d56Sopenharmony_ci "--- Set errors only ---", 2367db96d56Sopenharmony_ci "Expected encoding: default", 2377db96d56Sopenharmony_ci "Expected errors: ignore", 2387db96d56Sopenharmony_ci "stdin: {in_encoding}:ignore", 2397db96d56Sopenharmony_ci "stdout: {out_encoding}:ignore", 2407db96d56Sopenharmony_ci "stderr: {out_encoding}:backslashreplace", 2417db96d56Sopenharmony_ci "--- Set encoding only ---", 2427db96d56Sopenharmony_ci "Expected encoding: iso8859-1", 2437db96d56Sopenharmony_ci "Expected errors: default", 2447db96d56Sopenharmony_ci "stdin: iso8859-1:{errors}", 2457db96d56Sopenharmony_ci "stdout: iso8859-1:{errors}", 2467db96d56Sopenharmony_ci "stderr: iso8859-1:backslashreplace", 2477db96d56Sopenharmony_ci "--- Set encoding and errors ---", 2487db96d56Sopenharmony_ci "Expected encoding: iso8859-1", 2497db96d56Sopenharmony_ci "Expected errors: replace", 2507db96d56Sopenharmony_ci "stdin: iso8859-1:replace", 2517db96d56Sopenharmony_ci "stdout: iso8859-1:replace", 2527db96d56Sopenharmony_ci "stderr: iso8859-1:backslashreplace"]) 2537db96d56Sopenharmony_ci expected_output = expected_output.format( 2547db96d56Sopenharmony_ci in_encoding=expected_stream_encoding, 2557db96d56Sopenharmony_ci out_encoding=expected_stream_encoding, 2567db96d56Sopenharmony_ci errors=expected_errors) 2577db96d56Sopenharmony_ci # This is useful if we ever trip over odd platform behaviour 2587db96d56Sopenharmony_ci self.maxDiff = None 2597db96d56Sopenharmony_ci self.assertEqual(out.strip(), expected_output) 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ci def test_pre_initialization_api(self): 2627db96d56Sopenharmony_ci """ 2637db96d56Sopenharmony_ci Checks some key parts of the C-API that need to work before the runtime 2647db96d56Sopenharmony_ci is initialized (via Py_Initialize()). 2657db96d56Sopenharmony_ci """ 2667db96d56Sopenharmony_ci env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path)) 2677db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_pre_initialization_api", env=env) 2687db96d56Sopenharmony_ci if MS_WINDOWS: 2697db96d56Sopenharmony_ci expected_path = self.test_exe 2707db96d56Sopenharmony_ci else: 2717db96d56Sopenharmony_ci expected_path = os.path.join(os.getcwd(), "spam") 2727db96d56Sopenharmony_ci expected_output = f"sys.executable: {expected_path}\n" 2737db96d56Sopenharmony_ci self.assertIn(expected_output, out) 2747db96d56Sopenharmony_ci self.assertEqual(err, '') 2757db96d56Sopenharmony_ci 2767db96d56Sopenharmony_ci def test_pre_initialization_sys_options(self): 2777db96d56Sopenharmony_ci """ 2787db96d56Sopenharmony_ci Checks that sys.warnoptions and sys._xoptions can be set before the 2797db96d56Sopenharmony_ci runtime is initialized (otherwise they won't be effective). 2807db96d56Sopenharmony_ci """ 2817db96d56Sopenharmony_ci env = remove_python_envvars() 2827db96d56Sopenharmony_ci env['PYTHONPATH'] = os.pathsep.join(sys.path) 2837db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter( 2847db96d56Sopenharmony_ci "test_pre_initialization_sys_options", env=env) 2857db96d56Sopenharmony_ci expected_output = ( 2867db96d56Sopenharmony_ci "sys.warnoptions: ['once', 'module', 'default']\n" 2877db96d56Sopenharmony_ci "sys._xoptions: {'not_an_option': '1', 'also_not_an_option': '2'}\n" 2887db96d56Sopenharmony_ci "warnings.filters[:3]: ['default', 'module', 'once']\n" 2897db96d56Sopenharmony_ci ) 2907db96d56Sopenharmony_ci self.assertIn(expected_output, out) 2917db96d56Sopenharmony_ci self.assertEqual(err, '') 2927db96d56Sopenharmony_ci 2937db96d56Sopenharmony_ci def test_bpo20891(self): 2947db96d56Sopenharmony_ci """ 2957db96d56Sopenharmony_ci bpo-20891: Calling PyGILState_Ensure in a non-Python thread must not 2967db96d56Sopenharmony_ci crash. 2977db96d56Sopenharmony_ci """ 2987db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_bpo20891") 2997db96d56Sopenharmony_ci self.assertEqual(out, '') 3007db96d56Sopenharmony_ci self.assertEqual(err, '') 3017db96d56Sopenharmony_ci 3027db96d56Sopenharmony_ci def test_initialize_twice(self): 3037db96d56Sopenharmony_ci """ 3047db96d56Sopenharmony_ci bpo-33932: Calling Py_Initialize() twice should do nothing (and not 3057db96d56Sopenharmony_ci crash!). 3067db96d56Sopenharmony_ci """ 3077db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_initialize_twice") 3087db96d56Sopenharmony_ci self.assertEqual(out, '') 3097db96d56Sopenharmony_ci self.assertEqual(err, '') 3107db96d56Sopenharmony_ci 3117db96d56Sopenharmony_ci def test_initialize_pymain(self): 3127db96d56Sopenharmony_ci """ 3137db96d56Sopenharmony_ci bpo-34008: Calling Py_Main() after Py_Initialize() must not fail. 3147db96d56Sopenharmony_ci """ 3157db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_initialize_pymain") 3167db96d56Sopenharmony_ci self.assertEqual(out.rstrip(), "Py_Main() after Py_Initialize: sys.argv=['-c', 'arg2']") 3177db96d56Sopenharmony_ci self.assertEqual(err, '') 3187db96d56Sopenharmony_ci 3197db96d56Sopenharmony_ci def test_run_main(self): 3207db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_run_main") 3217db96d56Sopenharmony_ci self.assertEqual(out.rstrip(), "Py_RunMain(): sys.argv=['-c', 'arg2']") 3227db96d56Sopenharmony_ci self.assertEqual(err, '') 3237db96d56Sopenharmony_ci 3247db96d56Sopenharmony_ci def test_run_main_loop(self): 3257db96d56Sopenharmony_ci # bpo-40413: Calling Py_InitializeFromConfig()+Py_RunMain() multiple 3267db96d56Sopenharmony_ci # times must not crash. 3277db96d56Sopenharmony_ci nloop = 5 3287db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_run_main_loop") 3297db96d56Sopenharmony_ci self.assertEqual(out, "Py_RunMain(): sys.argv=['-c', 'arg2']\n" * nloop) 3307db96d56Sopenharmony_ci self.assertEqual(err, '') 3317db96d56Sopenharmony_ci 3327db96d56Sopenharmony_ci def test_finalize_structseq(self): 3337db96d56Sopenharmony_ci # bpo-46417: Py_Finalize() clears structseq static types. Check that 3347db96d56Sopenharmony_ci # sys attributes using struct types still work when 3357db96d56Sopenharmony_ci # Py_Finalize()/Py_Initialize() is called multiple times. 3367db96d56Sopenharmony_ci # print() calls type->tp_repr(instance) and so checks that the types 3377db96d56Sopenharmony_ci # are still working properly. 3387db96d56Sopenharmony_ci script = support.findfile('_test_embed_structseq.py') 3397db96d56Sopenharmony_ci with open(script, encoding="utf-8") as fp: 3407db96d56Sopenharmony_ci code = fp.read() 3417db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_repeated_init_exec", code) 3427db96d56Sopenharmony_ci self.assertEqual(out, 'Tests passed\n' * INIT_LOOPS) 3437db96d56Sopenharmony_ci 3447db96d56Sopenharmony_ci def test_simple_initialization_api(self): 3457db96d56Sopenharmony_ci # _testembed now uses Py_InitializeFromConfig by default 3467db96d56Sopenharmony_ci # This case specifically checks Py_Initialize(Ex) still works 3477db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_repeated_simple_init") 3487db96d56Sopenharmony_ci self.assertEqual(out, 'Finalized\n' * INIT_LOOPS) 3497db96d56Sopenharmony_ci 3507db96d56Sopenharmony_ci def test_quickened_static_code_gets_unquickened_at_Py_FINALIZE(self): 3517db96d56Sopenharmony_ci # https://github.com/python/cpython/issues/92031 3527db96d56Sopenharmony_ci 3537db96d56Sopenharmony_ci # Do these imports outside of the code string to avoid using 3547db96d56Sopenharmony_ci # importlib too much from within the code string, so that 3557db96d56Sopenharmony_ci # _handle_fromlist doesn't get quickened until we intend it to. 3567db96d56Sopenharmony_ci from dis import _all_opmap 3577db96d56Sopenharmony_ci resume = _all_opmap["RESUME"] 3587db96d56Sopenharmony_ci resume_quick = _all_opmap["RESUME_QUICK"] 3597db96d56Sopenharmony_ci from test.test_dis import QUICKENING_WARMUP_DELAY 3607db96d56Sopenharmony_ci 3617db96d56Sopenharmony_ci code = textwrap.dedent(f"""\ 3627db96d56Sopenharmony_ci import importlib._bootstrap 3637db96d56Sopenharmony_ci func = importlib._bootstrap._handle_fromlist 3647db96d56Sopenharmony_ci code = func.__code__ 3657db96d56Sopenharmony_ci 3667db96d56Sopenharmony_ci # Assert initially unquickened. 3677db96d56Sopenharmony_ci # Use sets to account for byte order. 3687db96d56Sopenharmony_ci if set(code._co_code_adaptive[:2]) != set([{resume}, 0]): 3697db96d56Sopenharmony_ci raise AssertionError() 3707db96d56Sopenharmony_ci 3717db96d56Sopenharmony_ci for i in range({QUICKENING_WARMUP_DELAY}): 3727db96d56Sopenharmony_ci func(importlib._bootstrap, ["x"], lambda *args: None) 3737db96d56Sopenharmony_ci 3747db96d56Sopenharmony_ci # Assert quickening worked 3757db96d56Sopenharmony_ci if set(code._co_code_adaptive[:2]) != set([{resume_quick}, 0]): 3767db96d56Sopenharmony_ci raise AssertionError() 3777db96d56Sopenharmony_ci 3787db96d56Sopenharmony_ci print("Tests passed") 3797db96d56Sopenharmony_ci """) 3807db96d56Sopenharmony_ci run = self.run_embedded_interpreter 3817db96d56Sopenharmony_ci out, err = run("test_repeated_init_exec", code) 3827db96d56Sopenharmony_ci self.assertEqual(out, 'Tests passed\n' * INIT_LOOPS) 3837db96d56Sopenharmony_ci 3847db96d56Sopenharmony_ci def test_ucnhash_capi_reset(self): 3857db96d56Sopenharmony_ci # bpo-47182: unicodeobject.c:ucnhash_capi was not reset on shutdown. 3867db96d56Sopenharmony_ci code = "print('\\N{digit nine}')" 3877db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_repeated_init_exec", code) 3887db96d56Sopenharmony_ci self.assertEqual(out, '9\n' * INIT_LOOPS) 3897db96d56Sopenharmony_ci 3907db96d56Sopenharmony_ciclass InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 3917db96d56Sopenharmony_ci maxDiff = 4096 3927db96d56Sopenharmony_ci UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape') 3937db96d56Sopenharmony_ci 3947db96d56Sopenharmony_ci # Marker to read the default configuration: get_default_config() 3957db96d56Sopenharmony_ci GET_DEFAULT_CONFIG = object() 3967db96d56Sopenharmony_ci 3977db96d56Sopenharmony_ci # Marker to ignore a configuration parameter 3987db96d56Sopenharmony_ci IGNORE_CONFIG = object() 3997db96d56Sopenharmony_ci 4007db96d56Sopenharmony_ci PRE_CONFIG_COMPAT = { 4017db96d56Sopenharmony_ci '_config_init': API_COMPAT, 4027db96d56Sopenharmony_ci 'allocator': PYMEM_ALLOCATOR_NOT_SET, 4037db96d56Sopenharmony_ci 'parse_argv': 0, 4047db96d56Sopenharmony_ci 'configure_locale': 1, 4057db96d56Sopenharmony_ci 'coerce_c_locale': 0, 4067db96d56Sopenharmony_ci 'coerce_c_locale_warn': 0, 4077db96d56Sopenharmony_ci 'utf8_mode': 0, 4087db96d56Sopenharmony_ci } 4097db96d56Sopenharmony_ci if MS_WINDOWS: 4107db96d56Sopenharmony_ci PRE_CONFIG_COMPAT.update({ 4117db96d56Sopenharmony_ci 'legacy_windows_fs_encoding': 0, 4127db96d56Sopenharmony_ci }) 4137db96d56Sopenharmony_ci PRE_CONFIG_PYTHON = dict(PRE_CONFIG_COMPAT, 4147db96d56Sopenharmony_ci _config_init=API_PYTHON, 4157db96d56Sopenharmony_ci parse_argv=1, 4167db96d56Sopenharmony_ci coerce_c_locale=GET_DEFAULT_CONFIG, 4177db96d56Sopenharmony_ci utf8_mode=GET_DEFAULT_CONFIG, 4187db96d56Sopenharmony_ci ) 4197db96d56Sopenharmony_ci PRE_CONFIG_ISOLATED = dict(PRE_CONFIG_COMPAT, 4207db96d56Sopenharmony_ci _config_init=API_ISOLATED, 4217db96d56Sopenharmony_ci configure_locale=0, 4227db96d56Sopenharmony_ci isolated=1, 4237db96d56Sopenharmony_ci use_environment=0, 4247db96d56Sopenharmony_ci utf8_mode=0, 4257db96d56Sopenharmony_ci dev_mode=0, 4267db96d56Sopenharmony_ci coerce_c_locale=0, 4277db96d56Sopenharmony_ci ) 4287db96d56Sopenharmony_ci 4297db96d56Sopenharmony_ci COPY_PRE_CONFIG = [ 4307db96d56Sopenharmony_ci 'dev_mode', 4317db96d56Sopenharmony_ci 'isolated', 4327db96d56Sopenharmony_ci 'use_environment', 4337db96d56Sopenharmony_ci ] 4347db96d56Sopenharmony_ci 4357db96d56Sopenharmony_ci CONFIG_COMPAT = { 4367db96d56Sopenharmony_ci '_config_init': API_COMPAT, 4377db96d56Sopenharmony_ci 'isolated': 0, 4387db96d56Sopenharmony_ci 'use_environment': 1, 4397db96d56Sopenharmony_ci 'dev_mode': 0, 4407db96d56Sopenharmony_ci 4417db96d56Sopenharmony_ci 'install_signal_handlers': 1, 4427db96d56Sopenharmony_ci 'use_hash_seed': 0, 4437db96d56Sopenharmony_ci 'hash_seed': 0, 4447db96d56Sopenharmony_ci 'faulthandler': 0, 4457db96d56Sopenharmony_ci 'tracemalloc': 0, 4467db96d56Sopenharmony_ci 'import_time': 0, 4477db96d56Sopenharmony_ci 'code_debug_ranges': 1, 4487db96d56Sopenharmony_ci 'show_ref_count': 0, 4497db96d56Sopenharmony_ci 'dump_refs': 0, 4507db96d56Sopenharmony_ci 'malloc_stats': 0, 4517db96d56Sopenharmony_ci 4527db96d56Sopenharmony_ci 'filesystem_encoding': GET_DEFAULT_CONFIG, 4537db96d56Sopenharmony_ci 'filesystem_errors': GET_DEFAULT_CONFIG, 4547db96d56Sopenharmony_ci 4557db96d56Sopenharmony_ci 'pycache_prefix': None, 4567db96d56Sopenharmony_ci 'program_name': GET_DEFAULT_CONFIG, 4577db96d56Sopenharmony_ci 'parse_argv': 0, 4587db96d56Sopenharmony_ci 'argv': [""], 4597db96d56Sopenharmony_ci 'orig_argv': [], 4607db96d56Sopenharmony_ci 4617db96d56Sopenharmony_ci 'xoptions': [], 4627db96d56Sopenharmony_ci 'warnoptions': [], 4637db96d56Sopenharmony_ci 4647db96d56Sopenharmony_ci 'pythonpath_env': None, 4657db96d56Sopenharmony_ci 'home': None, 4667db96d56Sopenharmony_ci 'executable': GET_DEFAULT_CONFIG, 4677db96d56Sopenharmony_ci 'base_executable': GET_DEFAULT_CONFIG, 4687db96d56Sopenharmony_ci 4697db96d56Sopenharmony_ci 'prefix': GET_DEFAULT_CONFIG, 4707db96d56Sopenharmony_ci 'base_prefix': GET_DEFAULT_CONFIG, 4717db96d56Sopenharmony_ci 'exec_prefix': GET_DEFAULT_CONFIG, 4727db96d56Sopenharmony_ci 'base_exec_prefix': GET_DEFAULT_CONFIG, 4737db96d56Sopenharmony_ci 'module_search_paths': GET_DEFAULT_CONFIG, 4747db96d56Sopenharmony_ci 'module_search_paths_set': 1, 4757db96d56Sopenharmony_ci 'platlibdir': sys.platlibdir, 4767db96d56Sopenharmony_ci 'stdlib_dir': GET_DEFAULT_CONFIG, 4777db96d56Sopenharmony_ci 4787db96d56Sopenharmony_ci 'site_import': 1, 4797db96d56Sopenharmony_ci 'bytes_warning': 0, 4807db96d56Sopenharmony_ci 'warn_default_encoding': 0, 4817db96d56Sopenharmony_ci 'inspect': 0, 4827db96d56Sopenharmony_ci 'interactive': 0, 4837db96d56Sopenharmony_ci 'optimization_level': 0, 4847db96d56Sopenharmony_ci 'parser_debug': 0, 4857db96d56Sopenharmony_ci 'write_bytecode': 1, 4867db96d56Sopenharmony_ci 'verbose': 0, 4877db96d56Sopenharmony_ci 'quiet': 0, 4887db96d56Sopenharmony_ci 'user_site_directory': 1, 4897db96d56Sopenharmony_ci 'configure_c_stdio': 0, 4907db96d56Sopenharmony_ci 'buffered_stdio': 1, 4917db96d56Sopenharmony_ci 4927db96d56Sopenharmony_ci 'stdio_encoding': GET_DEFAULT_CONFIG, 4937db96d56Sopenharmony_ci 'stdio_errors': GET_DEFAULT_CONFIG, 4947db96d56Sopenharmony_ci 4957db96d56Sopenharmony_ci 'skip_source_first_line': 0, 4967db96d56Sopenharmony_ci 'run_command': None, 4977db96d56Sopenharmony_ci 'run_module': None, 4987db96d56Sopenharmony_ci 'run_filename': None, 4997db96d56Sopenharmony_ci 5007db96d56Sopenharmony_ci '_install_importlib': 1, 5017db96d56Sopenharmony_ci 'check_hash_pycs_mode': 'default', 5027db96d56Sopenharmony_ci 'pathconfig_warnings': 1, 5037db96d56Sopenharmony_ci '_init_main': 1, 5047db96d56Sopenharmony_ci '_isolated_interpreter': 0, 5057db96d56Sopenharmony_ci 'use_frozen_modules': not Py_DEBUG, 5067db96d56Sopenharmony_ci 'safe_path': 0, 5077db96d56Sopenharmony_ci '_is_python_build': IGNORE_CONFIG, 5087db96d56Sopenharmony_ci } 5097db96d56Sopenharmony_ci if MS_WINDOWS: 5107db96d56Sopenharmony_ci CONFIG_COMPAT.update({ 5117db96d56Sopenharmony_ci 'legacy_windows_stdio': 0, 5127db96d56Sopenharmony_ci }) 5137db96d56Sopenharmony_ci 5147db96d56Sopenharmony_ci CONFIG_PYTHON = dict(CONFIG_COMPAT, 5157db96d56Sopenharmony_ci _config_init=API_PYTHON, 5167db96d56Sopenharmony_ci configure_c_stdio=1, 5177db96d56Sopenharmony_ci parse_argv=2, 5187db96d56Sopenharmony_ci ) 5197db96d56Sopenharmony_ci CONFIG_ISOLATED = dict(CONFIG_COMPAT, 5207db96d56Sopenharmony_ci _config_init=API_ISOLATED, 5217db96d56Sopenharmony_ci isolated=1, 5227db96d56Sopenharmony_ci use_environment=0, 5237db96d56Sopenharmony_ci user_site_directory=0, 5247db96d56Sopenharmony_ci safe_path=1, 5257db96d56Sopenharmony_ci dev_mode=0, 5267db96d56Sopenharmony_ci install_signal_handlers=0, 5277db96d56Sopenharmony_ci use_hash_seed=0, 5287db96d56Sopenharmony_ci faulthandler=0, 5297db96d56Sopenharmony_ci tracemalloc=0, 5307db96d56Sopenharmony_ci pathconfig_warnings=0, 5317db96d56Sopenharmony_ci ) 5327db96d56Sopenharmony_ci if MS_WINDOWS: 5337db96d56Sopenharmony_ci CONFIG_ISOLATED['legacy_windows_stdio'] = 0 5347db96d56Sopenharmony_ci 5357db96d56Sopenharmony_ci # global config 5367db96d56Sopenharmony_ci DEFAULT_GLOBAL_CONFIG = { 5377db96d56Sopenharmony_ci 'Py_HasFileSystemDefaultEncoding': 0, 5387db96d56Sopenharmony_ci 'Py_HashRandomizationFlag': 1, 5397db96d56Sopenharmony_ci '_Py_HasFileSystemDefaultEncodeErrors': 0, 5407db96d56Sopenharmony_ci } 5417db96d56Sopenharmony_ci COPY_GLOBAL_PRE_CONFIG = [ 5427db96d56Sopenharmony_ci ('Py_UTF8Mode', 'utf8_mode'), 5437db96d56Sopenharmony_ci ] 5447db96d56Sopenharmony_ci COPY_GLOBAL_CONFIG = [ 5457db96d56Sopenharmony_ci # Copy core config to global config for expected values 5467db96d56Sopenharmony_ci # True means that the core config value is inverted (0 => 1 and 1 => 0) 5477db96d56Sopenharmony_ci ('Py_BytesWarningFlag', 'bytes_warning'), 5487db96d56Sopenharmony_ci ('Py_DebugFlag', 'parser_debug'), 5497db96d56Sopenharmony_ci ('Py_DontWriteBytecodeFlag', 'write_bytecode', True), 5507db96d56Sopenharmony_ci ('Py_FileSystemDefaultEncodeErrors', 'filesystem_errors'), 5517db96d56Sopenharmony_ci ('Py_FileSystemDefaultEncoding', 'filesystem_encoding'), 5527db96d56Sopenharmony_ci ('Py_FrozenFlag', 'pathconfig_warnings', True), 5537db96d56Sopenharmony_ci ('Py_IgnoreEnvironmentFlag', 'use_environment', True), 5547db96d56Sopenharmony_ci ('Py_InspectFlag', 'inspect'), 5557db96d56Sopenharmony_ci ('Py_InteractiveFlag', 'interactive'), 5567db96d56Sopenharmony_ci ('Py_IsolatedFlag', 'isolated'), 5577db96d56Sopenharmony_ci ('Py_NoSiteFlag', 'site_import', True), 5587db96d56Sopenharmony_ci ('Py_NoUserSiteDirectory', 'user_site_directory', True), 5597db96d56Sopenharmony_ci ('Py_OptimizeFlag', 'optimization_level'), 5607db96d56Sopenharmony_ci ('Py_QuietFlag', 'quiet'), 5617db96d56Sopenharmony_ci ('Py_UnbufferedStdioFlag', 'buffered_stdio', True), 5627db96d56Sopenharmony_ci ('Py_VerboseFlag', 'verbose'), 5637db96d56Sopenharmony_ci ] 5647db96d56Sopenharmony_ci if MS_WINDOWS: 5657db96d56Sopenharmony_ci COPY_GLOBAL_PRE_CONFIG.extend(( 5667db96d56Sopenharmony_ci ('Py_LegacyWindowsFSEncodingFlag', 'legacy_windows_fs_encoding'), 5677db96d56Sopenharmony_ci )) 5687db96d56Sopenharmony_ci COPY_GLOBAL_CONFIG.extend(( 5697db96d56Sopenharmony_ci ('Py_LegacyWindowsStdioFlag', 'legacy_windows_stdio'), 5707db96d56Sopenharmony_ci )) 5717db96d56Sopenharmony_ci 5727db96d56Sopenharmony_ci EXPECTED_CONFIG = None 5737db96d56Sopenharmony_ci 5747db96d56Sopenharmony_ci @classmethod 5757db96d56Sopenharmony_ci def tearDownClass(cls): 5767db96d56Sopenharmony_ci # clear cache 5777db96d56Sopenharmony_ci cls.EXPECTED_CONFIG = None 5787db96d56Sopenharmony_ci 5797db96d56Sopenharmony_ci def main_xoptions(self, xoptions_list): 5807db96d56Sopenharmony_ci xoptions = {} 5817db96d56Sopenharmony_ci for opt in xoptions_list: 5827db96d56Sopenharmony_ci if '=' in opt: 5837db96d56Sopenharmony_ci key, value = opt.split('=', 1) 5847db96d56Sopenharmony_ci xoptions[key] = value 5857db96d56Sopenharmony_ci else: 5867db96d56Sopenharmony_ci xoptions[opt] = True 5877db96d56Sopenharmony_ci return xoptions 5887db96d56Sopenharmony_ci 5897db96d56Sopenharmony_ci def _get_expected_config_impl(self): 5907db96d56Sopenharmony_ci env = remove_python_envvars() 5917db96d56Sopenharmony_ci code = textwrap.dedent(''' 5927db96d56Sopenharmony_ci import json 5937db96d56Sopenharmony_ci import sys 5947db96d56Sopenharmony_ci import _testinternalcapi 5957db96d56Sopenharmony_ci 5967db96d56Sopenharmony_ci configs = _testinternalcapi.get_configs() 5977db96d56Sopenharmony_ci 5987db96d56Sopenharmony_ci data = json.dumps(configs) 5997db96d56Sopenharmony_ci data = data.encode('utf-8') 6007db96d56Sopenharmony_ci sys.stdout.buffer.write(data) 6017db96d56Sopenharmony_ci sys.stdout.buffer.flush() 6027db96d56Sopenharmony_ci ''') 6037db96d56Sopenharmony_ci 6047db96d56Sopenharmony_ci # Use -S to not import the site module: get the proper configuration 6057db96d56Sopenharmony_ci # when test_embed is run from a venv (bpo-35313) 6067db96d56Sopenharmony_ci args = [sys.executable, '-S', '-c', code] 6077db96d56Sopenharmony_ci proc = subprocess.run(args, env=env, 6087db96d56Sopenharmony_ci stdout=subprocess.PIPE, 6097db96d56Sopenharmony_ci stderr=subprocess.PIPE) 6107db96d56Sopenharmony_ci if proc.returncode: 6117db96d56Sopenharmony_ci raise Exception(f"failed to get the default config: " 6127db96d56Sopenharmony_ci f"stdout={proc.stdout!r} stderr={proc.stderr!r}") 6137db96d56Sopenharmony_ci stdout = proc.stdout.decode('utf-8') 6147db96d56Sopenharmony_ci # ignore stderr 6157db96d56Sopenharmony_ci try: 6167db96d56Sopenharmony_ci return json.loads(stdout) 6177db96d56Sopenharmony_ci except json.JSONDecodeError: 6187db96d56Sopenharmony_ci self.fail(f"fail to decode stdout: {stdout!r}") 6197db96d56Sopenharmony_ci 6207db96d56Sopenharmony_ci def _get_expected_config(self): 6217db96d56Sopenharmony_ci cls = InitConfigTests 6227db96d56Sopenharmony_ci if cls.EXPECTED_CONFIG is None: 6237db96d56Sopenharmony_ci cls.EXPECTED_CONFIG = self._get_expected_config_impl() 6247db96d56Sopenharmony_ci 6257db96d56Sopenharmony_ci # get a copy 6267db96d56Sopenharmony_ci configs = {} 6277db96d56Sopenharmony_ci for config_key, config_value in cls.EXPECTED_CONFIG.items(): 6287db96d56Sopenharmony_ci config = {} 6297db96d56Sopenharmony_ci for key, value in config_value.items(): 6307db96d56Sopenharmony_ci if isinstance(value, list): 6317db96d56Sopenharmony_ci value = value.copy() 6327db96d56Sopenharmony_ci config[key] = value 6337db96d56Sopenharmony_ci configs[config_key] = config 6347db96d56Sopenharmony_ci return configs 6357db96d56Sopenharmony_ci 6367db96d56Sopenharmony_ci def get_expected_config(self, expected_preconfig, expected, 6377db96d56Sopenharmony_ci env, api, modify_path_cb=None): 6387db96d56Sopenharmony_ci configs = self._get_expected_config() 6397db96d56Sopenharmony_ci 6407db96d56Sopenharmony_ci pre_config = configs['pre_config'] 6417db96d56Sopenharmony_ci for key, value in expected_preconfig.items(): 6427db96d56Sopenharmony_ci if value is self.GET_DEFAULT_CONFIG: 6437db96d56Sopenharmony_ci expected_preconfig[key] = pre_config[key] 6447db96d56Sopenharmony_ci 6457db96d56Sopenharmony_ci if not expected_preconfig['configure_locale'] or api == API_COMPAT: 6467db96d56Sopenharmony_ci # there is no easy way to get the locale encoding before 6477db96d56Sopenharmony_ci # setlocale(LC_CTYPE, "") is called: don't test encodings 6487db96d56Sopenharmony_ci for key in ('filesystem_encoding', 'filesystem_errors', 6497db96d56Sopenharmony_ci 'stdio_encoding', 'stdio_errors'): 6507db96d56Sopenharmony_ci expected[key] = self.IGNORE_CONFIG 6517db96d56Sopenharmony_ci 6527db96d56Sopenharmony_ci if not expected_preconfig['configure_locale']: 6537db96d56Sopenharmony_ci # UTF-8 Mode depends on the locale. There is no easy way 6547db96d56Sopenharmony_ci # to guess if UTF-8 Mode will be enabled or not if the locale 6557db96d56Sopenharmony_ci # is not configured. 6567db96d56Sopenharmony_ci expected_preconfig['utf8_mode'] = self.IGNORE_CONFIG 6577db96d56Sopenharmony_ci 6587db96d56Sopenharmony_ci if expected_preconfig['utf8_mode'] == 1: 6597db96d56Sopenharmony_ci if expected['filesystem_encoding'] is self.GET_DEFAULT_CONFIG: 6607db96d56Sopenharmony_ci expected['filesystem_encoding'] = 'utf-8' 6617db96d56Sopenharmony_ci if expected['filesystem_errors'] is self.GET_DEFAULT_CONFIG: 6627db96d56Sopenharmony_ci expected['filesystem_errors'] = self.UTF8_MODE_ERRORS 6637db96d56Sopenharmony_ci if expected['stdio_encoding'] is self.GET_DEFAULT_CONFIG: 6647db96d56Sopenharmony_ci expected['stdio_encoding'] = 'utf-8' 6657db96d56Sopenharmony_ci if expected['stdio_errors'] is self.GET_DEFAULT_CONFIG: 6667db96d56Sopenharmony_ci expected['stdio_errors'] = 'surrogateescape' 6677db96d56Sopenharmony_ci 6687db96d56Sopenharmony_ci if MS_WINDOWS: 6697db96d56Sopenharmony_ci default_executable = self.test_exe 6707db96d56Sopenharmony_ci elif expected['program_name'] is not self.GET_DEFAULT_CONFIG: 6717db96d56Sopenharmony_ci default_executable = os.path.abspath(expected['program_name']) 6727db96d56Sopenharmony_ci else: 6737db96d56Sopenharmony_ci default_executable = os.path.join(os.getcwd(), '_testembed') 6747db96d56Sopenharmony_ci if expected['executable'] is self.GET_DEFAULT_CONFIG: 6757db96d56Sopenharmony_ci expected['executable'] = default_executable 6767db96d56Sopenharmony_ci if expected['base_executable'] is self.GET_DEFAULT_CONFIG: 6777db96d56Sopenharmony_ci expected['base_executable'] = default_executable 6787db96d56Sopenharmony_ci if expected['program_name'] is self.GET_DEFAULT_CONFIG: 6797db96d56Sopenharmony_ci expected['program_name'] = './_testembed' 6807db96d56Sopenharmony_ci 6817db96d56Sopenharmony_ci config = configs['config'] 6827db96d56Sopenharmony_ci for key, value in expected.items(): 6837db96d56Sopenharmony_ci if value is self.GET_DEFAULT_CONFIG: 6847db96d56Sopenharmony_ci expected[key] = config[key] 6857db96d56Sopenharmony_ci 6867db96d56Sopenharmony_ci if expected['module_search_paths'] is not self.IGNORE_CONFIG: 6877db96d56Sopenharmony_ci pythonpath_env = expected['pythonpath_env'] 6887db96d56Sopenharmony_ci if pythonpath_env is not None: 6897db96d56Sopenharmony_ci paths = pythonpath_env.split(os.path.pathsep) 6907db96d56Sopenharmony_ci expected['module_search_paths'] = [*paths, *expected['module_search_paths']] 6917db96d56Sopenharmony_ci if modify_path_cb is not None: 6927db96d56Sopenharmony_ci expected['module_search_paths'] = expected['module_search_paths'].copy() 6937db96d56Sopenharmony_ci modify_path_cb(expected['module_search_paths']) 6947db96d56Sopenharmony_ci 6957db96d56Sopenharmony_ci for key in self.COPY_PRE_CONFIG: 6967db96d56Sopenharmony_ci if key not in expected_preconfig: 6977db96d56Sopenharmony_ci expected_preconfig[key] = expected[key] 6987db96d56Sopenharmony_ci 6997db96d56Sopenharmony_ci def check_pre_config(self, configs, expected): 7007db96d56Sopenharmony_ci pre_config = dict(configs['pre_config']) 7017db96d56Sopenharmony_ci for key, value in list(expected.items()): 7027db96d56Sopenharmony_ci if value is self.IGNORE_CONFIG: 7037db96d56Sopenharmony_ci pre_config.pop(key, None) 7047db96d56Sopenharmony_ci del expected[key] 7057db96d56Sopenharmony_ci self.assertEqual(pre_config, expected) 7067db96d56Sopenharmony_ci 7077db96d56Sopenharmony_ci def check_config(self, configs, expected): 7087db96d56Sopenharmony_ci config = dict(configs['config']) 7097db96d56Sopenharmony_ci if MS_WINDOWS: 7107db96d56Sopenharmony_ci value = config.get(key := 'program_name') 7117db96d56Sopenharmony_ci if value and isinstance(value, str): 7127db96d56Sopenharmony_ci value = value[:len(value.lower().removesuffix('.exe'))] 7137db96d56Sopenharmony_ci if debug_build(sys.executable): 7147db96d56Sopenharmony_ci value = value[:len(value.lower().removesuffix('_d'))] 7157db96d56Sopenharmony_ci config[key] = value 7167db96d56Sopenharmony_ci for key, value in list(expected.items()): 7177db96d56Sopenharmony_ci if value is self.IGNORE_CONFIG: 7187db96d56Sopenharmony_ci config.pop(key, None) 7197db96d56Sopenharmony_ci del expected[key] 7207db96d56Sopenharmony_ci self.assertEqual(config, expected) 7217db96d56Sopenharmony_ci 7227db96d56Sopenharmony_ci def check_global_config(self, configs): 7237db96d56Sopenharmony_ci pre_config = configs['pre_config'] 7247db96d56Sopenharmony_ci config = configs['config'] 7257db96d56Sopenharmony_ci 7267db96d56Sopenharmony_ci expected = dict(self.DEFAULT_GLOBAL_CONFIG) 7277db96d56Sopenharmony_ci for item in self.COPY_GLOBAL_CONFIG: 7287db96d56Sopenharmony_ci if len(item) == 3: 7297db96d56Sopenharmony_ci global_key, core_key, opposite = item 7307db96d56Sopenharmony_ci expected[global_key] = 0 if config[core_key] else 1 7317db96d56Sopenharmony_ci else: 7327db96d56Sopenharmony_ci global_key, core_key = item 7337db96d56Sopenharmony_ci expected[global_key] = config[core_key] 7347db96d56Sopenharmony_ci for item in self.COPY_GLOBAL_PRE_CONFIG: 7357db96d56Sopenharmony_ci if len(item) == 3: 7367db96d56Sopenharmony_ci global_key, core_key, opposite = item 7377db96d56Sopenharmony_ci expected[global_key] = 0 if pre_config[core_key] else 1 7387db96d56Sopenharmony_ci else: 7397db96d56Sopenharmony_ci global_key, core_key = item 7407db96d56Sopenharmony_ci expected[global_key] = pre_config[core_key] 7417db96d56Sopenharmony_ci 7427db96d56Sopenharmony_ci self.assertEqual(configs['global_config'], expected) 7437db96d56Sopenharmony_ci 7447db96d56Sopenharmony_ci def check_all_configs(self, testname, expected_config=None, 7457db96d56Sopenharmony_ci expected_preconfig=None, 7467db96d56Sopenharmony_ci modify_path_cb=None, 7477db96d56Sopenharmony_ci stderr=None, *, api, preconfig_api=None, 7487db96d56Sopenharmony_ci env=None, ignore_stderr=False, cwd=None): 7497db96d56Sopenharmony_ci new_env = remove_python_envvars() 7507db96d56Sopenharmony_ci if env is not None: 7517db96d56Sopenharmony_ci new_env.update(env) 7527db96d56Sopenharmony_ci env = new_env 7537db96d56Sopenharmony_ci 7547db96d56Sopenharmony_ci if preconfig_api is None: 7557db96d56Sopenharmony_ci preconfig_api = api 7567db96d56Sopenharmony_ci if preconfig_api == API_ISOLATED: 7577db96d56Sopenharmony_ci default_preconfig = self.PRE_CONFIG_ISOLATED 7587db96d56Sopenharmony_ci elif preconfig_api == API_PYTHON: 7597db96d56Sopenharmony_ci default_preconfig = self.PRE_CONFIG_PYTHON 7607db96d56Sopenharmony_ci else: 7617db96d56Sopenharmony_ci default_preconfig = self.PRE_CONFIG_COMPAT 7627db96d56Sopenharmony_ci if expected_preconfig is None: 7637db96d56Sopenharmony_ci expected_preconfig = {} 7647db96d56Sopenharmony_ci expected_preconfig = dict(default_preconfig, **expected_preconfig) 7657db96d56Sopenharmony_ci 7667db96d56Sopenharmony_ci if expected_config is None: 7677db96d56Sopenharmony_ci expected_config = {} 7687db96d56Sopenharmony_ci 7697db96d56Sopenharmony_ci if api == API_PYTHON: 7707db96d56Sopenharmony_ci default_config = self.CONFIG_PYTHON 7717db96d56Sopenharmony_ci elif api == API_ISOLATED: 7727db96d56Sopenharmony_ci default_config = self.CONFIG_ISOLATED 7737db96d56Sopenharmony_ci else: 7747db96d56Sopenharmony_ci default_config = self.CONFIG_COMPAT 7757db96d56Sopenharmony_ci expected_config = dict(default_config, **expected_config) 7767db96d56Sopenharmony_ci 7777db96d56Sopenharmony_ci self.get_expected_config(expected_preconfig, 7787db96d56Sopenharmony_ci expected_config, 7797db96d56Sopenharmony_ci env, 7807db96d56Sopenharmony_ci api, modify_path_cb) 7817db96d56Sopenharmony_ci 7827db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter(testname, 7837db96d56Sopenharmony_ci env=env, cwd=cwd) 7847db96d56Sopenharmony_ci if stderr is None and not expected_config['verbose']: 7857db96d56Sopenharmony_ci stderr = "" 7867db96d56Sopenharmony_ci if stderr is not None and not ignore_stderr: 7877db96d56Sopenharmony_ci self.assertEqual(err.rstrip(), stderr) 7887db96d56Sopenharmony_ci try: 7897db96d56Sopenharmony_ci configs = json.loads(out) 7907db96d56Sopenharmony_ci except json.JSONDecodeError: 7917db96d56Sopenharmony_ci self.fail(f"fail to decode stdout: {out!r}") 7927db96d56Sopenharmony_ci 7937db96d56Sopenharmony_ci self.check_pre_config(configs, expected_preconfig) 7947db96d56Sopenharmony_ci self.check_config(configs, expected_config) 7957db96d56Sopenharmony_ci self.check_global_config(configs) 7967db96d56Sopenharmony_ci return configs 7977db96d56Sopenharmony_ci 7987db96d56Sopenharmony_ci def test_init_default_config(self): 7997db96d56Sopenharmony_ci self.check_all_configs("test_init_initialize_config", api=API_COMPAT) 8007db96d56Sopenharmony_ci 8017db96d56Sopenharmony_ci def test_preinit_compat_config(self): 8027db96d56Sopenharmony_ci self.check_all_configs("test_preinit_compat_config", api=API_COMPAT) 8037db96d56Sopenharmony_ci 8047db96d56Sopenharmony_ci def test_init_compat_config(self): 8057db96d56Sopenharmony_ci self.check_all_configs("test_init_compat_config", api=API_COMPAT) 8067db96d56Sopenharmony_ci 8077db96d56Sopenharmony_ci def test_init_global_config(self): 8087db96d56Sopenharmony_ci preconfig = { 8097db96d56Sopenharmony_ci 'utf8_mode': 1, 8107db96d56Sopenharmony_ci } 8117db96d56Sopenharmony_ci config = { 8127db96d56Sopenharmony_ci 'program_name': './globalvar', 8137db96d56Sopenharmony_ci 'site_import': 0, 8147db96d56Sopenharmony_ci 'bytes_warning': 1, 8157db96d56Sopenharmony_ci 'warnoptions': ['default::BytesWarning'], 8167db96d56Sopenharmony_ci 'inspect': 1, 8177db96d56Sopenharmony_ci 'interactive': 1, 8187db96d56Sopenharmony_ci 'optimization_level': 2, 8197db96d56Sopenharmony_ci 'write_bytecode': 0, 8207db96d56Sopenharmony_ci 'verbose': 1, 8217db96d56Sopenharmony_ci 'quiet': 1, 8227db96d56Sopenharmony_ci 'buffered_stdio': 0, 8237db96d56Sopenharmony_ci 8247db96d56Sopenharmony_ci 'user_site_directory': 0, 8257db96d56Sopenharmony_ci 'pathconfig_warnings': 0, 8267db96d56Sopenharmony_ci } 8277db96d56Sopenharmony_ci self.check_all_configs("test_init_global_config", config, preconfig, 8287db96d56Sopenharmony_ci api=API_COMPAT) 8297db96d56Sopenharmony_ci 8307db96d56Sopenharmony_ci def test_init_from_config(self): 8317db96d56Sopenharmony_ci preconfig = { 8327db96d56Sopenharmony_ci 'allocator': PYMEM_ALLOCATOR_MALLOC, 8337db96d56Sopenharmony_ci 'utf8_mode': 1, 8347db96d56Sopenharmony_ci } 8357db96d56Sopenharmony_ci config = { 8367db96d56Sopenharmony_ci 'install_signal_handlers': 0, 8377db96d56Sopenharmony_ci 'use_hash_seed': 1, 8387db96d56Sopenharmony_ci 'hash_seed': 123, 8397db96d56Sopenharmony_ci 'tracemalloc': 2, 8407db96d56Sopenharmony_ci 'import_time': 1, 8417db96d56Sopenharmony_ci 'code_debug_ranges': 0, 8427db96d56Sopenharmony_ci 'show_ref_count': 1, 8437db96d56Sopenharmony_ci 'malloc_stats': 1, 8447db96d56Sopenharmony_ci 8457db96d56Sopenharmony_ci 'stdio_encoding': 'iso8859-1', 8467db96d56Sopenharmony_ci 'stdio_errors': 'replace', 8477db96d56Sopenharmony_ci 8487db96d56Sopenharmony_ci 'pycache_prefix': 'conf_pycache_prefix', 8497db96d56Sopenharmony_ci 'program_name': './conf_program_name', 8507db96d56Sopenharmony_ci 'argv': ['-c', 'arg2'], 8517db96d56Sopenharmony_ci 'orig_argv': ['python3', 8527db96d56Sopenharmony_ci '-W', 'cmdline_warnoption', 8537db96d56Sopenharmony_ci '-X', 'cmdline_xoption', 8547db96d56Sopenharmony_ci '-c', 'pass', 8557db96d56Sopenharmony_ci 'arg2'], 8567db96d56Sopenharmony_ci 'parse_argv': 2, 8577db96d56Sopenharmony_ci 'xoptions': [ 8587db96d56Sopenharmony_ci 'config_xoption1=3', 8597db96d56Sopenharmony_ci 'config_xoption2=', 8607db96d56Sopenharmony_ci 'config_xoption3', 8617db96d56Sopenharmony_ci 'cmdline_xoption', 8627db96d56Sopenharmony_ci ], 8637db96d56Sopenharmony_ci 'warnoptions': [ 8647db96d56Sopenharmony_ci 'cmdline_warnoption', 8657db96d56Sopenharmony_ci 'default::BytesWarning', 8667db96d56Sopenharmony_ci 'config_warnoption', 8677db96d56Sopenharmony_ci ], 8687db96d56Sopenharmony_ci 'run_command': 'pass\n', 8697db96d56Sopenharmony_ci 8707db96d56Sopenharmony_ci 'site_import': 0, 8717db96d56Sopenharmony_ci 'bytes_warning': 1, 8727db96d56Sopenharmony_ci 'inspect': 1, 8737db96d56Sopenharmony_ci 'interactive': 1, 8747db96d56Sopenharmony_ci 'optimization_level': 2, 8757db96d56Sopenharmony_ci 'write_bytecode': 0, 8767db96d56Sopenharmony_ci 'verbose': 1, 8777db96d56Sopenharmony_ci 'quiet': 1, 8787db96d56Sopenharmony_ci 'configure_c_stdio': 1, 8797db96d56Sopenharmony_ci 'buffered_stdio': 0, 8807db96d56Sopenharmony_ci 'user_site_directory': 0, 8817db96d56Sopenharmony_ci 'faulthandler': 1, 8827db96d56Sopenharmony_ci 'platlibdir': 'my_platlibdir', 8837db96d56Sopenharmony_ci 'module_search_paths': self.IGNORE_CONFIG, 8847db96d56Sopenharmony_ci 'safe_path': 1, 8857db96d56Sopenharmony_ci 8867db96d56Sopenharmony_ci 'check_hash_pycs_mode': 'always', 8877db96d56Sopenharmony_ci 'pathconfig_warnings': 0, 8887db96d56Sopenharmony_ci 8897db96d56Sopenharmony_ci '_isolated_interpreter': 1, 8907db96d56Sopenharmony_ci } 8917db96d56Sopenharmony_ci self.check_all_configs("test_init_from_config", config, preconfig, 8927db96d56Sopenharmony_ci api=API_COMPAT) 8937db96d56Sopenharmony_ci 8947db96d56Sopenharmony_ci def test_init_compat_env(self): 8957db96d56Sopenharmony_ci preconfig = { 8967db96d56Sopenharmony_ci 'allocator': PYMEM_ALLOCATOR_MALLOC, 8977db96d56Sopenharmony_ci } 8987db96d56Sopenharmony_ci config = { 8997db96d56Sopenharmony_ci 'use_hash_seed': 1, 9007db96d56Sopenharmony_ci 'hash_seed': 42, 9017db96d56Sopenharmony_ci 'tracemalloc': 2, 9027db96d56Sopenharmony_ci 'import_time': 1, 9037db96d56Sopenharmony_ci 'code_debug_ranges': 0, 9047db96d56Sopenharmony_ci 'malloc_stats': 1, 9057db96d56Sopenharmony_ci 'inspect': 1, 9067db96d56Sopenharmony_ci 'optimization_level': 2, 9077db96d56Sopenharmony_ci 'pythonpath_env': '/my/path', 9087db96d56Sopenharmony_ci 'pycache_prefix': 'env_pycache_prefix', 9097db96d56Sopenharmony_ci 'write_bytecode': 0, 9107db96d56Sopenharmony_ci 'verbose': 1, 9117db96d56Sopenharmony_ci 'buffered_stdio': 0, 9127db96d56Sopenharmony_ci 'stdio_encoding': 'iso8859-1', 9137db96d56Sopenharmony_ci 'stdio_errors': 'replace', 9147db96d56Sopenharmony_ci 'user_site_directory': 0, 9157db96d56Sopenharmony_ci 'faulthandler': 1, 9167db96d56Sopenharmony_ci 'warnoptions': ['EnvVar'], 9177db96d56Sopenharmony_ci 'platlibdir': 'env_platlibdir', 9187db96d56Sopenharmony_ci 'module_search_paths': self.IGNORE_CONFIG, 9197db96d56Sopenharmony_ci 'safe_path': 1, 9207db96d56Sopenharmony_ci } 9217db96d56Sopenharmony_ci self.check_all_configs("test_init_compat_env", config, preconfig, 9227db96d56Sopenharmony_ci api=API_COMPAT) 9237db96d56Sopenharmony_ci 9247db96d56Sopenharmony_ci def test_init_python_env(self): 9257db96d56Sopenharmony_ci preconfig = { 9267db96d56Sopenharmony_ci 'allocator': PYMEM_ALLOCATOR_MALLOC, 9277db96d56Sopenharmony_ci 'utf8_mode': 1, 9287db96d56Sopenharmony_ci } 9297db96d56Sopenharmony_ci config = { 9307db96d56Sopenharmony_ci 'use_hash_seed': 1, 9317db96d56Sopenharmony_ci 'hash_seed': 42, 9327db96d56Sopenharmony_ci 'tracemalloc': 2, 9337db96d56Sopenharmony_ci 'import_time': 1, 9347db96d56Sopenharmony_ci 'code_debug_ranges': 0, 9357db96d56Sopenharmony_ci 'malloc_stats': 1, 9367db96d56Sopenharmony_ci 'inspect': 1, 9377db96d56Sopenharmony_ci 'optimization_level': 2, 9387db96d56Sopenharmony_ci 'pythonpath_env': '/my/path', 9397db96d56Sopenharmony_ci 'pycache_prefix': 'env_pycache_prefix', 9407db96d56Sopenharmony_ci 'write_bytecode': 0, 9417db96d56Sopenharmony_ci 'verbose': 1, 9427db96d56Sopenharmony_ci 'buffered_stdio': 0, 9437db96d56Sopenharmony_ci 'stdio_encoding': 'iso8859-1', 9447db96d56Sopenharmony_ci 'stdio_errors': 'replace', 9457db96d56Sopenharmony_ci 'user_site_directory': 0, 9467db96d56Sopenharmony_ci 'faulthandler': 1, 9477db96d56Sopenharmony_ci 'warnoptions': ['EnvVar'], 9487db96d56Sopenharmony_ci 'platlibdir': 'env_platlibdir', 9497db96d56Sopenharmony_ci 'module_search_paths': self.IGNORE_CONFIG, 9507db96d56Sopenharmony_ci 'safe_path': 1, 9517db96d56Sopenharmony_ci } 9527db96d56Sopenharmony_ci self.check_all_configs("test_init_python_env", config, preconfig, 9537db96d56Sopenharmony_ci api=API_PYTHON) 9547db96d56Sopenharmony_ci 9557db96d56Sopenharmony_ci def test_init_env_dev_mode(self): 9567db96d56Sopenharmony_ci preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG) 9577db96d56Sopenharmony_ci config = dict(dev_mode=1, 9587db96d56Sopenharmony_ci faulthandler=1, 9597db96d56Sopenharmony_ci warnoptions=['default']) 9607db96d56Sopenharmony_ci self.check_all_configs("test_init_env_dev_mode", config, preconfig, 9617db96d56Sopenharmony_ci api=API_COMPAT) 9627db96d56Sopenharmony_ci 9637db96d56Sopenharmony_ci def test_init_env_dev_mode_alloc(self): 9647db96d56Sopenharmony_ci preconfig = dict(allocator=PYMEM_ALLOCATOR_MALLOC) 9657db96d56Sopenharmony_ci config = dict(dev_mode=1, 9667db96d56Sopenharmony_ci faulthandler=1, 9677db96d56Sopenharmony_ci warnoptions=['default']) 9687db96d56Sopenharmony_ci self.check_all_configs("test_init_env_dev_mode_alloc", config, preconfig, 9697db96d56Sopenharmony_ci api=API_COMPAT) 9707db96d56Sopenharmony_ci 9717db96d56Sopenharmony_ci def test_init_dev_mode(self): 9727db96d56Sopenharmony_ci preconfig = { 9737db96d56Sopenharmony_ci 'allocator': PYMEM_ALLOCATOR_DEBUG, 9747db96d56Sopenharmony_ci } 9757db96d56Sopenharmony_ci config = { 9767db96d56Sopenharmony_ci 'faulthandler': 1, 9777db96d56Sopenharmony_ci 'dev_mode': 1, 9787db96d56Sopenharmony_ci 'warnoptions': ['default'], 9797db96d56Sopenharmony_ci } 9807db96d56Sopenharmony_ci self.check_all_configs("test_init_dev_mode", config, preconfig, 9817db96d56Sopenharmony_ci api=API_PYTHON) 9827db96d56Sopenharmony_ci 9837db96d56Sopenharmony_ci def test_preinit_parse_argv(self): 9847db96d56Sopenharmony_ci # Pre-initialize implicitly using argv: make sure that -X dev 9857db96d56Sopenharmony_ci # is used to configure the allocation in preinitialization 9867db96d56Sopenharmony_ci preconfig = { 9877db96d56Sopenharmony_ci 'allocator': PYMEM_ALLOCATOR_DEBUG, 9887db96d56Sopenharmony_ci } 9897db96d56Sopenharmony_ci config = { 9907db96d56Sopenharmony_ci 'argv': ['script.py'], 9917db96d56Sopenharmony_ci 'orig_argv': ['python3', '-X', 'dev', '-P', 'script.py'], 9927db96d56Sopenharmony_ci 'run_filename': os.path.abspath('script.py'), 9937db96d56Sopenharmony_ci 'dev_mode': 1, 9947db96d56Sopenharmony_ci 'faulthandler': 1, 9957db96d56Sopenharmony_ci 'warnoptions': ['default'], 9967db96d56Sopenharmony_ci 'xoptions': ['dev'], 9977db96d56Sopenharmony_ci 'safe_path': 1, 9987db96d56Sopenharmony_ci } 9997db96d56Sopenharmony_ci self.check_all_configs("test_preinit_parse_argv", config, preconfig, 10007db96d56Sopenharmony_ci api=API_PYTHON) 10017db96d56Sopenharmony_ci 10027db96d56Sopenharmony_ci def test_preinit_dont_parse_argv(self): 10037db96d56Sopenharmony_ci # -X dev must be ignored by isolated preconfiguration 10047db96d56Sopenharmony_ci preconfig = { 10057db96d56Sopenharmony_ci 'isolated': 0, 10067db96d56Sopenharmony_ci } 10077db96d56Sopenharmony_ci argv = ["python3", 10087db96d56Sopenharmony_ci "-E", "-I", "-P", 10097db96d56Sopenharmony_ci "-X", "dev", 10107db96d56Sopenharmony_ci "-X", "utf8", 10117db96d56Sopenharmony_ci "script.py"] 10127db96d56Sopenharmony_ci config = { 10137db96d56Sopenharmony_ci 'argv': argv, 10147db96d56Sopenharmony_ci 'orig_argv': argv, 10157db96d56Sopenharmony_ci 'isolated': 0, 10167db96d56Sopenharmony_ci } 10177db96d56Sopenharmony_ci self.check_all_configs("test_preinit_dont_parse_argv", config, preconfig, 10187db96d56Sopenharmony_ci api=API_ISOLATED) 10197db96d56Sopenharmony_ci 10207db96d56Sopenharmony_ci def test_init_isolated_flag(self): 10217db96d56Sopenharmony_ci config = { 10227db96d56Sopenharmony_ci 'isolated': 1, 10237db96d56Sopenharmony_ci 'safe_path': 1, 10247db96d56Sopenharmony_ci 'use_environment': 0, 10257db96d56Sopenharmony_ci 'user_site_directory': 0, 10267db96d56Sopenharmony_ci } 10277db96d56Sopenharmony_ci self.check_all_configs("test_init_isolated_flag", config, api=API_PYTHON) 10287db96d56Sopenharmony_ci 10297db96d56Sopenharmony_ci def test_preinit_isolated1(self): 10307db96d56Sopenharmony_ci # _PyPreConfig.isolated=1, _PyCoreConfig.isolated not set 10317db96d56Sopenharmony_ci config = { 10327db96d56Sopenharmony_ci 'isolated': 1, 10337db96d56Sopenharmony_ci 'safe_path': 1, 10347db96d56Sopenharmony_ci 'use_environment': 0, 10357db96d56Sopenharmony_ci 'user_site_directory': 0, 10367db96d56Sopenharmony_ci } 10377db96d56Sopenharmony_ci self.check_all_configs("test_preinit_isolated1", config, api=API_COMPAT) 10387db96d56Sopenharmony_ci 10397db96d56Sopenharmony_ci def test_preinit_isolated2(self): 10407db96d56Sopenharmony_ci # _PyPreConfig.isolated=0, _PyCoreConfig.isolated=1 10417db96d56Sopenharmony_ci config = { 10427db96d56Sopenharmony_ci 'isolated': 1, 10437db96d56Sopenharmony_ci 'safe_path': 1, 10447db96d56Sopenharmony_ci 'use_environment': 0, 10457db96d56Sopenharmony_ci 'user_site_directory': 0, 10467db96d56Sopenharmony_ci } 10477db96d56Sopenharmony_ci self.check_all_configs("test_preinit_isolated2", config, api=API_COMPAT) 10487db96d56Sopenharmony_ci 10497db96d56Sopenharmony_ci def test_preinit_isolated_config(self): 10507db96d56Sopenharmony_ci self.check_all_configs("test_preinit_isolated_config", api=API_ISOLATED) 10517db96d56Sopenharmony_ci 10527db96d56Sopenharmony_ci def test_init_isolated_config(self): 10537db96d56Sopenharmony_ci self.check_all_configs("test_init_isolated_config", api=API_ISOLATED) 10547db96d56Sopenharmony_ci 10557db96d56Sopenharmony_ci def test_preinit_python_config(self): 10567db96d56Sopenharmony_ci self.check_all_configs("test_preinit_python_config", api=API_PYTHON) 10577db96d56Sopenharmony_ci 10587db96d56Sopenharmony_ci def test_init_python_config(self): 10597db96d56Sopenharmony_ci self.check_all_configs("test_init_python_config", api=API_PYTHON) 10607db96d56Sopenharmony_ci 10617db96d56Sopenharmony_ci def test_init_dont_configure_locale(self): 10627db96d56Sopenharmony_ci # _PyPreConfig.configure_locale=0 10637db96d56Sopenharmony_ci preconfig = { 10647db96d56Sopenharmony_ci 'configure_locale': 0, 10657db96d56Sopenharmony_ci 'coerce_c_locale': 0, 10667db96d56Sopenharmony_ci } 10677db96d56Sopenharmony_ci self.check_all_configs("test_init_dont_configure_locale", {}, preconfig, 10687db96d56Sopenharmony_ci api=API_PYTHON) 10697db96d56Sopenharmony_ci 10707db96d56Sopenharmony_ci @unittest.skip('as of 3.11 this test no longer works because ' 10717db96d56Sopenharmony_ci 'path calculations do not occur on read') 10727db96d56Sopenharmony_ci def test_init_read_set(self): 10737db96d56Sopenharmony_ci config = { 10747db96d56Sopenharmony_ci 'program_name': './init_read_set', 10757db96d56Sopenharmony_ci 'executable': 'my_executable', 10767db96d56Sopenharmony_ci 'base_executable': 'my_executable', 10777db96d56Sopenharmony_ci } 10787db96d56Sopenharmony_ci def modify_path(path): 10797db96d56Sopenharmony_ci path.insert(1, "test_path_insert1") 10807db96d56Sopenharmony_ci path.append("test_path_append") 10817db96d56Sopenharmony_ci self.check_all_configs("test_init_read_set", config, 10827db96d56Sopenharmony_ci api=API_PYTHON, 10837db96d56Sopenharmony_ci modify_path_cb=modify_path) 10847db96d56Sopenharmony_ci 10857db96d56Sopenharmony_ci def test_init_sys_add(self): 10867db96d56Sopenharmony_ci config = { 10877db96d56Sopenharmony_ci 'faulthandler': 1, 10887db96d56Sopenharmony_ci 'xoptions': [ 10897db96d56Sopenharmony_ci 'config_xoption', 10907db96d56Sopenharmony_ci 'cmdline_xoption', 10917db96d56Sopenharmony_ci 'sysadd_xoption', 10927db96d56Sopenharmony_ci 'faulthandler', 10937db96d56Sopenharmony_ci ], 10947db96d56Sopenharmony_ci 'warnoptions': [ 10957db96d56Sopenharmony_ci 'ignore:::cmdline_warnoption', 10967db96d56Sopenharmony_ci 'ignore:::sysadd_warnoption', 10977db96d56Sopenharmony_ci 'ignore:::config_warnoption', 10987db96d56Sopenharmony_ci ], 10997db96d56Sopenharmony_ci 'orig_argv': ['python3', 11007db96d56Sopenharmony_ci '-W', 'ignore:::cmdline_warnoption', 11017db96d56Sopenharmony_ci '-X', 'cmdline_xoption'], 11027db96d56Sopenharmony_ci } 11037db96d56Sopenharmony_ci self.check_all_configs("test_init_sys_add", config, api=API_PYTHON) 11047db96d56Sopenharmony_ci 11057db96d56Sopenharmony_ci def test_init_run_main(self): 11067db96d56Sopenharmony_ci code = ('import _testinternalcapi, json; ' 11077db96d56Sopenharmony_ci 'print(json.dumps(_testinternalcapi.get_configs()))') 11087db96d56Sopenharmony_ci config = { 11097db96d56Sopenharmony_ci 'argv': ['-c', 'arg2'], 11107db96d56Sopenharmony_ci 'orig_argv': ['python3', '-c', code, 'arg2'], 11117db96d56Sopenharmony_ci 'program_name': './python3', 11127db96d56Sopenharmony_ci 'run_command': code + '\n', 11137db96d56Sopenharmony_ci 'parse_argv': 2, 11147db96d56Sopenharmony_ci } 11157db96d56Sopenharmony_ci self.check_all_configs("test_init_run_main", config, api=API_PYTHON) 11167db96d56Sopenharmony_ci 11177db96d56Sopenharmony_ci def test_init_main(self): 11187db96d56Sopenharmony_ci code = ('import _testinternalcapi, json; ' 11197db96d56Sopenharmony_ci 'print(json.dumps(_testinternalcapi.get_configs()))') 11207db96d56Sopenharmony_ci config = { 11217db96d56Sopenharmony_ci 'argv': ['-c', 'arg2'], 11227db96d56Sopenharmony_ci 'orig_argv': ['python3', 11237db96d56Sopenharmony_ci '-c', code, 11247db96d56Sopenharmony_ci 'arg2'], 11257db96d56Sopenharmony_ci 'program_name': './python3', 11267db96d56Sopenharmony_ci 'run_command': code + '\n', 11277db96d56Sopenharmony_ci 'parse_argv': 2, 11287db96d56Sopenharmony_ci '_init_main': 0, 11297db96d56Sopenharmony_ci } 11307db96d56Sopenharmony_ci self.check_all_configs("test_init_main", config, 11317db96d56Sopenharmony_ci api=API_PYTHON, 11327db96d56Sopenharmony_ci stderr="Run Python code before _Py_InitializeMain") 11337db96d56Sopenharmony_ci 11347db96d56Sopenharmony_ci def test_init_parse_argv(self): 11357db96d56Sopenharmony_ci config = { 11367db96d56Sopenharmony_ci 'parse_argv': 2, 11377db96d56Sopenharmony_ci 'argv': ['-c', 'arg1', '-v', 'arg3'], 11387db96d56Sopenharmony_ci 'orig_argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'], 11397db96d56Sopenharmony_ci 'program_name': './argv0', 11407db96d56Sopenharmony_ci 'run_command': 'pass\n', 11417db96d56Sopenharmony_ci 'use_environment': 0, 11427db96d56Sopenharmony_ci } 11437db96d56Sopenharmony_ci self.check_all_configs("test_init_parse_argv", config, api=API_PYTHON) 11447db96d56Sopenharmony_ci 11457db96d56Sopenharmony_ci def test_init_dont_parse_argv(self): 11467db96d56Sopenharmony_ci pre_config = { 11477db96d56Sopenharmony_ci 'parse_argv': 0, 11487db96d56Sopenharmony_ci } 11497db96d56Sopenharmony_ci config = { 11507db96d56Sopenharmony_ci 'parse_argv': 0, 11517db96d56Sopenharmony_ci 'argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'], 11527db96d56Sopenharmony_ci 'orig_argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'], 11537db96d56Sopenharmony_ci 'program_name': './argv0', 11547db96d56Sopenharmony_ci } 11557db96d56Sopenharmony_ci self.check_all_configs("test_init_dont_parse_argv", config, pre_config, 11567db96d56Sopenharmony_ci api=API_PYTHON) 11577db96d56Sopenharmony_ci 11587db96d56Sopenharmony_ci def default_program_name(self, config): 11597db96d56Sopenharmony_ci if MS_WINDOWS: 11607db96d56Sopenharmony_ci program_name = 'python' 11617db96d56Sopenharmony_ci executable = self.test_exe 11627db96d56Sopenharmony_ci else: 11637db96d56Sopenharmony_ci program_name = 'python3' 11647db96d56Sopenharmony_ci if MACOS: 11657db96d56Sopenharmony_ci executable = self.test_exe 11667db96d56Sopenharmony_ci else: 11677db96d56Sopenharmony_ci executable = shutil.which(program_name) or '' 11687db96d56Sopenharmony_ci config.update({ 11697db96d56Sopenharmony_ci 'program_name': program_name, 11707db96d56Sopenharmony_ci 'base_executable': executable, 11717db96d56Sopenharmony_ci 'executable': executable, 11727db96d56Sopenharmony_ci }) 11737db96d56Sopenharmony_ci 11747db96d56Sopenharmony_ci def test_init_setpath(self): 11757db96d56Sopenharmony_ci # Test Py_SetPath() 11767db96d56Sopenharmony_ci config = self._get_expected_config() 11777db96d56Sopenharmony_ci paths = config['config']['module_search_paths'] 11787db96d56Sopenharmony_ci 11797db96d56Sopenharmony_ci config = { 11807db96d56Sopenharmony_ci 'module_search_paths': paths, 11817db96d56Sopenharmony_ci 'prefix': '', 11827db96d56Sopenharmony_ci 'base_prefix': '', 11837db96d56Sopenharmony_ci 'exec_prefix': '', 11847db96d56Sopenharmony_ci 'base_exec_prefix': '', 11857db96d56Sopenharmony_ci # The current getpath.c doesn't determine the stdlib dir 11867db96d56Sopenharmony_ci # in this case. 11877db96d56Sopenharmony_ci 'stdlib_dir': '', 11887db96d56Sopenharmony_ci } 11897db96d56Sopenharmony_ci self.default_program_name(config) 11907db96d56Sopenharmony_ci env = {'TESTPATH': os.path.pathsep.join(paths)} 11917db96d56Sopenharmony_ci 11927db96d56Sopenharmony_ci self.check_all_configs("test_init_setpath", config, 11937db96d56Sopenharmony_ci api=API_COMPAT, env=env, 11947db96d56Sopenharmony_ci ignore_stderr=True) 11957db96d56Sopenharmony_ci 11967db96d56Sopenharmony_ci def test_init_setpath_config(self): 11977db96d56Sopenharmony_ci # Test Py_SetPath() with PyConfig 11987db96d56Sopenharmony_ci config = self._get_expected_config() 11997db96d56Sopenharmony_ci paths = config['config']['module_search_paths'] 12007db96d56Sopenharmony_ci 12017db96d56Sopenharmony_ci config = { 12027db96d56Sopenharmony_ci # set by Py_SetPath() 12037db96d56Sopenharmony_ci 'module_search_paths': paths, 12047db96d56Sopenharmony_ci 'prefix': '', 12057db96d56Sopenharmony_ci 'base_prefix': '', 12067db96d56Sopenharmony_ci 'exec_prefix': '', 12077db96d56Sopenharmony_ci 'base_exec_prefix': '', 12087db96d56Sopenharmony_ci # The current getpath.c doesn't determine the stdlib dir 12097db96d56Sopenharmony_ci # in this case. 12107db96d56Sopenharmony_ci 'stdlib_dir': '', 12117db96d56Sopenharmony_ci 'use_frozen_modules': not Py_DEBUG, 12127db96d56Sopenharmony_ci # overridden by PyConfig 12137db96d56Sopenharmony_ci 'program_name': 'conf_program_name', 12147db96d56Sopenharmony_ci 'base_executable': 'conf_executable', 12157db96d56Sopenharmony_ci 'executable': 'conf_executable', 12167db96d56Sopenharmony_ci } 12177db96d56Sopenharmony_ci env = {'TESTPATH': os.path.pathsep.join(paths)} 12187db96d56Sopenharmony_ci self.check_all_configs("test_init_setpath_config", config, 12197db96d56Sopenharmony_ci api=API_PYTHON, env=env, ignore_stderr=True) 12207db96d56Sopenharmony_ci 12217db96d56Sopenharmony_ci def module_search_paths(self, prefix=None, exec_prefix=None): 12227db96d56Sopenharmony_ci config = self._get_expected_config() 12237db96d56Sopenharmony_ci if prefix is None: 12247db96d56Sopenharmony_ci prefix = config['config']['prefix'] 12257db96d56Sopenharmony_ci if exec_prefix is None: 12267db96d56Sopenharmony_ci exec_prefix = config['config']['prefix'] 12277db96d56Sopenharmony_ci if MS_WINDOWS: 12287db96d56Sopenharmony_ci return config['config']['module_search_paths'] 12297db96d56Sopenharmony_ci else: 12307db96d56Sopenharmony_ci ver = sys.version_info 12317db96d56Sopenharmony_ci return [ 12327db96d56Sopenharmony_ci os.path.join(prefix, sys.platlibdir, 12337db96d56Sopenharmony_ci f'python{ver.major}{ver.minor}.zip'), 12347db96d56Sopenharmony_ci os.path.join(prefix, sys.platlibdir, 12357db96d56Sopenharmony_ci f'python{ver.major}.{ver.minor}'), 12367db96d56Sopenharmony_ci os.path.join(exec_prefix, sys.platlibdir, 12377db96d56Sopenharmony_ci f'python{ver.major}.{ver.minor}', 'lib-dynload'), 12387db96d56Sopenharmony_ci ] 12397db96d56Sopenharmony_ci 12407db96d56Sopenharmony_ci @contextlib.contextmanager 12417db96d56Sopenharmony_ci def tmpdir_with_python(self, subdir=None): 12427db96d56Sopenharmony_ci # Temporary directory with a copy of the Python program 12437db96d56Sopenharmony_ci with tempfile.TemporaryDirectory() as tmpdir: 12447db96d56Sopenharmony_ci # bpo-38234: On macOS and FreeBSD, the temporary directory 12457db96d56Sopenharmony_ci # can be symbolic link. For example, /tmp can be a symbolic link 12467db96d56Sopenharmony_ci # to /var/tmp. Call realpath() to resolve all symbolic links. 12477db96d56Sopenharmony_ci tmpdir = os.path.realpath(tmpdir) 12487db96d56Sopenharmony_ci if subdir: 12497db96d56Sopenharmony_ci tmpdir = os.path.normpath(os.path.join(tmpdir, subdir)) 12507db96d56Sopenharmony_ci os.makedirs(tmpdir) 12517db96d56Sopenharmony_ci 12527db96d56Sopenharmony_ci if MS_WINDOWS: 12537db96d56Sopenharmony_ci # Copy pythonXY.dll (or pythonXY_d.dll) 12547db96d56Sopenharmony_ci import fnmatch 12557db96d56Sopenharmony_ci exedir = os.path.dirname(self.test_exe) 12567db96d56Sopenharmony_ci for f in os.listdir(exedir): 12577db96d56Sopenharmony_ci if fnmatch.fnmatch(f, '*.dll'): 12587db96d56Sopenharmony_ci shutil.copyfile(os.path.join(exedir, f), os.path.join(tmpdir, f)) 12597db96d56Sopenharmony_ci 12607db96d56Sopenharmony_ci # Copy Python program 12617db96d56Sopenharmony_ci exec_copy = os.path.join(tmpdir, os.path.basename(self.test_exe)) 12627db96d56Sopenharmony_ci shutil.copyfile(self.test_exe, exec_copy) 12637db96d56Sopenharmony_ci shutil.copystat(self.test_exe, exec_copy) 12647db96d56Sopenharmony_ci self.test_exe = exec_copy 12657db96d56Sopenharmony_ci 12667db96d56Sopenharmony_ci yield tmpdir 12677db96d56Sopenharmony_ci 12687db96d56Sopenharmony_ci def test_init_setpythonhome(self): 12697db96d56Sopenharmony_ci # Test Py_SetPythonHome(home) with PYTHONPATH env var 12707db96d56Sopenharmony_ci config = self._get_expected_config() 12717db96d56Sopenharmony_ci paths = config['config']['module_search_paths'] 12727db96d56Sopenharmony_ci paths_str = os.path.pathsep.join(paths) 12737db96d56Sopenharmony_ci 12747db96d56Sopenharmony_ci for path in paths: 12757db96d56Sopenharmony_ci if not os.path.isdir(path): 12767db96d56Sopenharmony_ci continue 12777db96d56Sopenharmony_ci if os.path.exists(os.path.join(path, 'os.py')): 12787db96d56Sopenharmony_ci home = os.path.dirname(path) 12797db96d56Sopenharmony_ci break 12807db96d56Sopenharmony_ci else: 12817db96d56Sopenharmony_ci self.fail(f"Unable to find home in {paths!r}") 12827db96d56Sopenharmony_ci 12837db96d56Sopenharmony_ci prefix = exec_prefix = home 12847db96d56Sopenharmony_ci if MS_WINDOWS: 12857db96d56Sopenharmony_ci stdlib = os.path.join(home, "Lib") 12867db96d56Sopenharmony_ci # Because we are specifying 'home', module search paths 12877db96d56Sopenharmony_ci # are fairly static 12887db96d56Sopenharmony_ci expected_paths = [paths[0], os.path.join(home, 'DLLs'), stdlib] 12897db96d56Sopenharmony_ci else: 12907db96d56Sopenharmony_ci version = f'{sys.version_info.major}.{sys.version_info.minor}' 12917db96d56Sopenharmony_ci stdlib = os.path.join(home, sys.platlibdir, f'python{version}') 12927db96d56Sopenharmony_ci expected_paths = self.module_search_paths(prefix=home, exec_prefix=home) 12937db96d56Sopenharmony_ci 12947db96d56Sopenharmony_ci config = { 12957db96d56Sopenharmony_ci 'home': home, 12967db96d56Sopenharmony_ci 'module_search_paths': expected_paths, 12977db96d56Sopenharmony_ci 'prefix': prefix, 12987db96d56Sopenharmony_ci 'base_prefix': prefix, 12997db96d56Sopenharmony_ci 'exec_prefix': exec_prefix, 13007db96d56Sopenharmony_ci 'base_exec_prefix': exec_prefix, 13017db96d56Sopenharmony_ci 'pythonpath_env': paths_str, 13027db96d56Sopenharmony_ci 'stdlib_dir': stdlib, 13037db96d56Sopenharmony_ci } 13047db96d56Sopenharmony_ci self.default_program_name(config) 13057db96d56Sopenharmony_ci env = {'TESTHOME': home, 'PYTHONPATH': paths_str} 13067db96d56Sopenharmony_ci self.check_all_configs("test_init_setpythonhome", config, 13077db96d56Sopenharmony_ci api=API_COMPAT, env=env) 13087db96d56Sopenharmony_ci 13097db96d56Sopenharmony_ci def test_init_is_python_build_with_home(self): 13107db96d56Sopenharmony_ci # Test _Py_path_config._is_python_build configuration (gh-91985) 13117db96d56Sopenharmony_ci config = self._get_expected_config() 13127db96d56Sopenharmony_ci paths = config['config']['module_search_paths'] 13137db96d56Sopenharmony_ci paths_str = os.path.pathsep.join(paths) 13147db96d56Sopenharmony_ci 13157db96d56Sopenharmony_ci for path in paths: 13167db96d56Sopenharmony_ci if not os.path.isdir(path): 13177db96d56Sopenharmony_ci continue 13187db96d56Sopenharmony_ci if os.path.exists(os.path.join(path, 'os.py')): 13197db96d56Sopenharmony_ci home = os.path.dirname(path) 13207db96d56Sopenharmony_ci break 13217db96d56Sopenharmony_ci else: 13227db96d56Sopenharmony_ci self.fail(f"Unable to find home in {paths!r}") 13237db96d56Sopenharmony_ci 13247db96d56Sopenharmony_ci prefix = exec_prefix = home 13257db96d56Sopenharmony_ci if MS_WINDOWS: 13267db96d56Sopenharmony_ci stdlib = os.path.join(home, "Lib") 13277db96d56Sopenharmony_ci # Because we are specifying 'home', module search paths 13287db96d56Sopenharmony_ci # are fairly static 13297db96d56Sopenharmony_ci expected_paths = [paths[0], os.path.join(home, 'DLLs'), stdlib] 13307db96d56Sopenharmony_ci else: 13317db96d56Sopenharmony_ci version = f'{sys.version_info.major}.{sys.version_info.minor}' 13327db96d56Sopenharmony_ci stdlib = os.path.join(home, sys.platlibdir, f'python{version}') 13337db96d56Sopenharmony_ci expected_paths = self.module_search_paths(prefix=home, exec_prefix=home) 13347db96d56Sopenharmony_ci 13357db96d56Sopenharmony_ci config = { 13367db96d56Sopenharmony_ci 'home': home, 13377db96d56Sopenharmony_ci 'module_search_paths': expected_paths, 13387db96d56Sopenharmony_ci 'prefix': prefix, 13397db96d56Sopenharmony_ci 'base_prefix': prefix, 13407db96d56Sopenharmony_ci 'exec_prefix': exec_prefix, 13417db96d56Sopenharmony_ci 'base_exec_prefix': exec_prefix, 13427db96d56Sopenharmony_ci 'pythonpath_env': paths_str, 13437db96d56Sopenharmony_ci 'stdlib_dir': stdlib, 13447db96d56Sopenharmony_ci } 13457db96d56Sopenharmony_ci # The code above is taken from test_init_setpythonhome() 13467db96d56Sopenharmony_ci env = {'TESTHOME': home, 'PYTHONPATH': paths_str} 13477db96d56Sopenharmony_ci 13487db96d56Sopenharmony_ci env['NEGATIVE_ISPYTHONBUILD'] = '1' 13497db96d56Sopenharmony_ci config['_is_python_build'] = 0 13507db96d56Sopenharmony_ci self.check_all_configs("test_init_is_python_build", config, 13517db96d56Sopenharmony_ci api=API_COMPAT, env=env) 13527db96d56Sopenharmony_ci 13537db96d56Sopenharmony_ci env['NEGATIVE_ISPYTHONBUILD'] = '0' 13547db96d56Sopenharmony_ci config['_is_python_build'] = 1 13557db96d56Sopenharmony_ci exedir = os.path.dirname(sys.executable) 13567db96d56Sopenharmony_ci with open(os.path.join(exedir, 'pybuilddir.txt'), encoding='utf8') as f: 13577db96d56Sopenharmony_ci expected_paths[1 if MS_WINDOWS else 2] = os.path.normpath( 13587db96d56Sopenharmony_ci os.path.join(exedir, f'{f.read()}\n$'.splitlines()[0])) 13597db96d56Sopenharmony_ci if not MS_WINDOWS: 13607db96d56Sopenharmony_ci # PREFIX (default) is set when running in build directory 13617db96d56Sopenharmony_ci prefix = exec_prefix = sys.prefix 13627db96d56Sopenharmony_ci # stdlib calculation (/Lib) is not yet supported 13637db96d56Sopenharmony_ci expected_paths[0] = self.module_search_paths(prefix=prefix)[0] 13647db96d56Sopenharmony_ci config.update(prefix=prefix, base_prefix=prefix, 13657db96d56Sopenharmony_ci exec_prefix=exec_prefix, base_exec_prefix=exec_prefix) 13667db96d56Sopenharmony_ci self.check_all_configs("test_init_is_python_build", config, 13677db96d56Sopenharmony_ci api=API_COMPAT, env=env) 13687db96d56Sopenharmony_ci 13697db96d56Sopenharmony_ci def copy_paths_by_env(self, config): 13707db96d56Sopenharmony_ci all_configs = self._get_expected_config() 13717db96d56Sopenharmony_ci paths = all_configs['config']['module_search_paths'] 13727db96d56Sopenharmony_ci paths_str = os.path.pathsep.join(paths) 13737db96d56Sopenharmony_ci config['pythonpath_env'] = paths_str 13747db96d56Sopenharmony_ci env = {'PYTHONPATH': paths_str} 13757db96d56Sopenharmony_ci return env 13767db96d56Sopenharmony_ci 13777db96d56Sopenharmony_ci @unittest.skipIf(MS_WINDOWS, 'See test_init_pybuilddir_win32') 13787db96d56Sopenharmony_ci def test_init_pybuilddir(self): 13797db96d56Sopenharmony_ci # Test path configuration with pybuilddir.txt configuration file 13807db96d56Sopenharmony_ci 13817db96d56Sopenharmony_ci with self.tmpdir_with_python() as tmpdir: 13827db96d56Sopenharmony_ci # pybuilddir.txt is a sub-directory relative to the current 13837db96d56Sopenharmony_ci # directory (tmpdir) 13847db96d56Sopenharmony_ci vpath = sysconfig.get_config_var("VPATH") or '' 13857db96d56Sopenharmony_ci subdir = 'libdir' 13867db96d56Sopenharmony_ci libdir = os.path.join(tmpdir, subdir) 13877db96d56Sopenharmony_ci # The stdlib dir is dirname(executable) + VPATH + 'Lib' 13887db96d56Sopenharmony_ci stdlibdir = os.path.normpath(os.path.join(tmpdir, vpath, 'Lib')) 13897db96d56Sopenharmony_ci os.mkdir(libdir) 13907db96d56Sopenharmony_ci 13917db96d56Sopenharmony_ci filename = os.path.join(tmpdir, 'pybuilddir.txt') 13927db96d56Sopenharmony_ci with open(filename, "w", encoding="utf8") as fp: 13937db96d56Sopenharmony_ci fp.write(subdir) 13947db96d56Sopenharmony_ci 13957db96d56Sopenharmony_ci module_search_paths = self.module_search_paths() 13967db96d56Sopenharmony_ci module_search_paths[-2] = stdlibdir 13977db96d56Sopenharmony_ci module_search_paths[-1] = libdir 13987db96d56Sopenharmony_ci 13997db96d56Sopenharmony_ci executable = self.test_exe 14007db96d56Sopenharmony_ci config = { 14017db96d56Sopenharmony_ci 'base_exec_prefix': sysconfig.get_config_var("exec_prefix"), 14027db96d56Sopenharmony_ci 'base_prefix': sysconfig.get_config_var("prefix"), 14037db96d56Sopenharmony_ci 'base_executable': executable, 14047db96d56Sopenharmony_ci 'executable': executable, 14057db96d56Sopenharmony_ci 'module_search_paths': module_search_paths, 14067db96d56Sopenharmony_ci 'stdlib_dir': stdlibdir, 14077db96d56Sopenharmony_ci } 14087db96d56Sopenharmony_ci env = self.copy_paths_by_env(config) 14097db96d56Sopenharmony_ci self.check_all_configs("test_init_compat_config", config, 14107db96d56Sopenharmony_ci api=API_COMPAT, env=env, 14117db96d56Sopenharmony_ci ignore_stderr=True, cwd=tmpdir) 14127db96d56Sopenharmony_ci 14137db96d56Sopenharmony_ci @unittest.skipUnless(MS_WINDOWS, 'See test_init_pybuilddir') 14147db96d56Sopenharmony_ci def test_init_pybuilddir_win32(self): 14157db96d56Sopenharmony_ci # Test path configuration with pybuilddir.txt configuration file 14167db96d56Sopenharmony_ci 14177db96d56Sopenharmony_ci vpath = sysconfig.get_config_var("VPATH") 14187db96d56Sopenharmony_ci subdir = r'PCbuild\arch' 14197db96d56Sopenharmony_ci if os.path.normpath(vpath).count(os.sep) == 2: 14207db96d56Sopenharmony_ci subdir = os.path.join(subdir, 'instrumented') 14217db96d56Sopenharmony_ci 14227db96d56Sopenharmony_ci with self.tmpdir_with_python(subdir) as tmpdir: 14237db96d56Sopenharmony_ci # The prefix is dirname(executable) + VPATH 14247db96d56Sopenharmony_ci prefix = os.path.normpath(os.path.join(tmpdir, vpath)) 14257db96d56Sopenharmony_ci # The stdlib dir is dirname(executable) + VPATH + 'Lib' 14267db96d56Sopenharmony_ci stdlibdir = os.path.normpath(os.path.join(tmpdir, vpath, 'Lib')) 14277db96d56Sopenharmony_ci 14287db96d56Sopenharmony_ci filename = os.path.join(tmpdir, 'pybuilddir.txt') 14297db96d56Sopenharmony_ci with open(filename, "w", encoding="utf8") as fp: 14307db96d56Sopenharmony_ci fp.write(tmpdir) 14317db96d56Sopenharmony_ci 14327db96d56Sopenharmony_ci module_search_paths = self.module_search_paths() 14337db96d56Sopenharmony_ci module_search_paths[-3] = os.path.join(tmpdir, os.path.basename(module_search_paths[-3])) 14347db96d56Sopenharmony_ci module_search_paths[-2] = tmpdir 14357db96d56Sopenharmony_ci module_search_paths[-1] = stdlibdir 14367db96d56Sopenharmony_ci 14377db96d56Sopenharmony_ci executable = self.test_exe 14387db96d56Sopenharmony_ci config = { 14397db96d56Sopenharmony_ci 'base_exec_prefix': prefix, 14407db96d56Sopenharmony_ci 'base_prefix': prefix, 14417db96d56Sopenharmony_ci 'base_executable': executable, 14427db96d56Sopenharmony_ci 'executable': executable, 14437db96d56Sopenharmony_ci 'prefix': prefix, 14447db96d56Sopenharmony_ci 'exec_prefix': prefix, 14457db96d56Sopenharmony_ci 'module_search_paths': module_search_paths, 14467db96d56Sopenharmony_ci 'stdlib_dir': stdlibdir, 14477db96d56Sopenharmony_ci } 14487db96d56Sopenharmony_ci env = self.copy_paths_by_env(config) 14497db96d56Sopenharmony_ci self.check_all_configs("test_init_compat_config", config, 14507db96d56Sopenharmony_ci api=API_COMPAT, env=env, 14517db96d56Sopenharmony_ci ignore_stderr=False, cwd=tmpdir) 14527db96d56Sopenharmony_ci 14537db96d56Sopenharmony_ci def test_init_pyvenv_cfg(self): 14547db96d56Sopenharmony_ci # Test path configuration with pyvenv.cfg configuration file 14557db96d56Sopenharmony_ci 14567db96d56Sopenharmony_ci with self.tmpdir_with_python() as tmpdir, \ 14577db96d56Sopenharmony_ci tempfile.TemporaryDirectory() as pyvenv_home: 14587db96d56Sopenharmony_ci ver = sys.version_info 14597db96d56Sopenharmony_ci 14607db96d56Sopenharmony_ci if not MS_WINDOWS: 14617db96d56Sopenharmony_ci lib_dynload = os.path.join(pyvenv_home, 14627db96d56Sopenharmony_ci sys.platlibdir, 14637db96d56Sopenharmony_ci f'python{ver.major}.{ver.minor}', 14647db96d56Sopenharmony_ci 'lib-dynload') 14657db96d56Sopenharmony_ci os.makedirs(lib_dynload) 14667db96d56Sopenharmony_ci else: 14677db96d56Sopenharmony_ci lib_folder = os.path.join(pyvenv_home, 'Lib') 14687db96d56Sopenharmony_ci os.makedirs(lib_folder) 14697db96d56Sopenharmony_ci # getpath.py uses Lib\os.py as the LANDMARK 14707db96d56Sopenharmony_ci shutil.copyfile( 14717db96d56Sopenharmony_ci os.path.join(support.STDLIB_DIR, 'os.py'), 14727db96d56Sopenharmony_ci os.path.join(lib_folder, 'os.py'), 14737db96d56Sopenharmony_ci ) 14747db96d56Sopenharmony_ci 14757db96d56Sopenharmony_ci filename = os.path.join(tmpdir, 'pyvenv.cfg') 14767db96d56Sopenharmony_ci with open(filename, "w", encoding="utf8") as fp: 14777db96d56Sopenharmony_ci print("home = %s" % pyvenv_home, file=fp) 14787db96d56Sopenharmony_ci print("include-system-site-packages = false", file=fp) 14797db96d56Sopenharmony_ci 14807db96d56Sopenharmony_ci paths = self.module_search_paths() 14817db96d56Sopenharmony_ci if not MS_WINDOWS: 14827db96d56Sopenharmony_ci paths[-1] = lib_dynload 14837db96d56Sopenharmony_ci else: 14847db96d56Sopenharmony_ci paths = [ 14857db96d56Sopenharmony_ci os.path.join(tmpdir, os.path.basename(paths[0])), 14867db96d56Sopenharmony_ci pyvenv_home, 14877db96d56Sopenharmony_ci os.path.join(pyvenv_home, "Lib"), 14887db96d56Sopenharmony_ci ] 14897db96d56Sopenharmony_ci 14907db96d56Sopenharmony_ci executable = self.test_exe 14917db96d56Sopenharmony_ci base_executable = os.path.join(pyvenv_home, os.path.basename(executable)) 14927db96d56Sopenharmony_ci exec_prefix = pyvenv_home 14937db96d56Sopenharmony_ci config = { 14947db96d56Sopenharmony_ci 'base_prefix': sysconfig.get_config_var("prefix"), 14957db96d56Sopenharmony_ci 'base_exec_prefix': exec_prefix, 14967db96d56Sopenharmony_ci 'exec_prefix': exec_prefix, 14977db96d56Sopenharmony_ci 'base_executable': base_executable, 14987db96d56Sopenharmony_ci 'executable': executable, 14997db96d56Sopenharmony_ci 'module_search_paths': paths, 15007db96d56Sopenharmony_ci } 15017db96d56Sopenharmony_ci if MS_WINDOWS: 15027db96d56Sopenharmony_ci config['base_prefix'] = pyvenv_home 15037db96d56Sopenharmony_ci config['prefix'] = pyvenv_home 15047db96d56Sopenharmony_ci config['stdlib_dir'] = os.path.join(pyvenv_home, 'Lib') 15057db96d56Sopenharmony_ci config['use_frozen_modules'] = int(not Py_DEBUG) 15067db96d56Sopenharmony_ci else: 15077db96d56Sopenharmony_ci # cannot reliably assume stdlib_dir here because it 15087db96d56Sopenharmony_ci # depends too much on our build. But it ought to be found 15097db96d56Sopenharmony_ci config['stdlib_dir'] = self.IGNORE_CONFIG 15107db96d56Sopenharmony_ci config['use_frozen_modules'] = int(not Py_DEBUG) 15117db96d56Sopenharmony_ci 15127db96d56Sopenharmony_ci env = self.copy_paths_by_env(config) 15137db96d56Sopenharmony_ci self.check_all_configs("test_init_compat_config", config, 15147db96d56Sopenharmony_ci api=API_COMPAT, env=env, 15157db96d56Sopenharmony_ci ignore_stderr=True, cwd=tmpdir) 15167db96d56Sopenharmony_ci 15177db96d56Sopenharmony_ci @unittest.skipUnless(MS_WINDOWS, 'specific to Windows') 15187db96d56Sopenharmony_ci def test_getpath_abspath_win32(self): 15197db96d56Sopenharmony_ci # Check _Py_abspath() is passed a backslashed path not to fall back to 15207db96d56Sopenharmony_ci # GetFullPathNameW() on startup, which (re-)normalizes the path overly. 15217db96d56Sopenharmony_ci # Currently, _Py_normpath() doesn't trim trailing dots and spaces. 15227db96d56Sopenharmony_ci CASES = [ 15237db96d56Sopenharmony_ci ("C:/a. . .", "C:\\a. . ."), 15247db96d56Sopenharmony_ci ("C:\\a. . .", "C:\\a. . ."), 15257db96d56Sopenharmony_ci ("\\\\?\\C:////a////b. . .", "\\\\?\\C:\\a\\b. . ."), 15267db96d56Sopenharmony_ci ("//a/b/c. . .", "\\\\a\\b\\c. . ."), 15277db96d56Sopenharmony_ci ("\\\\a\\b\\c. . .", "\\\\a\\b\\c. . ."), 15287db96d56Sopenharmony_ci ("a. . .", f"{os.getcwd()}\\a"), # relpath gets fully normalized 15297db96d56Sopenharmony_ci ] 15307db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter( 15317db96d56Sopenharmony_ci "test_init_initialize_config", 15327db96d56Sopenharmony_ci env={**remove_python_envvars(), 15337db96d56Sopenharmony_ci "PYTHONPATH": os.path.pathsep.join(c[0] for c in CASES)} 15347db96d56Sopenharmony_ci ) 15357db96d56Sopenharmony_ci self.assertEqual(err, "") 15367db96d56Sopenharmony_ci try: 15377db96d56Sopenharmony_ci out = json.loads(out) 15387db96d56Sopenharmony_ci except json.JSONDecodeError: 15397db96d56Sopenharmony_ci self.fail(f"fail to decode stdout: {out!r}") 15407db96d56Sopenharmony_ci 15417db96d56Sopenharmony_ci results = out['config']["module_search_paths"] 15427db96d56Sopenharmony_ci for (_, expected), result in zip(CASES, results): 15437db96d56Sopenharmony_ci self.assertEqual(result, expected) 15447db96d56Sopenharmony_ci 15457db96d56Sopenharmony_ci def test_global_pathconfig(self): 15467db96d56Sopenharmony_ci # Test C API functions getting the path configuration: 15477db96d56Sopenharmony_ci # 15487db96d56Sopenharmony_ci # - Py_GetExecPrefix() 15497db96d56Sopenharmony_ci # - Py_GetPath() 15507db96d56Sopenharmony_ci # - Py_GetPrefix() 15517db96d56Sopenharmony_ci # - Py_GetProgramFullPath() 15527db96d56Sopenharmony_ci # - Py_GetProgramName() 15537db96d56Sopenharmony_ci # - Py_GetPythonHome() 15547db96d56Sopenharmony_ci # 15557db96d56Sopenharmony_ci # The global path configuration (_Py_path_config) must be a copy 15567db96d56Sopenharmony_ci # of the path configuration of PyInterpreter.config (PyConfig). 15577db96d56Sopenharmony_ci ctypes = import_helper.import_module('ctypes') 15587db96d56Sopenharmony_ci _testinternalcapi = import_helper.import_module('_testinternalcapi') 15597db96d56Sopenharmony_ci 15607db96d56Sopenharmony_ci def get_func(name): 15617db96d56Sopenharmony_ci func = getattr(ctypes.pythonapi, name) 15627db96d56Sopenharmony_ci func.argtypes = () 15637db96d56Sopenharmony_ci func.restype = ctypes.c_wchar_p 15647db96d56Sopenharmony_ci return func 15657db96d56Sopenharmony_ci 15667db96d56Sopenharmony_ci Py_GetPath = get_func('Py_GetPath') 15677db96d56Sopenharmony_ci Py_GetPrefix = get_func('Py_GetPrefix') 15687db96d56Sopenharmony_ci Py_GetExecPrefix = get_func('Py_GetExecPrefix') 15697db96d56Sopenharmony_ci Py_GetProgramName = get_func('Py_GetProgramName') 15707db96d56Sopenharmony_ci Py_GetProgramFullPath = get_func('Py_GetProgramFullPath') 15717db96d56Sopenharmony_ci Py_GetPythonHome = get_func('Py_GetPythonHome') 15727db96d56Sopenharmony_ci 15737db96d56Sopenharmony_ci config = _testinternalcapi.get_configs()['config'] 15747db96d56Sopenharmony_ci 15757db96d56Sopenharmony_ci self.assertEqual(Py_GetPath().split(os.path.pathsep), 15767db96d56Sopenharmony_ci config['module_search_paths']) 15777db96d56Sopenharmony_ci self.assertEqual(Py_GetPrefix(), config['prefix']) 15787db96d56Sopenharmony_ci self.assertEqual(Py_GetExecPrefix(), config['exec_prefix']) 15797db96d56Sopenharmony_ci self.assertEqual(Py_GetProgramName(), config['program_name']) 15807db96d56Sopenharmony_ci self.assertEqual(Py_GetProgramFullPath(), config['executable']) 15817db96d56Sopenharmony_ci self.assertEqual(Py_GetPythonHome(), config['home']) 15827db96d56Sopenharmony_ci 15837db96d56Sopenharmony_ci def test_init_warnoptions(self): 15847db96d56Sopenharmony_ci # lowest to highest priority 15857db96d56Sopenharmony_ci warnoptions = [ 15867db96d56Sopenharmony_ci 'ignore:::PyConfig_Insert0', # PyWideStringList_Insert(0) 15877db96d56Sopenharmony_ci 'default', # PyConfig.dev_mode=1 15887db96d56Sopenharmony_ci 'ignore:::env1', # PYTHONWARNINGS env var 15897db96d56Sopenharmony_ci 'ignore:::env2', # PYTHONWARNINGS env var 15907db96d56Sopenharmony_ci 'ignore:::cmdline1', # -W opt command line option 15917db96d56Sopenharmony_ci 'ignore:::cmdline2', # -W opt command line option 15927db96d56Sopenharmony_ci 'default::BytesWarning', # PyConfig.bytes_warnings=1 15937db96d56Sopenharmony_ci 'ignore:::PySys_AddWarnOption1', # PySys_AddWarnOption() 15947db96d56Sopenharmony_ci 'ignore:::PySys_AddWarnOption2', # PySys_AddWarnOption() 15957db96d56Sopenharmony_ci 'ignore:::PyConfig_BeforeRead', # PyConfig.warnoptions 15967db96d56Sopenharmony_ci 'ignore:::PyConfig_AfterRead'] # PyWideStringList_Append() 15977db96d56Sopenharmony_ci preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG) 15987db96d56Sopenharmony_ci config = { 15997db96d56Sopenharmony_ci 'dev_mode': 1, 16007db96d56Sopenharmony_ci 'faulthandler': 1, 16017db96d56Sopenharmony_ci 'bytes_warning': 1, 16027db96d56Sopenharmony_ci 'warnoptions': warnoptions, 16037db96d56Sopenharmony_ci 'orig_argv': ['python3', 16047db96d56Sopenharmony_ci '-Wignore:::cmdline1', 16057db96d56Sopenharmony_ci '-Wignore:::cmdline2'], 16067db96d56Sopenharmony_ci } 16077db96d56Sopenharmony_ci self.check_all_configs("test_init_warnoptions", config, preconfig, 16087db96d56Sopenharmony_ci api=API_PYTHON) 16097db96d56Sopenharmony_ci 16107db96d56Sopenharmony_ci def test_init_set_config(self): 16117db96d56Sopenharmony_ci config = { 16127db96d56Sopenharmony_ci '_init_main': 0, 16137db96d56Sopenharmony_ci 'bytes_warning': 2, 16147db96d56Sopenharmony_ci 'warnoptions': ['error::BytesWarning'], 16157db96d56Sopenharmony_ci } 16167db96d56Sopenharmony_ci self.check_all_configs("test_init_set_config", config, 16177db96d56Sopenharmony_ci api=API_ISOLATED) 16187db96d56Sopenharmony_ci 16197db96d56Sopenharmony_ci def test_get_argc_argv(self): 16207db96d56Sopenharmony_ci self.run_embedded_interpreter("test_get_argc_argv") 16217db96d56Sopenharmony_ci # ignore output 16227db96d56Sopenharmony_ci 16237db96d56Sopenharmony_ci def test_init_use_frozen_modules(self): 16247db96d56Sopenharmony_ci tests = { 16257db96d56Sopenharmony_ci ('=on', 1), 16267db96d56Sopenharmony_ci ('=off', 0), 16277db96d56Sopenharmony_ci ('=', 1), 16287db96d56Sopenharmony_ci ('', 1), 16297db96d56Sopenharmony_ci } 16307db96d56Sopenharmony_ci for raw, expected in tests: 16317db96d56Sopenharmony_ci optval = f'frozen_modules{raw}' 16327db96d56Sopenharmony_ci config = { 16337db96d56Sopenharmony_ci 'parse_argv': 2, 16347db96d56Sopenharmony_ci 'argv': ['-c'], 16357db96d56Sopenharmony_ci 'orig_argv': ['./argv0', '-X', optval, '-c', 'pass'], 16367db96d56Sopenharmony_ci 'program_name': './argv0', 16377db96d56Sopenharmony_ci 'run_command': 'pass\n', 16387db96d56Sopenharmony_ci 'use_environment': 1, 16397db96d56Sopenharmony_ci 'xoptions': [optval], 16407db96d56Sopenharmony_ci 'use_frozen_modules': expected, 16417db96d56Sopenharmony_ci } 16427db96d56Sopenharmony_ci env = {'TESTFROZEN': raw[1:]} if raw else None 16437db96d56Sopenharmony_ci with self.subTest(repr(raw)): 16447db96d56Sopenharmony_ci self.check_all_configs("test_init_use_frozen_modules", config, 16457db96d56Sopenharmony_ci api=API_PYTHON, env=env) 16467db96d56Sopenharmony_ci 16477db96d56Sopenharmony_ci 16487db96d56Sopenharmony_ciclass SetConfigTests(unittest.TestCase): 16497db96d56Sopenharmony_ci def test_set_config(self): 16507db96d56Sopenharmony_ci # bpo-42260: Test _PyInterpreterState_SetConfig() 16517db96d56Sopenharmony_ci import_helper.import_module('_testcapi') 16527db96d56Sopenharmony_ci cmd = [sys.executable, '-X', 'utf8', '-I', '-m', 'test._test_embed_set_config'] 16537db96d56Sopenharmony_ci proc = subprocess.run(cmd, 16547db96d56Sopenharmony_ci stdout=subprocess.PIPE, 16557db96d56Sopenharmony_ci stderr=subprocess.PIPE, 16567db96d56Sopenharmony_ci encoding='utf-8', errors='backslashreplace') 16577db96d56Sopenharmony_ci if proc.returncode and support.verbose: 16587db96d56Sopenharmony_ci print(proc.stdout) 16597db96d56Sopenharmony_ci print(proc.stderr) 16607db96d56Sopenharmony_ci self.assertEqual(proc.returncode, 0, 16617db96d56Sopenharmony_ci (proc.returncode, proc.stdout, proc.stderr)) 16627db96d56Sopenharmony_ci 16637db96d56Sopenharmony_ci 16647db96d56Sopenharmony_ciclass AuditingTests(EmbeddingTestsMixin, unittest.TestCase): 16657db96d56Sopenharmony_ci def test_open_code_hook(self): 16667db96d56Sopenharmony_ci self.run_embedded_interpreter("test_open_code_hook") 16677db96d56Sopenharmony_ci 16687db96d56Sopenharmony_ci def test_audit(self): 16697db96d56Sopenharmony_ci self.run_embedded_interpreter("test_audit") 16707db96d56Sopenharmony_ci 16717db96d56Sopenharmony_ci def test_audit_subinterpreter(self): 16727db96d56Sopenharmony_ci self.run_embedded_interpreter("test_audit_subinterpreter") 16737db96d56Sopenharmony_ci 16747db96d56Sopenharmony_ci def test_audit_run_command(self): 16757db96d56Sopenharmony_ci self.run_embedded_interpreter("test_audit_run_command", 16767db96d56Sopenharmony_ci timeout=support.SHORT_TIMEOUT, 16777db96d56Sopenharmony_ci returncode=1) 16787db96d56Sopenharmony_ci 16797db96d56Sopenharmony_ci def test_audit_run_file(self): 16807db96d56Sopenharmony_ci self.run_embedded_interpreter("test_audit_run_file", 16817db96d56Sopenharmony_ci timeout=support.SHORT_TIMEOUT, 16827db96d56Sopenharmony_ci returncode=1) 16837db96d56Sopenharmony_ci 16847db96d56Sopenharmony_ci def test_audit_run_interactivehook(self): 16857db96d56Sopenharmony_ci startup = os.path.join(self.oldcwd, os_helper.TESTFN) + ".py" 16867db96d56Sopenharmony_ci with open(startup, "w", encoding="utf-8") as f: 16877db96d56Sopenharmony_ci print("import sys", file=f) 16887db96d56Sopenharmony_ci print("sys.__interactivehook__ = lambda: None", file=f) 16897db96d56Sopenharmony_ci try: 16907db96d56Sopenharmony_ci env = {**remove_python_envvars(), "PYTHONSTARTUP": startup} 16917db96d56Sopenharmony_ci self.run_embedded_interpreter("test_audit_run_interactivehook", 16927db96d56Sopenharmony_ci timeout=support.SHORT_TIMEOUT, 16937db96d56Sopenharmony_ci returncode=10, env=env) 16947db96d56Sopenharmony_ci finally: 16957db96d56Sopenharmony_ci os.unlink(startup) 16967db96d56Sopenharmony_ci 16977db96d56Sopenharmony_ci def test_audit_run_startup(self): 16987db96d56Sopenharmony_ci startup = os.path.join(self.oldcwd, os_helper.TESTFN) + ".py" 16997db96d56Sopenharmony_ci with open(startup, "w", encoding="utf-8") as f: 17007db96d56Sopenharmony_ci print("pass", file=f) 17017db96d56Sopenharmony_ci try: 17027db96d56Sopenharmony_ci env = {**remove_python_envvars(), "PYTHONSTARTUP": startup} 17037db96d56Sopenharmony_ci self.run_embedded_interpreter("test_audit_run_startup", 17047db96d56Sopenharmony_ci timeout=support.SHORT_TIMEOUT, 17057db96d56Sopenharmony_ci returncode=10, env=env) 17067db96d56Sopenharmony_ci finally: 17077db96d56Sopenharmony_ci os.unlink(startup) 17087db96d56Sopenharmony_ci 17097db96d56Sopenharmony_ci def test_audit_run_stdin(self): 17107db96d56Sopenharmony_ci self.run_embedded_interpreter("test_audit_run_stdin", 17117db96d56Sopenharmony_ci timeout=support.SHORT_TIMEOUT, 17127db96d56Sopenharmony_ci returncode=1) 17137db96d56Sopenharmony_ci 17147db96d56Sopenharmony_ci def test_get_incomplete_frame(self): 17157db96d56Sopenharmony_ci self.run_embedded_interpreter("test_get_incomplete_frame") 17167db96d56Sopenharmony_ci 17177db96d56Sopenharmony_ci 17187db96d56Sopenharmony_ciclass MiscTests(EmbeddingTestsMixin, unittest.TestCase): 17197db96d56Sopenharmony_ci def test_unicode_id_init(self): 17207db96d56Sopenharmony_ci # bpo-42882: Test that _PyUnicode_FromId() works 17217db96d56Sopenharmony_ci # when Python is initialized multiples times. 17227db96d56Sopenharmony_ci self.run_embedded_interpreter("test_unicode_id_init") 17237db96d56Sopenharmony_ci 17247db96d56Sopenharmony_ci # See bpo-44133 17257db96d56Sopenharmony_ci @unittest.skipIf(os.name == 'nt', 17267db96d56Sopenharmony_ci 'Py_FrozenMain is not exported on Windows') 17277db96d56Sopenharmony_ci def test_frozenmain(self): 17287db96d56Sopenharmony_ci env = dict(os.environ) 17297db96d56Sopenharmony_ci env['PYTHONUNBUFFERED'] = '1' 17307db96d56Sopenharmony_ci out, err = self.run_embedded_interpreter("test_frozenmain", env=env) 17317db96d56Sopenharmony_ci executable = os.path.realpath('./argv0') 17327db96d56Sopenharmony_ci expected = textwrap.dedent(f""" 17337db96d56Sopenharmony_ci Frozen Hello World 17347db96d56Sopenharmony_ci sys.argv ['./argv0', '-E', 'arg1', 'arg2'] 17357db96d56Sopenharmony_ci config program_name: ./argv0 17367db96d56Sopenharmony_ci config executable: {executable} 17377db96d56Sopenharmony_ci config use_environment: 1 17387db96d56Sopenharmony_ci config configure_c_stdio: 1 17397db96d56Sopenharmony_ci config buffered_stdio: 0 17407db96d56Sopenharmony_ci """).lstrip() 17417db96d56Sopenharmony_ci self.assertEqual(out, expected) 17427db96d56Sopenharmony_ci 17437db96d56Sopenharmony_ci @unittest.skipUnless(hasattr(sys, 'gettotalrefcount'), 17447db96d56Sopenharmony_ci '-X showrefcount requires a Python debug build') 17457db96d56Sopenharmony_ci def test_no_memleak(self): 17467db96d56Sopenharmony_ci # bpo-1635741: Python must release all memory at exit 17477db96d56Sopenharmony_ci tests = ( 17487db96d56Sopenharmony_ci ('off', 'pass'), 17497db96d56Sopenharmony_ci ('on', 'pass'), 17507db96d56Sopenharmony_ci ('off', 'import __hello__'), 17517db96d56Sopenharmony_ci ('on', 'import __hello__'), 17527db96d56Sopenharmony_ci ) 17537db96d56Sopenharmony_ci for flag, stmt in tests: 17547db96d56Sopenharmony_ci xopt = f"frozen_modules={flag}" 17557db96d56Sopenharmony_ci cmd = [sys.executable, "-I", "-X", "showrefcount", "-X", xopt, "-c", stmt] 17567db96d56Sopenharmony_ci proc = subprocess.run(cmd, 17577db96d56Sopenharmony_ci stdout=subprocess.PIPE, 17587db96d56Sopenharmony_ci stderr=subprocess.STDOUT, 17597db96d56Sopenharmony_ci text=True) 17607db96d56Sopenharmony_ci self.assertEqual(proc.returncode, 0) 17617db96d56Sopenharmony_ci out = proc.stdout.rstrip() 17627db96d56Sopenharmony_ci match = re.match(r'^\[(-?\d+) refs, (-?\d+) blocks\]', out) 17637db96d56Sopenharmony_ci if not match: 17647db96d56Sopenharmony_ci self.fail(f"unexpected output: {out!a}") 17657db96d56Sopenharmony_ci refs = int(match.group(1)) 17667db96d56Sopenharmony_ci blocks = int(match.group(2)) 17677db96d56Sopenharmony_ci with self.subTest(frozen_modules=flag, stmt=stmt): 17687db96d56Sopenharmony_ci self.assertEqual(refs, 0, out) 17697db96d56Sopenharmony_ci self.assertEqual(blocks, 0, out) 17707db96d56Sopenharmony_ci 17717db96d56Sopenharmony_ci 17727db96d56Sopenharmony_ciclass StdPrinterTests(EmbeddingTestsMixin, unittest.TestCase): 17737db96d56Sopenharmony_ci # Test PyStdPrinter_Type which is used by _PySys_SetPreliminaryStderr(): 17747db96d56Sopenharmony_ci # "Set up a preliminary stderr printer until we have enough 17757db96d56Sopenharmony_ci # infrastructure for the io module in place." 17767db96d56Sopenharmony_ci 17777db96d56Sopenharmony_ci STDOUT_FD = 1 17787db96d56Sopenharmony_ci 17797db96d56Sopenharmony_ci def create_printer(self, fd): 17807db96d56Sopenharmony_ci ctypes = import_helper.import_module('ctypes') 17817db96d56Sopenharmony_ci PyFile_NewStdPrinter = ctypes.pythonapi.PyFile_NewStdPrinter 17827db96d56Sopenharmony_ci PyFile_NewStdPrinter.argtypes = (ctypes.c_int,) 17837db96d56Sopenharmony_ci PyFile_NewStdPrinter.restype = ctypes.py_object 17847db96d56Sopenharmony_ci return PyFile_NewStdPrinter(fd) 17857db96d56Sopenharmony_ci 17867db96d56Sopenharmony_ci def test_write(self): 17877db96d56Sopenharmony_ci message = "unicode:\xe9-\u20ac-\udc80!\n" 17887db96d56Sopenharmony_ci 17897db96d56Sopenharmony_ci stdout_fd = self.STDOUT_FD 17907db96d56Sopenharmony_ci stdout_fd_copy = os.dup(stdout_fd) 17917db96d56Sopenharmony_ci self.addCleanup(os.close, stdout_fd_copy) 17927db96d56Sopenharmony_ci 17937db96d56Sopenharmony_ci rfd, wfd = os.pipe() 17947db96d56Sopenharmony_ci self.addCleanup(os.close, rfd) 17957db96d56Sopenharmony_ci self.addCleanup(os.close, wfd) 17967db96d56Sopenharmony_ci try: 17977db96d56Sopenharmony_ci # PyFile_NewStdPrinter() only accepts fileno(stdout) 17987db96d56Sopenharmony_ci # or fileno(stderr) file descriptor. 17997db96d56Sopenharmony_ci os.dup2(wfd, stdout_fd) 18007db96d56Sopenharmony_ci 18017db96d56Sopenharmony_ci printer = self.create_printer(stdout_fd) 18027db96d56Sopenharmony_ci printer.write(message) 18037db96d56Sopenharmony_ci finally: 18047db96d56Sopenharmony_ci os.dup2(stdout_fd_copy, stdout_fd) 18057db96d56Sopenharmony_ci 18067db96d56Sopenharmony_ci data = os.read(rfd, 100) 18077db96d56Sopenharmony_ci self.assertEqual(data, message.encode('utf8', 'backslashreplace')) 18087db96d56Sopenharmony_ci 18097db96d56Sopenharmony_ci def test_methods(self): 18107db96d56Sopenharmony_ci fd = self.STDOUT_FD 18117db96d56Sopenharmony_ci printer = self.create_printer(fd) 18127db96d56Sopenharmony_ci self.assertEqual(printer.fileno(), fd) 18137db96d56Sopenharmony_ci self.assertEqual(printer.isatty(), os.isatty(fd)) 18147db96d56Sopenharmony_ci printer.flush() # noop 18157db96d56Sopenharmony_ci printer.close() # noop 18167db96d56Sopenharmony_ci 18177db96d56Sopenharmony_ci def test_disallow_instantiation(self): 18187db96d56Sopenharmony_ci fd = self.STDOUT_FD 18197db96d56Sopenharmony_ci printer = self.create_printer(fd) 18207db96d56Sopenharmony_ci support.check_disallow_instantiation(self, type(printer)) 18217db96d56Sopenharmony_ci 18227db96d56Sopenharmony_ci 18237db96d56Sopenharmony_ciif __name__ == "__main__": 18247db96d56Sopenharmony_ci unittest.main() 1825