Skip to content

🐛 fix(batch): save an undefined PROMPT so deactivate can restore it - #3489

Merged
gaborbernat merged 2 commits into
pypa:mainfrom
darrenhuai:fix/batch-unset-prompt
Oct 28, 2026
Merged

gaborbernat merged 2 commits into
pypa:mainfrom
darrenhuai:fix/batch-unset-prompt

Conversation

@darrenhuai

@darrenhuai darrenhuai commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Running prompt with no arguments resets the cmd prompt by deleting the PROMPT variable, and set PROMPT= does the same. If you activated an environment after either, deactivate.bat left the environment name in the prompt, and activating again added a second one. 🐛 With virtualenv 21.15.1 the prompt went (venv) $P$G while active, stayed (venv) $P$G after deactivate, and became (venv) (venv) $P$G on the next activation. After this change deactivate restores the default $P$G, which cmd displays the same way as an undefined PROMPT. A new cmd window always starts with PROMPT=$P$G, so only those two commands lead here.

activate.bat fell back to $P$G for an undefined PROMPT inside 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, and deactivate.bat restores 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, or VIRTUAL_ENV_DISABLE_PROMPT is 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 through prek on the changed files; the semgrep hook only looks at activate.sh.

  • wrote descriptive pull request text

  • ensured there are test(s) validating the fix

  • added a docs/changelog/+short-description.<type>.rst fragment for each user-facing change, or applied skip news

  • updated/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's PROMPT. The change only moves the literal $P$G assignment out of the block. The script still reads the user's prompt through the same quoted set "_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

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
darrenhuai marked this pull request as ready for review October 28, 2026 06:15

@gaborbernat gaborbernat left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaborbernat
gaborbernat merged commit 861cff7 into pypa:main Oct 28, 2026
79 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants