diff options
author | Victor Stinner <vstinner@redhat.com> | 2018-11-14 01:01:52 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-14 01:01:52 (GMT) |
commit | 35c28d562ec7249f2a6aef8e326eadac130a1656 (patch) | |
tree | 3a6d8ab6b5348965a80653293b71a6acf4b0b160 | |
parent | 52fb9f14b1b872f088e8110179aa7071fc06bbde (diff) | |
download | cpython-35c28d562ec7249f2a6aef8e326eadac130a1656.zip cpython-35c28d562ec7249f2a6aef8e326eadac130a1656.tar.gz cpython-35c28d562ec7249f2a6aef8e326eadac130a1656.tar.bz2 |
[3.7] bpo-35233: Rewrite test_embed.InitConfigTests (GH-10524) (GH-10529)
* Add C functions:
* _Py_GetGlobalVariablesAsDict()
* _PyCoreConfig_AsDict()
* _PyMainInterpreterConfig_AsDict()
* Add new _testcapi methods:
* get_global_config()
* get_core_config()
* get_main_config()
* test.pythoninfo: get global, core and main configuration
* _testembed now serializes global, core and main configurations
using JSON to reuse _Py_GetGlobalVariablesAsDict(),
_PyCoreConfig_AsDict() and _PyMainInterpreterConfig_AsDict(),
rather than duplicating code.
* test_embed.InitConfigTests now test much more configuration
variables
-rw-r--r-- | Include/pylifecycle.h | 5 | ||||
-rw-r--r-- | Lib/test/pythoninfo.py | 31 | ||||
-rw-r--r-- | Lib/test/test_embed.py | 200 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 28 | ||||
-rw-r--r-- | Modules/main.c | 230 | ||||
-rw-r--r-- | Programs/_testembed.c | 133 |
6 files changed, 498 insertions, 129 deletions
diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index 1192961..41f7d14 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -61,11 +61,14 @@ PyAPI_FUNC(_PyInitError) _Py_InitializeFromConfig( PyAPI_FUNC(void) _Py_Initialize_ReadEnvVarsNoAlloc(void); #endif +PyAPI_FUNC(PyObject *) _Py_GetGlobalVariablesAsDict(void); + PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *); PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *); PyAPI_FUNC(int) _PyCoreConfig_Copy( _PyCoreConfig *config, const _PyCoreConfig *config2); +PyAPI_FUNC(PyObject *) _PyCoreConfig_AsDict(const _PyCoreConfig *config); PyAPI_FUNC(void) _PyCoreConfig_SetGlobalConfig( const _PyCoreConfig *config); @@ -77,6 +80,8 @@ PyAPI_FUNC(void) _PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *); PyAPI_FUNC(int) _PyMainInterpreterConfig_Copy( _PyMainInterpreterConfig *config, const _PyMainInterpreterConfig *config2); +PyAPI_FUNC(PyObject*) _PyMainInterpreterConfig_AsDict( + const _PyMainInterpreterConfig *config); PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter( PyInterpreterState *interp, diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 4a563e9..9257fdf 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -142,7 +142,7 @@ def collect_platform(info_add): info_add('platform.python_implementation', platform.python_implementation()) info_add('platform.platform', - platform.platform(aliased=True, terse=True)) + platform.platform(aliased=True)) def collect_locale(info_add): @@ -525,6 +525,33 @@ def collect_cc(info_add): info_add('CC.version', text) +def collect_gdbm(info_add): + try: + from _gdbm import _GDBM_VERSION + except ImportError: + return + + info_add('gdbm.GDBM_VERSION', '.'.join(map(str, _GDBM_VERSION))) + + +def collect_get_config(info_add): + # Dump global configuration variables, _PyCoreConfig + # and _PyMainInterpreterConfig + try: + from _testcapi import get_global_config, get_core_config, get_main_config + except ImportError: + return + + for prefix, get_config_func in ( + ('global_config', get_global_config), + ('core_config', get_core_config), + ('main_config', get_main_config), + ): + config = get_config_func() + for key in sorted(config): + info_add('%s[%s]' % (prefix, key), repr(config[key])) + + def collect_info(info): error = False info_add = info.add @@ -552,6 +579,8 @@ def collect_info(info): collect_testcapi, collect_resource, collect_cc, + collect_gdbm, + collect_get_config, # Collecting from tests should be last as they have side effects. collect_test_socket, diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 2927458..62a20ab 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -3,6 +3,7 @@ from test import support import unittest from collections import namedtuple +import json import os import re import subprocess @@ -251,12 +252,52 @@ class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase): class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): maxDiff = 4096 - DEFAULT_CONFIG = { + UTF8_MODE_ERRORS = ('surrogatepass' if sys.platform == 'win32' + else 'surrogateescape') + # FIXME: untested core configuration variables + UNTESTED_CORE_CONFIG = ( + 'base_exec_prefix', + 'base_prefix', + 'exec_prefix', + 'executable', + 'home', + 'module_search_path_env', + 'module_search_paths', + 'prefix', + ) + # FIXME: untested main configuration variables + UNTESTED_MAIN_CONFIG = ( + 'install_signal_handlers', + 'module_search_path', + ) + DEFAULT_GLOBAL_CONFIG = { + 'Py_BytesWarningFlag': 0, + 'Py_DebugFlag': 0, + 'Py_DontWriteBytecodeFlag': 0, + 'Py_FrozenFlag': 0, + 'Py_HasFileSystemDefaultEncoding': 0, + 'Py_HashRandomizationFlag': 1, + 'Py_InspectFlag': 0, + 'Py_InteractiveFlag': 0, + 'Py_IsolatedFlag': 0, + 'Py_NoSiteFlag': 0, + 'Py_NoUserSiteDirectory': 0, + 'Py_OptimizeFlag': 0, + 'Py_QuietFlag': 0, + 'Py_UnbufferedStdioFlag': 0, + 'Py_VerboseFlag': 0, + } + if os.name == 'nt': + DEFAULT_GLOBAL_CONFIG['Py_HasFileSystemDefaultEncoding'] = 1 + DEFAULT_GLOBAL_CONFIG['Py_LegacyWindowsFSEncodingFlag'] = 0 + DEFAULT_GLOBAL_CONFIG['Py_LegacyWindowsStdioFlag'] = 0 + + DEFAULT_CORE_CONFIG = { 'install_signal_handlers': 1, - 'Py_IgnoreEnvironmentFlag': 0, + 'ignore_environment': 0, 'use_hash_seed': 0, 'hash_seed': 0, - 'allocator': '(null)', + 'allocator': None, 'dev_mode': 0, 'faulthandler': 0, 'tracemalloc': 0, @@ -265,34 +306,42 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'show_alloc_count': 0, 'dump_refs': 0, 'malloc_stats': 0, - 'utf8_mode': 0, + 'utf8_mode': 0, 'coerce_c_locale': 0, 'coerce_c_locale_warn': 0, 'program_name': './_testembed', - 'argc': 0, - 'argv': '[]', - 'program': '(null)', + 'argv': [], + 'program': None, - 'Py_IsolatedFlag': 0, - 'Py_NoSiteFlag': 0, - 'Py_BytesWarningFlag': 0, - 'Py_InspectFlag': 0, - 'Py_InteractiveFlag': 0, - 'Py_OptimizeFlag': 0, - 'Py_DebugFlag': 0, - 'Py_DontWriteBytecodeFlag': 0, - 'Py_VerboseFlag': 0, - 'Py_QuietFlag': 0, - 'Py_NoUserSiteDirectory': 0, - 'Py_UnbufferedStdioFlag': 0, + 'xoptions': [], + 'warnoptions': [], '_disable_importlib': 0, - 'Py_FrozenFlag': 0, } - def check_config(self, testname, expected): + 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 check_config(self, testname, expected, expected_global): + expected = dict(self.DEFAULT_CORE_CONFIG, **expected) + env = dict(os.environ) for key in list(env): if key.startswith('PYTHON'): @@ -301,42 +350,78 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): # on the current locale env['PYTHONCOERCECLOCALE'] = '0' env['PYTHONUTF8'] = '0' + out, err = self.run_embedded_interpreter(testname, env=env) # Ignore err - expected = dict(self.DEFAULT_CONFIG, **expected) - for key, value in expected.items(): - expected[key] = str(value) + config = json.loads(out) + core_config = config['core_config'] + executable = core_config['executable'] + main_config = config['main_config'] + + for key in self.UNTESTED_MAIN_CONFIG: + del main_config[key] + + expected_main = { + 'argv': [], + 'prefix': sys.prefix, + 'executable': core_config['executable'], + 'base_prefix': sys.base_prefix, + 'base_exec_prefix': sys.base_exec_prefix, + 'warnoptions': core_config['warnoptions'], + 'xoptions': {}, + 'exec_prefix': core_config['exec_prefix'], + } + self.assertEqual(main_config, expected_main) - config = {} - for line in out.splitlines(): - key, value = line.split(' = ', 1) - config[key] = value - self.assertEqual(config, expected) + expected_global = dict(self.DEFAULT_GLOBAL_CONFIG, **expected_global) + + if 'Py_FileSystemDefaultEncoding' not in expected_global: + isolated = expected_global['Py_IsolatedFlag'] + fs_encoding, fs_errors = self.get_filesystem_encoding(isolated, env) + expected_global['Py_FileSystemDefaultEncodeErrors'] = fs_errors + expected_global['Py_FileSystemDefaultEncoding'] = fs_encoding + + for global_key, core_key in ( + ('Py_UTF8Mode', 'utf8_mode'), + ('Py_IgnoreEnvironmentFlag', 'ignore_environment'), + ): + expected_global[global_key] = core_config[core_key] + + self.assertEqual(config['global_config'], expected_global) + + for key in self.UNTESTED_CORE_CONFIG: + core_config.pop(key, None) + self.assertEqual(core_config, expected) def test_init_default_config(self): - self.check_config("init_default_config", {}) + self.check_config("init_default_config", {}, {}) def test_init_global_config(self): - config = { + core_config = { 'program_name': './globalvar', - 'Py_NoSiteFlag': 1, + 'utf8_mode': 1, + } + global_config = { 'Py_BytesWarningFlag': 1, + 'Py_DontWriteBytecodeFlag': 1, + 'Py_HasFileSystemDefaultEncoding': 1, + 'Py_FileSystemDefaultEncodeErrors': self.UTF8_MODE_ERRORS, + 'Py_FileSystemDefaultEncoding': 'utf-8', 'Py_InspectFlag': 1, 'Py_InteractiveFlag': 1, + 'Py_NoSiteFlag': 1, + 'Py_NoUserSiteDirectory': 1, 'Py_OptimizeFlag': 2, - 'Py_DontWriteBytecodeFlag': 1, - 'Py_VerboseFlag': 1, 'Py_QuietFlag': 1, - 'Py_UnbufferedStdioFlag': 1, - 'utf8_mode': 1, - 'Py_NoUserSiteDirectory': 1, + 'Py_VerboseFlag': 1, 'Py_FrozenFlag': 1, + 'Py_UnbufferedStdioFlag': 1, } - self.check_config("init_global_config", config) + self.check_config("init_global_config", core_config, global_config) def test_init_from_config(self): - config = { + core_config = { 'install_signal_handlers': 0, 'use_hash_seed': 1, 'hash_seed': 123, @@ -354,10 +439,14 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'faulthandler': 1, } - self.check_config("init_from_config", config) + global_config = { + 'Py_HasFileSystemDefaultEncoding': 1, + 'Py_NoUserSiteDirectory': 0, + } + self.check_config("init_from_config", core_config, global_config) def test_init_env(self): - config = { + core_config = { 'use_hash_seed': 1, 'hash_seed': 42, 'allocator': 'malloc_debug', @@ -365,32 +454,39 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'import_time': 1, 'malloc_stats': 1, 'utf8_mode': 1, + 'faulthandler': 1, + 'dev_mode': 1, + } + global_config = { + 'Py_DontWriteBytecodeFlag': 1, + 'Py_HasFileSystemDefaultEncoding': 1, 'Py_InspectFlag': 1, + 'Py_NoUserSiteDirectory': 1, 'Py_OptimizeFlag': 2, - 'Py_DontWriteBytecodeFlag': 1, - 'Py_VerboseFlag': 1, 'Py_UnbufferedStdioFlag': 1, - 'Py_NoUserSiteDirectory': 1, - 'faulthandler': 1, - 'dev_mode': 1, + 'Py_VerboseFlag': 1, + 'Py_FileSystemDefaultEncoding': 'utf-8', + 'Py_FileSystemDefaultEncodeErrors': self.UTF8_MODE_ERRORS, } - self.check_config("init_env", config) + self.check_config("init_env", core_config, global_config) def test_init_dev_mode(self): - config = { + core_config = { 'dev_mode': 1, 'faulthandler': 1, 'allocator': 'debug', } - self.check_config("init_dev_mode", config) + self.check_config("init_dev_mode", core_config, {}) def test_init_isolated(self): - config = { + core_config = { + 'ignore_environment': 1, + } + global_config = { 'Py_IsolatedFlag': 1, - 'Py_IgnoreEnvironmentFlag': 1, 'Py_NoUserSiteDirectory': 1, } - self.check_config("init_isolated", config) + self.check_config("init_isolated", core_config, global_config) if __name__ == "__main__": diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 174b767..eafe347 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4551,6 +4551,31 @@ new_hamt(PyObject *self, PyObject *args) } +static PyObject * +get_global_config(PyObject *self, PyObject *Py_UNUSED(args)) +{ + return _Py_GetGlobalVariablesAsDict(); +} + + +static PyObject * +get_core_config(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyInterpreterState *interp = PyThreadState_GET()->interp; + const _PyCoreConfig *config = &interp->core_config; + return _PyCoreConfig_AsDict(config); +} + + +static PyObject * +get_main_config(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyInterpreterState *interp = PyThreadState_GET()->interp; + const _PyMainInterpreterConfig *config = &interp->config; + return _PyMainInterpreterConfig_AsDict(config); +} + + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS}, @@ -4777,6 +4802,9 @@ static PyMethodDef TestMethods[] = { {"get_mapping_items", get_mapping_items, METH_O}, {"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS}, {"hamt", new_hamt, METH_NOARGS}, + {"get_global_config", get_global_config, METH_NOARGS}, + {"get_core_config", get_core_config, METH_NOARGS}, + {"get_main_config", get_main_config, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/main.c b/Modules/main.c index 7771d27..ab7ac86 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -1297,7 +1297,7 @@ pymain_init_core_argv(_PyMain *pymain, _PyCoreConfig *config, static PyObject* -wstrlist_as_pylist(int len, wchar_t **list) +_Py_wstrlist_as_pylist(int len, wchar_t **list) { assert(list != NULL || len < 1); @@ -1361,6 +1361,77 @@ pymain_update_sys_path(_PyMain *pymain, PyObject *path0) } +PyObject * +_Py_GetGlobalVariablesAsDict(void) +{ + PyObject *dict, *obj; + + dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + +#define SET_ITEM(KEY, EXPR) \ + do { \ + obj = (EXPR); \ + if (obj == NULL) { \ + return NULL; \ + } \ + int res = PyDict_SetItemString(dict, (KEY), obj); \ + Py_DECREF(obj); \ + if (res < 0) { \ + goto fail; \ + } \ + } while (0) +#define SET_ITEM_INT(VAR) \ + SET_ITEM(#VAR, PyLong_FromLong(VAR)) +#define FROM_STRING(STR) \ + ((STR != NULL) ? \ + PyUnicode_FromString(STR) \ + : (Py_INCREF(Py_None), Py_None)) +#define SET_ITEM_STR(VAR) \ + SET_ITEM(#VAR, FROM_STRING(VAR)) + + SET_ITEM_STR(Py_FileSystemDefaultEncoding); + SET_ITEM_INT(Py_HasFileSystemDefaultEncoding); + SET_ITEM_STR(Py_FileSystemDefaultEncodeErrors); + + SET_ITEM_INT(Py_UTF8Mode); + SET_ITEM_INT(Py_DebugFlag); + SET_ITEM_INT(Py_VerboseFlag); + SET_ITEM_INT(Py_QuietFlag); + SET_ITEM_INT(Py_InteractiveFlag); + SET_ITEM_INT(Py_InspectFlag); + + SET_ITEM_INT(Py_OptimizeFlag); + SET_ITEM_INT(Py_NoSiteFlag); + SET_ITEM_INT(Py_BytesWarningFlag); + SET_ITEM_INT(Py_FrozenFlag); + SET_ITEM_INT(Py_IgnoreEnvironmentFlag); + SET_ITEM_INT(Py_DontWriteBytecodeFlag); + SET_ITEM_INT(Py_NoUserSiteDirectory); + SET_ITEM_INT(Py_UnbufferedStdioFlag); + SET_ITEM_INT(Py_HashRandomizationFlag); + SET_ITEM_INT(Py_IsolatedFlag); + +#ifdef MS_WINDOWS + SET_ITEM_INT(Py_LegacyWindowsFSEncodingFlag); + SET_ITEM_INT(Py_LegacyWindowsStdioFlag); +#endif + + return dict; + +fail: + Py_DECREF(dict); + return NULL; + +#undef FROM_STRING +#undef SET_ITEM +#undef SET_ITEM_INT +#undef SET_ITEM_STR +} + + void _PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config) { @@ -2432,6 +2503,110 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) } +PyObject * +_PyCoreConfig_AsDict(const _PyCoreConfig *config) +{ + PyObject *dict, *obj; + + dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + +#define FROM_STRING(STR) \ + ((STR != NULL) ? \ + PyUnicode_FromString(STR) \ + : (Py_INCREF(Py_None), Py_None)) +#define FROM_WSTRING(STR) \ + ((STR != NULL) ? \ + PyUnicode_FromWideChar(STR, -1) \ + : (Py_INCREF(Py_None), Py_None)) +#define SET_ITEM(KEY, EXPR) \ + do { \ + obj = (EXPR); \ + if (obj == NULL) { \ + return NULL; \ + } \ + int res = PyDict_SetItemString(dict, (KEY), obj); \ + Py_DECREF(obj); \ + if (res < 0) { \ + goto fail; \ + } \ + } while (0) + + SET_ITEM("install_signal_handlers", + PyLong_FromLong(config->install_signal_handlers)); + SET_ITEM("ignore_environment", + PyLong_FromLong(config->ignore_environment)); + SET_ITEM("use_hash_seed", + PyLong_FromLong(config->use_hash_seed)); + SET_ITEM("hash_seed", + PyLong_FromUnsignedLong(config->hash_seed)); + SET_ITEM("allocator", + FROM_STRING(config->allocator)); + SET_ITEM("dev_mode", + PyLong_FromLong(config->dev_mode)); + SET_ITEM("faulthandler", + PyLong_FromLong(config->faulthandler)); + SET_ITEM("tracemalloc", + PyLong_FromLong(config->tracemalloc)); + SET_ITEM("import_time", + PyLong_FromLong(config->import_time)); + SET_ITEM("show_ref_count", + PyLong_FromLong(config->show_ref_count)); + SET_ITEM("show_alloc_count", + PyLong_FromLong(config->show_alloc_count)); + SET_ITEM("dump_refs", + PyLong_FromLong(config->dump_refs)); + SET_ITEM("malloc_stats", + PyLong_FromLong(config->malloc_stats)); + SET_ITEM("coerce_c_locale", + PyLong_FromLong(config->coerce_c_locale)); + SET_ITEM("coerce_c_locale_warn", + PyLong_FromLong(config->coerce_c_locale_warn)); + SET_ITEM("utf8_mode", + PyLong_FromLong(config->utf8_mode)); + SET_ITEM("program_name", + FROM_WSTRING(config->program_name)); + SET_ITEM("argv", + _Py_wstrlist_as_pylist(config->argc, config->argv)); + SET_ITEM("program", + FROM_WSTRING(config->program)); + SET_ITEM("xoptions", + _Py_wstrlist_as_pylist(config->nxoption, config->xoptions)); + SET_ITEM("warnoptions", + _Py_wstrlist_as_pylist(config->nwarnoption, config->warnoptions)); + SET_ITEM("module_search_path_env", + FROM_WSTRING(config->module_search_path_env)); + SET_ITEM("home", + FROM_WSTRING(config->home)); + SET_ITEM("module_search_paths", + _Py_wstrlist_as_pylist(config->nmodule_search_path, config->module_search_paths)); + SET_ITEM("executable", + FROM_WSTRING(config->executable)); + SET_ITEM("prefix", + FROM_WSTRING(config->prefix)); + SET_ITEM("base_prefix", + FROM_WSTRING(config->base_prefix)); + SET_ITEM("exec_prefix", + FROM_WSTRING(config->exec_prefix)); + SET_ITEM("base_exec_prefix", + FROM_WSTRING(config->base_exec_prefix)); + SET_ITEM("_disable_importlib", + PyLong_FromLong(config->_disable_importlib)); + + return dict; + +fail: + Py_DECREF(dict); + return NULL; + +#undef FROM_STRING +#undef FROM_WSTRING +#undef SET_ITEM +} + + void _PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config) { @@ -2501,6 +2676,57 @@ _PyMainInterpreterConfig_Copy(_PyMainInterpreterConfig *config, } +PyObject* +_PyMainInterpreterConfig_AsDict(const _PyMainInterpreterConfig *config) +{ + PyObject *dict, *obj; + int res; + + dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + +#define SET_ITEM(KEY, ATTR) \ + do { \ + obj = config->ATTR; \ + if (obj == NULL) { \ + obj = Py_None; \ + } \ + res = PyDict_SetItemString(dict, (KEY), obj); \ + if (res < 0) { \ + goto fail; \ + } \ + } while (0) + + obj = PyLong_FromLong(config->install_signal_handlers); + if (obj == NULL) { + goto fail; + } + res = PyDict_SetItemString(dict, "install_signal_handlers", obj); + Py_DECREF(obj); + if (res < 0) { + goto fail; + } + + SET_ITEM("argv", argv); + SET_ITEM("executable", executable); + SET_ITEM("prefix", prefix); + SET_ITEM("base_prefix", base_prefix); + SET_ITEM("exec_prefix", exec_prefix); + SET_ITEM("base_exec_prefix", base_exec_prefix); + SET_ITEM("warnoptions", warnoptions); + SET_ITEM("xoptions", xoptions); + SET_ITEM("module_search_path", module_search_path); + + return dict; + +fail: + Py_DECREF(dict); + return NULL; + +#undef SET_ITEM +} _PyInitError @@ -2530,7 +2756,7 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config, #define COPY_WSTRLIST(ATTR, LEN, LIST) \ do { \ if (ATTR == NULL) { \ - ATTR = wstrlist_as_pylist(LEN, LIST); \ + ATTR = _Py_wstrlist_as_pylist(LEN, LIST); \ if (ATTR == NULL) { \ return _Py_INIT_NO_MEMORY(); \ } \ diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 6c35f95..b198962 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -293,92 +293,77 @@ static int test_initialize_pymain(void) } -static void -dump_config(void) +static int +dump_config_impl(void) { -#define ASSERT_EQUAL(a, b) \ - if ((a) != (b)) { \ - printf("ERROR: %s != %s (%i != %i)\n", #a, #b, (a), (b)); \ - exit(1); \ + PyObject *config = NULL; + PyObject *dict = NULL; + + config = PyDict_New(); + if (config == NULL) { + goto error; } -#define ASSERT_STR_EQUAL(a, b) \ - if ((a) == NULL || (b == NULL) || wcscmp((a), (b)) != 0) { \ - printf("ERROR: %s != %s ('%ls' != '%ls')\n", #a, #b, (a), (b)); \ - exit(1); \ + + /* global config */ + dict = _Py_GetGlobalVariablesAsDict(); + if (dict == NULL) { + goto error; + } + if (PyDict_SetItemString(config, "global_config", dict) < 0) { + goto error; } + Py_CLEAR(dict); + /* core config */ PyInterpreterState *interp = PyThreadState_Get()->interp; - _PyCoreConfig *config = &interp->core_config; - - printf("install_signal_handlers = %i\n", config->install_signal_handlers); - - printf("Py_IgnoreEnvironmentFlag = %i\n", Py_IgnoreEnvironmentFlag); + const _PyCoreConfig *core_config = &interp->core_config; + dict = _PyCoreConfig_AsDict(core_config); + if (dict == NULL) { + goto error; + } + if (PyDict_SetItemString(config, "core_config", dict) < 0) { + goto error; + } + Py_CLEAR(dict); - printf("use_hash_seed = %i\n", config->use_hash_seed); - printf("hash_seed = %lu\n", config->hash_seed); + /* main config */ + const _PyMainInterpreterConfig *main_config = &interp->config; + dict = _PyMainInterpreterConfig_AsDict(main_config); + if (dict == NULL) { + goto error; + } + if (PyDict_SetItemString(config, "main_config", dict) < 0) { + goto error; + } + Py_CLEAR(dict); + + PyObject *json = PyImport_ImportModule("json"); + PyObject *res = PyObject_CallMethod(json, "dumps", "O", config); + Py_DECREF(json); + Py_CLEAR(config); + if (res == NULL) { + goto error; + } - printf("allocator = %s\n", config->allocator); + PySys_FormatStdout("%S\n", res); + Py_DECREF(res); - printf("dev_mode = %i\n", config->dev_mode); - printf("faulthandler = %i\n", config->faulthandler); - printf("tracemalloc = %i\n", config->tracemalloc); - printf("import_time = %i\n", config->import_time); - printf("show_ref_count = %i\n", config->show_ref_count); - printf("show_alloc_count = %i\n", config->show_alloc_count); - printf("dump_refs = %i\n", config->dump_refs); - printf("malloc_stats = %i\n", config->malloc_stats); + return 0; - printf("coerce_c_locale = %i\n", config->coerce_c_locale); - printf("coerce_c_locale_warn = %i\n", config->coerce_c_locale_warn); - printf("utf8_mode = %i\n", config->utf8_mode); +error: + Py_XDECREF(config); + Py_XDECREF(dict); + return -1; +} - printf("program_name = %ls\n", config->program_name); - ASSERT_STR_EQUAL(config->program_name, Py_GetProgramName()); - printf("argc = %i\n", config->argc); - printf("argv = ["); - for (int i=0; i < config->argc; i++) { - if (i) { - printf(", "); - } - printf("\"%ls\"", config->argv[i]); +static void +dump_config(void) +{ + if (dump_config_impl() < 0) { + fprintf(stderr, "failed to dump the configuration:\n"); + PyErr_Print(); } - printf("]\n"); - - printf("program = %ls\n", config->program); - /* FIXME: test xoptions */ - /* FIXME: test warnoptions */ - /* FIXME: test module_search_path_env */ - /* FIXME: test home */ - /* FIXME: test module_search_paths */ - /* FIXME: test executable */ - /* FIXME: test prefix */ - /* FIXME: test base_prefix */ - /* FIXME: test exec_prefix */ - /* FIXME: test base_exec_prefix */ - /* FIXME: test dll_path */ - - printf("Py_IsolatedFlag = %i\n", Py_IsolatedFlag); - printf("Py_NoSiteFlag = %i\n", Py_NoSiteFlag); - printf("Py_BytesWarningFlag = %i\n", Py_BytesWarningFlag); - printf("Py_InspectFlag = %i\n", Py_InspectFlag); - printf("Py_InteractiveFlag = %i\n", Py_InteractiveFlag); - printf("Py_OptimizeFlag = %i\n", Py_OptimizeFlag); - printf("Py_DebugFlag = %i\n", Py_DebugFlag); - printf("Py_DontWriteBytecodeFlag = %i\n", Py_DontWriteBytecodeFlag); - printf("Py_VerboseFlag = %i\n", Py_VerboseFlag); - printf("Py_QuietFlag = %i\n", Py_QuietFlag); - printf("Py_NoUserSiteDirectory = %i\n", Py_NoUserSiteDirectory); - printf("Py_UnbufferedStdioFlag = %i\n", Py_UnbufferedStdioFlag); - /* FIXME: test legacy_windows_fs_encoding */ - /* FIXME: test legacy_windows_stdio */ - - printf("_disable_importlib = %i\n", config->_disable_importlib); - /* cannot test _Py_CheckHashBasedPycsMode: the symbol is not exported */ - printf("Py_FrozenFlag = %i\n", Py_FrozenFlag); - -#undef ASSERT_EQUAL -#undef ASSERT_STR_EQUAL } |