-
-
Notifications
You must be signed in to change notification settings - Fork 12.3k
Expand file tree
/
Copy pathpyright_completeness.py
More file actions
77 lines (64 loc) · 2.21 KB
/
pyright_completeness.py
File metadata and controls
77 lines (64 loc) · 2.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
"""
Run PyRight's `--verifytypes` and check that its reported type completeness is above
a minimum threshold.
Requires `basedpyright` to be installed in the environment.
Example usage:
spin run python tools/pyright_completeness.py --verifytypes numpy --ignoreexternal \
--exclude-like '*.tests.*' '*.conftest.*'
We use `--ignoreexternal` to avoid "partially unknown" reports coming from the stdlib
`numbers` module, see https://github.com/microsoft/pyright/discussions/9911.
"""
import argparse
import fnmatch
import json
import subprocess
import sys
from collections.abc import Sequence
def main(argv: Sequence[str] | None = None) -> int:
parser = argparse.ArgumentParser()
parser.add_argument(
"--exclude-like",
required=False,
nargs="*",
type=str,
help="Exclude symbols whose names matches this glob pattern",
)
args, unknownargs = parser.parse_known_args(argv)
pyright_args = list(unknownargs)
if "--outputjson" not in pyright_args:
pyright_args.append("--outputjson")
return run_pyright_with_coverage(pyright_args, args.exclude_like)
def run_pyright_with_coverage(
pyright_args: list[str],
exclude_like: Sequence[str],
) -> int:
result = subprocess.run(
["basedpyright", *pyright_args],
capture_output=True,
text=True,
)
try:
data = json.loads(result.stdout)
except json.decoder.JSONDecodeError:
sys.stdout.write(result.stdout)
sys.stderr.write(result.stderr)
return 1
if exclude_like:
symbols = data["typeCompleteness"]["symbols"]
matched_symbols = [
x
for x in symbols
if not any(fnmatch.fnmatch(x["name"], pattern) for pattern in exclude_like)
and x["isExported"]
]
covered = sum(x["isTypeKnown"] for x in matched_symbols) / len(matched_symbols)
else:
covered = data["typeCompleteness"]["completenessScore"]
sys.stderr.write(result.stderr)
if covered < 1:
sys.stdout.write(f"Coverage {covered:.1%} is below minimum required 100%\n")
return 1
sys.stdout.write("Coverage is at 100%\n")
return 0
if __name__ == "__main__":
sys.exit(main())