tox-uv icon indicating copy to clipboard operation
tox-uv copied to clipboard

Fails to run test for on the defined Python versions, except on uv's pinned Python version.

Open flowgunso opened this issue 1 year ago • 12 comments

Issue

Tox does not manage to run the tests on the defined Python version list, but it does manage to run the tests on the Python version pinned with uv. The remaining fails when trying to create a log file.

FileNotFoundError: [Errno 2] No such file or directory: '/home/[...]/snippets/get_configuration/.tox/py312/log/2-uv-sync.log'

The log/ directory does not exist. Creating it prior to running tox does not solves the issue.

Environment

  • OS: Ubuntu 22.04.4 LTS
Output of uv --version of the host Python.
uv 0.4.14
Output of tox --version of the host Python. Tox was installed using uv tool install tox --with tox-uv
4.20.0 from /home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/__init__.py
registered plugins:
    tox-uv-1.13.0 at /home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox_uv/plugin.py with uv==0.4.14

Output of running tox

Output of tox -rvv
py38: 209 W remove tox env folder /home/[...]/snippets/get_configuration/.tox/py38 [tox/tox_env/api.py:324]
py38: 214 W venv> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p 3.8 --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py38 [tox/tox_env/api.py:426]
DEBUG uv 0.4.14
DEBUG Found project root: `/home/[...]/snippets/get_configuration`
DEBUG No workspace root found, using project root
DEBUG Searching for Python 3.8 in managed installations
DEBUG Searching for managed installations at `/home/[...]/.local/share/uv/python`
DEBUG Found managed installation `cpython-3.8.19-linux-x86_64-gnu`
DEBUG Found `cpython-3.8.19-linux-x86_64-gnu` at `/home/[...]/.local/share/uv/python/cpython-3.8.19-linux-x86_64-gnu/bin/python3` (managed installations)
Using Python 3.8.19
Creating virtual environment at: .tox/py38
DEBUG Allowing existing directory
py38: 231 I exit 0 (0.02 seconds) /home/[...]/snippets/get_configuration> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p 3.8 --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py38 pid=1729520 [tox/execute/api.py:286]
py38: 233 W uv-sync> uv sync --frozen --no-dev [tox/tox_env/api.py:426]
py38: 254 E internal error [tox/session/cmd/run/single.py:60]
Traceback (most recent call last):
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/session/cmd/run/single.py", line 47, in _evaluate
    tox_env.setup()
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 249, in setup
    self._setup_env()
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox_uv/_run_lock.py", line 59, in _setup_env
    outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=False)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 388, in execute
    with self.execute_async(cmd, stdin, show, cwd, run_id, executor) as status:
  File "/home/[...]/.local/share/uv/python/cpython-3.12.5-linux-x86_64-gnu/lib/python3.12/contextlib.py", line 144, in __exit__
    next(self.gen)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 442, in execute_async
    self._log_execute(request, execute_status)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 448, in _log_execute
    self._write_execute_log(self.name, self.env_log_dir / f"{self._log_id}-{request.run_id}.log", request, status)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 452, in _write_execute_log
    with log_file.open("wt", encoding="utf-8") as file:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/[...]/.local/share/uv/python/cpython-3.12.5-linux-x86_64-gnu/lib/python3.12/pathlib.py", line 1013, in open
    return io.open(self, mode, buffering, encoding, errors, newline)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/home/[...]/snippets/get_configuration/.tox/py38/log/2-uv-sync.log'
