Skip to content

Commit 3c9bd6a

Browse files
committed
Update JSON export tool to support binary meta cache files
1 parent b266dd1 commit 3c9bd6a

File tree

3 files changed

+101
-8
lines changed

3 files changed

+101
-8
lines changed

mypy/exportjson.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Tool to convert mypy cache file to a JSON format (print to stdout).
1+
"""Tool to convert binary mypy cache files (.ff) to JSON (.ff.json).
22
33
Usage:
44
python -m mypy.exportjson .mypy_cache/.../my_module.data.ff
@@ -21,6 +21,7 @@
2121

2222
from librt.internal import Buffer
2323

24+
from mypy.cache import CacheMeta
2425
from mypy.nodes import (
2526
FUNCBASE_FLAGS,
2627
FUNCDEF_FLAGS,
@@ -552,6 +553,30 @@ def convert_unbound_type(self: UnboundType) -> Json:
552553
}
553554

554555

556+
def convert_binary_cache_meta_to_json(data: bytes, data_file: str) -> Json:
557+
meta = CacheMeta.read(Buffer(data), data_file)
558+
assert meta is not None, f"Error reading meta cache file associated with {data_file}"
559+
return {
560+
"id": meta.id,
561+
"path": meta.path,
562+
"mtime": meta.mtime,
563+
"size": meta.size,
564+
"hash": meta.hash,
565+
"data_mtime": meta.data_mtime,
566+
"dependencies": meta.dependencies,
567+
"suppressed": meta.suppressed,
568+
"options": meta.options,
569+
"dep_prios": meta.dep_prios,
570+
"dep_lines": meta.dep_lines,
571+
"dep_hashes": [dep.hex() for dep in meta.dep_hashes],
572+
"interface_hash": meta.interface_hash.hex(),
573+
"error_lines": meta.error_lines,
574+
"version_id": meta.version_id,
575+
"ignore_all": meta.ignore_all,
576+
"plugin_data": meta.plugin_data,
577+
}
578+
579+
555580
def main() -> None:
556581
parser = argparse.ArgumentParser(
557582
description="Convert binary cache files to JSON. "
@@ -563,11 +588,19 @@ def main() -> None:
563588
args = parser.parse_args()
564589
fnams: list[str] = args.path
565590
for fnam in fnams:
566-
if not fnam.endswith(".data.ff"):
567-
sys.exit(f"error: Expected .data.ff extension, but got {fnam}")
591+
if fnam.endswith(".data.ff"):
592+
is_data = True
593+
elif fnam.endswith(".meta.ff"):
594+
is_data = False
595+
else:
596+
sys.exit(f"error: Expected .data.ff or .meta.ff extension, but got {fnam}")
568597
with open(fnam, "rb") as f:
569598
data = f.read()
570-
json_data = convert_binary_cache_to_json(data)
599+
if is_data:
600+
json_data = convert_binary_cache_to_json(data)
601+
else:
602+
data_file = fnam.removesuffix(".meta.ff") + ".data.ff"
603+
json_data = convert_binary_cache_meta_to_json(data, data_file)
571604
new_fnam = fnam + ".json"
572605
with open(new_fnam, "w") as f:
573606
json.dump(json_data, f)

mypy/test/testexportjson.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from mypy import build
1111
from mypy.errors import CompileError
12-
from mypy.exportjson import convert_binary_cache_to_json
12+
from mypy.exportjson import convert_binary_cache_meta_to_json, convert_binary_cache_to_json
1313
from mypy.modulefinder import BuildSource
1414
from mypy.options import Options
1515
from mypy.test.config import test_temp_dir
@@ -53,12 +53,28 @@ def run_case(self, testcase: DataDrivenTestCase) -> None:
5353
):
5454
continue
5555
fnam = os.path.join(cache_dir, f"{module}.data.ff")
56-
with open(fnam, "rb") as f:
57-
json_data = convert_binary_cache_to_json(f.read(), implicit_names=False)
56+
is_meta = testcase.name.endswith("_meta")
57+
if not is_meta:
58+
with open(fnam, "rb") as f:
59+
json_data = convert_binary_cache_to_json(f.read(), implicit_names=False)
60+
else:
61+
meta_fnam = os.path.join(cache_dir, f"{module}.meta.ff")
62+
with open(meta_fnam, "rb") as f:
63+
json_data = convert_binary_cache_meta_to_json(f.read(), fnam)
5864
for line in json.dumps(json_data, indent=4).splitlines():
5965
if '"path": ' in line:
60-
# We source file path is unpredictable, so filter it out
66+
# The source file path is unpredictable, so filter it out
6167
line = re.sub(r'"[^"]+\.pyi?"', "...", line)
68+
if is_meta:
69+
if '"version_id"' in line:
70+
line = re.sub(r'"[0-9][^"]+"', "...", line)
71+
if '"mtime"' in line or '"data_mtime"' in line:
72+
line = re.sub(r": [0-9]+", ": ...", line)
73+
if '"platform"' in line:
74+
line = re.sub(': "[^"]+"', ": ...", line)
75+
if '"hash"' not in line:
76+
# Some hashes are unpredictable so filter them out
77+
line = re.sub(r'"[a-f0-9]{40}"', '"<hash>"', line)
6278
assert "ERROR" not in line, line
6379
a.append(line)
6480
except CompileError as e:

test-data/unit/exportjson.test

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,47 @@ x: X = 2
278278
[builtins fixtures/tuple.pyi]
279279
[out]
280280
<not checked>
281+
282+
[case testExportMetaBasic_meta]
283+
import typing
284+
from typing_extensions import Final
285+
[builtins fixtures/tuple.pyi]
286+
[out]
287+
{
288+
"id": "main",
289+
"path": ...,
290+
"mtime": ...,
291+
"size": 49,
292+
"hash": "db2252f953c889e6b78dde8e30bd241a0c86b2d9",
293+
"data_mtime": ...,
294+
"dependencies": [
295+
"typing",
296+
"typing_extensions",
297+
"builtins"
298+
],
299+
"suppressed": [],
300+
"options": {
301+
"other_options": "<hash>",
302+
"platform": ...
303+
},
304+
"dep_prios": [
305+
10,
306+
5,
307+
5
308+
],
309+
"dep_lines": [
310+
1,
311+
2,
312+
1
313+
],
314+
"dep_hashes": [
315+
"<hash>",
316+
"<hash>",
317+
"<hash>"
318+
],
319+
"interface_hash": "<hash>",
320+
"error_lines": [],
321+
"version_id": ...,
322+
"ignore_all": false,
323+
"plugin_data": null
324+
}

0 commit comments

Comments
 (0)