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