Skip to content

🐛 fix(py_info): stop venv lookups rewriting each other's executable - #171

Merged
gaborbernat merged 3 commits into
tox-dev:mainfrom
darrenhuai:fix/cached-info-copies
Oct 28, 2026
Merged

gaborbernat merged 3 commits into
tox-dev:mainfrom
darrenhuai:fix/cached-info-copies

Conversation

@darrenhuai

@darrenhuai darrenhuai commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Looking up one venv rewrote the executable of results from earlier lookups that share its base interpreter. 🐛 After get_interpreter("/path/to/vb/bin/python"), a result already returned for venv va, along with PythonInfo.current_system() (and PythonInfo.current() when running from the base), reported vb as its executable, so running it started the wrong environment. iter_interpreters had the same problem across its yields. Once this merges, every result keeps the executable it was looked up with, on Linux and Windows.

The interpreter cache hands every lookup of a base interpreter the same object, and resolving a venv to its base then wrote the venv's path onto that shared object, a behavior carried over from virtualenv in #28. Resolution now gives the caller its own shallow copy whenever the executable has to change, and leaves the cached object alone. When the executable already matches, it returns the cached object unchanged, so get_interpreter(sys.executable) is PythonInfo.current() still holds for a base interpreter, an identity virtualenv relies on.

darrenhuai and others added 3 commits October 27, 2026 18:57
resolve_to_system swaps a venv's info for the base interpreter's info, which
comes straight out of the in-process cache, and then writes the venv's
executable onto it. Every venv built on the same base, and the base itself,
get that one object back, so each lookup rewrites the executable of every
earlier result. A process running from a venv that looks up a second venv on
the same base then gets the second venv from get_interpreter("python") and
from PythonInfo.current_system(), and running that executable lands in the
wrong environment. Results yielded by iter_interpreters change after the fact
in the same way, and when the process runs from the base interpreter the
object is the one PythonInfo.current() returns.

resolve_to_system now copies the info before pointing it at the start
executable, whether the info came from from_exe or from the discover_exe walk,
since both hand back cached objects. When the executable already matches, the
same object comes back as before, so virtualenv's check that the interpreter
is PythonInfo.current() keeps working.
@gaborbernat gaborbernat added the bug Something isn't working label Oct 28, 2026
@gaborbernat
gaborbernat merged commit 57e1308 into tox-dev:main Oct 28, 2026
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants