Skip to content

lowest-direct resolution error with constraints #8819

Closed
@azmeuk

Description

@azmeuk

The following dockerfile is the minimum reproducible example of a situation I met in a real project CI.

The Dockerfile runs with python 3.10 but there is a setuptools dependency for python 3.12+ in pyproject.toml.
The other dependency in pyproject.toml is pycountry, on its 22.1.10 version, and it has a loose dependency to setuptools.

In this situation I would expect setuptools to not be a direct dependency. However uv --resolution=lowest-direct appears to resolve at the minimum setuptools available, that is 0.7.2. Of course, this is an old incompatible version, and the installation fails.

Removing the python_version>='3.12' constraint on the setuptools dependency appears to solve the issue, so I suppose this is a cause of the bug.

pyproject.toml

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "foobar"
version = "0.0.1"
requires-python = ">=3.10"

dependencies = [
    "pycountry >= 22.1.10",
    "setuptools >= 50.0.0; python_version>='3.12'"
]

Dockerfile

FROM ghcr.io/astral-sh/uv:0.4-python3.10-bookworm-slim
WORKDIR /foobar
COPY foobar pyproject.toml /foobar/
RUN uv sync --resolution=lowest-direct
docker build .           
[+] Building 11.3s (8/8) FINISHED                                                                                           docker:default
 => [internal] load build definition from Dockerfile                                                                                  0.1s
 => => transferring dockerfile: 185B                                                                                                  0.0s
 => [internal] load metadata for ghcr.io/astral-sh/uv:0.4-python3.10-bookworm-slim                                                    0.0s
 => [internal] load .dockerignore                                                                                                     0.1s
 => => transferring context: 2B                                                                                                       0.0s
 => [1/4] FROM ghcr.io/astral-sh/uv:0.4-python3.10-bookworm-slim                                                                      0.0s
 => [internal] load build context                                                                                                     0.1s
 => => transferring context: 326B                                                                                                     0.0s
 => CACHED [2/4] WORKDIR /foobar                                                                                                      0.0s
 => [3/4] COPY foobar pyproject.toml /foobar/                                                                                         0.3s
 => ERROR [4/4] RUN uv sync --resolution=lowest-direct                                                                               10.5s
------                                                                                                                                     
 > [4/4] RUN uv sync --resolution=lowest-direct:                                                                                           
