Skip to content

Commit c10a404

Browse files
committed
gh-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 d67edcf commit c10a404

File tree

12 files changed

+632
-56
lines changed

12 files changed

+632
-56
lines changed

Doc/data/stable_abi.dat

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

Include/Python.h

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 11 deletions
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 ----------------------------------------------- */
@@ -255,9 +252,3 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config,
255252
256253
See also PyConfig.orig_argv. */
257254
PyAPI_FUNC(void) Py_GetArgcArgv(int *argc, wchar_t ***argv);
258-
259-
#ifdef __cplusplus
260-
}
261-
#endif
262-
#endif /* !Py_LIMITED_API */
263-
#endif /* !Py_PYCORECONFIG_H */

Include/initconfig.h

Lines changed: 96 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 31 additions & 16 deletions
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')
@@ -511,7 +519,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
511519
'check_hash_pycs_mode': 'default',
512520
'pathconfig_warnings': 1,
513521
'_init_main': 1,
514-
'use_frozen_modules': not support.Py_DEBUG,
522+
'use_frozen_modules': int(not support.Py_DEBUG),
515523
'safe_path': 0,
516524
'_is_python_build': IGNORE_CONFIG,
517525
}
@@ -991,33 +999,26 @@ def test_init_env_dev_mode_alloc(self):
991999
api=API_COMPAT)
9921000

9931001
def test_init_dev_mode(self):
994-
preconfig = {
995-
'allocator': PYMEM_ALLOCATOR_DEBUG,
996-
}
1002+
preconfig = {}
9971003
config = {
998-
'faulthandler': 1,
9991004
'dev_mode': 1,
1000-
'warnoptions': ['default'],
10011005
}
1006+
config_dev_mode(preconfig, config)
10021007
self.check_all_configs("test_init_dev_mode", config, preconfig,
10031008
api=API_PYTHON)
10041009

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

@@ -1618,16 +1619,15 @@ def test_init_warnoptions(self):
16181619
'ignore:::PySys_AddWarnOption2', # PySys_AddWarnOption()
16191620
'ignore:::PyConfig_BeforeRead', # PyConfig.warnoptions
16201621
'ignore:::PyConfig_AfterRead'] # PyWideStringList_Append()
1621-
preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG)
1622+
preconfig = {}
16221623
config = {
1623-
'dev_mode': 1,
1624-
'faulthandler': 1,
16251624
'bytes_warning': 1,
1626-
'warnoptions': warnoptions,
16271625
'orig_argv': ['python3',
16281626
'-Wignore:::cmdline1',
16291627
'-Wignore:::cmdline2'],
16301628
}
1629+
config_dev_mode(preconfig, config)
1630+
config['warnoptions'] = warnoptions
16311631
self.check_all_configs("test_init_warnoptions", config, preconfig,
16321632
api=API_PYTHON)
16331633

@@ -1640,6 +1640,21 @@ def test_init_set_config(self):
16401640
self.check_all_configs("test_init_set_config", config,
16411641
api=API_ISOLATED)
16421642

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

Lib/test/test_stable_abi_ctypes.py

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

Misc/stable_abi.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,3 +2460,26 @@
24602460
added = '3.13'
24612461
[function.PyMapping_HasKeyStringWithError]
24622462
added = '3.13'
2463+
2464+
[function.PyInitConfig_Python_New]
2465+
added = '3.13'
2466+
[function.PyInitConfig_Isolated_New]
2467+
added = '3.13'
2468+
[function.PyInitConfig_Free]
2469+
added = '3.13'
2470+
[function.PyInitConfig_SetInt]
2471+
added = '3.13'
2472+
[function.PyInitConfig_SetStr]
2473+
added = '3.13'
2474+
[function.PyInitConfig_SetStrList]
2475+
added = '3.13'
2476+
[function.PyInitConfig_SetWStr]
2477+
added = '3.13'
2478+
[function.PyInitConfig_SetWStrList]
2479+
added = '3.13'
2480+
[function.PyInitConfig_GetErrorMsg]
2481+
added = '3.13'
2482+
[function.Py_InitializeFromInitConfig]
2483+
added = '3.13'
2484+
[function.Py_ExitWithInitConfig]
2485+
added = '3.13'

PC/python3dll.c

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

0 commit comments

Comments
 (0)