-
Notifications
You must be signed in to change notification settings - Fork 81
Description
Version
pulpcore: 3.102.0
pulp-python: 3.24.1
Installation method: Podman, via this docker-compose:
services:
pulp:
image: pulp/pulp
container_name: pulp
ports:
- "8080:80"
cap_add:
- SYS_ADMIN
security_opt:
- label=disable
devices:
- /dev/fuse
volumes:
- ./settings:/etc/pulp:U
- pulp_storage:/var/lib/pulp
- pgsql:/var/lib/pgsql
- containers:/var/lib/containers
- container_build:/var/lib/pulp/.local/share/containers
restart: unless-stopped
volumes:
pulp_storage:
pgsql:
containers:
container_build:
Describe the bug
Setting up a repository, a corresponding distribution, a remote pointing to pypi, in pull-through caching mode, the setup works with pip, but uv (https://docs.astral.sh/uv/) is unable to resolve dependencies.
To Reproduce
- Do the standard setup of pulp and pulp-cli as described in the tutorials.
- Set up repository, distribution and remote as follows:
pulp python repository create --name orgalorg-repo
pulp python distribution create --name orgalorg-dist --base-path orgalorg --repository orgalorg-repo
pulp python remote create --name pypi --url https://pypi.org/ --policy on_demand
pulp python distribution update --name orgalorg-dist --remote pypi
- Set up a dummy project via uv (e.g.
uv init dummyproject) and in the createdpyproject.tomlwrite
[project]
name = "dummyenv"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.14"
dependencies = ["requests==2.32.5"]
[[tool.uv.index]]
name = "orgalorg"
url = "http://localhost:8080/pypi/orgalorg/simple"
default = true
Vary the dependencies, for example I have tried requests, requests==2.32.5 and numpy.
-
Run
uv sync -
Observe that
uvfails to resolve dependencies (see later for additional data). -
To ensure things work with pip, destroy the venv (
rm -rf .venv), then
python -m venv .venv
source .venv/bin/activate
pip install requests==2.32.5
Observe that pip does this successfully and running pulp content list (in a venv where pulp-cli has been installed) will display the downloaded package (Note: aborted resolution attempts by uv can also result in some packages being downloaded and cached).
-
Destroy the venv again, and try
uv syncagain, for example withrequests==2.32.5in thedependencies. Again observe failure but now for different reasons (the package is now cached in the pulp server). -
Recreate the venv (
uv venv) if it doesn't exist and runuv pip install requests=2.32.5 --no-deps. Observe that nowuvinstalls the package successfully (but without its dependencies), confirming that this is not a connection problem but a dependency resolution problem.
Expected behavior
uv should be able to resolve dependencies through the proxy.
Additional context
Output when trying to sync project with uv with requests unconstrained:
benzor@orgalorg:~/Projects/Local/dummyenv$ uv sync
× Failed to download and build `requests==1.2.3`
├─▶ Failed to resolve requirements from `setup.py` build
├─▶ No solution found when resolving: `setuptools>=40.8.0`
╰─▶ Because only the following versions of setuptools are available:
setuptools<=40.8.0
setuptools==40.9.0
setuptools==41.0.0
setuptools==41.0.1
setuptools==41.1.0
setuptools==41.2.0
setuptools==41.3.0
setuptools==41.4.0
setuptools==41.5.0
setuptools==41.5.1
setuptools==41.6.0
setuptools==42.0.0
setuptools==42.0.1
setuptools==42.0.2
setuptools==43.0.0
setuptools==44.0.0
setuptools==44.1.0
setuptools==44.1.1
setuptools==45.0.0
setuptools==45.1.0
setuptools==45.2.0
setuptools==45.3.0
setuptools==46.0.0
setuptools==46.1.0
setuptools==46.1.1
setuptools==46.1.2
setuptools==46.1.3
setuptools==46.2.0
setuptools==46.3.0
setuptools==46.3.1
setuptools==46.4.0
setuptools==47.0.0
setuptools==47.1.0
setuptools==47.1.1
setuptools==47.2.0
setuptools==47.3.0
setuptools==47.3.1
setuptools==47.3.2
setuptools==48.0.0
setuptools==49.0.0
setuptools==49.0.1
setuptools==49.1.0
setuptools==49.1.1
setuptools==49.1.2
setuptools==49.1.3
setuptools==49.2.0
setuptools==49.2.1
setuptools==49.3.0
setuptools==49.3.1
setuptools==49.3.2
setuptools==49.4.0
setuptools==49.5.0
setuptools==49.6.0
setuptools==50.0.0
setuptools==50.0.1
setuptools==50.0.2
setuptools==50.0.3
setuptools==50.1.0
setuptools==50.2.0
setuptools==50.3.0
setuptools==50.3.1
setuptools==50.3.2
setuptools==51.0.0
setuptools==51.1.0
setuptools==51.1.0.post20201221
setuptools==51.1.1
setuptools==51.1.2
setuptools==51.2.0
setuptools==51.3.0
setuptools==51.3.1
setuptools==51.3.2
setuptools==51.3.3
setuptools==52.0.0
setuptools==53.0.0
setuptools==53.1.0
setuptools==54.0.0
setuptools==54.1.0
setuptools==54.1.1
setuptools==54.1.2
setuptools==54.1.3
setuptools==54.2.0
setuptools==56.0.0
setuptools==56.1.0
setuptools==56.2.0
setuptools==57.0.0
setuptools==57.1.0
setuptools==57.2.0
setuptools==57.3.0
setuptools==57.4.0
setuptools==57.5.0
setuptools==58.0.0
setuptools==58.0.1
setuptools==58.0.2
setuptools==58.0.3
setuptools==58.0.4
setuptools==58.1.0
setuptools==58.2.0
setuptools==58.3.0
setuptools==58.4.0
setuptools==58.5.0
setuptools==58.5.1
setuptools==58.5.2
setuptools==58.5.3
setuptools==59.0.1
setuptools==59.1.0
setuptools==59.1.1
setuptools==59.2.0
setuptools==59.3.0
setuptools==59.4.0
setuptools==59.5.0
setuptools==59.6.0
setuptools==59.7.0
setuptools==59.8.0
setuptools==60.0.0
setuptools==60.0.1
setuptools==60.0.2
setuptools==60.0.3
setuptools==60.0.4
setuptools==60.0.5
setuptools==60.1.0
setuptools==60.1.1
setuptools==60.2.0
setuptools==60.3.0
setuptools==60.3.1
setuptools==60.4.0
setuptools==60.5.0
setuptools==60.6.0
setuptools==60.7.0
setuptools==60.7.1
setuptools==60.8.0
setuptools==60.8.1
setuptools==60.8.2
setuptools==60.9.0
setuptools==60.9.1
setuptools==60.9.2
setuptools==60.9.3
setuptools==60.10.0
setuptools==61.0.0
setuptools==61.1.0
setuptools==61.1.1
setuptools==61.2.0
setuptools==61.3.0
setuptools==61.3.1
setuptools==62.0.0
setuptools==62.1.0
setuptools==62.2.0
setuptools==62.3.0
setuptools==62.3.1
setuptools==62.3.2
setuptools==62.3.3
setuptools==62.3.4
setuptools==62.4.0
setuptools==62.5.0
setuptools==62.6.0
setuptools==63.0.0
setuptools==63.1.0
setuptools==63.2.0
setuptools==63.3.0
setuptools==63.4.0
setuptools==63.4.1
setuptools==63.4.2
setuptools==63.4.3
setuptools==64.0.0
setuptools==64.0.1
setuptools==64.0.2
setuptools==64.0.3
setuptools==65.0.0
setuptools==65.0.1
setuptools==65.0.2
setuptools==65.1.0
setuptools==65.1.1
setuptools==65.2.0
setuptools==65.3.0
setuptools==65.4.0
setuptools==65.4.1
setuptools==65.5.0
setuptools==65.5.1
setuptools==65.6.0
setuptools==65.6.1
setuptools==65.6.2
setuptools==65.6.3
setuptools==65.7.0
setuptools==66.0.0
setuptools==66.1.0
setuptools==66.1.1
setuptools==67.0.0
setuptools==67.1.0
setuptools==67.2.0
setuptools==67.3.1
setuptools==67.3.2
setuptools==67.3.3
setuptools==67.4.0
setuptools==67.5.0
setuptools==67.5.1
setuptools==67.6.0
setuptools==67.6.1
setuptools==67.7.0
setuptools==67.7.1
setuptools==67.7.2
setuptools==67.8.0
setuptools==68.0.0
setuptools==68.1.0
setuptools==68.1.2
setuptools==68.2.0
setuptools==68.2.1
setuptools==68.2.2
setuptools==69.0.0
setuptools==69.0.1
setuptools==69.0.2
setuptools==69.0.3
setuptools==69.1.0
setuptools==69.1.1
setuptools==69.2.0
setuptools==69.3.0
setuptools==69.3.1
setuptools==69.4.0
setuptools==69.4.1
setuptools==69.4.2
setuptools==69.5.0
setuptools==69.5.1
setuptools==70.0.0
setuptools==70.1.0
setuptools==70.1.1
setuptools==70.2.0
setuptools==70.3.0
setuptools==71.0.0
setuptools==71.0.1
setuptools==71.0.2
setuptools==71.0.3
setuptools==71.0.4
setuptools==71.1.0
setuptools==72.0.0
setuptools==72.1.0
setuptools==72.2.0
setuptools==73.0.0
setuptools==73.0.1
setuptools==74.0.0
setuptools==74.1.0
setuptools==74.1.1
setuptools==74.1.2
setuptools==74.1.3
setuptools==75.0.0
setuptools==75.1.0
setuptools==75.2.0
setuptools==75.3.0
setuptools==75.3.1
setuptools==75.3.2
setuptools==75.3.3
setuptools==75.4.0
setuptools==75.5.0
setuptools==75.6.0
setuptools==75.7.0
setuptools==75.8.0
setuptools==75.8.1
setuptools==75.8.2
setuptools==75.9.0
setuptools==75.9.1
setuptools==76.0.0
setuptools==76.1.0
setuptools==77.0.1
setuptools==77.0.3
setuptools==78.0.1
setuptools==78.0.2
setuptools==78.1.0
setuptools==78.1.1
setuptools==79.0.0
setuptools==79.0.1
setuptools==80.0.0
setuptools==80.0.1
setuptools==80.1.0
setuptools==80.2.0
setuptools==80.3.0
setuptools==80.3.1
setuptools==80.4.0
setuptools==80.6.0
setuptools==80.7.0
setuptools==80.7.1
setuptools==80.8.0
setuptools==80.9.0
setuptools==80.10.1
setuptools==80.10.2
and setuptools>=40.8.0 has invalid metadata, we can conclude that setuptools>=40.8.0 cannot be used.
And because you require setuptools>=40.8.0, we can conclude that your requirements are unsatisfiable.
hint: Only pre-releases of `setuptools` (e.g., 63.0.0b1) match these build requirements, and
build environments can't enable pre-releases automatically. Add `setuptools>=63.0.0b1` to
`build-system.requires`, `[tool.uv.extra-build-dependencies]`, or supply it via `uv build
--build-constraint`.
hint: Metadata for `setuptools` (v80.10.2) could not be parsed:
Metadata field Name not found
help: `requests` (v1.2.3) was included because `dummyenv` (v0.1.0) depends on `requests`
Output when trying to sync with requests==2.32.5:
benzor@orgalorg:~/Projects/Local/dummyenv$ uv sync
× No solution found when resolving dependencies:
╰─▶ Because requests==2.32.5 has invalid metadata and your project depends on requests==2.32.5, we can
conclude that your project's requirements are unsatisfiable.
hint: Metadata for `requests` (v2.32.5) could not be parsed:
Header cannot start with a space; it is likely an overhanging line from a previous header
Logs in the container when trying to sync with requests==2.32.5:
('pulp [fa62431e7c8547ef92b483ea5742dcb5]: ::1 - - [28/Jan/2026:21:35:42 +0000] "GET /pypi/orgalorg/simple/requests/ HTTP/1.0" 200 99533 "-" "uv/0.9.27 {\"installer\":{\"name\":\"uv\",\"version\":\"0.9.27\",\"subcommand\":[\"sync\"]},\"python\":\"3.14.2\",\"implementation\":{\"name\":\"CPython\",\"version\":\"3.14.2\"},\"distro\":{\"name\":\"Fedora Linux\",\"version\":\"43\",\"id\":\"\",\"libc\":{\"lib\":\"glibc\",\"version\":\"2.42\"}},\"system\":{\"name\":\"Linux\",\"release\":\"6.18.6-200.fc43.x86_64\"},\"cpu\":\"x86_64\",\"openssl_version\":null,\"setuptools_version\":null,\"rustc_version\":null,\"ci\":null}"',)
[2026-01-28 21:35:42 +0000] [485] [ERROR] Error handling request from ::1
Traceback (most recent call last):
File "/usr/local/lib64/python3.11/site-packages/aiohttp/web_protocol.py", line 510, in _handle_request
resp = await request_handler(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib64/python3.11/site-packages/aiohttp/web_app.py", line 569, in _handle
return await handler(request)
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib64/python3.11/site-packages/aiohttp/web_middlewares.py", line 117, in impl
return await handler(request)
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulpcore/content/authentication.py", line 27, in guid
return await handler(request)
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulpcore/content/authentication.py", line 58, in authenticate
return await handler(request)
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulpcore/content/handler.py", line 291, in stream_content
return await self._match_and_stream(path, request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulpcore/content/handler.py", line 922, in _match_and_stream
return await self._stream_remote_artifact(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulpcore/content/handler.py", line 1348, in _stream_remote_artifact
content_artifacts = await asyncio.shield(
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 504, in __call__
ret = await asyncio.shield(exec_coro)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.11/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 559, in thread_handler
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulpcore/content/handler.py", line 1052, in _save_artifact
content = c_type.init_from_artifact_and_relative_path(artifact, rel_path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulp_python/app/models.py", line 217, in init_from_artifact_and_relative_path
data = artifact_to_python_content_data(path.name, artifact, domain=get_domain())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulp_python/app/utils.py", line 252, in artifact_to_python_content_data
metadata = get_project_metadata_from_file(temp_file.name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pulp_python/app/utils.py", line 196, in get_project_metadata_from_file
pkg_type_index = [filename.endswith(ext) for ext in extensions].index(True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: True is not in list
Output when trying to sync with requests==2.32.5 after this package has been cached (by installing successfully through pip):
benzor@orgalorg:~/Projects/Local/dummyenv$ uv sync
Using CPython 3.14.2 interpreter at: /usr/bin/python3.14
Creating virtual environment at: .venv
⠧ requests==2.32.5 error: Failed to fetch: `http://orgalorg:8080/pulp/content/orgalorg/requests-2.32.5-py3-none-any.whl.metadata`
Caused by: HTTP status client error (404 Error while fetching from upstream remote(https://pypi.org/requests-2.32.5-py3-none-any.whl.metadata): Not Found) for url (http://orgalorg:8080/pulp/content/orgalorg/requests-2.32.5-py3-none-any.whl.metadata)
And corresponding container logs:
[28/Jan/2026:21:39:19 +0000] "GET /pulp/content/orgalorg/requests-2.32.5-py3-none-any.whl.metadata HTTP/1.0" 404 381 "-" "uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["sync"]},"python":"3.14.2","implementation":{"name":"CPython","version":"3.14.2"},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":{"lib":"glibc","version":"2.42"}},"system":{"name":"Linux","release":"6.18.6-200.fc43.x86_64"},"cpu":"x86_64","openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}"
Notes:
I am quite ignorant when it comes to PyPI specifics and packaging in general besides building wheels, but it seems to me the issue is that uv is trying to get .whl.metadata files. I have no idea what these are (as far as I know, metadata is contained in a wheel itself).
The output of pulp content list is
(pulp-server) benzor@orgalorg:~/Projects/Local/pulp-server$ pulp content list
[
{
"pulp_href": "/pulp/api/v3/content/python/packages/019c068b-217b-769e-9308-779cc829e741/",
"prn": "prn:python.pythonpackagecontent:019c068b-217b-769e-9308-779cc829e741",
"pulp_created": "2026-01-28T21:38:27.324595Z",
"pulp_last_updated": "2026-01-28T21:38:27.324607Z",
"pulp_labels": {},
"vuln_report": null,
"artifacts": {
"certifi-2026.1.4-py3-none-any.whl": "/pulp/api/v3/artifacts/019c068b-2175-7cf8-a59e-3609e6cdec82/"
}
},
{
"pulp_href": "/pulp/api/v3/content/python/packages/019c068b-1d85-71ec-9172-55f1a957a019/",
"prn": "prn:python.pythonpackagecontent:019c068b-1d85-71ec-9172-55f1a957a019",
"pulp_created": "2026-01-28T21:38:26.309999Z",
"pulp_last_updated": "2026-01-28T21:38:26.310011Z",
"pulp_labels": {},
"vuln_report": null,
"artifacts": {
"urllib3-2.6.3-py3-none-any.whl": "/pulp/api/v3/artifacts/019c068b-1d7f-7434-a594-f1b59069e40e/"
}
},
{
"pulp_href": "/pulp/api/v3/content/python/packages/019c068b-1bb6-7795-9621-541c2b381220/",
"prn": "prn:python.pythonpackagecontent:019c068b-1bb6-7795-9621-541c2b381220",
"pulp_created": "2026-01-28T21:38:25.847351Z",
"pulp_last_updated": "2026-01-28T21:38:25.847360Z",
"pulp_labels": {},
"vuln_report": null,
"artifacts": {
"idna-3.11-py3-none-any.whl": "/pulp/api/v3/artifacts/019c068b-1bb1-791e-81e2-59540e0b3196/"
}
},
{
"pulp_href": "/pulp/api/v3/content/python/packages/019c068b-1a8d-7895-928c-92ff922746b6/",
"prn": "prn:python.pythonpackagecontent:019c068b-1a8d-7895-928c-92ff922746b6",
"pulp_created": "2026-01-28T21:38:25.550239Z",
"pulp_last_updated": "2026-01-28T21:38:25.550249Z",
"pulp_labels": {},
"vuln_report": null,
"artifacts": {
"charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "/pulp/api/v3/artifacts/019c068b-1a88-7c0d-b8fc-1857d748d2a8/"
}
},
{
"pulp_href": "/pulp/api/v3/content/python/packages/019c068b-1959-7aac-bec0-8bf1e07e6fb1/",
"prn": "prn:python.pythonpackagecontent:019c068b-1959-7aac-bec0-8bf1e07e6fb1",
"pulp_created": "2026-01-28T21:38:25.242970Z",
"pulp_last_updated": "2026-01-28T21:38:25.242982Z",
"pulp_labels": {},
"vuln_report": null,
"artifacts": {
"requests-2.32.5-py3-none-any.whl": "/pulp/api/v3/artifacts/019c068b-1953-7093-9f56-8e9f644369f7/"
}
},
{
"pulp_href": "/pulp/api/v3/content/python/packages/019c0678-dbd3-71c0-8f0d-5ef1f9d1b6cd/",
"prn": "prn:python.pythonpackagecontent:019c0678-dbd3-71c0-8f0d-5ef1f9d1b6cd",
"pulp_created": "2026-01-28T21:18:29.844404Z",
"pulp_last_updated": "2026-01-28T21:18:29.844415Z",
"pulp_labels": {},
"vuln_report": null,
"artifacts": {
"numpy-1.10.0.post2.tar.gz": "/pulp/api/v3/artifacts/019c0678-db5b-76d2-a581-9a42d978d127/"
}
},
{
"pulp_href": "/pulp/api/v3/content/python/packages/019c0667-1868-77d2-8c37-e5db6ce403c3/",
"prn": "prn:python.pythonpackagecontent:019c0667-1868-77d2-8c37-e5db6ce403c3",
"pulp_created": "2026-01-28T20:59:05.706536Z",
"pulp_last_updated": "2026-01-28T20:59:05.706548Z",
"pulp_labels": {},
"vuln_report": null,
"artifacts": {
"requests-1.2.3.tar.gz": "/pulp/api/v3/artifacts/019c0667-1859-70c0-b0e5-f09e55a719ba/"
}
},
{
"pulp_href": "/pulp/api/v3/content/python/packages/019c065a-5d0c-74b2-a669-099544911d20/",
"prn": "prn:python.pythonpackagecontent:019c065a-5d0c-74b2-a669-099544911d20",
"pulp_created": "2026-01-28T20:45:11.310796Z",
"pulp_last_updated": "2026-01-28T20:45:11.310808Z",
"pulp_labels": {},
"vuln_report": null,
"artifacts": {
"orgalorg_greeter-0.1.0-py3-none-any.whl": "/pulp/api/v3/artifacts/019c065a-5caa-76ba-8cd3-bdecdb6ee4e3/",
"orgalorg_greeter-0.1.0-py3-none-any.whl.metadata": "/pulp/api/v3/artifacts/019c065a-5d15-76b8-afd6-385c81a76217/"
}
}
]
Here orgalorg_greeter is a dummy package I have created and uploaded to the index. Although this dummy package has no dependencies (so I am not sure if it accurately tests whether uv can resolve dependencies for packages that are uploaded manually to the index as opposed to proxied), uv has no problem resolving this dependency. We can observe the last line
"artifacts": {
"orgalorg_greeter-0.1.0-py3-none-any.whl": "/pulp/api/v3/artifacts/019c065a-5caa-76ba-8cd3-bdecdb6ee4e3/",
"orgalorg_greeter-0.1.0-py3-none-any.whl.metadata": "/pulp/api/v3/artifacts/019c065a-5d15-76b8-afd6-385c81a76217/"
}
which shows that a .whl.metadata file has been uploaded when I published the wheel via twine.
For the rest of the packages -- which have been cached from the PyPI -- there is no such .whl.metadata file. I suspect uv wants this, cannot find it on our index when cached, and for some reason pulp does not properly get this when proxying. But I'm just guessing.