☰
BentoML 类型存根工程实践:typings 目录的构建、验证与第三方库 .pyi 文件贡献流程
2026/9/25 4:02:18 网站建设 项目流程
  • 模型推理服务
  • 人工智能
  • 后端
  • 大模型
  • MLOps
  • LLMOps

【免费下载链接】BentoML

The easiest way to serve AI apps and models - Build Model Inference APIs, Job queues, LLM apps, Multi-model pipelines, and more!

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

BentoML 仓库根目录下的 typings 目录存放了一套“vendor 化”的第三方库 Python 类型存根(.pyi文件),用于让 PyYAML、fsspec、python-multipart、easyocr、Triton 客户端等依赖库在主类型检查器 Pyright 下获得精确的类型解析。本篇以仓库内的 typings/README.md 为核心,结合 pyproject.toml 的 pyright 配置、tools/typings 检查脚本与 tools/dev.Dockerfile 中的存根自动生成流程,完整讲解这套存根体系的工作机制,以及新增一个存根的官方五步贡献流程。

一、typings 目录是什么:为什么 BentoML 要自带第三方库存根

typings/README.md 的第一行即点明了目录定位:“Library stubs used by bentoml”(BentoML 使用的库存根)。当前目录中实际维护了以下第三方库的存根:

库存根入口典型规模(当前仓库快照)
PyYAMLtypings/yaml__init__.pyi约 108 行,另含 dumper/emitter/resolver/serializer 等模块存根
Pillow (PIL)typings/PIL/Image.pyi约 203 行
fsspectypings/fsspec含spec.pyi、registry.pyi、callbacks.pyi及implementations/子包
easyocrtypings/easyocr含Reader与config的存根
schematypings/schema.pyi约 155 行,覆盖SchemaError与OpsMeta协议
multiparttypings/multipart/multipart.pyi极小型存根(约 5 行)
filetype / pathspec / deepmerge各自子目录模块级最小化存根
tritonclienttypings/tritonclient其中grpc/service_pb2.pyi约 3381 行,由.proto自动生成

从存根内容可以观察到两种典型形态:

  • 手写精简存根:如 typings/fsspec/registry.pyi 只用一个TypedDict精确描述了known_implementations的结构(class: str, err: NotRequired[str]);typings/easyocr/init.pyi 仅做from .easyocr import Reader as Reader再导出加版本号占位。这类存根刻意把接口面压缩到 BentoML 实际用到的最小集合,方便后续维护。
  • 生成式存根:如 Triton gRPC 客户端的service_pb2.pyi是直接从 protobuf 定义生成的完整类型描述,行数巨大,人工无法维护(其生成机制见第四节)。

二、存根如何接入类型检查:pyright 与 ruff 的协同配置

typings 目录不是“放着的备份文件”,它被显式纳入了 pyproject.toml 的类型检查范围:

[tool.pyright] pythonVersion = "3.12" include = ["src/", "examples/", "tests/", "typings/"] analysis.useLibraryCodeForTypes = true reportMissingTypeStubs = "warning" # ... 其余 report* 级别配置

关键配置含义(对应 pyproject.toml):

  • include中包含"typings/":Pyright 在解析import yaml、import fsspec等第三方模块时,会优先采用本仓库内的存根而非站点包内类型,保证 CI 与开发环境的类型判定一致;
  • analysis.useLibraryCodeForTypes = true与reportMissingTypeStubs = "warning":允许从库代码推断类型,同时对缺少存根的依赖给出告警——这正是持续为缺失存根补 stub 的动力来源;
  • reportGeneralTypeIssues = "error"、reportUnusedImport = "error"等严格级别,使得存根中的签名错误会直接阻断检查,倒逼存根保持与实际库行为一致。

与之配合的还有两条排除规则,确保存根本身不被代码风格工具干扰(对应 pyproject.toml):

  • [tool.ruff]的extend-exclude排除了**/*_grpc.pyi、**/*_pb2.pyi等生成式存根;
  • [tool.ruff.lint]的exclude中直接排除了"typings"整个目录,即存根只受类型检查约束,不受 lint 规则约束。

此外,仓库提供了一个最小化的存根验证入口 tools/typings:

#!/usr/bin/env bash # Check if pyright is installed, otherwise exit 1 [[ -x "$(command -v pyright)" ]] || ( echo "pyright not found" exit 1 ) pyright src/bentoml --level error 2> /dev/null || exit 0

该脚本对src/bentoml执行 error 级别的 Pyright 检查。由于include已覆盖typings/,任何存根签名与src/中调用不匹配的问题都会在这一层暴露出来,可以把它视为 typings 目录的“回归门禁”。

三、贡献新存根的官方五步流程

typings/README.md 定义了为仓库尚未覆盖的第三方库补充存根的标准流程,要求先在本地 fork 配置好指向 BentoML 主仓库的 upstream remote(README 中给出的上游 GitHub 帮助文档链接在此不再复述),然后执行以下步骤:

步骤 1:用 pyright 生成存根骨架

pyright --createstub <imports_library>

例如pyright --createstub fsspec,Pyright 会基于该库的运行时元数据自动生成一版.pyi骨架。生成结果通常冗长且包含大量与 BentoML 无关的接口。

步骤 2:最小化存根

