Pyrefly v1.0入門—Meta製の高速Python型チェッカーをmypyから移行

Pyrefly v1.0入門—Meta製の高速Python型チェッカーをmypyから移行 | mohablog
目次

Pyrefly v1.0が出てきた背景

Metaが2026年5月に Pyrefly v1.0 を出しました。Rust 実装の型チェッカーで、売りは毎秒185万行のチェック速度。同じ時期に Astral の ty もアルファ版で動いているため、Python の型チェッカーは事実上「mypy / Pyright / Pyrefly / ty」の4本柱になっています。

Meta 社内で PyTorch・JAX の検査に β 版を当てて運用していた経緯があり、stable は最初から大規模リポ前提のチューニング。「とりあえず動くお試し版」というよりは、PyTorch クラスの規模で回せる設計になっています。

4本柱の位置づけ

  • mypy: Python 本体に最も近いリファレンス実装。プラグインが豊富で、Django-stubs / Pydantic / SQLAlchemy などエコシステムが厚い
  • Pyright: Microsoft 製。typing spec 準拠 98%、IDE 連携が最も完成度高い
  • Pyrefly: Meta 製、Rust 実装。準拠 87.8%、CLI 検査が 10倍以上速い
  • ty: Astral(Ruff の会社) 製、Rust 実装。LSP の差分計算が圧倒的に速く、Pyrefly 比で約500倍

Pyrefly を入れる動機が出る場面

mypy で CI が遅い、もしくは Pyright を CI に通すと数十分かかる規模のプロジェクト。Pyrefly はキャッシュなしの一発検査が pandas 全体で 1.9 秒。「dev で繰り返し回す」用途ではなく、まずは CI 専用ツールとして差分が大きく出ます。

インストールと最初のチェック

uv 環境ならワンライナーで導入完了。

uv add --dev pyrefly
uv run pyrefly init
uv run pyrefly check

実行結果:

$ uv run pyrefly init
Initializing pyrefly in /Users/moha/work/sample
Wrote pyrefly.toml
$ uv run pyrefly check
INFO Checking 142 files...
ERROR src/services/user.py:42:13 Argument `None` is not assignable to parameter `email` of type `str` [bad-argument-type]
INFO 1 errors (in 0.31s)

pip 系なら pip install pyrefly、Poetry なら poetry add --group dev pyrefly、conda は conda install -c conda-forge pyrefly。CI 用のスタンドアロンバイナリも GitHub Releases にぶら下がっているため、Python 環境を作らず単体で動かすことも可能。

pyrefly init が何を作るか

pyrefly initpyrefly.toml を生成します。プロジェクトに mypy.inipyproject.toml [tool.mypy] がある場合は、その内容を解釈して引き継ぐ仕組み。引き継げない設定は無視せず、コメント付きで pyrefly.toml に「未対応」と書き残します。

VS Code 拡張の併用

VS Code Marketplace に公式拡張あり。settings.json で Pylance や Mypy 拡張を止めておかないと、同じファイルにエラーが二重に出ます。Pylance 側を python.analysis.typeCheckingMode: "off" にしておけば、Pyrefly の診断だけが残ります。

mypy からの移行—設定の自動変換

mypy で運用中のプロジェクトに Pyrefly を後乗せする場合、mypy.ini を手で書き直すのは面倒。Pyrefly はこの変換ロジックを pyrefly init に内蔵しています。

自動変換の中身

公式ドキュメントの “Mypy Config Migration” セクションによれば、pyrefly init path/to/project は次の手順で動作します。

  • mypy.ini または pyproject.toml [tool.mypy] を探索
  • 共通オプションを pyrefly.toml にマップ
  • mypy のモジュール単位設定は、ファイルパスグロブの sub-config に変換

挙動を mypy 寄せにするための設定

そのままだと Pyrefly はデフォルトで mypy より厳しい検査を行います。mypy の検査結果と差分を小さくしたいなら、pyrefly.toml に次の2行を入れておくのが定番。

[tool.pyrefly]
check-unannotated-defs = false
infer-return-types = "never"

実行結果:

$ pyrefly check --summarize-errors
INFO Checking 412 files...
INFO 38 errors total (was 217 with default settings)

check-unannotated-defs = false は「型注釈がない関数本体は検査しない」設定。mypy のデフォルトに揃えるためのスイッチです。infer-return-types = "never" は戻り値型を推論せず、書かれた注釈だけを信用するモード。Pyrefly のデフォルト "checked" は戻り値を推論して使う方針なので、mypy と差分が出やすい点。

エラーコードの対応表

mypy の arg-type は Pyrefly では bad-argument-type に名前が変わる、といった違いがあります。約50個のエラーコードの対応が “Error Kind Mapping” セクションに表でまとまっています。type: ignore[arg-type] がそのまま動くわけではないため、検査を回す前にコメントの書き換えが必要。具体的には type: ignore[bad-argument-type] に置換するか、後述の enabled-ignores で両方を許可しておきます。

pyrefly.toml の主要オプション

設定ファイルでよく触る項目を表にまとめます。完全版は公式 “Configuration” にあるとおり。

項目デフォルト用途
project-includes["**/*.py*"]検査対象のグロブ
project-excludesnode_modules / __pycache__ ほか除外グロブ
python-version環境から検出検査時に想定する Python 版
check-unannotated-defstrue注釈なし関数本体の検査
infer-return-types"checked"戻り値の推論方針
preset(未指定)off / basic / legacy / default / strict
errors{}エラー種別ごとの有効/無効
baselineなし既存エラーを抑止する基準ファイル

