Skip to content

Commit 2b5a76c

Browse files
committed
pythongh-107954: Add PyInitConfig C API
Add PyInitConfig functions: * PyInitConfig_Python_New() * PyInitConfig_Isolated_New() * PyInitConfig_Free(config) * PyInitConfig_SetInt(config, key, value) * PyInitConfig_SetStr(config, key, value) * PyInitConfig_SetWStr(config, key, value) * PyInitConfig_SetStrList(config, key, length, items) * PyInitConfig_SetWStrList(config, key, length, items) * PyInitConfig_GetErrorMsg(config) Add also functions using it: * Py_InitializeFromInitConfig(config) * Py_ExitWithInitConfig(config) Add these 11 functions to the limited C API. Changes: * Add Include/initconfig.h header.
1 parent 038c356 commit 2b5a76c

File tree

12 files changed

+632
-56
lines changed

12 files changed

+632
-56
lines changed

Doc/data/stable_abi.dat

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/Python.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
#include "sliceobject.h"
8383
#include "cpython/cellobject.h"
8484
#include "iterobject.h"
85-
#include "cpython/initconfig.h"
85+
#include "initconfig.h"
8686
#include "pystate.h"
8787
#include "cpython/genobject.h"
8888
#include "descrobject.h"

Include/cpython/initconfig.h

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
#ifndef Py_PYCORECONFIG_H
2-
#define Py_PYCORECONFIG_H
3-
#ifndef Py_LIMITED_API
4-
#ifdef __cplusplus
5-
extern "C" {
1+
#ifndef Py_CPYTHON_INITCONFIG_H
2+
# error "this header file must not be included directly"
63
#endif
74

85
/* --- PyStatus ----------------------------------------------- */
@@ -252,9 +249,3 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config,
252249
253250
See also PyConfig.orig_argv. */
254251
PyAPI_FUNC(void) Py_GetArgcArgv(int *argc, wchar_t ***argv);
255-
256-
#ifdef __cplusplus
257-
}
258-
#endif
259-
#endif /* !Py_LIMITED_API */
260-
#endif /* !Py_PYCORECONFIG_H */

Include/initconfig.h

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#ifndef Py_INITCONFIG_H
2+
#define Py_INITCONFIG_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
8+
9+
typedef struct PyInitConfig PyInitConfig;
10+
11+
// Create a new initialization configuration.
12+
// It must be freed by PyInitConfig_Free().
13+
// Return NULL on memory allocation failure.
14+
//
15+
// PyInitConfig_Python_New() has a Python configuration by default.
16+
// PyInitConfig_Isolated_New() has an Isolated configuration by default.
17+
PyAPI_FUNC(PyInitConfig*) PyInitConfig_Python_New(void);
18+
PyAPI_FUNC(PyInitConfig*) PyInitConfig_Isolated_New(void);
19+
20+
// Free memory of a initialization configuration.
21+
PyAPI_FUNC(void) PyInitConfig_Free(PyInitConfig *config);
22+
23+
// Set an integer configuration option.
24+
// Return 0 on success, or return -1 on error.
25+
PyAPI_FUNC(int) PyInitConfig_SetInt(
26+
PyInitConfig *config,
27+
const char *key,
28+
int64_t value);
29+
30+
// Set a string configuration option from a bytes string.
31+
//
32+
// The bytes string is decoded by Py_DecodeLocale(). Preinitialize Python if
33+
// needed to ensure that encodings are properly configured.
34+
//
35+
// Return 0 on success, or return -1 on error.
36+
PyAPI_FUNC(int) PyInitConfig_SetStr(
37+
PyInitConfig *config,
38+
const char *key,
39+
const char *value);
40+
41+
// Set a string configuration option from a wide string.
42+
// Preinitialize Python if needed.
43+
// Return 0 on success, or return -1 on error.
44+
PyAPI_FUNC(int) PyInitConfig_SetWStr(
45+
PyInitConfig *config,
46+
const char *key,
47+
const wchar_t *value);
48+
49+
// Set a string list configuration option from bytes strings.
50+
//
51+
// The bytes strings are decoded by Py_DecodeLocale(). Preinitialize Python if
52+
// needed to ensure that encodings are properly configured.
53+
//
54+
// Return 0 on success, or return -1 on error.
55+
PyAPI_FUNC(int) PyInitConfig_SetStrList(
56+
PyInitConfig *config,
57+
const char *key,
58+
size_t length,
59+
char * const *items);
60+
61+
// Set a string list configuration option from a wide strings.
62+
// Preinitialize Python if needed.
63+
// Return 0 on success, or return -1 on error.
64+
PyAPI_FUNC(int) PyInitConfig_SetWStrList(
65+
PyInitConfig *config,
66+
const char *key,
67+
size_t length,
68+
wchar_t * const *items);
69+
70+
// Initialize Python from the initialization configuration.
71+
// Return 0 on success.
72+
// Return -1 if Python wants to exit and on error
73+
PyAPI_FUNC(int) Py_InitializeFromInitConfig(PyInitConfig *config);
74+
75+
// Get the current error message.
76+
// Return a UTF-8 string allocated by malloc(). It must be released by free().
77+
// Return NULL on memory allocation failure.
78+
PyAPI_FUNC(char*) PyInitConfig_GetErrorMsg(PyInitConfig* config);
79+
80+
// Exit Python and free memory of a initialization configuration.
81+
// The function does not return.
82+
PyAPI_FUNC(void) _Py_NO_RETURN Py_ExitWithInitConfig(PyInitConfig *config);
83+
84+
#endif // !Py_LIMITED_API
85+
86+
87+
#ifndef Py_LIMITED_API
88+
# define Py_CPYTHON_INITCONFIG_H
89+
# include "cpython/initconfig.h"
90+
# undef Py_CPYTHON_INITCONFIG_H
91+
#endif
92+
93+
#ifdef __cplusplus
94+
}
95+
#endif
96+
#endif // !Py_INITCONFIG_H

