Работа с PyPI¶
Proxy-репозиторий¶
curl -X POST https://save.example.com/api/v1/repos \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"project": "backend",
"name": "pypi-proxy",
"format": "pypi",
"repository_type": "proxy",
"remote_url": "https://pypi.org/",
"cache_ttl": 3600
}'
Hosted-репозиторий¶
curl -X POST https://save.example.com/api/v1/repos \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"project": "backend",
"name": "pypi-hosted",
"format": "pypi",
"repository_type": "hosted"
}'
После создания репозиторий доступен по URL https://save.example.com/pypi/<project>/<repository>/. Simple-индекс — по /simple/, загрузка пакета (twine-совместимый POST) — на корень репозитория.
Настройка клиента¶
pip¶
# Разовая установка через флаг --index-url
pip install --index-url https://save.example.com/pypi/<project>/pypi-proxy/simple/ <package>
# Постоянная конфигурация через pip.conf
cat > ~/.config/pip/pip.conf << EOF
[global]
index-url = https://USER:PASS@save.example.com/pypi/<project>/pypi-proxy/simple/
trusted-host = save.example.com
EOF
Расположение pip.conf
- Linux/macOS:
~/.config/pip/pip.confили~/.pip/pip.conf - Windows:
%APPDATA%\pip\pip.ini - В virtualenv:
$VIRTUAL_ENV/pip.conf
Robot-аккаунты в CI
Для CI/CD используйте robot-аккаунт: username = sa$<robot-name>, password = <api-key>. Конфиг pip.conf не меняется — отличается только значение username. Подробнее — в общем разделе Аутентификация.
poetry¶
В pyproject.toml:
[[tool.poetry.source]]
name = "codescoring"
url = "https://save.example.com/pypi/<project>/pypi-proxy/simple/"
priority = "primary"
Credentials передаются через poetry config:
pipenv¶
В Pipfile:
[[source]]
url = "https://USER:PASS@save.example.com/pypi/<project>/pypi-proxy/simple/"
verify_ssl = true
name = "codescoring"
uv¶
Или в pyproject.toml:
[[tool.uv.index]]
name = "codescoring"
url = "https://save.example.com/pypi/<project>/pypi-proxy/simple/"
default = true
Публикация (twine, hosted)¶
Загрузка пакетов в hosted-репозиторий — стандартным twine upload. URL-адрес публикации — корень репозитория (без /simple/).
# ~/.pypirc
[distutils]
index-servers = codescoring
[codescoring]
repository = https://save.example.com/pypi/<project>/pypi-hosted/
username = <username>
password = <password>
Миграция URL репозитория¶
Сценарий использования: миграция репозитория PyPI с Nexus / Artifactory на CodeScoring.Save.
| Источник | URL в pip.conf до миграции | URL в pip.conf после миграции |
|---|---|---|
| Nexus | https://nexus.host.ru/repository/pypi-proxy/simple |
https://save.example.com/pypi/<project>/pypi-proxy/simple/ |
| Artifactory | https://jfrog.host.ru/artifactory/api/pypi/pypi-remote/simple |
https://save.example.com/pypi/<project>/pypi-proxy/simple/ |
| Официальный репозиторий | https://pypi.org/simple |
https://save.example.com/pypi/<project>/pypi-proxy/simple/ |
Параметры аутентификации (имя пользователя / пароль) и формат pip.conf сохраняются без изменений.
Устранение неполадок¶
Проверка простого индекса¶
curl -u "<username>:<password>" \
https://save.example.com/pypi/<project>/pypi-proxy/simple/<package>/
Ответ — HTML-страница со списком ссылок на файлы пакета. Если страница пустая или возвращается 404 — пакет не закэширован и upstream его не вернул.
Состояние сервиса¶
Аудит по репозиторию¶
curl -u "<username>:<password>" \
"https://save.example.com/api/v1/admin/audit?resource_type=repository&q=pypi-proxy&limit=50"