Skip to content

Commit dd6c047

Browse files
committed
Add PyConfig_GetInt()
* Add functions to get runtime config: * PyConfig_GetInt() * PyConfig_GetStr() * PyConfig_GetStrList() * Add Modules/_testcapi/config.c * Add test_initconfig
1 parent c10a404 commit dd6c047

File tree

12 files changed

+503
-62
lines changed

12 files changed

+503
-62
lines changed

Include/initconfig.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,29 @@ PyAPI_FUNC(char*) PyInitConfig_GetErrorMsg(PyInitConfig* config);
8181
// The function does not return.
8282
PyAPI_FUNC(void) _Py_NO_RETURN Py_ExitWithInitConfig(PyInitConfig *config);
8383

84+
85+
// Get an integer configuration option.
86+
// Return 0 and set '*value' on success.
87+
// Raise an exception return -1 on error.
88+
PyAPI_FUNC(int) PyConfig_GetInt(
89+
const char *key,
90+
int64_t *value);
91+
92+
// Get a string configuration option.
93+
// Return 0 and set '*value' on success. '*value' can be set to a Python str
94+
// object or to None.
95+
// Raise an exception return -1 on error.
96+
PyAPI_FUNC(int) PyConfig_GetStr(
97+
const char *key,
98+
PyObject **value);
99+
100+
// Get a string configuration option.
101+
// Return 0 and set '*value' to a Python list on success.
102+
// Raise an exception return -1 on error.
103+
PyAPI_FUNC(int) PyConfig_GetStrList(
104+
const char *key,
105+
PyObject **value);
106+
84107
#endif // !Py_LIMITED_API
85108

86109

