Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Include/cpython/coreconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,8 +400,7 @@ typedef struct {

/* --- Function used for testing ---------------------------------- */

PyAPI_FUNC(PyObject *) _Py_GetGlobalVariablesAsDict(void);
PyAPI_FUNC(PyObject *) _PyCoreConfig_AsDict(const _PyCoreConfig *config);
PyAPI_FUNC(PyObject*) _Py_GetConfigsAsDict(void);

#ifdef __cplusplus
}
Expand Down
3 changes: 0 additions & 3 deletions Include/cpython/pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ PyAPI_FUNC(void) _PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *);
PyAPI_FUNC(int) _PyMainInterpreterConfig_Copy(
_PyMainInterpreterConfig *config,
const _PyMainInterpreterConfig *config2);
/* Used by _testcapi.get_main_config() */
PyAPI_FUNC(PyObject*) _PyMainInterpreterConfig_AsDict(
const _PyMainInterpreterConfig *config);

PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter(
PyInterpreterState *interp,
Expand Down
8 changes: 6 additions & 2 deletions Include/internal/pycore_coreconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ PyAPI_FUNC(void) _Py_get_env_flag(_PyPreConfig *config,
PyAPI_FUNC(_PyInitError) _PyPreConfig_Read(_PyPreConfig *config,
const _PyArgv *args,
const _PyCoreConfig *coreconfig);
PyAPI_FUNC(int) _PyPreConfig_AsDict(const _PyPreConfig *config,
PyObject *dict);
PyAPI_FUNC(PyObject*) _PyPreConfig_AsDict(const _PyPreConfig *config);
PyAPI_FUNC(_PyInitError) _PyPreConfig_ReadFromArgv(_PyPreConfig *config,
const _PyArgv *args);
PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(_PyPreConfig *config);
Expand Down Expand Up @@ -121,6 +120,11 @@ PyAPI_FUNC(_PyInitError) _PyCoreConfig_ReadFromArgv(_PyCoreConfig *config,
const _PyArgv *args);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Write(const _PyCoreConfig *config);

/* --- _PyMainInterpreterConfig ----------------------------------- */

PyAPI_FUNC(PyObject*) _PyMainInterpreterConfig_AsDict(
const _PyMainInterpreterConfig *config);

#ifdef __cplusplus
}
#endif
Expand Down
13 changes: 5 additions & 8 deletions Lib/test/pythoninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,18 +598,15 @@ 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
from _testcapi import get_configs
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()
all_configs = get_configs()
for config_type in sorted(all_configs):
config = all_configs[config_type]
for key in sorted(config):
info_add('%s[%s]' % (prefix, key), repr(config[key]))
info_add('%s[%s]' % (config_type, key), repr(config[key]))


def collect_subprocess(info_add):
Expand Down
112 changes: 74 additions & 38 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,19 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
)
# Mark config which should be get by get_default_config()
GET_DEFAULT_CONFIG = object()
DEFAULT_PRE_CONFIG = {
'allocator': None,
'coerce_c_locale': 0,
'coerce_c_locale_warn': 0,
'dev_mode': 0,
'isolated': 0,
'use_environment': 1,
'utf8_mode': 0,
}
DEFAULT_CORE_CONFIG = {
'install_signal_handlers': 1,
'use_environment': 1,
'use_hash_seed': 0,
'hash_seed': 0,
'allocator': None,
'dev_mode': 0,
'faulthandler': 0,
'tracemalloc': 0,
'import_time': 0,
Expand All @@ -286,10 +292,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'filesystem_encoding': GET_DEFAULT_CONFIG,
'filesystem_errors': GET_DEFAULT_CONFIG,

'utf8_mode': 0,
'coerce_c_locale': 0,
'coerce_c_locale_warn': 0,

'pycache_prefix': None,
'program_name': './_testembed',
'argv': [""],
Expand All @@ -306,7 +308,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'exec_prefix': GET_DEFAULT_CONFIG,
'base_exec_prefix': GET_DEFAULT_CONFIG,

'isolated': 0,
'site_import': 1,
'bytes_warning': 0,
'inspect': 0,
Expand All @@ -332,8 +333,10 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'_frozen': 0,
}
if MS_WINDOWS:
DEFAULT_CORE_CONFIG.update({
DEFAULT_PRE_CONFIG.update({
'legacy_windows_fs_encoding': 0,
})
DEFAULT_CORE_CONFIG.update({
'legacy_windows_stdio': 0,
})

Expand All @@ -359,6 +362,11 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'Py_HashRandomizationFlag': 1,
'_Py_HasFileSystemDefaultEncodeErrors': 0,
}
COPY_GLOBAL_PRE_CONFIG = [
('Py_IgnoreEnvironmentFlag', 'use_environment', True),
('Py_IsolatedFlag', 'isolated'),
('Py_UTF8Mode', 'utf8_mode'),
]
COPY_GLOBAL_CONFIG = [
# Copy core config to global config for expected values
# True means that the core config value is inverted (0 => 1 and 1 => 0)
Expand All @@ -368,21 +376,20 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
('Py_FileSystemDefaultEncodeErrors', 'filesystem_errors'),
('Py_FileSystemDefaultEncoding', 'filesystem_encoding'),
('Py_FrozenFlag', '_frozen'),
('Py_IgnoreEnvironmentFlag', 'use_environment', True),
('Py_InspectFlag', 'inspect'),
('Py_InteractiveFlag', 'interactive'),
('Py_IsolatedFlag', 'isolated'),
('Py_NoSiteFlag', 'site_import', True),
('Py_NoUserSiteDirectory', 'user_site_directory', True),
('Py_OptimizeFlag', 'optimization_level'),
('Py_QuietFlag', 'quiet'),
('Py_UTF8Mode', 'utf8_mode'),
('Py_UnbufferedStdioFlag', 'buffered_stdio', True),
('Py_VerboseFlag', 'verbose'),
]
if MS_WINDOWS:
COPY_GLOBAL_CONFIG.extend((
COPY_GLOBAL_PRE_CONFIG.extend((
('Py_LegacyWindowsFSEncodingFlag', 'legacy_windows_fs_encoding'),
))
COPY_GLOBAL_CONFIG.extend((
('Py_LegacyWindowsStdioFlag', 'legacy_windows_stdio'),
))

Expand All @@ -408,7 +415,7 @@ def check_main_config(self, config):
expected['xoptions'] = self.main_xoptions(core_config['xoptions'])
self.assertEqual(main_config, expected)

def get_expected_config(self, expected, env):
def get_expected_config(self, expected, expected_preconfig, env):
expected = dict(self.DEFAULT_CORE_CONFIG, **expected)

code = textwrap.dedent('''
Expand Down Expand Up @@ -436,7 +443,7 @@ def get_expected_config(self, expected, env):
# when test_embed is run from a venv (bpo-35313)
args = (sys.executable, '-S', '-c', code)
env = dict(env)
if not expected['isolated']:
if not expected_preconfig['isolated']:
env['PYTHONCOERCECLOCALE'] = '0'
env['PYTHONUTF8'] = '0'
proc = subprocess.run(args, env=env,
Expand All @@ -453,13 +460,19 @@ def get_expected_config(self, expected, env):
expected[key] = config[key]
return expected

def check_pre_config(self, config, expected):
pre_config = dict(config['pre_config'])
core_config = dict(config['core_config'])
self.assertEqual(pre_config, expected)

def check_core_config(self, config, expected):
core_config = dict(config['core_config'])
for key in self.UNTESTED_CORE_CONFIG:
core_config.pop(key, None)
self.assertEqual(core_config, expected)

def check_global_config(self, config):
pre_config = config['pre_config']
core_config = config['core_config']

expected = dict(self.DEFAULT_GLOBAL_CONFIG)
Expand All @@ -470,10 +483,17 @@ def check_global_config(self, config):
else:
global_key, core_key = item
expected[global_key] = core_config[core_key]
for item in self.COPY_GLOBAL_PRE_CONFIG:
if len(item) == 3:
global_key, core_key, opposite = item
expected[global_key] = 0 if pre_config[core_key] else 1
else:
global_key, core_key = item
expected[global_key] = pre_config[core_key]

self.assertEqual(config['global_config'], expected)

def check_config(self, testname, expected):
def check_config(self, testname, expected_config, expected_preconfig):
env = dict(os.environ)
# Remove PYTHON* environment variables to get deterministic environment
for key in list(env):
Expand All @@ -488,15 +508,21 @@ def check_config(self, testname, expected):
# Ignore err
config = json.loads(out)

expected = self.get_expected_config(expected, env)
self.check_core_config(config, expected)
expected_preconfig = dict(self.DEFAULT_PRE_CONFIG, **expected_preconfig)
expected_config = self.get_expected_config(expected_config, expected_preconfig, env)

self.check_core_config(config, expected_config)
self.check_pre_config(config, expected_preconfig)
self.check_main_config(config)
self.check_global_config(config)

def test_init_default_config(self):
self.check_config("init_default_config", {})
self.check_config("init_default_config", {}, {})

def test_init_global_config(self):
preconfig = {
'utf8_mode': 1,
}
config = {
'program_name': './globalvar',
'site_import': 0,
Expand All @@ -509,29 +535,30 @@ def test_init_global_config(self):
'quiet': 1,
'buffered_stdio': 0,

'utf8_mode': 1,
'stdio_encoding': 'utf-8',
'stdio_errors': 'surrogateescape',
'filesystem_encoding': 'utf-8',
'filesystem_errors': self.UTF8_MODE_ERRORS,
'user_site_directory': 0,
'_frozen': 1,
}
self.check_config("init_global_config", config)
self.check_config("init_global_config", config, preconfig)

def test_init_from_config(self):
preconfig = {
'allocator': 'malloc',
'utf8_mode': 1,
}
config = {
'install_signal_handlers': 0,
'use_hash_seed': 1,
'hash_seed': 123,
'allocator': 'malloc',
'tracemalloc': 2,
'import_time': 1,
'show_ref_count': 1,
'show_alloc_count': 1,
'malloc_stats': 1,

'utf8_mode': 1,
'stdio_encoding': 'iso8859-1',
'stdio_errors': 'replace',
'filesystem_encoding': 'utf-8',
Expand Down Expand Up @@ -559,16 +586,18 @@ def test_init_from_config(self):
'_check_hash_pycs_mode': 'always',
'_frozen': 1,
}
self.check_config("init_from_config", config)
self.check_config("init_from_config", config, preconfig)

INIT_ENV_PRECONFIG = {
'allocator': 'malloc',
'utf8_mode': 1,
}
INIT_ENV_CONFIG = {
'use_hash_seed': 1,
'hash_seed': 42,
'allocator': 'malloc',
'tracemalloc': 2,
'import_time': 1,
'malloc_stats': 1,
'utf8_mode': 1,
'filesystem_encoding': 'utf-8',
'filesystem_errors': UTF8_MODE_ERRORS,
'inspect': 1,
Expand All @@ -584,35 +613,42 @@ def test_init_from_config(self):
}

def test_init_env(self):
self.check_config("init_env", self.INIT_ENV_CONFIG)
self.check_config("init_env", self.INIT_ENV_CONFIG, self.INIT_ENV_PRECONFIG)

def test_init_env_dev_mode(self):
config = dict(self.INIT_ENV_CONFIG,
preconfig = dict(self.INIT_ENV_PRECONFIG,
allocator='debug',
dev_mode=1)
self.check_config("init_env_dev_mode", config)

def test_init_env_dev_mode(self):
config = dict(self.INIT_ENV_CONFIG,
allocator='malloc',
dev_mode=1)
self.check_config("init_env_dev_mode_alloc", config)
self.check_config("init_env_dev_mode", config, preconfig)

def test_init_env_dev_mode(self):
preconfig = dict(self.INIT_ENV_PRECONFIG,
allocator='malloc',
dev_mode=1)
config = dict(self.INIT_ENV_CONFIG)
self.check_config("init_env_dev_mode_alloc", config, preconfig)

def test_init_dev_mode(self):
config = {
preconfig = {
'allocator': 'debug',
'dev_mode': 1,
}
config = {
'faulthandler': 1,
'allocator': 'debug',
}
self.check_config("init_dev_mode", config)
self.check_config("init_dev_mode", config, preconfig)

def test_init_isolated(self):
config = {
preconfig = {
'isolated': 1,
'use_environment': 0,
}
config = {
'user_site_directory': 0,
}
self.check_config("init_isolated", config)
self.check_config("init_isolated", config, preconfig)


if __name__ == "__main__":
Expand Down
26 changes: 3 additions & 23 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -4675,27 +4675,9 @@ decode_locale_ex(PyObject *self, PyObject *args)


static PyObject *
get_global_config(PyObject *self, PyObject *Py_UNUSED(args))
get_configs(PyObject *self, PyObject *Py_UNUSED(args))
{
return _Py_GetGlobalVariablesAsDict();
}


static PyObject *
get_core_config(PyObject *self, PyObject *Py_UNUSED(args))
{
PyInterpreterState *interp = _PyInterpreterState_Get();
const _PyCoreConfig *config = _PyInterpreterState_GetCoreConfig(interp);
return _PyCoreConfig_AsDict(config);
}


static PyObject *
get_main_config(PyObject *self, PyObject *Py_UNUSED(args))
{
PyInterpreterState *interp = _PyInterpreterState_Get();
const _PyMainInterpreterConfig *config = _PyInterpreterState_GetMainConfig(interp);
return _PyMainInterpreterConfig_AsDict(config);
return _Py_GetConfigsAsDict();
}


Expand Down Expand Up @@ -4942,9 +4924,7 @@ static PyMethodDef TestMethods[] = {
{"bad_get", (PyCFunction)(void(*)(void))bad_get, METH_FASTCALL},
{"EncodeLocaleEx", encode_locale_ex, METH_VARARGS},
{"DecodeLocaleEx", decode_locale_ex, METH_VARARGS},
{"get_global_config", get_global_config, METH_NOARGS},
{"get_core_config", get_core_config, METH_NOARGS},
{"get_main_config", get_main_config, METH_NOARGS},
{"get_configs", get_configs, METH_NOARGS},
#ifdef Py_REF_DEBUG
{"negative_refcount", negative_refcount, METH_NOARGS},
#endif
Expand Down
Loading