#!/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) def subpackages(package: str) -> Iterable[str]: ppath = package.replace('.', '/') yield from sorted({ package_name(p.relative_to(DIR)) for p in (DIR / ppath).rglob('*.py') }) # TODO meh.. think how to check _everything_ on CI def core_modules() -> Iterable[str]: return [ *subpackages('my.core'), 'my.config', 'my.cfg', '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 subpackages('my') 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' cmd = [ 'mypy', '--color-output', # TODO eh? doesn't work.. *(['-p'] if is_package else []), thing, ] print(' '.join(cmd), file=sys.stderr) return run(cmd, 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()