mirror of https://github.com/python/cpython
bpo-42260: Add _PyConfig_FromDict() (GH-23167)
* Rename config_as_dict() to _PyConfig_AsDict(). * Add 'module_search_paths_set' to _PyConfig_AsDict(). * Add _PyConfig_FromDict(). * Add get_config() and set_config() to _testinternalcapi. * Add config_check_consistency().
This commit is contained in:
parent
4662fa9bfe
commit
f3cb814315
|
@ -158,6 +158,9 @@ extern PyStatus _PyConfig_SetPyArgv(
|
||||||
PyConfig *config,
|
PyConfig *config,
|
||||||
const _PyArgv *args);
|
const _PyArgv *args);
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyObject*) _PyConfig_AsDict(const PyConfig *config);
|
||||||
|
PyAPI_FUNC(int) _PyConfig_FromDict(PyConfig *config, PyObject *dict);
|
||||||
|
|
||||||
|
|
||||||
/* --- Function used for testing ---------------------------------- */
|
/* --- Function used for testing ---------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,243 @@
|
||||||
|
# bpo-42260: Test _PyInterpreterState_GetConfigCopy()
|
||||||
|
# and _PyInterpreterState_SetConfig().
|
||||||
|
#
|
||||||
|
# Test run in a subinterpreter since set_config(get_config())
|
||||||
|
# does reset sys attributes to their state of the Python startup
|
||||||
|
# (before the site module is run).
|
||||||
|
|
||||||
|
import _testinternalcapi
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
MS_WINDOWS = (os.name == 'nt')
|
||||||
|
MAX_HASH_SEED = 4294967295
|
||||||
|
|
||||||
|
class SetConfigTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.old_config = _testinternalcapi.get_config()
|
||||||
|
self.sys_copy = dict(sys.__dict__)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.set_config(parse_argv=0)
|
||||||
|
sys.__dict__.clear()
|
||||||
|
sys.__dict__.update(self.sys_copy)
|
||||||
|
|
||||||
|
def set_config(self, **kwargs):
|
||||||
|
_testinternalcapi.set_config(self.old_config | kwargs)
|
||||||
|
|
||||||
|
def check(self, **kwargs):
|
||||||
|
self.set_config(**kwargs)
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
self.assertEqual(getattr(sys, key), value,
|
||||||
|
(key, value))
|
||||||
|
|
||||||
|
def test_set_invalid(self):
|
||||||
|
invalid_uint = -1
|
||||||
|
NULL = None
|
||||||
|
invalid_wstr = NULL
|
||||||
|
# PyWideStringList strings must be non-NULL
|
||||||
|
invalid_wstrlist = ["abc", NULL, "def"]
|
||||||
|
|
||||||
|
type_tests = []
|
||||||
|
value_tests = [
|
||||||
|
# enum
|
||||||
|
('_config_init', 0),
|
||||||
|
('_config_init', 4),
|
||||||
|
# unsigned long
|
||||||
|
("hash_seed", -1),
|
||||||
|
("hash_seed", MAX_HASH_SEED + 1),
|
||||||
|
]
|
||||||
|
|
||||||
|
# int (unsigned)
|
||||||
|
options = [
|
||||||
|
'_config_init',
|
||||||
|
'isolated',
|
||||||
|
'use_environment',
|
||||||
|
'dev_mode',
|
||||||
|
'install_signal_handlers',
|
||||||
|
'use_hash_seed',
|
||||||
|
'faulthandler',
|
||||||
|
'tracemalloc',
|
||||||
|
'import_time',
|
||||||
|
'show_ref_count',
|
||||||
|
'dump_refs',
|
||||||
|
'malloc_stats',
|
||||||
|
'parse_argv',
|
||||||
|
'site_import',
|
||||||
|
'bytes_warning',
|
||||||
|
'inspect',
|
||||||
|
'interactive',
|
||||||
|
'optimization_level',
|
||||||
|
'parser_debug',
|
||||||
|
'write_bytecode',
|
||||||
|
'verbose',
|
||||||
|
'quiet',
|
||||||
|
'user_site_directory',
|
||||||
|
'configure_c_stdio',
|
||||||
|
'buffered_stdio',
|
||||||
|
'pathconfig_warnings',
|
||||||
|
'module_search_paths_set',
|
||||||
|
'skip_source_first_line',
|
||||||
|
'_install_importlib',
|
||||||
|
'_init_main',
|
||||||
|
'_isolated_interpreter',
|
||||||
|
]
|
||||||
|
if MS_WINDOWS:
|
||||||
|
options.append('legacy_windows_stdio')
|
||||||
|
for key in options:
|
||||||
|
value_tests.append((key, invalid_uint))
|
||||||
|
type_tests.append((key, "abc"))
|
||||||
|
type_tests.append((key, 2.0))
|
||||||
|
|
||||||
|
# wchar_t*
|
||||||
|
for key in (
|
||||||
|
'filesystem_encoding',
|
||||||
|
'filesystem_errors',
|
||||||
|
'stdio_encoding',
|
||||||
|
'stdio_errors',
|
||||||
|
'check_hash_pycs_mode',
|
||||||
|
'program_name',
|
||||||
|
'platlibdir',
|
||||||
|
'executable',
|
||||||
|
'base_executable',
|
||||||
|
'prefix',
|
||||||
|
'base_prefix',
|
||||||
|
'exec_prefix',
|
||||||
|
'base_exec_prefix',
|
||||||
|
# optional wstr:
|
||||||
|
# 'pythonpath_env'
|
||||||
|
# 'home',
|
||||||
|
# 'pycache_prefix'
|
||||||
|
# 'run_command'
|
||||||
|
# 'run_module'
|
||||||
|
# 'run_filename'
|
||||||
|
):
|
||||||
|
value_tests.append((key, invalid_wstr))
|
||||||
|
type_tests.append((key, b'bytes'))
|
||||||
|
type_tests.append((key, 123))
|
||||||
|
|
||||||
|
# PyWideStringList
|
||||||
|
for key in (
|
||||||
|
'orig_argv',
|
||||||
|
'argv',
|
||||||
|
'xoptions',
|
||||||
|
'warnoptions',
|
||||||
|
'module_search_paths',
|
||||||
|
):
|
||||||
|
value_tests.append((key, invalid_wstrlist))
|
||||||
|
type_tests.append((key, 123))
|
||||||
|
type_tests.append((key, "abc"))
|
||||||
|
type_tests.append((key, [123]))
|
||||||
|
type_tests.append((key, [b"bytes"]))
|
||||||
|
|
||||||
|
|
||||||
|
if MS_WINDOWS:
|
||||||
|
value_tests.append(('legacy_windows_stdio', invalid_uint))
|
||||||
|
|
||||||
|
for exc_type, tests in (
|
||||||
|
(ValueError, value_tests),
|
||||||
|
(TypeError, type_tests),
|
||||||
|
):
|
||||||
|
for key, value in tests:
|
||||||
|
config = self.old_config | {key: value}
|
||||||
|
with self.subTest(key=key, value=value, exc_type=exc_type):
|
||||||
|
with self.assertRaises(exc_type):
|
||||||
|
_testinternalcapi.set_config(config)
|
||||||
|
|
||||||
|
def test_flags(self):
|
||||||
|
for sys_attr, key, value in (
|
||||||
|
("debug", "parser_debug", 1),
|
||||||
|
("inspect", "inspect", 2),
|
||||||
|
("interactive", "interactive", 3),
|
||||||
|
("optimize", "optimization_level", 4),
|
||||||
|
("verbose", "verbose", 1),
|
||||||
|
("bytes_warning", "bytes_warning", 10),
|
||||||
|
("quiet", "quiet", 11),
|
||||||
|
("isolated", "isolated", 12),
|
||||||
|
):
|
||||||
|
with self.subTest(sys=sys_attr, key=key, value=value):
|
||||||
|
self.set_config(**{key: value, 'parse_argv': 0})
|
||||||
|
self.assertEqual(getattr(sys.flags, sys_attr), value)
|
||||||
|
|
||||||
|
self.set_config(write_bytecode=0)
|
||||||
|
self.assertEqual(sys.flags.dont_write_bytecode, True)
|
||||||
|
self.assertEqual(sys.dont_write_bytecode, True)
|
||||||
|
|
||||||
|
self.set_config(write_bytecode=1)
|
||||||
|
self.assertEqual(sys.flags.dont_write_bytecode, False)
|
||||||
|
self.assertEqual(sys.dont_write_bytecode, False)
|
||||||
|
|
||||||
|
self.set_config(user_site_directory=0, isolated=0)
|
||||||
|
self.assertEqual(sys.flags.no_user_site, 1)
|
||||||
|
self.set_config(user_site_directory=1, isolated=0)
|
||||||
|
self.assertEqual(sys.flags.no_user_site, 0)
|
||||||
|
|
||||||
|
self.set_config(site_import=0)
|
||||||
|
self.assertEqual(sys.flags.no_site, 1)
|
||||||
|
self.set_config(site_import=1)
|
||||||
|
self.assertEqual(sys.flags.no_site, 0)
|
||||||
|
|
||||||
|
self.set_config(dev_mode=0)
|
||||||
|
self.assertEqual(sys.flags.dev_mode, False)
|
||||||
|
self.set_config(dev_mode=1)
|
||||||
|
self.assertEqual(sys.flags.dev_mode, True)
|
||||||
|
|
||||||
|
self.set_config(use_environment=0, isolated=0)
|
||||||
|
self.assertEqual(sys.flags.ignore_environment, 1)
|
||||||
|
self.set_config(use_environment=1, isolated=0)
|
||||||
|
self.assertEqual(sys.flags.ignore_environment, 0)
|
||||||
|
|
||||||
|
self.set_config(use_hash_seed=1, hash_seed=0)
|
||||||
|
self.assertEqual(sys.flags.hash_randomization, 0)
|
||||||
|
self.set_config(use_hash_seed=0, hash_seed=0)
|
||||||
|
self.assertEqual(sys.flags.hash_randomization, 1)
|
||||||
|
self.set_config(use_hash_seed=1, hash_seed=123)
|
||||||
|
self.assertEqual(sys.flags.hash_randomization, 1)
|
||||||
|
|
||||||
|
def test_options(self):
|
||||||
|
self.check(warnoptions=[])
|
||||||
|
self.check(warnoptions=["default", "ignore"])
|
||||||
|
|
||||||
|
self.set_config(xoptions=[])
|
||||||
|
self.assertEqual(sys._xoptions, {})
|
||||||
|
self.set_config(xoptions=["dev", "tracemalloc=5"])
|
||||||
|
self.assertEqual(sys._xoptions, {"dev": True, "tracemalloc": "5"})
|
||||||
|
|
||||||
|
def test_pathconfig(self):
|
||||||
|
self.check(
|
||||||
|
executable='executable',
|
||||||
|
prefix="prefix",
|
||||||
|
base_prefix="base_prefix",
|
||||||
|
exec_prefix="exec_prefix",
|
||||||
|
base_exec_prefix="base_exec_prefix",
|
||||||
|
platlibdir="platlibdir")
|
||||||
|
|
||||||
|
self.set_config(base_executable="base_executable")
|
||||||
|
self.assertEqual(sys._base_executable, "base_executable")
|
||||||
|
|
||||||
|
def test_path(self):
|
||||||
|
self.set_config(module_search_paths_set=1,
|
||||||
|
module_search_paths=['a', 'b', 'c'])
|
||||||
|
self.assertEqual(sys.path, ['a', 'b', 'c'])
|
||||||
|
|
||||||
|
# Leave sys.path unchanged if module_search_paths_set=0
|
||||||
|
self.set_config(module_search_paths_set=0,
|
||||||
|
module_search_paths=['new_path'])
|
||||||
|
self.assertEqual(sys.path, ['a', 'b', 'c'])
|
||||||
|
|
||||||
|
def test_argv(self):
|
||||||
|
self.set_config(parse_argv=0,
|
||||||
|
argv=['python_program', 'args'],
|
||||||
|
orig_argv=['orig', 'orig_args'])
|
||||||
|
self.assertEqual(sys.argv, ['python_program', 'args'])
|
||||||
|
self.assertEqual(sys.orig_argv, ['orig', 'orig_args'])
|
||||||
|
|
||||||
|
def test_pycache_prefix(self):
|
||||||
|
self.check(pycache_prefix=None)
|
||||||
|
self.check(pycache_prefix="pycache_prefix")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
|
@ -30,6 +30,8 @@ API_PYTHON = 2
|
||||||
# _PyCoreConfig_InitIsolatedConfig()
|
# _PyCoreConfig_InitIsolatedConfig()
|
||||||
API_ISOLATED = 3
|
API_ISOLATED = 3
|
||||||
|
|
||||||
|
MAX_HASH_SEED = 4294967295
|
||||||
|
|
||||||
|
|
||||||
def debug_build(program):
|
def debug_build(program):
|
||||||
program = os.path.basename(program)
|
program = os.path.basename(program)
|
||||||
|
@ -382,6 +384,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
'exec_prefix': GET_DEFAULT_CONFIG,
|
'exec_prefix': GET_DEFAULT_CONFIG,
|
||||||
'base_exec_prefix': GET_DEFAULT_CONFIG,
|
'base_exec_prefix': GET_DEFAULT_CONFIG,
|
||||||
'module_search_paths': GET_DEFAULT_CONFIG,
|
'module_search_paths': GET_DEFAULT_CONFIG,
|
||||||
|
'module_search_paths_set': 1,
|
||||||
'platlibdir': sys.platlibdir,
|
'platlibdir': sys.platlibdir,
|
||||||
|
|
||||||
'site_import': 1,
|
'site_import': 1,
|
||||||
|
@ -1408,6 +1411,17 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
# ignore output
|
# ignore output
|
||||||
|
|
||||||
|
|
||||||
|
class SetConfigTests(unittest.TestCase):
|
||||||
|
def test_set_config(self):
|
||||||
|
# bpo-42260: Test _PyInterpreterState_SetConfig()
|
||||||
|
cmd = [sys.executable, '-I', '-m', 'test._test_embed_set_config']
|
||||||
|
proc = subprocess.run(cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
self.assertEqual(proc.returncode, 0,
|
||||||
|
(proc.returncode, proc.stdout, proc.stderr))
|
||||||
|
|
||||||
|
|
||||||
class AuditingTests(EmbeddingTestsMixin, unittest.TestCase):
|
class AuditingTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
def test_open_code_hook(self):
|
def test_open_code_hook(self):
|
||||||
self.run_embedded_interpreter("test_open_code_hook")
|
self.run_embedded_interpreter("test_open_code_hook")
|
||||||
|
|
|
@ -13,9 +13,10 @@
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "pycore_bitutils.h" // _Py_bswap32()
|
#include "pycore_bitutils.h" // _Py_bswap32()
|
||||||
#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
|
|
||||||
#include "pycore_hashtable.h" // _Py_hashtable_new()
|
|
||||||
#include "pycore_gc.h" // PyGC_Head
|
#include "pycore_gc.h" // PyGC_Head
|
||||||
|
#include "pycore_hashtable.h" // _Py_hashtable_new()
|
||||||
|
#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
|
||||||
|
#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -231,6 +232,38 @@ test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
test_get_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
|
||||||
|
{
|
||||||
|
PyConfig config;
|
||||||
|
PyConfig_InitIsolatedConfig(&config);
|
||||||
|
if (_PyInterpreterState_GetConfigCopy(&config) < 0) {
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *dict = _PyConfig_AsDict(&config);
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
test_set_config(PyObject *Py_UNUSED(self), PyObject *dict)
|
||||||
|
{
|
||||||
|
PyConfig config;
|
||||||
|
PyConfig_InitIsolatedConfig(&config);
|
||||||
|
if (_PyConfig_FromDict(&config, dict) < 0) {
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (_PyInterpreterState_SetConfig(&config) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef TestMethods[] = {
|
static PyMethodDef TestMethods[] = {
|
||||||
{"get_configs", get_configs, METH_NOARGS},
|
{"get_configs", get_configs, METH_NOARGS},
|
||||||
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
|
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
|
||||||
|
@ -238,6 +271,8 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"test_popcount", test_popcount, METH_NOARGS},
|
{"test_popcount", test_popcount, METH_NOARGS},
|
||||||
{"test_bit_length", test_bit_length, METH_NOARGS},
|
{"test_bit_length", test_bit_length, METH_NOARGS},
|
||||||
{"test_hashtable", test_hashtable, METH_NOARGS},
|
{"test_hashtable", test_hashtable, METH_NOARGS},
|
||||||
|
{"get_config", test_get_config, METH_NOARGS},
|
||||||
|
{"set_config", test_set_config, METH_O},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -577,6 +577,74 @@ Py_GetArgcArgv(int *argc, wchar_t ***argv)
|
||||||
? _PyStatus_ERR("cannot decode " NAME) \
|
? _PyStatus_ERR("cannot decode " NAME) \
|
||||||
: _PyStatus_NO_MEMORY())
|
: _PyStatus_NO_MEMORY())
|
||||||
|
|
||||||
|
#define MAX_HASH_SEED 4294967295UL
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
static int
|
||||||
|
config_check_consistency(const PyConfig *config)
|
||||||
|
{
|
||||||
|
/* Check config consistency */
|
||||||
|
assert(config->isolated >= 0);
|
||||||
|
assert(config->use_environment >= 0);
|
||||||
|
assert(config->dev_mode >= 0);
|
||||||
|
assert(config->install_signal_handlers >= 0);
|
||||||
|
assert(config->use_hash_seed >= 0);
|
||||||
|
assert(config->hash_seed <= MAX_HASH_SEED);
|
||||||
|
assert(config->faulthandler >= 0);
|
||||||
|
assert(config->tracemalloc >= 0);
|
||||||
|
assert(config->import_time >= 0);
|
||||||
|
assert(config->show_ref_count >= 0);
|
||||||
|
assert(config->dump_refs >= 0);
|
||||||
|
assert(config->malloc_stats >= 0);
|
||||||
|
assert(config->site_import >= 0);
|
||||||
|
assert(config->bytes_warning >= 0);
|
||||||
|
assert(config->inspect >= 0);
|
||||||
|
assert(config->interactive >= 0);
|
||||||
|
assert(config->optimization_level >= 0);
|
||||||
|
assert(config->parser_debug >= 0);
|
||||||
|
assert(config->write_bytecode >= 0);
|
||||||
|
assert(config->verbose >= 0);
|
||||||
|
assert(config->quiet >= 0);
|
||||||
|
assert(config->user_site_directory >= 0);
|
||||||
|
assert(config->parse_argv >= 0);
|
||||||
|
assert(config->configure_c_stdio >= 0);
|
||||||
|
assert(config->buffered_stdio >= 0);
|
||||||
|
assert(config->program_name != NULL);
|
||||||
|
assert(_PyWideStringList_CheckConsistency(&config->orig_argv));
|
||||||
|
assert(_PyWideStringList_CheckConsistency(&config->argv));
|
||||||
|
/* sys.argv must be non-empty: empty argv is replaced with [''] */
|
||||||
|
assert(config->argv.length >= 1);
|
||||||
|
assert(_PyWideStringList_CheckConsistency(&config->xoptions));
|
||||||
|
assert(_PyWideStringList_CheckConsistency(&config->warnoptions));
|
||||||
|
assert(_PyWideStringList_CheckConsistency(&config->module_search_paths));
|
||||||
|
assert(config->module_search_paths_set >= 0);
|
||||||
|
if (config->_install_importlib) {
|
||||||
|
/* don't check config->module_search_paths */
|
||||||
|
assert(config->executable != NULL);
|
||||||
|
assert(config->base_executable != NULL);
|
||||||
|
assert(config->prefix != NULL);
|
||||||
|
assert(config->base_prefix != NULL);
|
||||||
|
assert(config->exec_prefix != NULL);
|
||||||
|
assert(config->base_exec_prefix != NULL);
|
||||||
|
}
|
||||||
|
assert(config->platlibdir != NULL);
|
||||||
|
assert(config->filesystem_encoding != NULL);
|
||||||
|
assert(config->filesystem_errors != NULL);
|
||||||
|
assert(config->stdio_encoding != NULL);
|
||||||
|
assert(config->stdio_errors != NULL);
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
assert(config->legacy_windows_stdio >= 0);
|
||||||
|
#endif
|
||||||
|
/* -c and -m options are exclusive */
|
||||||
|
assert(!(config->run_command != NULL && config->run_module != NULL));
|
||||||
|
assert(config->check_hash_pycs_mode != NULL);
|
||||||
|
assert(config->_install_importlib >= 0);
|
||||||
|
assert(config->pathconfig_warnings >= 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Free memory allocated in config, but don't clear all attributes */
|
/* Free memory allocated in config, but don't clear all attributes */
|
||||||
void
|
void
|
||||||
|
@ -880,8 +948,8 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
PyObject *
|
||||||
config_as_dict(const PyConfig *config)
|
_PyConfig_AsDict(const PyConfig *config)
|
||||||
{
|
{
|
||||||
PyObject *dict = PyDict_New();
|
PyObject *dict = PyDict_New();
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
|
@ -936,6 +1004,7 @@ config_as_dict(const PyConfig *config)
|
||||||
SET_ITEM_WSTRLIST(warnoptions);
|
SET_ITEM_WSTRLIST(warnoptions);
|
||||||
SET_ITEM_WSTR(pythonpath_env);
|
SET_ITEM_WSTR(pythonpath_env);
|
||||||
SET_ITEM_WSTR(home);
|
SET_ITEM_WSTR(home);
|
||||||
|
SET_ITEM_INT(module_search_paths_set);
|
||||||
SET_ITEM_WSTRLIST(module_search_paths);
|
SET_ITEM_WSTRLIST(module_search_paths);
|
||||||
SET_ITEM_WSTR(executable);
|
SET_ITEM_WSTR(executable);
|
||||||
SET_ITEM_WSTR(base_executable);
|
SET_ITEM_WSTR(base_executable);
|
||||||
|
@ -987,6 +1056,285 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
config_dict_get(PyObject *dict, const char *name)
|
||||||
|
{
|
||||||
|
PyObject *item = PyDict_GetItemString(dict, name);
|
||||||
|
if (item == NULL) {
|
||||||
|
PyErr_Format(PyExc_ValueError, "missing config key: %s", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
config_dict_invalid_value(const char *name)
|
||||||
|
{
|
||||||
|
PyErr_Format(PyExc_ValueError, "invalid config value: %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
config_dict_invalid_type(const char *name)
|
||||||
|
{
|
||||||
|
PyErr_Format(PyExc_TypeError, "invalid config type: %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
config_dict_get_int(PyObject *dict, const char *name, int *result)
|
||||||
|
{
|
||||||
|
PyObject *item = config_dict_get(dict, name);
|
||||||
|
if (item == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int value = _PyLong_AsInt(item);
|
||||||
|
if (value == -1 && PyErr_Occurred()) {
|
||||||
|
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
|
||||||
|
config_dict_invalid_type(name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
config_dict_invalid_value(name);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*result = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
config_dict_get_ulong(PyObject *dict, const char *name, unsigned long *result)
|
||||||
|
{
|
||||||
|
PyObject *item = config_dict_get(dict, name);
|
||||||
|
if (item == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
unsigned long value = PyLong_AsUnsignedLong(item);
|
||||||
|
if (value == (unsigned long)-1 && PyErr_Occurred()) {
|
||||||
|
config_dict_invalid_value(name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*result = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
config_dict_get_wstr(PyObject *dict, const char *name, PyConfig *config,
|
||||||
|
wchar_t **result)
|
||||||
|
{
|
||||||
|
PyObject *item = config_dict_get(dict, name);
|
||||||
|
if (item == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyStatus status;
|
||||||
|
if (item == Py_None) {
|
||||||
|
status = PyConfig_SetString(config, result, NULL);
|
||||||
|
}
|
||||||
|
else if (!PyUnicode_Check(item)) {
|
||||||
|
config_dict_invalid_type(name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wchar_t *wstr = PyUnicode_AsWideCharString(item, NULL);
|
||||||
|
if (wstr == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = PyConfig_SetString(config, result, wstr);
|
||||||
|
PyMem_Free(wstr);
|
||||||
|
}
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
config_dict_get_wstrlist(PyObject *dict, const char *name, PyConfig *config,
|
||||||
|
PyWideStringList *result)
|
||||||
|
{
|
||||||
|
PyObject *list = config_dict_get(dict, name);
|
||||||
|
if (list == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyList_CheckExact(list)) {
|
||||||
|
config_dict_invalid_type(name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyWideStringList wstrlist = _PyWideStringList_INIT;
|
||||||
|
for (Py_ssize_t i=0; i < PyList_GET_SIZE(list); i++) {
|
||||||
|
PyObject *item = PyList_GET_ITEM(list, i);
|
||||||
|
|
||||||
|
if (item == Py_None) {
|
||||||
|
config_dict_invalid_value(name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else if (!PyUnicode_Check(item)) {
|
||||||
|
config_dict_invalid_type(name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
wchar_t *wstr = PyUnicode_AsWideCharString(item, NULL);
|
||||||
|
if (wstr == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
PyStatus status = PyWideStringList_Append(&wstrlist, wstr);
|
||||||
|
PyMem_Free(wstr);
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_PyWideStringList_Copy(result, &wstrlist) < 0) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
_PyWideStringList_Clear(&wstrlist);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
_PyWideStringList_Clear(&wstrlist);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyConfig_FromDict(PyConfig *config, PyObject *dict)
|
||||||
|
{
|
||||||
|
if (!PyDict_Check(dict)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "dict expected");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_VALUE(NAME, TEST) \
|
||||||
|
if (!(TEST)) { \
|
||||||
|
config_dict_invalid_value(NAME); \
|
||||||
|
return -1; \
|
||||||
|
}
|
||||||
|
#define GET_UINT(KEY) \
|
||||||
|
do { \
|
||||||
|
if (config_dict_get_int(dict, #KEY, &config->KEY) < 0) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
CHECK_VALUE(#KEY, config->KEY >= 0); \
|
||||||
|
} while (0)
|
||||||
|
#define GET_WSTR(KEY) \
|
||||||
|
do { \
|
||||||
|
if (config_dict_get_wstr(dict, #KEY, config, &config->KEY) < 0) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
CHECK_VALUE(#KEY, config->KEY != NULL); \
|
||||||
|
} while (0)
|
||||||
|
#define GET_WSTR_OPT(KEY) \
|
||||||
|
do { \
|
||||||
|
if (config_dict_get_wstr(dict, #KEY, config, &config->KEY) < 0) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define GET_WSTRLIST(KEY) \
|
||||||
|
do { \
|
||||||
|
if (config_dict_get_wstrlist(dict, #KEY, config, &config->KEY) < 0) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
GET_UINT(_config_init);
|
||||||
|
CHECK_VALUE("_config_init",
|
||||||
|
config->_config_init == _PyConfig_INIT_COMPAT
|
||||||
|
|| config->_config_init == _PyConfig_INIT_PYTHON
|
||||||
|
|| config->_config_init == _PyConfig_INIT_ISOLATED);
|
||||||
|
GET_UINT(isolated);
|
||||||
|
GET_UINT(use_environment);
|
||||||
|
GET_UINT(dev_mode);
|
||||||
|
GET_UINT(install_signal_handlers);
|
||||||
|
GET_UINT(use_hash_seed);
|
||||||
|
if (config_dict_get_ulong(dict, "hash_seed", &config->hash_seed) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
CHECK_VALUE("hash_seed", config->hash_seed <= MAX_HASH_SEED);
|
||||||
|
GET_UINT(faulthandler);
|
||||||
|
GET_UINT(tracemalloc);
|
||||||
|
GET_UINT(import_time);
|
||||||
|
GET_UINT(show_ref_count);
|
||||||
|
GET_UINT(dump_refs);
|
||||||
|
GET_UINT(malloc_stats);
|
||||||
|
GET_WSTR(filesystem_encoding);
|
||||||
|
GET_WSTR(filesystem_errors);
|
||||||
|
GET_WSTR_OPT(pycache_prefix);
|
||||||
|
GET_UINT(parse_argv);
|
||||||
|
GET_WSTRLIST(orig_argv);
|
||||||
|
GET_WSTRLIST(argv);
|
||||||
|
GET_WSTRLIST(xoptions);
|
||||||
|
GET_WSTRLIST(warnoptions);
|
||||||
|
GET_UINT(site_import);
|
||||||
|
GET_UINT(bytes_warning);
|
||||||
|
GET_UINT(inspect);
|
||||||
|
GET_UINT(interactive);
|
||||||
|
GET_UINT(optimization_level);
|
||||||
|
GET_UINT(parser_debug);
|
||||||
|
GET_UINT(write_bytecode);
|
||||||
|
GET_UINT(verbose);
|
||||||
|
GET_UINT(quiet);
|
||||||
|
GET_UINT(user_site_directory);
|
||||||
|
GET_UINT(configure_c_stdio);
|
||||||
|
GET_UINT(buffered_stdio);
|
||||||
|
GET_WSTR(stdio_encoding);
|
||||||
|
GET_WSTR(stdio_errors);
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
GET_UINT(legacy_windows_stdio);
|
||||||
|
#endif
|
||||||
|
GET_WSTR(check_hash_pycs_mode);
|
||||||
|
|
||||||
|
GET_UINT(pathconfig_warnings);
|
||||||
|
GET_WSTR(program_name);
|
||||||
|
GET_WSTR_OPT(pythonpath_env);
|
||||||
|
GET_WSTR_OPT(home);
|
||||||
|
GET_WSTR(platlibdir);
|
||||||
|
|
||||||
|
GET_UINT(module_search_paths_set);
|
||||||
|
GET_WSTRLIST(module_search_paths);
|
||||||
|
if (config->_install_importlib) {
|
||||||
|
GET_WSTR(executable);
|
||||||
|
GET_WSTR(base_executable);
|
||||||
|
GET_WSTR(prefix);
|
||||||
|
GET_WSTR(base_prefix);
|
||||||
|
GET_WSTR(exec_prefix);
|
||||||
|
GET_WSTR(base_exec_prefix);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GET_WSTR_OPT(executable);
|
||||||
|
GET_WSTR_OPT(base_executable);
|
||||||
|
GET_WSTR_OPT(prefix);
|
||||||
|
GET_WSTR_OPT(base_prefix);
|
||||||
|
GET_WSTR_OPT(exec_prefix);
|
||||||
|
GET_WSTR_OPT(base_exec_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_UINT(skip_source_first_line);
|
||||||
|
GET_WSTR_OPT(run_command);
|
||||||
|
GET_WSTR_OPT(run_module);
|
||||||
|
GET_WSTR_OPT(run_filename);
|
||||||
|
|
||||||
|
GET_UINT(_install_importlib);
|
||||||
|
GET_UINT(_init_main);
|
||||||
|
GET_UINT(_isolated_interpreter);
|
||||||
|
|
||||||
|
assert(config_check_consistency(config));
|
||||||
|
|
||||||
|
#undef CHECK_VALUE
|
||||||
|
#undef GET_UINT
|
||||||
|
#undef GET_WSTR
|
||||||
|
#undef GET_WSTR_OPT
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char*
|
static const char*
|
||||||
config_get_env(const PyConfig *config, const char *name)
|
config_get_env(const PyConfig *config, const char *name)
|
||||||
{
|
{
|
||||||
|
@ -1254,7 +1602,6 @@ config_init_home(PyConfig *config)
|
||||||
L"PYTHONHOME", "PYTHONHOME");
|
L"PYTHONHOME", "PYTHONHOME");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyStatus
|
static PyStatus
|
||||||
config_init_hash_seed(PyConfig *config)
|
config_init_hash_seed(PyConfig *config)
|
||||||
{
|
{
|
||||||
|
@ -1268,7 +1615,7 @@ config_init_hash_seed(PyConfig *config)
|
||||||
errno = 0;
|
errno = 0;
|
||||||
seed = strtoul(seed_text, (char **)&endptr, 10);
|
seed = strtoul(seed_text, (char **)&endptr, 10);
|
||||||
if (*endptr != '\0'
|
if (*endptr != '\0'
|
||||||
|| seed > 4294967295UL
|
|| seed > MAX_HASH_SEED
|
||||||
|| (errno == ERANGE && seed == ULONG_MAX))
|
|| (errno == ERANGE && seed == ULONG_MAX))
|
||||||
{
|
{
|
||||||
return _PyStatus_ERR("PYTHONHASHSEED must be \"random\" "
|
return _PyStatus_ERR("PYTHONHASHSEED must be \"random\" "
|
||||||
|
@ -2532,58 +2879,7 @@ PyConfig_Read(PyConfig *config)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check config consistency */
|
assert(config_check_consistency(config));
|
||||||
assert(config->isolated >= 0);
|
|
||||||
assert(config->use_environment >= 0);
|
|
||||||
assert(config->dev_mode >= 0);
|
|
||||||
assert(config->install_signal_handlers >= 0);
|
|
||||||
assert(config->use_hash_seed >= 0);
|
|
||||||
assert(config->faulthandler >= 0);
|
|
||||||
assert(config->tracemalloc >= 0);
|
|
||||||
assert(config->site_import >= 0);
|
|
||||||
assert(config->bytes_warning >= 0);
|
|
||||||
assert(config->inspect >= 0);
|
|
||||||
assert(config->interactive >= 0);
|
|
||||||
assert(config->optimization_level >= 0);
|
|
||||||
assert(config->parser_debug >= 0);
|
|
||||||
assert(config->write_bytecode >= 0);
|
|
||||||
assert(config->verbose >= 0);
|
|
||||||
assert(config->quiet >= 0);
|
|
||||||
assert(config->user_site_directory >= 0);
|
|
||||||
assert(config->parse_argv >= 0);
|
|
||||||
assert(config->configure_c_stdio >= 0);
|
|
||||||
assert(config->buffered_stdio >= 0);
|
|
||||||
assert(config->program_name != NULL);
|
|
||||||
assert(_PyWideStringList_CheckConsistency(&config->argv));
|
|
||||||
/* sys.argv must be non-empty: empty argv is replaced with [''] */
|
|
||||||
assert(config->argv.length >= 1);
|
|
||||||
assert(_PyWideStringList_CheckConsistency(&config->xoptions));
|
|
||||||
assert(_PyWideStringList_CheckConsistency(&config->warnoptions));
|
|
||||||
assert(_PyWideStringList_CheckConsistency(&config->module_search_paths));
|
|
||||||
if (config->_install_importlib) {
|
|
||||||
assert(config->module_search_paths_set != 0);
|
|
||||||
/* don't check config->module_search_paths */
|
|
||||||
assert(config->executable != NULL);
|
|
||||||
assert(config->base_executable != NULL);
|
|
||||||
assert(config->prefix != NULL);
|
|
||||||
assert(config->base_prefix != NULL);
|
|
||||||
assert(config->exec_prefix != NULL);
|
|
||||||
assert(config->base_exec_prefix != NULL);
|
|
||||||
}
|
|
||||||
assert(config->platlibdir != NULL);
|
|
||||||
assert(config->filesystem_encoding != NULL);
|
|
||||||
assert(config->filesystem_errors != NULL);
|
|
||||||
assert(config->stdio_encoding != NULL);
|
|
||||||
assert(config->stdio_errors != NULL);
|
|
||||||
#ifdef MS_WINDOWS
|
|
||||||
assert(config->legacy_windows_stdio >= 0);
|
|
||||||
#endif
|
|
||||||
/* -c and -m options are exclusive */
|
|
||||||
assert(!(config->run_command != NULL && config->run_module != NULL));
|
|
||||||
assert(config->check_hash_pycs_mode != NULL);
|
|
||||||
assert(config->_install_importlib >= 0);
|
|
||||||
assert(config->pathconfig_warnings >= 0);
|
|
||||||
assert(_PyWideStringList_CheckConsistency(&config->orig_argv));
|
|
||||||
|
|
||||||
status = _PyStatus_OK();
|
status = _PyStatus_OK();
|
||||||
|
|
||||||
|
@ -2628,7 +2924,7 @@ _Py_GetConfigsAsDict(void)
|
||||||
|
|
||||||
/* core config */
|
/* core config */
|
||||||
const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
|
const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
|
||||||
dict = config_as_dict(config);
|
dict = _PyConfig_AsDict(config);
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2922,7 +2922,9 @@ _PySys_UpdateConfig(PyThreadState *tstate)
|
||||||
#define SET_SYS_FROM_WSTR(KEY, VALUE) \
|
#define SET_SYS_FROM_WSTR(KEY, VALUE) \
|
||||||
SET_SYS(KEY, PyUnicode_FromWideChar(VALUE, -1));
|
SET_SYS(KEY, PyUnicode_FromWideChar(VALUE, -1));
|
||||||
|
|
||||||
COPY_LIST("path", config->module_search_paths);
|
if (config->module_search_paths_set) {
|
||||||
|
COPY_LIST("path", config->module_search_paths);
|
||||||
|
}
|
||||||
|
|
||||||
SET_SYS_FROM_WSTR("executable", config->executable);
|
SET_SYS_FROM_WSTR("executable", config->executable);
|
||||||
SET_SYS_FROM_WSTR("_base_executable", config->base_executable);
|
SET_SYS_FROM_WSTR("_base_executable", config->base_executable);
|
||||||
|
|
Loading…
Reference in New Issue