@@ -86,37 +86,22 @@ inline wchar_t *widen_chars(const char *safe_arg) {
8686 return widened_arg;
8787}
8888
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 () {
11490 if (Py_IsInitialized () != 0 ) {
11591 pybind11_fail (" The interpreter is already running" );
11692 }
93+ }
11794
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
11998
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 ();
120105 Py_InitializeEx (init_signal_handlers ? 1 : 0 );
121106# if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000
122107 PyEval_InitThreads ();
@@ -150,33 +135,74 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
150135 auto *pysys_argv = widened_argv.get ();
151136
152137 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
159140
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 ) {
162151 // A failure here indicates a character-encoding failure or the python
163152 // 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" );
167156 }
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" );
173162 }
174163 if (add_program_dir_to_path) {
175164 PyRun_SimpleString (" import sys, os.path; "
176165 " sys.path.insert(0, "
177166 " os.path.abspath(os.path.dirname(sys.argv[0])) "
178167 " if sys.argv and os.path.exists(sys.argv[0]) else '')" );
179168 }
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);
180206#endif
181207}
182208
@@ -264,6 +290,15 @@ class scoped_interpreter {
264290 initialize_interpreter (init_signal_handlers, argc, argv, add_program_dir_to_path);
265291 }
266292
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+
267302 scoped_interpreter (const scoped_interpreter &) = delete ;
268303 scoped_interpreter (scoped_interpreter &&other) noexcept { other.is_valid = false ; }
269304 scoped_interpreter &operator =(const scoped_interpreter &) = delete ;
0 commit comments