Skip to content

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" level and basedpyright's "hint" level 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:

[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

This configuration:

An even stricter configuration -- that goes beyond what mypy and pyright check for in their default --strict mode in several respects -- might look like this:

[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: the following rules are known to have a significant number of false positives,
# which is mostly unavoidable. Enable them at your own risk!
division-by-zero = "warn"
possibly-missing-attribute = "warn"
possibly-missing-import = "warn"

[tool.ty.analysis]
strict-literal-narrowing = true
strict-generic-narrowing = true

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

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 diagnostic may appear in multiple rows when it covers distinct cases. 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 rule Mypy error code Pyright or basedpyright diagnostic
abstract-and-final-method misc
abstract-method-in-final-class misc reportGeneralTypeIssues
call-abstract-method reportAbstractUsage
call-non-callable operator
misc
reportCallIssue
reportOptionalCall
conflicting-declarations no-redef reportRedeclaration
conflicting-metaclass metaclass reportGeneralTypeIssues
cyclic-class-definition misc reportGeneralTypeIssues
dataclass-field-order misc reportGeneralTypeIssues
deprecated deprecated reportDeprecated
division-by-zero
duplicate-base misc reportGeneralTypeIssues
duplicate-kw-only misc
dynamic-function-decorator-return untyped-decorator reportUntypedFunctionDecorator (Unknown returns only)
empty-body empty-body reportReturnType (... bodies are exempt)
final-on-non-method misc reportGeneralTypeIssues
final-without-value misc reportGeneralTypeIssues
inconsistent-mro misc reportGeneralTypeIssues
index-out-of-bounds misc reportGeneralTypeIssues
invalid-argument-type arg-type
index
type-var
typeddict-item
reportArgumentType
reportAssignmentType
invalid-assignment assignment
list-item
dict-item
reportAssignmentType
invalid-assignment (incompatible method replacements only) method-assign (rejects all method assignments) reportAttributeAccessIssue (incompatible replacements only)
invalid-assignment (TypedDict item values) typeddict-item reportGeneralTypeIssues
invalid-assignment (read-only TypedDict keys) typeddict-readonly-mutated reportTypedDictNotRequiredAccess (read-only mutations only)
invalid-attribute-access misc reportAttributeAccessIssue
invalid-attribute-override misc reportIncompatibleVariableOverride (class/instance variables only)
invalid-await misc reportGeneralTypeIssues
invalid-base valid-type
misc
reportGeneralTypeIssues
invalid-context-manager misc
attr-defined
union-attr
reportGeneralTypeIssues
reportOptionalContextManager
invalid-dataclass misc
invalid-exception-caught misc reportGeneralTypeIssues
invalid-explicit-override misc reportGeneralTypeIssues
invalid-frozen-dataclass-subclass misc reportGeneralTypeIssues
invalid-key typeddict-item
typeddict-unknown-key
reportGeneralTypeIssues
reportAssignmentType
reportCallIssue
invalid-legacy-type-variable misc
valid-type
reportGeneralTypeIssues
reportInvalidTypeForm
invalid-metaclass metaclass
invalid-method-override override reportIncompatibleMethodOverride
invalid-module-getattr-call
invalid-newtype valid-newtype
misc
reportGeneralTypeIssues
reportArgumentType
invalid-overload no-overload-impl
misc
reportNoOverloadImplementation
reportInconsistentOverload
invalid-parameter-default assignment reportArgumentType
invalid-protocol misc reportGeneralTypeIssues
invalid-raise misc reportGeneralTypeIssues
invalid-return-type return
return-value
reportReturnType
invalid-type-arguments misc
type-var
reportInvalidTypeArguments
invalid-type-form valid-type reportInvalidTypeForm
reportGeneralTypeIssues
invalid-type-guard-definition narrowed-type-not-subtype
valid-type
reportGeneralTypeIssues
invalid-type-variable-bound valid-type
misc
reportGeneralTypeIssues
invalid-type-variable-constraints valid-type
misc
reportGeneralTypeIssues
invalid-type-variable-default misc reportGeneralTypeIssues
invalid-typed-dict-field misc reportIncompatibleVariableOverride
invalid-yield misc reportReturnType
isinstance-against-protocol misc reportArgumentType
reportGeneralTypeIssues
isinstance-against-typed-dict misc reportArgumentType
reportGeneralTypeIssues
mismatched-type-name name-match
misc
reportGeneralTypeIssues
missing-argument call-arg reportCallIssue
missing-override-decorator explicit-override reportImplicitOverride
missing-type-argument type-arg reportMissingTypeArgument
missing-typed-dict-key typeddict-item reportAssignmentType
no-matching-overload call-overload reportCallIssue
not-iterable misc
attr-defined
union-attr
reportGeneralTypeIssues
reportOptionalIterable
not-subscriptable index reportIndexIssue
reportOptionalSubscript
override-of-final-method misc reportIncompatibleMethodOverride
override-of-final-variable misc reportGeneralTypeIssues
parameter-already-assigned misc
call-arg
reportCallIssue
positional-only-parameter-as-kwarg call-arg reportCallIssue
possibly-missing-attribute
possibly-unresolved-reference possibly-undefined reportPossiblyUnboundVariable
redundant-cast redundant-cast reportUnnecessaryCast
subclass-of-final-class misc reportGeneralTypeIssues
too-many-positional-arguments call-arg reportCallIssue
type-assertion-failure assert-type reportAssertTypeFailure
unbound-type-variable valid-type reportGeneralTypeIssues
undefined-reveal unimported-reveal
unknown-argument call-arg reportCallIssue
unresolved-attribute attr-defined
union-attr
reportAttributeAccessIssue
reportFunctionMemberAccess
reportOptionalMemberAccess
unresolved-import import-not-found reportMissingImports
unresolved-reference, Ruff F823 name-defined
used-before-def
reportUndefinedVariable
reportUnboundVariable
unsound-assignment (variables only)
unsound-return-statement no-any-return
unsound-yield
unsupported-operator operator reportOperatorIssue
reportOptionalOperand
unused-awaitable (native coroutines only) unused-coroutine
unused-awaitable
reportUnusedCoroutine
unused-ignore-comment unused-ignore reportUnnecessaryTypeIgnoreComment
unused-type-ignore-comment unused-ignore reportUnnecessaryTypeIgnoreComment
blanket-ignore-comment, Ruff PGH003 ignore-without-code reportIgnoreCommentWithoutRule (basedpyright only)
None yet for instantiating abstract classes abstract reportAbstractUsage
No direct equivalent planned for passing abstract classes where concrete classes are required type-abstract
None yet for calling abstract methods through super() safe-super reportAbstractUsage
Ruff F631 reportAssertAlwaysTrue
Ruff B006
Ruff B008 (partial coverage; immutable annotations and calls are excluded)
reportCallInDefaultInitializer
None yet (tracked in Ruff #10137) reportConstantRedefinition
Ruff F811
Ruff I001 (partial coverage; separate import blocks may be missed)
reportDuplicateImport
Ruff ISC001
Ruff ISC002
reportImplicitStringConcatenation
None yet (tracked in #3647) reportImportCycles
None yet for mutable attribute types (tracked in #2158) mutable-override reportIncompatibleVariableOverride
None yet reportIncompleteStub
None yet (tracked in #3651) reportInconsistentConstructor
Ruff W605 reportInvalidStringEscapeSequence
Ruff PYI010
Ruff PYI017
Ruff PYI048
Ruff PYI052
reportInvalidStubStatement
None yet (tracked in #1017, #3636, #3637) type-var reportInvalidTypeVarUse
None yet (tracked in #1060) exhaustive-match reportMatchNotExhaustive
None yet (tracked in #1577) reportMissingModuleSource
None yet (tracked in #3652) reportMissingSuperCall
None yet (tracked in #3638) import-untyped reportMissingTypeStubs
None yet (tracked in #103) overload-cannot-match
overload-overlap
reportOverlappingOverload
None yet (tracked in #200) attr-defined
(extended by --no-implicit-reexport)
reportPrivateImportUsage
reportPrivateLocalImportUsage (basedpyright only)
Ruff SLF001
Ruff PLC2701 (partial coverage; PLC2701 requires preview)
reportPrivateUsage
None yet (tracked in #3633) reportPropertyTypeMismatch
Ruff N804
Ruff N805
reportSelfClsParameterName
Ruff PYI033 (.py files require preview) reportTypeCommentUsage
None yet for accessing non-required keys (tracked in #2810) reportTypedDictNotRequiredAccess
None yet (tracked in #3781) reportUnhashable
None yet (tracked in #2954) reportUninitializedInstanceVariable
None yet reportUnknownArgumentType
reportUnknownLambdaType
reportUnknownMemberType
None yet var-annotated
None yet reportUnknownVariableType
None yet (tracked in #576) comparison-overlap reportUnnecessaryComparison
reportUnnecessaryContains
None yet reportUnnecessaryIsInstance
None yet (tracked in #1948) unreachable reportUnreachable
Ruff F822
Ruff PLE0604
Ruff PLE0605
Ruff PYI056
reportUnsupportedDunderAll
None yet reportUntypedBaseClass
reportUntypedClassDecorator
Ruff PYI024 reportUntypedNamedTuple
None yet reportUnusedClass
reportUnusedFunction
None yet reportUnusedCallResult
Ruff ARG rules reportUnusedParameter (basedpyright only)
Ruff B025 (duplicate exception handlers only; other cases tracked in #3701) reportUnusedExcept
Ruff B015
Ruff B018
reportUnusedExpression
Ruff F401 reportUnusedImport
Ruff F841 (function-local variables only) reportUnusedVariable
Ruff F403 reportWildcardImportFromLibrary
Ruff ANN401 (function annotations only) explicit-any reportExplicitAny (basedpyright only)
None yet func-returns-value
None yet no-any-unimported
None yet (tracked in #4381) no-untyped-call
None yet truthy-function reportUnnecessaryComparison
None yet truthy-iterable
Ruff ANN rules no-untyped-def reportMissingParameterType
reportUnknownParameterType

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.