从 mypy / pyright 迁移到 ty:规则映射、严格模式与迁移实战指南
从 mypy / pyright 迁移到 ty规则映射、严格模式与迁移实战指南【免费下载链接】tyAn extremely fast Python type checker and language server, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ty2/ty迁移到新类型检查器时最大的痛点往往不是工具本身而是你早已习惯的那套“错误码方言”# type: ignore[code]、disable_error_code、reportXyz none……这些都要逐一重新学习。本文以 ty 官方迁移指南为核心系统对比 mypy / pyright / basedpyright 与 ty 的规则体系给出可直接落地的严格模式配置并附上完整的三方规则映射表。读完你可以在一个下午内完成项目迁移并借机把类型检查严格度提升到高于以往的水平。迁移速览三种检查器的“方言”对照ty 的项目定位是“用 Rust 编写、极快的 Python 类型检查器与语言服务器”它不是一个兼容 mypy 配置的克隆品而是建立在同一套 PEP 484 类型体系之上、拥有自己规则命名与严重度体系的新工具。因此迁移的第一课是把你在 mypy / pyright 里学到的配置词汇翻译成 ty 的词汇。抑制注释suppression comments的对应关系检查器行内抑制语法mypy# type: ignore[code]pyright# pyright: ignore[reportXyz]ty# ty: ignore[rule]ty 的抑制注释细节见 docs/suppression.md这里给出最常用的几种形态抑制单行违规a 10 test # ty: ignore[unsupported-operator]抑制跨行违规放在违规语句的首行或末行均可sum_three_numbers( # ty: ignore[missing-argument] 3, 2 ) # 或放在末行 sum_three_numbers( 3, 2 ) # ty: ignore[missing-argument]一行内抑制多条规则用逗号分隔sum_three_numbers(one, 5) # ty: ignore[missing-argument, invalid-argument-type]在文件开头任何 Python 代码之前放一行独立注释可抑制整个文件的特定规则# ty: ignore[invalid-argument-type]ty 还兼容 PEP 484 标准的type: ignore注释。值得特别注意的是它的混合能力# 忽略下一行所有类型错误 sum_three_numbers(one, 5) # type: ignore # 同一个注释里同时写 mypy 错误码和 ty 规则 sum_three_numbers(one, 5, 2) # type: ignore[arg-type, ty:invalid-argument-type]其中type: ignore[ty:rule]只抑制匹配的 ty 规则不带ty:前缀的错误码会被忽略——这使你可以在一行注释里同时兼容多个类型检查器非常适合迁移过渡期“mypy/ty 并存”的场景。两个与迁移直接相关的细节与其他工具的注释共存一行上可以同时挂多个注释例如result calculate() # ty: ignore[invalid-argument-type] # fmt: skip。no_type_checkty 支持用typing.no_type_check装饰器抑制函数体内的全部违规但不支持装饰整个类。如果你的项目里还留着大量旧式# type: ignore注释可以留意respect-type-ignore-comments配置项默认true将其设为false后type: ignore会被当作普通注释必须改用ty: ignore才能抑制错误适合希望完全切到 ty 语法的团队。配置方式见 docs/reference/configuration.md。全局禁用规则的对应关系mypy 的disable_error_code [...]与 pyright 的reportXyz none在 ty 中统一对应为把规则级别设为ignore[tool.ty.rules] possibly-unresolved-reference warn division-by-zero ignore在 pyproject.toml 中 ty 使用[tool.ty.rules]顶层键如果你用独立的ty.toml则写作[rules]。可用的严重度只有三档ignore禁用该规则warn启用产生警告级诊断error启用产生错误级诊断注意pyright 的information级别与 basedpyright 的hint级别在 ty 中没有直接对应——迁移时统一用warn代替。默认情况下只要存在warn或error级诊断ty 就以退出码 1 结束若希望只有警告时仍以 0 退出可设[tool.ty.terminal] error-on-warning false详见 docs/reference/configuration.md。命令行层的“方言”除了配置文件ty 的命令行也提供了规则级别的快捷控制详见 docs/reference/cli.mdty check --errorall # 把所有规则设为 error 级别 ty check --warnrule-name # 把指定规则设为 warn可重复传 ty check --ignorerule-name # 禁用指定规则可重复传这些选项等价于 mypy 命令行中的--disable-error-code/--enable-error-code之类的能力且--config选项传入的单个设置优先级高于所有配置文件。无类型代码的检查策略差异这是迁移中最容易踩坑的行为差异三条规则必须记住ty 没有对应disallow_untyped_defsmypy/no-untyped-def、reportMissingParameterType、reportUnknownParameterTypepyright的规则。ty 不会对未标注的函数参数、返回值或变量报错而是把这类符号的类型推断为Unknown详见 docs/reference/typing-faq.md 中 “Why doesnt ty warn about missing type annotations?” 一节。如果你需要强制补全注解等价物在 Ruff 侧flake8-annotationsANN规则组例如ANN001函数参数缺注解、ANN201公共函数缺返回注解等。ty 无条件检查无注解函数的函数体因此不存在与 mypycheck_untyped_defs对应的 ty 规则——它本来就是 ty 的默认行为且目前不可配置。pyright 侧的对等概念是analyzeUnannotatedFunctions true这也是 pyright 的默认值。ty 没有--check-untyped-defs或strictListInference这类开关因为它们对应的行为检查无注解函数体、对列表做元素级推断同样是 ty 的默认行为。例如在 pyright 的非严格模式下[1, foo]会被推断为list[Unknown]而 ty 直接推断为list[int | str]。更严格的检查ty 的默认严格度与推荐配置mypy 和 pyright 的strict模式不只是“多开几个错误码”它还会根本性地改变类型推断与检查的工作方式mypy 的 strict 包含--check-untyped-defs否则无注解函数完全不被检查pyright 的 strict 包含strictListInference否则列表字面量被推断为list[Unknown]。ty 的默认模式在诸多方面已经比两者的默认甚至 strict模式更严格原因有二那些在 mypy/pyright 中需要显式开启的行为如检查无注解函数体是 ty 的默认行为且不可配置几乎所有 ty 规则默认都是开启的默认关闭的规则通常是因为“过于主观”或“误报较多”。注意ty 目前没有名为--strict的标志见 docs/reference/typing-faq.md 的 “Does ty have a strict mode?” 一节但你可以用配置近似出其他检查器的--strict。推荐配置一近似 mypy / pyright 的--strict[tool.ty.rules] dynamic-function-decorator-return error missing-type-argument error possibly-unresolved-reference warn unsound-return-statement error [tool.ruff.lint] extend-select [ANN, PYI] preview true这份配置的作用拆解如下开启 ty 中默认关闭的四条规则dynamic-function-decorator-return对应 mypyuntyped-decorator/ pyrightreportUntypedFunctionDecorator、missing-type-argument对应 mypytype-arg/ pyrightreportMissingTypeArgument、possibly-unresolved-reference对应 mypypossibly-undefined/ pyrightreportPossiblyUnboundVariable、unsound-return-statement对应 mypyno-any-return把 Ruff 的默认规则扩展到ANNflake8-annotations与PYIflake8-pyi两个类别——它们都专注于“更有效地给代码加注解”开启 Ruff preview 模式使PYI033legacy type comment对应 pyrightreportTypeCommentUsage同时检查.py文件。推荐配置二比 strict 更严格[tool.ty.rules] blanket-ignore-comment error dynamic-function-decorator-return error missing-type-argument error possibly-unresolved-reference warn unsound-assignment error unsound-return-statement error unsound-yield error unsupported-dynamic-base warn # NOTE: 以下规则已知存在大量基本无法避免的误报启用风险自负 division-by-zero warn possibly-missing-attribute warn possibly-missing-import warn [tool.ty.analysis] strict-equality-semantics true strict-generic-narrowing true [tool.ruff.lint] extend-select [ANN, PYI, PGH003] preview true与第一份配置相比它额外启用了blanket-ignore-comment对应 mypyignore-without-code/ basedpyrightreportIgnoreCommentWithoutRule要求所有ignore注释都写明规则名Ruff 侧的PGH003同样禁止裸# type: ignoreunsound-assignment仅针对变量与unsound-yield这两条在 mypy / pyright 中没有直接对应见映射表unsupported-dynamic-base目前标记为warn因其可能误报两条[tool.ty.analysis]严格化开关它们的语义如下完整说明见 docs/reference/configuration.mdstrict-equality-semantics默认false控制相等性检查的类型推断与收窄行为。默认情况下 ty 会做出若干符合直觉但不完全 sound 的假设例如from typing import Literal def parse(value: str) - Literal[a] | None: # 开启 strict-equality-semantics true 后这里不发生收窄 # 并在 return 语句上报错。 if value a: return value return None不 sound 的原因在于Literal[a]只能被恰好是str的实例占据而str的子类以及StrEnum默认与a比较相等却不属于Literal[a]。开启该选项后ty 对相等性推断更保守不把str收窄为Literal[a]也不会假设子类不会覆写__eq__/__ne__从而不再把Foo | None在x other后收窄为Foo。该选项同样影响in检查与match值模式中的收窄。strict-generic-narrowing默认false控制未特化泛型类在isinstance()/issubclass()、match类模式、TypeIs检查中的收窄方式。开启后isinstance(value, list)会把object收窄为Top[list[Unknown]]所有可能list特化的无限并集迭代元素类型为object关闭时使用渐进式泛型收窄尽可能保留原类型参数——例如把Sequence[int]收窄为list[int]无特化可循时才收窄为list[Unknown]。文中PGH003、ANN、PYI等 Ruff 规则均属于 Ruff lint 范畴与 ty 的规则体系互补ty 负责类型正确性诊断Ruff 负责注解完整性与代码风格。若你尚未在项目中引入 Ruff可参考仓库根目录的 pyproject.toml 中的[tool.ruff.lint]配置进行扩展。规则映射总表mypy / pyright → ty / Ruff映射表是迁移时的核心查表工具。阅读方法如下ty or Ruff rule 列优先给出 ty 规则名完整清单见 docs/reference/rules.md在[tool.ty.rules]下配置若该检查没有 ty 规则而 Ruff 提供了等价覆盖则给出 Ruff 规则或规则组Mypy error code 列传给# type: ignore[code]或disable_error_code的错误码。部分 ty 规则会以 mypy 的兜底错误码misc、assignment、valid-type形式出现这类映射是故意放宽的Pyright diagnostic 列pyrightconfig.json或[tool.pyright]中的report*设置。同一诊断可能在多行出现对应不同子情形空白单元格表示该检查器没有直接对应物要么不产生该诊断要么已被折叠进其他 ty 规则对应的更宽泛类别中。有 ty 规则的映射ty / Ruff 规则mypy 错误码pyright / basedpyright 诊断abstract-and-final-methodmiscabstract-method-in-final-classmiscreportGeneralTypeIssuescall-abstract-methodreportAbstractUsagecall-non-callableoperator、miscreportCallIssue、reportOptionalCallconflicting-declarationsno-redefreportRedeclarationconflicting-metaclassmetaclassreportGeneralTypeIssuescyclic-class-definitionmiscreportGeneralTypeIssuesdataclass-field-ordermiscreportGeneralTypeIssuesdeprecateddeprecatedreportDeprecateddisjoint-castreportInvalidCast仅 basedpyrightdivision-by-zeroduplicate-basemiscreportGeneralTypeIssuesduplicate-kw-onlymiscdynamic-function-decorator-returnuntyped-decoratorreportUntypedFunctionDecorator仅 Unknown 返回empty-bodyempty-bodyreportReturnType...函数体豁免final-on-non-methodmiscreportGeneralTypeIssuesfinal-without-valuemiscreportGeneralTypeIssuesinconsistent-mromiscreportGeneralTypeIssuesindex-out-of-boundsmiscreportGeneralTypeIssuesinvalid-argument-typearg-type、index、type-var、typeddict-itemreportArgumentType、reportAssignmentTypeinvalid-assignmentassignment、list-item、dict-itemreportAssignmentTypeinvalid-assignment仅不兼容的方法替换method-assign拒绝一切方法赋值reportAttributeAccessIssue仅不兼容替换invalid-assignmentTypedDict 键值typeddict-itemreportGeneralTypeIssuesinvalid-assignment只读 TypedDict 键typeddict-readonly-mutatedreportTypedDictNotRequiredAccess仅只读修改invalid-attribute-accessmiscreportAttributeAccessIssueinvalid-attribute-overridemiscreportIncompatibleVariableOverride仅类/实例变量invalid-awaitmiscreportGeneralTypeIssuesinvalid-basevalid-type、miscreportGeneralTypeIssuesinvalid-context-managermisc、attr-defined、union-attrreportGeneralTypeIssues、reportOptionalContextManagerinvalid-dataclassmiscinvalid-exception-caughtmiscreportGeneralTypeIssuesinvalid-explicit-overridemiscreportGeneralTypeIssuesinvalid-frozen-dataclass-subclassmiscreportGeneralTypeIssuesinvalid-keytypeddict-item、typeddict-unknown-keyreportGeneralTypeIssues、reportAssignmentType、reportCallIssueinvalid-legacy-type-variablemisc、valid-typereportGeneralTypeIssues、reportInvalidTypeForminvalid-metaclassmetaclassinvalid-method-overrideoverridereportIncompatibleMethodOverrideinvalid-module-getattr-callinvalid-newtypevalid-newtype、miscreportGeneralTypeIssues、reportArgumentTypeinvalid-overloadno-overload-impl、miscreportNoOverloadImplementation、reportInconsistentOverloadinvalid-parameter-defaultassignmentreportArgumentTypeinvalid-protocolmiscreportGeneralTypeIssuesinvalid-raisemiscreportGeneralTypeIssuesinvalid-return-typereturn、return-valuereportReturnTypeinvalid-type-argumentsmisc、type-varreportInvalidTypeArgumentsinvalid-type-formvalid-typereportInvalidTypeForm、reportGeneralTypeIssuesinvalid-type-guard-definitionnarrowed-type-not-subtype、valid-typereportGeneralTypeIssuesinvalid-type-variable-boundvalid-type、miscreportGeneralTypeIssuesinvalid-type-variable-constraintsvalid-type、miscreportGeneralTypeIssuesinvalid-type-variable-defaultmiscreportGeneralTypeIssuesinvalid-typed-dict-fieldmiscreportIncompatibleVariableOverrideinvalid-yieldmiscreportReturnTypeisinstance-against-protocolmiscreportArgumentType、reportGeneralTypeIssuesisinstance-against-typed-dictmiscreportArgumentType、reportGeneralTypeIssuesmismatched-type-namename-match、miscreportGeneralTypeIssuesmissing-argumentcall-argreportCallIssuemissing-override-decoratorexplicit-overridereportImplicitOverridemissing-type-argumenttype-argreportMissingTypeArgumentmissing-typed-dict-keytypeddict-itemreportAssignmentTypeno-matching-overloadcall-overloadreportCallIssuenot-iterablemisc、attr-defined、union-attrreportGeneralTypeIssues、reportOptionalIterablenot-subscriptableindexreportIndexIssue、reportOptionalSubscriptoverride-of-final-methodmiscreportIncompatibleMethodOverrideoverride-of-final-variablemiscreportGeneralTypeIssuesparameter-already-assignedmisc、call-argreportCallIssuepositional-only-parameter-as-kwargcall-argreportCallIssuepossibly-missing-attributepossibly-unresolved-referencepossibly-undefinedreportPossiblyUnboundVariableredundant-castredundant-castreportUnnecessaryCastredundant-condition仅确定真值性truthy-boolredundant-condition仅函数对象truthy-functionreportUnnecessaryComparisonredundant-condition、redundant-condition-strictredundant-expr注意与 mypy 不同ty 只在if测试等布尔条件中检查and/or不检查用于计算值的情形redundant-condition、redundant-condition-strictcomparison-overlap仅布尔条件中其余情形尚未实现reportUnnecessaryComparison、reportUnnecessaryContains均仅布尔条件中redundant-condition、redundant-condition-strictunreachable布尔条件中导致不可达代码的情形其余尚未实现reportUnreachable仅布尔条件中导致不可达代码的情形redundant-condition-strictreportUnnecessaryIsInstance布尔条件中subclass-of-final-classmiscreportGeneralTypeIssuestoo-many-positional-argumentscall-argreportCallIssuetype-assertion-failureassert-typereportAssertTypeFailureunbound-type-variablevalid-typereportGeneralTypeIssuesundefined-revealunimported-revealunknown-argumentcall-argreportCallIssueunresolved-attributeattr-defined、union-attrreportAttributeAccessIssue、reportFunctionMemberAccess、reportOptionalMemberAccessunresolved-importimport-not-foundreportMissingImportsunresolved-reference RuffF823name-defined、used-before-defreportUndefinedVariable、reportUnboundVariableunsound-assignment仅变量unsound-return-statementno-any-returnunsound-yieldunsupported-operatoroperatorreportOperatorIssue、reportOptionalOperandunused-awaitable仅原生协程unused-coroutine、unused-awaitablereportUnusedCoroutineunused-ignore-commentunused-ignorereportUnnecessaryTypeIgnoreCommentunused-type-ignore-commentunused-ignorereportUnnecessaryTypeIgnoreCommentblanket-ignore-comment RuffPGH003ignore-without-codereportIgnoreCommentWithoutRule仅 basedpyright由 Ruff 规则覆盖的映射ty / Ruff 规则mypy 错误码pyright / basedpyright 诊断RuffF631reportAssertAlwaysTrueRuffB006、B008部分覆盖排除不可变注解与调用reportCallInDefaultInitializerRuffF811、I001部分覆盖可能漏掉独立 import 块reportDuplicateImportRuffISC001、ISC002reportImplicitStringConcatenationRuffW605reportInvalidStringEscapeSequenceRuffPYI010、PYI017、PYI048、PYI052reportInvalidStubStatementRuffSLF001、PLC2701部分覆盖PLC2701需 previewreportPrivateUsageRuffN804、N805reportSelfClsParameterNameRuffPYI033.py文件需 previewreportTypeCommentUsageRuffF822、PLE0604、PLE0605、PYI056reportUnsupportedDunderAllRuffPYI024reportUntypedNamedTupleRuffARG系列reportUnusedParameter仅 basedpyrightRuffB025仅重复异常处理器其余情形跟踪中reportUnusedExceptRuffB015、B018reportUnusedExpressionRuffF401reportUnusedImportRuffF841仅函数局部变量reportUnusedVariableRuffF403reportWildcardImportFromLibraryRuffANN401仅函数注解explicit-anyreportExplicitAny仅 basedpyrightRuffANN系列no-untyped-defreportMissingParameterType、reportUnknownParameterType尚未实现迁移时请保持心理预期原文档明确指出mypy 和 pyright 的若干检查 ty 尚未实现。映射表中已标出“None yet”的行这里汇总最常遇到的几类ty 侧状态mypy 错误码pyright / basedpyright 诊断实例化抽象类尚无规则abstractreportAbstractUsage向需要具体类的位置传抽象类暂无直接等价实现计划type-abstract通过super()调用抽象方法尚无规则safe-superreportAbstractUsage尚无规则跟踪中reportConstantRedefinition、reportImportCycles、reportIncompleteStub、reportInconsistentConstructor、reportInvalidTypeVarUse、reportMatchNotExhaustive、reportMissingModuleSource、reportMissingSuperCall、reportMissingTypeStubs、reportOverlappingOverload、reportPrivateImportUsage、reportPropertyTypeMismatch、reportTypedDictNotRequiredAccess非必需键访问、reportUnhashable、reportUninitializedInstanceVariable、reportUnusedClass、reportUnusedFunction、reportUnusedCallResult 等尚无规则reportUnknownArgumentType、reportUnknownLambdaType、reportUnknownMemberType、reportUnknownVariableType、reportUntypedBaseClass、reportUntypedClassDecorator尚无规则var-annotated、func-returns-value、no-any-unimported、truthy-iterable尚无规则跟踪中no-untyped-call、import-untyped、mutable-override、overload-cannot-match、overload-overlap、exhaustive-match、attr-defined由--no-implicit-reexport扩展、type-var其中与“Unknown 相关”的一族reportUnknown*尤其值得注意它对应的是 pyright 对“类型未知”的告警而 ty 的哲学是用Unknown渐进类型在无注解代码中避免误报详见 docs/reference/typing-faq.md 对Unknown类型的解释——这解释了为什么 ty 选择不实现这些检查。ty 的完整规则清单包括上表中没有直接对应物的规则见 docs/reference/rules.md。迁移 FAQ 与常见坑以下问题在原文档及配套 FAQdocs/reference/typing-faq.md中有更完整的讨论这里给出与迁移直接相关的要点ty 没有--strict标志但默认就相当严格用本文第二节的两份配置可以近似甚至超越其他检查器的 strict 模式。“为什么 ty 不警告缺注解”这是设计决策而非缺陷——ty 把缺注解符号推断为Unknown继续提供其余有用的诊断需要强制注解时用 RuffANN规则组。未使用的抑制注释开启unused-ignore-comment规则后ty 会报告未生效的ty: ignore与type: ignore注释。这类违规只能用# ty: ignore[unused-ignore-comment]抑制不能用裸# ty: ignore或# type: ignore见 docs/suppression.md。迁移旧代码时历史遗留的type: ignore很容易触发此规则需要逐个清理。迁移过渡期可以双跑ty check与旧检查器并行运行利用type: ignore[arg-type, ty:invalid-argument-type]这种混合注释逐步替换直到确认 ty 的诊断稳定后再完全切换。--errorall慎用文档明确建议不要用--errorall一把梭因为默认关闭的规则多为“主观”或“误报多”的规则按需开启是更稳妥的路径。迁移检查清单用# ty: ignore[rule]替换# type: ignore[code]与# pyright: ignore[reportXyz]过渡期可用混合注释type: ignore[ty:rule]与旧检查器共存。把disable_error_code/reportXyz none迁移为[tool.ty.rules]下的ignorepyright 的information、basedpyright 的hint一律用warn。需要强制注解时引入 RuffANN必要时再加PYI、PGH003并开启 preview 以获得PYI033等新能力。按第二节推荐配置逐条审视默认关闭的规则优先启用dynamic-function-decorator-return、missing-type-argument、unsound-return-statement等误报可控的规则division-by-zero、possibly-missing-attribute、possibly-missing-import等高误报规则谨慎启用。在 CI 中先以ty check替换或并行旧检查器结合unused-ignore-comment清理历史抑制注释对照映射表确认尚未实现的检查是否影响你的代码库必要时用 Ruff 规则补位。【免费下载链接】tyAn extremely fast Python type checker and language server, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ty2/ty创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →