Skip to main content

Mypy Config to Pyrefly

This page separates what pyrefly init converts today from the settings that only have a manual or approximate Pyrefly equivalent.

warning

A conceptual equivalent is not necessarily implemented by the converter. Read the generated config before trusting a row.

Quick conversion

pyrefly init

A typical generated config starts like this:

# pyrefly.toml
preset = "legacy"
project-includes = ["src"]
project-excludes = ["**/generated/**"]
search-path = ["src"]
python-version = "3.13"

[errors]
missing-import = "error"

Mapping status

  • Automatic: pyrefly init reads the mypy option and writes one or more Pyrefly settings.
  • Automatic; review: converted by pyrefly init, but the semantics differ or the conversion is lossy so you should review.
  • Manual: a related Pyrefly setting exists, but it is not captured by pyrefly init so you should manually add it to your Pyrefly config.
  • Not mapped: no current automatic or direct equivalent.

Complete option matrix

Mypy optionClosest Pyrefly setting or workflowStatusMigration note
mypy_pathsearch-pathAutomaticBoth add import roots; verify ordering and config-relative paths.
filesproject-includesAutomaticEntries are converted to Pyrefly filesystem globs.
modulesproject-includesAutomatic; reviewMypy does not recurse through modules; a path-oriented Pyrefly include may cover more files.
packagesproject-includesAutomaticReview namespace-package layouts.
excludeproject-excludesAutomatic; approximateMypy regexes are converted to globs. Complex regex features cannot be preserved exactly.
exclude_gitignoreuse-ignore-filesManual; not exactPyrefly reads .gitignore, .ignore, and .git/info/exclude by default, which is not the same rule set.
namespace_packagesNo direct settingNot mappedValidate import resolution on namespace packages.
explicit_package_basessearch-path and project layoutManualRepresent package roots explicitly rather than translating the flag.
ignore_missing_importsignore-missing-importsAutomaticPer-module mypy overrides become module globs. Imports are replaced with Any only when they cannot be found.
follow_untyped_importsNo direct settingNot mappedPyrefly's source and stub discovery differ; test representative third-party imports.
follow_importsreplace-imports-with-any for skip; the converter emits ignore-missing-importsAutomatic but lossy for skipMypy skip discards an import even when it resolves. The converter groups it with ignore_missing_imports, which is narrower, so change the generated entry by hand when exact skip behavior matters. normal, silent, and error have no equivalent.
follow_imports_for_stubsNo direct settingNot mapped
python_executablepython-interpreter-pathAutomaticPrefer environment autoconfiguration where possible.
no_site_packagesskip-interpreter-query plus explicit site-package-pathManual; not exactSkipping the interpreter query also affects the inferred Python version and platform.
no_silence_site_packagesNo direct settingNot mappedPyrefly treats site packages as dependencies rather than project files.
python_versionpython-versionAutomatic
platformpython-platformManualThe settings are equivalent, but the mypy converter does not wire this one through. Set python-platform explicitly.
always_trueNo direct settingNot mapped
always_falseNo direct settingNot mapped
disallow_any_unimporteduntyped-import, missing-import, and the implicit-Any kindsManual; no exact 1:1
disallow_any_exprNo direct settingNot mappedPyrefly has targeted explicit and implicit Any diagnostics, not a general expression-level ban.
disallow_any_decoratedNo direct settingNot mapped
disallow_any_explicit[errors] explicit-any = "error"Automatic
disallow_any_generics[errors] implicit-any = "error"Automatic; broaderFor closer semantics, enable only implicit-any-type-argument.
disallow_subclassing_anyunsupported-dynamic-baseManual; not exact
disallow_untyped_callsNo direct settingNot mapped
untyped_calls_excludeNo direct settingNot mapped
disallow_untyped_defsimplicit-any-parameter + unannotated-returnAutomatic
disallow_incomplete_defsimplicit-any-parameter + unannotated-returnAutomatic; broaderThe Pyrefly pair does not distinguish partially annotated from fully unannotated definitions the way mypy does.
check_untyped_defscheck-unannotated-defs = true and infer-return-types = "never"Automatic; global onlyBoth the INI and [tool.mypy] paths read this field, falling back to strict. Per-module sections are ignored, so a config that only enables it per module needs a manual review.
disallow_untyped_decoratorsuntyped-function-decorator, untyped-class-decoratorManual
implicit_optionalNo direct settingNot mappedPyrefly follows modern explicit-Optional behavior.
strict_optionalNo direct settingNot mappedPyrefly has no equivalent of mypy's legacy non-strict Optional mode.
warn_redundant_casts[errors] redundant-cast = "warn"Automatic
warn_unused_ignoresunused-type-ignore and/or unused-ignoreManualChoose based on which ignore syntax you are enforcing.
warn_no_returnbad-return behaviorNo config translation neededPyrefly does not expose this as a standalone toggle.
warn_return_any[errors] no-any-return = "error"Automatic
warn_unreachable[errors] unreachable = "warn"Manual
deprecated_calls_excludeSub-config or source suppressionManual; no exact 1:1
ignore_errorsBaseline, pyrefly suppress, or sub-configsManual; no exact 1:1Prefer a baseline for incremental rollout rather than excluding code outright.
allow_untyped_globalsNo direct settingNot mapped
allow_redefinition[errors] redefinition = "ignore"ManualThe converter reads the key allow_redefinitions, not mypy's documented allow_redefinition, so do not assume this is preserved automatically.
allow_redefinition_new[errors] redefinition = "ignore"Manual; approximatePyrefly has no equivalent of mypy's old/new redefinition split.
allow_redefinition_old[errors] redefinition = "ignore"Manual; approximatePyrefly has no equivalent of mypy's old/new redefinition split.
local_partial_typesNo direct settingNot mapped
disable_error_code[errors] or [sub-config.errors]Automatic for mapped codesUnrecognized mypy codes are dropped by the converter; audit the generated config.
enable_error_code[errors] or [sub-config.errors]Automatic for mapped codesUnrecognized mypy codes are dropped by the converter; audit the generated config.
extra_checksSpecific error kinds, or preset = "strict"ManualThere is no matching bundle.
implicit_reexport[errors] implicit-reexport = ...Manual
strict_equalityincompatible-comparison, unnecessary-comparisonManual
strict_equality_for_noneNo separate settingNot mapped
strict_bytesNo direct settingNot mappedValidate bytes and bytearray behavior on representative code.
strictpreset = "legacy" plus selected error overridesAutomatic; incompleteThe two strict bundles differ and evolve independently. The converter maps the error policies listed in Mypy error codes, but does not fully expand mypy strict. In particular, verify check-unannotated-defs = true, because mypy strict includes check_untyped_defs.
show_error_contextoutput-format and CLI outputNo 1:1 mapping
show_column_numbersPyrefly output always includes locationsNo 1:1 mapping
show_error_code_linksNo direct settingNot mapped
hide_error_codesNo direct settingNot mapped
prettyoutput-format = "full-text"Manual; approximate
color_outputTerminal behaviorNo 1:1 mapping
error_summaryNo direct settingNot mapped
show_absolute_pathNo direct settingNot mapped
incrementalNo user-facing equivalentNot mappedPyrefly manages its own incremental analysis.
cache_dirNo user-facing equivalentNot mapped
sqlite_cacheNo user-facing equivalentNot mapped
cache_fine_grainedNo user-facing equivalentNot mapped
skip_version_checkNo user-facing equivalentNot mapped
skip_cache_mtime_checksNo user-facing equivalentNot mapped
num_workersNo direct settingNot mappedBenchmark Pyrefly's default execution on the target repository.
pluginsNo plugin-loader settingNot mappedPyrefly does not execute arbitrary mypy plugins, but built-in Pydantic v2+, Django, and attrs support replaces several common plugin use cases. Review custom plugins separately.
pdbNo direct settingNot mapped
show_tracebackNo direct settingNot mapped
raise_exceptionsNo direct settingNot mapped
custom_typing_moduleNo direct settingNot mapped
custom_typeshed_dirtypeshed-pathManual
warn_incomplete_stubNo direct settingNot mapped
native_parserNo direct settingNot mapped
any_exprs_reportpyrefly coverageManual; not equivalentCoverage reports measure annotation and type coverage, not mypy's Any-expression report.
cobertura_xml_reportExternal coverage toolingManual
html_report / xslt_html_reportExternal coverage toolingManual
linecount_reportpyrefly coverageManual
linecoverage_reportpyrefly coverageManual
lineprecision_reportpyrefly coverageManual
txt_report / xslt_txt_reportExternal coverage toolingManual
xml_reportExternal coverage toolingManual
junit_xmloutput-format = "junit-xml"Manual
junit_formatNo direct settingNot mapped
scripts_are_modulesNo direct settingNot mapped
warn_unused_configsNo direct settingNot mappedPyrefly rejects unknown options in its own config files.
verbosityCLI logging flagsNo 1:1 mapping

