news 2026/9/29 6:21:24

Hatch 构建配置完全指南:从文件选择到可复现构建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Hatch 构建配置完全指南:从文件选择到可复现构建
  • 开发工具
  • 构建工具

【免费下载链接】hatch

Modern, extensible Python project management

项目地址:https://gitcode.com/gh_mirrors/ha/hatch
点击查看免费下载

本篇技术指南以 Hatch 项目的 docs/config/build.md 为骨架,系统讲解构建配置的核心主题:如何通过tool.hatch.build与tool.hatch.build.targets两个 TOML 配置表精确控制打包文件的选择、路径重写、构建目标与构建钩子,并结合构建后端 hatchling 的源码(config.py、plugin/interface.py)深入解析每个配置项的底层实现。读完本文,你将掌握 Hatch 构建系统的完整配置语法、文件选择策略的优先级关系、可复现构建原理、开发模式(dev mode)机制以及构建钩子的执行顺序,并能在自己的项目中直接落地使用。

构建目标的定义方式

构建目标(Build Targets)是 Hatch 构建配置的核心概念。每个构建目标对应一种分发产物,在pyproject.toml中表示为tool.hatch.build.targets下的一个节(section):

[tool.hatch.build.targets.<TARGET_NAME>]

其中<TARGET_NAME>是构建器插件(builder plugin)注册的名字。Hatchling 内置了三个构建目标:wheel、sdist 和 custom,分别对应 Python wheel 包、源码发行包和自定义构建逻辑。任何第三方构建器插件(如hatch-aws、hatch-zipped-directory,见 builder 插件参考)都可以通过 hooks.py 中注册的hatch_register_builder钩子提供新的构建目标。

虽然不建议,但你也可以在tool.hatch.build表中定义全局配置,目标级配置中的同名键会覆盖全局配置。这一点在源码中体现得很明确:BuilderConfig的各个属性解析器(如ignore_vcs、skip_excluded_dirs、reproducible等)都采用同一套模式——先检查target_config中是否存在该键,存在则使用目标级配置,否则回退到build_config中的全局配置,具体可见 config.py 中skip_excluded_dirs与ignore_vcs的实现。

与 Python 打包生态兼容的构建系统声明

要让项目与更广泛的 Python 打包生态 兼容,必须在pyproject.toml顶部按 PEP 517 定义构建系统:

[build-system] requires = ["hatchling"] build-backend = "hatchling.build"

这里声明的hatchling版本将用于构建所有目标。hatchling 是一个符合标准的构建后端,同时它本身也是 Hatch 的依赖项。Hatchling 对 PEP 517 和 PEP 660 的支持保证了与其他构建工具(pip、tox、CI 等)的互操作性。

文件选择(File selection)

构建的本质是把哪些文件放进分发产物。Hatch 提供了一整套由粗到细的文件选择机制,理解它们的优先级是正确配置的关键。从源码看,文件选择的核心裁决逻辑位于BuilderConfig.include_path()(config.py):一个相对路径最终能否被包含,取决于它是否是构建产物(build artifact)、是否符合artifacts模式、是否被排除、以及是否命中include模式。

VCS 忽略规则

默认情况下,Hatch 会尊重项目根目录或其父目录中找到的第一个.gitignore或.hgignore文件。将ignore-vcs设为true可禁用这一行为:

[tool.hatch.build.targets.sdist] ignore-vcs = true

注意:对于.hgignore文件,只支持 glob 语法。这一约束在源码中有对应实现——load_vcs_exclusion_patterns 读取.hgignore时会解析syntax: glob指令,只有 glob 模式下的行才会被采纳,而.gitignore则整文件按 Git 模式格式(gitignore 模式格式)读取。VCS 忽略文件的查找由locate_file完成,边界条件为.git或.hg目录(vcs_exclusion_files)。另外,default_global_exclude会默认排除*.py[cdo]和dist目录(config.py)。

模式匹配:include 与 exclude

include和exclude选项可以精确指定每个构建要打包的文件,其中exclude优先级更高。每个条目都是一个 Git 风格 glob 模式(gitignore 模式格式)。

例如以下配置:

[tool.hatch.build.targets.sdist] include = [ "pkg/*.py", "/tests", ] exclude = [ "*.json", "pkg/_compat.py", ]

效果是:排除所有.json扩展名文件;包含项目根下tests目录的全部内容,以及根下pkg目录中直接位于其下的所有.py文件(_compat.py除外)。/tests开头的/表示匹配仅限项目根目录,这是 Git 风格模式中"锚定"到根目录的语法。

在源码层面,include与exclude都会转换为pathspec.GitIgnoreSpec(include_spec、exclude_spec),并支持目标级覆盖全局级。所有模式条目必须是字符串,空字符串会被拒绝。另外值得注意的是:当设置了packages时,源码会为每个包自动追加/{relative_path}/形式的 include 模式,确保包目录必然被遍历。

