Help us learn about your current experience with the documentation. Take the survey.

包注册表中的 PyPI 包

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

Python 包索引(PyPI)是 Python 的官方第三方软件仓库。 使用 GitLab PyPI 包注册表来发布和分享您 GitLab 项目、组和组织中的 Python 包, 此集成使您能够与代码一起管理 Python 依赖项,为 GitLab 内的 Python 开发提供无缝工作流。

包注册表支持以下工具:

有关 piptwine 客户端使用的特定 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 包注册表交互之前,必须对其进行身份验证。

您可以通过以下方式进行身份验证:

请勿使用此处文档之外的身份验证方法。未记录的身份验证方法将来可能会被移除。

要使用 GitLab token 进行身份验证:

  • 更新 TWINE_USERNAMETWINE_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 发布包。

先决条件:

PyPI 包使用您的项目 ID 发布。如果您的项目位于组中,发布到项目注册表的 PyPI 包在组注册表中也可用。有关更多信息,请参阅从组安装

要发布包:

  1. 定义您的仓库源,编辑 ~/.pypirc 文件并添加:

    [distutils]
    index-servers =
        gitlab
    
    [gitlab]
    repository = https://gitlab.example.com/api/v4/projects/<project_id>/packages/pypi
  2. 使用 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.packagepip install 请求会查找匹配这三个字符中的任意一个的包,例如 my-packagemy_packagemy....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-urlextra-index-url 参数

您可以定义多个 index-urlextra-index-url 参数。

如果您多次使用相同域名(如 gitlab.example.com)但使用不同的认证令牌,pip 可能无法找到您的包。这个问题是由于 pip 在命令执行期间如何注册和存储您的令牌造成的。

要解决此问题,您可以使用来自所有由 index-urlextra-index-url 值指向的项目或组的共同父组的 group deploy token,其范围为 read_package_registry

意外的包源

如果您打算仅使用 GitLab 注册表,但包却从 PyPI 安装:

  • 检查您组的包转发设置。
  • 同时使用 --no-index--index-url 标志来防止 PyPI 回退。
  • 定期使用 pip debug 审计您的包源。