[PYTHON] [mypy] Summary of options not enabled by `--strict`

I've used mypy --strict properly so far, but I was wondering if it was really strict, so I decided to check if there were any important options that were not enabled.

** The following is the latest version 0.770 as of the posting date **

Conclusion

The following 6 warning options are not enabled by --strict.

Whether each option is valid

First, the warning options displayed by mypy --help are summarized below as to whether they are enabled by --strict.

However, it does not include the options that are turned on by default as shown below (mypy --help will display the options to suppress each).

Enabled with --strict: ✅ / Disabled: ❌

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

For options that are not enabled

--disallow-any-unimported

Without the stub, the type of the external library would be an alias for typing.Any, but warn you that you are using it.

sample.py


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)

You can change it as follows.

- def func() -> np.ndarray:
+ def func() -> t.Any:

I was wondering if it would be full of ʻAny, but it may be quite possible because np.ndarrayis also just an illusion after all. I think that there are times when I writenp.ndarray` as a comment, so I think that it is an individual decision.

--disallow-any-expr

Warning for expressions containing typing.Any. Out with np.array (1) + np.array (2). You can do almost nothing without creating a stub.

--disallow-any-decorated

Warning that the function after passing through the decorator has typing.Any in the argument or return value.

sample.py


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)

Unless an ordinary function adds --disallow-any-explicit, you can use typing.Any as an argument, but I don't understand the meaning of specializing only the decorator (and --disallow-". I don't feel like I can do any-explicit).

--disallow-any-explicit

Warn explicit typing.Any. Strict.

--warn-unreachable

Warning for non-delivery code.

sample.py


def process(x: int) -> None:
    if isinstance(x, int) or x > 7:
        print(str(x) + "bad")
    else:
        print(str(x) + "bad")

(The code of https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-warn-unreachable was changed a little.)

$ 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)

Not all non-delivery codes can be detected, but isn't it bad?

--warn-incomplete-stub

Warning for stubs. I'm not sure because stubgen doesn't work in the first place. In the documentation

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.

Is it okay because it says?

Impressions

Personally, in addition to --strict, I thought that the following two could be considered.

In the first place, mypy is used only by inertia, so if there is something easy to use around Pyright, Pyre, pytype, I would like to switch.

Miscellaneous comparison

Tool name language GitHub repository Star number(2020/5/2 22:41 Currently)
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

reference

--Official document

Recommended Posts

[mypy] Summary of options not enabled by `--strict`
Summary of basic implementation by PyTorch
Summary of restrictions by file system
Summary of library hosting pages by language
Summary of SQLAlchemy connection method by DB
Summary of gcc options (updated from time to time)
Super (concise) summary of image classification by ArcFace
Summary of Python articles by pharmaceutical company researcher Yukiya
Separation summary of development environment by chroot of various Linux