Skip to content

Commit 7c382c7

Browse files
authored
Run mypy tests for stdlib and third-party separately (#5760)
1 parent 7f320c6 commit 7c382c7

File tree

2 files changed

+69
-58
lines changed

2 files changed

+69
-58
lines changed

requirements-tests-py3.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
mypy==0.902
1+
mypy==0.910
22
typed-ast==1.4.3
33
black==21.6b0
44
flake8==3.9.2
55
flake8-bugbear==21.4.3
66
flake8-pyi==20.10.0
7-
isort==5.8.0
7+
isort==5.9.2
88
pytype==2021.06.17

tests/mypy_test.py

Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@
1616
import os
1717
import re
1818
import sys
19-
import toml
2019
import tempfile
2120
from glob import glob
2221
from pathlib import Path
2322
from typing import Dict, NamedTuple
2423

25-
parser = argparse.ArgumentParser(
26-
description="Test runner for typeshed. Patterns are unanchored regexps on the full path."
27-
)
24+
import toml
25+
26+
parser = argparse.ArgumentParser(description="Test runner for typeshed. Patterns are unanchored regexps on the full path.")
2827
parser.add_argument("-v", "--verbose", action="count", default=0, help="More output")
2928
parser.add_argument("-n", "--dry-run", action="store_true", help="Don't actually run mypy")
3029
parser.add_argument("-x", "--exclude", type=str, nargs="*", help="Exclude pattern")
@@ -123,10 +122,7 @@ def add_files(files, seen, root, name, args, exclude_list):
123122
if match(full, args, exclude_list):
124123
seen.add(mod)
125124
files.append(full)
126-
elif (
127-
os.path.isfile(os.path.join(full, "__init__.pyi")) or
128-
os.path.isfile(os.path.join(full, "__init__.py"))
129-
):
125+
elif os.path.isfile(os.path.join(full, "__init__.pyi")) or os.path.isfile(os.path.join(full, "__init__.py")):
130126
for r, ds, fs in os.walk(full):
131127
ds.sort()
132128
fs.sort()
@@ -143,6 +139,7 @@ class MypyDistConf(NamedTuple):
143139
module_name: str
144140
values: Dict
145141

142+
146143
# The configuration section in the metadata file looks like the following, with multiple module sections possible
147144
# [mypy-tests]
148145
# [mypy-tests.yaml]
@@ -179,18 +176,61 @@ def add_configuration(configurations, seen_dist_configs, distribution):
179176
seen_dist_configs.add(distribution)
180177

181178

182-
def main():
183-
args = parser.parse_args()
184-
185-
with open(os.path.join(os.path.dirname(__file__), "mypy_exclude_list.txt")) as f:
186-
exclude_list = re.compile("(%s)$" % "|".join(re.findall(r"^\s*([^\s#]+)\s*(?:#.*)?$", f.read(), flags=re.M)))
187-
179+
def run_mypy(args, configurations, major, minor, files, *, custom_typeshed=False):
188180
try:
189181
from mypy.main import main as mypy_main
190182
except ImportError:
191183
print("Cannot import mypy. Did you install it?")
192184
sys.exit(1)
193185

186+
with tempfile.NamedTemporaryFile("w+") as temp:
187+
temp.write("[mypy]\n")
188+
for dist_conf in configurations:
189+
temp.write("[mypy-%s]\n" % dist_conf.module_name)
190+
for k, v in dist_conf.values.items():
191+
temp.write("{} = {}\n".format(k, v))
192+
temp.flush()
193+
194+
flags = [
195+
"--python-version",
196+
"%d.%d" % (major, minor),
197+
"--config-file",
198+
temp.name,
199+
"--strict-optional",
200+
"--no-site-packages",
201+
"--show-traceback",
202+
"--no-implicit-optional",
203+
"--disallow-any-generics",
204+
"--disallow-subclassing-any",
205+
"--warn-incomplete-stub",
206+
]
207+
if custom_typeshed:
208+
# Setting custom typeshed dir prevents mypy from falling back to its bundled
209+
# typeshed in case of stub deletions
210+
flags.extend(["--custom-typeshed-dir", os.path.dirname(os.path.dirname(__file__))])
211+
if args.warn_unused_ignores:
212+
flags.append("--warn-unused-ignores")
213+
if args.platform:
214+
flags.extend(["--platform", args.platform])
215+
sys.argv = ["mypy"] + flags + files
216+
if args.verbose:
217+
print("running", " ".join(sys.argv))
218+
else:
219+
print("running mypy", " ".join(flags), "# with", len(files), "files")
220+
if not args.dry_run:
221+
try:
222+
mypy_main("", sys.stdout, sys.stderr)
223+
except SystemExit as err:
224+
return err.code
225+
return 0
226+
227+
228+
def main():
229+
args = parser.parse_args()
230+
231+
with open(os.path.join(os.path.dirname(__file__), "mypy_exclude_list.txt")) as f:
232+
exclude_list = re.compile("(%s)$" % "|".join(re.findall(r"^\s*([^\s#]+)\s*(?:#.*)?$", f.read(), flags=re.M)))
233+
194234
versions = [(3, 10), (3, 9), (3, 8), (3, 7), (3, 6), (2, 7)]
195235
if args.python_version:
196236
versions = [v for v in versions if any(("%d.%d" % v).startswith(av) for av in args.python_version)]
@@ -201,12 +241,12 @@ def main():
201241
code = 0
202242
runs = 0
203243
for major, minor in versions:
204-
files = []
205244
seen = {"__builtin__", "builtins", "typing"} # Always ignore these.
206245
configurations = []
207246
seen_dist_configs = set()
208247

209-
# First add standard library files.
248+
# Test standard library files.
249+
files = []
210250
if major == 2:
211251
root = os.path.join("stdlib", "@python2")
212252
for name in os.listdir(root):
@@ -224,7 +264,13 @@ def main():
224264
if supported_versions[mod][0] <= (major, minor) <= supported_versions[mod][1]:
225265
add_files(files, seen, root, name, args, exclude_list)
226266

227-
# Next add files for all third party distributions.
267+
if files:
268+
this_code = run_mypy(args, configurations, major, minor, files, custom_typeshed=True)
269+
code = max(code, this_code)
270+
runs += 1
271+
272+
# Test files of all third party distributions.
273+
files = []
228274
for distribution in os.listdir("stubs"):
229275
if not is_supported(distribution, major):
230276
continue
@@ -242,46 +288,11 @@ def main():
242288
add_configuration(configurations, seen_dist_configs, distribution)
243289

244290
if files:
245-
with tempfile.NamedTemporaryFile("w+", delete=False) as temp:
246-
temp.write("[mypy]\n")
247-
248-
for dist_conf in configurations:
249-
temp.write("[mypy-%s]\n" % dist_conf.module_name)
250-
for k, v in dist_conf.values.items():
251-
temp.write("{} = {}\n".format(k, v))
252-
253-
config_file_name = temp.name
291+
# TODO: remove custom_typeshed after mypy 0.920 is released
292+
this_code = run_mypy(args, configurations, major, minor, files, custom_typeshed=True)
293+
code = max(code, this_code)
254294
runs += 1
255-
flags = [
256-
"--python-version", "%d.%d" % (major, minor),
257-
"--config-file", config_file_name,
258-
"--strict-optional",
259-
"--no-site-packages",
260-
"--show-traceback",
261-
"--no-implicit-optional",
262-
"--disallow-any-generics",
263-
"--disallow-subclassing-any",
264-
"--warn-incomplete-stub",
265-
# Setting custom typeshed dir prevents mypy from falling back to its bundled
266-
# typeshed in case of stub deletions
267-
"--custom-typeshed-dir", os.path.dirname(os.path.dirname(__file__)),
268-
]
269-
if args.warn_unused_ignores:
270-
flags.append("--warn-unused-ignores")
271-
if args.platform:
272-
flags.extend(["--platform", args.platform])
273-
sys.argv = ["mypy"] + flags + files
274-
if args.verbose:
275-
print("running", " ".join(sys.argv))
276-
else:
277-
print("running mypy", " ".join(flags), "# with", len(files), "files")
278-
try:
279-
if not args.dry_run:
280-
mypy_main("", sys.stdout, sys.stderr)
281-
except SystemExit as err:
282-
code = max(code, err.code)
283-
finally:
284-
os.remove(config_file_name)
295+
285296
if code:
286297
print("--- exit status", code, "---")
287298
sys.exit(code)

0 commit comments

Comments
 (0)