Skip to content

fix(nodeenv): keep the python virtualenv's scripts under -p on Windows - #411

Merged
ekalinin merged 2 commits into
masterfrom
fix/win-p-overwrites-venv-scripts
Sep 22, 2026
Merged

ekalinin merged 2 commits into
masterfrom
fix/win-p-overwrites-venv-scripts

Conversation

@ekalinin

Copy link
Copy Markdown
Owner

Fixes #243.

The problem

nodeenv -p inside a python virtualenv on Windows overwrote
Scripts/activate.bat, Scripts/deactivate.bat and
Scripts/Activate.ps1, so VIRTUAL_ENV and the virtualenv's own
deactivation were gone after the run. Only the posix Scripts/activate
survived, because that one is appended.

install_activate() picked append over overwrite by
bool(disable_prompt), and DISABLE_PROMPT has entries only for
activate and activate.fish, never for the cmd and PowerShell
scripts.

The fix

  • the choice now goes by the file: everything python's virtualenv
    writes is extended, listed in PYTHON_VIRTUALENV_FILES. For posix
    this is the same set as before, and shim/node are still
    overwritten
  • ACTIVATE_PS1 defines deactivate as well, and so does the
    virtualenv's own Activate.ps1 it is appended to. It now saves the
    one already in place as _OLD_NODE_DEACTIVATE and puts it back and
    calls it on a real deactivate. The internal deactivate -nondestructive does not chain, or it would undo the activation that
    just happened above it
  • writefile() starts an appended part on a line of its own: a
    deactivate.bat ending with :END and no trailing newline swallows
    the first appended line into the label

ACTIVATE_BAT and DEACTIVATE_BAT are unchanged. Under -p both
environments share one directory, so the _OLD_VIRTUAL_PROMPT /
_OLD_VIRTUAL_PATH bookkeeping the two scripts have in common composes
correctly: PATH and PROMPT after activation are the ones the virtualenv
set, and on deactivation the virtualenv's part runs first and clears
them, so the appended part leaves them alone.

Tests

  • tests/test_install_activate.py: the three cmd/PowerShell scripts
    keep the content the virtualenv wrote, and Activate.ps1 keeps a
    deactivate that is already there
  • tests/nodeenv_test.py: writefile() append starts on a new line
  • tests/test_activate_win.py: new, the counterpart of
    test_activate_shells.py for cmd and PowerShell. It runs the scripts
    for real and checks VIRTUAL_ENV, NODE_VIRTUAL_ENV and PATH after
    activation and after deactivation. Needs a Windows host, so it only
    runs in the windows-latest jobs

`nodeenv -p` decided between appending and overwriting by whether the
file had prompt-disable content, and only the posix `activate` and
`activate.fish` have any. "activate.bat", "deactivate.bat" and
"Activate.ps1" were therefore overwritten, so VIRTUAL_ENV and the
virtualenv's own deactivation were thrown away.

The decision now goes by the file: everything python's virtualenv writes
is extended. Activate.ps1 defines `deactivate` too, so the appended part
saves the one already in place and calls it when the user really
deactivates, instead of taking the name over for good.

writefile() now starts an appended part on a line of its own: a
"deactivate.bat" ending with `:END` and no trailing newline would
otherwise swallow the first appended line into the label.

#243
The Activate.ps1 python ships on Windows is signed, and PowerShell will
not parse a script with code after its signature block: the whole
activation failed with "Executable script code found in signature
block" instead of only losing the prompt.

writefile() now inserts an appended part in front of the block. The
signature no longer matches, but editing the script voids it whichever
end the new part goes to.

The PowerShell probe runs with $ErrorActionPreference = 'Stop' and its
stderr folded into stdout, so a script that cannot be parsed fails the
test that runs it instead of the next one.
@ekalinin
ekalinin merged commit 6790a73 into master Sep 22, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Installing into python venv overwrites VIRTUAL_ENV environment variable

1 participant