高级用法
自动化测试
使用 Tox 作为运行器
Tox 是一个很棒的工具,用于在多个 Python 版本或依赖集上进行测试。您可以配置一个 tox.ini,如下所示,以将您的测试与 PDM 集成:
[tox]env_list = py{36,37,38},lint[testenv]setenv =PDM_IGNORE_SAVED_PYTHON="1"deps = pdmcommands =pdm install --devpytest tests[testenv:lint]deps = pdmcommands =pdm install -G lintflake8 src/
要使用 Tox 创建的虚拟环境,您应该确保已设置 pdm config python.use_venv true。然后 PDM 将从 pdm lock 将依赖项安装到虚拟环境中。在专用的 venv 中,您可以直接运行工具,例如 pytest tests/,而不是 pdm run pytest tests/。
您还应确保在测试命令中不要运行 pdm add/pdm remove/pdm update/pdm lock,否则 pdm lock 文件将被意外修改。可以使用 deps 配置提供额外的依赖项。此外,isolated_build 和 passenv 配置应按上述示例设置,以使 PDM 正常工作。
为了摆脱这些限制,有一个 Tox 插件 tox-pdm 可以简化使用。您可以通过以下方式安装它:
pip install tox-pdm
或者,
pdm add --dev tox-pdm
然后,您可以使 tox.ini 更加整洁,如下所示:
[tox]env_list = py{36,37,38},lint[testenv]groups = devcommands =pytest tests[testenv:lint]groups = lintcommands =flake8 src/
查看 项目的 README 以获取详细指南。
使用 Nox 作为运行器
Nox 是另一个用于自动化测试的优秀工具。与 tox 不同,Nox 使用标准的 Python 文件进行配置。
在 Nox 中使用 PDM 更容易,以下是 noxfile.py 的示例:
```python hl_lines=”4” import os import nox
os.environ.update({“PDM_IGNORE_SAVED_PYTHON”: “1”})
@nox.session def tests(session): session.run_always(‘pdm’, ‘install’, ‘-G’, ‘test’, external=True) session.run(‘pytest’)
@nox.session def lint(session): session.run_always(‘pdm’, ‘install’, ‘-G’, ‘lint’, external=True) session.run(‘flake8’, ‘—import-order-style’, ‘google’)
请注意,应设置 `PDM_IGNORE_SAVED_PYTHON`,以便 PDM 可以正确地在虚拟环境中获取 Python。还要确保 `pdm` 在 `PATH` 中可用。在运行 nox 之前,您还应确保配置项 `python.use_venv` 为 true,以启用 venv 重用。### 关于 PEP 582 `__pypackages__` 目录默认情况下,如果您通过 [`pdm run`](../reference/cli.md#run) 运行工具,`__pypackages__` 将被程序及其创建的所有子进程看到。这意味着由这些工具创建的虚拟环境也了解 `__pypackages__` 内的包,这在某些情况下会导致意外行为。对于 `nox`,您可以通过在 `noxfile.py` 中添加一行来避免这个问题:```pythonos.environ.pop("PYTHONPATH", None)
对于 tox,PYTHONPATH 不会传递给测试会话,所以这不会成为问题。此外,建议让 nox 和 tox 位于它们自己的 pipx 环境中,这样您就不需要为每个项目安装。在这种情况下,PEP 582 包也不会成为问题。
在持续集成中使用 PDM
只需记住一件事 —— PDM 无法在 Python < 3.7 上安装,所以如果您的项目需要在这些 Python 版本上进行测试,您必须确保 PDM 已在正确的 Python 版本上安装,这可能与特定作业/任务运行的目标 Python 版本不同。
幸运的是,如果您正在使用 GitHub Action,有 pdm-project/setup-pdm 可以让这个过程变得更容易。以下是一个 GitHub Actions 的示例工作流程,您可以将其适应于其他 CI 平台。
Testing:runs-on: ${{ matrix.os }}strategy:matrix:python-version: [3.7, 3.8, 3.9, '3.10', '3.11']os: [ubuntu-latest, macOS-latest, windows-latest]steps:- uses: actions/checkout@v3- name: Set up PDMuses: pdm-project/setup-pdm@v3with:python-version: ${{ matrix.python-version }}- name: Install dependenciesrun: |pdm sync -d -G testing- name: Run Testsrun: |pdm run -v pytest tests
!!! 重要 “提示”
对于 GitHub Action 用户,Ubuntu 虚拟环境上存在一个已知的兼容性问题。
如果在那台机器上 PDM 并行安装失败,您应该将 parallel_install 设置为 false,或者设置环境变量 LD_PRELOAD=/lib/x86_64-linux-gnu/libgcc_s.so.1。
pdm-project/setup-pdm 操作已经处理了这个问题。
!!! 注意 如果您的 CI 脚本在没有正确设置用户的情况下运行,当 PDM 尝试创建其缓存目录时,您可能会遇到权限错误。 要解决这个问题,您可以自己设置 HOME 环境变量,到一个可写的目录,例如:
```bashexport HOME=/tmp/home```
在多阶段 Dockerfile 中使用 PDM
可以在多阶段 Dockerfile 中使用 PDM,首先将项目和依赖项安装到 __pypackages__ 中,然后将该文件夹复制到最终阶段,并添加到 PYTHONPATH。
ARG PYTHON_BASE=3.10-slim# 构建阶段FROM python:$PYTHON_BASE AS builder# 安装 PDMRUN pip install -U pdm# 禁用更新检查ENV PDM_CHECK_UPDATE=false# 复制文件COPY pyproject.toml pdm.lock README.md /project/COPY src/ /project/src# 将依赖项和项目安装到本地包目录WORKDIR /projectRUN pdm install --check --prod --no-editable# 运行阶段FROM python:$PYTHON_BASE# 从构建阶段检索包COPY --from=builder /project/.venv/ /project/.venvENV PATH="/project/.venv/bin:$PATH"# 设置命令/入口点,适应您的需求COPY src /project/srcCMD ["python", "src/__main__.py"]
使用 PDM 管理单体仓库
使用 PDM,您可以在单个项目中拥有多个子包,每个子包都有自己的 pyproject.toml 文件。并且您可以创建只有一个 pdm.lock 文件来锁定所有依赖项。子包可以相互作为它们的依赖项。要实现这一点,请按照以下步骤操作:
project/pyproject.toml:
[tool.pdm.dev-dependencies]dev = ["-e file:///${PROJECT_ROOT}/packages/foo-core","-e file:///${PROJECT_ROOT}/packages/foo-cli","-e file:///${PROJECT_ROOT}/packages/foo-app",]
packages/foo-cli/pyproject.toml:
[project]dependencies = ["foo-core"]
packages/foo-app/pyproject.toml:
[project]dependencies = ["foo-core"]
现在,在项目根目录下运行 pdm install,您将得到一个锁定所有依赖项的 pdm.lock。所有子包将以可编辑模式安装。
查看 🚀 示例仓库 了解更多详情。
pre-commit 的钩子
pre-commit 是一个强大的框架,用于集中管理 git 钩子。PDM 已经使用 pre-commit 钩子 进行其内部质量检查。PDM 还公开了几个可以本地或在 CI 管道中运行的钩子。
导出 requirements.txt
此钩子包装了命令 pdm export 以及任何有效的参数。它可以用作钩子(例如,用于 CI),以确保您将要签入代码库的 requirements.txt 反映了 pdm lock 的实际内容。
# 导出 Python 需求- repo: https://github.com/pdm-project/pdmrev: 2.x.y # 公开钩子的 PDM 版本hooks:- id: pdm-export# 命令参数,例如:args: ['-o', 'requirements.txt', '--without-hashes']files: ^pdm.lock$
检查 pdm.lock 是否与 pyproject.toml 保持最新
此钩子包装了命令 pdm lock --check 以及任何有效的参数。它可以用作钩子(例如,用于 CI),以确保每当 pyproject.toml 有依赖项被添加/更改/删除时,pdm.lock 也是最新的。
- repo: https://github.com/pdm-project/pdmrev: 2.x.y # 公开钩子的 PDM 版本hooks:- id: pdm-lock-check
将当前工作集与 pdm.lock 同步
此钩子包装了命令 pdm sync 以及任何有效的参数。它可以用作钩子,以确保每当您检出或合并一个分支时,您的当前工作集与 pdm.lock 同步。如果您想要使用系统的凭证存储,请在 additional_dependencies 中添加 keyring。
- repo: https://github.com/pdm-project/pdmrev: 2.x.y # 公开钩子的 PDM 版本hooks:- id: pdm-syncadditional_dependencies:- keyring