py38: FAIL ✖ in 0.05 seconds
py39: 256 W remove tox env folder /home/[...]/snippets/get_configuration/.tox/py39 [tox/tox_env/api.py:324]
py39: 260 W venv> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p 3.9 --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py39 [tox/tox_env/api.py:426]
DEBUG uv 0.4.14
DEBUG Found project root: `/home/[...]/snippets/get_configuration`
DEBUG No workspace root found, using project root
DEBUG Searching for Python 3.9 in managed installations
DEBUG Searching for managed installations at `/home/[...]/.local/share/uv/python`
DEBUG Found managed installation `cpython-3.9.19-linux-x86_64-gnu`
DEBUG Found `cpython-3.9.19-linux-x86_64-gnu` at `/home/[...]/.local/share/uv/python/cpython-3.9.19-linux-x86_64-gnu/bin/python3` (managed installations)
Using Python 3.9.19
Creating virtual environment at: .tox/py39
DEBUG Allowing existing directory
py39: 280 I exit 0 (0.02 seconds) /home/[...]/snippets/get_configuration> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p 3.9 --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py39 pid=1729555 [tox/execute/api.py:286]
py39: 281 W uv-sync> uv sync --frozen --no-dev [tox/tox_env/api.py:426]
py39: 305 E internal error [tox/session/cmd/run/single.py:60]
Traceback (most recent call last):
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/session/cmd/run/single.py", line 47, in _evaluate
    tox_env.setup()
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 249, in setup
    self._setup_env()
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox_uv/_run_lock.py", line 59, in _setup_env
    outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=False)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 388, in execute
    with self.execute_async(cmd, stdin, show, cwd, run_id, executor) as status:
  File "/home/[...]/.local/share/uv/python/cpython-3.12.5-linux-x86_64-gnu/lib/python3.12/contextlib.py", line 144, in __exit__
    next(self.gen)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 442, in execute_async
    self._log_execute(request, execute_status)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 448, in _log_execute
    self._write_execute_log(self.name, self.env_log_dir / f"{self._log_id}-{request.run_id}.log", request, status)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 452, in _write_execute_log
    with log_file.open("wt", encoding="utf-8") as file:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/[...]/.local/share/uv/python/cpython-3.12.5-linux-x86_64-gnu/lib/python3.12/pathlib.py", line 1013, in open
    return io.open(self, mode, buffering, encoding, errors, newline)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/home/[...]/snippets/get_configuration/.tox/py39/log/2-uv-sync.log'
py39: FAIL ✖ in 0.05 seconds
py310: 307 W remove tox env folder /home/[...]/snippets/get_configuration/.tox/py310 [tox/tox_env/api.py:324]
py310: 318 W venv> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p 3.10 --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py310 [tox/tox_env/api.py:426]
DEBUG uv 0.4.14
DEBUG Found project root: `/home/[...]/snippets/get_configuration`
DEBUG No workspace root found, using project root
DEBUG Searching for Python 3.10 in managed installations
DEBUG Searching for managed installations at `/home/[...]/.local/share/uv/python`
DEBUG Found managed installation `cpython-3.10.14-linux-x86_64-gnu`
DEBUG Found `cpython-3.10.14-linux-x86_64-gnu` at `/home/[...]/.local/share/uv/python/cpython-3.10.14-linux-x86_64-gnu/bin/python3` (managed installations)
Using Python 3.10.14
Creating virtual environment at: .tox/py310
DEBUG Allowing existing directory
py310: 338 I exit 0 (0.02 seconds) /home/[...]/snippets/get_configuration> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p 3.10 --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py310 pid=1729591 [tox/execute/api.py:286]
py310: 340 W uv-sync> uv sync --frozen --no-dev [tox/tox_env/api.py:426]
py310: 366 E internal error [tox/session/cmd/run/single.py:60]
Traceback (most recent call last):
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/session/cmd/run/single.py", line 47, in _evaluate
    tox_env.setup()
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 249, in setup
    self._setup_env()
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox_uv/_run_lock.py", line 59, in _setup_env
    outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=False)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 388, in execute
    with self.execute_async(cmd, stdin, show, cwd, run_id, executor) as status:
  File "/home/[...]/.local/share/uv/python/cpython-3.12.5-linux-x86_64-gnu/lib/python3.12/contextlib.py", line 144, in __exit__
    next(self.gen)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 442, in execute_async
    self._log_execute(request, execute_status)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 448, in _log_execute
    self._write_execute_log(self.name, self.env_log_dir / f"{self._log_id}-{request.run_id}.log", request, status)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 452, in _write_execute_log
    with log_file.open("wt", encoding="utf-8") as file:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/[...]/.local/share/uv/python/cpython-3.12.5-linux-x86_64-gnu/lib/python3.12/pathlib.py", line 1013, in open
    return io.open(self, mode, buffering, encoding, errors, newline)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/home/[...]/snippets/get_configuration/.tox/py310/log/2-uv-sync.log'
