Skip to content

Commit 4ad7fa8

Browse files
Tweak run_mypy.py to be more user-friendly
1 parent bedbb17 commit 4ad7fa8

File tree

1 file changed

+47
-53
lines changed

1 file changed

+47
-53
lines changed

scripts/run_mypy.py

Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@
1313

1414
import argparse
1515
import importlib
16+
import io
1617
import os
1718
import pathlib
1819
import subprocess
1920
import sys
2021

21-
from collections.abc import Iterator
22-
23-
import pandas
22+
import pandas as pd
2423

2524
DP_ROOT = pathlib.Path(__file__).absolute().parent.parent
2625
FAILING = """
@@ -59,55 +58,25 @@ def enforce_pep561(module_name):
5958
return
6059

6160

62-
def mypy_to_pandas(input_lines: Iterator[str]) -> pandas.DataFrame:
61+
def mypy_to_pandas(mypy_result: str) -> pd.DataFrame:
6362
"""Reformats mypy output with error codes to a DataFrame.
6463
6564
Adapted from: https://gist.github.com/michaelosthege/24d0703e5f37850c9e5679f69598930a
6665
"""
67-
current_section = None
68-
data = {
69-
"file": [],
70-
"line": [],
71-
"type": [],
72-
"errorcode": [],
73-
"message": [],
74-
}
75-
for line in input_lines:
76-
line = line.strip()
77-
elems = line.split(":")
78-
if len(elems) < 3:
79-
continue
80-
try:
81-
file, lineno, message_type, *_ = elems[0:3]
82-
message_type = message_type.strip()
83-
if message_type == "error":
84-
current_section = line.split(" [")[-1][:-1]
85-
message = line.replace(f"{file}:{lineno}: {message_type}: ", "").replace(
86-
f" [{current_section}]", ""
87-
)
88-
data["file"].append(file)
89-
data["line"].append(lineno)
90-
data["type"].append(message_type)
91-
data["errorcode"].append(current_section)
92-
data["message"].append(message)
93-
except Exception as ex:
94-
print(elems)
95-
print(ex)
96-
return pandas.DataFrame(data=data).set_index(["file", "line"])
97-
98-
99-
def check_no_unexpected_results(mypy_lines: Iterator[str]):
66+
return pd.read_json(io.StringIO(mypy_result), lines=True)
67+
68+
69+
def check_no_unexpected_results(mypy_df: pd.DataFrame, show_expected: bool):
10070
"""Compare mypy results with list of known FAILING files.
10171
10272
Exits the process with non-zero exit code upon unexpected results.
10373
"""
104-
df = mypy_to_pandas(mypy_lines)
10574
all_files = {
10675
str(fp).replace(str(DP_ROOT), "").strip(os.sep).replace(os.sep, "/")
10776
for fp in DP_ROOT.glob("pymc/**/*.py")
10877
if "tests" not in str(fp)
10978
}
110-
failing = set(df.reset_index().file.str.replace(os.sep, "/", regex=False))
79+
failing = set(mypy_df.file.str.replace(os.sep, "/", regex=False))
11180
if not failing.issubset(all_files):
11281
raise Exception(
11382
"Mypy should have ignored these files:\n"
@@ -122,13 +91,24 @@ def check_no_unexpected_results(mypy_lines: Iterator[str]):
12291
print(f"{len(passing)}/{len(all_files)} files pass as expected.")
12392
else:
12493
print("!!!!!!!!!")
125-
print(f"{len(unexpected_failing)} files unexpectedly failed.")
94+
print(f"{len(unexpected_failing)} files unexpectedly failed:")
12695
print("\n".join(sorted(map(str, unexpected_failing))))
127-
print(
128-
"These files did not fail before, so please check the above output"
129-
f" for errors in {unexpected_failing} and fix them."
130-
)
131-
print("You can run `python scripts/run_mypy.py --verbose` to reproduce this test locally.")
96+
97+
if show_expected:
98+
print(
99+
"\nThese files did not fail before, so please check the above output"
100+
f" for errors in {unexpected_failing} and fix them."
101+
)
102+
else:
103+
print("\nThese files did not fail before. Fix all errors reported in the output above.")
104+
print(
105+
f"\nNote: In addition to these errors, {len(failing.intersection(expected_failing))} errors in files "
106+
f'marked as "expected failures" were also found. To see these failures, run: '
107+
f"`python scripts/run_mypy.py --show-expected`"
108+
)
109+
110+
print("You can run `python scripts/run_mypy.py` to reproduce this test locally.")
111+
132112
sys.exit(1)
133113

134114
if unexpected_passing:
@@ -149,7 +129,12 @@ def check_no_unexpected_results(mypy_lines: Iterator[str]):
149129
if __name__ == "__main__":
150130
parser = argparse.ArgumentParser(description="Run mypy type checks on PyMC codebase.")
151131
parser.add_argument(
152-
"--verbose", action="count", default=0, help="Pass this to print mypy output."
132+
"--verbose", action="count", default=1, help="Pass this to print mypy output."
133+
)
134+
parser.add_argument(
135+
"--show-expected",
136+
action="store_true",
137+
help="Also show expected failures in verbose output.",
153138
)
154139
parser.add_argument(
155140
"--groupby",
@@ -159,16 +144,24 @@ def check_no_unexpected_results(mypy_lines: Iterator[str]):
159144
args, _ = parser.parse_known_args()
160145

161146
cp = subprocess.run(
162-
["mypy", "--show-error-codes", "--exclude", "tests", "pymc"],
147+
["mypy", "--output", "json", "--show-error-codes", "--exclude", "tests", "pymc"],
163148
capture_output=True,
164149
)
165-
output = cp.stdout.decode()
150+
151+
output = cp.stdout.decode("utf-8")
152+
df = mypy_to_pandas(output)
153+
166154
if args.verbose:
167-
df = mypy_to_pandas(output.split("\n"))
168-
for section, sdf in df.reset_index().groupby(args.groupby):
155+
if not args.show_expected:
156+
expected_failing = set(FAILING.strip().split("\n")) - {""}
157+
filtered_df = df.query("file not in @expected_failing")
158+
else:
159+
filtered_df = df
160+
161+
for section, sdf in filtered_df.groupby(args.groupby):
169162
print(f"\n\n[{section}]")
170-
for row in sdf.itertuples():
171-
print(f"{row.file}:{row.line}: {row.type} [{row.errorcode}]: {row.message}")
163+
for idx, row in sdf.iterrows():
164+
print(f"{row.file}:{row.line}: {row.code} [{row.severity}]: {row.message}")
172165
print()
173166
else:
174167
print(
@@ -177,5 +170,6 @@ def check_no_unexpected_results(mypy_lines: Iterator[str]):
177170
" or `python run_mypy.py --help` for other options."
178171
)
179172

180-
check_no_unexpected_results(output.split("\n"))
173+
check_no_unexpected_results(df, show_expected=args.show_expected)
174+
181175
sys.exit(0)

0 commit comments

Comments
 (0)