Back to Ty

Coming from mypy or pyright

docs/coming-from-mypy-or-pyright.md

0.0.5149.3 KB
Original Source

Coming from mypy or pyright

This guide helps you migrate a project from mypy or pyright to ty.

Migration tips

  • mypy disables an error code with # type: ignore[code]; pyright suppresses a single line with # pyright: ignore[reportXyz]; ty's equivalent is # ty: ignore[rule]. See this page for more information about suppression comments.
  • mypy's disable_error_code and pyright's reportXyz = "none" both correspond to setting <rule> = "ignore" under [tool.ty.rules]. See this section for details.
  • Severities in ty are ignore, warn, error. Pyright's "information" and "hint" levels have no direct ty equivalent — use warn for both.
  • If you are looking for the equivalent of disallow_untyped_defs / no-untyped-def (mypy) or reportMissingParameterType, reportUnknownParameterType (pyright), check out this FAQ entry.
  • Unlike mypy, ty checks the bodies of unannotated functions unconditionally, so there is no ty rule corresponding to mypy's check_untyped_defs setting. The equivalent pyright setting is analyzeUnannotatedFunctions = true.

Stricter checking with ty

For both mypy and pyright, "strict" mode enables several error codes that are otherwise disabled by default, but also makes fundamental changes to the way type inference and type checking works. Mypy's strict mode includes --check-untyped-defs, for example, without which unannotated functions are left unchecked; pyright's strict mode includes strictListInference, without which [1, "foo"] will be inferred as having type list[Unknown] rather than list[int | str] or similar.

ty's default mode is currently stricter by default than either mypy or pyright in many ways. ty does not have flags such as --check-untyped-defs or strictListInference, because these are ty's default behaviour and are not currently configurable. Meanwhile, nearly all ty rules are enabled by default, and the ones that are disabled by default are usually in that category because they are either very opinionated or have many false positives.

To enable all ty rules at once with the error severity, you can simply use --error=all, but we wouldn't recommend it. Instead, you can currently approximate something similar to the --strict mode of other type checkers with the following configuration:

toml
[tool.ty.terminal]
error-on-warning = true

[tool.ty.rules]
missing-type-argument = "error"
possibly-unresolved-reference = "warn"

[tool.ruff.lint]
extend-select = ["ANN", "PYI"]

This configuration:

  • Ensures ty exits with a non-zero status if it emits any warning-level diagnostics
  • Enables ty's disabled-by-default missing-type-argument and possibly-unresolved-reference rules
  • Extends Ruff's default rules with the ANN and PYI rule categories, both of which are focussed on type-annotating your code more effectively

Note that several checks in mypy and pyright are not yet implemented in ty. See the rule mapping table below for more details.

Mapping pyright/mypy rules to ty/Ruff rules

How to read this table

  • ty or Ruff rule: the canonical name, as listed in Rules if it is a ty rule. Configure ty rules under [tool.ty.rules]. Where Ruff provides equivalent coverage for a check that has no ty rule, the relevant Ruff rule or rule group is linked instead.
  • mypy error code: the value passed to # type: ignore[<code>] or disable_error_code. Some ty rules surface as one of mypy's catch-all codes (misc, assignment, valid-type); these mappings are deliberately broad.
  • pyright diagnostic: the report* setting in pyrightconfig.json or [tool.pyright].

A blank cell means no direct equivalent exists in that checker (the diagnostic is either not emitted, or is folded into a broader category that already appears for another ty rule).

Rules

