跳至主要内容

构建和测试 Python

您可以创建一个持续集成 (CI) 工作流来构建和测试您的 Python 项目。

简介

本指南将向您展示如何构建、测试和发布 Python 包。

GitHub 托管运行器具有一个包含预安装软件的工具缓存,其中包括 Python 和 PyPy。您无需安装任何内容!有关最新软件的完整列表以及 Python 和 PyPy 的预安装版本,请参阅“使用 GitHub 托管运行器”。

先决条件

您应该熟悉 YAML 和 GitHub Actions 的语法。有关更多信息,请参阅“编写工作流”。

我们建议您对 Python 和 pip 有基本了解。有关更多信息,请参阅

使用 Python 工作流模板

要快速入门,请将工作流模板添加到存储库的 .github/workflows 目录中。

如果您的存储库中至少包含一个 .py 文件,GitHub 提供了一个 Python 工作流模板,该模板应该可以正常工作。本指南后续部分提供了如何自定义此工作流模板的示例。

  1. 在 GitHub 上,导航到存储库的主页。

  2. 在您的存储库名称下,单击 操作.

    Screenshot of the tabs for the "github/docs" repository. The "Actions" tab is highlighted with an orange outline.

  3. 如果您已经在存储库中拥有工作流,请单击新建工作流

  4. “选择工作流”页面显示了推荐的工作流模板选择。搜索“Python 应用程序”。

  5. 在“Python 应用程序”工作流上,单击配置

  6. 根据需要编辑工作流。例如,更改 Python 版本。

  7. 单击提交更改

    python-app.yml 工作流文件将添加到存储库的 .github/workflows 目录中。

指定 Python 版本

要在 GitHub 托管的运行器上使用预安装的 Python 或 PyPy 版本,请使用 setup-python 操作。此操作从每个运行器上的工具缓存中查找特定版本的 Python 或 PyPy,并将必要的二进制文件添加到 PATH 中,这些二进制文件将保留在作业的其余部分。如果工具缓存中没有预安装特定版本的 Python,则 setup-python 操作将从 python-versions 存储库下载并设置相应的版本。

使用 setup-python 操作是在 GitHub Actions 中使用 Python 的推荐方法,因为它确保了跨不同运行器和不同 Python 版本的一致行为。如果您使用的是自托管运行器,则必须安装 Python 并将其添加到 PATH 中。有关更多信息,请参阅 setup-python 操作

下表描述了每个 GitHub 托管运行器中工具缓存的位置。

