You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since 3.14, starting a virtual environment's interpreter through a non-normalized path makes site emit two spurious RuntimeWarnings on every process start:
<frozen site>:101: RuntimeWarning: Unexpected value in sys.prefix, expected /tmp/v, got /tmp/sub/../v
<frozen site>:101: RuntimeWarning: Unexpected value in sys.exec_prefix, expected /tmp/v, got /tmp/sub/../v
/tmp/sub/../v
Expected behavior
No warning. /tmp/v and /tmp/sub/../v are the same directory. Only the spelling differs, and there is no action the user can take in response.
Bisection
Clean venvs, invoking ../v/bin/python from a sibling directory:
version
warnings
sys.prefix
3.11.15, 3.12.13, 3.13.15
0
/tmp/v
3.14.7, 3.15.0rc1
2
/tmp/sub/../v
sys.executable is identical on all five (/tmp/sub/../v/bin/python). Only sys.prefix and the check are new.
Cause
site._venv() compares a sys.prefix that is not normalized against a site_prefix that is:
exe_dir=os.path.dirname(os.path.abspath(executable)) # abspath() normalizessite_prefix=os.path.dirname(exe_dir)
...
ifsys.prefix!=site_prefix:
_warn(f'Unexpected value in sys.prefix, expected {site_prefix}, got {sys.prefix}',
RuntimeWarning)
Up to 3.13 that line was an assignment, sys.prefix = sys.exec_prefix = site_prefix, so the normalized value won and nothing could disagree. GH-126987 (gh-126985), by Filipe Laíns, turned it into a consistency check while moving pyvenv.cfg detection into getpath. sys.prefix now comes from getpath, which does not normalize. The check is worth keeping, since it catches a real disagreement, and the tests below keep it doing that. Only the string comparison is too strict.
The abspath() on the other side is not incidental. It was added in #60723 (bpo-16519, 2012), reported by Christian Heimes and fixed by Vinay Sajip, specifically so that invoking the interpreter through a relative path would work, the same shape of invocation as above. That fix still does its job. What is new is that the other side of the comparison no longer goes through it.
Both sides derive from the same executable and differ only by that abspath():
and likewise for exec_prefix. No observable value changes.sys.prefix, sys.exec_prefix and sys.executable are all left as they are, and the message still reports the original value. Only the condition for warning changes.
This does not weaken the check. On a build of main (eb08902), only the false positives change, and every genuine mismatch still warns, including the one from #154160.
os.path.normpath is a C builtin and the comparison only runs inside a venv, so the cost is around 1 µs per interpreter start. I could not measure it above noise end to end.
I have a patch with two tests, since there is currently no test for this warning in test_site.py or test_venv.py, plus a NEWS entry. Happy to open a PR.
Related, but not duplicates
sys.executable generating canonical path #58296 and sys.executable can be not normalized #75213 ask for sys.executable and the prefixes to be canonicalized. That was declined, and this report does not ask for it. It starts from that decision. Victor Stinner's "the path is not required to be normalized" in sys.executable generating canonical path #58296 is the premise here: precisely because a non-normalized sys.prefix is accepted behaviour, comparing it with != against a normalized path is the wrong test. The bisection supports that reading, since sys.executable is unchanged from 3.11 through 3.15 and only the comparison is new.
sys.executable can be a relative path contrary to documented behavior [3.11 regression] #154160 / gh-154160: Make sys.executable absolute when resolved from a relative PATH entry #154163: Peter Wu's report shows these same two warnings in its output, so it ran into the symptom first. I only noticed afterwards that they can also be reached without PATH being involved at all. It is a different branch of Modules/getpath.py, reached only when program_name has no separator, so Vyron Vasileiadis' fix there does not cover this case. With env -i, where ENV_PATH is empty and that branch is unreachable, the warnings still appear. Conversely, nothing suggested here affects the relative-PATH symptom reported there. The two changes are independent, and neither makes the other redundant.
Found via a shell script that did cd subdir && ../venv/bin/python …, which put two warning lines at the top of every log it produced.
Since this is a 3.14 regression, a backport may be appropriate, but I will leave that call to you.
CPython versions tested on:
CPython main branch, 3.11, 3.12, 3.13, 3.14, 3.15, 3.16
Bug report
Bug description:
Current behavior
Since 3.14, starting a virtual environment's interpreter through a non-normalized path makes
siteemit two spuriousRuntimeWarnings on every process start:Expected behavior
No warning.
/tmp/vand/tmp/sub/../vare the same directory. Only the spelling differs, and there is no action the user can take in response.Bisection
Clean venvs, invoking
../v/bin/pythonfrom a sibling directory:sys.prefix/tmp/v/tmp/sub/../vsys.executableis identical on all five (/tmp/sub/../v/bin/python). Onlysys.prefixand the check are new.Cause
site._venv()compares asys.prefixthat is not normalized against asite_prefixthat is:Up to 3.13 that line was an assignment,
sys.prefix = sys.exec_prefix = site_prefix, so the normalized value won and nothing could disagree. GH-126987 (gh-126985), by Filipe Laíns, turned it into a consistency check while movingpyvenv.cfgdetection intogetpath.sys.prefixnow comes fromgetpath, which does not normalize. The check is worth keeping, since it catches a real disagreement, and the tests below keep it doing that. Only the string comparison is too strict.The
abspath()on the other side is not incidental. It was added in #60723 (bpo-16519, 2012), reported by Christian Heimes and fixed by Vinay Sajip, specifically so that invoking the interpreter through a relative path would work, the same shape of invocation as above. That fix still does its job. What is new is that the other side of the comparison no longer goes through it.Both sides derive from the same
executableand differ only by thatabspath():Suggested fix
Compare normalized forms:
and likewise for
exec_prefix. No observable value changes.sys.prefix,sys.exec_prefixandsys.executableare all left as they are, and the message still reports the original value. Only the condition for warning changes.This does not weaken the check. On a build of
main(eb08902), only the false positives change, and every genuine mismatch still warns, including the one from #154160.Every case, measured with and without the change
../v/bin/pythonfrom a sibling directoryenv -i(noPATHin the environment)PATHentry (the #154160 symptom)//tmp/v/bin/python..in the middle of the pathpyvenv.cfgnext to the interpreteros.path.normpathis a C builtin and the comparison only runs inside a venv, so the cost is around 1 µs per interpreter start. I could not measure it above noise end to end.I have a patch with two tests, since there is currently no test for this warning in
test_site.pyortest_venv.py, plus a NEWS entry. Happy to open a PR.Related, but not duplicates
sys.executableand the prefixes to be canonicalized. That was declined, and this report does not ask for it. It starts from that decision. Victor Stinner's "the path is not required to be normalized" in sys.executable generating canonical path #58296 is the premise here: precisely because a non-normalizedsys.prefixis accepted behaviour, comparing it with!=against a normalized path is the wrong test. The bisection supports that reading, sincesys.executableis unchanged from 3.11 through 3.15 and only the comparison is new.PATHbeing involved at all. It is a different branch ofModules/getpath.py, reached only whenprogram_namehas no separator, so Vyron Vasileiadis' fix there does not cover this case. Withenv -i, whereENV_PATHis empty and that branch is unreachable, the warnings still appear. Conversely, nothing suggested here affects the relative-PATHsymptom reported there. The two changes are independent, and neither makes the other redundant.Found via a shell script that did
cd subdir && ../venv/bin/python …, which put two warning lines at the top of every log it produced.Since this is a 3.14 regression, a backport may be appropriate, but I will leave that call to you.
CPython versions tested on:
CPython main branch, 3.11, 3.12, 3.13, 3.14, 3.15, 3.16
Operating systems tested on:
Linux
Linked PRs