Skip to content

Commit

Permalink
Pass sys.executable to uv venv if it is the same version (#40)
Browse files Browse the repository at this point in the history
* Pass sys.executable to `uv venv` if it is the same version

Support the case when pythonX.Y is not in the search path, but
it corresponds to the currently running Python interpreter.

This may happen if e.g. Tox is installed (along with tox-uv) in
a virtual environment that has been created with a Python interpreter
coming from a non-standard location, and then `tox` is invoked
directly from the virtual environment's `bin/` directory:

    [roam@straylight ~]$ mkdir ~/not-in-path

    [roam@straylight ~]$ uv venv -p /opt/some-vendor/python3/bin/python3 ~/not-in-path/venv
    Using Python 3.8.17 interpreter at: /opt/some-vendor/python3/bin/python3
    Creating virtualenv at: /home/roam/not-in-path/venv
    Activate with: source /home/roam/not-in-path/venv/bin/activate

    [roam@straylight ~]$ (set -e; . ~/not-in-path/venv/bin/activate; uv pip install tox tox-uv)
    ...snip...

    [roam@straylight ~]$ printf -- '%s\n' '[testenv]' 'package=skip' 'commands=python3 -c "print()"' > ~/not-in-path/tox.ini

    [roam@straylight ~]$ ~/not-in-path/venv/bin/tox -c ~/not-in-path/tox.ini
    py: venv /home/roam/not-in-path> venv/bin/uv venv -p 3.8 /home/roam/not-in-path/.tox/py/.venv
      × No Python 3.8 in `PATH`. Is Python 3.8 installed?
    py: exit 1 (0.01 seconds) /home/roam/not-in-path> venv/bin/uv venv -p 3.8 /home/roam/not-in-path/.tox/py/.venv pid=1059253
      py: FAIL code 1 (0.02 seconds)
      evaluation failed :( (0.11 seconds)

    [roam@straylight ~]$

* Let Ruff know that we try to use subprocess responsibly

* Tox is certainly installed during the test suite run
  • Loading branch information
ppentchev authored Mar 16, 2024
1 parent db7196f commit 04363ff
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/tox_uv/_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,13 @@ def _default_pass_env(self) -> list[str]:

def create_python_env(self) -> None:
base = self.base_python.version_info
version_spec = f"{base.major}.{base.minor}" if base.minor else f"{base.major}"
version_spec = (
sys.executable
if (base.major, base.minor) == sys.version_info[:2]
else f"{base.major}.{base.minor}"
if base.minor
else f"{base.major}"
)
cmd: list[str] = [self.uv, "venv", "-p", version_spec]
if self.options.verbosity > 2: # noqa: PLR2004
cmd.append("-v")
Expand Down
30 changes: 30 additions & 0 deletions tests/test_tox_uv_venv.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from __future__ import annotations

import importlib.util
import os
import os.path
import pathlib
import subprocess # noqa: S404
import sys
from configparser import ConfigParser
from typing import TYPE_CHECKING
Expand Down Expand Up @@ -86,3 +91,28 @@ def test_uv_env_site_package_dir(tox_project: ToxProjectCreator) -> None:
else: # pragma: win32 no cover
path = str(env_dir / "lib" / f"python{ver.major}.{ver.minor}" / "site-packages")
assert path in result.out


def test_uv_env_python_not_in_path(tox_project: ToxProjectCreator) -> None:
# Make sure there is no pythonX.Y in the search path
ver = sys.version_info
exe_ext = ".exe" if sys.platform == "win32" else ""
python_exe = f"python{ver.major}.{ver.minor}{exe_ext}"
env = dict(os.environ)
env["PATH"] = os.path.pathsep.join(
path for path in env["PATH"].split(os.path.pathsep) if not (pathlib.Path(path) / python_exe).is_file()
)

# Make sure the Python interpreter can find our Tox module
tox_spec = importlib.util.find_spec("tox")
assert tox_spec is not None
tox_lines = subprocess.check_output(
[sys.executable, "-c", "import tox; print(tox.__file__);"], encoding="UTF-8", env=env
).splitlines()
assert tox_lines == [tox_spec.origin]

# Now use that Python interpreter to run Tox
project = tox_project({"tox.ini": "[testenv]\npackage=skip\ncommands=python -c 'print(\"{env_python}\")'"})
tox_ini = project.path / "tox.ini"
assert tox_ini.is_file()
subprocess.check_call([sys.executable, "-m", "tox", "-c", tox_ini], env=env)

0 comments on commit 04363ff

Please sign in to comment.