Artifacts:绕过 VCS 忽略的产物

如果要包含被 VCS 忽略的文件(例如由 构建钩子 生成的文件),可以使用artifacts选项。它在语义上与include等价,但有两点关键差异:

  • exclude不影响 artifacts;
  • artifacts 只能用更明确的路径或!取反操作符来排除,且使用!时,取反模式必须放在更通用模式之后。
[tool.hatch.build.targets.wheel] artifacts = [ "*.so", "*.dll", "!/foo/*.so", ]

在include_path()的裁决顺序中,path_is_artifact()的判定优先级高于排除逻辑(config.py),这正是"artifacts 不受 exclude 影响"的源码依据。构建钩子运行时写入build_data["artifacts"]的路径则通过set_build_data生成build_artifact_spec生效(config.py)。

显式选择:only-include

only-include选项可阻止从项目根开始的目录遍历,只选择特定的相对路径(目录或文件)。使用该选项会忽略任何已定义的include模式:

[tool.hatch.build.targets.sdist] only-include = ["pkg", "tests/unit"]

从源码看,only_include的默认值是default_only_include()或packages配置(config.py),路径必须是相对路径(以~或..开头的路径会被拒绝),且不允许重复。当设置了only_include时,recurse_selected_project_files会走recurse_explicit_files分支而不是全量遍历(plugin/interface.py),但显式选择的文件仍会经过include_path(..., explicit=True)的过滤,即 exclude 依然生效。

Packages:打包 src 布局的利器

packages选项在语义上与only-include等价(且only-include优先级更高),区别在于:发行路径会被折叠为只包含最后一个路径组件。

例如,要打包存放在src目录下的包foo:

[tool.hatch.build.targets.wheel] packages = ["src/foo"]

源码中packages配置会被规范化排序(config.py),并且packages本身依赖于sources机制——packages = ["src/foo"]对wheel目标而言等价于:

[tool.hatch.build.targets.wheel] only-include = ["src/foo"] sources = ["src"]

强制包含:force-include

force-include选项允许从文件系统的任意位置选择特定文件或目录,并映射到期望的相对发行路径:

[tool.hatch.build.targets.wheel.force-include] "../artifacts" = "pkg" "~/lib.h" = "pkg/lib.h"

例如,项目根旁有一个包含lib.so的artifacts目录,家目录中还有一个lib.h,上面的配置会把两个文件都打包进发行版的pkg目录。使用时有以下注意点:

  • 文件必须精确映射到期望路径,而不是映射到目录;
  • 目录源的内容会被递归包含;
  • 要将目录内容直接映射到根目录,使用/(正斜杠);
  • 源不存在会直接报错。

从源码看,force_include会通过normalize_inclusion_map把~展开、把相对路径解析为基于项目根的绝对路径(config.py);recurse_forced_files(plugin/interface.py)负责遍历并生成IncludedFile,且强制包含的文件不受 include/exclude/only-packages 过滤。警告:试图覆盖其他文件选择选项已包含的任何文件路径会报错。这一约束在 wheel 归档阶段由_WheelZipFile.open检查实现——同路径二次写入会抛出 ValueError(wheel.py)。

默认文件选择

如果未提供任何文件选择选项,则包含哪些文件由各 构建目标 自行决定。例如 wheel 目标默认会查找包目录,sdist 目标默认包含项目根下的文件,详见 wheel 与 sdist 文档。

排除包之外的文件:only-packages

如果想排除不在 Python 包内的非 artifacts 文件,将only-packages设为true:

[tool.hatch.build.targets.wheel] only-packages = true

其语义在include_path()的第一行条件中体现:not (self.only_packages and not is_package)——当启用only-packages时,凡不是包(目录内无__init__.py)的文件都会被拒绝(config.py)。包的判定依据recurse_project_files中is_package = "__init__.py" in files(plugin/interface.py)。

路径重写:sources

sources选项可以重写目录的相对路径。例如:

[tool.hatch.build.targets.wheel.sources] "src/foo" = "bar"

会将src/foo/file.ext以bar/file.ext分发。

如果要完全移除路径前缀,与其把每个都设为空字符串,不如把sources定义为数组:

[tool.hatch.build.targets.wheel] sources = ["src"]

如果要给路径添加前缀,可以使用空字符串键。例如:

[tool.hatch.build.targets.wheel.sources] "" = "foo"

会将bar/file.ext以foo/bar/file.ext分发。

源码中sources同时接受数组(移除前缀)和映射(精确重写)两种形式(config.py),并支持映射形式下空键代表根目录。实际分发路径由get_distribution_path计算:命中 source 前缀则替换,未命中则保持原路径(config.py)。

