|
| 1 | +#!/usr/bin/env python |
| 2 | +import argparse |
| 3 | +import ast |
| 4 | +import json |
| 5 | +from _ast import AST |
| 6 | +from pathlib import Path |
| 7 | + |
| 8 | + |
| 9 | +def print_parsed_result(file: Path, out:Path): |
| 10 | + node = ast.parse(file.read_text()) |
| 11 | + |
| 12 | + json_out = ast2json(node) |
| 13 | + |
| 14 | +# with open(Path(file.stem + "_ast").with_suffix(".json"), "w") as f: |
| 15 | +# json.dump(json.loads(json_out), f, indent=2) |
| 16 | + |
| 17 | + with open(Path(out), "w") as f: |
| 18 | + json.dump(json.loads(json_out), f, indent=2) |
| 19 | + |
| 20 | + |
| 21 | +def ast2json(node) -> str: |
| 22 | + if not isinstance(node, AST): |
| 23 | + raise TypeError('expected AST, got %r' % node.__class__.__name__) |
| 24 | + |
| 25 | + def _format(node) -> str: |
| 26 | + if isinstance(node, AST): |
| 27 | + name = node.__class__.__name__ |
| 28 | + fields = [('_PyType', _format(name))] |
| 29 | + fields += [(a, _format(b)) for a, b in iter_fields(node)] |
| 30 | + return '{ %s }' % ', '.join(('"%s": %s' % field for field in fields)) |
| 31 | + |
| 32 | + if isinstance(node, list): |
| 33 | + return '[ %s ]' % ', '.join([_format(x) for x in node]) |
| 34 | + |
| 35 | + # todo: better handling here? |
| 36 | + # this doesn't distinguish between |
| 37 | + # some_name: Tuple[a, ...] and some_name: Tuple[a, "..."] |
| 38 | + # both are serialized to |
| 39 | + # { |
| 40 | + # "_PyType": "Constant", |
| 41 | + # "value": "...", |
| 42 | + # "kind": null |
| 43 | + # } |
| 44 | + if node is ...: |
| 45 | + return json.dumps("...") |
| 46 | + |
| 47 | + return json.dumps(node) |
| 48 | + |
| 49 | + return _format(node) |
| 50 | + |
| 51 | + |
| 52 | +def iter_fields(node): |
| 53 | + for field in node._fields: |
| 54 | + try: |
| 55 | + yield field, getattr(node, field) |
| 56 | + except AttributeError: |
| 57 | + pass |
| 58 | + |
| 59 | + |
| 60 | +if __name__ == '__main__': |
| 61 | + parser = argparse.ArgumentParser() |
| 62 | + parser.add_argument("py_file") |
| 63 | + parser.add_argument("json_dump_file") |
| 64 | + |
| 65 | + args = parser.parse_args() |
| 66 | + |
| 67 | + print_parsed_result(Path(args.py_file), Path(args.json_dump_file)) |
0 commit comments