Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makes --python command-line flag take precedence over env var #2821

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading