Skip to content

Commit

Permalink
Merge pull request #2821 from filiplajszczak/cli-precedence-2285
Browse files Browse the repository at this point in the history
Makes --python command-line flag take precedence over env var
  • Loading branch information
filiplajszczak authored Jan 14, 2025
1 parent 11995e7 commit bc7a91a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/virtualenv/discovery/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import os
import sys
from collections import deque
from contextlib import suppress
from pathlib import Path
from typing import TYPE_CHECKING
Expand All @@ -22,13 +23,16 @@


class Builtin(Discover):
python_spec: Sequence[str]
python_spec: Sequence[str] | deque[str]
app_data: AppData
try_first_with: Sequence[str]

def __init__(self, options) -> None:
super().__init__(options)
self.python_spec = options.python or [sys.executable]
if self._env.get("VIRTUALENV_PYTHON"):
self.python_spec = deque(self.python_spec)
self.python_spec.rotate(-1)
self.app_data = options.app_data
self.try_first_with = options.try_first_with

Expand Down
51 changes: 51 additions & 0 deletions tests/unit/discovery/test_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,54 @@ def test_discovery_fallback_ok(session_app_data, caplog):
assert result.executable == sys.executable, caplog.text

assert "accepted" in caplog.text


@pytest.fixture
def mock_get_interpreter(mocker):
return mocker.patch(
"virtualenv.discovery.builtin.get_interpreter",
lambda key, *args, **kwargs: getattr(mocker.sentinel, key), # noqa: ARG005
)


@pytest.mark.usefixtures("mock_get_interpreter")
def test_returns_first_python_specified_when_only_env_var_one_is_specified(mocker, monkeypatch, session_app_data):
monkeypatch.setenv("VIRTUALENV_PYTHON", "python_from_env_var")
builtin = Builtin(
Namespace(app_data=session_app_data, try_first_with=[], python=["python_from_env_var"], env=os.environ),
)

result = builtin.run()

assert result == mocker.sentinel.python_from_env_var


@pytest.mark.usefixtures("mock_get_interpreter")
def test_returns_second_python_specified_when_more_than_one_is_specified_and_env_var_is_specified(
mocker, monkeypatch, session_app_data
):
monkeypatch.setenv("VIRTUALENV_PYTHON", "python_from_env_var")
builtin = Builtin(
Namespace(
app_data=session_app_data,
try_first_with=[],
python=["python_from_env_var", "python_from_cli"],
env=os.environ,
),
)

result = builtin.run()

assert result == mocker.sentinel.python_from_cli


@pytest.mark.usefixtures("mock_get_interpreter")
def test_returns_first_python_specified_when_no_env_var_is_specified(mocker, monkeypatch, session_app_data):
monkeypatch.delenv("VIRTUALENV_PYTHON", raising=False)
builtin = Builtin(
Namespace(app_data=session_app_data, try_first_with=[], python=["python_from_cli"], env=os.environ),
)

result = builtin.run()

assert result == mocker.sentinel.python_from_cli

0 comments on commit bc7a91a

Please sign in to comment.