これは、なにをしたくて書いたもの?
Pythonでソースコードを書く時にはできる限り型をつけていこうかなと思っているのですが、mypyについてはとりあえず
--disallow-untyped-defsをつけて型指定がない場合にエラーにしているくらいだったので、もう少しちゃんと設定というかどういうチェックを
するべきか見ておこうかなと思いまして。
mypyの設定
説明としてはこちらです。
The mypy configuration file - mypy 1.14.0 documentation
mypyの設定は以下から読み込まれます。
- ./mypy.ini
- ./.mypy.ini
- ./pyproject.toml
- ./setup.cfg
- $XDG_CONFIG_HOME/mypy/config
- ~/.config/mypy/config
- ~/.mypy.ini
あとはコマンドライン引数ですね。
The mypy command line - mypy 1.14.0 documentation
環境
今回の環境はこちら。
$ python3 --version Python 3.12.3 $ pip3 --version pip 24.0 from /usr/lib/python3/dist-packages/pip (python 3.12)
mypyの設定を見る
ひとまずmypyをインストールします。
$ pip3 install mypy $ mypy --version mypy 1.14.0 (compiled: yes)
ヘルプを見てみます。
$ mypy --help
今回は型チェックに関する内容が見たいので、見るべきはこのあたりですね。
Disallow dynamic typing:
Disallow the use of the dynamic 'Any' type under certain conditions.
--disallow-any-expr Disallow all expressions that have type Any
--disallow-any-decorated Disallow functions that have Any in their signature after decorator transformation
--disallow-any-explicit Disallow explicit Any in type positions
--disallow-any-generics Disallow usage of generic types that do not specify explicit type parameters (inverse: --allow-any-generics)
--disallow-any-unimported
Disallow Any types resulting from unfollowed imports (inverse: --allow-any-unimported)
--disallow-subclassing-any
Disallow subclassing values of type 'Any' when defining classes (inverse: --allow-subclassing-any)
Untyped definitions and calls:
Configure how untyped definitions and calls are handled. Note: by default, mypy ignores any untyped function definitions and assumes any calls to such functions
have a return type of 'Any'.
--disallow-untyped-calls Disallow calling functions without type annotations from functions with type annotations (inverse: --allow-untyped-calls)
--untyped-calls-exclude MODULE
Disable --disallow-untyped-calls for functions/methods coming from specific package, module, or class
--disallow-untyped-defs Disallow defining functions without type annotations or with incomplete type annotations (inverse: --allow-untyped-defs)
--disallow-incomplete-defs
Disallow defining functions with incomplete type annotations (while still allowing entirely unannotated definitions) (inverse: --allow-
incomplete-defs)
--check-untyped-defs Type check the interior of functions without type annotations (inverse: --no-check-untyped-defs)
--disallow-untyped-decorators
Disallow decorating typed functions with untyped decorators (inverse: --allow-untyped-decorators)
None and Optional handling:
Adjust how values of type 'None' are handled. For more context on how mypy handles values of type 'None', see:
https://mypy.readthedocs.io/en/stable/kinds_of_types.html#no-strict-optional
--implicit-optional Assume arguments with default values of None are Optional (inverse: --no-implicit-optional)
--no-strict-optional Disable strict Optional checks (inverse: --strict-optional)
Configuring warnings:
Detect code that is sound but redundant or problematic.
--warn-redundant-casts Warn about casting an expression to its inferred type (inverse: --no-warn-redundant-casts)
--warn-unused-ignores Warn about unneeded '# type: ignore' comments (inverse: --no-warn-unused-ignores)
--no-warn-no-return Do not warn about functions that end without returning (inverse: --warn-no-return)
--warn-return-any Warn about returning values of type Any from non-Any typed functions (inverse: --no-warn-return-any)
--warn-unreachable Warn about statements or expressions inferred to be unreachable (inverse: --no-warn-unreachable)
--report-deprecated-as-note
Report importing or using deprecated features as notes instead of errors (inverse: --no-report-deprecated-as-note)
Miscellaneous strictness flags:
--allow-untyped-globals Suppress toplevel errors caused by missing annotations (inverse: --disallow-untyped-globals)
--allow-redefinition Allow unconditional variable redefinition with a new type (inverse: --disallow-redefinition)
--no-implicit-reexport Treat imports as private unless aliased (inverse: --implicit-reexport)
--strict-equality Prohibit equality, identity, and container checks for non-overlapping types (inverse: --no-strict-equality)
--extra-checks Enable additional checks that are technically correct but may be impractical in real code. For example, this prohibits partial overlap in
TypedDict updates, and makes arguments prepended via Concatenate positional-only (inverse: --no-extra-checks)
--strict Strict mode; enables the following flags: --warn-unused-configs, --disallow-any-generics, --disallow-subclassing-any, --disallow-untyped-
calls, --disallow-untyped-defs, --disallow-incomplete-defs, --check-untyped-defs, --disallow-untyped-decorators, --warn-redundant-casts,
--warn-unused-ignores, --warn-return-any, --no-implicit-reexport, --strict-equality, --extra-checks
--disable-error-code NAME
Disable a specific error code
--enable-error-code NAME Enable a specific error code
Configuring error messages:
Adjust the amount of detail shown in error messages.
--show-error-context Precede errors with "note:" messages explaining context (inverse: --hide-error-context)
--show-column-numbers Show column numbers in error messages (inverse: --hide-column-numbers)
--show-error-end Show end line/end column numbers in error messages. This implies --show-column-numbers (inverse: --hide-error-end)
--hide-error-codes Hide error codes in error messages (inverse: --show-error-codes)
--show-error-code-links Show links to error code documentation (inverse: --hide-error-code-links)
--pretty Use visually nicer output in error messages: Use soft word wrap, show source code snippets, and show error location markers (inverse:
--no-pretty)
--no-color-output Do not colorize error messages (inverse: --color-output)
--no-error-summary Do not show error stats summary (inverse: --error-summary)
--show-absolute-path Show absolute paths to files (inverse: --hide-absolute-path)
ちなみに、設定ファイルに書く時には_区切りになるようです。
デフォルト値はドキュメントを見ないとわからないようですね。
The mypy configuration file - mypy 1.14.0 documentation
ただ、説明自体はコマンドライン引数の方が読んだ方がよいみたいです。
The mypy command line - mypy 1.14.0 documentation
--strictはドキュメントを見ても「ヘルプを見ること」としか書かれていないので、実際に見てみるとこんな感じでした。
--strict Strict mode; enables the following flags: --warn-unused-configs, --disallow-any-generics, --disallow-subclassing-any, --disallow-untyped-
calls, --disallow-untyped-defs, --disallow-incomplete-defs, --check-untyped-defs, --disallow-untyped-decorators, --warn-redundant-casts,
--warn-unused-ignores, --warn-return-any, --no-implicit-reexport, --strict-equality, --extra-checks
Enable all optional error checking flags. You can see the list of flags enabled by strict mode in the full mypy --help output.
mypy 1.14.0では以下のフラグが有効になるようです。
- --warn-unused-configs
- --disallow-any-generics
- --disallow-subclassing-any
- --disallow-untyped-calls
- --disallow-untyped-defs
- --disallow-incomplete-defs
- --check-untyped-defs
- --disallow-untyped-decorators
- --warn-redundant-casts
- --warn-unused-ignores
- --warn-return-any
- --no-implicit-reexport
- --strict-equality
- --extra-checks
OSSプロジェクトではどういう設定をしているんでしょう?とFastAPIを見たところ、全体としてはstrictのみtrueにしてあり、
ディレクトリによってはオーバーライドしているものもある、という感じでした。
https://github.com/fastapi/fastapi/blob/0.115.6/pyproject.toml#L123-L140
| カテゴリー | 項目 | 説明 | デフォルト値 | strictに含まれているか? |
|---|---|---|---|---|
| 動的型付けを許可しない | disallow_any_unimported | フォローされていないインポートから取得する型(Any)の使用を禁止する |
False | |
| disallow_any_expr | Anyを使う式を許可しない |
False | ||
| disallow_any_decorated | デコーレーターによる変換後の関数シグネチャにAnyが含まれることを禁止する |
False | ||
| disallow_any_explicit | Anyの明示的な使用を禁止する |
False | ||
| disallow_any_generics | 明示的な型パラメーターを指定しないジェネリック型の使用を禁止する | False | ○ | |
| disallow_subclassing_any | Anyのサブクラス化を禁止する |
False | ○ | |
| 型のない定義と呼び出し | disallow_untyped_calls | 型アノテーションを持つ関数を型アノテーションなしでの呼び出しを禁止する | False | ○ |
| untyped_calls_exclude | 特定のパッケージ、モジュール、またはクラスで定義された関数を disallow_untyped_calls アクションから選択して除外する | |||
| disallow_untyped_defs | 型アノテーションのない関数定義または不完全な型アノテーションのある関数定義を禁止する | False | ○ | |
| disallow_incomplete_defs | 部分的に型アノテーションが付与された関数定義を禁止する。完全に型アノテーションがない場合は許容する | False | ○ | |
| check_untyped_defs | False | ○ | ||
| disallow_untyped_decorators | 型アノテーションつきの関数を型アノテーションなしのデコレーターで装飾することを禁止する | False | ○ | |
NoneとOptionalの扱い |
implicit_optional | デフォルト値を持つパラメーターを暗黙的に T | None として扱う | False | |
| strict_optional | Optionalの型とNone値のチェックを無効にする。つまり、Noneはすべての型と互換性があるものとして扱う |
True | ||
| 警告の設定 | warn_redundant_casts | 冗長なキャストを使用すると警告する | False | ○ |
| warn_unused_ignores | 不要な# type: ignoreコメントがあると警告する |
False | ○ | |
| warn_no_return | 関数からreturn文が欠落している場合に警告する。例外は関数の戻り値の肩がNoneまたはAny、関数本体が空で抽象メソッドとしてマークされているか、プロトコルクラス内またはスタブファイル内にある、例外をスローするなどのreturnに制御が移らない場合 |
True | ||
| warn_return_any | Any以外の型を戻り値として定義している関数からAnyを返そうとすると警告する |
False | ○ | |
| warn_unreachable | 到達不能または冗長であるコードを検出すると警告する | False | ||
| エラーの抑制 | ignore_errors | 致命的なエラー以外を無視する | False | |
| その他の厳密性フラグ | allow_untyped_globals | 型指定のないグローバル変数を許容する | False | |
| allow_redefinition | 変数を別の型で再定義することを許容する | False | ||
| local_partial_types | ローカル変数に対する部分型(Noneを部分型として扱うこと)を禁止する |
False(mypy daemonでは暗黙的にTrueになる) | ||
| disable_error_code | 指定したエラーコードを無効にする。複数指定する場合はカンマで区切る | |||
| enable_error_code | 指定したエラーコードを有効にする。複数指定する場合はカンマで区切る | |||
| extra_checks | 技術的には正しいが実用的なコードでない可能性があるものに対して、追加のチェックを行う | False | ○ | |
| implicit_reexport | モジュールにインポートしたものを、暗黙的にエクスポートする | True | ※ no_implicit_reexportが有効になる |
|
| strict_concatenate | ?(extra_checksのこと?) | False | ||
| strict_equality | 互換性のない型の間での等価チェック、一意性チェック、コンテナチェックを禁止する | False | ○ | |
| strict | 特定のチェックが有効になる(この表の右端を参照) | False | ||
| エラーメッセージの設定 | show_error_context | 各エラーの先頭に関連するコンテキストを付与する | False | |
| show_column_numbers | エラーメッセージに列番号を表示する | False | ||
| show_error_code_links | 対応するエラーコードへのドキュメントのリンクを表示する | False | ||
| hide_error_codes | エラーメッセージからエラーコードを非表示にする | False | ||
| pretty | エラーメッセージを見やすくする | False | ||
| color_output | エラーメッセージを色付きで表示する | True | ||
| error_summary | エラーメッセージの後に短いサマリーを表示する | True | ||
| show_absolute_path | ファイルの絶対パスを表示する | False | ||
| force_uppercase_builtins | Python 3.9以降であってもエラーメッセージの表示では大文字を強制する | False | ||
| force_union_syntax | Python 3.10以降であってもエラーメッセージ内の共用型には | の代わりにUnion[]やOptional[]を使用する |
False | ||
| その他 | warn_unused_configs | mypyの呼び出し時に処理されるファイルと一致しない、設定ファイル内のモジュールごとのセクションに対して警告する | False | ○ |
その他は型チェックには関係しなさそうでしたが、strictで有効になるwarn_unused_configsのみ載せました。
こう見ていると、最低限strictを有効にすればよいのでは?という気もしますね。
mypy.iniを設定してみる
というわけで、ここまでの内容を元にmypyの設定ファイルであるmypy.iniを作成してみます。
まずはこんな感じにしてみようかなと思います。今回はデフォルト値のままでいいものについては省略しました。
mypy.ini
[mypy] strict = True disallow_any_unimported = True disallow_any_expr = True disallow_any_explicit = True warn_unreachable = True pretty = True
uvでpyproject.tomlに書く場合はこうでしょうか。
[tool.mypy] strict = true disallow_any_unimported = true disallow_any_expr = true disallow_any_explicit = true warn_unreachable = true pretty = true
使っていて微妙に思ったら、適宜見直していこうと思います。
ところで、設定する項目名を間違えると警告してくれるのがいいですね。
こんな感じで。
mypy.ini: [mypy]: Unrecognized option: hoge = True
おわりに
mypyの設定について調べてみました。
せっかくなのでざっくりまとめつつという感じで進めてみましたが、だいたい雰囲気はわかった感じです。
ちゃんと使っていこうと思います。