Lib/test/test_initconfig.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""
2+
Tests on PyConfig API (PEP 587).
3+
"""
4+
import os
5+
import sys
6+
import unittest
7+
try:
8+
import _testcapi
9+
except ImportError:
10+
_testcapi = None
11+
12+
13+
@unittest.skipIf(_testcapi is None, 'need _testcapi')
14+
class CAPITests(unittest.TestCase):
15+
def check_get_func(self, get_func, wrong_type_key: str):
16+
with self.assertRaises(TypeError):
17+
get_func(wrong_type_key)
18+
19+
with self.assertRaisesRegex(ValueError,
20+
'unknown config option: NONEXISTENT_KEY'):
21+
get_func('NONEXISTENT_KEY')
22+
23+
def test_config_getint(self):
24+
config_getint = _testcapi.config_getint
25+
# PyConfig_MEMBER_INT type
26+
self.assertEqual(config_getint('verbose'), sys.flags.verbose)
27+
28+
# PyConfig_MEMBER_UINT type
29+
self.assertEqual(config_getint('isolated'), sys.flags.isolated)
30+
31+
# PyConfig_MEMBER_ULONG type
32+
hash_seed = config_getint('hash_seed')
33+
self.assertIsInstance(hash_seed, int)
34+
self.assertGreaterEqual(hash_seed, 0)
35+
36+
# platlibdir is a str
37+
self.check_get_func(config_getint, 'platlibdir')
38+
39+
def test_config_getstr(self):
40+
config_getstr = _testcapi.config_getstr
41+
# PyConfig_MEMBER_WSTR type
42+
self.assertEqual(config_getstr('platlibdir'), sys.platlibdir)
43+
if 'PYTHONDUMPREFSFILE' not in os.environ:
44+
# PyConfig_MEMBER_WSTR_OPT type
45+
self.assertIsNone(config_getstr('dump_refs_file'))
46+
47+
# verbose is an int
48+
self.check_get_func(config_getstr, 'verbose')
49+
50+
def test_config_getstrlist(self):
51+
config_getstrlist = _testcapi.config_getstrlist
52+
self.assertEqual(config_getstrlist('orig_argv'), sys.orig_argv)
53+
54+
# verbose is an int
55+
self.check_get_func(config_getstrlist, 'verbose')
56+
57+
58+
if __name__ == "__main__":
59+
unittest.main()

Modules/Setup.stdlib.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
160160
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
161161
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c
162-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c
162+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/config.c
163163
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
164164
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
165165

Modules/_testcapi/clinic/config.c.h

Lines changed: 114 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_testcapi/config.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#define Py_LIMITED_API 0x030d0000 // 3.13
2+
#include "parts.h"
3+
4+
#include "clinic/config.c.h"
5+
6+
/*[clinic input]
7+
module _testcapi
8+
[clinic start generated code]*/
9+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/
10+
11+
/*[clinic input]
12+
_testcapi.config_getint
13+
14+
name: str
15+
/
16+
[clinic start generated code]*/
17+
18+
static PyObject *
19+
_testcapi_config_getint_impl(PyObject *module, const char *name)
20+
/*[clinic end generated code: output=25c0f293af162318 input=e432a47a41785e41]*/
21+
{
22+
int64_t value;
23+
if (PyConfig_GetInt(name, &value) < 0) {
24+
return NULL;
25+
}
26+
Py_BUILD_ASSERT(sizeof(long long) >= sizeof(int64_t));
27+
return PyLong_FromLongLong(value);
28+
}
29+
30+
31+
/*[clinic input]
32+
_testcapi.config_getstr
33+
34+
name: str
35+
/
36+
[clinic start generated code]*/
37+
38+
static PyObject *
39+
_testcapi_config_getstr_impl(PyObject *module, const char *name)
40+
/*[clinic end generated code: output=7c71c97700a6d313 input=caba5bd5f7d88b42]*/
41+
{
42+
PyObject *value;
43+
if (PyConfig_GetStr(name, &value) < 0) {
44+
return NULL;
45+
}
46+
return value;
47+
}
48+
49+
50+
/*[clinic input]
51+
_testcapi.config_getstrlist
52+
53+
name: str
54+
/
55+
[clinic start generated code]*/
56+
57+
static PyObject *
58+
_testcapi_config_getstrlist_impl(PyObject *module, const char *name)
59+
/*[clinic end generated code: output=10dc18bbfb9981b8 input=bc9fe7319fcf9f68]*/
60+
{
61+
PyObject *value;
62+
if (PyConfig_GetStrList(name, &value) < 0) {
63+
return NULL;
64+
}
65+
return value;
66+
}
67+
68+
69+
static PyMethodDef test_methods[] = {
70+
_TESTCAPI_CONFIG_GETINT_METHODDEF
71+
_TESTCAPI_CONFIG_GETSTR_METHODDEF
72+
_TESTCAPI_CONFIG_GETSTRLIST_METHODDEF
73+
{NULL}
74+
};
75+
76+
int _PyTestCapi_Init_Config(PyObject *mod)
77+
{
78+
if (PyModule_AddFunctions(mod, test_methods) < 0) {
79+
return -1;
80+
}
81+
82+
return 0;
83+
}

Modules/_testcapi/gc.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,6 @@ int _PyTestCapi_Init_GC(PyObject *mod)
325325
if (PyModule_AddFunctions(mod, test_methods) < 0) {
326326
return -1;
327327
}
328-
if (PyModule_AddFunctions(mod, test_methods) < 0) {
329-
return -1;
330-
}
331328

332329
PyObject *ObjExtraData_Type = PyType_FromModuleAndSpec(
333330
mod, &ObjExtraData_TypeSpec, NULL);

Modules/_testcapi/parts.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ int _PyTestCapi_Init_PyAtomic(PyObject *module);
4242
int _PyTestCapi_Init_PyOS(PyObject *module);
4343
int _PyTestCapi_Init_Immortal(PyObject *module);
4444
int _PyTestCapi_Init_GC(PyObject *mod);
45-
4645
int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
4746
int _PyTestCapi_Init_HeaptypeRelative(PyObject *module);
47+
int _PyTestCapi_Init_Config(PyObject *mod);
4848

4949
#endif // Py_TESTCAPI_PARTS_H

Modules/_testcapimodule.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4011,6 +4011,9 @@ PyInit__testcapi(void)
40114011
if (_PyTestCapi_Init_HeaptypeRelative(m) < 0) {
40124012
return NULL;
40134013
}
4014+
if (_PyTestCapi_Init_Config(m) < 0) {
4015+
return NULL;
4016+
}
40144017

40154018
PyState_AddModule(m, &_testcapimodule);
40164019
return m;

PCbuild/_testcapi.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
<ClCompile Include="..\Modules\_testcapi\pyos.c" />
117117
<ClCompile Include="..\Modules\_testcapi\immortal.c" />
118118
<ClCompile Include="..\Modules\_testcapi\gc.c" />
119+
<ClCompile Include="..\Modules\_testcapi\config.c" />
119120
</ItemGroup>
120121
<ItemGroup>
121122
<ResourceCompile Include="..\PC\python_nt.rc" />

PCbuild/_testcapi.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
<ClCompile Include="..\Modules\_testcapi\gc.c">
7676
<Filter>Source Files</Filter>
7777
</ClCompile>
78+
<ClCompile Include="..\Modules\_testcapi\config.c">
79+
<Filter>Source Files</Filter>
80+
</ClCompile>
7881
</ItemGroup>
7982
<ItemGroup>
8083
<ResourceCompile Include="..\PC\python_nt.rc">

0 commit comments

Comments
 (0)