PDM 的内部实现(1)

PDM 的内部实现(1)

💡 原文中文,约6400字,阅读约需16分钟。
📝

内容提要

这篇文章介绍了PDM的lockfile,它是一个记录项目依赖的文件,用于提供可复现的Python环境。PDM生成lockfile的方式是根据当前环境和Python版本进行依赖解析。lockfile中的requires-python字段定义了包支持的Python版本范围。文章还介绍了markers的概念,用于限制包的安装条件。PDM的lockfile记录了每个包的元数据,以版本为单位记录,并支持多种不同的lock策略。

🔎

延伸解读

跨版本锁定与当前环境锁定的区别

PDM 的 lockfile 采用跨版本锁定策略,旨在让同一份 lockfile 能在所有 requires-python 指定的 Python 版本上工作。这与 pip 等工具仅针对当前环境解析不同。因此,即使你当前使用 Python 3.10,若项目声明 requires-python = ">=3.8",PDM 也会拒绝仅支持 3.9+ 的包版本,以确保兼容性。这种设计提高了可复现性,但可能导致某些新版本包无法安装。

requires-python 对依赖解析的关键影响

requires-python 字段定义了包支持的 Python 版本范围,在 PDM 的依赖解析中起决定性作用。PDM 会确保所有依赖的 requires-python 范围是项目 requires-python 范围的超集。如果某个依赖不支持项目声明的最低 Python 版本,解析就会失败。因此,项目中的 requires-python 必须谨慎设置,它直接决定了可用的依赖版本集合。

markers 的条件传递与合并逻辑

markers 用于限制包的安装条件,如平台或 Python 版本。在跨版本 lock 中,PDM 会记录完整的 marker 表达式,并处理条件传递:若父包有条件,其依赖也继承相同条件;若依赖有多个来源,条件则用或逻辑合并。最终,每个包的 markers 字段记录合并后的结果,安装时直接求值,无需追溯上游条件。这简化了安装逻辑,但要求解析时正确合并条件。

元数据记录的假设与性能权衡

PDM 的 lockfile 以版本为单位记录元数据,并假设同一版本的不同文件元数据相同,且每个版本包含所有平台的文件。这并非规范要求,但为了性能,PDM 选择了这一折中。实际上,不同文件可能有不同依赖,sdist 的元数据甚至可能变化。这种假设在大多数情况下成立,但可能导致某些边缘情况解析失败。Poetry 和 uv 也采用类似策略。

❓

Q&A

PDM的lockfile有什么作用?

PDM的lockfile用于记录项目的依赖和版本号,提供可复现的Python环境。

如何生成PDM的lockfile?

PDM通过运行pdm lock命令生成lockfile,并在运行pdm install时确保lockfile存在与有效。

什么是requires-python字段,它有什么重要性?

requires-python字段定义了包支持的Python版本范围,对依赖解析至关重要。

PDM的lockfile如何处理条件依赖?

PDM使用markers来限制包的安装条件,条件依赖的依赖也应遵循相同条件。

PDM的lockfile支持哪些锁定策略?

PDM的lockfile支持多种不同的锁定策略,具体策略将在后续文章中介绍。

PDM在依赖解析中如何处理不同Python版本的兼容性?

PDM会确保lockfile能在所有指定的Python版本上工作,而不仅仅是当前使用的版本。

🏷️

标签

➡️

继续阅读