forked from zulip/zulip
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrun-mypy
executable file
·131 lines (114 loc) · 5.11 KB
/
run-mypy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python
from __future__ import absolute_import
from __future__ import print_function
import os
import sys
import argparse
import subprocess
import six
import lister
from typing import cast, Dict, List
TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
os.chdir(os.path.dirname(TOOLS_DIR))
exclude_common = """
api/integrations/codebase/zulip_codebase_config.py
api/integrations/git/zulip_git_config.py
api/integrations/perforce/git_p4.py
api/integrations/perforce/zulip_perforce_config.py
api/integrations/svn/zulip_svn_config.py
api/integrations/trac/zulip_trac_config.py
api/integrations/git/post-receive
zproject/settings.py
zproject/test_settings.py
""".split()
# We don't run mypy on api/bots since the code there will
# often be shared with other projects that do not want a mypy
# dependency (at least while it's still kind of beta).
exclude_common += ['api/bots']
exclude_py2 = [] # type: List[str]
exclude_py3 = """
api/integrations/zephyr/process_ccache
""".split()
parser = argparse.ArgumentParser(description="Run mypy on files tracked by git.")
parser.add_argument('targets', nargs='*', default=[],
help="""files and directories to include in the result.
If this is not specified, the current directory is used""")
parser.add_argument('-m', '--modified', action='store_true', default=False, help='list only modified files')
parser.add_argument('-a', '--all', dest='all', action='store_true', default=False,
help="""run mypy on all python files, ignoring the exclude list.
This is useful if you have to find out which files fail mypy check.""")
parser.add_argument('--linecoverage-report', dest='linecoverage_report', action='store_true', default=False,
help="""run the linecoverage report to see annotation coverage""")
parser.add_argument('--no-disallow-untyped-defs', dest='disallow_untyped_defs', action='store_false', default=True,
help="""Don't throw errors when functions are not annotated""")
parser.add_argument('--scripts-only', dest='scripts_only', action='store_true', default=False,
help="""Only type check extensionless python scripts""")
parser.add_argument('--strict-optional', dest='strict_optional', action='store_true', default=False,
help="""Use the --strict-optional flag with mypy""")
parser.add_argument('--no-ignore-missing-imports', dest='ignore_missing_imports', action='store_false', default=True,
help="""Don't use the --ignore-missing-imports flag with mypy""")
parser.add_argument('--quick', action='store_true', default=False,
help="""Use the --quick flag with mypy""")
group = parser.add_mutually_exclusive_group()
group.add_argument('--py2', default=False, action='store_true', help="Use Python 2 mode")
group.add_argument('--py3', default=False, action='store_true', help="Use Python 3 mode")
args = parser.parse_args()
if args.py2:
py_version = 2
elif args.py3:
py_version = 3
else:
py_version = 2
if args.all:
exclude = [] # type: List[str]
if py_version == 2:
exclude = exclude_common + exclude_py2
else:
exclude = exclude_common + exclude_py3
# find all non-excluded files in current directory
files_dict = cast(Dict[str, List[str]],
lister.list_files(targets=args.targets, ftypes=['py', 'pyi'],
use_shebang=True, modified_only=args.modified,
exclude = exclude + ['stubs'], group_by_ftype=True,
extless_only=args.scripts_only))
pyi_files = set(files_dict['pyi'])
python_files = [fpath for fpath in files_dict['py']
if not fpath.endswith('.py') or fpath + 'i' not in pyi_files]
# Use zulip-py3-venv's mypy if it's available and we're on python 2
PY3_VENV_DIR = "/srv/zulip-py3-venv"
MYPY_VENV_PATH = os.path.join(PY3_VENV_DIR, "bin", "mypy")
if six.PY2 and os.path.exists(MYPY_VENV_PATH):
mypy_command = MYPY_VENV_PATH
print("Using mypy from", mypy_command)
else:
mypy_command = "mypy"
extra_args = ["--check-untyped-defs",
"--follow-imports=silent",
"--scripts-are-modules",
"-i", "--cache-dir=var/mypy-cache"]
if py_version == 2:
extra_args.append("--py2")
if args.linecoverage_report:
extra_args.append("--linecoverage-report")
extra_args.append("var/linecoverage-report")
if args.disallow_untyped_defs:
extra_args.append("--disallow-untyped-defs")
if args.strict_optional:
extra_args.append("--strict-optional")
if args.ignore_missing_imports:
extra_args.append("--ignore-missing-imports")
if args.quick:
extra_args.append("--quick")
# run mypy
if python_files:
rc = subprocess.call([mypy_command] + extra_args + python_files)
if args.linecoverage_report:
# Move the coverage report to where codecov will look for it.
try:
os.rename('var/linecoverage-report/coverage.txt', 'var/.coverage')
except OSError:
# maybe mypy crashed; exit with its error code
pass
sys.exit(rc)
else:
print("There are no files to run mypy on.")