preset = "strict" を入れると mypy の --strict 相当の厳しさに。baseline は既存エラーを「既知のもの」として記録するスナップショットで、CI でこのファイルに載っていないエラーだけを失格扱いにできます。最初は legacydefault で入れて、ベースラインを撮ってから徐々に上げていくのが現実解。

mypy・Pyright・ty との性能比較

公式の Speed and Memory Comparison (MacBook M4 / 64GB / キャッシュなし / 5回測定の平均、デフォルト設定) から数字を引きます。pandas プロジェクトを丸ごと検査した結果がこちら。

チェッカーpandas検査時間準拠率(typing spec)実装言語
Pyright144.4秒98%Node.js
mypy13.9秒58%Python
Pyrefly1.9秒87.8%Rust
ty1.5秒53.2%Rust

速度の読み方

Pyright の 144 秒に対して Pyrefly は 約76倍速い。mypy 比でも 7.3 倍。ty はさらに高速で、Salsa による増分計算でファイル編集後の差分検査は 4.7ms(Pyright 386ms 比で約80倍速い)。CLI 一発検査では Pyrefly、IDE のリアルタイム再計算では ty が有利、という棲み分け。

typing spec 準拠率の読み方

準拠率は Python typing conformance test suite (139 test cases) の通過数。速さと準拠率はトレードオフで、Pyrefly は Pyright の 98% から約10ポイント差まで詰めています。ty の 53.2% は mypy(58%) と同程度で、現状はマイナーケースの誤検出が多い段階。新しい仕様(TypeVarTupleParamSpec など)になると差が出やすいため、利用前に手元のリポで --summarize-errors を取って Pyright との差分を見ておくのが安全。

CI 統合と pre-commit

GitHub Actions には公式 composite action あり。uses: facebook/pyrefly@v1 を1行追加すれば検査が走ります。

- uses: facebook/pyrefly@v1
  with:
    args: check --summarize-errors

実行結果:

Run facebook/pyrefly@v1
Installing pyrefly 1.0.3
INFO Checking 412 files...
INFO 0 errors

pre-commit hook

pre-commit リポジトリも公式提供。.pre-commit-config.yaml に追記すれば動作。

- repo: https://github.com/facebook/pyrefly
  rev: 1.0.3
  hooks:
    - id: pyrefly

実行結果:

$ pre-commit run pyrefly --all-files
pyrefly..................................................................Passed

移行で踏みやすい落とし穴と導入後の実感

mypy から Pyrefly に乗り換えるときに気をつける場所と、業務リポへ通したときの所感をまとめます。

mypy プラグインが効かない

NG: mypy 用の django-stubssqlalchemy.ext.mypy プラグインに依存していると、Pyrefly では型情報が剥がれて誤検出が出ます。

# mypy + django-stubs では User.objects.filter() の戻り値型が
# QuerySet[User] に推論されるが、Pyrefly はそこまで賢くない
qs = User.objects.filter(is_active=True)
qs.order_by("created_at")  # Pyrefly: Method `order_by` not found on `Any`

OK: そのモジュールだけ Pyrefly の検査対象から外すか、replace-imports-with-any に該当パッケージを並べて Any にフォールバックさせます。

[tool.pyrefly]
replace-imports-with-any = ["django.db.models.*"]

type: ignore コメントが効かない

mypy の type: ignore[arg-type] はそのままでは Pyrefly に効きません。Pyrefly は自前の pyrefly: ignore[bad-argument-type] 構文を持ちます。両方を共存させるには enabled-ignores を明示。

[tool.pyrefly]
enabled-ignores = ["type", "pyrefly"]
permissive-ignores = true

これで mypy 用の既存 type: ignore コメントも尊重されます。permissive-ignores = true は他ツールの ignore 指令を緩く解釈するスイッチ。

大規模リポへ通したときの実感

手元の業務リポ(Python 約400ファイル、mypy が CI で毎回 1分40秒)に pyrefly check を流したら 4秒で終わりました。エラー件数は mypy 比で約3倍に増えましたが、その多くは戻り値推論の差分。infer-return-types = "never" を立てた時点で半数近くが消え、残りは本当に注釈不足の関数。mypy を完全に消せるかは Django プラグインを諦められるかで決まります。プラグイン依存が薄いプロジェクトなら、Pyrefly に寄せて CI 時間を約10分の1まで縮められる計算になります。

まとめ

  • Pyrefly v1.0 は 2026年5月リリース、Meta 製。Rust 実装で pandas 検査 1.9秒
  • mypy.ini から pyrefly init で自動変換できる。エラーコード名は別物なので置換が要る
  • 挙動を mypy 寄せにするなら check-unannotated-defs = falseinfer-return-types = "never"
  • CLI 一発検査は Pyrefly、IDE 差分計算は ty が強い。Pyright は IDE 体験で依然有力
  • Django・SQLAlchemy の mypy プラグインに依存しているプロジェクトは要注意

型ヒントの基礎を mypy で押さえたい場合は Pythonの型ヒントを使いこなす!mypyでコード品質を大幅向上させる方法 を先に読むと、Pyrefly との差分が理解しやすくなります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次