Skip to content

fix(nodeenv): let -p target a virtualenv nodeenv isn't installed in - #402

Merged
ekalinin merged 2 commits into
masterfrom
fix/python-virtualenv-arg
Sep 19, 2026
Merged

ekalinin merged 2 commits into
masterfrom
fix/python-virtualenv-arg

Conversation

@ekalinin

@ekalinin ekalinin commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Closes #156

Problem

-p takes no argument, and the env dir detection checks sys.prefix before VIRTUAL_ENV. When nodeenv is installed into its own virtualenv (pipx, pipsi, uv tool), sys.prefix is that virtualenv, so -p silently installs node.js there instead of the activated one:

VIRTUAL_ENV env var : /tmp/t156/target
sys.prefix          : /tmp/t156/nodeenv-home
nodeenv picks       : /tmp/t156/nodeenv-home

nodeenv --force $VIRTUAL_ENV is not a workaround: without -p the activation script is written with append=False, so the virtualenv's own bin/activate gets overwritten, and the predeactivate hook is not installed.

Changes

  • -p accepts an optional directory (nargs='?', const=True), so any virtualenv can be targeted explicitly. A missing directory is an error (exit 2) instead of silently creating a new one, since the "environment already exists" check is skipped for -p.
  • Without an argument, VIRTUAL_ENV now wins over sys.prefix.
  • The two can only differ when nodeenv is installed outside the activated virtualenv, and then the choice is ambiguous, so nodeenv logs which one it took and how to override it:
 * Using activated virtualenv /path/to/target, not /path/to/nodeenv-home where nodeenv is installed, pass a directory to -p to override
  • The three sys.prefix branches all resolved to the same value, so they are folded into a single check that the warning reuses.
  • Three existing get_env_dir tests did not isolate os.environ; they now clear it, so the result no longer depends on whether pytest runs from an activated virtualenv.
  • New tests for the explicit directory, the missing directory, the VIRTUAL_ENV preference and both quiet cases.

Compatibility

With nodeenv installed into virtualenv inplace:

Scenario Before After
activated virtualenv is the one nodeenv is installed in inplace inplace
another virtualenv is activated inplace activated one, with a warning
nothing activated, inplace/bin/nodeenv -p inplace inplace
VIRTUAL_ENV inherited from an outer shell, inplace/bin/nodeenv -p by path inplace outer one, with a warning

The common case - node.js installed into the virtualenv you are in - is unchanged, including activation through a symlink, where venv exports the resolved path in VIRTUAL_ENV. The last row is a behaviour change; it is no longer silent and -p DIR selects the intended virtualenv.

nodeenv -p somedir previously ignored somedir and used the current virtualenv; it now treats it as the target virtualenv.

Verification

Beyond the unit tests, the scenario from the issue end to end - nodeenv installed in nodeenv-home, target activated:

  • -p resolves to target (previously nodeenv-home)
  • -p /path/to/target works with no VIRTUAL_ENV set
  • nodeenv -p /path/to/target --node=system appends to the existing bin/activate (76 -> 220 lines); after source, both VIRTUAL_ENV and NODE_VIRTUAL_ENV are set and node resolves inside the target virtualenv

-p now takes an optional directory, so a pipx/pipsi/uv tool installation
can set up node.js in any python virtualenv.

Without an argument the activated VIRTUAL_ENV is preferred over
sys.prefix: when nodeenv lives in its own virtualenv, sys.prefix points
at that virtualenv instead of the activated one.

Closes #156
The activated VIRTUAL_ENV and the virtualenv nodeenv is installed in can
only differ when nodeenv is installed elsewhere, and then the choice is
ambiguous, so log which one is used and how to override it.

The three sys.prefix branches all resolved to the same value, they are
folded into a single check reused by the warning.
@ekalinin
ekalinin force-pushed the fix/python-virtualenv-arg branch from 9afae88 to e60ab77 Compare September 19, 2026 12:19
@ekalinin
ekalinin merged commit bb01555 into master Sep 19, 2026
42 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.

nodeenv -p should take an argument

1 participant