100 lines
2.5 KiB
Python
Executable file
100 lines
2.5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
from pathlib import Path
|
|
from pprint import pprint
|
|
from itertools import chain
|
|
from subprocess import check_call, run, PIPE
|
|
import sys
|
|
import os
|
|
from typing import List, Optional, Iterable
|
|
|
|
|
|
def log(*args):
|
|
print(*args, file=sys.stderr)
|
|
|
|
CI = 'CI' in os.environ
|
|
|
|
DIR = Path(__file__).absolute().parent
|
|
|
|
# hmm. I guess I need to check all subpackages separately
|
|
# otherwise pylint doesn't work and mypy doesn't discover everything
|
|
|
|
# TODO could reuse in readme??
|
|
# returns None if not a package
|
|
def package_name(p: Path) -> str:
|
|
def mname(p: Path):
|
|
nosuf = p.with_suffix('')
|
|
return str(nosuf).replace('/', '.')
|
|
|
|
has_init = (p.parent / '__init__.py').exists()
|
|
if has_init:
|
|
return mname(p.parent)
|
|
else:
|
|
return mname(p)
|
|
|
|
# TODO meh.. think how to check _everything_ on CI
|
|
def core_modules() -> Iterable[str]:
|
|
return [
|
|
'my.common',
|
|
'my.config',
|
|
'my.core',
|
|
'my.cfg',
|
|
'my.error',
|
|
'my.init',
|
|
'tests/misc.py',
|
|
'tests/get_files.py',
|
|
# 'tests/config.py', TODO hmm. unclear how to type check this module
|
|
]
|
|
|
|
|
|
def all_modules() -> Iterable[str]:
|
|
yield from sorted(set(
|
|
package_name(p.relative_to(DIR)) for p in (DIR / 'my').rglob('*.py')
|
|
))
|
|
yield from sorted(
|
|
str(f.relative_to(DIR)) for f in (DIR / 'tests').rglob('*.py')
|
|
)
|
|
|
|
|
|
def pylint():
|
|
# TODO ugh. pylint still doesn't like checking my.config or my.books
|
|
# only top level .py files seem ok??
|
|
pass
|
|
|
|
|
|
def mypy(thing: str):
|
|
is_package = Path(thing).suffix != '.py'
|
|
return run([
|
|
'mypy',
|
|
'--color-output', # TODO eh? doesn't work..
|
|
*(['-p'] if is_package else []), thing,
|
|
], stdout=PIPE, stderr=PIPE)
|
|
|
|
|
|
def mypy_all() -> Iterable[Exception]:
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
|
|
pkgs = list(core_modules() if CI else all_modules())
|
|
log(f"Checking {pkgs}")
|
|
with ThreadPoolExecutor() as pool:
|
|
for p, res in zip(pkgs, pool.map(mypy, pkgs)):
|
|
ret = res.returncode
|
|
if ret > 0:
|
|
log(f'FAILED: {p}')
|
|
else:
|
|
log(f'OK: {p}')
|
|
print(res.stdout.decode('utf8'))
|
|
print(res.stderr.decode('utf8'), file=sys.stderr)
|
|
try:
|
|
res.check_returncode()
|
|
except Exception as e:
|
|
yield e
|
|
|
|
|
|
def main():
|
|
errors = list(mypy_all())
|
|
if len(errors) > 0:
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|