どこにでもいるSEの備忘録

たぶん動くと思うからリリースしようぜ

ty (Red-Knot) を使ってみる

ついこの間ですが、AstralからType Checkerであるtyが公開されました。

github.com

Xで話題にしている方も結構多かったので興味が湧いたので、実際に使ってみたので今回はそのメモです。

Python Type Checker

今回の記事のテーマであるtyはPythonのType Checkerで、有名なものだとmypyが非常によく知られていると思います。 用途としてはエディタに組み込んで使ったり、CIなどでコードを自動チェックしたりするのに使われたり、さまざまなところで使われています。

mypyやty以外にもPython Type Checkerは存在しています。

個別の話は下記の記事などで色々まとめられていますので、よければ御覧ください。

tech.iimon.co.jp

ty

tyはAstralが作っているType Checkerです。

astral.sh

リポジトリはこちらです。

github.com

特徴

tyの特徴についてはAstralで実際に作っている方の紹介記事がありますので、詳しくはそちらを参照いただいたほうがいいと思います。

zenn.dev

また、英語がわかる方であればこちらの動画でも紹介されています。

youtu.be

上記ブログを見てtyの特徴を個人的にざっくりまとめると、

  • とにかく高速
  • シングルバイナリで提供されてる
    • 環境構築がCI上でのセットアップが簡単
  • salsaをベースにしており、冗長な計算を削減
  • その他、独自の機能も追加

その他、Geminiにまとめてもらった結果を貼っておきますので、もうちょっと細かくまとめが欲しいという方はご参照ください。

Geminiにまとめてもらった結果

  • パフォーマンスとスケーラビリティ:
    • 既存の型チェッカーと比較して、桁違いに高速であることを目指しています。
    • 特に、大規模なコードベース(数千万行以上)でのパフォーマンスとスケーラビリティに焦点を当てています。これにより、大規模プロジェクトでのローカルでの型チェックや、CIでの実行時間(数十秒〜数分)を大幅に短縮(10〜15秒、あるいはそれ以下)することを目指しています。
  • インクリメンタルな分析と選択的分析:
    • エディターの言語サーバー機能を強化するためにゼロから設計されており、高度なインクリメンタルな計算が可能です。これは、コード編集時のリアルタイムな応答性を高めるために、変更された部分とそれに影響を受ける最小限の部分のみを再分析することを意味します。
    • コードベース全体を一度に見るのではなく、実際にインポートまたは使用されている特定の要素(定数など)だけを選択的に分析します。これにより、特に大規模プロジェクトの初回チェック(コールドチェック)が高速化されます。
    • この機能は、RustのライブラリであるSalsaによって実現されています。
  • 開発者体験の向上:
    • 型チェックだけでなく、エディター内での言語サーバー体験(オートコンプリート、リアルタイム診断、定義へのジャンプなど)も重視しており、型情報がこれらの機能を向上させます。
    • 型をコードに追加することで、CIで型チェッカーを実行しない場合でも、エディターの機能が向上し生産性が上がると考えています。
    • 型は、AIによるコード生成や修正の効率化にも役立つ可能性があります。
    • 型付けされていない既存のコードベースに対して誤ったエラー(false positive)を少なくし、段階的な型付けの導入をスムーズにすることを目指しています。これは、MyPyやPyrightのように不要な仮定を立てず、明示的な型アノテーションに依存するという設計思想に基づいています。
  • 設計思想と互換性:
    • MyPyやPyrightのドロップインリプレイスメント(そのまま置き換えられるもの)ではありません。異なる設計思想(特にインクリメンタル性、スケーラビリティ、開発者体験)に基づいています。
    • Pythonの型付け仕様のコンフォーマンススイートにパスすることを目指しており、複数の型チェッカー間での互換性を確保することに重点を置いています。特に、ライブラリ作者が、MyPy、Pyright、tyなど異なる型チェッカーを使用するユーザー全員に対して機能する型を提供できるようにすることを目指しています。
  • 技術スタック:
    • Rustで開発されています。
    • Ruffと共通のインフラ(パーサー、ASTなど)を共有しています。
  • 名称:
    • 「ty」という名称は、短く入力しやすく、特徴的で、型チェック(type checking)と「Thank you」という言葉に曖昧に関連付けられています。開発中のコードネームは「Rednot」でした。
  • リリース計画:
    • 試用やフィードバック収集を目的とした早期実験的プレビュー/アルファ版が、PyCon USの時期(5月16日頃)までに公開される予定です。このバージョンには多くの機能が不足しており、バグが含まれる可能性があります。
    • より安定したベータ版や、製品として利用可能になる正式リリースは、今年後半(おそらく秋頃)を目標としています。
    • 初期のアルファ版では、コマンドラインでの型チェックとWebプレイグラウンドに重点が置かれ、言語サーバーサポートはまだ初期段階となります。
  • インストールと設定:
    • Ruffとは別のツールとしてリリースされる予定です。UVツールインストールやUVインストールを使ってインストールします。
    • 設定は、ty.tomlファイル(Webプレイグラウンドではty.json)で行うことが想定されています。
  • CI連携:
    • Ruffと同様に、pre-commitフックやGitHub Actionsなど、CI連携も提供される予定です。パフォーマンスの向上がCIでのフィードバック速度を劇的に改善します。
  • Webプレイグラウンド:
    • types.ruff.rsで公開されており、WebAssemblyとしてコンパイルされたtyがブラウザ上で実行されます。Piodideを使ったコード実行機能も含まれており、型チェック結果と実際のランタイムの動作を確認できます。
  • プラグイン/拡張機能:
    • 標準化という設計思想や、パフォーマンス上の理由から、現時点ではプラグインや拡張機能のサポートは可能性が低いとされています。これは、プラグインが特定のツールに依存することになり、型チェッカー間の互換性を損なう可能性があるためです。