py311: 368 W remove tox env folder /home/[...]/snippets/get_configuration/.tox/py311 [tox/tox_env/api.py:324]
py310: FAIL ✖ in 0.06 seconds
py311: 391 W venv> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p 3.11 --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py311 [tox/tox_env/api.py:426]
DEBUG uv 0.4.14
DEBUG Found project root: `/home/[...]/snippets/get_configuration`
DEBUG No workspace root found, using project root
DEBUG Searching for Python 3.11 in managed installations
DEBUG Searching for managed installations at `/home/[...]/.local/share/uv/python`
DEBUG Found managed installation `cpython-3.11.9-linux-x86_64-gnu`
DEBUG Found `cpython-3.11.9-linux-x86_64-gnu` at `/home/[...]/.local/share/uv/python/cpython-3.11.9-linux-x86_64-gnu/bin/python3` (managed installations)
Using Python 3.11.9
Creating virtual environment at: .tox/py311
DEBUG Allowing existing directory
py311: 411 I exit 0 (0.02 seconds) /home/[...]/snippets/get_configuration> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p 3.11 --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py311 pid=1729626 [tox/execute/api.py:286]
py311: 413 W uv-sync> uv sync --frozen --no-dev [tox/tox_env/api.py:426]
py311: 430 I exit 0 (0.02 seconds) /home/[...]/snippets/get_configuration> uv sync --frozen --no-dev pid=1729645 [tox/execute/api.py:286]
py311: 431 W commands[0]> make tests [tox/tox_env/api.py:426]
uv run pytest --cov=env tests.py
Installed 7 packages in 12ms
================================================ test session starts ================================================
platform linux -- Python 3.11.9, pytest-8.3.3, pluggy-1.5.0
cachedir: .tox/py311/.pytest_cache
rootdir: /home/[...]/snippets/get_configuration
configfile: pyproject.toml
plugins: cov-5.0.0, mock-3.14.0
collected 6 items                                                                                                   

tests.py ......                                                                                               [100%]

---------- coverage: platform linux, python 3.11.9-final-0 -----------
Name                       Stmts   Miss  Cover
----------------------------------------------
src/env/__init__.py            2      0   100%
src/env/configuration.py      24      0   100%
----------------------------------------------
TOTAL                         26      0   100%