性能:skip-excluded-dirs

默认情况下所有遇到的目录都会被遍历。要跳过被排除的非 artifacts 目录,可设置skip-excluded-dirs为true:

[tool.hatch.build] skip-excluded-dirs = true

警告:这可能导致期望的文件没有被打包。例如想包含a/b/c.txt,但 VCS 忽略 了a/b,那么c.txt将不会被看到,因为其父目录不会被进入。此时可以使用force-include选项。源码中directory_is_excluded在启用该选项时会把目录视为已排除而不进入(config.py);注意目录路径尾部必须带/,这样bar/才能正确匹配foo/bar。此外,一些常见的缓存/虚拟环境目录(如__pycache__、.venv、.git、.hatch、.tox、.ruff_cache等)在任何情况下都会被排除,见 constants.py。

可复现构建(Reproducible builds)

默认情况下,只要 构建目标 支持,就会以可复现的方式构建。要禁用,设置reproducible为false:

[tool.hatch.build] reproducible = false

启用后,所有构建时间戳都会使用 SOURCE_DATE_EPOCH。reproducible的默认值在 config.py 中为True。

该选项在 wheel 与 sdist 归档中都有落地:wheel 使用统一时间元组写入 ZipInfo,并将文件权限规范化为 644/755(wheel.py、utils.py);sdist 则将 tar 条目的 uid/gid 归零、清空用户名/组名并统一 mtime(sdist.py)。

输出目录(Output directory)

当未向build命令提供输出目录时,默认使用dist目录。可以通过相对或绝对路径更改默认值:

[tool.hatch.build] directory = "<PATH>"

源码中默认值为常量DEFAULT_BUILD_DIRECTORY = "dist"(constants.py),normalize_build_directory会把相对路径基于项目根解析为绝对路径(config.py)。此外,HATCH_BUILD_LOCATION环境变量可以覆盖构建命令的输出位置(见下文环境变量表)。

开发模式(Dev mode)

对于 开发模式 的环境安装或 可编辑安装,wheel目标默认会根据 所选文件 决定哪些目录应加入 Python 的搜索路径(即sys.path)。

要覆盖这一自动检测,或同时指示其他构建目标,可以使用dev-mode-dirs选项:

[tool.hatch.build] dev-mode-dirs = ["."]

如果不想把整个目录加入 Python 搜索路径,可以启用更精确的dev-mode-exact选项(与dev-mode-dirs互斥):

[tool.hatch.build] dev-mode-exact = true

