暗无天日

=============>DarkSun的个人博客

使用mypy对python程序进行静态检查

自从python3.6开始,允许为参数和返回类型添加 type hint,这使得对python程序进行静态检查成为可能。

mypy就是这么一个python type checker.

安装mypy

我们可以使用 pip 来安装mypy。

[lujun9972@T520 work]$ pip install mypy
Collecting mypy
  Downloading mypy-0.570-py3-none-any.whl (1.2MB)
    100% |████████████████████████████████| 1.2MB 70kB/s 
Collecting typed-ast<1.2.0,>=1.1.0 (from mypy)
  Downloading typed_ast-1.1.0-cp36-cp36m-manylinux1_x86_64.whl (724kB)
    100% |████████████████████████████████| 727kB 68kB/s 
Installing collected packages: typed-ast, mypy
Successfully installed mypy-0.570 typed-ast-1.1.0

使用mypy进行静态检查

假设有这么一个 test.py 的文件:

class Student():
    def __init__(self,id,name,age,major):
        self.id = id
        self.name = name
        self.age = age
        self.major = major


def display(persons):
    for person in persons:
        print(f'{person.id} {person.name}')

dark = Student('1', 'Dark', '19', 'computer')
sun = Student('2', 'Sun', 21, 'account')
lujun= Student(3, 'lujun', 'MBA', 25)

display(dark)
display([sun, dark, 'lujun'])

这段代码并没有添加 type hint,但是从代码中可以很容易看出是有许多错误的。

我们用 mypy 来检查一下看能不能查出什么:

[lujun9972@T520 work]$ mypy /tmp/test.py 
[lujun9972@T520 work]$ 

你会发现 mypy 什么错误都没有提示。

现在我们来为程序加上type hint

from typing import List
class Student():
    def __init__(self, id:int, name:str, age:int, major:str)->None:
        self.id = id
        self.name = name
        self.age = age
        self.major = major


def display(persons:List[Student])->None:
    for person in persons:
        print(f'{person.id} {person.name}')

dark = Student('1', 'Dark', '19', 'computer')
sun = Student('2', 'Sun', 21, 'account')
lujun= Student(3, 'lujun', 'MBA', 25)

display(dark)
display([sun, dark, 'lujun'])

再次用 mypy 来检查一下

[lujun9972@T520 work]$ mypy /tmp/test_with_type_hint.py 
/tmp/test_with_type_hint.py:14: error: Argument 1 to "Student" has incompatible type "str"; expected "int"
/tmp/test_with_type_hint.py:14: error: Argument 3 to "Student" has incompatible type "str"; expected "int"
/tmp/test_with_type_hint.py:15: error: Argument 1 to "Student" has incompatible type "str"; expected "int"
/tmp/test_with_type_hint.py:16: error: Argument 3 to "Student" has incompatible type "str"; expected "int"
/tmp/test_with_type_hint.py:16: error: Argument 4 to "Student" has incompatible type "int"; expected "str"
/tmp/test_with_type_hint.py:18: error: Argument 1 to "display" has incompatible type "Student"; expected "List[Student]"
/tmp/test_with_type_hint.py:19: error: List item 2 has incompatible type "str"; expected "Student"

可以发现,找出了一堆问题。

帮助信息

mypy还带有一堆的参数来定义检查的方法,运行 mypy -h 就会列出帮助信息了:

[lujun9972@T520 work]$ mypy --help
usage: mypy [-h] [-v] [-V] [--python-version x.y] [--platform PLATFORM] [-2]
            [--ignore-missing-imports]
            [--follow-imports {normal,silent,skip,error}]
            [--disallow-any-unimported] [--disallow-any-expr]
            [--disallow-any-decorated] [--disallow-any-explicit]
            [--disallow-any-generics] [--disallow-untyped-calls]
            [--disallow-untyped-defs] [--disallow-incomplete-defs]
            [--check-untyped-defs] [--disallow-subclassing-any]
            [--warn-incomplete-stub] [--disallow-untyped-decorators]
            [--warn-redundant-casts] [--no-warn-no-return] [--warn-return-any]
            [--warn-unused-ignores] [--warn-unused-configs]
            [--show-error-context] [--no-implicit-optional] [-i]
            [--quick-and-dirty] [--cache-dir DIR] [--cache-fine-grained]
            [--skip-version-check] [--strict-optional]
            [--strict-optional-whitelist [GLOB [GLOB ...]]]
            [--junit-xml JUNIT_XML] [--pdb] [--show-traceback] [--stats]
            [--inferstats] [--custom-typing MODULE]
            [--custom-typeshed-dir DIR] [--scripts-are-modules]
            [--config-file CONFIG_FILE] [--show-column-numbers]
            [--find-occurrences CLASS.MEMBER] [--strict]
            [--shadow-file SOURCE_FILE SHADOW_FILE] [--any-exprs-report DIR]
            [--cobertura-xml-report DIR] [--html-report DIR]
            [--linecount-report DIR] [--linecoverage-report DIR]
            [--memory-xml-report DIR] [--txt-report DIR] [--xml-report DIR]
            [--xslt-html-report DIR] [--xslt-txt-report DIR] [-m MODULE]
            [-c PROGRAM_TEXT] [-p PACKAGE]
            [files [files ...]]

