diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index 98cc3e46641..0e1a0304d77 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -86,37 +86,6 @@ inline wchar_t *widen_chars(const char *safe_arg) { return widened_arg; } -/// Python 2.x/3.x-compatible version of `PySys_SetArgv` -inline void set_interpreter_argv(int argc, const char *const *argv, bool add_program_dir_to_path) { - // Before it was special-cased in python 3.8, passing an empty or null argv - // caused a segfault, so we have to reimplement the special case ourselves. - bool special_case = (argv == nullptr || argc <= 0); - - const char *const empty_argv[]{"\0"}; - const char *const *safe_argv = special_case ? empty_argv : argv; - if (special_case) { - argc = 1; - } - - auto argv_size = static_cast(argc); - // SetArgv* on python 3 takes wchar_t, so we have to convert. - std::unique_ptr widened_argv(new wchar_t *[argv_size]); - std::vector> widened_argv_entries; - widened_argv_entries.reserve(argv_size); - for (size_t ii = 0; ii < argv_size; ++ii) { - widened_argv_entries.emplace_back(widen_chars(safe_argv[ii])); - if (!widened_argv_entries.back()) { - // A null here indicates a character-encoding failure or the python - // interpreter out of memory. Give up. - return; - } - widened_argv[ii] = widened_argv_entries.back().get(); - } - - auto *pysys_argv = widened_argv.get(); - PySys_SetArgvEx(argc, pysys_argv, static_cast(add_program_dir_to_path)); -} - PYBIND11_NAMESPACE_END(detail) /** \rst @@ -146,9 +115,54 @@ inline void initialize_interpreter(bool init_signal_handlers = true, pybind11_fail("The interpreter is already running"); } +#if PY_VERSION_HEX < 0x030B0000 + Py_InitializeEx(init_signal_handlers ? 1 : 0); - detail::set_interpreter_argv(argc, argv, add_program_dir_to_path); + // Before it was special-cased in python 3.8, passing an empty or null argv + // caused a segfault, so we have to reimplement the special case ourselves. + bool special_case = (argv == nullptr || argc <= 0); + + const char *const empty_argv[]{"\0"}; + const char *const *safe_argv = special_case ? empty_argv : argv; + if (special_case) { + argc = 1; + } + + auto argv_size = static_cast(argc); + // SetArgv* on python 3 takes wchar_t, so we have to convert. + std::unique_ptr widened_argv(new wchar_t *[argv_size]); + std::vector> widened_argv_entries; + widened_argv_entries.reserve(argv_size); + for (size_t ii = 0; ii < argv_size; ++ii) { + widened_argv_entries.emplace_back(widen_chars(safe_argv[ii])); + if (!widened_argv_entries.back()) { + // A null here indicates a character-encoding failure or the python + // interpreter out of memory. Give up. + return; + } + widened_argv[ii] = widened_argv_entries.back().get(); + } + + auto *pysys_argv = widened_argv.get(); + + PySys_SetArgvEx(argc, pysys_argv, static_cast(add_program_dir_to_path)); +#else + PyConfig config; + PyConfig_InitPythonConfig(&config); + config.safe_path = add_program_dir_to_path ? 0 : 1; + config.install_signal_handlers = init_signal_handlers ? 1 : 0; + + PyStatus status = PyConfig_SetBytesArgv(&config, argc, const_cast(argv)); + if (PyStatus_Exception(status)) { + // A failure here indicates a character-encoding failure or the python + // interpreter out of memory. Give up. + PyConfig_Clear(&config); + return; + } + Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); +#endif } /** \rst diff --git a/tests/requirements.txt b/tests/requirements.txt index 1159287fa94..04aafa8cf93 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,4 +1,4 @@ -build==0.7.0 +build==0.8.0 numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7" numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6" numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"