Skip to content

Commit fee8cc4

Browse files
committed
New PyConfig_Get() API
1 parent 328fa6d commit fee8cc4

File tree

4 files changed

+107
-123
lines changed

4 files changed

+107
-123
lines changed

Include/initconfig.h

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -98,20 +98,10 @@ PyAPI_FUNC(int) PyConfig_GetInt(
9898
const char *name,
9999
int64_t *value);
100100

101-
// Get a string configuration option.
102-
// Return 0 and set '*value' on success. '*value' can be set to a Python str
103-
// object or to None.
104-
// Raise an exception return -1 on error.
105-
PyAPI_FUNC(int) PyConfig_GetStr(
106-
const char *name,
107-
PyObject **value);
108-
109-
// Get a string configuration option.
110-
// Return 0 and set '*value' to a Python list on success.
111-
// Raise an exception return -1 on error.
112-
PyAPI_FUNC(int) PyConfig_GetStrList(
113-
const char *name,
114-
PyObject **value);
101+
// Get a configuration option.
102+
// Return a new reference on success.
103+
// Set an exception and return NULL on error.
104+
PyAPI_FUNC(PyObject*) PyConfig_Get(const char *name);
115105

116106
#endif // !Py_LIMITED_API
117107

Lib/test/test_capi/test_config.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,12 @@ def test_config_getint(self):
4646
self.assertEqual(config_getint('write_bytecode'), 1)
4747

4848
def test_config_getstr(self):
49-
config_getstr = _testcapi.config_getstr
49+
config_get = _testcapi.config_get
5050
# PyConfig_MEMBER_WSTR type
51-
self.assertEqual(config_getstr('platlibdir'), sys.platlibdir)
51+
self.assertEqual(config_get('platlibdir'), sys.platlibdir)
5252
if 'PYTHONDUMPREFSFILE' not in os.environ:
5353
# PyConfig_MEMBER_WSTR_OPT type
54-
self.assertIsNone(config_getstr('dump_refs_file'))
55-
56-
# verbose is an int
57-
self.check_error(config_getstr, 'verbose')
54+
self.assertIsNone(config_get('dump_refs_file'))
5855

5956
# attributes read from sys
6057
value = "TEST_MARKER_STR"
@@ -69,7 +66,7 @@ def test_config_getstr(self):
6966
):
7067
with self.subTest(name=name):
7168
with support.swap_attr(sys, name, value):
72-
self.assertEqual(config_getstr(name), value)
69+
self.assertEqual(config_get(name), value)
7370

7471
# attributes read from sys with a different name
7572
# (add underscore prefix)
@@ -79,14 +76,11 @@ def test_config_getstr(self):
7976
):
8077
with self.subTest(config_name=config_name, sys_name=sys_name):
8178
with support.swap_attr(sys, sys_name, value):
82-
self.assertEqual(config_getstr(config_name), value)
79+
self.assertEqual(config_get(config_name), value)
8380

8481
def test_config_getstrlist(self):
85-
config_getstrlist = _testcapi.config_getstrlist
86-
self.assertEqual(config_getstrlist('orig_argv'), sys.orig_argv)
87-
88-
# verbose is an int
89-
self.check_error(config_getstrlist, 'verbose')
82+
config_get = _testcapi.config_get
83+
self.assertEqual(config_get('orig_argv'), sys.orig_argv)
9084

9185
# attributes read from sys
9286
value = ["TEST_MARKER_STRLIST"]
@@ -97,19 +91,19 @@ def test_config_getstrlist(self):
9791
):
9892
with self.subTest(name=name):
9993
with support.swap_attr(sys, name, value):
100-
self.assertEqual(config_getstrlist(name), value)
94+
self.assertEqual(config_get(name), value)
10195

10296
with support.swap_attr(sys, "path", value):
103-
self.assertEqual(config_getstrlist("module_search_paths"), value)
97+
self.assertEqual(config_get("module_search_paths"), value)
10498