警告:dev-mode-exact机制不被静态分析工具和 IDE 支持(参见 pylance-release#2114),它通过在每个模块文件旁生成桩模块实现精确映射,而非整个目录进入搜索路径。

构建目标(Build targets)

构建目标可由任何 builder 插件 提供,内置目标有 wheel、sdist 和 custom 三种。

目标依赖

可以为每个构建环境指定额外依赖,例如第三方构建器所需的插件:

[tool.hatch.build.targets.your-target-name] dependencies = [ "your-builder-plugin" ]

还可以通过require-runtime-dependencies声明依赖项目的 运行时依赖:

[tool.hatch.build.targets.your-target-name] require-runtime-dependencies = true

此外,还可以通过require-runtime-features声明依赖项目的特定 运行时特性:

[tool.hatch.build.targets.your-target-name] require-runtime-features = [ "feature1", "feature2", ]

从源码看,dependencies是一个有序去重集合,会合并目标级与全局级依赖、构建钩子的依赖、require-runtime-dependencies展开的项目dependencies、以及require-runtime-features展开的optional-dependencies(config.py)。require-runtime-features中引用的特性必须真实存在于project.optional-dependencies中,否则抛 ValueError(config.py)。

版本(Versions)

如果构建目标支持多种构建策略,或随时间有大版本变更,可以用versions选项指定精确要构建的版本:

[tool.hatch.build.targets.<TARGET_NAME>] versions = [ "v1", "beta-feature", ]

参见 wheel 目标的真实示例(standard与editable两种 wheel 构建策略)。源码中versions为空时会回退到构建器声明的默认版本get_default_versions(),且声明的版本必须是get_version_api()提供的版本之一,否则报错(config.py)。实际构建流程在BuilderInterface.build中按版本逐一执行:初始化钩子 → 构建产物 → 收尾钩子,详见 plugin/interface.py。

构建钩子(Build hooks)

构建钩子定义了在构建过程各阶段执行的代码,可由任何 build hook 插件 提供。内置的构建钩子是 custom,它通过加载项目中的构建脚本(默认build.py)来执行自定义逻辑(custom.py)。

构建钩子既可以全局应用:

[tool.hatch.build.hooks.<HOOK_NAME>]

也可以应用到特定构建目标:

[tool.hatch.build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]

钩子依赖

可以指定每个构建环境中额外安装的依赖,例如第三方构建钩子:

[tool.hatch.build.hooks.your-hook-name] dependencies = [ "your-build-hook-plugin" ]

也可以声明依赖项目的 运行时依赖:

[tool.hatch.build.hooks.your-hook-name] require-runtime-dependencies = true

还可以声明依赖项目的特定 运行时特性:

[tool.hatch.build.hooks.your-hook-name] require-runtime-features = [ "feature1", "feature2", ]

这些配置在dependencies属性中被统一合并进构建环境的依赖集合(config.py),运行时特性同样必须存在于optional-dependencies。

执行顺序

对每个构建目标,构建钩子按定义顺序执行,全局钩子先执行。例如对于以下配置:

[tool.hatch.build.targets.foo.hooks.hook2] [tool.hatch.build.hooks.hook3] [tool.hatch.build.hooks.hook1]

当构建目标foo时,hook3首先执行,然后是hook1,最后是hook2。源码中hook_config先收集全局钩子再收集目标钩子,目标级钩子覆盖同名全局钩子,且键的顺序被保留(config.py);get_build_hooks按此顺序实例化钩子(plugin/interface.py)。

条件执行

如果希望默认禁用某个构建钩子、仅由 环境变量 控制其启用,可以设置enable-by-default为false:

[tool.hatch.build.hooks.<HOOK_NAME>] enable-by-default = false

源码中hook_config在以下任一条件满足时才会保留钩子:HATCH_BUILD_HOOKS_ENABLE生效(全部启用)、钩子未显式关闭enable-by-default、或对应的HATCH_BUILD_HOOK_ENABLE_<HOOK_NAME>环境变量为真;而HATCH_BUILD_NO_HOOKS会直接清空全部钩子(config.py)。

环境变量

变量默认值描述
HATCH_BUILD_CLEANfalse是否先移除已存在的产物
HATCH_BUILD_CLEAN_HOOKS_AFTERfalse每次构建后是否移除构建钩子的产物
HATCH_BUILD_HOOKS_ONLYfalse是否只执行构建钩子
HATCH_BUILD_NO_HOOKSfalse是否禁用所有构建钩子;优先于其他选项
HATCH_BUILD_HOOKS_ENABLEfalse是否启用所有构建钩子
HATCH_BUILD_HOOK_ENABLE_<HOOK_NAME>false是否启用名为<HOOK_NAME>的构建钩子
HATCH_BUILD_LOCATIONdist构建目标的位置;仅由build命令使用

这些环境变量在 constants.py 中被定义为BuildEnvVars常量,由env_var_enabled解析——环境变量值只有1或true才视为启用(config.py)。在BuilderInterface.build中,HATCH_BUILD_LOCATION会覆盖输出目录、HATCH_BUILD_CLEAN控制是否清理、HATCH_BUILD_HOOKS_ONLY让流程只跑钩子不产包(plugin/interface.py)。

结语

Hatch 的构建配置是一套层层递进的文件选择与产物生成体系:VCS 规则提供默认基线,include/exclude/artifacts提供模式化筛选,only-include/packages/force-include/sources提供路径级精确控制,only-packages、skip-excluded-dirs提供语义约束与性能调优,而构建目标、构建钩子与环境变量则共同构成了可组合、可复现、可扩展的完整构建流水线。结合 config.py 的源码阅读,可以清楚看到每个配置项背后真实的判定逻辑与优先级,帮助你在实际项目中写出既精确又高效的构建配置。

  • 开发工具
  • 构建工具

【免费下载链接】hatch

Modern, extensible Python project management

项目地址:https://gitcode.com/gh_mirrors/ha/hatch
点击查看免费下载

相关推荐

上一篇:Dagger TypeScript SDK 的 DirectoryExportOpts 详解:用 wipe 精准控制目录导出行为
下一篇:Rerun 可视化 DROID 机器人操作数据集:关节状态、立体相机与遥操作动作的 2D/3D 同步呈现

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 6:19:22

TensorFlow工业落地实战:从环境配置到边缘部署全链路避坑指南

1. 这不是“又一个深度学习框架”——TensorFlow 是怎么从实验室走向产线的你搜“tensorflow”&#xff0c;页面上跳出来的全是安装报错、版本冲突、CUDA不匹配、GPU识别失败……但真正用过三年以上 TensorFlow 的人&#xff0c;第一反应不是“怎么装”&#xff0c;而是“这个模…

作者头像 李华
网站建设 2026/9/29 6:17:05

Cherry Studio 配 TaoToken:MCP 文件操控的 config.toml 骨架与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华