diff options
author | Victor Stinner <vstinner@redhat.com> | 2018-11-26 10:54:12 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-26 10:54:12 (GMT) |
commit | a6537fb7c2f7a007b4ab616c4617afd56d18347d (patch) | |
tree | c10494d827432873a10e5a0931b36e7aecfa3c45 | |
parent | f0e0f2008d160cdd7e5bc02ea61c43f8c7b2b82f (diff) | |
download | cpython-a6537fb7c2f7a007b4ab616c4617afd56d18347d.zip cpython-a6537fb7c2f7a007b4ab616c4617afd56d18347d.tar.gz cpython-a6537fb7c2f7a007b4ab616c4617afd56d18347d.tar.bz2 |
bpo-35313: Fix test_embed when run from venv (GH-10713)
test_embed.InitConfigTests now gets the expected configuration from
a child process run with -S to not run the site module.
-rw-r--r-- | Lib/test/test_embed.py | 131 |
1 files changed, 68 insertions, 63 deletions
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 3f383d7..b6c25e3 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -9,6 +9,7 @@ import platform import re import subprocess import sys +import textwrap MS_WINDOWS = (os.name == 'nt') @@ -265,6 +266,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'executable', 'module_search_paths', ) + # Mark config which should be get by get_default_config() + GET_DEFAULT_CONFIG = object() DEFAULT_CORE_CONFIG = { 'install_signal_handlers': 1, 'use_environment': 1, @@ -280,9 +283,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'dump_refs': 0, 'malloc_stats': 0, - # None means that the value is get by get_locale_encoding() - 'filesystem_encoding': None, - 'filesystem_errors': None, + 'filesystem_encoding': GET_DEFAULT_CONFIG, + 'filesystem_errors': GET_DEFAULT_CONFIG, 'utf8_mode': 0, 'coerce_c_locale': 0, @@ -298,10 +300,11 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'module_search_path_env': None, 'home': None, - 'prefix': sys.prefix, - 'base_prefix': sys.base_prefix, - 'exec_prefix': sys.exec_prefix, - 'base_exec_prefix': sys.base_exec_prefix, + + 'prefix': GET_DEFAULT_CONFIG, + 'base_prefix': GET_DEFAULT_CONFIG, + 'exec_prefix': GET_DEFAULT_CONFIG, + 'base_exec_prefix': GET_DEFAULT_CONFIG, 'isolated': 0, 'site_import': 1, @@ -316,9 +319,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'user_site_directory': 1, 'buffered_stdio': 1, - # None means that the value is get by get_stdio_encoding() - 'stdio_encoding': None, - 'stdio_errors': None, + 'stdio_encoding': GET_DEFAULT_CONFIG, + 'stdio_errors': GET_DEFAULT_CONFIG, '_install_importlib': 1, '_check_hash_pycs_mode': 'default', @@ -379,35 +381,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): ('Py_LegacyWindowsStdioFlag', 'legacy_windows_stdio'), )) - def get_stdio_encoding(self, env): - code = 'import sys; print(sys.stdout.encoding, sys.stdout.errors)' - args = (sys.executable, '-c', code) - proc = subprocess.run(args, env=env, text=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - if proc.returncode: - raise Exception(f"failed to get the stdio encoding: stdout={proc.stdout!r}") - out = proc.stdout.rstrip() - return out.split() - - def get_filesystem_encoding(self, isolated, env): - code = ('import codecs, locale, sys; ' - 'print(sys.getfilesystemencoding(), ' - 'sys.getfilesystemencodeerrors())') - args = (sys.executable, '-c', code) - env = dict(env) - if not isolated: - env['PYTHONCOERCECLOCALE'] = '0' - env['PYTHONUTF8'] = '0' - proc = subprocess.run(args, text=True, env=env, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - if proc.returncode: - raise Exception(f"failed to get the locale encoding: " - f"stdout={proc.stdout!r} stderr={proc.stderr!r}") - out = proc.stdout.rstrip() - return out.split() - def main_xoptions(self, xoptions_list): xoptions = {} for opt in xoptions_list: @@ -423,27 +396,61 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): main_config = config['main_config'] # main config - expected_main = {} + expected = {} for key in self.COPY_MAIN_CONFIG: - expected_main[key] = core_config[key] - expected_main['module_search_path'] = core_config['module_search_paths'] - expected_main['xoptions'] = self.main_xoptions(core_config['xoptions']) - self.assertEqual(main_config, expected_main) + expected[key] = core_config[key] + expected['module_search_path'] = core_config['module_search_paths'] + expected['xoptions'] = self.main_xoptions(core_config['xoptions']) + self.assertEqual(main_config, expected) - def check_core_config(self, config, expected, env): - if expected['stdio_encoding'] is None or expected['stdio_errors'] is None: - res = self.get_stdio_encoding(env) - if expected['stdio_encoding'] is None: - expected['stdio_encoding'] = res[0] - if expected['stdio_errors'] is None: - expected['stdio_errors'] = res[1] - if expected['filesystem_encoding'] is None or expected['filesystem_errors'] is None: - res = self.get_filesystem_encoding(expected['isolated'], env) - if expected['filesystem_encoding'] is None: - expected['filesystem_encoding'] = res[0] - if expected['filesystem_errors'] is None: - expected['filesystem_errors'] = res[1] + def get_expected_config(self, expected, env): + expected = dict(self.DEFAULT_CORE_CONFIG, **expected) + code = textwrap.dedent(''' + import json + import locale + import sys + + data = { + 'stdio_encoding': sys.stdout.encoding, + 'stdio_errors': sys.stdout.errors, + 'prefix': sys.prefix, + 'base_prefix': sys.base_prefix, + 'exec_prefix': sys.exec_prefix, + 'base_exec_prefix': sys.base_exec_prefix, + 'filesystem_encoding': sys.getfilesystemencoding(), + 'filesystem_errors': sys.getfilesystemencodeerrors(), + } + + data = json.dumps(data) + data = data.encode('utf-8') + sys.stdout.buffer.write(data) + sys.stdout.buffer.flush() + ''') + + # Use -S to not import the site module: get the proper configuration + # when test_embed is run from a venv (bpo-35313) + args = (sys.executable, '-S', '-c', code) + env = dict(env) + if not expected['isolated']: + env['PYTHONCOERCECLOCALE'] = '0' + env['PYTHONUTF8'] = '0' + proc = subprocess.run(args, env=env, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + if proc.returncode: + raise Exception(f"failed to get the default config: " + f"stdout={proc.stdout!r} stderr={proc.stderr!r}") + stdout = proc.stdout.decode('utf-8') + config = json.loads(stdout) + + for key, value in expected.items(): + if value is self.GET_DEFAULT_CONFIG: + expected[key] = config[key] + return expected + + def check_core_config(self, config, expected, env): + expected = self.get_expected_config(expected, env) core_config = dict(config['core_config']) for key in self.UNTESTED_CORE_CONFIG: core_config.pop(key, None) @@ -452,20 +459,18 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): def check_global_config(self, config): core_config = config['core_config'] - expected_global = dict(self.DEFAULT_GLOBAL_CONFIG) + expected = dict(self.DEFAULT_GLOBAL_CONFIG) for item in self.COPY_GLOBAL_CONFIG: if len(item) == 3: global_key, core_key, opposite = item - expected_global[global_key] = 0 if core_config[core_key] else 1 + expected[global_key] = 0 if core_config[core_key] else 1 else: global_key, core_key = item - expected_global[global_key] = core_config[core_key] + expected[global_key] = core_config[core_key] - self.assertEqual(config['global_config'], expected_global) + self.assertEqual(config['global_config'], expected) def check_config(self, testname, expected): - expected = dict(self.DEFAULT_CORE_CONFIG, **expected) - env = dict(os.environ) # Remove PYTHON* environment variables to get deterministic environment for key in list(env): |