Python之stubmaker包语法、参数和实际应用案例
作者:王国平
一、stubmaker 概述与核心功能
1. 什么是 stubmaker
stubmaker 是 Python 官方配套的存根文件(.pyi)自动生成工具,底层封装 inspect、typing、ast 模块,用于为已有 Python 源码、第三方编译扩展库(C/C++/Rust 编写的 .so/.pyd)、动态模块生成类型提示存根文件(Stub File)。
区分同类工具:
stubgen:内置工具,仅支持纯 Python 源码;无法解析二进制扩展库;stubmaker:增强版,兼容纯 Python + 编译扩展模块,自动推导函数签名、类属性、泛型、异常抛出,生成规范.pyi类型提示文件,适配 VSCode/PyCharm/mypy 静态类型检查。
2. 核心功能
- 纯Python源码批量生成存根:扫描文件夹/单文件,自动解析函数参数、返回值、类字段、装饰器;
- 二进制扩展库存根生成:解析
.pyd/.so动态库、Cython 模块,弥补 stubgen 无法处理编译模块的短板; - 类型自动推导:识别基础类型、Union、Optional、List/Dict、泛型、TypeVar;
- 导出完整模块结构:导出
__all__、常量、枚举、内置异常、类继承关系; - 自定义过滤规则:忽略私有函数、过滤指定模块、保留/删除注释;
- 增量生成:对比旧
.pyi文件,仅更新变更部分,不覆盖手写类型注释; - mypy 兼容:生成符合 PEP484/PEP561 标准存根,支持静态类型校验。
二、安装方式
方式1:pip 标准安装
pip install stubmaker # 带类型检查依赖(推荐) pip install stubmaker mypy typing-extensions
方式2:源码安装(最新开发版)
git clone https://github.com/osandov/stubmaker.git cd stubmaker pip install .
依赖要求
- Python ≥3.7;
- 可选依赖:
mypy(类型校验)、cython(解析Cython模块)、setuptools(解析扩展库元数据)。
三、命令行语法、全局参数、子命令参数
基础命令语法
stubmaker [全局参数] 子命令 [子命令参数] 目标路径
支持两大核心子命令:generate(生成存根)、check(校验已有存根合法性)
1. 全局通用参数
| 参数 | 作用 |
|---|---|
| -h/--help | 全局帮助文档 |
| -v/--verbose | 输出详细日志,打印解析每个函数/类的过程 |
| -q/--quiet | 静默模式,仅输出报错 |
| --python-exec PATH | 指定解析用Python解释器(用于多版本环境) |
| --cache-dir DIR | 设置模块解析缓存目录,加速重复生成 |
2. generate 子命令(核心生成命令)完整参数
stubmaker generate [OPTIONS] TARGET
| 参数 | 说明 |
|---|---|
| -o/--output DIR | 指定 .pyi 输出目录,默认和源码同目录 |
| --recursive/-r | 递归扫描文件夹,批量生成子模块存根 |
| --ignore-private | 跳过下划线开头私有方法/变量(_func, __attr) |
| --include-docstrings | 将源码docstring写入存根文件 |
| --no-types-eval | 关闭运行时类型推导,仅通过AST静态解析(安全,避免执行恶意代码) |
| --module-filter REGEX | 正则过滤模块,只生成匹配模块的存根 |
| --exclude REGEX | 排除匹配正则的文件/模块 |
| --incremental | 增量更新,不覆盖手动修改的.pyi |
| --force | 强制覆盖所有旧存根文件 |
| --stub-extension SUFFIX | 自定义存根后缀,默认 .pyi |
| --add-type-imports | 自动补充 typing 模块导入(Optional, List, Any等) |
| --skip-constants | 不生成模块常量存根 |
| --export-all | 自动生成 __all__ 列表,导出所有公有对象 |
3. check 子命令(存根校验)参数
stubmaker check [OPTIONS] STUB_FILE
| 参数 | 作用 |
|---|---|
| --strict | 严格校验,类型不匹配直接报错 |
| --mypy-config FILE | 指定mypy配置文件校验存根 |
4. Python 代码内调用API语法(可编程生成)
stubmaker 提供编程式接口,可嵌入脚本批量自动化生成:
from stubmaker import StubGenerator, GeneratorConfig
# 配置类
config = GeneratorConfig(
recursive=True,
ignore_private=True,
output_dir="./stubs",
incremental=True
)
# 初始化生成器
gen = StubGenerator(config=config)
# 生成单文件
gen.generate_file("mylib/main.py")
# 生成整个包
gen.generate_package("mylib/")
# 校验存根
gen.check_stub("stubs/main.pyi")
四、8个完整可运行实战应用案例
案例1:为单个纯Python文件生成基础存根
场景:给项目单文件 utils.py 生成 utils.pyi,输出到同目录,忽略私有方法。
命令行:
stubmaker generate --ignore-private utils.py
生成效果:自动提取所有公有函数、类,推导参数/返回值类型,生成标准 .pyi。
案例2:递归批量为整个项目包生成存根(输出至独立stubs文件夹)
场景:项目包名 myproject/,递归扫描所有子模块,存根统一输出到 ./stubs,增量更新。
stubmaker generate -r -o ./stubs --incremental --export-all myproject/
代码API版本:
from stubmaker import StubGenerator, GeneratorConfig
cfg = GeneratorConfig(recursive=True, output_dir="./stubs", incremental=True, export_all=True)
gen = StubGenerator(cfg)
gen.generate_package("./myproject")
案例3:解析Cython编译扩展.pyd二进制模块生成存根
场景:第三方Cython库 fastcalc.pyd,stubgen无法解析,使用stubmaker运行时解析二进制导出符号。
stubmaker generate --python-exec python3 fastcalc.pyd -o ./stubs
关键:不加 --no-types-eval,必须运行加载模块读取运行时签名。
案例4:过滤指定模块、排除测试文件
场景:项目过滤 core.* 模块,排除所有 test_*.py 文件,不生成测试存根。
stubmaker generate -r --module-filter "^core\." --exclude "test_.*" src/
案例5:生成带文档注释、完整类型导入的标准化存根
场景:生成可发布给第三方的规范存根,保留docstring、自动补全typing导入。
stubmaker generate --include-docstrings --add-type-imports --force src/api.py -o dist/stubs
案例6:安全静态解析(禁止执行源码,防恶意代码)
场景:解析外部不可信第三方源码,关闭运行时类型求值,仅用AST静态分析。
stubmaker generate --no-types-eval untrusted_lib.py
限制:无法解析动态赋值类型、二进制扩展库,仅纯静态语法树解析。
案例7:自动化脚本打包时生成存根(setup.py集成)
场景:打包发布Python库时,自动构建stubs并打包进分发包。build_stubs.py 脚本:
from stubmaker import StubGenerator, GeneratorConfig
import os
def build_package_stubs():
cfg = GeneratorConfig(
recursive=True,
output_dir="./build/stubs",
ignore_private=True,
export_all=True
)
gen = StubGenerator(cfg)
gen.generate_package("./mypackage")
print("存根生成完成,路径:", os.path.abspath("./build/stubs"))
if __name__ == "__main__":
build_package_stubs()执行:python build_stubs.py,配合 setup.py 的 cmdclass 自动构建。
案例8:校验已手写存根与源码类型一致性
场景:手动修改过 .pyi,校验是否和源码函数签名、类型匹配,严格模式报错阻断发布。
stubmaker check --strict stubs/core.pyi --mypy-config mypy.ini
脚本API校验:
from stubmaker import StubGenerator, GeneratorConfig
gen = StubGenerator(GeneratorConfig())
result = gen.check_stub("./stubs/core.pyi", strict=True)
if not result.success:
raise SystemExit("存根与源码类型不匹配")
五、常见错误、报错原因与解决方案
错误1:ModuleNotFoundError: No module named ‘stubmaker’
- 原因:未安装包、pip环境与运行Python解释器不匹配;
- 解决:
# 确认当前pip绑定当前python python -m pip install stubmaker
错误2:Failed to load module xxx.pyd / segmentation fault when parsing extension
- 原因1:Python版本与编译扩展库版本不兼容(32/64位、3.8 vs 3.10);
- 原因2:扩展库依赖系统动态库缺失(Windows缺少VC++运行库、Linux缺少glibc);
- 解决:使用对应版本解释器
--python-exec,安装系统依赖,或切换静态解析--no-types-eval(仅纯py文件)。
错误3:Type evaluation disabled, cannot process binary module
- 原因:使用
--no-types-eval参数同时解析.pyd/.so扩展;静态AST无法读取二进制导出符号; - 解决:移除
--no-types-eval,允许运行时加载模块解析。
错误4:Stub file not updated with --incremental but source changed
- 原因:增量模式会跳过手动修改过的
.pyi文件,不会覆盖手写代码; - 解决:需要全量更新时加
--force参数强制覆盖。
错误5:SyntaxError in generated .pyi, invalid type annotation
- 原因1:源码存在动态复杂类型(动态生成类、元编程),自动推导出错;
- 原因2:旧Python版本不支持PEP604
|联合类型; - 解决:手动修正对应存根,或添加
--skip-constants过滤动态常量,升级Python到3.10+。
错误6:Recursive scan not working, subfolder stubs missing
- 原因:忘记加
-r/--recursive参数,仅处理顶层文件; - 解决:命令行追加
-r,API配置recursive=True。
错误7:ImportError: cannot import name ‘StubGenerator’ from ‘stubmaker’
- 原因:stubmaker版本过低,早期版本无编程API;
- 解决:升级到最新版
pip install --upgrade stubmaker。
错误8:Mypy check reports “Missing type annotation” in generated stubs
- 原因:源码无类型注解,stubmaker自动推导为
Any; - 解决:源码补充基础类型注解,或生成时手动修改存根,添加显式类型。
六、使用注意事项
1. 安全风险
- 默认模式会导入目标模块执行代码以获取运行时类型,不要用默认参数解析未知/恶意第三方代码;处理不信任源码必须加
--no-types-eval。 - 解析二进制扩展库会加载本地动态库,存在崩溃风险,建议隔离虚拟环境操作。
2. 类型推导局限性
- 高度元编程、动态创建函数/类、工厂模式无法100%精准推导,生成后需人工校对;
- 运行时动态修改的属性、 monkey patch 不会出现在存根中;
- 复杂泛型、自定义TypeVar可能推导为Any,需手动修正。
3. 项目工程规范
- 生产项目建议将
.pyi存根统一放入独立stubs/目录,不要和源码混杂; - 发布开源库时,将生成的
.pyi打包分发,搭配py.typed文件(PEP561)告知类型检查器存在存根; - 版本迭代时使用
--incremental保护手写的精细类型注释。
4. 性能优化
- 开启
--cache-dir缓存模块解析信息,多次生成大幅提速; - 大型项目配合
--exclude过滤测试、第三方依赖、文档目录,减少扫描耗时。
5. 编辑器兼容
- VSCode/PyCharm识别
.pyi需确保输出目录加入sys.path; - 若IDE不读取生成存根,在项目根目录创建
py.typed空文件。
6. 版本兼容提醒
- Python3.7及以下不支持
|联合类型,生成存根会使用Union[]兼容写法; - 低于0.10版本的stubmaker不支持递归批量生成,建议升级至0.12+稳定版。
到此这篇关于Python之stubmaker包语法、参数和实际应用案例的文章就介绍到这了,更多相关Python stubmaker包应用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
