今まで適当に mypy --strict
を使ってきたが,本当にstrictなのか気になったので,何か有効になっていないオプションで大事なものがないか調べることにしました.
以下は投稿日時現在で最新のバージョン 0.770 のものです
結論
--strict
で有効になっていない警告系のオプションは以下の6つ.
--disallow-any-unimported
--disallow-any-expr
--disallow-any-decorated
--disallow-any-explicit
--warn-unreachable
--warn-incomplete-stub
それぞれのオプションが有効かどうか
まず,mypy --help
で表示される警告系のオプションについて --strict
で有効になるかどうかを以下にまとめました.
ただし,以下のようにデフォルトでオンになっているオプションは含めていません( mypy --help
だとそれぞれを抑制するためのオプションが表示されます).
--strict-optional
--warn-no-return
--disallow-untyped-globals
--disallow-redefinition
--strict
で有効:✅ / 無効:❌
Config file
option | description | |
---|---|---|
✅ | --warn-unused-configs |
Warn about unused '[mypy-]' config sections |
Disallow dynamic typing
option | description | |
---|---|---|
❌ | --disallow-any-unimported |
Disallow Any types resulting from unfollowed imports |
❌ | --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 |
✅ | --disallow-subclassing-any |
Disallow subclassing values of type Any when defining classes |
Untyped definitions and calls
option | description | |
---|---|---|
✅ | --disallow-untyped-calls |
Disallow calling functions without type annotations from functions with type annotations |
✅ | --disallow-untyped-defs |
Disallow defining functions without type annotations or with incomplete type annotations |
✅ | --disallow-incomplete-defs |
Disallow defining functions with incomplete type annotations |
✅ | --check-untyped-defs |
Type check the interior of functions without type annotations |
✅ | --disallow-untyped-decorators |
Disallow decorating typed functions with untyped decorators |
None and Optional handling
option | description | |
---|---|---|
✅ | --no-implicit-optional |
Don't assume arguments with default values of None are Optional
|
Configuring warnings
option | description | |
---|---|---|
✅ | --warn-redundant-casts |
Warn about casting an expression to its inferred type |
✅ | --warn-unused-ignores |
Warn about unneeded # type: ignore comments |
✅ | --warn-return-any |
Warn about returning values of type Any from non-Any typed functions |
❌ | --warn-unreachable |
Warn about statements or expressions inferred to be unreachable or redundant |
Miscellaneous strictness flags
option | description | |
---|---|---|
✅ | --no-implicit-reexport |
Treat imports as private unless aliased |
✅ | --strict-equality |
Prohibit equality, identity, and container checks for non-overlapping types |
Advanced options
option | description | |
---|---|---|
❌ | --warn-incomplete-stub |
Warn if missing type annotation in typeshed, only relevant with --disallow-untyped-defs or --disallow-incomplete-defs enabled |
有効になっていないオプションについて
--disallow-any-unimported
スタブがないと,外部ライブラリの型は typing.Any
のエイリアスになりますが,それを使用していると警告.
import numpy as np # type: ignore
def func() -> np.ndarray:
return np.array(1)
$ mypy --strict --show-error-code --pretty sample.py
Success: no issues found in 1 source file
$ mypy --disallow-any-unimported --show-error-code --pretty sample.py
sample.py:3: error: Return type becomes "Any" due to an unfollowed import [no-any-unimported]
def func() -> np.ndarray:
^
Found 1 error in 1 file (checked 1 source file)
以下のように変更するとOK.
- def func() -> np.ndarray:
+ def func() -> t.Any:
Any
だらけになるからどうかとも思ったが, np.ndarray
も結局のところ錯覚でしかないので結構ありかもしれません.
コメントと割り切って, np.ndarray
とか書く場合もあると思うので,そこら辺は個人の判断だと思います.
--disallow-any-expr
typing.Any
を含む式に警告.
np.array(1) + np.array(2)
とかでアウト.スタブを作らないとほとんど何もできない.
--disallow-any-decorated
デコレータを通したあとの関数が引数or返り値に typing.Any
を持っていると警告.
from abc import ABC, abstractmethod
from functools import wraps
import typing as t
class A(ABC):
@abstractmethod
def func_a(a: t.Any) -> None:
pass
def deco(f: t.Callable[[int], int]) -> t.Callable[[int], t.Any]:
@wraps(f)
def wrapper(a: int) -> t.Any:
return t.cast(t.Any, f(a))
return wrapper
@deco
def func_b(a: int) -> int:
return 0
$ mypy --strict --show-error-code --pretty sample.py
Success: no issues found in 1 source file
$ mypy --disallow-any-decorated --show-error-code --pretty sample.py
sample.py:8: error: Type of decorated function contains type "Any" ("Callable[[Any], None]") [misc]
def func_a(a: t.Any) -> None:
^
sample.py:21: error: Type of decorated function contains type "Any" ("Callable[[int], Any]") [misc]
def func_b(a: int) -> int:
^
Found 2 errors in 1 file (checked 1 source file)
普通の関数が --disallow-any-explicit
付けない限り,typing.Any
を引数等に使ってもよいのに,デコレータだけ特別視する意味がよくわからない(そして, --disallow-any-explicit
はできる気がしない).
--disallow-any-explicit
明示的な typing.Any
に警告.厳しい.
--warn-unreachable
不達コードに対して警告.
def process(x: int) -> None:
if isinstance(x, int) or x > 7:
print(str(x) + "bad")
else:
print(str(x) + "bad")
(https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-warn-unreachable のコードを少し変更した.)
$ mypy --strict --show-error-code --pretty sample.py
Success: no issues found in 1 source file
$ mypy --warn-unreachable --show-error-code --pretty sample.py
sample.py:2: error: Right operand of 'or' is never evaluated [unreachable]
if isinstance(x, int) or x > 7:
^
sample.py:5: error: Statement is unreachable [unreachable]
print(str(x) + "bad")
^
Found 2 errors in 1 file (checked 1 source file)
あらゆる不達コードを検出できるわけではないが付けて悪いことはなさそう?
--warn-incomplete-stub
スタブに対する警告.そもそも stubgen
がうまくいかないのでよくわからない.
ドキュメントに
This flag is mainly intended to be used by people who want contribute to typeshed and would like a convenient way to find gaps and omissions.
って書いてあるから別にいいのかな?
感想
個人的には,--strict
に加えて,以下の2つは一考の余地があるかなと思いました.
--disallow-any-unimported
--warn-unreachable
そもそもmypyを使っているのは単なる惰性なので,Pyright, Pyre, pytype辺りで使いやすいのがあれば乗り換えたい.
雑比較
|ツール名|言語|GitHubリポジトリ|Star数 (2020/5/2 22:41現在)
|---|---|---|---|---
|mypy|Python|https://github.com/python/mypy|8379
|pytype|Python|https://github.com/google/pytype|2629
|Pyre|OCaml|https://github.com/facebook/pyre-check|3334
|Pyright|TypeScript|https://github.com/microsoft/pyright|5107