Pyright 是一个 Python 类型检查器,而 Basedpyright 是 的一个非理智的分支。
# pyproject.toml
[tool.pyright]
enableTypeIgnoreComments = true
reportIgnoreCommentWithoutRule = false
reportAny = false
reportExplicitAny = false
reportInvalidCast = false
reportRedeclaration = false
reportPrivateImportUsage = false
reportMissingModuleSource = false
reportUnknownMemberType = false
reportUnknownArgumentType = false
reportUnknownParameterType = false
reportUnknownVariableType = false
reportUnknownLambdaType = false
你说得对,但 Pyright 是由 Microsoft 开发的一款 Python Language Server。尽管由 Node.js 驱动,这款 LSP 的性能甚至超过竞品,并通过捆绑销售在 Visual Studio Code 中广泛被使用。但 VSC 中提供的是加入了额外闭源功能的变体 Pylance,因此在其他编辑器中使用体验不佳或直接被封禁。Basedpyright 是一个尝试向 Pyright 添加更多 LSP 功能的社区分支,其中的 inlay hint 等功能十分实用,但这一分支尽管自称 based
,但仍然引入了一些偏执的选项——这与 Pylance 行为不一致,且在基础类型检查(basic
)中默认开启。本文记录如何修正这些偏执的选项。
特别注意,我们不考虑 baseline 文件。在被迫使用别人制造的💩️时,严于律己没有任何裨益。
Ignore 注释
Basedpyright 默认禁用 # type: ignore
而是要求换用 # pyright: ignore[<理由>]
。这听起来像是 TypeScript 社区的优秀实践,但实际上,由于 Python 的渐进类型系统和静态类型检查以搞笑为主,常用的第三方库代码质量经常一团糟,# type: ignore
成了强力压制暴走的类型检查器或流氓第三方库的居家必备之佳品。在很多情况下,用户根本不想解释理由(给类型检查器的注释有时比实际代码都长?),并向代码直接扔了一个 # type: ignore
,这是 PEP 484 所准许的。因此,通过 enableTypeIgnoreComments = true
和 reportIgnoreCommentWithoutRule = false
强制恢复标准行为。
Any
作为类型系统的顶端,Any
在面对别人的💩代码时是很难避免的,对于一个动态类型语言来说它也非常本质。但 Basedpyright 偏要默认警告隐式显式的 Any
用例,惨绝人寰,因此将 reportAny
和 reportExplicitAny
都关闭。此外,TypeScript 中强制转换到不兼容的类型写作 as any as T
,在对结构化类型(structural typing)支持十分苟且的 Python 中用 typing.cast
本可以一步到位,但 Basedpyright 又将其封堵,因此关闭 reportInvalidCast
。
Unknown
Pyright 系列中引入了一个 Python 类型系统中不存在的 Unknown
类型,这个类型和 TypeScript 的 unknown
不同,实质上等价于隐式的 Any
,允许进行任何操作(相比之下,TypeScript 的 unknown
不允许进行任何操作,除非强制类型转换)。
Unknown
无非以下情况:使用了没有类型标注的代码,类型检查器推不出来类型,或者这个类型在 Python 里完全写不出来直接摆烂。因此,禁止 Unknown
的出现大概率是自讨苦吃。
Pyright 一共实现了五条 Unknown
规则:reportUnknown{Member, Argument, Parameter, Variable, Lambda}Type
。其中,reportUnknownLambdaType
更是重量级,因为 Python 的 lambda
表达式里面根本不支持标注任何类型。在 Pyright 中,这几条规则都被设为了关闭,只在 strict
模式下打开,但 Basedpyright 把它在 recommend
模式下设为了警告,这对于主要使用第三方库(即:面对别人的💩代码)的场景来说十分不友好。但经测试,似乎 Basedpyright 1.29.0 在关闭类型检查的情况下也会爆警告,只好填配置通通关闭掉。
遮蔽
在 Python 中遮蔽已经定义过的名字是常见的用例——因为这是一门动态语言!尽管应当尽力避免这种用法,但在中间变量过多的情况下它让代码变得更可读,且有时需要在运行时动态遮蔽不支持的实现(implementation)。因此无论 Pyright / Pylance 还是 Basedpyright 都应当考虑关闭 reportRedeclaration
。
其他
reportPrivateImportUsage
,对于质量非常差且不再更新维护的第三方库来说,包装其底层实现是合理的。reportMissingModuleSource
,人家模块有没有实现不关类型检查器的事——也许这是运行时动态注入实现呢?