@@ -86,37 +86,22 @@ inline wchar_t *widen_chars(const char *safe_arg) {
86
86
return widened_arg;
87
87
}
88
88
89
- PYBIND11_NAMESPACE_END (detail)
90
-
91
- /* * \rst
92
- Initialize the Python interpreter. No other pybind11 or CPython API functions can be
93
- called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
94
- optional `init_signal_handlers` parameter can be used to skip the registration of
95
- signal handlers (see the `Python documentation`_ for details). Calling this function
96
- again after the interpreter has already been initialized is a fatal error.
97
-
98
- If initializing the Python interpreter fails, then the program is terminated. (This
99
- is controlled by the CPython runtime and is an exception to pybind11's normal behavior
100
- of throwing exceptions on errors.)
101
-
102
- The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
103
- used to populate ``sys.argv`` and ``sys.path``.
104
- See the |PySys_SetArgvEx documentation|_ for details.
105
-
106
- .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
107
- .. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
108
- .. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
109
- \endrst */
110
- inline void initialize_interpreter(bool init_signal_handlers = true ,
111
- int argc = 0 ,
112
- const char *const *argv = nullptr ,
113
- bool add_program_dir_to_path = true ) {
89
+ inline void precheck_interpreter () {
114
90
if (Py_IsInitialized () != 0 ) {
115
91
pybind11_fail (" The interpreter is already running" );
116
92
}
93
+ }
117
94
118
- #if PY_VERSION_HEX < 0x030B0000
95
+ #if !defined(PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX)
96
+ # define PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX (0x03080000 )
97
+ #endif
119
98
99
+ #if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
100
+ inline void initialize_interpreter_pre_pyconfig (bool init_signal_handlers,
101
+ int argc,
102
+ const char *const *argv,
103
+ bool add_program_dir_to_path) {
104
+ detail::precheck_interpreter ();
120
105
Py_InitializeEx (init_signal_handlers ? 1 : 0 );
121
106
# if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000
122
107
PyEval_InitThreads ();
@@ -150,33 +135,74 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
150
135
auto *pysys_argv = widened_argv.get ();
151
136
152
137
PySys_SetArgvEx (argc, pysys_argv, static_cast <int >(add_program_dir_to_path));
153
- #else
154
- PyConfig config;
155
- PyConfig_InitIsolatedConfig (&config);
156
- config.isolated = 0 ;
157
- config.use_environment = 1 ;
158
- config.install_signal_handlers = init_signal_handlers ? 1 : 0 ;
138
+ }
139
+ #endif
159
140
160
- PyStatus status = PyConfig_SetBytesArgv (&config, argc, const_cast <char *const *>(argv));
161
- if (PyStatus_Exception (status)) {
141
+ PYBIND11_NAMESPACE_END (detail)
142
+
143
+ #if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
144
+ inline void initialize_interpreter (PyConfig *config,
145
+ int argc = 0 ,
146
+ const char *const *argv = nullptr ,
147
+ bool add_program_dir_to_path = true ) {
148
+ detail::precheck_interpreter ();
149
+ PyStatus status = PyConfig_SetBytesArgv (config, argc, const_cast <char *const *>(argv));
150
+ if (PyStatus_Exception (status) != 0 ) {
162
151
// A failure here indicates a character-encoding failure or the python
163
152
// interpreter out of memory. Give up.
164
- PyConfig_Clear (& config);
165
- throw std::runtime_error (PyStatus_IsError (status) ? status.err_msg
166
- : " Failed to prepare CPython" );
153
+ PyConfig_Clear (config);
154
+ throw std::runtime_error (PyStatus_IsError (status) != 0 ? status.err_msg
155
+ : " Failed to prepare CPython" );
167
156
}
168
- status = Py_InitializeFromConfig (& config);
169
- PyConfig_Clear (&config);
170
- if ( PyStatus_Exception (status)) {
171
- throw std::runtime_error (PyStatus_IsError (status) ? status.err_msg
172
- : " Failed to init CPython" );
157
+ status = Py_InitializeFromConfig (config);
158
+ if ( PyStatus_Exception (status) != 0 ) {
159
+ PyConfig_Clear (config);
160
+ throw std::runtime_error (PyStatus_IsError (status) != 0 ? status.err_msg
161
+ : " Failed to init CPython" );
173
162
}
174
163
if (add_program_dir_to_path) {
175
164
PyRun_SimpleString (" import sys, os.path; "
176
165
" sys.path.insert(0, "
177
166
" os.path.abspath(os.path.dirname(sys.argv[0])) "
178
167
" if sys.argv and os.path.exists(sys.argv[0]) else '')" );
179
168
}
169
+ PyConfig_Clear (config);
170
+ }
171
+ #endif
172
+
173
+ /* * \rst
174
+ Initialize the Python interpreter. No other pybind11 or CPython API functions can be
175
+ called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
176
+ optional `init_signal_handlers` parameter can be used to skip the registration of
177
+ signal handlers (see the `Python documentation`_ for details). Calling this function
178
+ again after the interpreter has already been initialized is a fatal error.
179
+
180
+ If initializing the Python interpreter fails, then the program is terminated. (This
181
+ is controlled by the CPython runtime and is an exception to pybind11's normal behavior
182
+ of throwing exceptions on errors.)
183
+
184
+ The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
185
+ used to populate ``sys.argv`` and ``sys.path``.
186
+ See the |PySys_SetArgvEx documentation|_ for details.
187
+
188
+ .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
189
+ .. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
190
+ .. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
191
+ \endrst */
192
+ inline void initialize_interpreter (bool init_signal_handlers = true ,
193
+ int argc = 0 ,
194
+ const char *const *argv = nullptr ,
195
+ bool add_program_dir_to_path = true ) {
196
+ #if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
197
+ detail::initialize_interpreter_pre_pyconfig (
198
+ init_signal_handlers, argc, argv, add_program_dir_to_path);
199
+ #else
200
+ PyConfig config;
201
+ PyConfig_InitIsolatedConfig (&config);
202
+ config.isolated = 0 ;
203
+ config.use_environment = 1 ;
204
+ config.install_signal_handlers = init_signal_handlers ? 1 : 0 ;
205
+ initialize_interpreter (&config, argc, argv, add_program_dir_to_path);
180
206
#endif
181
207
}
182
208
@@ -264,6 +290,15 @@ class scoped_interpreter {
264
290
initialize_interpreter (init_signal_handlers, argc, argv, add_program_dir_to_path);
265
291
}
266
292
293
+ #if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
294
+ explicit scoped_interpreter (PyConfig *config,
295
+ int argc = 0 ,
296
+ const char *const *argv = nullptr ,
297
+ bool add_program_dir_to_path = true ) {
298
+ initialize_interpreter (config, argc, argv, add_program_dir_to_path);
299
+ }
300
+ #endif
301
+
267
302
scoped_interpreter (const scoped_interpreter &) = delete ;
268
303
scoped_interpreter (scoped_interpreter &&other) noexcept { other.is_valid = false ; }
269
304
scoped_interpreter &operator =(const scoped_interpreter &) = delete ;
0 commit comments