blob: f2cf4a63add2874cc93ef03d69c9d3370a002d79 [file] [log] [blame]
Nick Coghlan39f0bb52017-11-28 08:11:51 +10001# Run the tests in Programs/_testembed.c (tests for the CPython embedding APIs)
2from test import support
Hai Shibb0424b2020-08-04 00:47:42 +08003from test.support import import_helper
4from test.support import os_helper
Nick Coghlan39f0bb52017-11-28 08:11:51 +10005import unittest
6
7from collections import namedtuple
Victor Stinner52ad33a2019-09-25 02:10:35 +02008import contextlib
Victor Stinner7ddd56f2018-11-14 00:24:28 +01009import json
Nick Coghlan39f0bb52017-11-28 08:11:51 +100010import os
11import re
Victor Stinner52ad33a2019-09-25 02:10:35 +020012import shutil
Nick Coghlan39f0bb52017-11-28 08:11:51 +100013import subprocess
14import sys
Victor Stinner52ad33a2019-09-25 02:10:35 +020015import tempfile
Victor Stinnera6537fb2018-11-26 11:54:12 +010016import textwrap
Nick Coghlan39f0bb52017-11-28 08:11:51 +100017
18
Victor Stinner01de89c2018-11-14 17:39:45 +010019MS_WINDOWS = (os.name == 'nt')
Victor Stinner49d99f02019-09-26 04:01:49 +020020MACOS = (sys.platform == 'darwin')
Victor Stinner022be022019-05-22 23:58:50 +020021
Victor Stinnerb16b4e42019-05-17 15:20:52 +020022PYMEM_ALLOCATOR_NOT_SET = 0
23PYMEM_ALLOCATOR_DEBUG = 2
24PYMEM_ALLOCATOR_MALLOC = 3
Victor Stinner01de89c2018-11-14 17:39:45 +010025
Victor Stinner022be022019-05-22 23:58:50 +020026# _PyCoreConfig_InitCompatConfig()
27API_COMPAT = 1
28# _PyCoreConfig_InitPythonConfig()
29API_PYTHON = 2
30# _PyCoreConfig_InitIsolatedConfig()
31API_ISOLATED = 3
Victor Stinner6d1c4672019-05-20 11:02:00 +020032
Victor Stinnerece38412021-06-23 17:47:38 +020033INIT_LOOPS = 16
Victor Stinnerf3cb8142020-11-05 18:12:33 +010034MAX_HASH_SEED = 4294967295
35
Victor Stinner01de89c2018-11-14 17:39:45 +010036
Victor Stinner52ad33a2019-09-25 02:10:35 +020037def debug_build(program):
38 program = os.path.basename(program)
39 name = os.path.splitext(program)[0]
Steve Dowerdcbaa1b2020-07-06 17:32:00 +010040 return name.casefold().endswith("_d".casefold())
Victor Stinner52ad33a2019-09-25 02:10:35 +020041
42
Victor Stinnerdbdc9912019-06-18 00:11:00 +020043def remove_python_envvars():
44 env = dict(os.environ)
45 # Remove PYTHON* environment variables to get deterministic environment
46 for key in list(env):
47 if key.startswith('PYTHON'):
48 del env[key]
49 return env
50
51
Victor Stinner56b29b62018-07-26 18:57:56 +020052class EmbeddingTestsMixin:
Nick Coghlan39f0bb52017-11-28 08:11:51 +100053 def setUp(self):
54 here = os.path.abspath(__file__)
55 basepath = os.path.dirname(os.path.dirname(os.path.dirname(here)))
56 exename = "_testembed"
Victor Stinner01de89c2018-11-14 17:39:45 +010057 if MS_WINDOWS:
Victor Stinner52ad33a2019-09-25 02:10:35 +020058 ext = ("_d" if debug_build(sys.executable) else "") + ".exe"
Nick Coghlan39f0bb52017-11-28 08:11:51 +100059 exename += ext
60 exepath = os.path.dirname(sys.executable)
61 else:
62 exepath = os.path.join(basepath, "Programs")
63 self.test_exe = exe = os.path.join(exepath, exename)
64 if not os.path.exists(exe):
65 self.skipTest("%r doesn't exist" % exe)
66 # This is needed otherwise we get a fatal error:
67 # "Py_Initialize: Unable to get the locale encoding
68 # LookupError: no codec search functions registered: can't find encoding"
69 self.oldcwd = os.getcwd()
70 os.chdir(basepath)
71
72 def tearDown(self):
73 os.chdir(self.oldcwd)
74
Steve Dowere226e832019-07-01 16:03:53 -070075 def run_embedded_interpreter(self, *args, env=None,
Victor Stinner52ad33a2019-09-25 02:10:35 +020076 timeout=None, returncode=0, input=None,
77 cwd=None):
Nick Coghlan39f0bb52017-11-28 08:11:51 +100078 """Runs a test in the embedded interpreter"""
79 cmd = [self.test_exe]
80 cmd.extend(args)
Victor Stinner01de89c2018-11-14 17:39:45 +010081 if env is not None and MS_WINDOWS:
Nick Coghlan39f0bb52017-11-28 08:11:51 +100082 # Windows requires at least the SYSTEMROOT environment variable to
83 # start Python.
84 env = env.copy()
85 env['SYSTEMROOT'] = os.environ['SYSTEMROOT']
86
87 p = subprocess.Popen(cmd,
88 stdout=subprocess.PIPE,
89 stderr=subprocess.PIPE,
90 universal_newlines=True,
Victor Stinner52ad33a2019-09-25 02:10:35 +020091 env=env,
92 cwd=cwd)
Victor Stinner2f549082019-03-29 15:13:46 +010093 try:
Steve Dowere226e832019-07-01 16:03:53 -070094 (out, err) = p.communicate(input=input, timeout=timeout)
Victor Stinner2f549082019-03-29 15:13:46 +010095 except:
96 p.terminate()
97 p.wait()
98 raise
Steve Dowere226e832019-07-01 16:03:53 -070099 if p.returncode != returncode and support.verbose:
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000100 print(f"--- {cmd} failed ---")
101 print(f"stdout:\n{out}")
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000102 print(f"stderr:\n{err}")
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000103 print(f"------")
104
Steve Dowere226e832019-07-01 16:03:53 -0700105 self.assertEqual(p.returncode, returncode,
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000106 "bad returncode %d, stderr is %r" %
107 (p.returncode, err))
108 return out, err
109
110 def run_repeated_init_and_subinterpreters(self):
Victor Stinner5edcf262019-05-23 00:57:57 +0200111 out, err = self.run_embedded_interpreter("test_repeated_init_and_subinterpreters")
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000112 self.assertEqual(err, "")
113
114 # The output from _testembed looks like this:
Victor Stinnerece38412021-06-23 17:47:38 +0200115 # --- Pass 1 ---
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000116 # interp 0 <0x1cf9330>, thread state <0x1cf9700>: id(modules) = 139650431942728
117 # interp 1 <0x1d4f690>, thread state <0x1d35350>: id(modules) = 139650431165784
118 # interp 2 <0x1d5a690>, thread state <0x1d99ed0>: id(modules) = 139650413140368
119 # interp 3 <0x1d4f690>, thread state <0x1dc3340>: id(modules) = 139650412862200
120 # interp 0 <0x1cf9330>, thread state <0x1cf9700>: id(modules) = 139650431942728
Victor Stinnerece38412021-06-23 17:47:38 +0200121 # --- Pass 2 ---
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000122 # ...
123
124 interp_pat = (r"^interp (\d+) <(0x[\dA-F]+)>, "
125 r"thread state <(0x[\dA-F]+)>: "
126 r"id\(modules\) = ([\d]+)$")
127 Interp = namedtuple("Interp", "id interp tstate modules")
128
Victor Stinnerece38412021-06-23 17:47:38 +0200129 numloops = 1
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000130 current_run = []
131 for line in out.splitlines():
132 if line == "--- Pass {} ---".format(numloops):
133 self.assertEqual(len(current_run), 0)
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000134 if support.verbose > 1:
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000135 print(line)
136 numloops += 1
137 continue
138
139 self.assertLess(len(current_run), 5)
140 match = re.match(interp_pat, line)
141 if match is None:
142 self.assertRegex(line, interp_pat)
143
144 # Parse the line from the loop. The first line is the main
145 # interpreter and the 3 afterward are subinterpreters.
146 interp = Interp(*match.groups())
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000147 if support.verbose > 1:
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000148 print(interp)
149 self.assertTrue(interp.interp)
150 self.assertTrue(interp.tstate)
151 self.assertTrue(interp.modules)
152 current_run.append(interp)
153
154 # The last line in the loop should be the same as the first.
155 if len(current_run) == 5:
156 main = current_run[0]
157 self.assertEqual(interp, main)
158 yield current_run
159 current_run = []
160
Victor Stinner56b29b62018-07-26 18:57:56 +0200161
162class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
Victor Stinnerece38412021-06-23 17:47:38 +0200163 maxDiff = 100 * 50
164
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000165 def test_subinterps_main(self):
166 for run in self.run_repeated_init_and_subinterpreters():
167 main = run[0]
168
169 self.assertEqual(main.id, '0')
170
171 def test_subinterps_different_ids(self):
172 for run in self.run_repeated_init_and_subinterpreters():
173 main, *subs, _ = run
174
175 mainid = int(main.id)
176 for i, sub in enumerate(subs):
177 self.assertEqual(sub.id, str(mainid + i + 1))
178
179 def test_subinterps_distinct_state(self):
180 for run in self.run_repeated_init_and_subinterpreters():
181 main, *subs, _ = run
182
183 if '0x0' in main:
184 # XXX Fix on Windows (and other platforms): something
185 # is going on with the pointers in Programs/_testembed.c.
186 # interp.interp is 0x0 and interp.modules is the same
187 # between interpreters.
188 raise unittest.SkipTest('platform prints pointers as 0x0')
189
190 for sub in subs:
191 # A new subinterpreter may have the same
192 # PyInterpreterState pointer as a previous one if
193 # the earlier one has already been destroyed. So
194 # we compare with the main interpreter. The same
195 # applies to tstate.
196 self.assertNotEqual(sub.interp, main.interp)
197 self.assertNotEqual(sub.tstate, main.tstate)
198 self.assertNotEqual(sub.modules, main.modules)
199
Victor Stinnerece38412021-06-23 17:47:38 +0200200 def test_repeated_init_and_inittab(self):
201 out, err = self.run_embedded_interpreter("test_repeated_init_and_inittab")
202 self.assertEqual(err, "")
203
204 lines = [f"--- Pass {i} ---" for i in range(1, INIT_LOOPS+1)]
205 lines = "\n".join(lines) + "\n"
206 self.assertEqual(out, lines)
207
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000208 def test_forced_io_encoding(self):
209 # Checks forced configuration of embedded interpreter IO streams
210 env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")
Victor Stinner5edcf262019-05-23 00:57:57 +0200211 out, err = self.run_embedded_interpreter("test_forced_io_encoding", env=env)
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000212 if support.verbose > 1:
213 print()
214 print(out)
215 print(err)
216 expected_stream_encoding = "utf-8"
217 expected_errors = "surrogateescape"
218 expected_output = '\n'.join([
219 "--- Use defaults ---",
220 "Expected encoding: default",
221 "Expected errors: default",
222 "stdin: {in_encoding}:{errors}",
223 "stdout: {out_encoding}:{errors}",
224 "stderr: {out_encoding}:backslashreplace",
225 "--- Set errors only ---",
226 "Expected encoding: default",
227 "Expected errors: ignore",
228 "stdin: {in_encoding}:ignore",
229 "stdout: {out_encoding}:ignore",
230 "stderr: {out_encoding}:backslashreplace",
231 "--- Set encoding only ---",
Victor Stinner9e4994d2018-08-28 23:26:33 +0200232 "Expected encoding: iso8859-1",
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000233 "Expected errors: default",
Victor Stinner9e4994d2018-08-28 23:26:33 +0200234 "stdin: iso8859-1:{errors}",
235 "stdout: iso8859-1:{errors}",
236 "stderr: iso8859-1:backslashreplace",
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000237 "--- Set encoding and errors ---",
Victor Stinner9e4994d2018-08-28 23:26:33 +0200238 "Expected encoding: iso8859-1",
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000239 "Expected errors: replace",
Victor Stinner9e4994d2018-08-28 23:26:33 +0200240 "stdin: iso8859-1:replace",
241 "stdout: iso8859-1:replace",
242 "stderr: iso8859-1:backslashreplace"])
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000243 expected_output = expected_output.format(
244 in_encoding=expected_stream_encoding,
245 out_encoding=expected_stream_encoding,
246 errors=expected_errors)
247 # This is useful if we ever trip over odd platform behaviour
248 self.maxDiff = None
249 self.assertEqual(out.strip(), expected_output)
250
251 def test_pre_initialization_api(self):
252 """
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000253 Checks some key parts of the C-API that need to work before the runtine
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000254 is initialized (via Py_Initialize()).
255 """
256 env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
Victor Stinner5edcf262019-05-23 00:57:57 +0200257 out, err = self.run_embedded_interpreter("test_pre_initialization_api", env=env)
Victor Stinner01de89c2018-11-14 17:39:45 +0100258 if MS_WINDOWS:
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000259 expected_path = self.test_exe
260 else:
261 expected_path = os.path.join(os.getcwd(), "spam")
262 expected_output = f"sys.executable: {expected_path}\n"
263 self.assertIn(expected_output, out)
264 self.assertEqual(err, '')
265
266 def test_pre_initialization_sys_options(self):
267 """
268 Checks that sys.warnoptions and sys._xoptions can be set before the
269 runtime is initialized (otherwise they won't be effective).
270 """
Victor Stinnerdbdc9912019-06-18 00:11:00 +0200271 env = remove_python_envvars()
272 env['PYTHONPATH'] = os.pathsep.join(sys.path)
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000273 out, err = self.run_embedded_interpreter(
Victor Stinner5edcf262019-05-23 00:57:57 +0200274 "test_pre_initialization_sys_options", env=env)
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000275 expected_output = (
276 "sys.warnoptions: ['once', 'module', 'default']\n"
277 "sys._xoptions: {'not_an_option': '1', 'also_not_an_option': '2'}\n"
278 "warnings.filters[:3]: ['default', 'module', 'once']\n"
279 )
280 self.assertIn(expected_output, out)
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000281 self.assertEqual(err, '')
282
Victor Stinnerb4d1e1f2017-11-30 22:05:00 +0100283 def test_bpo20891(self):
284 """
Victor Stinner3225b9f2020-03-09 20:56:57 +0100285 bpo-20891: Calling PyGILState_Ensure in a non-Python thread must not
286 crash.
Victor Stinnerb4d1e1f2017-11-30 22:05:00 +0100287 """
Victor Stinner5edcf262019-05-23 00:57:57 +0200288 out, err = self.run_embedded_interpreter("test_bpo20891")
Victor Stinnerb4d1e1f2017-11-30 22:05:00 +0100289 self.assertEqual(out, '')
290 self.assertEqual(err, '')
291
Victor Stinner209abf72018-06-22 19:14:51 +0200292 def test_initialize_twice(self):
293 """
294 bpo-33932: Calling Py_Initialize() twice should do nothing (and not
295 crash!).
296 """
Victor Stinner5edcf262019-05-23 00:57:57 +0200297 out, err = self.run_embedded_interpreter("test_initialize_twice")
Victor Stinner209abf72018-06-22 19:14:51 +0200298 self.assertEqual(out, '')
299 self.assertEqual(err, '')
300
Victor Stinnerfb47bca2018-07-20 17:34:23 +0200301 def test_initialize_pymain(self):
302 """
303 bpo-34008: Calling Py_Main() after Py_Initialize() must not fail.
304 """
Victor Stinner5edcf262019-05-23 00:57:57 +0200305 out, err = self.run_embedded_interpreter("test_initialize_pymain")
Victor Stinnerfb47bca2018-07-20 17:34:23 +0200306 self.assertEqual(out.rstrip(), "Py_Main() after Py_Initialize: sys.argv=['-c', 'arg2']")
307 self.assertEqual(err, '')
308
Victor Stinner2f549082019-03-29 15:13:46 +0100309 def test_run_main(self):
Victor Stinner5edcf262019-05-23 00:57:57 +0200310 out, err = self.run_embedded_interpreter("test_run_main")
Victor Stinner331a6a52019-05-27 16:39:22 +0200311 self.assertEqual(out.rstrip(), "Py_RunMain(): sys.argv=['-c', 'arg2']")
Victor Stinner2f549082019-03-29 15:13:46 +0100312 self.assertEqual(err, '')
313
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000314
Victor Stinner56b29b62018-07-26 18:57:56 +0200315class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
316 maxDiff = 4096
Victor Stinner01de89c2018-11-14 17:39:45 +0100317 UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape')
318
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200319 # Marker to read the default configuration: get_default_config()
Victor Stinnera6537fb2018-11-26 11:54:12 +0100320 GET_DEFAULT_CONFIG = object()
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200321
322 # Marker to ignore a configuration parameter
323 IGNORE_CONFIG = object()
324
Victor Stinner022be022019-05-22 23:58:50 +0200325 PRE_CONFIG_COMPAT = {
Victor Stinner20e1e252019-05-23 04:12:27 +0200326 '_config_init': API_COMPAT,
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200327 'allocator': PYMEM_ALLOCATOR_NOT_SET,
Victor Stinner6d1c4672019-05-20 11:02:00 +0200328 'parse_argv': 0,
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200329 'configure_locale': 1,
Victor Stinner1075d162019-03-25 23:19:57 +0100330 'coerce_c_locale': 0,
331 'coerce_c_locale_warn': 0,
Victor Stinner1075d162019-03-25 23:19:57 +0100332 'utf8_mode': 0,
333 }
Victor Stinner6d1c4672019-05-20 11:02:00 +0200334 if MS_WINDOWS:
Victor Stinner022be022019-05-22 23:58:50 +0200335 PRE_CONFIG_COMPAT.update({
Victor Stinner6d1c4672019-05-20 11:02:00 +0200336 'legacy_windows_fs_encoding': 0,
337 })
Victor Stinner022be022019-05-22 23:58:50 +0200338 PRE_CONFIG_PYTHON = dict(PRE_CONFIG_COMPAT,
Victor Stinner20e1e252019-05-23 04:12:27 +0200339 _config_init=API_PYTHON,
Victor Stinner6d1c4672019-05-20 11:02:00 +0200340 parse_argv=1,
Victor Stinner425717f2019-05-20 16:38:48 +0200341 coerce_c_locale=GET_DEFAULT_CONFIG,
342 utf8_mode=GET_DEFAULT_CONFIG,
Victor Stinner6d1c4672019-05-20 11:02:00 +0200343 )
Victor Stinner022be022019-05-22 23:58:50 +0200344 PRE_CONFIG_ISOLATED = dict(PRE_CONFIG_COMPAT,
Victor Stinner20e1e252019-05-23 04:12:27 +0200345 _config_init=API_ISOLATED,
Victor Stinnerbab0db62019-05-18 03:21:27 +0200346 configure_locale=0,
347 isolated=1,
348 use_environment=0,
349 utf8_mode=0,
350 dev_mode=0,
Victor Stinner425717f2019-05-20 16:38:48 +0200351 coerce_c_locale=0,
Victor Stinnerbab0db62019-05-18 03:21:27 +0200352 )
Victor Stinnerbab0db62019-05-18 03:21:27 +0200353
Victor Stinner20004952019-03-26 02:31:11 +0100354 COPY_PRE_CONFIG = [
355 'dev_mode',
356 'isolated',
357 'use_environment',
358 ]
359
Victor Stinner331a6a52019-05-27 16:39:22 +0200360 CONFIG_COMPAT = {
Victor Stinner022be022019-05-22 23:58:50 +0200361 '_config_init': API_COMPAT,
Victor Stinner20004952019-03-26 02:31:11 +0100362 'isolated': 0,
363 'use_environment': 1,
364 'dev_mode': 0,
365
Victor Stinner56b29b62018-07-26 18:57:56 +0200366 'install_signal_handlers': 1,
Victor Stinner56b29b62018-07-26 18:57:56 +0200367 'use_hash_seed': 0,
368 'hash_seed': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200369 'faulthandler': 0,
370 'tracemalloc': 0,
371 'import_time': 0,
372 'show_ref_count': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200373 'dump_refs': 0,
374 'malloc_stats': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200375
Victor Stinnera6537fb2018-11-26 11:54:12 +0100376 'filesystem_encoding': GET_DEFAULT_CONFIG,
377 'filesystem_errors': GET_DEFAULT_CONFIG,
Victor Stinnerc5989cd2018-08-29 19:32:47 +0200378
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100379 'pycache_prefix': None,
Victor Stinner91c99872019-05-14 22:01:51 +0200380 'program_name': GET_DEFAULT_CONFIG,
Victor Stinnercab5d072019-05-17 19:01:14 +0200381 'parse_argv': 0,
Victor Stinner62599762019-03-15 16:03:23 +0100382 'argv': [""],
Victor Stinnerdd8a93e2020-06-30 00:49:03 +0200383 'orig_argv': [],
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100384
385 'xoptions': [],
386 'warnoptions': [],
Victor Stinner56b29b62018-07-26 18:57:56 +0200387
Victor Stinner331a6a52019-05-27 16:39:22 +0200388 'pythonpath_env': None,
Victor Stinner01de89c2018-11-14 17:39:45 +0100389 'home': None,
Victor Stinner91c99872019-05-14 22:01:51 +0200390 'executable': GET_DEFAULT_CONFIG,
Steve Dower9048c492019-06-29 10:34:11 -0700391 'base_executable': GET_DEFAULT_CONFIG,
Victor Stinnera6537fb2018-11-26 11:54:12 +0100392
393 'prefix': GET_DEFAULT_CONFIG,
394 'base_prefix': GET_DEFAULT_CONFIG,
395 'exec_prefix': GET_DEFAULT_CONFIG,
396 'base_exec_prefix': GET_DEFAULT_CONFIG,
Victor Stinner5eb8b072019-05-15 02:12:48 +0200397 'module_search_paths': GET_DEFAULT_CONFIG,
Victor Stinnerf3cb8142020-11-05 18:12:33 +0100398 'module_search_paths_set': 1,
Sandro Mani8f023a22020-06-08 17:28:11 +0200399 'platlibdir': sys.platlibdir,
Victor Stinner01de89c2018-11-14 17:39:45 +0100400
Victor Stinner56b29b62018-07-26 18:57:56 +0200401 'site_import': 1,
402 'bytes_warning': 0,
Inada Naoki48274832021-03-29 12:28:14 +0900403 'warn_default_encoding': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200404 'inspect': 0,
405 'interactive': 0,
406 'optimization_level': 0,
Victor Stinner98512272018-08-01 03:07:00 +0200407 'parser_debug': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200408 'write_bytecode': 1,
409 'verbose': 0,
410 'quiet': 0,
411 'user_site_directory': 1,
Victor Stinnercab5d072019-05-17 19:01:14 +0200412 'configure_c_stdio': 0,
Victor Stinner98512272018-08-01 03:07:00 +0200413 'buffered_stdio': 1,
Victor Stinnerc5989cd2018-08-29 19:32:47 +0200414
Victor Stinnera6537fb2018-11-26 11:54:12 +0100415 'stdio_encoding': GET_DEFAULT_CONFIG,
416 'stdio_errors': GET_DEFAULT_CONFIG,
Victor Stinner56b29b62018-07-26 18:57:56 +0200417
Victor Stinner62be7632019-03-01 13:10:14 +0100418 'skip_source_first_line': 0,
419 'run_command': None,
420 'run_module': None,
421 'run_filename': None,
422
Victor Stinner56b29b62018-07-26 18:57:56 +0200423 '_install_importlib': 1,
Victor Stinnercb9fbd32019-05-01 23:51:56 -0400424 'check_hash_pycs_mode': 'default',
Victor Stinner9ef5dca2019-05-16 17:38:16 +0200425 'pathconfig_warnings': 1,
426 '_init_main': 1,
Victor Stinner252346a2020-05-01 11:33:44 +0200427 '_isolated_interpreter': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200428 }
Victor Stinner01de89c2018-11-14 17:39:45 +0100429 if MS_WINDOWS:
Victor Stinner331a6a52019-05-27 16:39:22 +0200430 CONFIG_COMPAT.update({
Victor Stinner01de89c2018-11-14 17:39:45 +0100431 'legacy_windows_stdio': 0,
432 })
433
Victor Stinner331a6a52019-05-27 16:39:22 +0200434 CONFIG_PYTHON = dict(CONFIG_COMPAT,
Victor Stinner20e1e252019-05-23 04:12:27 +0200435 _config_init=API_PYTHON,
Victor Stinnerbab0db62019-05-18 03:21:27 +0200436 configure_c_stdio=1,
Victor Stinnerdc42af82020-11-05 18:58:07 +0100437 parse_argv=2,
Victor Stinnerbab0db62019-05-18 03:21:27 +0200438 )
Victor Stinner331a6a52019-05-27 16:39:22 +0200439 CONFIG_ISOLATED = dict(CONFIG_COMPAT,
Victor Stinner20e1e252019-05-23 04:12:27 +0200440 _config_init=API_ISOLATED,
Victor Stinnerbab0db62019-05-18 03:21:27 +0200441 isolated=1,
442 use_environment=0,
443 user_site_directory=0,
444 dev_mode=0,
445 install_signal_handlers=0,
446 use_hash_seed=0,
447 faulthandler=0,
448 tracemalloc=0,
449 pathconfig_warnings=0,
450 )
451 if MS_WINDOWS:
Victor Stinner331a6a52019-05-27 16:39:22 +0200452 CONFIG_ISOLATED['legacy_windows_stdio'] = 0
Victor Stinnerbab0db62019-05-18 03:21:27 +0200453
Victor Stinner01de89c2018-11-14 17:39:45 +0100454 # global config
455 DEFAULT_GLOBAL_CONFIG = {
456 'Py_HasFileSystemDefaultEncoding': 0,
457 'Py_HashRandomizationFlag': 1,
458 '_Py_HasFileSystemDefaultEncodeErrors': 0,
459 }
Victor Stinner1075d162019-03-25 23:19:57 +0100460 COPY_GLOBAL_PRE_CONFIG = [
Victor Stinner1075d162019-03-25 23:19:57 +0100461 ('Py_UTF8Mode', 'utf8_mode'),
462 ]
Victor Stinner01de89c2018-11-14 17:39:45 +0100463 COPY_GLOBAL_CONFIG = [
464 # Copy core config to global config for expected values
465 # True means that the core config value is inverted (0 => 1 and 1 => 0)
466 ('Py_BytesWarningFlag', 'bytes_warning'),
467 ('Py_DebugFlag', 'parser_debug'),
468 ('Py_DontWriteBytecodeFlag', 'write_bytecode', True),
469 ('Py_FileSystemDefaultEncodeErrors', 'filesystem_errors'),
470 ('Py_FileSystemDefaultEncoding', 'filesystem_encoding'),
Victor Stinner9ef5dca2019-05-16 17:38:16 +0200471 ('Py_FrozenFlag', 'pathconfig_warnings', True),
Victor Stinner20004952019-03-26 02:31:11 +0100472 ('Py_IgnoreEnvironmentFlag', 'use_environment', True),
Victor Stinner01de89c2018-11-14 17:39:45 +0100473 ('Py_InspectFlag', 'inspect'),
474 ('Py_InteractiveFlag', 'interactive'),
Victor Stinner20004952019-03-26 02:31:11 +0100475 ('Py_IsolatedFlag', 'isolated'),
Victor Stinner01de89c2018-11-14 17:39:45 +0100476 ('Py_NoSiteFlag', 'site_import', True),
477 ('Py_NoUserSiteDirectory', 'user_site_directory', True),
478 ('Py_OptimizeFlag', 'optimization_level'),
479 ('Py_QuietFlag', 'quiet'),
Victor Stinner01de89c2018-11-14 17:39:45 +0100480 ('Py_UnbufferedStdioFlag', 'buffered_stdio', True),
481 ('Py_VerboseFlag', 'verbose'),
482 ]
483 if MS_WINDOWS:
Victor Stinner1075d162019-03-25 23:19:57 +0100484 COPY_GLOBAL_PRE_CONFIG.extend((
Victor Stinner01de89c2018-11-14 17:39:45 +0100485 ('Py_LegacyWindowsFSEncodingFlag', 'legacy_windows_fs_encoding'),
Victor Stinner1075d162019-03-25 23:19:57 +0100486 ))
487 COPY_GLOBAL_CONFIG.extend((
Victor Stinner01de89c2018-11-14 17:39:45 +0100488 ('Py_LegacyWindowsStdioFlag', 'legacy_windows_stdio'),
489 ))
Victor Stinner56b29b62018-07-26 18:57:56 +0200490
Victor Stinner8f427482020-07-08 00:20:37 +0200491 # path config
492 if MS_WINDOWS:
493 PATH_CONFIG = {
494 'isolated': -1,
495 'site_import': -1,
496 'python3_dll': GET_DEFAULT_CONFIG,
497 }
498 else:
499 PATH_CONFIG = {}
500 # other keys are copied by COPY_PATH_CONFIG
501
502 COPY_PATH_CONFIG = [
503 # Copy core config to global config for expected values
504 'prefix',
505 'exec_prefix',
506 'program_name',
507 'home',
508 # program_full_path and module_search_path are copied indirectly from
509 # the core configuration in check_path_config().
510 ]
511 if MS_WINDOWS:
512 COPY_PATH_CONFIG.extend((
513 'base_executable',
514 ))
515
Victor Stinner425717f2019-05-20 16:38:48 +0200516 EXPECTED_CONFIG = None
517
Victor Stinner52ad33a2019-09-25 02:10:35 +0200518 @classmethod
519 def tearDownClass(cls):
520 # clear cache
521 cls.EXPECTED_CONFIG = None
522
Victor Stinner01de89c2018-11-14 17:39:45 +0100523 def main_xoptions(self, xoptions_list):
524 xoptions = {}
525 for opt in xoptions_list:
526 if '=' in opt:
527 key, value = opt.split('=', 1)
528 xoptions[key] = value
529 else:
530 xoptions[opt] = True
531 return xoptions
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200532
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +0200533 def _get_expected_config_impl(self):
534 env = remove_python_envvars()
Victor Stinnera6537fb2018-11-26 11:54:12 +0100535 code = textwrap.dedent('''
536 import json
Victor Stinnera6537fb2018-11-26 11:54:12 +0100537 import sys
Victor Stinner5eb8b072019-05-15 02:12:48 +0200538 import _testinternalcapi
Victor Stinnera6537fb2018-11-26 11:54:12 +0100539
Victor Stinner5eb8b072019-05-15 02:12:48 +0200540 configs = _testinternalcapi.get_configs()
Victor Stinnera6537fb2018-11-26 11:54:12 +0100541
Victor Stinner425717f2019-05-20 16:38:48 +0200542 data = json.dumps(configs)
Victor Stinnera6537fb2018-11-26 11:54:12 +0100543 data = data.encode('utf-8')
544 sys.stdout.buffer.write(data)
545 sys.stdout.buffer.flush()
546 ''')
547
548 # Use -S to not import the site module: get the proper configuration
549 # when test_embed is run from a venv (bpo-35313)
Victor Stinner5eb8b072019-05-15 02:12:48 +0200550 args = [sys.executable, '-S', '-c', code]
Victor Stinnera6537fb2018-11-26 11:54:12 +0100551 proc = subprocess.run(args, env=env,
552 stdout=subprocess.PIPE,
Victor Stinner52ad33a2019-09-25 02:10:35 +0200553 stderr=subprocess.PIPE)
Victor Stinnera6537fb2018-11-26 11:54:12 +0100554 if proc.returncode:
555 raise Exception(f"failed to get the default config: "
556 f"stdout={proc.stdout!r} stderr={proc.stderr!r}")
557 stdout = proc.stdout.decode('utf-8')
Victor Stinner52ad33a2019-09-25 02:10:35 +0200558 # ignore stderr
Victor Stinner4631da12019-05-02 15:30:21 -0400559 try:
Victor Stinner425717f2019-05-20 16:38:48 +0200560 return json.loads(stdout)
Victor Stinner4631da12019-05-02 15:30:21 -0400561 except json.JSONDecodeError:
562 self.fail(f"fail to decode stdout: {stdout!r}")
Victor Stinnera6537fb2018-11-26 11:54:12 +0100563
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +0200564 def _get_expected_config(self):
565 cls = InitConfigTests
566 if cls.EXPECTED_CONFIG is None:
567 cls.EXPECTED_CONFIG = self._get_expected_config_impl()
568
569 # get a copy
Victor Stinner52ad33a2019-09-25 02:10:35 +0200570 configs = {}
571 for config_key, config_value in cls.EXPECTED_CONFIG.items():
572 config = {}
573 for key, value in config_value.items():
574 if isinstance(value, list):
575 value = value.copy()
576 config[key] = value
577 configs[config_key] = config
578 return configs
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +0200579
Victor Stinner8f427482020-07-08 00:20:37 +0200580 def get_expected_config(self, expected_preconfig, expected,
581 expected_pathconfig, env, api,
Victor Stinner3842f292019-08-23 16:57:54 +0100582 modify_path_cb=None):
Victor Stinner425717f2019-05-20 16:38:48 +0200583 cls = self.__class__
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +0200584 configs = self._get_expected_config()
Victor Stinner425717f2019-05-20 16:38:48 +0200585
586 pre_config = configs['pre_config']
587 for key, value in expected_preconfig.items():
588 if value is self.GET_DEFAULT_CONFIG:
589 expected_preconfig[key] = pre_config[key]
590
Victor Stinner8f427482020-07-08 00:20:37 +0200591 path_config = configs['path_config']
592 for key, value in expected_pathconfig.items():
593 if value is self.GET_DEFAULT_CONFIG:
594 expected_pathconfig[key] = path_config[key]
595
Victor Stinner022be022019-05-22 23:58:50 +0200596 if not expected_preconfig['configure_locale'] or api == API_COMPAT:
Victor Stinner425717f2019-05-20 16:38:48 +0200597 # there is no easy way to get the locale encoding before
598 # setlocale(LC_CTYPE, "") is called: don't test encodings
599 for key in ('filesystem_encoding', 'filesystem_errors',
600 'stdio_encoding', 'stdio_errors'):
601 expected[key] = self.IGNORE_CONFIG
602
603 if not expected_preconfig['configure_locale']:
604 # UTF-8 Mode depends on the locale. There is no easy way
605 # to guess if UTF-8 Mode will be enabled or not if the locale
606 # is not configured.
607 expected_preconfig['utf8_mode'] = self.IGNORE_CONFIG
608
609 if expected_preconfig['utf8_mode'] == 1:
610 if expected['filesystem_encoding'] is self.GET_DEFAULT_CONFIG:
611 expected['filesystem_encoding'] = 'utf-8'
612 if expected['filesystem_errors'] is self.GET_DEFAULT_CONFIG:
613 expected['filesystem_errors'] = self.UTF8_MODE_ERRORS
614 if expected['stdio_encoding'] is self.GET_DEFAULT_CONFIG:
615 expected['stdio_encoding'] = 'utf-8'
616 if expected['stdio_errors'] is self.GET_DEFAULT_CONFIG:
617 expected['stdio_errors'] = 'surrogateescape'
618
Steve Dowerdcbaa1b2020-07-06 17:32:00 +0100619 if MS_WINDOWS:
Steve Dower9048c492019-06-29 10:34:11 -0700620 default_executable = self.test_exe
621 elif expected['program_name'] is not self.GET_DEFAULT_CONFIG:
622 default_executable = os.path.abspath(expected['program_name'])
623 else:
624 default_executable = os.path.join(os.getcwd(), '_testembed')
Victor Stinner91c99872019-05-14 22:01:51 +0200625 if expected['executable'] is self.GET_DEFAULT_CONFIG:
Steve Dower9048c492019-06-29 10:34:11 -0700626 expected['executable'] = default_executable
627 if expected['base_executable'] is self.GET_DEFAULT_CONFIG:
628 expected['base_executable'] = default_executable
Victor Stinner91c99872019-05-14 22:01:51 +0200629 if expected['program_name'] is self.GET_DEFAULT_CONFIG:
630 expected['program_name'] = './_testembed'
631
Victor Stinner331a6a52019-05-27 16:39:22 +0200632 config = configs['config']
Victor Stinnera6537fb2018-11-26 11:54:12 +0100633 for key, value in expected.items():
634 if value is self.GET_DEFAULT_CONFIG:
Victor Stinner331a6a52019-05-27 16:39:22 +0200635 expected[key] = config[key]
Victor Stinner5eb8b072019-05-15 02:12:48 +0200636
Sandro Mani8f023a22020-06-08 17:28:11 +0200637 if expected['module_search_paths'] is not self.IGNORE_CONFIG:
638 pythonpath_env = expected['pythonpath_env']
639 if pythonpath_env is not None:
640 paths = pythonpath_env.split(os.path.pathsep)
641 expected['module_search_paths'] = [*paths, *expected['module_search_paths']]
642 if modify_path_cb is not None:
643 expected['module_search_paths'] = expected['module_search_paths'].copy()
644 modify_path_cb(expected['module_search_paths'])
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200645
Victor Stinner425717f2019-05-20 16:38:48 +0200646 for key in self.COPY_PRE_CONFIG:
647 if key not in expected_preconfig:
648 expected_preconfig[key] = expected[key]
Victor Stinner01de89c2018-11-14 17:39:45 +0100649
Victor Stinner331a6a52019-05-27 16:39:22 +0200650 def check_pre_config(self, configs, expected):
651 pre_config = dict(configs['pre_config'])
Victor Stinner425717f2019-05-20 16:38:48 +0200652 for key, value in list(expected.items()):
653 if value is self.IGNORE_CONFIG:
Steve Dowerdcbaa1b2020-07-06 17:32:00 +0100654 pre_config.pop(key, None)
Victor Stinner425717f2019-05-20 16:38:48 +0200655 del expected[key]
656 self.assertEqual(pre_config, expected)
Victor Stinner1075d162019-03-25 23:19:57 +0100657
Victor Stinner331a6a52019-05-27 16:39:22 +0200658 def check_config(self, configs, expected):
659 config = dict(configs['config'])
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200660 for key, value in list(expected.items()):
661 if value is self.IGNORE_CONFIG:
Steve Dowerdcbaa1b2020-07-06 17:32:00 +0100662 config.pop(key, None)
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200663 del expected[key]
Victor Stinner331a6a52019-05-27 16:39:22 +0200664 self.assertEqual(config, expected)
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200665
Victor Stinner331a6a52019-05-27 16:39:22 +0200666 def check_global_config(self, configs):
667 pre_config = configs['pre_config']
668 config = configs['config']
Victor Stinner00b137c2018-11-13 19:59:26 +0100669
Victor Stinnera6537fb2018-11-26 11:54:12 +0100670 expected = dict(self.DEFAULT_GLOBAL_CONFIG)
Victor Stinner01de89c2018-11-14 17:39:45 +0100671 for item in self.COPY_GLOBAL_CONFIG:
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100672 if len(item) == 3:
673 global_key, core_key, opposite = item
Victor Stinner331a6a52019-05-27 16:39:22 +0200674 expected[global_key] = 0 if config[core_key] else 1
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100675 else:
676 global_key, core_key = item
Victor Stinner331a6a52019-05-27 16:39:22 +0200677 expected[global_key] = config[core_key]
Victor Stinner1075d162019-03-25 23:19:57 +0100678 for item in self.COPY_GLOBAL_PRE_CONFIG:
679 if len(item) == 3:
680 global_key, core_key, opposite = item
681 expected[global_key] = 0 if pre_config[core_key] else 1
682 else:
683 global_key, core_key = item
684 expected[global_key] = pre_config[core_key]
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100685
Victor Stinner331a6a52019-05-27 16:39:22 +0200686 self.assertEqual(configs['global_config'], expected)
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100687
Victor Stinner8f427482020-07-08 00:20:37 +0200688 def check_path_config(self, configs, expected):
689 config = configs['config']
690
691 for key in self.COPY_PATH_CONFIG:
692 expected[key] = config[key]
693 expected['module_search_path'] = os.path.pathsep.join(config['module_search_paths'])
694 expected['program_full_path'] = config['executable']
695
696 self.assertEqual(configs['path_config'], expected)
697
Victor Stinner331a6a52019-05-27 16:39:22 +0200698 def check_all_configs(self, testname, expected_config=None,
Victor Stinner8f427482020-07-08 00:20:37 +0200699 expected_preconfig=None, expected_pathconfig=None,
700 modify_path_cb=None,
Victor Stinner8bf39b62019-09-26 02:22:35 +0200701 stderr=None, *, api, preconfig_api=None,
702 env=None, ignore_stderr=False, cwd=None):
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +0200703 new_env = remove_python_envvars()
704 if env is not None:
705 new_env.update(env)
706 env = new_env
Victor Stinner01de89c2018-11-14 17:39:45 +0100707
Victor Stinner8bf39b62019-09-26 02:22:35 +0200708 if preconfig_api is None:
709 preconfig_api = api
710 if preconfig_api == API_ISOLATED:
Victor Stinner022be022019-05-22 23:58:50 +0200711 default_preconfig = self.PRE_CONFIG_ISOLATED
Victor Stinner8bf39b62019-09-26 02:22:35 +0200712 elif preconfig_api == API_PYTHON:
Victor Stinner022be022019-05-22 23:58:50 +0200713 default_preconfig = self.PRE_CONFIG_PYTHON
Victor Stinnerbab0db62019-05-18 03:21:27 +0200714 else:
Victor Stinner022be022019-05-22 23:58:50 +0200715 default_preconfig = self.PRE_CONFIG_COMPAT
Victor Stinnerbab0db62019-05-18 03:21:27 +0200716 if expected_preconfig is None:
717 expected_preconfig = {}
718 expected_preconfig = dict(default_preconfig, **expected_preconfig)
Victor Stinner8f427482020-07-08 00:20:37 +0200719
Victor Stinnerbab0db62019-05-18 03:21:27 +0200720 if expected_config is None:
721 expected_config = {}
Victor Stinner425717f2019-05-20 16:38:48 +0200722
Victor Stinner8f427482020-07-08 00:20:37 +0200723 if expected_pathconfig is None:
724 expected_pathconfig = {}
725 expected_pathconfig = dict(self.PATH_CONFIG, **expected_pathconfig)
726
Victor Stinner022be022019-05-22 23:58:50 +0200727 if api == API_PYTHON:
Victor Stinner331a6a52019-05-27 16:39:22 +0200728 default_config = self.CONFIG_PYTHON
Victor Stinner022be022019-05-22 23:58:50 +0200729 elif api == API_ISOLATED:
Victor Stinner331a6a52019-05-27 16:39:22 +0200730 default_config = self.CONFIG_ISOLATED
Victor Stinner425717f2019-05-20 16:38:48 +0200731 else:
Victor Stinner331a6a52019-05-27 16:39:22 +0200732 default_config = self.CONFIG_COMPAT
Victor Stinner425717f2019-05-20 16:38:48 +0200733 expected_config = dict(default_config, **expected_config)
Victor Stinner425717f2019-05-20 16:38:48 +0200734
735 self.get_expected_config(expected_preconfig,
Victor Stinner8f427482020-07-08 00:20:37 +0200736 expected_config,
737 expected_pathconfig,
738 env,
Victor Stinner3842f292019-08-23 16:57:54 +0100739 api, modify_path_cb)
Victor Stinner1075d162019-03-25 23:19:57 +0100740
Victor Stinner52ad33a2019-09-25 02:10:35 +0200741 out, err = self.run_embedded_interpreter(testname,
742 env=env, cwd=cwd)
Victor Stinner9ef5dca2019-05-16 17:38:16 +0200743 if stderr is None and not expected_config['verbose']:
744 stderr = ""
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +0200745 if stderr is not None and not ignore_stderr:
Victor Stinner9ef5dca2019-05-16 17:38:16 +0200746 self.assertEqual(err.rstrip(), stderr)
747 try:
Victor Stinner331a6a52019-05-27 16:39:22 +0200748 configs = json.loads(out)
Victor Stinner9ef5dca2019-05-16 17:38:16 +0200749 except json.JSONDecodeError:
750 self.fail(f"fail to decode stdout: {out!r}")
751
Victor Stinner331a6a52019-05-27 16:39:22 +0200752 self.check_pre_config(configs, expected_preconfig)
753 self.check_config(configs, expected_config)
754 self.check_global_config(configs)
Victor Stinner8f427482020-07-08 00:20:37 +0200755 self.check_path_config(configs, expected_pathconfig)
Steve Dowerdcbaa1b2020-07-06 17:32:00 +0100756 return configs
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100757
Victor Stinner56b29b62018-07-26 18:57:56 +0200758 def test_init_default_config(self):
Victor Stinner331a6a52019-05-27 16:39:22 +0200759 self.check_all_configs("test_init_initialize_config", api=API_COMPAT)
Victor Stinner022be022019-05-22 23:58:50 +0200760
761 def test_preinit_compat_config(self):
Victor Stinner331a6a52019-05-27 16:39:22 +0200762 self.check_all_configs("test_preinit_compat_config", api=API_COMPAT)
Victor Stinner022be022019-05-22 23:58:50 +0200763
764 def test_init_compat_config(self):
Victor Stinner331a6a52019-05-27 16:39:22 +0200765 self.check_all_configs("test_init_compat_config", api=API_COMPAT)
Victor Stinner56b29b62018-07-26 18:57:56 +0200766
767 def test_init_global_config(self):
Victor Stinner1075d162019-03-25 23:19:57 +0100768 preconfig = {
769 'utf8_mode': 1,
770 }
Victor Stinner56b29b62018-07-26 18:57:56 +0200771 config = {
772 'program_name': './globalvar',
773 'site_import': 0,
774 'bytes_warning': 1,
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100775 'warnoptions': ['default::BytesWarning'],
Victor Stinner56b29b62018-07-26 18:57:56 +0200776 'inspect': 1,
777 'interactive': 1,
778 'optimization_level': 2,
779 'write_bytecode': 0,
780 'verbose': 1,
781 'quiet': 1,
Victor Stinner98512272018-08-01 03:07:00 +0200782 'buffered_stdio': 0,
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200783
Victor Stinner56b29b62018-07-26 18:57:56 +0200784 'user_site_directory': 0,
Victor Stinner54b43bb2019-05-16 18:30:15 +0200785 'pathconfig_warnings': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200786 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200787 self.check_all_configs("test_init_global_config", config, preconfig,
788 api=API_COMPAT)
Victor Stinner56b29b62018-07-26 18:57:56 +0200789
790 def test_init_from_config(self):
Victor Stinner1075d162019-03-25 23:19:57 +0100791 preconfig = {
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200792 'allocator': PYMEM_ALLOCATOR_MALLOC,
Victor Stinner1075d162019-03-25 23:19:57 +0100793 'utf8_mode': 1,
794 }
Victor Stinner56b29b62018-07-26 18:57:56 +0200795 config = {
796 'install_signal_handlers': 0,
797 'use_hash_seed': 1,
798 'hash_seed': 123,
Victor Stinner56b29b62018-07-26 18:57:56 +0200799 'tracemalloc': 2,
800 'import_time': 1,
801 'show_ref_count': 1,
Victor Stinner56b29b62018-07-26 18:57:56 +0200802 'malloc_stats': 1,
803
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200804 'stdio_encoding': 'iso8859-1',
805 'stdio_errors': 'replace',
Victor Stinner56b29b62018-07-26 18:57:56 +0200806
807 'pycache_prefix': 'conf_pycache_prefix',
808 'program_name': './conf_program_name',
Victor Stinnere81f6e62020-06-08 18:12:59 +0200809 'argv': ['-c', 'arg2'],
Victor Stinnerdd8a93e2020-06-30 00:49:03 +0200810 'orig_argv': ['python3',
811 '-W', 'cmdline_warnoption',
812 '-X', 'cmdline_xoption',
813 '-c', 'pass',
814 'arg2'],
Victor Stinnerdc42af82020-11-05 18:58:07 +0100815 'parse_argv': 2,
Victor Stinner67310022019-07-01 19:52:45 +0200816 'xoptions': [
817 'config_xoption1=3',
818 'config_xoption2=',
819 'config_xoption3',
820 'cmdline_xoption',
821 ],
822 'warnoptions': [
Victor Stinner67310022019-07-01 19:52:45 +0200823 'cmdline_warnoption',
824 'default::BytesWarning',
Victor Stinnerfb4ae152019-09-30 01:40:17 +0200825 'config_warnoption',
Victor Stinner67310022019-07-01 19:52:45 +0200826 ],
Victor Stinner2f549082019-03-29 15:13:46 +0100827 'run_command': 'pass\n',
Victor Stinner56b29b62018-07-26 18:57:56 +0200828
829 'site_import': 0,
830 'bytes_warning': 1,
831 'inspect': 1,
832 'interactive': 1,
833 'optimization_level': 2,
834 'write_bytecode': 0,
835 'verbose': 1,
836 'quiet': 1,
Victor Stinnercab5d072019-05-17 19:01:14 +0200837 'configure_c_stdio': 1,
Victor Stinner98512272018-08-01 03:07:00 +0200838 'buffered_stdio': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200839 'user_site_directory': 0,
840 'faulthandler': 1,
Sandro Mani8f023a22020-06-08 17:28:11 +0200841 'platlibdir': 'my_platlibdir',
842 'module_search_paths': self.IGNORE_CONFIG,
Victor Stinnerb75d7e22018-08-01 02:13:04 +0200843
Victor Stinnercb9fbd32019-05-01 23:51:56 -0400844 'check_hash_pycs_mode': 'always',
Victor Stinner54b43bb2019-05-16 18:30:15 +0200845 'pathconfig_warnings': 0,
Victor Stinner252346a2020-05-01 11:33:44 +0200846
847 '_isolated_interpreter': 1,
Victor Stinner56b29b62018-07-26 18:57:56 +0200848 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200849 self.check_all_configs("test_init_from_config", config, preconfig,
850 api=API_COMPAT)
Victor Stinner56b29b62018-07-26 18:57:56 +0200851
Victor Stinner20e1e252019-05-23 04:12:27 +0200852 def test_init_compat_env(self):
853 preconfig = {
854 'allocator': PYMEM_ALLOCATOR_MALLOC,
855 }
856 config = {
857 'use_hash_seed': 1,
858 'hash_seed': 42,
859 'tracemalloc': 2,
860 'import_time': 1,
861 'malloc_stats': 1,
862 'inspect': 1,
863 'optimization_level': 2,
Victor Stinner331a6a52019-05-27 16:39:22 +0200864 'pythonpath_env': '/my/path',
Victor Stinner20e1e252019-05-23 04:12:27 +0200865 'pycache_prefix': 'env_pycache_prefix',
866 'write_bytecode': 0,
867 'verbose': 1,
868 'buffered_stdio': 0,
869 'stdio_encoding': 'iso8859-1',
870 'stdio_errors': 'replace',
871 'user_site_directory': 0,
872 'faulthandler': 1,
873 'warnoptions': ['EnvVar'],
Sandro Mani8f023a22020-06-08 17:28:11 +0200874 'platlibdir': 'env_platlibdir',
875 'module_search_paths': self.IGNORE_CONFIG,
Victor Stinner20e1e252019-05-23 04:12:27 +0200876 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200877 self.check_all_configs("test_init_compat_env", config, preconfig,
878 api=API_COMPAT)
Victor Stinner20e1e252019-05-23 04:12:27 +0200879
880 def test_init_python_env(self):
Victor Stinner425717f2019-05-20 16:38:48 +0200881 preconfig = {
882 'allocator': PYMEM_ALLOCATOR_MALLOC,
Victor Stinner022be022019-05-22 23:58:50 +0200883 'utf8_mode': 1,
Victor Stinner425717f2019-05-20 16:38:48 +0200884 }
885 config = {
886 'use_hash_seed': 1,
887 'hash_seed': 42,
888 'tracemalloc': 2,
889 'import_time': 1,
890 'malloc_stats': 1,
891 'inspect': 1,
892 'optimization_level': 2,
Victor Stinner331a6a52019-05-27 16:39:22 +0200893 'pythonpath_env': '/my/path',
Victor Stinner425717f2019-05-20 16:38:48 +0200894 'pycache_prefix': 'env_pycache_prefix',
895 'write_bytecode': 0,
896 'verbose': 1,
897 'buffered_stdio': 0,
898 'stdio_encoding': 'iso8859-1',
899 'stdio_errors': 'replace',
900 'user_site_directory': 0,
901 'faulthandler': 1,
902 'warnoptions': ['EnvVar'],
Sandro Mani8f023a22020-06-08 17:28:11 +0200903 'platlibdir': 'env_platlibdir',
904 'module_search_paths': self.IGNORE_CONFIG,
Victor Stinner425717f2019-05-20 16:38:48 +0200905 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200906 self.check_all_configs("test_init_python_env", config, preconfig,
907 api=API_PYTHON)
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100908
909 def test_init_env_dev_mode(self):
Victor Stinner425717f2019-05-20 16:38:48 +0200910 preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG)
911 config = dict(dev_mode=1,
912 faulthandler=1,
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100913 warnoptions=['default'])
Victor Stinner331a6a52019-05-27 16:39:22 +0200914 self.check_all_configs("test_init_env_dev_mode", config, preconfig,
915 api=API_COMPAT)
Victor Stinner56b29b62018-07-26 18:57:56 +0200916
Victor Stinner20004952019-03-26 02:31:11 +0100917 def test_init_env_dev_mode_alloc(self):
Victor Stinner425717f2019-05-20 16:38:48 +0200918 preconfig = dict(allocator=PYMEM_ALLOCATOR_MALLOC)
919 config = dict(dev_mode=1,
920 faulthandler=1,
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100921 warnoptions=['default'])
Victor Stinner331a6a52019-05-27 16:39:22 +0200922 self.check_all_configs("test_init_env_dev_mode_alloc", config, preconfig,
923 api=API_COMPAT)
Victor Stinner25d13f32019-03-06 12:51:53 +0100924
Victor Stinner56b29b62018-07-26 18:57:56 +0200925 def test_init_dev_mode(self):
Victor Stinner1075d162019-03-25 23:19:57 +0100926 preconfig = {
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200927 'allocator': PYMEM_ALLOCATOR_DEBUG,
Victor Stinner56b29b62018-07-26 18:57:56 +0200928 }
Victor Stinner1075d162019-03-25 23:19:57 +0100929 config = {
930 'faulthandler': 1,
Victor Stinner20004952019-03-26 02:31:11 +0100931 'dev_mode': 1,
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100932 'warnoptions': ['default'],
Victor Stinner1075d162019-03-25 23:19:57 +0100933 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200934 self.check_all_configs("test_init_dev_mode", config, preconfig,
935 api=API_PYTHON)
Victor Stinner6d1c4672019-05-20 11:02:00 +0200936
937 def test_preinit_parse_argv(self):
938 # Pre-initialize implicitly using argv: make sure that -X dev
939 # is used to configure the allocation in preinitialization
940 preconfig = {
941 'allocator': PYMEM_ALLOCATOR_DEBUG,
942 }
943 config = {
Victor Stinnera1a99b42019-12-09 17:34:02 +0100944 'argv': ['script.py'],
Victor Stinnerdd8a93e2020-06-30 00:49:03 +0200945 'orig_argv': ['python3', '-X', 'dev', 'script.py'],
Victor Stinnera1a99b42019-12-09 17:34:02 +0100946 'run_filename': os.path.abspath('script.py'),
Victor Stinner6d1c4672019-05-20 11:02:00 +0200947 'dev_mode': 1,
948 'faulthandler': 1,
949 'warnoptions': ['default'],
950 'xoptions': ['dev'],
951 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200952 self.check_all_configs("test_preinit_parse_argv", config, preconfig,
953 api=API_PYTHON)
Victor Stinner6d1c4672019-05-20 11:02:00 +0200954
955 def test_preinit_dont_parse_argv(self):
956 # -X dev must be ignored by isolated preconfiguration
957 preconfig = {
958 'isolated': 0,
959 }
Victor Stinnere81f6e62020-06-08 18:12:59 +0200960 argv = ["python3",
961 "-E", "-I",
962 "-X", "dev",
963 "-X", "utf8",
964 "script.py"]
Victor Stinner6d1c4672019-05-20 11:02:00 +0200965 config = {
Victor Stinnere81f6e62020-06-08 18:12:59 +0200966 'argv': argv,
Victor Stinnerdd8a93e2020-06-30 00:49:03 +0200967 'orig_argv': argv,
Victor Stinner6d1c4672019-05-20 11:02:00 +0200968 'isolated': 0,
969 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200970 self.check_all_configs("test_preinit_dont_parse_argv", config, preconfig,
971 api=API_ISOLATED)
Victor Stinner56b29b62018-07-26 18:57:56 +0200972
Victor Stinnercab5d072019-05-17 19:01:14 +0200973 def test_init_isolated_flag(self):
Victor Stinner1075d162019-03-25 23:19:57 +0100974 config = {
Victor Stinner20004952019-03-26 02:31:11 +0100975 'isolated': 1,
976 'use_environment': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200977 'user_site_directory': 0,
978 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200979 self.check_all_configs("test_init_isolated_flag", config, api=API_PYTHON)
Victor Stinner56b29b62018-07-26 18:57:56 +0200980
Victor Stinner6da20a42019-03-27 00:26:18 +0100981 def test_preinit_isolated1(self):
982 # _PyPreConfig.isolated=1, _PyCoreConfig.isolated not set
Victor Stinner6da20a42019-03-27 00:26:18 +0100983 config = {
984 'isolated': 1,
985 'use_environment': 0,
986 'user_site_directory': 0,
987 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200988 self.check_all_configs("test_preinit_isolated1", config, api=API_COMPAT)
Victor Stinner6da20a42019-03-27 00:26:18 +0100989
990 def test_preinit_isolated2(self):
991 # _PyPreConfig.isolated=0, _PyCoreConfig.isolated=1
Victor Stinner6da20a42019-03-27 00:26:18 +0100992 config = {
993 'isolated': 1,
994 'use_environment': 0,
995 'user_site_directory': 0,
996 }
Victor Stinner331a6a52019-05-27 16:39:22 +0200997 self.check_all_configs("test_preinit_isolated2", config, api=API_COMPAT)
Victor Stinner6da20a42019-03-27 00:26:18 +0100998
Victor Stinner6d1c4672019-05-20 11:02:00 +0200999 def test_preinit_isolated_config(self):
Victor Stinner331a6a52019-05-27 16:39:22 +02001000 self.check_all_configs("test_preinit_isolated_config", api=API_ISOLATED)
Victor Stinner6d1c4672019-05-20 11:02:00 +02001001
Victor Stinnercab5d072019-05-17 19:01:14 +02001002 def test_init_isolated_config(self):
Victor Stinner331a6a52019-05-27 16:39:22 +02001003 self.check_all_configs("test_init_isolated_config", api=API_ISOLATED)
Victor Stinner5edcf262019-05-23 00:57:57 +02001004
1005 def test_preinit_python_config(self):
Victor Stinner331a6a52019-05-27 16:39:22 +02001006 self.check_all_configs("test_preinit_python_config", api=API_PYTHON)
Victor Stinnercab5d072019-05-17 19:01:14 +02001007
1008 def test_init_python_config(self):
Victor Stinner331a6a52019-05-27 16:39:22 +02001009 self.check_all_configs("test_init_python_config", api=API_PYTHON)
Victor Stinnercab5d072019-05-17 19:01:14 +02001010
Victor Stinnerbcfbbd72019-05-17 22:44:16 +02001011 def test_init_dont_configure_locale(self):
1012 # _PyPreConfig.configure_locale=0
1013 preconfig = {
1014 'configure_locale': 0,
Victor Stinner425717f2019-05-20 16:38:48 +02001015 'coerce_c_locale': 0,
Victor Stinnerbcfbbd72019-05-17 22:44:16 +02001016 }
Victor Stinner331a6a52019-05-27 16:39:22 +02001017 self.check_all_configs("test_init_dont_configure_locale", {}, preconfig,
1018 api=API_PYTHON)
Victor Stinnerbcfbbd72019-05-17 22:44:16 +02001019
Victor Stinner91c99872019-05-14 22:01:51 +02001020 def test_init_read_set(self):
Victor Stinner331a6a52019-05-27 16:39:22 +02001021 config = {
Victor Stinner91c99872019-05-14 22:01:51 +02001022 'program_name': './init_read_set',
1023 'executable': 'my_executable',
1024 }
Victor Stinner3842f292019-08-23 16:57:54 +01001025 def modify_path(path):
1026 path.insert(1, "test_path_insert1")
1027 path.append("test_path_append")
Victor Stinner331a6a52019-05-27 16:39:22 +02001028 self.check_all_configs("test_init_read_set", config,
1029 api=API_PYTHON,
Victor Stinner3842f292019-08-23 16:57:54 +01001030 modify_path_cb=modify_path)
Victor Stinner91c99872019-05-14 22:01:51 +02001031
Victor Stinner120b7072019-08-23 18:03:08 +01001032 def test_init_sys_add(self):
1033 config = {
1034 'faulthandler': 1,
1035 'xoptions': [
1036 'config_xoption',
1037 'cmdline_xoption',
1038 'sysadd_xoption',
1039 'faulthandler',
1040 ],
1041 'warnoptions': [
Victor Stinner120b7072019-08-23 18:03:08 +01001042 'ignore:::cmdline_warnoption',
1043 'ignore:::sysadd_warnoption',
Victor Stinnerfb4ae152019-09-30 01:40:17 +02001044 'ignore:::config_warnoption',
Victor Stinner120b7072019-08-23 18:03:08 +01001045 ],
Victor Stinnerdd8a93e2020-06-30 00:49:03 +02001046 'orig_argv': ['python3',
1047 '-W', 'ignore:::cmdline_warnoption',
1048 '-X', 'cmdline_xoption'],
Victor Stinner120b7072019-08-23 18:03:08 +01001049 }
1050 self.check_all_configs("test_init_sys_add", config, api=API_PYTHON)
1051
Victor Stinner9ef5dca2019-05-16 17:38:16 +02001052 def test_init_run_main(self):
Victor Stinner5eb8b072019-05-15 02:12:48 +02001053 code = ('import _testinternalcapi, json; '
1054 'print(json.dumps(_testinternalcapi.get_configs()))')
Victor Stinner331a6a52019-05-27 16:39:22 +02001055 config = {
Victor Stinner5eb8b072019-05-15 02:12:48 +02001056 'argv': ['-c', 'arg2'],
Victor Stinnerdd8a93e2020-06-30 00:49:03 +02001057 'orig_argv': ['python3', '-c', code, 'arg2'],
Victor Stinner5eb8b072019-05-15 02:12:48 +02001058 'program_name': './python3',
1059 'run_command': code + '\n',
Victor Stinnerdc42af82020-11-05 18:58:07 +01001060 'parse_argv': 2,
Victor Stinner5eb8b072019-05-15 02:12:48 +02001061 }
Victor Stinner331a6a52019-05-27 16:39:22 +02001062 self.check_all_configs("test_init_run_main", config, api=API_PYTHON)
Victor Stinner9ef5dca2019-05-16 17:38:16 +02001063
1064 def test_init_main(self):
Victor Stinner9ef5dca2019-05-16 17:38:16 +02001065 code = ('import _testinternalcapi, json; '
1066 'print(json.dumps(_testinternalcapi.get_configs()))')
Victor Stinner331a6a52019-05-27 16:39:22 +02001067 config = {
Victor Stinner9ef5dca2019-05-16 17:38:16 +02001068 'argv': ['-c', 'arg2'],
Victor Stinnerdd8a93e2020-06-30 00:49:03 +02001069 'orig_argv': ['python3',
1070 '-c', code,
1071 'arg2'],
Victor Stinner9ef5dca2019-05-16 17:38:16 +02001072 'program_name': './python3',
1073 'run_command': code + '\n',
Victor Stinnerdc42af82020-11-05 18:58:07 +01001074 'parse_argv': 2,
Victor Stinner9ef5dca2019-05-16 17:38:16 +02001075 '_init_main': 0,
1076 }
Victor Stinner331a6a52019-05-27 16:39:22 +02001077 self.check_all_configs("test_init_main", config,
1078 api=API_PYTHON,
1079 stderr="Run Python code before _Py_InitializeMain")
Victor Stinner5eb8b072019-05-15 02:12:48 +02001080
Victor Stinnercab5d072019-05-17 19:01:14 +02001081 def test_init_parse_argv(self):
Victor Stinner331a6a52019-05-27 16:39:22 +02001082 config = {
Victor Stinnerdc42af82020-11-05 18:58:07 +01001083 'parse_argv': 2,
Victor Stinnercab5d072019-05-17 19:01:14 +02001084 'argv': ['-c', 'arg1', '-v', 'arg3'],
Victor Stinnerdd8a93e2020-06-30 00:49:03 +02001085 'orig_argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'],
Victor Stinnercab5d072019-05-17 19:01:14 +02001086 'program_name': './argv0',
Victor Stinnercab5d072019-05-17 19:01:14 +02001087 'run_command': 'pass\n',
1088 'use_environment': 0,
1089 }
Victor Stinner331a6a52019-05-27 16:39:22 +02001090 self.check_all_configs("test_init_parse_argv", config, api=API_PYTHON)
Victor Stinnercab5d072019-05-17 19:01:14 +02001091
Victor Stinnerae239f62019-05-16 17:02:56 +02001092 def test_init_dont_parse_argv(self):
Victor Stinner6d1c4672019-05-20 11:02:00 +02001093 pre_config = {
1094 'parse_argv': 0,
1095 }
Victor Stinner331a6a52019-05-27 16:39:22 +02001096 config = {
Victor Stinnerbab0db62019-05-18 03:21:27 +02001097 'parse_argv': 0,
Victor Stinnercab5d072019-05-17 19:01:14 +02001098 'argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'],
Victor Stinnerdd8a93e2020-06-30 00:49:03 +02001099 'orig_argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'],
Victor Stinnercab5d072019-05-17 19:01:14 +02001100 'program_name': './argv0',
Victor Stinnerae239f62019-05-16 17:02:56 +02001101 }
Victor Stinner331a6a52019-05-27 16:39:22 +02001102 self.check_all_configs("test_init_dont_parse_argv", config, pre_config,
1103 api=API_PYTHON)
Victor Stinnerae239f62019-05-16 17:02:56 +02001104
Victor Stinner8bf39b62019-09-26 02:22:35 +02001105 def default_program_name(self, config):
1106 if MS_WINDOWS:
1107 program_name = 'python'
1108 executable = self.test_exe
1109 else:
1110 program_name = 'python3'
Victor Stinner49d99f02019-09-26 04:01:49 +02001111 if MACOS:
1112 executable = self.test_exe
1113 else:
1114 executable = shutil.which(program_name) or ''
Victor Stinner8bf39b62019-09-26 02:22:35 +02001115 config.update({
1116 'program_name': program_name,
1117 'base_executable': executable,
1118 'executable': executable,
1119 })
1120
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +02001121 def test_init_setpath(self):
Victor Stinner8bf39b62019-09-26 02:22:35 +02001122 # Test Py_SetPath()
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +02001123 config = self._get_expected_config()
1124 paths = config['config']['module_search_paths']
1125
1126 config = {
1127 'module_search_paths': paths,
1128 'prefix': '',
1129 'base_prefix': '',
1130 'exec_prefix': '',
1131 'base_exec_prefix': '',
1132 }
Victor Stinner8bf39b62019-09-26 02:22:35 +02001133 self.default_program_name(config)
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +02001134 env = {'TESTPATH': os.path.pathsep.join(paths)}
Steve Dowerdcbaa1b2020-07-06 17:32:00 +01001135
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +02001136 self.check_all_configs("test_init_setpath", config,
1137 api=API_COMPAT, env=env,
1138 ignore_stderr=True)
1139
Victor Stinner8bf39b62019-09-26 02:22:35 +02001140 def test_init_setpath_config(self):
1141 # Test Py_SetPath() with PyConfig
1142 config = self._get_expected_config()
1143 paths = config['config']['module_search_paths']
1144
1145 config = {
1146 # set by Py_SetPath()
1147 'module_search_paths': paths,
1148 'prefix': '',
1149 'base_prefix': '',
1150 'exec_prefix': '',
1151 'base_exec_prefix': '',
1152 # overriden by PyConfig
1153 'program_name': 'conf_program_name',
1154 'base_executable': 'conf_executable',
1155 'executable': 'conf_executable',
1156 }
1157 env = {'TESTPATH': os.path.pathsep.join(paths)}
Victor Stinner8bf39b62019-09-26 02:22:35 +02001158 self.check_all_configs("test_init_setpath_config", config,
Victor Stinner49d99f02019-09-26 04:01:49 +02001159 api=API_PYTHON, env=env, ignore_stderr=True)
Victor Stinner8bf39b62019-09-26 02:22:35 +02001160
Victor Stinner52ad33a2019-09-25 02:10:35 +02001161 def module_search_paths(self, prefix=None, exec_prefix=None):
1162 config = self._get_expected_config()
1163 if prefix is None:
1164 prefix = config['config']['prefix']
1165 if exec_prefix is None:
1166 exec_prefix = config['config']['prefix']
1167 if MS_WINDOWS:
1168 return config['config']['module_search_paths']
1169 else:
1170 ver = sys.version_info
1171 return [
Victor Stinner8510f432020-03-10 09:53:09 +01001172 os.path.join(prefix, sys.platlibdir,
Victor Stinner52ad33a2019-09-25 02:10:35 +02001173 f'python{ver.major}{ver.minor}.zip'),
Victor Stinner8510f432020-03-10 09:53:09 +01001174 os.path.join(prefix, sys.platlibdir,
Victor Stinner52ad33a2019-09-25 02:10:35 +02001175 f'python{ver.major}.{ver.minor}'),
Victor Stinner8510f432020-03-10 09:53:09 +01001176 os.path.join(exec_prefix, sys.platlibdir,
Victor Stinner52ad33a2019-09-25 02:10:35 +02001177 f'python{ver.major}.{ver.minor}', 'lib-dynload'),
1178 ]
1179
1180 @contextlib.contextmanager
1181 def tmpdir_with_python(self):
1182 # Temporary directory with a copy of the Python program
1183 with tempfile.TemporaryDirectory() as tmpdir:
Victor Stinner00508a72019-09-25 16:30:36 +02001184 # bpo-38234: On macOS and FreeBSD, the temporary directory
1185 # can be symbolic link. For example, /tmp can be a symbolic link
1186 # to /var/tmp. Call realpath() to resolve all symbolic links.
1187 tmpdir = os.path.realpath(tmpdir)
1188
Victor Stinner52ad33a2019-09-25 02:10:35 +02001189 if MS_WINDOWS:
1190 # Copy pythonXY.dll (or pythonXY_d.dll)
1191 ver = sys.version_info
1192 dll = f'python{ver.major}{ver.minor}'
Steve Dowerdcbaa1b2020-07-06 17:32:00 +01001193 dll3 = f'python{ver.major}'
Victor Stinner52ad33a2019-09-25 02:10:35 +02001194 if debug_build(sys.executable):
1195 dll += '_d'
Steve Dowerdcbaa1b2020-07-06 17:32:00 +01001196 dll3 += '_d'
Victor Stinner52ad33a2019-09-25 02:10:35 +02001197 dll += '.dll'
Steve Dowerdcbaa1b2020-07-06 17:32:00 +01001198 dll3 += '.dll'
Victor Stinner52ad33a2019-09-25 02:10:35 +02001199 dll = os.path.join(os.path.dirname(self.test_exe), dll)
Steve Dowerdcbaa1b2020-07-06 17:32:00 +01001200 dll3 = os.path.join(os.path.dirname(self.test_exe), dll3)
Victor Stinner52ad33a2019-09-25 02:10:35 +02001201 dll_copy = os.path.join(tmpdir, os.path.basename(dll))
Steve Dowerdcbaa1b2020-07-06 17:32:00 +01001202 dll3_copy = os.path.join(tmpdir, os.path.basename(dll3))
Victor Stinner52ad33a2019-09-25 02:10:35 +02001203 shutil.copyfile(dll, dll_copy)
Steve Dowerdcbaa1b2020-07-06 17:32:00 +01001204 shutil.copyfile(dll3, dll3_copy)
Victor Stinner52ad33a2019-09-25 02:10:35 +02001205
1206 # Copy Python program
1207 exec_copy = os.path.join(tmpdir, os.path.basename(self.test_exe))
1208 shutil.copyfile(self.test_exe, exec_copy)
1209 shutil.copystat(self.test_exe, exec_copy)
1210 self.test_exe = exec_copy
1211
1212 yield tmpdir
1213
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +02001214 def test_init_setpythonhome(self):
Victor Stinner8bf39b62019-09-26 02:22:35 +02001215 # Test Py_SetPythonHome(home) with PYTHONPATH env var
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +02001216 config = self._get_expected_config()
1217 paths = config['config']['module_search_paths']
1218 paths_str = os.path.pathsep.join(paths)
1219
1220 for path in paths:
1221 if not os.path.isdir(path):
1222 continue
1223 if os.path.exists(os.path.join(path, 'os.py')):
1224 home = os.path.dirname(path)
1225 break
1226 else:
1227 self.fail(f"Unable to find home in {paths!r}")
1228
1229 prefix = exec_prefix = home
1230 ver = sys.version_info
Victor Stinner52ad33a2019-09-25 02:10:35 +02001231 expected_paths = self.module_search_paths(prefix=home, exec_prefix=home)
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +02001232
1233 config = {
1234 'home': home,
1235 'module_search_paths': expected_paths,
1236 'prefix': prefix,
1237 'base_prefix': prefix,
1238 'exec_prefix': exec_prefix,
1239 'base_exec_prefix': exec_prefix,
1240 'pythonpath_env': paths_str,
1241 }
Victor Stinner8bf39b62019-09-26 02:22:35 +02001242 self.default_program_name(config)
1243 env = {'TESTHOME': home, 'PYTHONPATH': paths_str}
Victor Stinnerbb6bf7d2019-09-24 18:21:02 +02001244 self.check_all_configs("test_init_setpythonhome", config,
1245 api=API_COMPAT, env=env)
1246
Victor Stinner52ad33a2019-09-25 02:10:35 +02001247 def copy_paths_by_env(self, config):
1248 all_configs = self._get_expected_config()
1249 paths = all_configs['config']['module_search_paths']
1250 paths_str = os.path.pathsep.join(paths)
1251 config['pythonpath_env'] = paths_str
1252 env = {'PYTHONPATH': paths_str}
1253 return env
1254
1255 @unittest.skipIf(MS_WINDOWS, 'Windows does not use pybuilddir.txt')
1256 def test_init_pybuilddir(self):
1257 # Test path configuration with pybuilddir.txt configuration file
1258
1259 with self.tmpdir_with_python() as tmpdir:
1260 # pybuilddir.txt is a sub-directory relative to the current
1261 # directory (tmpdir)
1262 subdir = 'libdir'
1263 libdir = os.path.join(tmpdir, subdir)
1264 os.mkdir(libdir)
1265
1266 filename = os.path.join(tmpdir, 'pybuilddir.txt')
1267 with open(filename, "w", encoding="utf8") as fp:
1268 fp.write(subdir)
1269
1270 module_search_paths = self.module_search_paths()
1271 module_search_paths[-1] = libdir
1272
1273 executable = self.test_exe
1274 config = {
1275 'base_executable': executable,
1276 'executable': executable,
1277 'module_search_paths': module_search_paths,
1278 }
1279 env = self.copy_paths_by_env(config)
1280 self.check_all_configs("test_init_compat_config", config,
1281 api=API_COMPAT, env=env,
1282 ignore_stderr=True, cwd=tmpdir)
1283
1284 def test_init_pyvenv_cfg(self):
1285 # Test path configuration with pyvenv.cfg configuration file
1286
1287 with self.tmpdir_with_python() as tmpdir, \
1288 tempfile.TemporaryDirectory() as pyvenv_home:
1289 ver = sys.version_info
1290
1291 if not MS_WINDOWS:
1292 lib_dynload = os.path.join(pyvenv_home,
Victor Stinner8510f432020-03-10 09:53:09 +01001293 sys.platlibdir,
Victor Stinner52ad33a2019-09-25 02:10:35 +02001294 f'python{ver.major}.{ver.minor}',
1295 'lib-dynload')
1296 os.makedirs(lib_dynload)
1297 else:
1298 lib_dynload = os.path.join(pyvenv_home, 'lib')
1299 os.makedirs(lib_dynload)
1300 # getpathp.c uses Lib\os.py as the LANDMARK
1301 shutil.copyfile(os.__file__, os.path.join(lib_dynload, 'os.py'))
1302
1303 filename = os.path.join(tmpdir, 'pyvenv.cfg')
1304 with open(filename, "w", encoding="utf8") as fp:
1305 print("home = %s" % pyvenv_home, file=fp)
1306 print("include-system-site-packages = false", file=fp)
1307
1308 paths = self.module_search_paths()
1309 if not MS_WINDOWS:
1310 paths[-1] = lib_dynload
1311 else:
1312 for index, path in enumerate(paths):
1313 if index == 0:
1314 paths[index] = os.path.join(tmpdir, os.path.basename(path))
1315 else:
1316 paths[index] = os.path.join(pyvenv_home, os.path.basename(path))
1317 paths[-1] = pyvenv_home
1318
1319 executable = self.test_exe
1320 exec_prefix = pyvenv_home
1321 config = {
1322 'base_exec_prefix': exec_prefix,
1323 'exec_prefix': exec_prefix,
1324 'base_executable': executable,
1325 'executable': executable,
1326 'module_search_paths': paths,
1327 }
Victor Stinner8f427482020-07-08 00:20:37 +02001328 path_config = {}
Victor Stinner52ad33a2019-09-25 02:10:35 +02001329 if MS_WINDOWS:
1330 config['base_prefix'] = pyvenv_home
1331 config['prefix'] = pyvenv_home
Steve Dowerdcbaa1b2020-07-06 17:32:00 +01001332
Victor Stinner8f427482020-07-08 00:20:37 +02001333 ver = sys.version_info
1334 dll = f'python{ver.major}'
1335 if debug_build(executable):
1336 dll += '_d'
1337 dll += '.DLL'
1338 dll = os.path.join(os.path.dirname(executable), dll)
1339 path_config['python3_dll'] = dll
1340
1341 env = self.copy_paths_by_env(config)
1342 self.check_all_configs("test_init_compat_config", config,
1343 expected_pathconfig=path_config,
1344 api=API_COMPAT, env=env,
1345 ignore_stderr=True, cwd=tmpdir)
Victor Stinner52ad33a2019-09-25 02:10:35 +02001346
Victor Stinner12f2f172019-09-26 15:51:50 +02001347 def test_global_pathconfig(self):
1348 # Test C API functions getting the path configuration:
1349 #
1350 # - Py_GetExecPrefix()
1351 # - Py_GetPath()
1352 # - Py_GetPrefix()
1353 # - Py_GetProgramFullPath()
1354 # - Py_GetProgramName()
1355 # - Py_GetPythonHome()
1356 #
1357 # The global path configuration (_Py_path_config) must be a copy
1358 # of the path configuration of PyInterpreter.config (PyConfig).
Hai Shibb0424b2020-08-04 00:47:42 +08001359 ctypes = import_helper.import_module('ctypes')
1360 _testinternalcapi = import_helper.import_module('_testinternalcapi')
Victor Stinner12f2f172019-09-26 15:51:50 +02001361
1362 def get_func(name):
1363 func = getattr(ctypes.pythonapi, name)
1364 func.argtypes = ()
1365 func.restype = ctypes.c_wchar_p
1366 return func
1367
1368 Py_GetPath = get_func('Py_GetPath')
1369 Py_GetPrefix = get_func('Py_GetPrefix')
1370 Py_GetExecPrefix = get_func('Py_GetExecPrefix')
1371 Py_GetProgramName = get_func('Py_GetProgramName')
1372 Py_GetProgramFullPath = get_func('Py_GetProgramFullPath')
1373 Py_GetPythonHome = get_func('Py_GetPythonHome')
1374
1375 config = _testinternalcapi.get_configs()['config']
1376
1377 self.assertEqual(Py_GetPath().split(os.path.pathsep),
1378 config['module_search_paths'])
1379 self.assertEqual(Py_GetPrefix(), config['prefix'])
1380 self.assertEqual(Py_GetExecPrefix(), config['exec_prefix'])
1381 self.assertEqual(Py_GetProgramName(), config['program_name'])
1382 self.assertEqual(Py_GetProgramFullPath(), config['executable'])
1383 self.assertEqual(Py_GetPythonHome(), config['home'])
1384
Victor Stinnerfb4ae152019-09-30 01:40:17 +02001385 def test_init_warnoptions(self):
1386 # lowest to highest priority
1387 warnoptions = [
1388 'ignore:::PyConfig_Insert0', # PyWideStringList_Insert(0)
1389 'default', # PyConfig.dev_mode=1
1390 'ignore:::env1', # PYTHONWARNINGS env var
1391 'ignore:::env2', # PYTHONWARNINGS env var
1392 'ignore:::cmdline1', # -W opt command line option
1393 'ignore:::cmdline2', # -W opt command line option
1394 'default::BytesWarning', # PyConfig.bytes_warnings=1
1395 'ignore:::PySys_AddWarnOption1', # PySys_AddWarnOption()
1396 'ignore:::PySys_AddWarnOption2', # PySys_AddWarnOption()
1397 'ignore:::PyConfig_BeforeRead', # PyConfig.warnoptions
1398 'ignore:::PyConfig_AfterRead'] # PyWideStringList_Append()
1399 preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG)
1400 config = {
1401 'dev_mode': 1,
1402 'faulthandler': 1,
1403 'bytes_warning': 1,
1404 'warnoptions': warnoptions,
Victor Stinnerdd8a93e2020-06-30 00:49:03 +02001405 'orig_argv': ['python3',
1406 '-Wignore:::cmdline1',
1407 '-Wignore:::cmdline2'],
Victor Stinnerfb4ae152019-09-30 01:40:17 +02001408 }
1409 self.check_all_configs("test_init_warnoptions", config, preconfig,
1410 api=API_PYTHON)
1411
Victor Stinner048a3562020-11-05 00:45:56 +01001412 def test_init_set_config(self):
1413 config = {
1414 '_init_main': 0,
1415 'bytes_warning': 2,
1416 'warnoptions': ['error::BytesWarning'],
1417 }
1418 self.check_all_configs("test_init_set_config", config,
1419 api=API_ISOLATED)
1420
Victor Stinnere81f6e62020-06-08 18:12:59 +02001421 def test_get_argc_argv(self):
1422 self.run_embedded_interpreter("test_get_argc_argv")
1423 # ignore output
1424
Victor Stinner56b29b62018-07-26 18:57:56 +02001425
Victor Stinnerf3cb8142020-11-05 18:12:33 +01001426class SetConfigTests(unittest.TestCase):
1427 def test_set_config(self):
1428 # bpo-42260: Test _PyInterpreterState_SetConfig()
1429 cmd = [sys.executable, '-I', '-m', 'test._test_embed_set_config']
1430 proc = subprocess.run(cmd,
1431 stdout=subprocess.PIPE,
1432 stderr=subprocess.PIPE)
1433 self.assertEqual(proc.returncode, 0,
1434 (proc.returncode, proc.stdout, proc.stderr))
1435
1436
Steve Dowerb82e17e2019-05-23 08:45:22 -07001437class AuditingTests(EmbeddingTestsMixin, unittest.TestCase):
1438 def test_open_code_hook(self):
1439 self.run_embedded_interpreter("test_open_code_hook")
1440
1441 def test_audit(self):
1442 self.run_embedded_interpreter("test_audit")
1443
1444 def test_audit_subinterpreter(self):
1445 self.run_embedded_interpreter("test_audit_subinterpreter")
1446
Steve Dowere226e832019-07-01 16:03:53 -07001447 def test_audit_run_command(self):
Victor Stinner7772b1a2019-12-11 22:17:04 +01001448 self.run_embedded_interpreter("test_audit_run_command",
1449 timeout=support.SHORT_TIMEOUT,
1450 returncode=1)
Steve Dowere226e832019-07-01 16:03:53 -07001451
1452 def test_audit_run_file(self):
Victor Stinner7772b1a2019-12-11 22:17:04 +01001453 self.run_embedded_interpreter("test_audit_run_file",
1454 timeout=support.SHORT_TIMEOUT,
1455 returncode=1)
Steve Dowere226e832019-07-01 16:03:53 -07001456
1457 def test_audit_run_interactivehook(self):
Hai Shibb0424b2020-08-04 00:47:42 +08001458 startup = os.path.join(self.oldcwd, os_helper.TESTFN) + ".py"
Steve Dowere226e832019-07-01 16:03:53 -07001459 with open(startup, "w", encoding="utf-8") as f:
1460 print("import sys", file=f)
1461 print("sys.__interactivehook__ = lambda: None", file=f)
1462 try:
1463 env = {**remove_python_envvars(), "PYTHONSTARTUP": startup}
Victor Stinner7772b1a2019-12-11 22:17:04 +01001464 self.run_embedded_interpreter("test_audit_run_interactivehook",
1465 timeout=support.SHORT_TIMEOUT,
Steve Dowere226e832019-07-01 16:03:53 -07001466 returncode=10, env=env)
1467 finally:
1468 os.unlink(startup)
1469
1470 def test_audit_run_startup(self):
Hai Shibb0424b2020-08-04 00:47:42 +08001471 startup = os.path.join(self.oldcwd, os_helper.TESTFN) + ".py"
Steve Dowere226e832019-07-01 16:03:53 -07001472 with open(startup, "w", encoding="utf-8") as f:
1473 print("pass", file=f)
1474 try:
1475 env = {**remove_python_envvars(), "PYTHONSTARTUP": startup}
Victor Stinner7772b1a2019-12-11 22:17:04 +01001476 self.run_embedded_interpreter("test_audit_run_startup",
1477 timeout=support.SHORT_TIMEOUT,
Steve Dowere226e832019-07-01 16:03:53 -07001478 returncode=10, env=env)
1479 finally:
1480 os.unlink(startup)
1481
1482 def test_audit_run_stdin(self):
Victor Stinner7772b1a2019-12-11 22:17:04 +01001483 self.run_embedded_interpreter("test_audit_run_stdin",
1484 timeout=support.SHORT_TIMEOUT,
1485 returncode=1)
Steve Dowerb82e17e2019-05-23 08:45:22 -07001486
Victor Stinner4908fae2021-04-30 14:56:27 +02001487
Victor Stinner11d13e82021-01-12 11:26:26 +01001488class MiscTests(EmbeddingTestsMixin, unittest.TestCase):
1489 def test_unicode_id_init(self):
1490 # bpo-42882: Test that _PyUnicode_FromId() works
1491 # when Python is initialized multiples times.
1492 self.run_embedded_interpreter("test_unicode_id_init")
1493
Victor Stinner4908fae2021-04-30 14:56:27 +02001494
1495class StdPrinterTests(EmbeddingTestsMixin, unittest.TestCase):
1496 # Test PyStdPrinter_Type which is used by _PySys_SetPreliminaryStderr():
1497 # "Set up a preliminary stderr printer until we have enough
1498 # infrastructure for the io module in place."
1499
1500 def get_stdout_fd(self):
1501 return sys.__stdout__.fileno()
1502
1503 def create_printer(self, fd):
1504 ctypes = import_helper.import_module('ctypes')
1505 PyFile_NewStdPrinter = ctypes.pythonapi.PyFile_NewStdPrinter
1506 PyFile_NewStdPrinter.argtypes = (ctypes.c_int,)
1507 PyFile_NewStdPrinter.restype = ctypes.py_object
1508 return PyFile_NewStdPrinter(fd)
1509
1510 def test_write(self):
1511 message = "unicode:\xe9-\u20ac-\udc80!\n"
1512
1513 stdout_fd = self.get_stdout_fd()
1514 stdout_fd_copy = os.dup(stdout_fd)
1515 self.addCleanup(os.close, stdout_fd_copy)
1516
1517 rfd, wfd = os.pipe()
1518 self.addCleanup(os.close, rfd)
1519 self.addCleanup(os.close, wfd)
1520 try:
1521 # PyFile_NewStdPrinter() only accepts fileno(stdout)
1522 # or fileno(stderr) file descriptor.
1523 os.dup2(wfd, stdout_fd)
1524
1525 printer = self.create_printer(stdout_fd)
1526 printer.write(message)
1527 finally:
1528 os.dup2(stdout_fd_copy, stdout_fd)
1529
1530 data = os.read(rfd, 100)
1531 self.assertEqual(data, message.encode('utf8', 'backslashreplace'))
1532
1533 def test_methods(self):
1534 fd = self.get_stdout_fd()
1535 printer = self.create_printer(fd)
1536 self.assertEqual(printer.fileno(), fd)
1537 self.assertEqual(printer.isatty(), os.isatty(fd))
1538 printer.flush() # noop
1539 printer.close() # noop
1540
1541 def test_disallow_instantiation(self):
1542 fd = self.get_stdout_fd()
1543 printer = self.create_printer(fd)
1544 PyStdPrinter_Type = type(printer)
1545 with self.assertRaises(TypeError):
1546 PyStdPrinter_Type(fd)
1547
1548
Nick Coghlan39f0bb52017-11-28 08:11:51 +10001549if __name__ == "__main__":
1550 unittest.main()