包注册表中的 PyPI 包
- Tier: Free, Premium, Ultimate
- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
Python 包索引(PyPI)是 Python 的官方第三方软件仓库。 使用 GitLab PyPI 包注册表来发布和分享您 GitLab 项目、组和组织中的 Python 包, 此集成使您能够与代码一起管理 Python 依赖项,为 GitLab 内的 Python 开发提供无缝工作流。
包注册表支持以下工具:
有关 pip 和 twine 客户端使用的特定 API 端点的文档,请参阅 PyPI API 文档。
学习如何构建 PyPI 包。
包请求转发安全提醒
使用 GitLab PyPI 包注册表时,在 GitLab 注册表中找不到的包请求会自动转发到 pypi.org。这种行为可能导致即使使用 --index-url 标志,也会从 pypi.org 下载包。
处理私有包时,为确保最大安全性:
- 在您的组设置中关闭包转发:
- 实例管理员可以在 Admin 区域的 Continuous Integration 部分 中禁用转发。
- 组所有者可以在组设置的 Packages and Registries 部分中禁用转发。
- 安装包时同时使用
--index-url和--no-index标志。
向 GitLab 包注册表进行身份验证
在与 GitLab 包注册表交互之前,必须对其进行身份验证。
您可以通过以下方式进行身份验证:
- 具有
api范围的 personal access token - 具有
read_package_registry、write_package_registry或两者范围的 deploy token - CI/CD job token
请勿使用此处文档之外的身份验证方法。未记录的身份验证方法将来可能会被移除。
要使用 GitLab token 进行身份验证:
- 更新
TWINE_USERNAME和TWINE_PASSWORD环境变量。
例如:
run:
image: python:latest
variables:
TWINE_USERNAME: <personal_access_token_name>
TWINE_PASSWORD: <personal_access_token>
script:
- pip install build twine
- python -m build
- python -m twine upload --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/*run:
image: python:latest
variables:
TWINE_USERNAME: <deploy_token_username>
TWINE_PASSWORD: <deploy_token>
script:
- pip install build twine
- python -m build
- python -m twine upload --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/*run:
image: python:latest
variables:
TWINE_USERNAME: gitlab-ci-token
TWINE_PASSWORD: $CI_JOB_TOKEN
script:
- pip install build twine
- python -m build
- python -m twine upload --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/*为组进行身份验证
要为组向包注册表进行身份验证:
- 向包注册表进行身份验证,但使用组 URL 而不是项目 URL:
https://gitlab.example.com/api/v4/groups/<group_id>/-/packages/pypi发布 PyPI 包
您可以使用 twine 发布包。
先决条件:
- 您必须向包注册表进行身份验证。
- 您的版本字符串必须有效。
- 该包:
- 大小不超过 5 GB。
description不超过 4000 个字符。更长的description字符串会被截断。- 尚未发布到包注册表。尝试发布相同版本的包会返回
400 Bad Request。
PyPI 包使用您的项目 ID 发布。如果您的项目位于组中,发布到项目注册表的 PyPI 包在组注册表中也可用。有关更多信息,请参阅从组安装。
要发布包:
-
定义您的仓库源,编辑
~/.pypirc文件并添加:[distutils] index-servers = gitlab [gitlab] repository = https://gitlab.example.com/api/v4/projects/<project_id>/packages/pypi -
使用 twine 上传您的包:
python3 -m twine upload --repository gitlab dist/*当包成功发布时,会显示如下消息:
Uploading distributions to https://gitlab.example.com/api/v4/projects/<project_id>/packages/pypi Uploading mypypipackage-0.0.1-py3-none-any.whl 100%|███████████████████████████████████████████████████████████████████████████████████████████| 4.58k/4.58k [00:00<00:00, 10.9kB/s] Uploading mypypipackage-0.0.1.tar.gz 100%|███████████████████████████████████████████████████████████████████████████████████████████| 4.24k/4.24k [00:00<00:00, 11.0kB/s]
包已发布到包注册表,并显示在 Packages and registries 页面上。
使用内联身份验证发布
如果您没有使用 .pypirc 文件定义仓库源,可以使用内联身份验证发布到仓库:
TWINE_PASSWORD=<personal_access_token, deploy_token, or $CI_JOB_TOKEN> \
TWINE_USERNAME=<username, deploy_token_username, or gitlab-ci-token> \
python3 -m twine upload --repository-url https://gitlab.example.com/api/v4/projects/<project_id>/packages/pypi dist/*发布同名同版本的包
如果已存在同名同版本的包,您无法发布该包。您必须先删除现有包。如果您尝试多次发布同一包,将发生 400 Bad Request 错误。
安装 PyPI 包
默认情况下,当在 GitLab 包注册表中找不到 PyPI 包时,请求会转发到 pypi.org。这种行为:
- 默认为所有 GitLab 实例启用
- 可以在组的 Packages and registries 设置中配置
- 即使使用
--index-url标志也适用
管理员可以在 Continuous Integration 设置 中全局禁用此行为。组所有者可以在组设置的 Packages and registries 部分中为特定组禁用此行为。
当您使用 --index-url 选项时,如果是默认端口,请不要指定端口号。http URL 默认为 80,https URL 默认为 443。
从项目安装
要安装包的最新版本,请使用以下命令:
pip install --index-url https://<personal_access_token_name>:<personal_access_token>@gitlab.example.com/api/v4/projects/<project_id>/packages/pypi/simple --no-deps <package_name><package_name>是包名称。<personal_access_token_name>是具有read_api范围的个人访问令牌名称。<personal_access_token>是具有read_api范围的个人访问令牌。<project_id>是项目的 URL 编码 路径(例如group%2Fproject)或项目 ID(例如42)。
在这些命令中,您可以使用 --extra-index-url 替代 --index-url。如果您按照指南操作并想要安装 MyPyPiPackage` 包,可以运行:
pip install mypypipackage --no-deps --index-url https://<personal_access_token_name>:<personal_access_token>@gitlab.example.com/api/v4/projects/<project_id>/packages/pypi/simple此消息表示包已成功安装:
Looking in indexes: https://<personal_access_token_name>:****@gitlab.example.com/api/v4/projects/<project_id>/packages/pypi/simple
Collecting mypypipackage
Downloading https://gitlab.example.com/api/v4/projects/<project_id>/packages/pypi/files/d53334205552a355fee8ca35a164512ef7334f33d309e60240d57073ee4386e6/mypypipackage-0.0.1-py3-none-any.whl (1.6 kB)
Installing collected packages: mypypipackage
Successfully installed mypypipackage-0.0.1从组安装
要从组安装包的最新版本,请使用以下命令:
pip install --index-url https://<personal_access_token_name>:<personal_access_token>@gitlab.example.com/api/v4/groups/<group_id>/-/packages/pypi/simple --no-deps <package_name>在此命令中:
<package_name>是包名称。<personal_access_token_name>是具有read_api范围的个人访问令牌名称。<personal_access_token>是具有read_api范围的个人访问令牌。<group_id>是组 ID。
在这些命令中,您可以使用 --extra-index-url 替代 --index-url。如果您按照指南操作并想要安装 MyPyPiPackage 包,可以运行:
pip install mypypipackage --no-deps --index-url https://<personal_access_token_name>:<personal_access_token>@gitlab.example.com/api/v4/groups/<group_id>/-/packages/pypi/simple包名称
GitLab 查找使用 Python 标准化名称 (PEP-503) 的包。
字符 -、_ 和 . 被视为相同,并且重复的字符会被移除。
对 my.package 的 pip install 请求会查找匹配这三个字符中的任意一个的包,例如 my-package、my_package 和 my....package。
安全影响
安装 PyPI 包时使用 --extra-index-url 与 --index-url 的安全影响很大,值得详细了解:
--index-url:此选项将默认的 PyPI 索引 URL 替换为指定的 URL。默认开启的 GitLab 包转发设置仍可能从 PyPI 下载在包注册表中找不到的包。为确保包仅从 GitLab 安装,可以:- 在组设置中禁用包转发
- 同时使用
--index-url和--no-index标志
--extra-index-url:此选项添加额外的索引进行搜索, alongside 默认的 PyPI 索引。 它的安全性较低,更容易受到依赖混淆攻击,因为它会同时检查默认的 PyPI 和额外的索引来查找包。
使用私有包时,请遵循以下最佳实践:
- 检查您组的包转发设置。
- 安装私有包时同时使用
--no-index和--index-url标志。 - 定期使用
pip debug审计您的包源。
使用 requirements.txt
如果希望 pip 访问您的公共注册表,请将 --extra-index-url 参数连同您的注册表 URL 一起添加到 requirements.txt 文件中。
--extra-index-url https://gitlab.example.com/api/v4/projects/<project_id>/packages/pypi/simple
package-name==1.0.0如果这是私有注册表,您可以通过几种方式进行身份验证。例如:
-
使用您的
requirements.txt文件:--extra-index-url https://gitlab-ci-token:<personal_token>@gitlab.example.com/api/v4/projects/<project_id>/packages/pypi/simple package-name==1.0.0 -
使用
~/.netrc文件:machine gitlab.example.com login gitlab-ci-token password <personal_token>
PyPI 包的版本控制
适当的版本控制对于有效管理 PyPI 包很重要。遵循以下最佳实践以确保您的包版本正确。
使用语义版本控制 (SemVer)
为您的包采用语义版本控制。版本号应为 MAJOR.MINOR.PATCH 格式:
- 对于不兼容的 API 更改,递增
MAJOR版本。 - 对于向后兼容的新功能,递增
MINOR版本。 - 对于向后兼容的错误修复,递增
PATCH版本。
例如:1.0.0、1.1.0、1.1.1。
对于新项目,从版本 0.1.0 开始。这表示初始开发阶段,此时 API 尚未稳定。
使用有效的版本字符串
确保您的版本字符串符合 PyPI 标准。GitLab 使用特定的正则表达式来验证版本字符串:
\A(?:
v?
(?:([0-9]+)!)? (?# epoch)
([0-9]+(?:\.[0-9]+)*) (?# release segment)
([-_\.]?((a|b|c|rc|alpha|beta|pre|preview))[-_\.]?([0-9]+)?)? (?# pre-release)
((?:-([0-9]+))|(?:[-_\.]?(post|rev|r)[-_\.]?([0-9]+)?))? (?# post release)
([-_\.]?(dev)[-_\.]?([0-9]+)?)? (?# dev release)
(?:([a-z0-9]+(?:[-_\.][a-z0-9]+)*))? (?# local version)
)\z}xi您可以使用此正则表达式编辑器来实验正则表达式并尝试您的版本字符串。
有关正则表达式的更多详细信息,请参阅 Python 文档。
支持的 CLI 命令
GitLab PyPI 仓库支持以下 CLI 命令:
twine upload:将包上传到注册表。pip install:从注册表安装 PyPI 包。
故障排除
为提高性能,pip 命令会缓存与包相关的文件。pip 不会自行删除数据。随着安装新包,缓存会增长。如果遇到问题,请使用以下命令清除缓存:
pip cache purge多个 index-url 或 extra-index-url 参数
您可以定义多个 index-url 和 extra-index-url 参数。
如果您多次使用相同域名(如 gitlab.example.com)但使用不同的认证令牌,pip 可能无法找到您的包。这个问题是由于 pip 在命令执行期间如何注册和存储您的令牌造成的。
要解决此问题,您可以使用来自所有由 index-url 和 extra-index-url 值指向的项目或组的共同父组的 group deploy token,其范围为 read_package_registry。
意外的包源
如果您打算仅使用 GitLab 注册表,但包却从 PyPI 安装:
- 检查您组的包转发设置。
- 同时使用
--no-index和--index-url标志来防止 PyPI 回退。 - 定期使用
pip debug审计您的包源。