optional arguments:
  -h, --help                show this help message and exit
  -v, --verbose             more verbose messages
  -V, --version             show program's version number and exit
  --python-version x.y      use Python x.y
  --platform PLATFORM       typecheck special-cased code for the given OS
                            platform (defaults to sys.platform).
  -2, --py2                 use Python 2 mode
  --ignore-missing-imports  silently ignore imports of missing modules
  --follow-imports {normal,silent,skip,error}
                            how to treat imports (default normal)
  --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-untyped-calls  disallow calling functions without type
                            annotations from functions with type annotations
                            (inverse: --allow-untyped-calls)
  --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 (inverse: --allow-incomplete-defs)
  --check-untyped-defs      type check the interior of functions without type
                            annotations (inverse: --no-check-untyped-defs)
  --disallow-subclassing-any
                            disallow subclassing values of type 'Any' when
                            defining classes (inverse: --allow-subclassing-
                            any)
  --warn-incomplete-stub    warn if missing type annotation in typeshed, only
                            relevant with --check-untyped-defs enabled
                            (inverse: --no-warn-incomplete-stub)
  --disallow-untyped-decorators
                            disallow decorating typed functions with untyped
                            decorators (inverse: --allow-untyped-decorators)
  --warn-redundant-casts    warn about casting an expression to its inferred
                            type (inverse: --no-warn-redundant-casts)
  --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-unused-ignores     warn about unneeded '# type: ignore' comments
                            (inverse: --no-warn-unused-ignores)
  --warn-unused-configs     warn about unused '[mypy-<pattern>]' config
                            sections (inverse: --no-warn-unused-configs)
  --show-error-context      Precede errors with "note:" messages explaining
                            context (inverse: --hide-error-context)
  --no-implicit-optional    don't assume arguments with default values of None
                            are Optional (inverse: --implicit-optional)
  -i, --incremental         enable module cache, (inverse: --no-incremental)
  --quick-and-dirty         use cache even if dependencies out of date
                            (implies --incremental)
  --cache-dir DIR           store module cache info in the given folder in
                            incremental mode (defaults to '.mypy_cache')
  --cache-fine-grained      include fine-grained dependency information in the
                            cache
  --skip-version-check      allow using cache written by older mypy version
  --strict-optional         enable experimental strict Optional checks
                            (inverse: --no-strict-optional)
  --strict-optional-whitelist [GLOB [GLOB ...]]
                            suppress strict Optional errors in all but the
                            provided files (experimental -- read documentation
                            before using!). Implies --strict-optional. Has the
                            undesirable side-effect of suppressing other
                            errors in non-whitelisted files.
  --junit-xml JUNIT_XML     write junit.xml to the given file
  --pdb                     invoke pdb on fatal error
  --show-traceback, --tb    show traceback on fatal error
  --stats                   dump stats
  --inferstats              dump type inference stats
  --custom-typing MODULE    use a custom typing module
  --custom-typeshed-dir DIR
                            use the custom typeshed in DIR
  --scripts-are-modules     Script x becomes module x instead of __main__
  --config-file CONFIG_FILE
                            Configuration file, must have a [mypy] section
                            (defaults to mypy.ini)
  --show-column-numbers     Show column numbers in error messages (inverse:
                            --hide-column-numbers)
  --find-occurrences CLASS.MEMBER
                            print out all usages of a class member
                            (experimental)
  --strict                  Strict mode. Enables the following flags:
                            --disallow-untyped-calls, --disallow-untyped-defs,
                            --disallow-incomplete-defs, --check-untyped-defs,
                            --disallow-subclassing-any, --disallow-untyped-
                            decorators, --warn-redundant-casts, --warn-return-
                            any, --warn-unused-ignores, --warn-unused-configs,
                            --no-implicit-optional, --strict-optional
  --shadow-file SOURCE_FILE SHADOW_FILE
                            Typecheck SHADOW_FILE in place of SOURCE_FILE.

report generation:
  Generate a report in the specified format.

  --any-exprs-report DIR
  --cobertura-xml-report DIR
  --html-report DIR
  --linecount-report DIR
  --linecoverage-report DIR
  --memory-xml-report DIR
  --txt-report DIR
  --xml-report DIR
  --xslt-html-report DIR
  --xslt-txt-report DIR

How to specify the code to type check:
  -m MODULE, --module MODULE
                            type-check module; can repeat for more modules
  -c PROGRAM_TEXT, --command PROGRAM_TEXT
                            type-check program passed in as string
  -p PACKAGE, --package PACKAGE
                            type-check all files in a directory
  files                     type-check given files or directories

environment variables: MYPYPATH additional module search path