ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

【Bug已解决】Missing library stubs or py.typed marker 解决方案

2026/8/2 22:53:34 拓冰建站 浏览量
【Bug已解决】Missing library stubs or py.typed marker 解决方案 【Bug已解决】Missing library stubs or py.typed marker 解决方案一、现象长什么样你维护一个 Python 库下游用户用mypy/pyright做类型检查时关于你这个库的调用全部报缺少类型信息error Library stubs for your_lib are missing (install with pip install ...) note (or use # type ignore 来抑制) # 或 mypy --strict 下 error Skipping analyzing your_lib module is installed but missing py.typed marker或者 IDEPyCharm / VSCode里你这个库的函数没有参数提示、没有返回类型推断。最小判据触发下游对使用了你的库的项目做类型检查 / IDE 分析 现象报 missing stubs / missing py.typed类型推断失效 根因你的包没有声明自己是带类型的缺 py.typed或没提供类型存根 影响下游类型安全与开发体验受损CI 的 mypy 严格模式失败最迷惑的是你的代码明明写了类型注解下游却说没有类型信息——因为类型信息有没有写和包有没有声明自己是带类型的是两回事。二、背景PEP 561 规定一个发行到 PyPI 的包若想让下游的类型检查器mypy/pyright使用它的类型注解必须在包里包含一个名为py.typed的空标记文件并在打包时把它作为package_data包含进 wheel。原理Python 类型检查器默认不信任第三方包的类型注解历史上很多包类型不准全信会误报py.typed是包的我声明我的类型注解是可靠的请使用它们的显式信号没有py.typed类型检查器要么忽略该包的类型报 skipping analyzing要么要求单独的types-xxxstub 包。另外两种情况包是纯 Python 且有内联注解只需加py.typed即可类型检查器直接读源码注解包含 C 扩展 / 动态生成模块源码注解读不到需要提供.pyi存根文件stub并同样配py.typed指向这些 stub。bug 的根因是打包配置遗漏了py.typed标记和package_data导致 wheel 里没有这个文件下游类型检查器拒绝使用该包类型。三、根因抽象成代码示意# pyproject.toml问题所在 [build-system] requires [setuptools] [project] name your_lib # BUG没有声明 py.typed 为 package_datawheel 里不含该标记根因链条库代码有类型注解但 wheel 里没有py.typed标记类型检查器按 PEP 561 规则发现无py.typed- 拒绝使用该包类型下游mypy报 missing stubs / skipping analyzingIDE 因类型检查器给不到信息参数提示、返回类型推断失效根因是打包遗漏py.typedpackage_data。一句话wheel 缺py.typed标记且未纳入 package_data下游类型检查器拒绝使用该包类型。四、最小可运行复现用纯 Python 模拟无 py.typed 时类型检查器拒绝# repro_py_typed.py def typechecker_accepts(package_has_py_typed): if not package_has_py_typed: raise RuntimeError(missing py.typed 拒绝使用包的类型) return use package types def main(): try: typechecker_accepts(package_has_py_typedFalse) except RuntimeError as e: print(复现成功 -, e) print(typechecker_accepts(package_has_py_typedTrue)) if __name__ __main__: main()运行输出复现成功 - missing py.typed 拒绝使用包的类型 use package types无py.typed时类型检查器拒绝正是真实 bug 的抽象。五、解决方案第一层最小直接修复最小且必须的一步在包目录里放一个空的py.typed文件并在打包配置里把它作为package_data包含进 wheelyour_lib/ __init__.py core.py py.typed # 空文件PEP 561 标记pyproject.tomlsetuptools[build-system] requires [setuptools61] build-backend setuptools.build_meta [project] name your_lib version 0.1.0 [tool.setuptools.packages.find] where [.] include [your_lib*] [tool.setuptools.package-data] your_lib [py.typed] # 关键把 py.typed 打进 wheel构建后验证 wheel 内含py.typedpython -m build unzip -l dist/your_lib-0.1.0-py3-none-any.whl | grep py.typed要点py.typed是空文件仅作标记package-data确保它被纳入 wheel下游mypy立刻能用该包内联注解。六、解决方案第二层结构性改进把类型声明完整性做成发布前的自动校验CI 在构建后检查 wheel 是否含py.typed并对源码做mypy --strict自检保证发布的类型可靠# fix_layer2.py from pathlib import Path import zipfile def wheel_has_py_typed(wheel_path: str, package: str) - bool: with zipfile.ZipFile(wheel_path) as z: names z.namelist() marker f{package}/py.typed return marker in names def assert_typed_release(wheel_path, package): assert wheel_has_py_typed(wheel_path, package), \ fwheel 缺少 {package}/py.typed下游无法使用类型 # CI 用法 assert_typed_release(dist/your_lib-0.1.0-py3-none-any.whl, your_lib)并在pyproject.toml配mypy自检[tool.mypy] strict true files [your_lib]要点wheel_has_py_typed在 CI 验证标记存在缺则发布失败mypy --strict对源码自检保证发布的类型本身可靠否则下游即使有 py.typed 也会误报类型质量与是否声明双管齐下。七、解决方案第三层断言 / CI 守护写 pytest 验证py.typed 存在且被打包# test_py_typed.py import pytest import zipfile, pathlib def test_py_typed_in_wheel(): wheel pathlib.Path(dist/your_lib-0.1.0-py3-none-any.whl) if not wheel.exists(): pytest.skip(wheel 未构建) with zipfile.ZipFile(wheel) as z: assert your_lib/py.typed in z.namelist() def test_py_typed_marker_present_in_source(): marker pathlib.Path(your_lib/py.typed) assert marker.exists(), 源码树必须有 py.typed 标记文件 def test_stub_or_inline_types(): # 至少有内联注解或 .pyi 存根之一 has_pyi any(pathlib.Path(your_lib).rglob(*.pyi)) has_annotations True # 实际应扫描源码是否有注解 assert has_pyi or has_annotationsCI 一旦有人把py.typed从打包配置删掉test_py_typed_in_wheel立即变红。八、排查清单下游报 missing stubs / missing py.typed 时确认 wheel 里是否含your_lib/py.typed解压看若没有在源码树放空py.typed并在package-data声明重新python -m build验证 marker 进 wheel若包含 C 扩展 / 动态模块额外提供.pyi存根用mypy --strict对源码自检保证类型本身可靠把第七节的 pytest 接进 CI守护 py.typed 被打包下游重新pip install你的新 wheel 后类型恢复。九、小结库的类型信息下游用不上根因是 wheel 缺py.typed标记且未纳入package-data。PEP 561 规定第三方包必须显式带py.typed才能被类型检查器信任缺它则下游mypy报 missing stubs / skipping analyzingIDE 推断失效。三层层级第一层源码树放空py.typed并在package-data声明打进 wheel第二层CI 构建后校验 wheel 含py.typed并对源码mypy --strict自检第三层pytest 验证 marker 存在且被打包锁进 CI。核心教训写了类型注解 ≠ 下游能用类型。是否声明为带类型包由py.typed这个 PEP 561 标记决定。任何发布到 PyPI 的库只要希望下游享受类型安全都必须把py.typed纳入打包——这是类型生态的入场券不是可选项。