mirror of
https://github.com/davidhalter/typeshed.git
synced 2025-12-08 13:04:46 +08:00
Now that the new analyzer is the default, this does exactly the same as the normal mypy self test.
157 lines
5.4 KiB
Python
Executable File
157 lines
5.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Test runner for typeshed.
|
|
|
|
Depends on mypy being installed.
|
|
|
|
Approach:
|
|
|
|
1. Parse sys.argv
|
|
2. Compute appropriate arguments for mypy
|
|
3. Stuff those arguments into sys.argv
|
|
4. Run mypy.main('')
|
|
5. Repeat steps 2-4 for other mypy runs (e.g. --py2)
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="Test runner for typeshed. "
|
|
"Patterns are unanchored regexps on the full path.")
|
|
parser.add_argument('-v', '--verbose', action='count', default=0, help="More output")
|
|
parser.add_argument('-n', '--dry-run', action='store_true', help="Don't actually run mypy")
|
|
parser.add_argument('-x', '--exclude', type=str, nargs='*', help="Exclude pattern")
|
|
parser.add_argument('-p', '--python-version', type=str, nargs='*',
|
|
help="These versions only (major[.minor])")
|
|
parser.add_argument('--warn-unused-ignores', action='store_true',
|
|
help="Run mypy with --warn-unused-ignores "
|
|
"(hint: only get rid of warnings that are "
|
|
"unused for all platforms and Python versions)")
|
|
|
|
parser.add_argument('filter', type=str, nargs='*', help="Include pattern (default all)")
|
|
|
|
|
|
def log(args, *varargs):
|
|
if args.verbose >= 2:
|
|
print(*varargs)
|
|
|
|
|
|
def match(fn, args, blacklist):
|
|
if blacklist.match(fn):
|
|
log(args, fn, 'exluded by blacklist')
|
|
return False
|
|
if not args.filter and not args.exclude:
|
|
log(args, fn, 'accept by default')
|
|
return True
|
|
if args.exclude:
|
|
for f in args.exclude:
|
|
if re.search(f, fn):
|
|
log(args, fn, 'excluded by pattern', f)
|
|
return False
|
|
if args.filter:
|
|
for f in args.filter:
|
|
if re.search(f, fn):
|
|
log(args, fn, 'accepted by pattern', f)
|
|
return True
|
|
if args.filter:
|
|
log(args, fn, 'rejected (no pattern matches)')
|
|
return False
|
|
log(args, fn, 'accepted (no exclude pattern matches)')
|
|
return True
|
|
|
|
|
|
def libpath(major, minor):
|
|
versions = ['%d.%d' % (major, minor)
|
|
for minor in reversed(range(minor + 1))]
|
|
versions.append(str(major))
|
|
versions.append('2and3')
|
|
paths = []
|
|
for v in versions:
|
|
for top in ['stdlib', 'third_party']:
|
|
p = os.path.join(top, v)
|
|
if os.path.isdir(p):
|
|
paths.append(p)
|
|
return paths
|
|
|
|
|
|
def main():
|
|
args = parser.parse_args()
|
|
|
|
with open(os.path.join(os.path.dirname(__file__), "mypy_blacklist.txt")) as f:
|
|
blacklist = re.compile("(%s)$" % "|".join(
|
|
re.findall(r"^\s*([^\s#]+)\s*(?:#.*)?$", f.read(), flags=re.M)))
|
|
|
|
try:
|
|
from mypy.main import main as mypy_main
|
|
except ImportError:
|
|
print("Cannot import mypy. Did you install it?")
|
|
sys.exit(1)
|
|
|
|
versions = [(3, 7), (3, 6), (3, 5), (3, 4), (2, 7)]
|
|
if args.python_version:
|
|
versions = [v for v in versions
|
|
if any(('%d.%d' % v).startswith(av) for av in args.python_version)]
|
|
if not versions:
|
|
print("--- no versions selected ---")
|
|
sys.exit(1)
|
|
|
|
code = 0
|
|
runs = 0
|
|
for major, minor in versions:
|
|
roots = libpath(major, minor)
|
|
files = []
|
|
seen = {'__builtin__', 'builtins', 'typing'} # Always ignore these.
|
|
for root in roots:
|
|
names = os.listdir(root)
|
|
for name in names:
|
|
full = os.path.join(root, name)
|
|
mod, ext = os.path.splitext(name)
|
|
if mod in seen or mod.startswith('.'):
|
|
continue
|
|
if ext in ['.pyi', '.py']:
|
|
if match(full, args, blacklist):
|
|
seen.add(mod)
|
|
files.append(full)
|
|
elif (os.path.isfile(os.path.join(full, '__init__.pyi')) or
|
|
os.path.isfile(os.path.join(full, '__init__.py'))):
|
|
for r, ds, fs in os.walk(full):
|
|
ds.sort()
|
|
fs.sort()
|
|
for f in fs:
|
|
m, x = os.path.splitext(f)
|
|
if x in ['.pyi', '.py']:
|
|
fn = os.path.join(r, f)
|
|
if match(fn, args, blacklist):
|
|
seen.add(mod)
|
|
files.append(fn)
|
|
if files:
|
|
runs += 1
|
|
flags = ['--python-version', '%d.%d' % (major, minor)]
|
|
flags.append('--strict-optional')
|
|
flags.append('--no-site-packages')
|
|
flags.append('--show-traceback')
|
|
flags.append('--no-implicit-optional')
|
|
if args.warn_unused_ignores:
|
|
flags.append('--warn-unused-ignores')
|
|
sys.argv = ['mypy'] + flags + files
|
|
if args.verbose:
|
|
print("running", ' '.join(sys.argv))
|
|
else:
|
|
print("running mypy", ' '.join(flags), "# with", len(files), "files")
|
|
try:
|
|
if not args.dry_run:
|
|
mypy_main('', sys.stdout, sys.stderr)
|
|
except SystemExit as err:
|
|
code = max(code, err.code)
|
|
if code:
|
|
print("--- exit status", code, "---")
|
|
sys.exit(code)
|
|
if not runs:
|
|
print("--- nothing to do; exit 1 ---")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|