================================================= 6 passed in 0.07s =================================================
py311: 1349 I exit 0 (0.92 seconds) /home/[...]/snippets/get_configuration> make tests pid=1729659 [tox/execute/api.py:286]
py311: OK ✔ in 0.98 seconds
py312: 1349 W remove tox env folder /home/[...]/snippets/get_configuration/.tox/py312 [tox/tox_env/api.py:324]
py312: 1357 W venv> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p /home/[...]/.local/share/uv/tools/tox/bin/python --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py312 [tox/tox_env/api.py:426]
DEBUG uv 0.4.14
DEBUG Found project root: `/home/[...]/snippets/get_configuration`
DEBUG No workspace root found, using project root
DEBUG Checking for Python interpreter at path `/home/[...]/.local/share/uv/tools/tox/bin/python`
Using Python 3.12.5 interpreter at: /home/[...]/.local/share/uv/tools/tox/bin/python
Creating virtual environment at: .tox/py312
DEBUG Allowing existing directory
py312: 1380 I exit 0 (0.02 seconds) /home/[...]/snippets/get_configuration> /home/[...]/.local/share/uv/tools/tox/bin/uv venv -p /home/[...]/.local/share/uv/tools/tox/bin/python --allow-existing -v --python-preference only-managed /home/[...]/snippets/get_configuration/.tox/py312 pid=1729739 [tox/execute/api.py:286]
py312: 1382 W uv-sync> uv sync --frozen --no-dev [tox/tox_env/api.py:426]
py312: 1407 E internal error [tox/session/cmd/run/single.py:60]
Traceback (most recent call last):
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/session/cmd/run/single.py", line 47, in _evaluate
    tox_env.setup()
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 249, in setup
    self._setup_env()
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox_uv/_run_lock.py", line 59, in _setup_env
    outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=False)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 388, in execute
    with self.execute_async(cmd, stdin, show, cwd, run_id, executor) as status:
  File "/home/[...]/.local/share/uv/python/cpython-3.12.5-linux-x86_64-gnu/lib/python3.12/contextlib.py", line 144, in __exit__
    next(self.gen)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 442, in execute_async
    self._log_execute(request, execute_status)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 448, in _log_execute
    self._write_execute_log(self.name, self.env_log_dir / f"{self._log_id}-{request.run_id}.log", request, status)
  File "/home/[...]/.local/share/uv/tools/tox/lib/python3.12/site-packages/tox/tox_env/api.py", line 452, in _write_execute_log
    with log_file.open("wt", encoding="utf-8") as file:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/[...]/.local/share/uv/python/cpython-3.12.5-linux-x86_64-gnu/lib/python3.12/pathlib.py", line 1013, in open
    return io.open(self, mode, buffering, encoding, errors, newline)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/home/[...]/snippets/get_configuration/.tox/py312/log/2-uv-sync.log'
  py38: FAIL code 2 (0.05 seconds)
  py39: FAIL code 2 (0.05 seconds)
  py310: FAIL code 2 (0.06 seconds)
  py311: OK (0.98=setup[0.06]+cmd[0.92] seconds)
  py312: FAIL code 2 (0.06 seconds)
  evaluation failed :( (1.27 seconds)

Any Python version pinned with uv will pass without any issues, and sometimes, the two most recent pinned Python version will also pass.

Trimmed output of tox showing only the report, after the Python version 3.8 then 3.9 were pinned.
  py38: OK (1.10=setup[0.04]+cmd[1.06] seconds)
  py39: OK (0.97=setup[0.03]+cmd[0.94] seconds)
  py310: FAIL code 2 (0.04 seconds)
  py311: FAIL code 2 (0.14 seconds)
  py312: FAIL code 2 (0.06 seconds)
  evaluation failed :( (2.39 seconds)

Related code

You can find the whole related code in the Gitlab snippet 1941025, but here are the tox.ini, pyproject.toml and the Makefile:

tox.ini
[tox]
env_list = py{38,39,310,311,312}

[testenv]
description = run unit tests
runner = uv-venv-lock-runner

allowlist_externals = make
commands =
    make tests
pyproject.toml

[project]
name = "env"
version = "3.1.0"
description = """
A helper function to retrieve configuration values from environment variables or Docker secrets. 
The function supports reading secrets from files (if *_FILE is set) and can return default values 
when no environment variable is found. Raises appropriate exceptions when required configuration 
is missing or when errors occur during file reading.
"""
readme = "README.md"
requires-python = ">=3.8"

[tool.uv]
dev-dependencies = [
    "pytest>=8.3.3",
    "pytest-mock>=3.14.0",
    "pytest-cov>=5.0.0",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Makefile
sync:
	uv sync

tests:
	uv run pytest --cov=env tests.py

flowgunso avatar Sep 20 '24 21:09 flowgunso

Do you have a docker image where you can replicate this? It doesn't replicate for me with the information provided.

gaborbernat avatar Sep 20 '24 23:09 gaborbernat

I've managed to reproduce with the following Dockerfile, with same installation steps:

FROM python:3-bookworm
# FROM python@sha256:096c49cf57695962d6d5e2998d0d23640b4234dfffcd8472d48adceb518582de

COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

RUN apt update && \
    apt install -y pipx && \
    pipx ensurepath && \
    pipx install tox

WORKDIR /opt/env
COPY . .
RUN uv sync && \
    uv tool install tox --with tox-uv --force

ENV PATH="$PATH:/root/.local/bin"

CMD [ "tox" ]

I suppose installing tox with pipx then with uv, but still using the tox from pipx is the actual problem ?

I've specified the Docker image digest so you can reproduce exactly with the same image.

Here the output of docker run --rm env, considering it's built with docker build -t env .:
py38: venv> /root/.local/share/uv/tools/tox/bin/uv venv -p 3.8 --allow-existing /opt/env/.tox/py38
py38: uv-sync> uv sync --frozen --no-dev
py38: internal error
Traceback (most recent call last):
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/session/cmd/run/single.py", line 47, in _evaluate
    tox_env.setup()
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 249, in setup
    self._setup_env()
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox_uv/_run_lock.py", line 59, in _setup_env
    outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=False)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 390, in execute
    pass  # pragma: no cover
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/contextlib.py", line 126, in __exit__
    next(self.gen)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 442, in execute_async
    self._log_execute(request, execute_status)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 448, in _log_execute
    self._write_execute_log(self.name, self.env_log_dir / f"{self._log_id}-{request.run_id}.log", request, status)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 452, in _write_execute_log
    with log_file.open("wt", encoding="utf-8") as file:
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/pathlib.py", line 1252, in open
    return io.open(self, mode, buffering, encoding, errors, newline,
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/pathlib.py", line 1120, in _opener
    return self._accessor.open(self, flags, mode)
FileNotFoundError: [Errno 2] No such file or directory: '/opt/env/.tox/py38/log/2-uv-sync.log'
py38: FAIL ✖ in 9.62 seconds
py39: uv-sync> uv sync --frozen --no-dev
py39: commands[0]> make tests
uv run pytest --cov=env tests.py
Installed 9 packages in 181ms
=============================================== test session starts ===============================================
platform linux -- Python 3.9.20, pytest-8.3.3, pluggy-1.5.0
cachedir: .tox/py39/.pytest_cache
rootdir: /opt/env
configfile: pyproject.toml
plugins: cov-5.0.0, mock-3.14.0
collected 6 items                                                                                                 

tests.py ......                                                                                             [100%]

---------- coverage: platform linux, python 3.9.20-final-0 -----------
Name                       Stmts   Miss  Cover
----------------------------------------------
src/env/__init__.py            2      0   100%
src/env/configuration.py      24      0   100%
----------------------------------------------
TOTAL                         26      0   100%


================================================ 6 passed in 0.11s ================================================
py39: OK ✔ in 1.33 seconds
py310: venv> /root/.local/share/uv/tools/tox/bin/uv venv -p 3.10 --allow-existing /opt/env/.tox/py310
py310: uv-sync> uv sync --frozen --no-dev
py310: internal error
Traceback (most recent call last):
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/session/cmd/run/single.py", line 47, in _evaluate
    tox_env.setup()
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 249, in setup
    self._setup_env()
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox_uv/_run_lock.py", line 59, in _setup_env
    outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=False)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 390, in execute
    pass  # pragma: no cover
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/contextlib.py", line 126, in __exit__
    next(self.gen)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 442, in execute_async
    self._log_execute(request, execute_status)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 448, in _log_execute
    self._write_execute_log(self.name, self.env_log_dir / f"{self._log_id}-{request.run_id}.log", request, status)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 452, in _write_execute_log
    with log_file.open("wt", encoding="utf-8") as file:
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/pathlib.py", line 1252, in open
    return io.open(self, mode, buffering, encoding, errors, newline,
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/pathlib.py", line 1120, in _opener
    return self._accessor.open(self, flags, mode)
FileNotFoundError: [Errno 2] No such file or directory: '/opt/env/.tox/py310/log/2-uv-sync.log'
py310: FAIL ✖ in 8.46 seconds
py311: venv> /root/.local/share/uv/tools/tox/bin/uv venv -p 3.11 --allow-existing /opt/env/.tox/py311
py311: uv-sync> uv sync --frozen --no-dev
py311: internal error
Traceback (most recent call last):
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/session/cmd/run/single.py", line 47, in _evaluate
    tox_env.setup()
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 249, in setup
    self._setup_env()
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox_uv/_run_lock.py", line 59, in _setup_env
    outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=False)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 390, in execute
    pass  # pragma: no cover
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/contextlib.py", line 126, in __exit__
    next(self.gen)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 442, in execute_async
    self._log_execute(request, execute_status)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 448, in _log_execute
    self._write_execute_log(self.name, self.env_log_dir / f"{self._log_id}-{request.run_id}.log", request, status)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 452, in _write_execute_log
    with log_file.open("wt", encoding="utf-8") as file:
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/pathlib.py", line 1252, in open
    return io.open(self, mode, buffering, encoding, errors, newline,
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/pathlib.py", line 1120, in _opener
    return self._accessor.open(self, flags, mode)
FileNotFoundError: [Errno 2] No such file or directory: '/opt/env/.tox/py311/log/2-uv-sync.log'
py311: FAIL ✖ in 0.18 seconds
py312: venv> /root/.local/share/uv/tools/tox/bin/uv venv -p 3.12 --allow-existing /opt/env/.tox/py312
py312: uv-sync> uv sync --frozen --no-dev
py312: internal error
Traceback (most recent call last):
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/session/cmd/run/single.py", line 47, in _evaluate
    tox_env.setup()
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 249, in setup
    self._setup_env()
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox_uv/_run_lock.py", line 59, in _setup_env
    outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=False)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 390, in execute
    pass  # pragma: no cover
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/contextlib.py", line 126, in __exit__
    next(self.gen)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 442, in execute_async
    self._log_execute(request, execute_status)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 448, in _log_execute
    self._write_execute_log(self.name, self.env_log_dir / f"{self._log_id}-{request.run_id}.log", request, status)
  File "/root/.local/share/uv/tools/tox/lib/python3.9/site-packages/tox/tox_env/api.py", line 452, in _write_execute_log
    with log_file.open("wt", encoding="utf-8") as file:
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/pathlib.py", line 1252, in open
    return io.open(self, mode, buffering, encoding, errors, newline,
  File "/root/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/pathlib.py", line 1120, in _opener
    return self._accessor.open(self, flags, mode)
FileNotFoundError: [Errno 2] No such file or directory: '/opt/env/.tox/py312/log/2-uv-sync.log'
  py38: FAIL code 2 (9.62 seconds)
  py39: OK (1.33=setup[0.05]+cmd[1.28] seconds)
  py310: FAIL code 2 (8.46 seconds)
  py311: FAIL code 2 (0.17 seconds)
  py312: FAIL code 2 (0.28 seconds)
  evaluation failed :( (20.15 seconds)
And here's the output of docker inspect python:3-bookworm
[
    {
        "Id": "sha256:ea2ebd905ab246ece277be25520ca0cfe82758b3d2b369e2fd69b374c1d6c7fa",
        "RepoTags": [
            "python:3-bookworm"
        ],
        "RepoDigests": [
            "python@sha256:096c49cf57695962d6d5e2998d0d23640b4234dfffcd8472d48adceb518582de"
        ],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2024-09-09T17:16:05Z",
        "DockerVersion": "",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "LANG=C.UTF-8",
                "GPG_KEY=7169605F62C751356D054A26A821E680E5FA6305",
                "PYTHON_VERSION=3.12.6"
            ],
            "Cmd": [
                "python3"
            ],
            "ArgsEscaped": true,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 1013190869,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/051b0a9d04d61de48810f9c937b7e8906a033ba351c17728341731202c7ae0fd/diff:/var/lib/docker/overlay2/46b6a9fc05d056deb798b7146af19c201eba7dcd2b1129164d8215505c958d5c/diff:/var/lib/docker/overlay2/de3be5f9fed6b0f7f2604c915a53a0fbb27cab000052c902a9eb139b9aec18c6/diff:/var/lib/docker/overlay2/b9bb0329cb3b9e3bec568453a93df05047637784f6e3b44ccf1760c02c812400/diff:/var/lib/docker/overlay2/64ef49fe5ad37bb84f39c69c95d887ae8589738d685d8e303bf7555933a80dbb/diff:/var/lib/docker/overlay2/573e85a97762b77d08cf33b18c20021f68a8da341ce9311dcfb658fe02c76bf5/diff",
                "MergedDir": "/var/lib/docker/overlay2/350d94ad279f878cd1da8167c2462f30d37ff0c47e42ed1db970494618deb55a/merged",
                "UpperDir": "/var/lib/docker/overlay2/350d94ad279f878cd1da8167c2462f30d37ff0c47e42ed1db970494618deb55a/diff",
                "WorkDir": "/var/lib/docker/overlay2/350d94ad279f878cd1da8167c2462f30d37ff0c47e42ed1db970494618deb55a/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:6abe10f2f60150ae9768e117986e4f8af5546137221553228eb5d21066f596b4",
                "sha256:25879f85bbb0206e6870e7073a576acd49be6e8c3a15ba4b443166f92b041327",
                "sha256:045d8b74bf0ddedb671bd1ba1ab114e3a3e7b86dc5c7e18f9b7edda74193174d",
                "sha256:3a8081ce85fac02e6d87b062aff5ace4027e2409de4a65a1844308b6510068cf",
                "sha256:4bad8619a2548e688aa5c0d066ef602a13ddd73f25f80c97a5e9e1722fdb0b44",
                "sha256:6e12f34fe52a9891444cf01c5d0b0741f3f27b9e6636d1f22530955dd0ce0b66",
                "sha256:d78767df0001818e81271ed8884312feb3af5b0cf392b642930c2c9a9bca7a3a"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

The Python version is 3.12 in the Docker image, but it pass with tox with Python 3.9, somehow.

flowgunso avatar Sep 21 '24 07:09 flowgunso

Why are you installing the tool twice?

gaborbernat avatar Sep 21 '24 16:09 gaborbernat

In this case, inside the Docker image, I do not see any project files or lock files you are working on. Can you post a reproducible that contains the project too, that you are testing with? Thank you.

gaborbernat avatar Sep 21 '24 16:09 gaborbernat

Sure, I've pushed the image to Docker Hub, you can get it from the image flowgunso/env, it calls tox directly. You can find the full code in the Gitlab snippet 1941025, though.

I wasn't sure how to link tox and tox-uv from uv with the system itself. That's why I've installed tox with pipx. Reading uv's documentation, I've learned about uv tool update-shell that makes sure ~/.local/bin is in my PATH.

I've updated the Dockerfile accordingly:

FROM python:3-bookworm

COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

WORKDIR /opt/env
COPY . .
RUN uv sync && \
    uv tool install tox --with tox-uv

ENV PATH="$PATH:/root/.local/bin"

CMD [ "tox" ]

Thanks for you help.

flowgunso avatar Sep 22 '24 08:09 flowgunso

Is there any way I can help you ?

flowgunso avatar Sep 24 '24 15:09 flowgunso

I'm also getting this same error on a Windows 10 environment.

butterlyn avatar Sep 30 '24 19:09 butterlyn

Are there workarounds for this issue perchance? @flowgunso

butterlyn avatar Oct 09 '24 07:10 butterlyn

Is there any way I can help you ?

At this point only by putting in a pull request to fix the issue.

gaborbernat avatar Oct 09 '24 07:10 gaborbernat

I'm fine with making a PR with the fix.

Knowing the codebase, do you have any ideas what the origin of the issue might be, so I can be on the right track, please ?

flowgunso avatar Oct 10 '24 13:10 flowgunso

Nothing jumps out to the top of my mind.

gaborbernat avatar Oct 10 '24 13:10 gaborbernat

Tox does not manage to run the tests on the defined Python version list, but it does manage to run the tests on the Python version pinned with uv

What does pinning with uv mean? I can't seem to replicate this:

~/git/github/tox-uv/magic/1941025 on  master [!]
❯ tox r -e 3.12
3.12: uv-sync> uv sync --frozen --no-dev
Uninstalled 7 packages in 51ms
 - coverage==7.6.1
 - iniconfig==2.0.0
 - packaging==24.1
 - pluggy==1.5.0
 - pytest==8.3.3
 - pytest-cov==5.0.0
 - pytest-mock==3.14.0
3.12: commands[0]> make tests
uv run pytest --cov=env tests.py
Installed 7 packages in 7ms
=========================================================================== test session starts ============================================================================
platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0
cachedir: .tox/3.12/.pytest_cache
rootdir: /Users/x/git/github/tox-uv/magic/1941025
configfile: pyproject.toml
plugins: cov-5.0.0, mock-3.14.0
collected 6 items

tests.py ......                                                                                                                                                      [100%]

---------- coverage: platform darwin, python 3.12.6-final-0 ----------
Name                       Stmts   Miss  Cover
----------------------------------------------
src/env/__init__.py            2      0   100%
src/env/configuration.py      24      0   100%
----------------------------------------------
TOTAL                         26      0   100%


============================================================================ 6 passed in 0.08s =============================================================================
  3.12: OK (1.22=setup[0.09]+cmd[1.13] seconds)
  congratulations :) (1.28 seconds)

gaborbernat avatar Oct 11 '24 16:10 gaborbernat

It allows to pin a specific Python version to a project. For example, uv python pin 3.12 or uv python pin 3.8 to use Python 3.12 or 3.8 in the project. See uv python pin.

flowgunso avatar Oct 11 '24 20:10 flowgunso

I do not use the pinning feature at all and it still works for me. See my output from above so I don't know what to say to you.

gaborbernat avatar Oct 11 '24 22:10 gaborbernat

@flowgunso I ran into this issue also when using uv in the make target. The issue here stems from using the global uv app (via make) inside the tox context.

Here we assume uv run pytest --cov=env tests.py will be auto-loaded with the desired version of Python used by tox, this is not the case as uv is configured outside of the tox runner with your development version of python, not the tox version.

I do not think there is a bug here, instead an unexpected (but valid) behaviour to what a developer thinks will/should happen. In this case, tox is behaving as expected. It is your make target you will need to refactor.

Here is how I got around it:

pyproject.toml

[tool.tox]
envlist = [
    "3.8",
    "3.9",
    "3.10",
    "3.11",
    "3.12",
]
isolated_build = true

[tool.tox.env_run_base]
description = "Run the tests for {base_python}"
runner = "uv-venv-runner"
extras = [
    "test",
]
setenv = { TOX_BIN_DIR = "{envbindir}", TOX_PYTHON_BIN = "{envpython}" }

allowlist_externals = [
    "make",
]

commands = [
    ["make", "test"],
]

Makefile

VENV_DIR_NAME = ./.venv    # Default `uv` venv directory path
SCRIPTS_DIR = $(or $(TOX_BIN_DIR), ${VENV_DIR_NAME}/bin)    # Path to `venv/bin` dir
PYTHON_VENV ?= $(or $(TOX_PYTHON_BIN), ${SCRIPTS_DIR}/python)    # Path to python venv executable
TESTS_DIR = tests    # Location of my test suite

test:
	@echo "🧪 *** Running tests..."; \
	${PYTHON_VENV} -m pytest -vv -s ${TESTS_DIR}

Note: Comments in Makefile above may need to be removed, I added these for clarity but are not in my running config.

In the above, I dynamically set SCRIPTS_DIR and PYTHON_VENV based on if the envvars TOX_BIN_DIR and TOX_PYTHON_BIN are set by tox or if they do not exist, set them to a default value which means running in development mode. As the make target is called for each version of python in tox, the envvars TOX_BIN_DIR and TOX_PYTHON_BIN are set each time to the current version being used by tox. This allows you to simply call pytest referencing the current active python version. This removes the global reference to uv in make and makes the makefile more generalisable for both dev and tox usage.

DavidWalshe93 avatar Oct 14 '24 13:10 DavidWalshe93

@gaborbernat

I do not use the pinning feature at all and it still works for me. See my output from above so I don't know what to say to you.

After doing a system update, I cannot reproduce the error either, all tests pass on the Python versions:

================================================ 4 passed in 0.09s =================================================
  py38: OK (0.97=setup[0.11]+cmd[0.86] seconds)
  py39: OK (1.04=setup[0.12]+cmd[0.92] seconds)
  py310: OK (1.01=setup[0.13]+cmd[0.88] seconds)
  py311: OK (0.99=setup[0.10]+cmd[0.89] seconds)
  py312: OK (1.30=setup[0.10]+cmd[1.20] seconds)
  congratulations :) (5.38 seconds)

uv did not update, so I sadly cannot say what solved the issue. I think that issue can be closed.

flowgunso avatar Oct 15 '24 07:10 flowgunso

@DavidWalshe93 thanks for the in-depth description. I've found another solution, after the issue solved itself with a system update.

Instead of using uv in the make target, like you pointed out, I'm using uv in the tox commands:

[tox]
env_list = py{38,39,310,311,312}

[testenv]
description = run unit tests
runner = uv-venv-lock-runner
allowlist_externals = make
commands =
    uv run pytest --cov=env_secrets tests/

And then, I'm using tox in the make target directly.

test:
	tox

That works as well.

flowgunso avatar Oct 15 '24 07:10 flowgunso