-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
embed.h Python 3.11 config.use_environment=1
+ PYTHONPATH
test
#4119
Conversation
@vstinner I saw you worked on
Does that ring any bells? Some details are below, JIC. @henryiii I wonder if this could have to do with PR #3923, which introduced a new *** The "exact same situation" is possibly unusual (interactively building Python from sources with configure; make install; using my own scons-based tools to build the pybind11 tests), but the only variable is the Python version. I added And patched the Python sources like this: --- Objects/unicodeobject.c.orig 2022-08-05 08:18:54.186431792 -0700
+++ Objects/unicodeobject.c 2022-08-04 17:36:36.375312426 -0700
@@ -16005,13 +16005,14 @@
init_fs_encoding(PyThreadState *tstate)
{
PyInterpreterState *interp = tstate->interp;
+ _Py_DumpPathConfig(tstate);
/* Update the filesystem encoding to the normalized Python codec name.
For example, replace "ANSI_X3.4-1968" (locale encoding) with "ascii"
(Python codec name). */
PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp);
if (config_get_codec_name(&config->filesystem_encoding) < 0) {
- _Py_DumpPathConfig(tstate);
+ //_Py_DumpPathConfig(tstate);
return _PyStatus_ERR("failed to get the Python codec "
"of the filesystem encoding");
} I'm seeing this with 3.10.5:
And this with 3.11.0b5:
|
pybind11 seems to use a different API on Python 3.10 and Python 3.11. PySys_SetArgvEx() called after Python init on Python 3.10 versus Py_InitializeFromConfig() on Python 3.11. Your dump says:
So PYTHONPATH was used. It's part of the computed sys.path. pybind11 doesn't call PySys_SetArgvEx() on Python 3.11. That's the function which changes sys.path. |
…ialize_interpreter()`
@vstinner Thanks a lot for the explanation and the pointers! I see
But evidently the computed sys.path is not in effect in test_embed. — What's the recommended way to restore the established behavior? I decided to try something straightforward, using --- a/include/pybind11/embed.h
+++ b/include/pybind11/embed.h
@@ -166,6 +166,9 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
throw std::runtime_error(PyStatus_IsError(status) ? status.err_msg
: "Failed to init CPython");
}
+ // Emulates established behavior (prior to Python 3.11 implemented by PySys_SetArgvEx()).
+ PyRun_SimpleString("import sys, os; "
+ "sys.path[:0] = os.environ.get('PYTHONPATH', []).split(os.pathsep)");
if (add_program_dir_to_path) {
PyRun_SimpleString("import sys, os.path; "
"sys.path.insert(0, " With that I get back the established behavior and test_embed passes in my situation. Is that approach OK? |
Sorry, I don't get how you manage to get PYTHONPATH environment variable being ignored. If you are looking for my help, it would help if you could write a short C or C++ program reproducing your issue. pybind11 is a very large code base that I don't know. |
There seems to be some kind of conflict in expectations & observations:
But earlier:
=========================================================================
At the moment I'm leaning more towards root-causing why @vstinner Would you have a pointer to the cpython sources that update |
Interestingly — and luckily — I'm seeing a behavior change between 3.11.0b5 and 3.11.0rc1, both installed from tar files. Everything except 3.11.0b5 vs 3.11.0rc1 being equal, when running test_embed with
I believe it is enlightening, because only the 1st This observation got me to look again at the new 3.11-specific I tried adding What do we want to do? A. Document the pybind11 behavior change? (What do we want to suggest as a solution for people who relied on the old behavior?) @henryiii @Skylion007 @vstinner what is your vote or recommendation? I don't like A but don't have enough background to decide between B, C, D. D doesn't look very general. Maybe B or C? |
PyConfig_InitIsolatedConfig() sets isolated to 1 and isolated=1 implies use_environment=0. |
That's closer to the regular "python" program. You can then tweak configuration from these defaults. For example, it uses isolated=0 and use_environment=1. Example:
|
If you are talking about PySys_SetArgvEx() that you only call on Python 3.10 and older: |
I only now got a chance to poke some more at this, trying to use - PyConfig_InitIsolatedConfig(&config);
+ PyConfig_InitPythonConfig(&config); With that as the only diff against current master, the
Note that I moved the With all other tested removed, this simply fails. With others tests present, it turns into a segfault (possibly triggered by the following test) even with the Commenting out the I have to give up for now. We don't use embedding, I cannot spend more time on this. For my local testing I can just use my If nobody else gets to this before the next pybind11 release, we should at least document that |
Python still uses PYTHONPATH env var. I cannot explain why pybind11 no longer uses it since you didn't provide a short example reproducing your issue. Python initialization is very complicated, they are like 50+ options, configuration files, etc. |
It's purely a pybind11 issue, because we're using
That's probably why I got stuck when trying To summarize:
|
You should be able to use PYTHONPATH if you set isolated=0 and use_environment=1. |
As suggsted by @vstinner here: pybind#4119 (comment)
Confirmed, thanks @vstinner! With that figured out, this PR boils down to just adding two lines in embed.h (I just need to remove the debug printf code). But I also want to add a unit test that fails if |
Nice! Maybe the effect of isolated=1 is not well explained in the doc. |
@@ -173,6 +173,18 @@ bool has_pybind11_internals_static() { | |||
|
|||
TEST_CASE("Restart the interpreter") { | |||
// Verify pre-restart state. | |||
fprintf(stdout, | |||
"\nLOOOK PYTHONPATH %s\n", | |||
py::module_::import("os") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be cleaner to just use the py::print API here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is/was just for debugging, I'll remove this before taking this PR out of draft mode, after adding a unit test for PYTHONPATH
processing.
I think py::print
could do indirections. For debugging I generally try to go straight down to the bare metal.
…s-backslash issue.
config.use_environment=1
+ PYTHONPATH
test
This (small) PR is ready for review now. |
I like the final change, short and simple :-D |
…lion007 Co-authored-by: Aaron Gokaslan <[email protected]>
Congrats for fixing your issue! |
…ybind#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: pybind#4119 (comment) * 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 <[email protected]> Co-authored-by: Aaron Gokaslan <[email protected]>
… test (pybind#4119)" This reverts commit 2488530.
Description
With pybind11 v2.10.0 & Python 3.11, the
PyConfig
in embed.h does not updatesys.path
fromPYTHONPATH
, which is incompatible with the behavior for all Python versions before 3.11. This PR changes embed.h so thatPYTHONPATH
is used also with Python 3.11.Suggested changelog entry:
embed.h was changed so that `PYTHONPATH` is used also with Python 3.11 (established behavior).