10599
with support.swap_attr(sys, "_xoptions", {"x": "value", "y": True}):
106-
self.assertEqual(config_getstrlist("xoptions"),
100+
self.assertEqual(config_get("xoptions"),
107101
["x=value", "y"])
108102

109103
# sys._xoptions must be a dict
110104
with support.swap_attr(sys, "_xoptions", "not_a_dict"):
111105
with self.assertRaises(TypeError):
112-
config_getstrlist("xoptions")
106+
config_get("xoptions")
113107

114108

115109
if __name__ == "__main__":

Modules/_testcapi/config.c

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,41 +26,20 @@ _testcapi_config_getint(PyObject *module, PyObject *name_obj)
2626

2727

2828
static PyObject *
29-
_testcapi_config_getstr(PyObject *module, PyObject *name_obj)
29+
_testcapi_config_get(PyObject *module, PyObject *name_obj)
3030
{
3131
const char *name;
3232
if (PyArg_Parse(name_obj, "s", &name) < 0) {
3333
return NULL;
3434
}
3535

36-
PyObject *value;
37-
if (PyConfig_GetStr(name, &value) < 0) {
38-
return NULL;
39-
}
40-
return value;
41-
}
42-
43-
44-
static PyObject *
45-
_testcapi_config_getstrlist(PyObject *module, PyObject *name_obj)
46-
{
47-
const char *name;
48-
if (PyArg_Parse(name_obj, "s", &name) < 0) {
49-
return NULL;
50-
}
51-
52-
PyObject *value;
53-
if (PyConfig_GetStrList(name, &value) < 0) {
54-
return NULL;
55-
}
56-
return value;
36+
return PyConfig_Get(name);
5737
}
5838

5939

6040
static PyMethodDef test_methods[] = {
6141
{"config_getint", _testcapi_config_getint, METH_O},
62-
{"config_getstr", _testcapi_config_getstr, METH_O},
63-
{"config_getstrlist", _testcapi_config_getstrlist, METH_O},
42+
{"config_get", _testcapi_config_get, METH_O},
6443
{NULL}
6544
};
6645

Python/initconfig.c

Lines changed: 89 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ config_get_int(const PyConfig *config, const PyConfigSpec *spec,
3333
static int
3434
config_get_str(const PyConfig *config, const PyConfigSpec *spec,
3535
PyObject **value, int use_sys);
36-
static int
37-
config_get_str_list(const PyConfig *config, const PyConfigSpec *spec,
38-
PyObject **value, int use_sys);
36+
static PyObject*
37+
config_get(const PyConfig *config, const PyConfigSpec *spec,
38+
int use_sys);
3939

4040
/* --- PyConfig spec ---------------------------------------------- */
4141

@@ -1061,47 +1061,6 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2)
10611061
}
10621062

10631063

