Skip to main content

Mypy Strict Mode in Pyrefly

Mypy's strict = true and Pyrefly's preset = "strict" are both strictness bundles, but they are not the same bundle, and each evolves on its own schedule. Decide which of the two goals below you have before you configure anything.

Goal 1: preserve the checks you have today

Let pyrefly init generate a mypy-oriented starting point, then review the composite behavior explicitly:

preset = "legacy"
check-unannotated-defs = true
infer-return-types = "never"

Mypy strict includes check_untyped_defs, so check-unannotated-defs = true is part of a faithful strict migration. The converter maps mypy's strictness flags onto Pyrefly error kinds, but it does not expand the strict bundle into behavior settings, and the legacy preset defaults check-unannotated-defs to false. Set it explicitly rather than inheriting the preset default.

Goal 2: adopt Pyrefly-native strictness

Once the migration is stable, this is a fresh policy decision rather than a translation:

preset = "strict"

The strict preset sets strict-callable-subtyping = true and enables implicit-any (which covers every implicit-Any sub-kind), missing-override-decorator, potential-bad-keyword-argument, unused-ignore, and direct-abstract-base-instantiation.

What the converter does with mypy strict

Mypy strict behaviorGenerated or closest Pyrefly policyReview
Returning Any from a typed functionno-any-return = "error"Close mapping; Pyrefly splits implicit and explicit return Any internally
Redundant castsredundant-cast = "warn"Generated at warning severity
Untyped or incompletely typed definitionsimplicit-any-parameter + unannotated-returnTwo Pyrefly policies stand in for several mypy flags
Missing generic argumentsimplicit-any = "error"Broader than implicit-any-type-argument alone
Checking unannotated function bodiesNot expanded by the converterSet check-unannotated-defs = true yourself
Explicit Anyexplicit-anyOnly when disallow_any_explicit is set; mypy strict alone does not enable it
Unused ignoresunused-type-ignore / unused-ignoreNot part of the mypy converter map; add by hand
Explicit override requirementmissing-override-decoratorManual, unless you adopt the Pyrefly strict preset

A hand-tuned compatibility config

Use specific kinds when the umbrella is broader than you want:

preset = "legacy"
check-unannotated-defs = true
infer-return-types = "never"

[errors]
implicit-any-parameter = "error"
implicit-any-type-argument = "error"
unannotated-return = "error"
no-any-return = "error"
redundant-cast = "warn"

Then consider adding the policies mypy strict does not cover:

[errors]
missing-override-decorator = "error"
unused-type-ignore = "error"