ty or Ruff rulemypy error codepyright diagnostic
call-abstract-methodreportAbstractUsage
call-non-callableoperatorreportCallIssue
conflicting-declarationsno-redefreportRedeclaration
conflicting-metaclassmetaclassreportGeneralTypeIssues
cyclic-class-definitionmiscreportGeneralTypeIssues
deprecateddeprecatedreportDeprecated
division-by-zero
duplicate-basemiscreportGeneralTypeIssues
empty-bodyempty-body
inconsistent-mromiscreportGeneralTypeIssues
index-out-of-boundsmiscreportGeneralTypeIssues
invalid-argument-typearg-type
index
type-var
typeddict-itemreportArgumentType
reportAssignmentType
invalid-assignmentassignmentreportAssignmentType
invalid-attribute-accessmiscreportAttributeAccessIssue
invalid-awaitmiscreportGeneralTypeIssues
invalid-basevalid-typereportGeneralTypeIssues
invalid-context-managermisc
attr-definedreportGeneralTypeIssues
invalid-exception-caughtmiscreportGeneralTypeIssues
invalid-keytypeddict-item
typeddict-unknown-keyreportAssignmentType
invalid-metaclassmetaclass
invalid-method-overrideoverridereportIncompatibleMethodOverride
invalid-overloadno-overload-implreportNoOverloadImplementation
invalid-parameter-defaultassignmentreportArgumentType
invalid-raisemiscreportGeneralTypeIssues
invalid-return-typereturn-valuereportReturnType
invalid-type-argumentsmisc
type-varreportInvalidTypeArguments
invalid-type-formvalid-typereportInvalidTypeForm
missing-argumentcall-argreportCallIssue
missing-override-decoratorexplicit-overridereportImplicitOverride
missing-type-argumenttype-argreportMissingTypeArgument
missing-typed-dict-keytypeddict-itemreportAssignmentType
no-matching-overloadcall-overloadreportCallIssue
not-iterablemisc
attr-definedreportGeneralTypeIssues
not-subscriptableindexreportIndexIssue
parameter-already-assignedmisc
call-argreportCallIssue
possibly-missing-attribute
possibly-unresolved-referencepossibly-undefinedreportPossiblyUnboundVariable
redundant-castredundant-castreportUnnecessaryCast
too-many-positional-argumentscall-argreportCallIssue
type-assertion-failureassert-typereportAssertTypeFailure
undefined-revealunimported-reveal
unknown-argumentcall-argreportCallIssue
unresolved-attributeattr-defined
union-attrreportAttributeAccessIssue
reportOptionalMemberAccess
unresolved-importimport-not-foundreportMissingImports
unresolved-referencename-definedreportUndefinedVariable
unsupported-operatoroperatorreportOperatorIssue
unused-awaitableunused-coroutine
unused-awaitablereportUnusedCoroutine
unused-ignore-commentunused-ignorereportUnnecessaryTypeIgnoreComment
None yet (tracked in Ruff #10137)reportConstantRedefinition
Ruff F811
Ruff I001reportDuplicateImport
None yet (tracked in #3647)reportImportCycles
None yetreportIncompleteStub
None yet (tracked in #3651)reportInconsistentConstructor
Ruff W605reportInvalidStringEscapeSequence
Ruff PYI010
Ruff PYI017
Ruff PYI048
Ruff PYI052reportInvalidStubStatement
None yet (tracked in #1017, #3636, #3637)type-varreportInvalidTypeVarUse
None yet (tracked in #1060)exhaustive-matchreportMatchNotExhaustive
None yet (tracked in #1577)reportMissingModuleSource
None yet (tracked in #3652)reportMissingSuperCall
None yet (tracked in #3638)import-untypedreportMissingTypeStubs
None yet (tracked in #103)overload-overlapreportOverlappingOverload
None yet (tracked in #200)attr-defined
(extended by --no-implicit-reexport)reportPrivateImportUsage
None yet (tracked in #3633)reportPropertyTypeMismatch
Ruff N804
Ruff N805reportSelfClsParameterName
Ruff PYI033 (stubs only)reportTypeCommentUsage
None yet (tracked in #2810)reportTypedDictNotRequiredAccess
None yet (tracked in #2954)reportUninitializedInstanceVariable
None yet (tracked in #576)comparison-overlapreportUnnecessaryComparison
reportUnnecessaryContains
None yet (tracked in #1948)unreachablereportUnreachable
Ruff F822
Ruff PLE0604
Ruff PLE0605
Ruff PYI056reportUnsupportedDunderAll
Ruff PYI024reportUntypedNamedTuple
Ruff B018reportUnusedExpression
Ruff F403reportWildcardImportFromLibrary
None yetno-any-return
None yetno-untyped-call
Ruff ANN rulesno-untyped-defreportMissingParameterType
reportUnknownParameterType
None yetuntyped-decoratorreportUntypedFunctionDecorator

The full list of ty rules — including those without a direct equivalent above — is in Rules. Contributions to extend this mapping are welcome via pull request to the ty repository; see issue #2111 for context.