embed.h Python 3.11 config.use_environment=1 + PYTHONPATH test (#4119)

* Add debug fprintf to test_interpreter.cpp

* Update `sys.path` from `PYTHONPATH` in Python >= 3.11 branch of `initialize_interpreter()`

* Use `config.isolated = 0; config.use_environment = 1;`

As suggsted by @vstinner here: https://github.com/pybind/pybind11/pull/4119#issuecomment-1219442853

* Add `TEST_CASE("PYTHONPATH is used to update sys.path")`

* Fix clang-tidy error.

* Use `_putenv_s()` under Windows.

* Fix clang-tidy error: argument name ... in comment does not match parameter name

* Remove slash from PYTHONPATH addition, to work around Windows slash-vs-backslash issue.

* Use `py::str(...)` instead of `.attr("__str__")` as suggested by @skylion007

Co-authored-by: Aaron Gokaslan <skylion.aaron@gmail.com>

Co-authored-by: Aaron Gokaslan <skylion.aaron@gmail.com>
This commit is contained in:
Ralf W. Grosse-Kunstleve 2022-08-21 09:44:01 -07:00 committed by GitHub
parent 81f35d29c6
commit 68e6fdaa90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 0 deletions

View File

@ -150,6 +150,8 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
#else #else
PyConfig config; PyConfig config;
PyConfig_InitIsolatedConfig(&config); PyConfig_InitIsolatedConfig(&config);
config.isolated = 0;
config.use_environment = 1;
config.install_signal_handlers = init_signal_handlers ? 1 : 0; config.install_signal_handlers = init_signal_handlers ? 1 : 0;
PyStatus status = PyConfig_SetBytesArgv(&config, argc, const_cast<char *const *>(argv)); PyStatus status = PyConfig_SetBytesArgv(&config, argc, const_cast<char *const *>(argv));

View File

@ -20,7 +20,25 @@
namespace py = pybind11; namespace py = pybind11;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Setup for TEST_CASE in test_interpreter.cpp, tagging on a large random number:
std::string updated_pythonpath("pybind11_test_embed_PYTHONPATH_2099743835476552");
const char *preexisting_pythonpath = getenv("PYTHONPATH");
if (preexisting_pythonpath != nullptr) {
#if defined(_WIN32)
updated_pythonpath += ';';
#else
updated_pythonpath += ':';
#endif
updated_pythonpath += preexisting_pythonpath;
}
#if defined(_WIN32)
_putenv_s("PYTHONPATH", updated_pythonpath.c_str());
#else
setenv("PYTHONPATH", updated_pythonpath.c_str(), /*replace=*/1);
#endif
py::scoped_interpreter guard{}; py::scoped_interpreter guard{};
auto result = Catch::Session().run(argc, argv); auto result = Catch::Session().run(argc, argv);
return result < 0xff ? result : 0xff; return result < 0xff ? result : 0xff;

View File

@ -75,6 +75,13 @@ PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) {
d["missing"].cast<py::object>(); d["missing"].cast<py::object>();
} }
TEST_CASE("PYTHONPATH is used to update sys.path") {
// The setup for this TEST_CASE is in catch.cpp!
auto sys_path = py::str(py::module_::import("sys").attr("path")).cast<std::string>();
REQUIRE_THAT(sys_path,
Catch::Matchers::Contains("pybind11_test_embed_PYTHONPATH_2099743835476552"));
}
TEST_CASE("Pass classes and data between modules defined in C++ and Python") { TEST_CASE("Pass classes and data between modules defined in C++ and Python") {
auto module_ = py::module_::import("test_interpreter"); auto module_ = py::module_::import("test_interpreter");
REQUIRE(py::hasattr(module_, "DerivedWidget")); REQUIRE(py::hasattr(module_, "DerivedWidget"));