README 要求使用./scripts/tools/stubs_cleanup.sh对存根做裁剪。需要指出的是:在当前仓库快照中,scripts/目录下仅有发布与清理脚本,未包含tools/stubs_cleanup.sh,可以推断该清理脚本已被移除、迁移或该步骤已改由人工处理。因此实际贡献时应以当前仓库结构为准:手动把存根压缩到 BentoML 真实引用的 API 子集,参照 typings/fsspec/registry.pyi 这类“只保留用到字段”的既有风格。

步骤 3:强制提交 typings 下的存根

git add -f typings/<imports_library>

使用-f强制添加,是应对历史上typings/曾被纳入忽略规则的做法;当前.gitignore中已没有 typings 相关条目,-f在这里更多是保险写法,确保存根一定进入暂存区。

步骤 4:与 upstream 主分支生成 diff

git diff HEAD upstream/main > <imports_library>.diff

README 的协作模式是:存根先提交到本地/feature 分支(HEAD),然后与upstream/main的基线对比生成一个.diff补丁文件——即存根变更以“补丁文件”的形式作为变更证据随 PR 提交,便于评审者直接审阅“这次到底给哪个库加了哪些类型声明”。

步骤 5:提交 diff 文件并发起评审

将上一步生成的<imports_library>.diff一并提交,完成本次存根贡献。评审通过后,新存根即进入 tool.pyright 的include范围,成为类型检查的一部分。

四、生成式存根的特例:tritonclient 存根如何从 .proto 自动构建

多数存根可离线生成,但 typings/tritonclient 中的 gRPC 存根(service_pb2.pyi、model_config_pb2.pyi、service_pb2_grpc.pyi)走的是 protobuf 编译管线,其构建逻辑定义在 tools/dev.Dockerfile 的generate-triton-stubs阶段:

RUN --mount=type=bind,target=.,rw <<EOT set -ex git clone --depth 1 --filter=blob:none --sparse https://github.com/triton-inference-server/common.git cd common && git sparse-checkout set protobuf cp protobuf/model_config.proto model_config.proto cp protobuf/grpc_service.proto service.proto mkdir -p ${GENERATED_DIR} python -m grpc_tools.protoc -I. --mypy_out=${GENERATED_DIR} model_config.proto python -m grpc_tools.protoc -I. --mypy_out=${GENERATED_DIR} --mypy_grpc_out=${GENERATED_DIR} service.proto tree typings/tritonclient || exit 1 mv typings/tritonclient/grpc/* /result/${GENERATED_DIR} EOT

流程要点:

  1. 以 sparse-checkout 方式只拉取 Tritoncommon仓库中的protobuf目录,拷贝model_config.proto与grpc_service.proto两个定义文件;
  2. 使用grpc_tools.protoc的--mypy_out(及 gRPC 存根所需的--mypy_grpc_out)直接从.proto生成类型存根,而非手写;
  3. 生成物落到typings/tritonclient/grpc/,由后续triton-protobuf-output阶段收集为构建产物。

这说明 typings/README.md 描述的手工流程适用于普通第三方库,而 proto 派生客户端(tritonclient)的存根应由上述构建阶段再生成并替换,手工改动会在下次构建时被覆盖。这与 pyright 配置中排除src/**/*_pb2.py*(pyproject.toml)以及 ruff 排除**/*_pb2.pyi的处理是同一套“生成代码免检”策略的组成部分。

五、维护建议与验证要点

结合以上源码事实,向 typings 贡献或排查存根问题时可以遵循以下检查清单:

  1. 验证闭环:本地执行 tools/typings 或直接pyright src/bentoml --level error,确认include内的src/、tests/、examples/与typings/全部通过,这是存根是否“可用”的最终判据;
  2. 风格对齐:新增存根保持最小接口面,避免把整库 API 全量塞入;对NotRequired、TypedDict、Protocol等现代类型构造的用法可参照 typings/fsspec/registry.pyi 与 typings/schema.pyi(后者用OpsMetaProtocol 表达validate的多态签名);
  3. 区分两类存根:普通库存根按 typings/README.md 五步流程手工生成与维护;tritonclient等 proto 派生存根走 tools/dev.Dockerfile 的构建管线,勿手改;
  4. 注意工具链差异:README 提到的scripts/tools/stubs_cleanup.sh在当前仓库快照中不存在,贡献前请先确认主仓库中该脚本的最新位置或改用手动裁剪;
  5. 保持 ignore/排除一致性:若新增生成式存根,应同时评估是否需要在[tool.ruff]/[tool.ruff.lint]的排除清单(pyproject.toml)与 pyright 的exclude(pyproject.toml)中登记对应通配模式,避免生成代码触发 lint 或类型告警。

至此,typings/README.md 中简短的五步流程已经落到具体的配置与代码位置:pyright --createstub生成骨架 → 裁剪至最小接口面 →git add -f typings/<lib>入库 → 与upstream/main对比生成.diff作为变更证据 → 提交 diff 完成贡献;而 pyproject.toml 的 include 范围与 tools/typings 检查脚本共同保证这些存根在每次类型检查中被真正消费。

  • 模型推理服务
  • 人工智能
  • 后端
  • 大模型
  • MLOps
  • LLMOps

【免费下载链接】BentoML

The easiest way to serve AI apps and models - Build Model Inference APIs, Job queues, LLM apps, Multi-model pipelines, and more!

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

相关推荐

上一篇:响应式设计资源:Instatic框架与组件库推荐
下一篇:OpenReel Desktop GPU Cloud Jobs:从 Worker 令牌到编辑器 AI 面板的完整实现指南

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询