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

uv_resolution lowest-direct can fail to use the correct version if dependency groups are used

Open effigies opened this issue 3 months ago • 1 comments

Issue

I have a package that depends on packaging, and I want to use uv_resolution: lowest-direct to ensure that I am actually compatible with the claimed minimum versions.

I use dependency-groups to declare my test dependencies, and pytest also depends on packaging. Because tox installs the dependency group before installing the package, any transitive dependencies of the dependency group are always the latest compatible version.

$ tox -vv -r -e py310-min 2>&1 | grep packaging
    73:	DEBUG Adding transitive dependency for pytest==8.3.0: packaging*
    80:	DEBUG Found fresh response for: https://pypi.org/simple/packaging/
    82:	DEBUG Searching for a compatible version of packaging (*)
    83:	DEBUG Selecting: packaging==25.0 [compatible] (packaging-25.0-py3-none-any.whl)
    86:	DEBUG Found fresh response for: https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl.metadata
   121:	DEBUG Tried 7 versions: exceptiongroup 1, iniconfig 1, packaging 1, pluggy 1, pytest 1, tomli 1, typing-extensions 1
   126:	DEBUG Registry requirement already cached: packaging==25.0
   134:	 + packaging==25.0
   229:	py310-min: 1988 W install_package_deps> /var/home/chris/.local/share/uv/tools/tox/bin/uv pip install --resolution lowest-direct 'packaging>=20.0' -v [tox/tox_env/api.py:463]
   235:	DEBUG Requirement satisfied: packaging>=20.0
   238:	py310-min: 2008 I exit 0 (0.02 seconds) /var/home/chris/Projects/bugs/tox-uv-resolution> /var/home/chris/.local/share/uv/tools/tox/bin/uv pip install --resolution lowest-direct 'packaging>=20.0' -v pid=2435358 [tox/execute/api.py:294]
   261:	DEBUG Unnecessary package: packaging==25.0

Environment

Provide at least:

  • OS: Fedora 42
Output of pip list of the host Python, where tox is installed
Package       Version
------------- -------
cachetools    6.2.0
chardet       5.2.0
colorama      0.4.6
distlib       0.4.0
filelock      3.19.1
packaging     25.0
platformdirs  4.4.0
pluggy        1.6.0
pyproject-api 1.9.1
tox           4.30.2
tox-uv        1.28.0
uv            0.8.15
virtualenv    20.34.0

Output of running tox

Results are fine. It's the resolution that's the problem.

Minimal example

pyproject.toml

[project]
name = "tox-uv-resolution"
version = "0.1.0"
description = "Reproduction"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
  "packaging>=20.0",
]

[dependency-groups]
test = [
    "pytest>=8.3",
]

tox.ini

[tox]
requires =
  tox>=4
  tox-uv
envlist =
  py310-min

[testenv]
dependency_groups =
    test
uv_resolution =
    min: lowest-direct

commands =
    pytest

To demonstrate that uv sync gets the correct result while tox-uv does not:

$ uv sync --group=test --resolution=lowest-direct
$ tox -e py310-min
$ ls -d {.venv,.tox/py310-min}/lib/python3*/site-packages/packaging*.dist-info
.venv/lib/python3.13/site-packages/packaging-20.0.dist-info
.tox/py310-min/lib/python3.10/site-packages/packaging-25.0.dist-info

effigies avatar Sep 07 '25 18:09 effigies

I spent a bit trying to understand the control flow of tox to see if I could make a patch, but got bogged down. Here's the sequence of installations:

$ tox -r -e py310-min
py310-min: remove tox env folder /var/home/user/Projects/bugs/tox-uv-resolution/.tox/py310-min
.pkg: remove tox env folder /var/home/user/Projects/bugs/tox-uv-resolution/.tox/.pkg
py310-min: venv> /var/home/user/.local/share/uv/tools/tox/bin/uv venv -p cpython3.10 --allow-existing --python-preference system /var/home/user/Projects/bugs/tox-uv-resolution/.tox/py310-min
py310-min: install_dependency-groups> /var/home/user/.local/share/uv/tools/tox/bin/uv pip install --resolution lowest-direct 'pytest>=8.3'
.pkg: venv> /var/home/user/.local/share/uv/tools/tox/bin/uv venv -p /var/home/user/.local/share/uv/tools/tox/bin/python3 --allow-existing --python-preference system /var/home/user/Projects/bugs/tox-uv-resolution/.tox/.pkg
.pkg: install_requires> /var/home/user/.local/share/uv/tools/tox/bin/uv pip install 'setuptools>=40.8.0'
.pkg: _optional_hooks> python /var/home/user/.local/share/uv/tools/tox/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: get_requires_for_build_sdist> python /var/home/user/.local/share/uv/tools/tox/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: build_sdist> python /var/home/user/.local/share/uv/tools/tox/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
py310-min: install_package_deps> /var/home/user/.local/share/uv/tools/tox/bin/uv pip install --resolution lowest-direct 'packaging>=20.0'
py310-min: install_package> /var/home/user/.local/share/uv/tools/tox/bin/uv pip install --resolution lowest-direct --reinstall --no-deps tox-uv-resolution@/var/home/user/Projects/bugs/tox-uv-resolution/.tox/.tmp/package/7/tox_uv_resolution-0.1.0.tar.gz
[...]

I think we want to identify when dependency-groups will be installed alongside the package, and combine install_dependency-groups with install_package_deps in that case. I just can't figure out where install_package_deps is getting called from.

effigies avatar Sep 07 '25 18:09 effigies