Include/internal/pycore_initconfig.h

+4
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ extern int _PyWideStringList_Copy(PyWideStringList *list,
6262
extern PyStatus _PyWideStringList_Extend(PyWideStringList *list,
6363
const PyWideStringList *list2);
6464
extern PyObject* _PyWideStringList_AsList(const PyWideStringList *list);
65+
extern PyStatus _PyWideStringList_FromBytes(
66+
PyWideStringList *list,
67+
Py_ssize_t length,
68+
char * const *items);
6569

6670

6771
/* --- _PyArgv ---------------------------------------------------- */

Lib/test/test_embed.py

+31-16
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,14 @@ def test_ucnhash_capi_reset(self):
393393
out, err = self.run_embedded_interpreter("test_repeated_init_exec", code)
394394
self.assertEqual(out, '9\n' * INIT_LOOPS)
395395

396+
397+
def config_dev_mode(preconfig, config):
398+
preconfig['allocator'] = PYMEM_ALLOCATOR_DEBUG
399+
config['dev_mode'] = 1
400+
config['warnoptions'] = ['default']
401+
config['faulthandler'] = 1
402+
403+
396404
class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
397405
maxDiff = 4096
398406
UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape')
@@ -510,7 +518,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
510518
'check_hash_pycs_mode': 'default',
511519
'pathconfig_warnings': 1,
512520
'_init_main': 1,
513-
'use_frozen_modules': not support.Py_DEBUG,
521+
'use_frozen_modules': int(not support.Py_DEBUG),
514522
'safe_path': 0,
515523
'_is_python_build': IGNORE_CONFIG,
516524
}
@@ -990,33 +998,26 @@ def test_init_env_dev_mode_alloc(self):
990998
api=API_COMPAT)
991999

9921000
def test_init_dev_mode(self):
993-
preconfig = {
994-
'allocator': PYMEM_ALLOCATOR_DEBUG,
995-
}
1001+
preconfig = {}
9961002
config = {
997-
'faulthandler': 1,
9981003
'dev_mode': 1,
999-
'warnoptions': ['default'],
10001004
}
1005+
config_dev_mode(preconfig, config)
10011006
self.check_all_configs("test_init_dev_mode", config, preconfig,
10021007
api=API_PYTHON)
10031008

