Репозитории формата PyPI работают с клиентами pip, uv, poetry и twine. В примерах используются условные имена pypi-proxy и pypi-hosted.

Подключение к proxy

Укажите индекс репозитория — путь заканчивается на /simple/:

pip install --index-url https://<USERNAME>:<PASSWORD>@<GALLEON_HOST>/repository/pypi-proxy/simple/ six==1.16.0

Для uv добавьте индекс в pyproject.toml (учётные данные — переменные UV_INDEX_GALLEON_USERNAME и UV_INDEX_GALLEON_PASSWORD):

[[tool.uv.index]]
name = "galleon"
url = "https://<GALLEON_HOST>/repository/pypi-proxy/simple/"
default = true

Для poetry (учётные данные — POETRY_HTTP_BASIC_GALLEON_USERNAME и POETRY_HTTP_BASIC_GALLEON_PASSWORD):

poetry source add --priority=primary galleon https://<GALLEON_HOST>/repository/pypi-proxy/simple/

Приватные пакеты

Пакеты из hosted-репозитория подключаются дополнительным индексом рядом с proxy.

Для pip — дополнительный индекс:

pip install --index-url https://<GALLEON_HOST>/repository/pypi-proxy/simple/ \
  --extra-index-url https://<GALLEON_HOST>/repository/pypi-hosted/simple/ mypkg

При нескольких индексах pip может выбрать пакет из любого из них — имена приватных пакетов должны быть уникальны относительно публичного PyPI (защита от подмены зависимостей).

Для uv — второй блок [[tool.uv.index]] с адресом pypi-hosted и закрепление приватного пакета за ним через [tool.uv.sources]:

[[tool.uv.index]]
name = "galleon-private"
url = "https://<GALLEON_HOST>/repository/pypi-hosted/simple/"

[tool.uv.sources]
mypkg = { index = "galleon-private" }

Публикация

Поддерживаются twine, uv publish и poetry publish. Аутентификация — только логин и пароль (или «Name code» и «Pass code» токена); формат одиночного секрета __token__ не поддерживается.

Публикация через twine (~/.pypirc):

[distutils]
index-servers = galleon

[galleon]
repository = https://<GALLEON_HOST>/repository/pypi-hosted/
username = <USERNAME>
password = <PASSWORD>
python -m build
twine upload --repository galleon dist/*

Публикация через uv:

UV_PUBLISH_USERNAME=<USERNAME> UV_PUBLISH_PASSWORD=<PASSWORD> \
  uv publish --publish-url https://<GALLEON_HOST>/repository/pypi-hosted/ dist/*

Особенности

Особенности формата:

  • Опубликованные версии неизменяемы: повторная загрузка файла отклоняется с сообщением «File already exists». Для идемпотентных публикаций в CI используйте uv publish --check-url или poetry publish --skip-existing — на уже загруженных байт в байт файлах они завершаются успешно.
  • Имена проектов нормализуются по правилам PyPI: любое написание (Foo_Bar, foo.bar) ведёт на одну каноническую страницу foo-bar.
  • Метаданные wheel-файлов отдаются отдельными файлами (PEP 658) — uv lock собирает информацию о зависимостях без скачивания самих пакетов.