UbuntuMacWindows
工具缓存目录/opt/hostedtoolcache/*/Users/runner/hostedtoolcache/*C:\hostedtoolcache\windows\*
Python 工具缓存/opt/hostedtoolcache/Python/*/Users/runner/hostedtoolcache/Python/*C:\hostedtoolcache\windows\Python\*
PyPy 工具缓存/opt/hostedtoolcache/PyPy/*/Users/runner/hostedtoolcache/PyPy/*C:\hostedtoolcache\windows\PyPy\*

如果您使用的是自托管运行器,则可以配置运行器以使用 setup-python 操作来管理您的依赖项。有关更多信息,请参阅 setup-python 自述文件中的 在自托管运行器中使用 setup-python

GitHub 支持语义版本控制语法。有关更多信息,请参阅“使用语义版本控制”和“语义版本控制规范”。

使用多个 Python 版本

以下示例使用作业的矩阵来设置多个 Python 版本。有关更多信息,请参阅“在工作流中运行作业的变体”。

YAML
name: Python package

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["pypy3.10", "3.9", "3.10", "3.11", "3.12", "3.13"]

    steps:
      - uses: actions/checkout@v4
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      # You can test your matrix by printing the current Python version
      - name: Display Python version
        run: python -c "import sys; print(sys.version)"

使用特定 Python 版本

您可以配置 Python 的特定版本。例如,3.12。或者,您可以使用语义版本语法获取最新的次要版本。此示例使用 Python 3 的最新次要版本。

YAML
name: Python package

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        # This is the version of the action for setting up Python, not the Python version.
        uses: actions/setup-python@v5
        with:
          # Semantic version range syntax or exact version of a Python version
          python-version: '3.x'
          # Optional - x64 or x86 architecture, defaults to x64
          architecture: 'x64'
      # You can test your matrix by printing the current Python version
      - name: Display Python version
        run: python -c "import sys; print(sys.version)"

排除版本

如果您指定了不可用的 Python 版本,setup-python 将失败并出现错误,例如:##[error]Version 3.7 with arch x64 not found。错误消息包含可用版本。

如果存在您不希望运行的 Python 配置,您也可以在工作流中使用 exclude 关键字。有关更多信息,请参阅“GitHub Actions 的工作流语法”。

YAML
name: Python package

on: [push]

jobs:
  build:

    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        python-version: ["3.9", "3.11", "3.13", "pypy3.10"]
        exclude:
          - os: macos-latest
            python-version: "3.11"
          - os: windows-latest
            python-version: "3.11"

使用默认 Python 版本

我们建议使用 setup-python 来配置工作流中使用的 Python 版本,因为它有助于使您的依赖项明确化。如果您不使用 setup-python,则在您调用 python 时,PATH 中设置的 Python 默认版本将用于任何 shell。GitHub 托管运行器之间的 Python 默认版本有所不同,这可能会导致意外更改或使用比预期更旧的版本。

GitHub 托管运行器描述
UbuntuUbuntu 运行器在 /usr/bin/python/usr/bin/python3 下安装了多个版本的系统 Python。与 Ubuntu 捆绑在一起的 Python 版本除了 GitHub 安装在工具缓存中的版本之外。
Windows排除工具缓存中的 Python 版本,Windows 没有附带等效版本的系统 Python。为了保持与其他运行器的一致行为,并允许在不使用 setup-python 操作的情况下开箱即用地使用 Python,GitHub 将工具缓存中的几个版本添加到 PATH 中。
macOSmacOS 运行器安装了多个版本的系统 Python,除了工具缓存中包含的版本之外。系统 Python 版本位于 /usr/local/Cellar/python/* 目录中。

安装依赖项

GitHub 托管运行器已安装 pip 包管理器。您可以使用 pip 从 PyPI 包注册表安装依赖项,然后再构建和测试代码。例如,以下 YAML 安装或升级 pip 包安装程序以及 setuptoolswheel 包。

您还可以缓存依赖项以加快工作流速度。有关更多信息,请参阅“缓存依赖项以加快工作流速度”。

YAML
steps:
- uses: actions/checkout@v4
- name: Set up Python
  uses: actions/setup-python@v5
  with:
    python-version: '3.x'
- name: Install dependencies
  run: python -m pip install --upgrade pip setuptools wheel

需求文件

更新 pip 后,典型的下一步是从 requirements.txt 安装依赖项。有关更多信息,请参阅 pip

YAML
steps:
- uses: actions/checkout@v4
- name: Set up Python
  uses: actions/setup-python@v5
  with:
    python-version: '3.x'
- name: Install dependencies
  run: |
    python -m pip install --upgrade pip
    pip install -r requirements.txt

缓存依赖项

您可以使用 setup-python 操作 缓存和恢复依赖项。

以下示例缓存 pip 的依赖项。

YAML
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
  with:
    python-version: '3.12'
    cache: 'pip'
- run: pip install -r requirements.txt
- run: pip test

默认情况下,setup-python 操作在整个存储库中搜索依赖项文件(对于 pip 为 requirements.txt,对于 pipenv 为 Pipfile.lock,对于 poetry 为 poetry.lock)。有关更多信息,请参阅 setup-python 自述文件中的“缓存包依赖项”。

如果您有自定义需求或需要更精细的缓存控制,则可以使用 cache 操作。Pip 在不同的位置缓存依赖项,具体取决于运行器的操作系统。您需要缓存的路径可能与上面的 Ubuntu 示例不同,具体取决于您使用的操作系统。有关更多信息,请参阅 cache 操作存储库中的 Python 缓存示例

测试您的代码

您可以使用与本地相同的命令来构建和测试代码。

使用 pytest 和 pytest-cov 进行测试

此示例安装或升级 pytestpytest-cov。然后运行测试并在 JUnit 格式中输出,同时代码覆盖率结果在 Cobertura 中输出。有关更多信息,请参阅 JUnitCobertura

YAML
steps:
- uses: actions/checkout@v4
- name: Set up Python
  uses: actions/setup-python@v5
  with:
    python-version: '3.x'
- name: Install dependencies
  run: |
    python -m pip install --upgrade pip
    pip install -r requirements.txt
- name: Test with pytest
  run: |
    pip install pytest pytest-cov
    pytest tests.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html

使用 Ruff 规范和/或格式化代码

以下示例安装或升级 ruff 并使用它来规范所有文件。有关更多信息,请参阅 Ruff

YAML
steps:
- uses: actions/checkout@v4
- name: Set up Python
  uses: actions/setup-python@v5
  with:
    python-version: '3.x'
- name: Install the code linting and formatting tool Ruff
  run: pipx install ruff
- name: Lint code with Ruff
  run: ruff check --output-format=github --target-version=py39
- name: Check code formatting with Ruff
  run: ruff format --diff --target-version=py39
  continue-on-error: true

格式化步骤已设置 continue-on-error: true。如果格式化步骤不成功,这将防止工作流失败。解决所有格式化错误后,您可以删除此选项,以便工作流捕获新问题。

使用 tox 运行测试

使用 GitHub Actions,您可以使用 tox 运行测试并将工作分散到多个作业中。您需要使用 -e py 选项调用 tox 以选择 PATH 中的 Python 版本,而不是指定特定版本。有关更多信息,请参阅 tox

YAML
name: Python package

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        python: ["3.9", "3.11", "3.13"]

    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install tox and any other packages
        run: pip install tox
      - name: Run tox
        # Run tox using the version of Python in `PATH`
        run: tox -e py

将工作流数据打包为工件

您可以在工作流完成后上传工件以进行查看。例如,您可能需要保存日志文件、核心转储、测试结果或屏幕截图。有关更多信息,请参阅“将数据存储和共享到工作流”。

以下示例演示了如何使用 upload-artifact 操作来存档运行 pytest 的测试结果。有关更多信息,请参阅 upload-artifact 操作

YAML
name: Python package

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

    steps:
      - uses: actions/checkout@v4
      - name: Setup Python # Set Python version
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      # Install pip and pytest
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install pytest
      - name: Test with pytest
        run: pytest tests.py --doctest-modules --junitxml=junit/test-results-${{ matrix.python-version }}.xml
      - name: Upload pytest test results
        uses: actions/upload-artifact@v4
        with:
          name: pytest-results-${{ matrix.python-version }}
          path: junit/test-results-${{ matrix.python-version }}.xml
        # Use always() to always run this step to publish test results when there are test failures
        if: ${{ always() }}

发布到 PyPI

您可以在 CI 测试通过后配置工作流以将您的 Python 包发布到 PyPI。本节演示了如何使用 GitHub Actions 在每次发布版本时将您的包上传到 PyPI。有关更多信息,请参阅“在存储库中管理版本”。

以下示例工作流使用 受信任发布 对 PyPI 进行身份验证,从而无需手动配置 API 令牌。

YAML
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# GitHub recommends pinning actions to a commit SHA.
# To get a newer version, you will need to update the SHA.
# You can also reference a tag or branch, but the action may change without warning.

name: Upload Python Package

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  release-build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"

      - name: Build release distributions
        run: |
          # NOTE: put your own distribution build steps here.
          python -m pip install build
          python -m build

      - name: Upload distributions
        uses: actions/upload-artifact@v4
        with:
          name: release-dists
          path: dist/

  pypi-publish:
    runs-on: ubuntu-latest

    needs:
      - release-build

    permissions:
      # IMPORTANT: this permission is mandatory for trusted publishing
      id-token: write

    # Dedicated environments with protections for publishing are strongly recommended.
    environment:
      name: pypi
      # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
      # url: https://pypi.ac.cn/p/YOURPROJECT

    steps:
      - name: Retrieve release distributions
        uses: actions/download-artifact@v4
        with:
          name: release-dists
          path: dist/

      - name: Publish release distributions to PyPI
        uses: pypa/gh-action-pypi-publish@6f7e8d9c0b1a2c3d4e5f6a7b8c9d0e1f2a3b4c5d

有关此工作流的更多信息,包括所需的 PyPI 设置,请参阅 在 PyPI 中配置 OpenID Connect