10041009
def test_preinit_parse_argv(self):
10051010
# Pre-initialize implicitly using argv: make sure that -X dev
10061011
# is used to configure the allocation in preinitialization
1007-
preconfig = {
1008-
'allocator': PYMEM_ALLOCATOR_DEBUG,
1009-
}
1012+
preconfig = {}
10101013
config = {
10111014
'argv': ['script.py'],
10121015
'orig_argv': ['python3', '-X', 'dev', '-P', 'script.py'],
10131016
'run_filename': os.path.abspath('script.py'),
1014-
'dev_mode': 1,
1015-
'faulthandler': 1,
1016-
'warnoptions': ['default'],
10171017
'xoptions': ['dev'],
10181018
'safe_path': 1,
10191019
}
1020+
config_dev_mode(preconfig, config)
10201021
self.check_all_configs("test_preinit_parse_argv", config, preconfig,
10211022
api=API_PYTHON)
10221023

@@ -1615,16 +1616,15 @@ def test_init_warnoptions(self):
16151616
'ignore:::PySys_AddWarnOption2', # PySys_AddWarnOption()
16161617
'ignore:::PyConfig_BeforeRead', # PyConfig.warnoptions
16171618
'ignore:::PyConfig_AfterRead'] # PyWideStringList_Append()
1618-
preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG)
1619+
preconfig = {}
16191620
config = {
1620-
'dev_mode': 1,
1621-
'faulthandler': 1,
16221621
'bytes_warning': 1,
1623-
'warnoptions': warnoptions,
16241622
'orig_argv': ['python3',
16251623
'-Wignore:::cmdline1',
16261624
'-Wignore:::cmdline2'],
16271625
}
1626+
config_dev_mode(preconfig, config)
1627+
config['warnoptions'] = warnoptions
16281628
self.check_all_configs("test_init_warnoptions", config, preconfig,
16291629
api=API_PYTHON)
16301630

@@ -1637,6 +1637,21 @@ def test_init_set_config(self):
16371637
self.check_all_configs("test_init_set_config", config,
16381638
api=API_ISOLATED)
16391639

1640+
def test_initconfig_api(self):
1641+
preconfig = {}
1642+
config = {
1643+
'dev_mode': 1,
1644+
'pycache_prefix': 'conf_pycache_prefix',
1645+
'argv': ['-c'],
1646+
'orig_argv': ['./_testembed', '-c', 'pass'],
1647+
'run_command': 'pass\n',
1648+
'xoptions': ['faulthandler'],
1649+
'faulthandler': 1,
1650+
}
1651+
config_dev_mode(preconfig, config)
1652+
self.check_all_configs("test_initconfig_api", config, preconfig,
1653+
api=API_PYTHON)
1654+
16401655
def test_get_argc_argv(self):
16411656
self.run_embedded_interpreter("test_get_argc_argv")
16421657
# ignore output

Lib/test/test_stable_abi_ctypes.py

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Misc/stable_abi.toml

+23
Original file line numberDiff line numberDiff line change
@@ -2464,3 +2464,26 @@
24642464
added = '3.13'
24652465
[function.PyMapping_HasKeyStringWithError]
24662466
added = '3.13'
2467+
2468+
[function.PyInitConfig_Python_New]
2469+
added = '3.13'
2470+
[function.PyInitConfig_Isolated_New]
2471+
added = '3.13'
2472+
[function.PyInitConfig_Free]
2473+
added = '3.13'
2474+
[function.PyInitConfig_SetInt]
2475+
added = '3.13'
2476+
[function.PyInitConfig_SetStr]
2477+
added = '3.13'
2478+
[function.PyInitConfig_SetStrList]
2479+
added = '3.13'
2480+
[function.PyInitConfig_SetWStr]
2481+
added = '3.13'
2482+
[function.PyInitConfig_SetWStrList]
2483+
added = '3.13'
2484+
[function.PyInitConfig_GetErrorMsg]
2485+
added = '3.13'
2486+
[function.Py_InitializeFromInitConfig]
2487+
added = '3.13'
2488+
[function.Py_ExitWithInitConfig]
2489+
added = '3.13'

PC/python3dll.c

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)