一点注意としては、2025/05/10現在ではpre-releaseなので製品として使用する準備は整っていないとのことなんで、その点ご注意ください。

Warning

ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors. https://github.com/astral-sh/ty

使ってみる

さて、実際に使ってみたいと思います。 コマンド自体はこんな感じで使えるらしいです。

uv run ty check src

エラーが出るときはこんな感じで出てきます。

(省略)
error[conflicting-declarations]: Conflicting declared types for `view`: def view(**kwargs: Any) -> Unknown, def view(**kwargs: Any) -> Unknown
   --> src/flask/views.py:122:17
    |
120 |             view.__module__ = cls.__module__
121 |             for decorator in cls.decorators:
122 |                 view = decorator(view)
    |                 ^^^^
123 |
124 |         # We attach the view class to the view function for two reasons:
    |
info: `conflicting-declarations` is enabled by default

Found 27 diagnostics

速度測定

試しにflaskのリポジトリを利用して速度測定させていただこうと思います。

  • 実行環境: Apple M3 Pro, memory 36 GB
  • 条件
    • コマンド実行、ディレクトリを指定して配下にあるファイルを検査
    • キャッシュが効いている状況下での比較 (何度も実行してから測定したので)
hyperfine -i 'uv run pytype src' 'uv run pyright src' 'uv run mypy src' 'uv run ty check src' 'uv run pyre check'
Benchmark 1: uv run pytype src
  Time (mean ± σ):      3.449 s ±  0.029 s    [User: 2.906 s, System: 0.537 s]
  Range (min … max):    3.405 s …  3.511 s    10 runs
 
  Warning: Ignoring non-zero exit code.
 
Benchmark 2: uv run pyright src
 ⠴ Current estimate: 5.420 s      ████████████████████████████████████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ETA 00:00:27  ⠹ Current estimate: 5.420 s      ████████████████████████████████████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ETA 00:00:27   Time (mean ± σ):      5.468 s ±  0.209 s    [User: 7.586 s, System: 0.264 s]
  Range (min … max):    5.095 s …  5.723 s    10 runs
 
  Warning: Ignoring non-zero exit code.
 
Benchmark 3: uv run mypy src
  Time (mean ± σ):     590.5 ms ±  47.2 ms    [User: 529.1 ms, System: 47.9 ms]
  Range (min … max):   566.9 ms … 723.5 ms    10 runs
 
  Warning: Ignoring non-zero exit code.
  Warning: The first benchmarking run for this command was significantly slower than the rest (723.5 ms). This could be caused by (filesystem) caches that were not filled until after the first run. You should consider using the '--warmup' option to fill those caches before the actual benchmark. Alternatively, use the '--prepare' option to clear the caches before each timing run.
 
Benchmark 4: uv run ty check src
  Time (mean ± σ):      49.6 ms ±   3.6 ms    [User: 130.4 ms, System: 25.3 ms]
  Range (min … max):    46.8 ms …  69.7 ms    41 runs
 
  Warning: Ignoring non-zero exit code.
  Warning: The first benchmarking run for this command was significantly slower than the rest (69.7 ms). This could be caused by (filesystem) caches that were not filled until after the first run. You should consider using the '--warmup' option to fill those caches before the actual benchmark. Alternatively, use the '--prepare' option to clear the caches before each timing run.
 
Benchmark 5: uv run pyre check
  Time (mean ± σ):      1.973 s ±  0.088 s    [User: 9.535 s, System: 1.765 s]
  Range (min … max):    1.872 s …  2.180 s    10 runs
 
  Warning: Ignoring non-zero exit code.
 
Summary
  uv run ty check src ran
   11.89 ± 1.28 times faster than uv run mypy src
   39.75 ± 3.39 times faster than uv run pyre check
   69.47 ± 5.08 times faster than uv run pytype src
  110.14 ± 9.04 times faster than uv run pyright src

他のツールと比較して、11.89 ~ 110.14倍速いという結果になりました。毎回測定誤差が出るので〇〇倍はアテになりませんが…

それでもtyは爆速といって差し支えないでしょう。

参考文献

下記の文献を参考にさせていただきました。

また、tyについて他にも試されている方がいらっしゃいまして、参考にさせていただきました。

感想

以上、簡単ですがtyを試してみた次第です。

個人的にも「Python Type Checkerでmypyより高速なものが出てきたらいいな」と思っていたので、たいへん楽しみにしています。 簡単な速度検証した結果ではありますが、非常に高速なことがわかってよかったです。

ty自体はまだまだ開発途中ですが、安定版がリリースされるくらいのタイミングにはきっと乗り換えるんだろうな、思いました。