1064-
static PyObject*
1065-
_PyConfig_Get(const PyConfig *config, const PyConfigSpec *spec)
1066-
{
1067-
switch (spec->type) {
1068-
case PyConfig_MEMBER_INT:
1069-
case PyConfig_MEMBER_UINT:
1070-
case PyConfig_MEMBER_ULONG:
1071-
{
1072-
int64_t value;
1073-
if (config_get_int(config, spec, &value, 0) < 0) {
1074-
return NULL;
1075-
}
1076-
1077-
Py_BUILD_ASSERT(sizeof(value) == sizeof(long long));
1078-
long long llvalue = (long long)value;
1079-
return PyLong_FromLongLong(llvalue);
1080-
}
1081-
case PyConfig_MEMBER_WSTR:
1082-
case PyConfig_MEMBER_WSTR_OPT:
1083-
{
1084-
PyObject *obj;
1085-
if (config_get_str(config, spec, &obj, 0) < 0) {
1086-
return NULL;
1087-
}
1088-
return obj;
1089-
}
1090-
case PyConfig_MEMBER_WSTR_LIST:
1091-
{
1092-
PyObject *obj;
1093-
if (config_get_str_list(config, spec, &obj, 0) < 0) {
1094-
return NULL;
1095-
}
1096-
return obj;
1097-
}
1098-
default:
1099-
break;
1100-
}
1101-
Py_UNREACHABLE();
1102-
}
1103-
1104-
11051064
PyObject *
11061065
_PyConfig_AsDict(const PyConfig *config)
11071066
{
@@ -1112,7 +1071,7 @@ _PyConfig_AsDict(const PyConfig *config)
11121071

11131072
const PyConfigSpec *spec = PYCONFIG_SPEC;
11141073
for (; spec->name != NULL; spec++) {
1115-
PyObject *obj = _PyConfig_Get(config, spec);
1074+
PyObject *obj = config_get(config, spec, 0);
11161075
if (obj == NULL) {
11171076
Py_DECREF(dict);
11181077
return NULL;
@@ -3672,7 +3631,6 @@ config_get_str(const PyConfig *config, const PyConfigSpec *spec,
36723631
}
36733632
}
36743633

3675-
wchar_t **member = config_spec_get_member(spec, config);
36763634
if (spec->type != PyConfig_MEMBER_WSTR
36773635
&& spec->type != PyConfig_MEMBER_WSTR_OPT)
36783636
{
@@ -3681,6 +3639,7 @@ config_get_str(const PyConfig *config, const PyConfigSpec *spec,
36813639
return -1;
36823640
}
36833641

3642+
wchar_t **member = config_spec_get_member(spec, config);
36843643
if (*member != NULL) {
36853644
*value = PyUnicode_FromWideChar(*member, -1);
36863645
if (*value == NULL) {
@@ -3745,13 +3704,25 @@ config_dict_as_str_list(PyObject *dict)
37453704
}
37463705

37473706

3748-
static int
3749-
config_get_str_list(const PyConfig *config, const PyConfigSpec *spec,
3750-
PyObject **value, int use_sys)
3707+
static PyObject*
3708+
config_get(const PyConfig *config, const PyConfigSpec *spec,
3709+
int use_sys)
37513710
{
37523711
if (use_sys && !_PyRuntime.initialized) {
37533712
use_sys = 0;
37543713
}
3714+
if (use_sys) {
3715+
if (strcmp(spec->name, "write_bytecode") == 0) {
3716+
PyObject *attr = PySys_GetObject("dont_write_bytecode");
3717+
if (attr != NULL) {
3718+
int is_true = PyObject_IsTrue(attr);
3719+
if (is_true < 0) {
3720+
return NULL;
3721+
}
3722+
return PyLong_FromLong(!is_true);
3723+
}
3724+
}
3725+
}
37553726
if (use_sys) {
37563727
const char* sys_attrs[] = {
37573728
"argv",
@@ -3765,43 +3736,93 @@ config_get_str_list(const PyConfig *config, const PyConfigSpec *spec,
37653736
for (const char **attr = sys_attrs; *attr != NULL; attr++) {
37663737
if (strcmp(name, *attr) == 0) {
37673738
if (strcmp(name, "module_search_paths") == 0) {
3768-
*value = Py_XNewRef(PySys_GetObject("path"));
3739+
return Py_XNewRef(PySys_GetObject("path"));
37693740
}
37703741
else if (strcmp(name, "xoptions") == 0) {
3771-
*value = config_dict_as_str_list(PySys_GetObject("_xoptions"));
3742+
return config_dict_as_str_list(PySys_GetObject("_xoptions"));
37723743
}
37733744
else {
3774-
*value = Py_XNewRef(PySys_GetObject(name));
3745+
return Py_XNewRef(PySys_GetObject(name));
37753746
}
3776-
if (*value == NULL) {
3777-
return -1;
3747+
}
3748+
}
3749+
}
3750+
if (use_sys) {
3751+
const char* sys_attrs[] = {
3752+
"base_exec_prefix",
3753+
"base_executable",
3754+
"base_prefix",
3755+
"exec_prefix",
3756+
"executable",
3757+
"platlibdir",
3758+
"prefix",
3759+
"pycache_prefix",
3760+
"stdlib_dir",
3761+
NULL,
3762+
};
3763+
const char *name = spec->name;
3764+
for (const char **attr = sys_attrs; *attr != NULL; attr++) {
3765+
if (strcmp(name, *attr) == 0) {
3766+
if (strcmp(name, "stdlib_dir") == 0) {
3767+
return Py_XNewRef(PySys_GetObject("_stdlib_dir"));
3768+
}
3769+
else if (strcmp(name, "base_executable") == 0) {
3770+
return Py_XNewRef(PySys_GetObject("_base_executable"));
3771+
}
3772+
else {
3773+
return Py_XNewRef(PySys_GetObject(name));
37783774
}
3779-
return 0;
37803775
}
37813776
}
37823777
}
37833778

3784-
if (spec->type != PyConfig_MEMBER_WSTR_LIST) {
3785-
PyErr_Format(PyExc_TypeError,
3786-
"config option %s is not a strings list", spec->name);
3787-
return -1;
3779+
char *member = config_spec_get_member(spec, config);
3780+
switch (spec->type) {
3781+
case PyConfig_MEMBER_INT:
3782+
case PyConfig_MEMBER_UINT:
3783+
{
3784+
int value = *(int *)member;
3785+
return PyLong_FromLong(value);
37883786
}
37893787

3790-
const PyWideStringList *list = config_spec_get_member(spec, config);
3791-
*value = _PyWideStringList_AsList(list);
3792-
if (*value == NULL) {
3793-
return -1;
3788+
case PyConfig_MEMBER_ULONG:
3789+
{
3790+
unsigned long value = *(unsigned long *)member;
3791+
return PyLong_FromUnsignedLong(value);
3792+
}
3793+
3794+
case PyConfig_MEMBER_WSTR:
3795+
case PyConfig_MEMBER_WSTR_OPT:
3796+
{
3797+
wchar_t *wstr = *(wchar_t **)member;
3798+
if (wstr != NULL) {
3799+
return PyUnicode_FromWideChar(wstr, -1);
3800+
}
3801+
else {
3802+
return Py_NewRef(Py_None);
3803+
}
3804+
}
3805+
3806+
case PyConfig_MEMBER_WSTR_LIST:
3807+
{
3808+
const PyWideStringList *list = (const PyWideStringList *)member;
3809+
return _PyWideStringList_AsList(list);
3810+
}
3811+
default:
3812+
PyErr_Format(PyExc_TypeError,
3813+
"config option %s is not a strings list", spec->name);
3814+
return NULL;
37943815
}
3795-
return 0;
37963816
}
37973817

3798-
int
3799-
PyConfig_GetStrList(const char *name, PyObject **value)
3818+
3819+
PyObject*
3820+
PyConfig_Get(const char *name)
38003821
{
38013822
const PyConfigSpec *spec = config_prepare_get(name);
38023823
if (spec == NULL) {
3803-
return -1;
3824+
return NULL;
38043825
}
38053826
const PyConfig *config = _Py_GetConfig();
3806-
return config_get_str_list(config, spec, value, 1);
3827+
return config_get(config, spec, 1);
38073828
}

0 commit comments

Comments
 (0)