blob: b6c25e3f7eda3d9f8e2c4e84024a053cb0a93394 [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
3import unittest
4
5from collections import namedtuple
Victor Stinner7ddd56f2018-11-14 00:24:28 +01006import json
Nick Coghlan39f0bb52017-11-28 08:11:51 +10007import os
Michael Feltd2067312018-09-15 11:28:31 +02008import platform
Nick Coghlan39f0bb52017-11-28 08:11:51 +10009import re
10import subprocess
11import sys
Victor Stinnera6537fb2018-11-26 11:54:12 +010012import textwrap
Nick Coghlan39f0bb52017-11-28 08:11:51 +100013
14
Victor Stinner01de89c2018-11-14 17:39:45 +010015MS_WINDOWS = (os.name == 'nt')
16
17
Victor Stinner56b29b62018-07-26 18:57:56 +020018class EmbeddingTestsMixin:
Nick Coghlan39f0bb52017-11-28 08:11:51 +100019 def setUp(self):
20 here = os.path.abspath(__file__)
21 basepath = os.path.dirname(os.path.dirname(os.path.dirname(here)))
22 exename = "_testembed"
Victor Stinner01de89c2018-11-14 17:39:45 +010023 if MS_WINDOWS:
Nick Coghlan39f0bb52017-11-28 08:11:51 +100024 ext = ("_d" if "_d" in sys.executable else "") + ".exe"
25 exename += ext
26 exepath = os.path.dirname(sys.executable)
27 else:
28 exepath = os.path.join(basepath, "Programs")
29 self.test_exe = exe = os.path.join(exepath, exename)
30 if not os.path.exists(exe):
31 self.skipTest("%r doesn't exist" % exe)
32 # This is needed otherwise we get a fatal error:
33 # "Py_Initialize: Unable to get the locale encoding
34 # LookupError: no codec search functions registered: can't find encoding"
35 self.oldcwd = os.getcwd()
36 os.chdir(basepath)
37
38 def tearDown(self):
39 os.chdir(self.oldcwd)
40
41 def run_embedded_interpreter(self, *args, env=None):
42 """Runs a test in the embedded interpreter"""
43 cmd = [self.test_exe]
44 cmd.extend(args)
Victor Stinner01de89c2018-11-14 17:39:45 +010045 if env is not None and MS_WINDOWS:
Nick Coghlan39f0bb52017-11-28 08:11:51 +100046 # Windows requires at least the SYSTEMROOT environment variable to
47 # start Python.
48 env = env.copy()
49 env['SYSTEMROOT'] = os.environ['SYSTEMROOT']
50
51 p = subprocess.Popen(cmd,
52 stdout=subprocess.PIPE,
53 stderr=subprocess.PIPE,
54 universal_newlines=True,
55 env=env)
56 (out, err) = p.communicate()
57 if p.returncode != 0 and support.verbose:
58 print(f"--- {cmd} failed ---")
59 print(f"stdout:\n{out}")
Nick Coghlanbc77eff2018-03-25 20:44:30 +100060 print(f"stderr:\n{err}")
Nick Coghlan39f0bb52017-11-28 08:11:51 +100061 print(f"------")
62
63 self.assertEqual(p.returncode, 0,
64 "bad returncode %d, stderr is %r" %
65 (p.returncode, err))
66 return out, err
67
68 def run_repeated_init_and_subinterpreters(self):
69 out, err = self.run_embedded_interpreter("repeated_init_and_subinterpreters")
70 self.assertEqual(err, "")
71
72 # The output from _testembed looks like this:
73 # --- Pass 0 ---
74 # interp 0 <0x1cf9330>, thread state <0x1cf9700>: id(modules) = 139650431942728
75 # interp 1 <0x1d4f690>, thread state <0x1d35350>: id(modules) = 139650431165784
76 # interp 2 <0x1d5a690>, thread state <0x1d99ed0>: id(modules) = 139650413140368
77 # interp 3 <0x1d4f690>, thread state <0x1dc3340>: id(modules) = 139650412862200
78 # interp 0 <0x1cf9330>, thread state <0x1cf9700>: id(modules) = 139650431942728
79 # --- Pass 1 ---
80 # ...
81
82 interp_pat = (r"^interp (\d+) <(0x[\dA-F]+)>, "
83 r"thread state <(0x[\dA-F]+)>: "
84 r"id\(modules\) = ([\d]+)$")
85 Interp = namedtuple("Interp", "id interp tstate modules")
86
87 numloops = 0
88 current_run = []
89 for line in out.splitlines():
90 if line == "--- Pass {} ---".format(numloops):
91 self.assertEqual(len(current_run), 0)
Nick Coghlanbc77eff2018-03-25 20:44:30 +100092 if support.verbose > 1:
Nick Coghlan39f0bb52017-11-28 08:11:51 +100093 print(line)
94 numloops += 1
95 continue
96
97 self.assertLess(len(current_run), 5)
98 match = re.match(interp_pat, line)
99 if match is None:
100 self.assertRegex(line, interp_pat)
101
102 # Parse the line from the loop. The first line is the main
103 # interpreter and the 3 afterward are subinterpreters.
104 interp = Interp(*match.groups())
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000105 if support.verbose > 1:
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000106 print(interp)
107 self.assertTrue(interp.interp)
108 self.assertTrue(interp.tstate)
109 self.assertTrue(interp.modules)
110 current_run.append(interp)
111
112 # The last line in the loop should be the same as the first.
113 if len(current_run) == 5:
114 main = current_run[0]
115 self.assertEqual(interp, main)
116 yield current_run
117 current_run = []
118
Victor Stinner56b29b62018-07-26 18:57:56 +0200119
120class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000121 def test_subinterps_main(self):
122 for run in self.run_repeated_init_and_subinterpreters():
123 main = run[0]
124
125 self.assertEqual(main.id, '0')
126
127 def test_subinterps_different_ids(self):
128 for run in self.run_repeated_init_and_subinterpreters():
129 main, *subs, _ = run
130
131 mainid = int(main.id)
132 for i, sub in enumerate(subs):
133 self.assertEqual(sub.id, str(mainid + i + 1))
134
135 def test_subinterps_distinct_state(self):
136 for run in self.run_repeated_init_and_subinterpreters():
137 main, *subs, _ = run
138
139 if '0x0' in main:
140 # XXX Fix on Windows (and other platforms): something
141 # is going on with the pointers in Programs/_testembed.c.
142 # interp.interp is 0x0 and interp.modules is the same
143 # between interpreters.
144 raise unittest.SkipTest('platform prints pointers as 0x0')
145
146 for sub in subs:
147 # A new subinterpreter may have the same
148 # PyInterpreterState pointer as a previous one if
149 # the earlier one has already been destroyed. So
150 # we compare with the main interpreter. The same
151 # applies to tstate.
152 self.assertNotEqual(sub.interp, main.interp)
153 self.assertNotEqual(sub.tstate, main.tstate)
154 self.assertNotEqual(sub.modules, main.modules)
155
156 def test_forced_io_encoding(self):
157 # Checks forced configuration of embedded interpreter IO streams
158 env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")
159 out, err = self.run_embedded_interpreter("forced_io_encoding", env=env)
160 if support.verbose > 1:
161 print()
162 print(out)
163 print(err)
164 expected_stream_encoding = "utf-8"
165 expected_errors = "surrogateescape"
166 expected_output = '\n'.join([
167 "--- Use defaults ---",
168 "Expected encoding: default",
169 "Expected errors: default",
170 "stdin: {in_encoding}:{errors}",
171 "stdout: {out_encoding}:{errors}",
172 "stderr: {out_encoding}:backslashreplace",
173 "--- Set errors only ---",
174 "Expected encoding: default",
175 "Expected errors: ignore",
176 "stdin: {in_encoding}:ignore",
177 "stdout: {out_encoding}:ignore",
178 "stderr: {out_encoding}:backslashreplace",
179 "--- Set encoding only ---",
Victor Stinner9e4994d2018-08-28 23:26:33 +0200180 "Expected encoding: iso8859-1",
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000181 "Expected errors: default",
Victor Stinner9e4994d2018-08-28 23:26:33 +0200182 "stdin: iso8859-1:{errors}",
183 "stdout: iso8859-1:{errors}",
184 "stderr: iso8859-1:backslashreplace",
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000185 "--- Set encoding and errors ---",
Victor Stinner9e4994d2018-08-28 23:26:33 +0200186 "Expected encoding: iso8859-1",
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000187 "Expected errors: replace",
Victor Stinner9e4994d2018-08-28 23:26:33 +0200188 "stdin: iso8859-1:replace",
189 "stdout: iso8859-1:replace",
190 "stderr: iso8859-1:backslashreplace"])
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000191 expected_output = expected_output.format(
192 in_encoding=expected_stream_encoding,
193 out_encoding=expected_stream_encoding,
194 errors=expected_errors)
195 # This is useful if we ever trip over odd platform behaviour
196 self.maxDiff = None
197 self.assertEqual(out.strip(), expected_output)
198
199 def test_pre_initialization_api(self):
200 """
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000201 Checks some key parts of the C-API that need to work before the runtine
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000202 is initialized (via Py_Initialize()).
203 """
204 env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
205 out, err = self.run_embedded_interpreter("pre_initialization_api", env=env)
Victor Stinner01de89c2018-11-14 17:39:45 +0100206 if MS_WINDOWS:
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000207 expected_path = self.test_exe
208 else:
209 expected_path = os.path.join(os.getcwd(), "spam")
210 expected_output = f"sys.executable: {expected_path}\n"
211 self.assertIn(expected_output, out)
212 self.assertEqual(err, '')
213
214 def test_pre_initialization_sys_options(self):
215 """
216 Checks that sys.warnoptions and sys._xoptions can be set before the
217 runtime is initialized (otherwise they won't be effective).
218 """
Pablo Galindo41148462018-04-27 13:23:13 +0100219 env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
Nick Coghlanbc77eff2018-03-25 20:44:30 +1000220 out, err = self.run_embedded_interpreter(
221 "pre_initialization_sys_options", env=env)
222 expected_output = (
223 "sys.warnoptions: ['once', 'module', 'default']\n"
224 "sys._xoptions: {'not_an_option': '1', 'also_not_an_option': '2'}\n"
225 "warnings.filters[:3]: ['default', 'module', 'once']\n"
226 )
227 self.assertIn(expected_output, out)
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000228 self.assertEqual(err, '')
229
Victor Stinnerb4d1e1f2017-11-30 22:05:00 +0100230 def test_bpo20891(self):
231 """
232 bpo-20891: Calling PyGILState_Ensure in a non-Python thread before
233 calling PyEval_InitThreads() must not crash. PyGILState_Ensure() must
234 call PyEval_InitThreads() for us in this case.
235 """
236 out, err = self.run_embedded_interpreter("bpo20891")
237 self.assertEqual(out, '')
238 self.assertEqual(err, '')
239
Victor Stinner209abf72018-06-22 19:14:51 +0200240 def test_initialize_twice(self):
241 """
242 bpo-33932: Calling Py_Initialize() twice should do nothing (and not
243 crash!).
244 """
245 out, err = self.run_embedded_interpreter("initialize_twice")
246 self.assertEqual(out, '')
247 self.assertEqual(err, '')
248
Victor Stinnerfb47bca2018-07-20 17:34:23 +0200249 def test_initialize_pymain(self):
250 """
251 bpo-34008: Calling Py_Main() after Py_Initialize() must not fail.
252 """
253 out, err = self.run_embedded_interpreter("initialize_pymain")
254 self.assertEqual(out.rstrip(), "Py_Main() after Py_Initialize: sys.argv=['-c', 'arg2']")
255 self.assertEqual(err, '')
256
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000257
Victor Stinner56b29b62018-07-26 18:57:56 +0200258class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
259 maxDiff = 4096
Victor Stinner01de89c2018-11-14 17:39:45 +0100260 UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape')
261
262 # core config
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100263 UNTESTED_CORE_CONFIG = (
Victor Stinner01de89c2018-11-14 17:39:45 +0100264 # FIXME: untested core configuration variables
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100265 'dll_path',
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100266 'executable',
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100267 'module_search_paths',
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100268 )
Victor Stinnera6537fb2018-11-26 11:54:12 +0100269 # Mark config which should be get by get_default_config()
270 GET_DEFAULT_CONFIG = object()
Victor Stinner00b137c2018-11-13 19:59:26 +0100271 DEFAULT_CORE_CONFIG = {
Victor Stinner56b29b62018-07-26 18:57:56 +0200272 'install_signal_handlers': 1,
273 'use_environment': 1,
274 'use_hash_seed': 0,
275 'hash_seed': 0,
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100276 'allocator': None,
Victor Stinner56b29b62018-07-26 18:57:56 +0200277 'dev_mode': 0,
278 'faulthandler': 0,
279 'tracemalloc': 0,
280 'import_time': 0,
281 'show_ref_count': 0,
282 'show_alloc_count': 0,
283 'dump_refs': 0,
284 'malloc_stats': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200285
Victor Stinnera6537fb2018-11-26 11:54:12 +0100286 'filesystem_encoding': GET_DEFAULT_CONFIG,
287 'filesystem_errors': GET_DEFAULT_CONFIG,
Victor Stinnerc5989cd2018-08-29 19:32:47 +0200288
Victor Stinnerb2457ef2018-08-29 13:25:36 +0200289 'utf8_mode': 0,
Victor Stinner06e76082018-09-19 14:56:36 -0700290 'coerce_c_locale': 0,
291 'coerce_c_locale_warn': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200292
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100293 'pycache_prefix': None,
Victor Stinner56b29b62018-07-26 18:57:56 +0200294 'program_name': './_testembed',
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100295 'argv': [],
296 'program': None,
297
298 'xoptions': [],
299 'warnoptions': [],
Victor Stinner56b29b62018-07-26 18:57:56 +0200300
Victor Stinner01de89c2018-11-14 17:39:45 +0100301 'module_search_path_env': None,
302 'home': None,
Victor Stinnera6537fb2018-11-26 11:54:12 +0100303
304 'prefix': GET_DEFAULT_CONFIG,
305 'base_prefix': GET_DEFAULT_CONFIG,
306 'exec_prefix': GET_DEFAULT_CONFIG,
307 'base_exec_prefix': GET_DEFAULT_CONFIG,
Victor Stinner01de89c2018-11-14 17:39:45 +0100308
Victor Stinner56b29b62018-07-26 18:57:56 +0200309 'isolated': 0,
310 'site_import': 1,
311 'bytes_warning': 0,
312 'inspect': 0,
313 'interactive': 0,
314 'optimization_level': 0,
Victor Stinner98512272018-08-01 03:07:00 +0200315 'parser_debug': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200316 'write_bytecode': 1,
317 'verbose': 0,
318 'quiet': 0,
319 'user_site_directory': 1,
Victor Stinner98512272018-08-01 03:07:00 +0200320 'buffered_stdio': 1,
Victor Stinnerc5989cd2018-08-29 19:32:47 +0200321
Victor Stinnera6537fb2018-11-26 11:54:12 +0100322 'stdio_encoding': GET_DEFAULT_CONFIG,
323 'stdio_errors': GET_DEFAULT_CONFIG,
Victor Stinner56b29b62018-07-26 18:57:56 +0200324
325 '_install_importlib': 1,
326 '_check_hash_pycs_mode': 'default',
Victor Stinnerb75d7e22018-08-01 02:13:04 +0200327 '_frozen': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200328 }
Victor Stinner01de89c2018-11-14 17:39:45 +0100329 if MS_WINDOWS:
330 DEFAULT_CORE_CONFIG.update({
331 'legacy_windows_fs_encoding': 0,
332 'legacy_windows_stdio': 0,
333 })
334
335 # main config
Victor Stinner01de89c2018-11-14 17:39:45 +0100336 COPY_MAIN_CONFIG = (
337 # Copy core config to main config for expected values
338 'argv',
339 'base_exec_prefix',
340 'base_prefix',
341 'exec_prefix',
342 'executable',
343 'install_signal_handlers',
344 'prefix',
345 'pycache_prefix',
346 'warnoptions',
Victor Stinner37cd9822018-11-16 11:55:35 +0100347 # xoptions is created from core_config in check_main_config().
348 # 'module_search_paths' is copied to 'module_search_path'.
Victor Stinner01de89c2018-11-14 17:39:45 +0100349 )
350
351 # global config
352 DEFAULT_GLOBAL_CONFIG = {
353 'Py_HasFileSystemDefaultEncoding': 0,
354 'Py_HashRandomizationFlag': 1,
355 '_Py_HasFileSystemDefaultEncodeErrors': 0,
356 }
357 COPY_GLOBAL_CONFIG = [
358 # Copy core config to global config for expected values
359 # True means that the core config value is inverted (0 => 1 and 1 => 0)
360 ('Py_BytesWarningFlag', 'bytes_warning'),
361 ('Py_DebugFlag', 'parser_debug'),
362 ('Py_DontWriteBytecodeFlag', 'write_bytecode', True),
363 ('Py_FileSystemDefaultEncodeErrors', 'filesystem_errors'),
364 ('Py_FileSystemDefaultEncoding', 'filesystem_encoding'),
365 ('Py_FrozenFlag', '_frozen'),
366 ('Py_IgnoreEnvironmentFlag', 'use_environment', True),
367 ('Py_InspectFlag', 'inspect'),
368 ('Py_InteractiveFlag', 'interactive'),
369 ('Py_IsolatedFlag', 'isolated'),
370 ('Py_NoSiteFlag', 'site_import', True),
371 ('Py_NoUserSiteDirectory', 'user_site_directory', True),
372 ('Py_OptimizeFlag', 'optimization_level'),
373 ('Py_QuietFlag', 'quiet'),
374 ('Py_UTF8Mode', 'utf8_mode'),
375 ('Py_UnbufferedStdioFlag', 'buffered_stdio', True),
376 ('Py_VerboseFlag', 'verbose'),
377 ]
378 if MS_WINDOWS:
379 COPY_GLOBAL_CONFIG.extend((
380 ('Py_LegacyWindowsFSEncodingFlag', 'legacy_windows_fs_encoding'),
381 ('Py_LegacyWindowsStdioFlag', 'legacy_windows_stdio'),
382 ))
Victor Stinner56b29b62018-07-26 18:57:56 +0200383
Victor Stinner01de89c2018-11-14 17:39:45 +0100384 def main_xoptions(self, xoptions_list):
385 xoptions = {}
386 for opt in xoptions_list:
387 if '=' in opt:
388 key, value = opt.split('=', 1)
389 xoptions[key] = value
390 else:
391 xoptions[opt] = True
392 return xoptions
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200393
Victor Stinner01de89c2018-11-14 17:39:45 +0100394 def check_main_config(self, config):
395 core_config = config['core_config']
396 main_config = config['main_config']
Victor Stinner56b29b62018-07-26 18:57:56 +0200397
Victor Stinner01de89c2018-11-14 17:39:45 +0100398 # main config
Victor Stinnera6537fb2018-11-26 11:54:12 +0100399 expected = {}
Victor Stinner01de89c2018-11-14 17:39:45 +0100400 for key in self.COPY_MAIN_CONFIG:
Victor Stinnera6537fb2018-11-26 11:54:12 +0100401 expected[key] = core_config[key]
402 expected['module_search_path'] = core_config['module_search_paths']
403 expected['xoptions'] = self.main_xoptions(core_config['xoptions'])
404 self.assertEqual(main_config, expected)
405
406 def get_expected_config(self, expected, env):
407 expected = dict(self.DEFAULT_CORE_CONFIG, **expected)
408
409 code = textwrap.dedent('''
410 import json
411 import locale
412 import sys
413
414 data = {
415 'stdio_encoding': sys.stdout.encoding,
416 'stdio_errors': sys.stdout.errors,
417 'prefix': sys.prefix,
418 'base_prefix': sys.base_prefix,
419 'exec_prefix': sys.exec_prefix,
420 'base_exec_prefix': sys.base_exec_prefix,
421 'filesystem_encoding': sys.getfilesystemencoding(),
422 'filesystem_errors': sys.getfilesystemencodeerrors(),
423 }
424
425 data = json.dumps(data)
426 data = data.encode('utf-8')
427 sys.stdout.buffer.write(data)
428 sys.stdout.buffer.flush()
429 ''')
430
431 # Use -S to not import the site module: get the proper configuration
432 # when test_embed is run from a venv (bpo-35313)
433 args = (sys.executable, '-S', '-c', code)
434 env = dict(env)
435 if not expected['isolated']:
436 env['PYTHONCOERCECLOCALE'] = '0'
437 env['PYTHONUTF8'] = '0'
438 proc = subprocess.run(args, env=env,
439 stdout=subprocess.PIPE,
440 stderr=subprocess.STDOUT)
441 if proc.returncode:
442 raise Exception(f"failed to get the default config: "
443 f"stdout={proc.stdout!r} stderr={proc.stderr!r}")
444 stdout = proc.stdout.decode('utf-8')
445 config = json.loads(stdout)
446
447 for key, value in expected.items():
448 if value is self.GET_DEFAULT_CONFIG:
449 expected[key] = config[key]
450 return expected
Victor Stinner01de89c2018-11-14 17:39:45 +0100451
452 def check_core_config(self, config, expected, env):
Victor Stinnera6537fb2018-11-26 11:54:12 +0100453 expected = self.get_expected_config(expected, env)
Victor Stinner01de89c2018-11-14 17:39:45 +0100454 core_config = dict(config['core_config'])
455 for key in self.UNTESTED_CORE_CONFIG:
456 core_config.pop(key, None)
457 self.assertEqual(core_config, expected)
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200458
Victor Stinner01de89c2018-11-14 17:39:45 +0100459 def check_global_config(self, config):
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100460 core_config = config['core_config']
Victor Stinner00b137c2018-11-13 19:59:26 +0100461
Victor Stinnera6537fb2018-11-26 11:54:12 +0100462 expected = dict(self.DEFAULT_GLOBAL_CONFIG)
Victor Stinner01de89c2018-11-14 17:39:45 +0100463 for item in self.COPY_GLOBAL_CONFIG:
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100464 if len(item) == 3:
465 global_key, core_key, opposite = item
Victor Stinnera6537fb2018-11-26 11:54:12 +0100466 expected[global_key] = 0 if core_config[core_key] else 1
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100467 else:
468 global_key, core_key = item
Victor Stinnera6537fb2018-11-26 11:54:12 +0100469 expected[global_key] = core_config[core_key]
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100470
Victor Stinnera6537fb2018-11-26 11:54:12 +0100471 self.assertEqual(config['global_config'], expected)
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100472
Victor Stinner01de89c2018-11-14 17:39:45 +0100473 def check_config(self, testname, expected):
Victor Stinner01de89c2018-11-14 17:39:45 +0100474 env = dict(os.environ)
475 # Remove PYTHON* environment variables to get deterministic environment
476 for key in list(env):
477 if key.startswith('PYTHON'):
478 del env[key]
479 # Disable C locale coercion and UTF-8 mode to not depend
480 # on the current locale
481 env['PYTHONCOERCECLOCALE'] = '0'
482 env['PYTHONUTF8'] = '0'
483
484 out, err = self.run_embedded_interpreter(testname, env=env)
485 # Ignore err
486 config = json.loads(out)
487
488 self.check_core_config(config, expected, env)
489 self.check_main_config(config)
490 self.check_global_config(config)
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100491
Victor Stinner56b29b62018-07-26 18:57:56 +0200492 def test_init_default_config(self):
493 self.check_config("init_default_config", {})
494
495 def test_init_global_config(self):
496 config = {
497 'program_name': './globalvar',
498 'site_import': 0,
499 'bytes_warning': 1,
500 'inspect': 1,
501 'interactive': 1,
502 'optimization_level': 2,
503 'write_bytecode': 0,
504 'verbose': 1,
505 'quiet': 1,
Victor Stinner98512272018-08-01 03:07:00 +0200506 'buffered_stdio': 0,
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200507
Victor Stinner56b29b62018-07-26 18:57:56 +0200508 'utf8_mode': 1,
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200509 'stdio_encoding': 'utf-8',
510 'stdio_errors': 'surrogateescape',
Victor Stinnerb2457ef2018-08-29 13:25:36 +0200511 'filesystem_encoding': 'utf-8',
512 'filesystem_errors': self.UTF8_MODE_ERRORS,
Victor Stinner56b29b62018-07-26 18:57:56 +0200513 'user_site_directory': 0,
Victor Stinnerb75d7e22018-08-01 02:13:04 +0200514 '_frozen': 1,
Victor Stinner56b29b62018-07-26 18:57:56 +0200515 }
516 self.check_config("init_global_config", config)
517
518 def test_init_from_config(self):
519 config = {
520 'install_signal_handlers': 0,
521 'use_hash_seed': 1,
522 'hash_seed': 123,
523 'allocator': 'malloc_debug',
524 'tracemalloc': 2,
525 'import_time': 1,
526 'show_ref_count': 1,
527 'show_alloc_count': 1,
528 'malloc_stats': 1,
529
530 'utf8_mode': 1,
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200531 'stdio_encoding': 'iso8859-1',
532 'stdio_errors': 'replace',
Victor Stinnerb2457ef2018-08-29 13:25:36 +0200533 'filesystem_encoding': 'utf-8',
534 'filesystem_errors': self.UTF8_MODE_ERRORS,
Victor Stinner56b29b62018-07-26 18:57:56 +0200535
536 'pycache_prefix': 'conf_pycache_prefix',
537 'program_name': './conf_program_name',
Victor Stinner01de89c2018-11-14 17:39:45 +0100538 'argv': ['-c', 'pass'],
Victor Stinner56b29b62018-07-26 18:57:56 +0200539 'program': 'conf_program',
Victor Stinner01de89c2018-11-14 17:39:45 +0100540 'xoptions': ['core_xoption1=3', 'core_xoption2=', 'core_xoption3'],
541 'warnoptions': ['default', 'error::ResourceWarning'],
Victor Stinner56b29b62018-07-26 18:57:56 +0200542
543 'site_import': 0,
544 'bytes_warning': 1,
545 'inspect': 1,
546 'interactive': 1,
547 'optimization_level': 2,
548 'write_bytecode': 0,
549 'verbose': 1,
550 'quiet': 1,
Victor Stinner98512272018-08-01 03:07:00 +0200551 'buffered_stdio': 0,
Victor Stinner56b29b62018-07-26 18:57:56 +0200552 'user_site_directory': 0,
553 'faulthandler': 1,
Victor Stinnerb75d7e22018-08-01 02:13:04 +0200554
Victor Stinner56b29b62018-07-26 18:57:56 +0200555 '_check_hash_pycs_mode': 'always',
Victor Stinnerb75d7e22018-08-01 02:13:04 +0200556 '_frozen': 1,
Victor Stinner56b29b62018-07-26 18:57:56 +0200557 }
558 self.check_config("init_from_config", config)
559
560 def test_init_env(self):
561 config = {
562 'use_hash_seed': 1,
563 'hash_seed': 42,
564 'allocator': 'malloc_debug',
565 'tracemalloc': 2,
566 'import_time': 1,
567 'malloc_stats': 1,
568 'utf8_mode': 1,
Victor Stinnerb2457ef2018-08-29 13:25:36 +0200569 'filesystem_encoding': 'utf-8',
570 'filesystem_errors': self.UTF8_MODE_ERRORS,
Victor Stinner56b29b62018-07-26 18:57:56 +0200571 'inspect': 1,
572 'optimization_level': 2,
573 'pycache_prefix': 'env_pycache_prefix',
574 'write_bytecode': 0,
575 'verbose': 1,
Victor Stinner98512272018-08-01 03:07:00 +0200576 'buffered_stdio': 0,
Victor Stinnerdfe0dc72018-08-29 11:47:29 +0200577 'stdio_encoding': 'iso8859-1',
578 'stdio_errors': 'replace',
Victor Stinner56b29b62018-07-26 18:57:56 +0200579 'user_site_directory': 0,
580 'faulthandler': 1,
581 'dev_mode': 1,
582 }
583 self.check_config("init_env", config)
584
585 def test_init_dev_mode(self):
586 config = {
587 'dev_mode': 1,
588 'faulthandler': 1,
589 'allocator': 'debug',
590 }
591 self.check_config("init_dev_mode", config)
592
593 def test_init_isolated(self):
594 config = {
595 'isolated': 1,
596 'use_environment': 0,
597 'user_site_directory': 0,
598 }
599 self.check_config("init_isolated", config)
600
601
Nick Coghlan39f0bb52017-11-28 08:11:51 +1000602if __name__ == "__main__":
603 unittest.main()