Plugin configuration

pyrefly init does not copy mypy's plugins option. That does not mean a plugin-backed project loses framework-aware checking:

Mypy integrationPyrefly equivalent
pydantic.mypyBuilt-in Pydantic v2+ support, enabled automatically
mypy_django_plugin.mainBuilt-in Django support with django-stubs installed
Mypy's built-in attrs handlingBuilt-in attrs support for attrs 23.2+
A custom plugin moduleNo equivalent; replace manually or keep mypy

Keep the mypy plugins entry while mypy still runs in parallel CI. Pyrefly simply does not consume it. See Mypy plugins for the migration checklist and the framework-specific caveats.

Per-module overrides

Mypy matches module names. Pyrefly sub-configs match file paths and support only:

  • errors;
  • replace-imports-with-any;
  • check-unannotated-defs;
  • infer-return-types;
  • ignore-errors-in-generated-code.

Example:

[[sub-config]]
matches = "src/legacy/**"
check-unannotated-defs = false
infer-return-types = "never"

[sub-config.errors]
implicit-any = "ignore"

Mypy per-module import suppression is migrated separately, into the ignore-missing-imports module-glob list rather than into a sub-config.

High-risk review items

  1. Custom plugins: Pyrefly does not execute arbitrary mypy plugin modules. Pydantic, Django, and attrs are native-support cases to validate, not wholesale gaps.
  2. Regex excludes: complex regexes cannot be preserved exactly as globs.
  3. modules: mypy and Pyrefly differ in recursion and project discovery.
  4. Strict mode: mypy strict is not Pyrefly strict.
  5. Platform: set python-platform explicitly and verify it.
  6. Per-module check_untyped_defs: review by hand; only the global setting is migrated.
  7. allow_redefinition: review by hand; the converter reads a different key spelling.
  8. Error codes: only recognized codes become Pyrefly error overrides.

Upstream references

Next steps

note

Last reviewed against upstream mypy documentation and Pyrefly's migration source on 2026-08-08.