PDM 高级用法实战:自动化测试、持续集成、Docker 与 Monorepo 集成指南 📅 发布时间:2026/9/16 18:49:50 👁 浏览次数: PDM 高级用法实战自动化测试、持续集成、Docker 与 Monorepo 集成指南【免费下载链接】pdmA modern Python package and dependency manager supporting the latest PEP standards项目地址: https://gitcode.com/GitHub_Trending/pd/pdm本篇技术指南以 PDM 官方文档《Advanced Usage》为核心骨架系统讲解如何把 PDM 深度接入工程化的日常工作流包括用 tox / nox 驱动自动化测试、在 GitHub Actions 等 CI 平台中安装与运行 PDM、用多阶段 Dockerfile 构建镜像、以单一pdm.lock管理 monorepo 多子包以及用 pre-commit 钩子守护锁文件与依赖导出的正确性。读完本文你将掌握这些高级场景下的完整配置模板、底层机制与踩坑规避方案直接可复制到实际项目中使用。自动化测试把 PDM 接入 tox 与 noxPDM 自身不提供测试运行器但与主流自动化测试框架tox、nox的集成非常顺畅。核心要点是让 PDM 识别并使用测试框架创建的虚拟环境中的解释器从而把依赖安装resolve install的职责交给 PDM把测试执行的职责交给测试框架。使用 tox 作为测试 runnertox 非常适合针对多个 Python 版本或依赖组合进行测试。下面是一份将 PDM 与 tox 集成的tox.ini模板[tox] env_list py{36,37,38},lint [testenv] setenv PDM_IGNORE_SAVED_PYTHON1 deps pdm commands pdm install --dev pytest tests [testenv:lint] deps pdm commands pdm install -G lint flake8 src/这份配置有四个关键设计点缺一不可PDM_IGNORE_SAVED_PYTHON1环境变量这是整个集成的核心。PDM 会把项目使用的 Python 解释器路径保存在项目根目录的.pdm-python文件中并在下次解析时优先复用该路径。从源码看src/pdm/project/core.py#L330 中resolve_interpreter()会检查环境变量PDM_IGNORE_SAVED_PYTHON一旦其为真就跳过.pdm-python中保存的解释器转而去解析 tox 激活的虚拟环境中的 Python。这样 PDM 就能跟随 tox 为每个 testenv 创建的 venv而不是固执地使用上一次保存的全局解释器。deps pdm让 tox 在创建 testenv 后先安装 PDM保证pdm命令在环境内可用。pdm install/pdm install -G lint将依赖安装完全交给 PDM。其中-G lint是当前版本的 dependency group 写法对应 pyproject.toml 中的[dependency-groups]或 PDM 早期版本的[tool.pdm.dev-dependencies]早期文档中的pdm install --dev在 2.x 中推荐改为pdm install -G dev。PDM 会依据pdm.lock把依赖装进当前激活的 tox venv。isolated_build与passenv应像示例那样显式配置否则 PDM 在 tox 的隔离构建环境中可能无法正常工作。让 tox 使用 PDM 的虚拟环境python.use_venv要使用 tox 创建的虚拟环境必须确保已开启pdm config python.use_venv true。该配置项在 src/pdm/project/config.py#L206 中定义默认值即为true环境变量PDM_USE_VENV可覆盖。开启后PDM 的resolve_interpreter()会优先寻找并复用环境变量VIRTUAL_ENV/CONDA_PREFIX指向的激活环境其次查找项目关联的虚拟环境详见 src/pdm/project/core.py#L342-L359。一旦 PDM 把依赖安装进 tox 的虚拟环境在 testenv 中就可以直接运行pytest tests/而无需pdm run pytest tests/因为该 venv 本身已包含全部依赖与 pytest 可执行文件。测试命令中禁止修改锁文件务必不要在测试命令中运行pdm add/pdm remove/pdm update/pdm lock否则pdm.lock会被意外改写导致 CI 与本地锁文件漂移。额外的依赖请通过 tox 的deps配置提供而不是在测试执行时临时变更项目依赖。用 tox-pdm 插件精简配置要摆脱上述手工约束官方推荐使用 tox 插件 [tox-pdm]。安装方式pip install tox-pdm或者作为项目开发依赖安装pdm add --dev tox-pdm安装后tox.ini可以大幅精简直接用groups指定 PDM 的依赖分组[tox] env_list py{36,37,38},lint [testenv] groups dev commands pytest tests [testenv:lint] groups lint commands flake8 src/值得说明的是PDM 仓库自身的tox.ini正是这种写法envlist py3{10,11,12,13,14}、passenv LD_PRELOAD、isolated_build Truetestenv 中groups test、commands test {posargs}。你可以直接对照 tox.ini 学习真实项目的落地方式。使用 nox 作为 runnernox 是另一款自动化测试工具与 tox 最大的区别是nox 使用标准的 Python 文件noxfile.py作为配置而非 ini 格式。PDM 在 nox 中的接入更加直接示例noxfile.py如下import os import nox os.environ.update({PDM_IGNORE_SAVED_PYTHON: 1}) nox.session def tests(session): session.run_always(pdm, install, -G, test, externalTrue) session.run(pytest) nox.session def lint(session): session.run_always(pdm, install, -G, lint, externalTrue) session.run(flake8, --import-order-style, google)使用要点同样需要设置PDM_IGNORE_SAVED_PYTHON让 PDM 正确拾取 nox 虚拟环境中的 Python 解释器session.run_always(pdm, install, -G, test, externalTrue)表示每次会话开始时都让 PDM 安装test分组依赖externalTrue表示允许执行外部命令确保pdm在系统PATH中可用运行 nox 前确认配置项python.use_venv为 true默认即为 true以启用虚拟环境复用。关于 PEP 582__pypackages__目录的注意事项默认情况下通过pdm run运行工具时__pypackages__目录会暴露给该程序及其创建的所有子进程。这意味着由这些工具创建的虚拟环境如 tox/nox 内部再创建的 venv也能看见__pypackages__中的包在某些场景下会导致意外行为例如依赖解析到 PEP 582 目录中的包而不是新环境中的包。针对 nox可以通过在noxfile.py中移除PYTHONPATH来规避os.environ.pop(PYTHONPATH, None)而 tox 本身不会把PYTHONPATH传递给测试会话因此不存在该问题。此外官方还建议把 nox 和 tox 安装到各自的 pipx 独立环境中pipx install nox、pipx install tox这样它们不属于任何项目自然也不会受 PEP 582 包的影响。在持续集成中使用 PDMPython 版本要求与安装策略在 CI 中接入 PDM 只需牢记一点PDM 自身对解释器版本有要求安装 PDM 所用的 Python 可以且应当区别于目标测试解释器。当前仓库的 docs/index.md 明确 PDM 要求 Python 3.10较早期版本要求 3.7文档中的表述以仓库现状为准。因此如果你的项目需要测试 Python 3.73.9 等较低版本PDM 应安装在更高版本的 Python 上再用目标解释器运行测试。GitHub Actions 工作流示例如果你使用 GitHub Actions推荐使用 setup-pdm 官方 action 来安装 PDM。以下是一个完整的工作流可平滑迁移到其他 CI 平台Testing: runs-on: ${{ matrix.os }} strategy: matrix: python-version: [3.9, 3.10, 3.11, 3.12, 3.13] os: [ubuntu-latest, macOS-latest, windows-latest] steps: - uses: actions/checkoutv4 - name: Set up PDM uses: pdm-project/setup-pdmv4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | pdm sync -d -G testing - name: Run Tests run: | pdm run -v pytest tests要点解析pdm sync直接从pdm.lock同步当前工作集而不是重新解析依赖速度更快且结果可复现-G testing指定同步testing分组-d表示同时包含默认 dev 组较新版本推荐直接写-G testing并配合--no-default等选项精确控制分组详见 src/pdm/cli/commands/sync.py 中对GroupSelection的解析。pdm run -v pytest tests在 PDM 管理的环境中执行测试-v输出详细日志。setup-pdm的一个已知处理GitHub Actions 的 Ubuntu 虚拟环境存在一个已知兼容性问题——如果 PDM 并行安装失败需要把parallel_install设为false或设置环境变量LD_PRELOAD/lib/x86_64-linux-gnu/libgcc_s.so.1。pdm-project/setup-pdmaction 已内置处理该问题若你自行安装 PDM则需手动应对。CI 无用户环境下的缓存目录权限问题如果 CI 脚本运行时没有设置合适的用户例如以 root 之外的匿名身份运行PDM 创建缓存目录时可能遇到权限错误。解决办法是自行指定一个可写的HOME目录export HOME/tmp/home使用 PDM 构建多阶段 DockerfilePDM 天然适合先构建、后运行的多阶段镜像策略在 builder 阶段把项目与依赖安装到虚拟环境再将整个环境目录复制进最终运行镜像。官方模板如下ARG PYTHON_BASE3.10-slim # build stage FROM python:$PYTHON_BASE AS builder # install PDM RUN pip install -U pdm # disable update check ENV PDM_CHECK_UPDATEfalse # copy files COPY pyproject.toml pdm.lock README.md /project/ COPY src/ /project/src # install dependencies and project into the local packages directory WORKDIR /project RUN pdm install --check --prod --no-editable # run stage FROM python:$PYTHON_BASE # retrieve packages from build stage COPY --frombuilder /project/.venv/ /project/.venv ENV PATH/project/.venv/bin:$PATH # set command/entrypoint, adapt to fit your needs COPY src /project/src CMD [python, src/__main__.py]各指令的设计意图ENV PDM_CHECK_UPDATEfalse禁用 PDM 的版本更新检查对应配置项check_update可用环境变量PDM_CHECK_UPDATE覆盖见 src/pdm/project/config.py#L123 与 src/pdm/core.py#L290 中is_in_zipapp()之外的启动检查逻辑避免每次构建联网检查、也避免输出干扰日志。RUN pdm install --check --prod --no-editable--check在安装前校验pdm.lock与pyproject.toml是否一致若不一致src/pdm/cli/commands/lock.py#L86-L104 中的--check分支会让命令以退出码 1 失败从而在镜像构建阶段就暴露锁文件过期问题--prod仅安装生产依赖剔除 dev/test 等非必需分组缩小镜像体积--no-editable以非可编辑模式安装项目自身editable 安装依赖源码目录容器中不利于固化产物。由于 PDM 默认在项目根目录创建.venv配置项venv.in_project默认true见 src/pdm/project/config.py#L266-L271builder 阶段只需COPY --frombuilder /project/.venv/ /project/.venv即可把完整依赖链带到运行阶段并通过ENV PATH/project/.venv/bin:$PATH让容器直接使用环境内的 Python 与工具。使用 PDM 管理 monorepoPDM 支持在单个项目内维护多个子包每个子包拥有独立的pyproject.toml彼此可以作为依赖而整个仓库只需一份pdm.lock锁定全部依赖。实现步骤非常简单。项目根目录project/pyproject.toml中通过 dependency groups 把子包以可编辑方式引入[dependency-groups] dev [ -e file:///${PROJECT_ROOT}/packages/foo-core, -e file:///${PROJECT_ROOT}/packages/foo-cli, -e file:///${PROJECT_ROOT}/packages/foo-app, ]其中-e表示可编辑安装${PROJECT_ROOT}是 PDM 支持的内置变量指向项目根目录保证路径在不同机器/CI 环境下依然有效。各子包在自身的pyproject.toml中声明对兄弟包的依赖packages/foo-cli/pyproject.toml[project] dependencies [foo-core]packages/foo-app/pyproject.toml[project] dependencies [foo-core]之后在项目根目录运行pdm installPDM 会解析所有子包的依赖并生成一份包含全部依赖的pdm.lock所有子包都会以可编辑模式安装到环境中开发时对任一子包的修改即时生效。仓库测试夹具中的 tests/fixtures/projects/test-monorepo含core、package_a、package_b三个子包及根级pyproject.toml就是这一模式的真实样例可对照研读更详细的 workspace 行为说明参见 docs/usage/workspace.md。用 pre-commit 钩子守护工程质量PDM 本身就在内部 QA 中使用pre-commit钩子同时对外暴露了三个可直接复用的钩子既能本地运行也能接入 CI 流水线。钩子一pdm-export导出requirements.txt该钩子封装了pdm export命令并透传任意合法参数。典型用途是在 CI 中确保仓库里提交的requirements.txt与pdm.lock实际内容保持一致。# export python requirements - repo: https://github.com/pdm-project/pdm rev: 2.x.y # a PDM release exposing the hook hooks: - id: pdm-export # command arguments, e.g.: args: [-o, requirements.txt, --without-hashes] files: ^pdm.lock$配置说明args中的-o requirements.txt指定输出文件--without-hashes等价于--no-hashes不输出校验哈希这两个选项在 src/pdm/cli/commands/export.py 中均有定义此外还支持-f/--formatrequirements或pylock、--no-markers、--no-extras、--pyproject、--expandvars等参数files: ^pdm.lock$表示只有当pdm.lock变更时才触发该钩子避免无谓的重复导出。钩子二pdm-lock-check校验锁文件与 pyproject 同步该钩子封装pdm lock --check在 CI 中确保pyproject.toml的依赖发生增删改时pdm.lock也必须同步更新。- repo: https://github.com/pdm-project/pdm rev: 2.x.y # a PDM release exposing the hook hooks: - id: pdm-lock-check其底层行为可追溯到 src/pdm/cli/commands/lock.py#L86-L104--check模式调用actions.check_lockfile()若锁文件过期则输出 Lockfile is out of date 并以退出码 1 结束从而使 pre-commit / CI 任务失败。钩子三pdm-sync同步当前工作集该钩子封装pdm sync在你 checkout 或 merge 分支后确保当前工作集与pdm.lock保持同步。如果想使用系统凭据存储可在additional_dependencies中加入keyring- repo: https://github.com/pdm-project/pdm rev: 2.x.y # a PDM release exposing the hook hooks: - id: pdm-sync additional_dependencies: - keyringpdm sync的实现位于 src/pdm/cli/commands/sync.py它在执行前先调用actions.check_lockfile(project)校验锁文件再依据GroupSelection精确同步所选分组支持--dry-run、--clean移除多余包、--reinstall强制重装等参数可作为团队协作时的自动对齐防线。小结本文围绕 PDM 的高阶用法展开覆盖了自动化测试tox / nox / tox-pdm、持续集成Python 版本策略、GitHub Actions 工作流、LD_PRELOAD 与 HOME 权限处理、多阶段 Dockerfile 构建、monorepo 多子包管理与三个 pre-commit 钩子。所有配置模板均可直接落地底层行为也都能在仓库源码如 src/pdm/project/core.py、src/pdm/project/config.py、src/pdm/cli/commands/lock.py、src/pdm/cli/commands/sync.py、src/pdm/cli/commands/export.py中找到实现依据。将 PDM 的解析、锁定与同步能力嵌入测试、构建与协作流程正是它在包管理之外提升工程化效率的核心价值。【免费下载链接】pdmA modern Python package and dependency manager supporting the latest PEP standards项目地址: https://gitcode.com/GitHub_Trending/pd/pdm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考