Files
zulip/tools/run-mypy
Zixuan James Li bf9f9c8b5d tools: Support running mypy daemon for better performance.
mypy daemon performs significantly better than running the regular
mypy cli tool when we type check the entire codebase multiple
times locally.

This adds running mypy daemon as an option for both
`tools/run-mypy` and `tools/lint`.

To ensure daemon messages like "Daemon started", "Daemon stopped"
won't get printed we filter any output that starts with "Daemon".

Signed-off-by: Zixuan James Li <p359101898@gmail.com>
2022-07-06 17:33:13 -07:00

89 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import os
import subprocess
import sys
from typing import List
from zulint import lister
TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT_DIR = os.path.dirname(TOOLS_DIR)
os.chdir(ROOT_DIR)
sys.path.append(ROOT_DIR)
from tools.lib.test_script import add_provision_check_override_param, assert_provisioning_status_ok
exclude = """
stubs/
""".split()
parser = argparse.ArgumentParser(description="Run mypy on files tracked by git.")
parser.add_argument("targets", nargs="*", help="files and directories to check (default: .)")
parser.add_argument("--version", action="store_true", help="show mypy version information and exit")
parser.add_argument("-m", "--modified", action="store_true", help="check only modified files")
parser.add_argument(
"--scripts-only", action="store_true", help="only check extensionless python scripts"
)
parser.add_argument(
"-a", "--all", action="store_true", help="check all files, bypassing the default exclude list"
)
parser.add_argument("-d", "--use-daemon", action="store_true", help="run mypy daemon instead")
add_provision_check_override_param(parser)
parser.add_argument("--quiet", action="store_true", help="suppress mypy summary output")
args = parser.parse_args()
assert_provisioning_status_ok(args.skip_provision_check)
if args.use_daemon:
command_name = "dmypy"
else:
command_name = "mypy"
# Use zulip-py3-venv's mypy if it's available.
VENV_DIR = "/srv/zulip-py3-venv"
MYPY_VENV_PATH = os.path.join(VENV_DIR, "bin", command_name)
if os.path.exists(MYPY_VENV_PATH):
mypy_command = MYPY_VENV_PATH
else:
mypy_command = command_name
if args.version:
print("mypy command:", mypy_command)
sys.exit(subprocess.call([mypy_command, "--version"]))
if args.all:
exclude = []
# find all non-excluded files in current directory
files_dict = lister.list_files(
targets=args.targets,
ftypes=["py", "pyi"],
use_shebang=True,
modified_only=args.modified,
exclude=exclude,
group_by_ftype=True,
extless_only=args.scripts_only,
)
pyi_files = list(files_dict["pyi"])
python_files = [
fpath for fpath in files_dict["py"] if not fpath.endswith(".py") or fpath + "i" not in pyi_files
]
if not python_files and not pyi_files:
print("There are no files to run mypy on.")
sys.exit(0)
mypy_args: List[str] = []
# --no-error-summary is a mypy flag that comes after all dmypy options
if args.use_daemon:
mypy_args += ["run", "--"]
if args.quiet:
mypy_args += ["--no-error-summary"]
mypy_args += ["--", *python_files, *pyi_files]
rc = subprocess.call([mypy_command, *mypy_args])
if rc != 0:
print("")
print("See https://zulip.readthedocs.io/en/latest/testing/mypy.html for debugging tips.")
sys.exit(rc)