这次我们讨论的不是一个新模型,也不是一个部署工具,而是 Python 类型检查生态里一件值得复盘的事:Basilisk 已经被从 python/typing 仓库维护的 typing conformance leaderboard(类型一致性排行榜)中移除。Basilisk 是一个开源 Python 类型检查器,主打对 typing 语义的激进实现和错误捕获能力。在登上排行榜的一段时间里,它以明显高于 mypy、pyright 等主流项目的符合率出现在前列,这个话题在社区里讨论度相当高。移除之后,排行榜上继续保留的是 pyright、mypy、pyre、pytype、basedpyright 等仍在活跃维护的项目。
对大多数 Python 开发者来说,Basilisk 这个名字可能有点陌生,但 conformance leaderboard 这个名字在类型检查器开发者和类型系统贡献者的圈子里知名度很高。它不是一个业务排行榜,而是一套可编程复现的测试集:给定大量覆盖 PEP 484、PEP 585、PEP 604 等 typing 特性的代码片段,自动检查不同类型检查器是否给出符合规范的诊断结果。Basilisk 被移除,意味着它不再被当作这个测试框架下可信的被测对象。
接下来我会分几块讲:先盘点 Basilisk 和 conformance leaderboard 的背景,再拆解移除背后的技术原因,然后顺着排行榜的测试机制说明为什么高分和实用体验是两回事,最后给出 Python 类型检查生态的选型参考、本地复现测试的实操路径和常见问题排查表。
需要先说明的是,Basilisk 被移除的完整官方说明以 python/typing 仓库的 GitHub 公告为准。这篇内容只做技术层面的分析和复盘,不把社区讨论中的猜测包装成既定事实。
1. 事件速览:Basilisk 是什么,conformance leaderboard 又是什么
1.1 Basilisk 的定位
Basilisk 是一个相对独立的 Python 类型检查器项目。它不是 mypy 这种从 2012 年就开始演进、有多年积累的成熟项目,也不是 pyright 这种由微软工程资源长期支持的检查器。Basilisk 更接近一个实验性、以“尽可能实现对 typing 语义的正确理解”为目标的独立实现。
从公开仓库信息来看,Basilisk 的核心差异在于不依赖 mypy 内部的类型推断逻辑,而是自己实现了一套对 PEP 484 及后续 typing 特性的解析与检查流程。它的主打能力是“对类型标注的理解更深”,而不是“在大型代码库上跑得更快”。这种定位决定了它在 conformance 测试这类偏语义准确性的场景中更容易拿到高分,但也意味着它的工程成熟度、文档完整度和周边生态需要另说。
它被移除之前,在 conformance leaderboard 上的名次一度很靠前,这也是社区讨论热度高的重要原因:一个相对小众的检查器,为什么能把 mypy、pyright 这些主流项目甩在身后?
1.2 conformance leaderboard 的定位
conformance leaderboard 由 python/typing 仓库维护,目标是度量不同类型检查器对官方 typing 规范的符合度。它不是一个在大型业务代码库上比“谁不崩溃”的排行榜,而是运行在一套覆盖精确类型语义的测试用例上,记录每个检查器与标准期望输出之间的差距。
榜单覆盖的检查器大致包括:
- mypy
- pyright / basedpyright
- pyre
- pytype
- Basilisk(曾经)
这个排行榜的独特之处在于,它不是靠投票或者人工评分,而是靠可以反复执行的测试脚本。任何人都可以通过克隆仓库、运行测试、对比输出来验证一个检查器的分数是否真实。这就引出了 Basilisk 被移除的关键问题:当项目无法被顺利安装、无法稳定复现,或者项目本身长期停更时,分数再高也无法进入一个追求可复现性的榜单。
1.3 事件背景信息速览
| 维度 | 信息 |
|---|---|
| 被测实体 | Python 类型检查器 |
| 相关项目 | Basilisk(已从榜单移除)、mypy、pyright、basedpyright、pyre、pytype |
| 核心仓库 | python/typing 的 conformance 测试集 |
| 事件关键点 | Basilisk 不再出现在 typing conformance leaderboard 上 |
| 直接原因 | 与可复现性、项目活跃度、得分有效性相关,具体以官方公告为准 |
| 对普通开发者的影响 | 较低,主流类型检查器仍可正常使用 |
| 对类型系统贡献者的影响 | 提醒基准测试分数需要批判性理解 |
2. Basilisk 为什么会被移除:技术层面拆解
2.1 可复现性:排行榜必须能重建
一个测试榜单要成立,前提是分数可以被重新跑出来。排行榜维护者不会只接受一张截图或一份日志,而是需要其他人在自己的环境里安装同一个版本的检查器,运行同一套测试集,得到接近一致的结果。
从社区讨论和仓库记录的常见情形看,Basilisk 被移除时面临的可复现性问题很可能集中在几个方面:
- 安装源不稳定,无法通过主流包管理工具直接安装。
- 项目依赖较新或较旧的第三方库,与当前 Python 版本不兼容。
- 高分数依赖特定的运行参数,而不是默认配置。
需要注意,这里并不是在逐条确认 Basilisk 官方给出的移除原因,而是说明无论具体触发点是哪一条,“测试不可复现”本身就是排行榜无法容忍的问题。当你维护一套被整个社区当作参考依据的基准测试时,一个无法重建的分数会降低整个榜单的可信度。
2.2 活跃度与演进能力
Python 的 typing 体系一直在演进,PEP 604 引入了X | Y语法,PEP 695 引入了新的泛型语法,PEP 649 也在不断调整注解相关行为。一个类型检查器要长期留在 conformance 榜单上,必须跟随规范演进:
- 新增语法能否及时支持。
- 新版本 Python 能否适配。
- 旧版本兼容性问题能否处理。
- 测试集中新增用例能否快速通过。
如果项目长期没有提交、没有发版、没有 issue 响应,那么它在榜单上的得分会越来越像一个“历史快照”,而不是一个持续可用的工具。这类项目被移除,对榜单来说是一种自我修正,而不是对项目历史贡献的否定。
2.3 得分公平性与默认配置
conformance 测试的意义在于衡量“开箱即用”的符合度。如果某个检查器为了通过测试,专门针对测试集做参数调优,或者在默认配置下关闭了大量检查项,那它的分数就失去了横向对比的价值。
这里要区分两种行为:
- 对 typing 语义做了深度实现,从而通过更多测试用例,这是合理的。
- 通过调整检查器行为、关闭诊断来“刷分”,这与榜单设计目标相冲突。
Basilisk 的定位是对 typing 语义做激进实现,所以它在语义理解上确实有独到之处。但从社区反馈看,它的实用性问题也很明显:缺少稳定的错误码体系、缺少 IDE 插件、缺少明确的生产环境使用路径。一个在基准测试里表现出色但难以嵌入日常开发流程的检查器,在排行榜上出现和消失,都是合理的结果。
2.4 移除不等于否定
这是最需要强调的一点。Basilisk 被移出 conformance leaderboard,不代表它的代码毫无价值,也不代表它过去拿出的分数是伪造的。这个事件更准确的理解是:当项目无法满足“可安装、可复现、活跃维护”这些基本门槛时,它就不再适合作为基准测试的被测对象。
从另一个角度看,Basilisk 能在 conformance 测试中获得高名次,至少说明一个独立开发者也有能力把 typing 语义的理解做到相当深入。这是对 Python 类型生态多样性的一种验证。
3. conformance leaderboard 到底怎么测
3.1 测试集的构造方式
python/typing 仓库的 conformance 测试集,本质是一个“类型检查器差分测试集合”。每个测试文件是一个.py或.pyi文件,里面包含带注释的代码。注释用于标记期望结果,测试脚本通过对比检查器实际输出与期望结果来判断是否通过。
测试代码的格式近似如下,这里只做语义示意,不是仓库原文:
from typing import List def take_int(x: int) -> None: ... take_int(1) # code: expect: No error take_int("s") # code: expect: error: Argument 1 has incompatible type "str"; expected "int"这种注释标记方式的好处是,一个文件可以同时覆盖多个类型检查器的行为预期,测试结果可以直接进行机器对比。
3.2 一次测试运行的流程
整个运行流程可以拆成以下步骤:
- 安装被测检查器到独立虚拟环境。
- 遍历测试目录中的所有测试文件。
- 对每个文件运行类型检查命令,并捕获 stdout、stderr 和退出码。
- 将实际输出与每个
# code: expect:标记的期望输出进行比对。 - 汇总所有文件的通过、失败、预期报错但未报错、报错但未预期等情况。
- 生成最终报告,展示各检查器的 conformance 分数。
复现命令的通用思路如下:
# 克隆 python/typing 仓库后,进入 conformance 相关目录 git clone https://github.com/python/typing.git cd typing # 具体运行入口以 README 为准,这里只是通用模板 python conformance/run_checker_tests.py --checker pyright --config pyright_config.json如果你打算实际跑一套测试,强烈建议使用虚拟环境,避免污染全局 Python。不同检查器之间的依赖可能互相冲突。
3.3 如何理解检查器输出
conformance 测试关注的是类型检查器对各类语法和 API 的“诊断能力”。以 mypy 为例,运行一个普通检查命令,输出格式类似:
pip install mypy mypy demo.py如果demo.py中存在类型错误,mypy 会输出类似这样的信息:
demo.py:4: error: Argument 1 to "take_int" has incompatible type "str"; expected "int"conformance 测试要对比的正是这种错误的行号、错误信息类型和消息内容。测试集并不关心业务逻辑是否正确,它只关心“类型系统是否表达了规范预期的语义”。
4. conformance 高分不等于生产可用
4.1 两个直接的反差场景
场景一:你的项目是一个几万行代码的 Django 服务。类型检查器需要在几秒内完成增量检查,需要在 IDE 里给出实时反馈,需要支持第三方库的 stubs,还需要能在 CI 中稳定运行。在这种情况下,一个在 conformance 测试里拿高分的实验性检查器,可能并不能给你带来任何提升,反而会因为缺少插件、缺少配置文档、缺少社区案例而拖慢开发流程。
场景二:你正在为 Python 类型系统贡献测试用例,或者你正在学习 PEP 484 的边界行为。这种情况下,一个对 typing 语义理解更深的检查器,确实可以帮助你看清很多边界情况。
这两个场景的核心差异在于:conformance 分数衡量的是“对规范的符合度”,而生产环境真正需要的是“在真实业务代码上的可用度”。这两件事有交集,但不相等。
4.2 分数能说明什么,不能说明什么
| 维度 | conformance 分数能反映 | conformance 分数不能完全反映 |
|---|---|---|
| 对 typing 规范的理解深度 | 直接相关 | 无 |
| 大型代码库的检查速度 | 不直接相关 | 与运行时间、增量编译、内存占用相关 |
| IDE 集成体验 | 不相关 | 与 LSP 服务、插件生态相关 |
| 错误信息的可读性 | 部分相关 | 与错误文案设计、上下文提示相关 |
| 配置与迁移成本 | 不相关 | 与默认配置、strict 程度相关 |
| 项目维护活跃度 | 不相关 | 与提交频率、发版节奏相关 |
| 社区案例与问题沉淀 | 不相关 | 与 issue 讨论、教程、企业案例相关 |
看这个表就知道,把 conformance 作为唯一选型依据是非常片面的。它更像是“类型系统语义理解”这一单项能力的雷达图,而不是完整的体检报告。
5. Python 类型检查生态现状与选型建议
5.1 主要检查器横向对比
| 检查器 | 维护方 | 核心特点 | 适合场景 |
|---|---|---|---|
| mypy | 社区 + Dropbox 长期贡献 | 最成熟、插件生态多、文档全 | 对稳定性要求高的中大型项目 |
| pyright | 微软 | 速度快、类型推断强、Pylance 内置 | VSCode 用户、希望快速反馈 |
| basedpyright | 社区 fork | pyright 扩展、更严格、兼容性好 | 想要 pyright 增强严格模式 |
| pyre | Meta | 性能较强、增量检查、配置复杂 | 大型 monorepo |
| pytype | 不需要完整注解也能推断 | 老代码逐步引入类型 |
这个对比是根据公开资料的稳定印象整理的,具体表现会随项目规模和 Python 版本变化,建议在真实代码库上验证后再定。
5.2 按场景选型
小型项目或个人项目:
- 直接用 pyright,因为它和 VSCode 集成度高,基本开箱即用。
- 如果希望把检查做得更严格,可以用 basedpyright。
中型团队或需要严格 CI:
- mypy 仍然是更稳妥的选择,因为相关资料多,团队成员查阅问题的成本低。
- 如果团队已经在用 VSCode 和 Pylance,可以先从 pyright 开始。
大型 monorepo:
- pyre 的增量检查能力更强,但配置和上手成本更高。
- 也可以考虑基于 mypy 的增量方案,配合缓存和分片检查。
5.3 配置文件示例
mypy 的pyproject.toml配置示例:
[tool.mypy] python_version = "3.12" strict = true warn_unreachable = true plugins = ["pydantic.mypy"] [[tool.mypy.overrides]] module = "tests.*" disallow_untyped_defs = falsepyright 的pyrightconfig.json配置示例:
{ "pythonVersion": "3.12", "typeCheckingMode": "strict", "reportGeneralTypeIssues": "error", "exclude": ["**/node_modules", "**/build"] }这种对比也能看出不同检查器的设计思路差异:mypy 更依赖配置项的精细控制,pyright 更偏向开箱即用再加严格模式。
6. 本地复现 conformance 测试的实操路线
6.1 准备独立环境
不建议在系统 Python 里直接装载多个类型检查器,它们依赖的第三方库可能互相冲突。推荐先创建虚拟环境。
python -m venv .venv source .venv/bin/activate pip install --upgrade pip然后按需安装类型检查器:
pip install mypy pyright basedpyright pyre-check pytype如果只是为了复现 conformance 测试,不需要全部安装,安装一两个即可。
6.2 克隆仓库与定位测试目录
git clone https://github.com/python/typing.git cd typing ls -la进入仓库后,先看 README 和 tests 相关目录结构。conformance 相关代码和测试数据通常会放在仓库的特定子目录中,具体入口以当前 README 为准,因为测试框架本身也在演进。
6.3 运行测试并解读结果
不同检查器的运行入口不同,这里给出通用模板:
# 进入 conformance 测试目录后,用项目提供的 runner 运行 python conformance/run_checker_tests.py --checker mypy --config mypy_config.json运行结束后,重点看这些指标:
- 完全通过数:检查器的输出与期望一致。
- 预期报错但未报错:说明检查器漏报。
- 报错但未预期:说明检查器误报或对规范理解有偏差。
- 运行失败:可能因为版本不兼容、依赖缺失或 Python 版本不匹配。
最终报告的分数是相对值,脱离测试集版本、Python 版本和检查器版本去比较分数没有意义。
7. Python typing conformance 测试常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| pip 安装 Basilisk 报错 | 项目不活跃、包名变化或依赖过时 | 查看官方 GitHub README 的安装说明 | 改用 mypy、pyright 等活跃检查器 |
| 本地复现分数与榜单不一致 | 检查器版本、Python 版本或配置不同 | 固定所有版本和运行参数后复跑 | 先锁定环境,再对比分数 |
| mypy strict 模式报错过多 | 老代码没有类型标注或可空类型未处理 | 先跑默认模式,观察报错量 | 用 project 配置逐步开启 strict |
| pyright 与 mypy 检查结果不一致 | 两者对部分 typing 边界的实现策略不同 | 查看官方 issue 和类型语义文档 | 以团队约定为准,二选一或双跑对照 |
| 排行榜页面看不到 Basilisk | 检查器已从榜单移除 | 看仓库历史 commit 和说明 | 以官方公告为最终结论 |
| conformance 测试运行卡住 | 检查器运行超时或依赖缺失 | 查看进程、日志、超时时间 | 增加超时限制,或单独运行失败用例 |
这个排查表适合大多数在本地复现 conformance 测试时遇到的问题。
8. 对类型检查器开发者和使用者的启示
8.1 对使用者:不要基于单一基准选型
Basilisk 的事件是一个很典型的案例。当一个检查器在单一 benchmark 上排名很高时,先不要着急替换团队现有工具,而是要看几个更实际的问题:
- 它能否被 pip 或其他包管理工具正常安装?
- 它是否有持续发版记录?
- 它是否支持你项目里的 Python 版本?
- 它是否能与 IDE、CI 正常集成?
- 它的错误信息是否可读?
任何一个答案是否定的,它在生产环境中的价值都会大打折扣。
8.2 对贡献者:conformance 高分只是入场券
如果你正在开发一个类型检查器,或者想为现有检查器贡献代码,conformance 测试是一个很好的练习场。它可以帮助你理解很多 typing 的边界行为。但要把一个检查器推广到生产环境,还需要:
- 建立稳定的发版流程和更新日志。
- 提供可复现的安装方式。
- 设计错误码体系和文档。
- 完善 IDE 集成方案。
- 维护与 Python 版本同步的兼容性测试。
单项能力的亮眼表现很重要,但生态建设才是长期可信的基础。
8.3 这个事件对 Python 类型生态的意义
从更大的视角看,Basilisk 被移出 conformance leaderboard,说明这个领域仍然处于可以被测试、被量化、被质疑的活跃阶段。一个健康的类型检查生态,既需要 mypy 这样可以支撑大型项目的成熟选项,也需要像 Basilisk 这样在某个方向上做深度实验的项目。即使实验性项目最终没有走向生产可用,它留下的测试结果、实现思路和对规范边界的探索,也仍然有一定价值。
对普通 Python 开发者来说,这件事的参考价值在于:当你看到任何“XX 榜单第一”的信息时,都应该多问一句——这个榜单测试的是什么,榜单之外还缺什么。conformance 分数只是众多指标中的一项,真正的选择应该建立在你自己的代码库、团队技术栈、IDE 习惯和 CI 流程之上。
有兴趣进一步验证的话,可以直接打开 python/typing 仓库,创建一个虚拟环境,把 pyright 和 mypy 都跑一遍,看看它们在不同 typing 特性上的表现差异。这个动作看起来简单,但足以帮你理解 conformance leaderboard 的价值在哪里,以及它的边界在哪里。