Repository navigation
🐛 fix(batch): save an undefined PROMPT so deactivate can restore it - #3489
Merged
Merged
Conversation
activate.bat fell back to $P$G for an undefined PROMPT inside the same parenthesized block that saves _OLD_VIRTUAL_PROMPT. cmd expands %PROMPT% for the whole block before running it, so the saved value was empty and the variable was never set. With PROMPT undefined (a bare `prompt` command, or `set PROMPT=`), deactivate left "(env) $P$G" behind and a second activate showed "(env) (env) $P$G". Set the default before the block so the save sees it. The round-trip test now also starts from an undefined PROMPT, in both expansion modes.
darrenhuai
marked this pull request as ready for review
October 28, 2026 06:15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Running
promptwith no arguments resets the cmd prompt by deleting thePROMPTvariable, andset PROMPT=does the same. If you activated an environment after either,deactivate.batleft the environment name in the prompt, and activating again added a second one. 🐛 With virtualenv 21.15.1 the prompt went(venv) $P$Gwhile active, stayed(venv) $P$Gafterdeactivate, and became(venv) (venv) $P$Gon the next activation. After this changedeactivaterestores the default$P$G, which cmd displays the same way as an undefinedPROMPT. A new cmd window always starts withPROMPT=$P$G, so only those two commands lead here.activate.batfell back to$P$Gfor an undefinedPROMPTinside the same parenthesized block that saves the old prompt. cmd expands%PROMPT%in a block when it reads the block, before any line in it runs (only delayed expansion substitutes at run time), so the save captured an empty value, anddeactivate.batrestores the prompt only when a saved value exists. The fallback now runs on its own line before the block, so the save sees$P$G. When an earlier activation's saved prompt is still present, orVIRTUAL_ENV_DISABLE_PROMPTis set, the script behaves as before.Thanks for contributing, make sure you address all the checklists (for details on how see development documentation)
ran the linter to address style issues (
tox -e fix). I ran the same hooks throughprekon the changed files; the semgrep hook only looks atactivate.sh.wrote descriptive pull request text
ensured there are test(s) validating the fix
added a
docs/changelog/+short-description.<type>.rstfragment for each user-facing change, or appliedskip newsupdated/extended the documentation (no docs describe this case)
for changes to activation scripts,
pyvenv.cfg, wheel downloads, app-data or release workflows: the outside input is the user'sPROMPT. The change only moves the literal$P$Gassignment out of the block. The script still reads the user's prompt through the same quotedset "_OLD_VIRTUAL_PROMPT=%PROMPT%"as before, and it expands or runs nothing new.ran tests on Python 3.9 and 3.15 (
tox run -e 3.9,3.15). I ran 3.13 locally and left 3.9 and 3.15 to CI.linked upstream issues beside any temporary interpreter overrides (none)
kept the PR in draft until CI passes