From 01b52fcca2e98c11e369175e9c8e7a0e6fb977ca Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Sun, 12 Apr 2020 13:15:33 +0100 Subject: [PATCH] add linting script for mypy --- lint | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mypy.ini | 10 +++++++ 2 files changed, 93 insertions(+) create mode 100755 lint create mode 100644 mypy.ini diff --git a/lint b/lint new file mode 100755 index 0000000..3aca624 --- /dev/null +++ b/lint @@ -0,0 +1,83 @@ +#!/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 +from typing import List, Optional, Iterable + + +def log(*args): + print(*args, file=sys.stderr) + + +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) -> Optional[str]: + def mname(p: Path): + nosuf = p.with_suffix('') + return str(nosuf).replace('/', '.') + + if p.suffix == '.py': + return mname(p) + + if p.is_dir() and (p / '__init__.py').exists(): + return mname(p) + + return None + + +def packages() -> Iterable[str]: + for p in sorted(p.relative_to(DIR) for p in (DIR / 'my').iterdir()): + res = package_name(p) + if res is not None: + yield res + + +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(package: str): + return run([ + 'mypy', + '--color-output', # TODO eh? doesn't work.. + '--namespace-packages', + '-p', package, + ], stdout=PIPE, stderr=PIPE) + + +def mypy_all() -> Iterable[Exception]: + from concurrent.futures import ThreadPoolExecutor + pkgs = list(packages()) + 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() diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..dd90c33 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,10 @@ +[mypy] +mypy_path=~/.config/my +pretty = True +show_error_context = True +show_error_codes = True +check_untyped_defs = True + +# it's not controled by me, so for now just ignore.. +[mypy-my.config.repos.pdfannots.pdfannots] +ignore_errors = True