1.423 Using CPython 3.10.15 interpreter at: /usr/local/bin/python                                                                          
1.423 Creating virtual environment at: .venv                                                                                               
1.425 warning: No `requires-python` value found in the workspace. Defaulting to `>=3.10`.                                                  
8.149 Resolved 4 packages in 6.72s                                                                                                         
9.249 error: Failed to prepare distributions
9.249   Caused by: Failed to download and build `setuptools==0.7.2`
9.249   Caused by: Build backend failed to determine requirements with `build_wheel()` (exit status: 1)
9.249 
9.249 [stdout]
9.249 --- build/src/tests/api_tests.txt	(original)
9.249 +++ build/src/tests/api_tests.txt	(refactored)
9.249 @@ -39,7 +39,7 @@
9.249      >>> dist.py_version == sys.version[:3]
9.249      True
9.249  
9.249 -    >>> print dist.platform
9.249 +    >>> print(dist.platform)
9.249      None
9.249  
9.249  Including various computed attributes::
9.249 @@ -199,7 +199,7 @@
9.249  You can ask a WorkingSet to ``find()`` a distribution matching a requirement::
9.249  
9.249      >>> from pkg_resources import Requirement
9.249 -    >>> print ws.find(Requirement.parse("Foo==1.0"))    # no match, return None
9.249 +    >>> print(ws.find(Requirement.parse("Foo==1.0")))    # no match, return None
9.249      None
9.249  
9.249      >>> ws.find(Requirement.parse("Bar==0.9"))  # match, return distribution
9.249 @@ -212,7 +212,7 @@
9.249      ...     ws.find(Requirement.parse("Bar==1.0"))
9.249      ... except pkg_resources.VersionConflict:
9.249      ...     exc = sys.exc_info()[1]
9.249 -    ...     print(str(exc))
9.249 +    ...     print((str(exc)))
9.249      ... else:
9.249      ...     raise AssertionError("VersionConflict was not raised")
9.249      (Bar 0.9 (http://example.com/something), Requirement.parse('Bar==1.0'))
9.249 @@ -222,7 +222,7 @@
9.249  once for each existing distribution in the working set, and then is called
9.249  again for new distributions added thereafter::
9.249  
9.249 -    >>> def added(dist): print "Added", dist
9.249 +    >>> def added(dist): print("Added", dist)
9.249      >>> ws.subscribe(added)
9.249      Added Bar 0.9
9.249      >>> foo12 = Distribution(project_name="Foo", version="1.2", location="f12")
9.249 @@ -338,52 +338,52 @@
9.249      >>> from pkg_resources import invalid_marker as im, evaluate_marker as em
9.249      >>> import os
9.249  
9.249 -    >>> print(im("sys_platform"))
9.249 +    >>> print((im("sys_platform")))
9.249      Comparison or logical expression expected
9.249  
9.249 -    >>> print(im("sys_platform=="))  # doctest: +ELLIPSIS
9.249 +    >>> print((im("sys_platform==")))  # doctest: +ELLIPSIS
9.249      unexpected EOF while parsing (...line 1)
9.249  
9.249 -    >>> print(im("sys_platform=='win32'"))
9.249 -    False
9.249 -
9.249 -    >>> print(im("sys=='x'"))
9.249 +    >>> print((im("sys_platform=='win32'")))
9.249 +    False
9.249 +
9.249 +    >>> print((im("sys=='x'")))
9.249      Unknown name 'sys'
9.249  
9.249 -    >>> print(im("(extra)"))
9.249 +    >>> print((im("(extra)")))
9.249      Comparison or logical expression expected
9.249  
9.249 -    >>> print(im("(extra"))  # doctest: +ELLIPSIS
9.249 +    >>> print((im("(extra")))  # doctest: +ELLIPSIS
9.249      unexpected EOF while parsing (...line 1)
9.249  
9.249 -    >>> print(im("os.open('foo')=='y'"))
9.249 +    >>> print((im("os.open('foo')=='y'")))
9.249      Language feature not supported in environment markers
9.249  
9.249 -    >>> print(im("'x'=='y' and os.open('foo')=='y'"))   # no short-circuit!
9.249 +    >>> print((im("'x'=='y' and os.open('foo')=='y'")))   # no short-circuit!
9.249      Language feature not supported in environment markers
9.249  
9.249 -    >>> print(im("'x'=='x' or os.open('foo')=='y'"))   # no short-circuit!
9.249 +    >>> print((im("'x'=='x' or os.open('foo')=='y'")))   # no short-circuit!
9.249      Language feature not supported in environment markers
9.249  
9.249 -    >>> print(im("'x' < 'y'"))
9.249 +    >>> print((im("'x' < 'y'")))
9.249      '<' operator not allowed in environment markers
9.249  
9.249 -    >>> print(im("'x' < 'y' < 'z'"))
9.249 +    >>> print((im("'x' < 'y' < 'z'")))
9.249      Chained comparison not allowed in environment markers
9.249  
9.249 -    >>> print(im("r'x'=='x'"))
9.249 +    >>> print((im("r'x'=='x'")))
9.249      Only plain strings allowed in environment markers
9.249  
9.249 -    >>> print(im("'''x'''=='x'"))
9.249 +    >>> print((im("'''x'''=='x'")))
9.249      Only plain strings allowed in environment markers
9.249  
9.249 -    >>> print(im('"""x"""=="x"'))
9.249 +    >>> print((im('"""x"""=="x"')))
9.249      Only plain strings allowed in environment markers
9.249  
9.249 -    >>> print(im(r"'x\n'=='x'"))
9.249 +    >>> print((im(r"'x\n'=='x'")))
9.249      Only plain strings allowed in environment markers
9.249  
9.249 -    >>> print(im("os.open=='y'"))
9.249 +    >>> print((im("os.open=='y'")))
9.249      Language feature not supported in environment markers
9.249  
9.249      >>> em('"x"=="x"')
9.249 
9.249 [stderr]
9.249 RefactoringTool: Skipping optional fixer: buffer
9.249 RefactoringTool: Skipping optional fixer: idioms
9.249 RefactoringTool: Skipping optional fixer: set_literal
9.249 RefactoringTool: Skipping optional fixer: ws_comma
9.249 RefactoringTool: Refactored build/src/tests/api_tests.txt
9.249 RefactoringTool: Files that were modified:
9.249 RefactoringTool: build/src/tests/api_tests.txt
9.249 root: copying setuptools/tests/indexes/test_links_priority/external.html -> build/src/setuptools/tests/indexes/test_links_priority
9.249 root: copying setuptools/tests/indexes/test_links_priority/simple/foobar/index.html -> build/src/setuptools/tests/indexes/test_links_priority/simple/foobar
9.249 root: copying docs/conf.py -> build/src/docs
9.249 root: copying docs/formats.txt -> build/src/docs
9.249 root: copying docs/index.txt -> build/src/docs
9.249 root: copying docs/easy_install.txt -> build/src/docs
9.249 root: copying docs/python3.txt -> build/src/docs
9.249 root: copying docs/using.txt -> build/src/docs
9.249 root: copying docs/setuptools.txt -> build/src/docs
9.249 root: copying docs/merge.txt -> build/src/docs
9.249 root: copying docs/roadmap.txt -> build/src/docs
9.249 root: copying docs/pkg_resources.txt -> build/src/docs
9.249 root: copying docs/merge-faq.txt -> build/src/docs
9.249 root: copying docs/_theme/nature/theme.conf -> build/src/docs/_theme/nature
9.249 root: copying docs/_theme/nature/static/pygments.css -> build/src/docs/_theme/nature/static
9.249 root: copying docs/_theme/nature/static/nature.css_t -> build/src/docs/_theme/nature/static
9.249 root: copying docs/Makefile -> build/src/docs
9.249 root: copying docs/_templates/indexsidebar.html -> build/src/docs/_templates
9.249 root: copying _markerlib/markers.py -> build/src/_markerlib
9.249 root: copying _markerlib/__init__.py -> build/src/_markerlib
9.249 root: copying ez_setup.py -> build/src
9.249 root: copying release.py -> build/src
9.249 root: copying setup.py -> build/src
9.249 root: copying distribute_setup.py -> build/src
9.249 root: copying pkg_resources.py -> build/src
9.249 root: copying easy_install.py -> build/src
9.249 root: copying CHANGES.txt -> build/src
9.249 root: copying CONTRIBUTORS.txt -> build/src
9.249 root: copying DEVGUIDE.txt -> build/src
9.249 root: copying README.txt -> build/src
9.249 root: copying MANIFEST.in -> build/src
9.249 root: copying launcher.c -> build/src
9.249 Traceback (most recent call last):
9.249   File "<string>", line 14, in <module>
9.249   File "/root/.cache/uv/builds-v0/.tmpiFWFBR/lib/python3.10/site-packages/setuptools/build_meta.py", line 333, in get_requires_for_build_wheel
9.249     return self._get_build_requires(config_settings, requirements=[])
9.249   File "/root/.cache/uv/builds-v0/.tmpiFWFBR/lib/python3.10/site-packages/setuptools/build_meta.py", line 303, in _get_build_requires
9.249     self.run_setup()
9.249   File "/root/.cache/uv/builds-v0/.tmpiFWFBR/lib/python3.10/site-packages/setuptools/build_meta.py", line 521, in run_setup
9.249     super().run_setup(setup_script=setup_script)
9.249   File "/root/.cache/uv/builds-v0/.tmpiFWFBR/lib/python3.10/site-packages/setuptools/build_meta.py", line 319, in run_setup
9.249     exec(code, locals())
9.249   File "<string>", line 34, in <module>
9.249 AttributeError: module 'distutils.util' has no attribute 'run_2to3'
------
Dockerfile:4
--------------------
   2 |     WORKDIR /foobar
   3 |     COPY foobar pyproject.toml /foobar/
   4 | >>> RUN uv sync --resolution=lowest-direct
   5 |     
--------------------
ERROR: failed to solve: process "/bin/sh -c uv sync --resolution=lowest-direct" did not complete successfully: exit code: 2

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions