Created
October 1, 2021 20:19
-
-
Save Varal7/798f940d98b9ebb66094547ef0ca809c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
import gzip | |
import re | |
import json | |
import argparse | |
import code | |
import copy | |
from jsondiff import diff | |
from typing import Union | |
from IPython import embed | |
parser = argparse.ArgumentParser(description='Read JSON file') | |
parser.add_argument('json', type=str, help='Filename') | |
args = parser.parse_args() | |
class CompactJSONEncoder(json.JSONEncoder): | |
"""A JSON Encoder that puts small containers on single lines.""" | |
CONTAINER_TYPES = (list, tuple, dict) | |
"""Container datatypes include primitives or other containers.""" | |
MAX_WIDTH = 70 | |
"""Maximum width of a container that might be put on a single line.""" | |
MAX_ITEMS = 4 | |
"""Maximum number of items in container that might be put on single line.""" | |
INDENTATION_CHAR = " " | |
def __init__(self, *args, **kwargs): | |
# using this class without indentation is pointless | |
if kwargs.get("indent") is None: | |
kwargs.update({"indent": 4}) | |
super().__init__(*args, **kwargs) | |
self.indentation_level = 0 | |
def encode(self, o): | |
"""Encode JSON object *o* with respect to single line lists.""" | |
if isinstance(o, (list, tuple)): | |
if self._put_on_single_line(o): | |
return "[" + ", ".join(self.encode(el) for el in o) + "]" | |
else: | |
self.indentation_level += 1 | |
output = [self.indent_str + self.encode(el) for el in o] | |
self.indentation_level -= 1 | |
return "[\n" + ",\n".join(output) + "\n" + self.indent_str + "]" | |
elif isinstance(o, dict): | |
if o: | |
if self._put_on_single_line(o): | |
return "{ " + ", ".join(f"{self.encode(k)}: {self.encode(el)}" for k, el in o.items()) + " }" | |
else: | |
self.indentation_level += 1 | |
output = [self.indent_str + f"{json.dumps(k)}: {self.encode(v)}" for k, v in o.items()] | |
self.indentation_level -= 1 | |
return "{\n" + ",\n".join(output) + "\n" + self.indent_str + "}" | |
else: | |
return "{}" | |
elif isinstance(o, float): # Use scientific notation for floats, where appropiate | |
return format(o, "g") | |
elif isinstance(o, str): # escape newlines | |
o = o.replace("\n", "\\n") | |
return f'"{o}"' | |
else: | |
return json.dumps(o) | |
def iterencode(self, o, **kwargs): | |
"""Required to also work with `json.dump`.""" | |
return self.encode(o) | |
def _put_on_single_line(self, o): | |
return self._primitives_only(o) and len(o) <= self.MAX_ITEMS and len(str(o)) - 2 <= self.MAX_WIDTH | |
def _primitives_only(self, o: Union[list, tuple, dict]): | |
if isinstance(o, (list, tuple)): | |
return not any(isinstance(el, self.CONTAINER_TYPES) for el in o) | |
elif isinstance(o, dict): | |
return not any(isinstance(el, self.CONTAINER_TYPES) for el in o.values()) | |
@property | |
def indent_str(self) -> str: | |
return self.INDENTATION_CHAR*(self.indentation_level*self.indent) | |
def save(): | |
global original | |
d = diff(original, content) | |
print("Diff:") | |
print(d) | |
if input("Save diff? (y/n)\n") == "y": | |
print("Saving to {}".format(args.json)) | |
with open(args.json, 'w') as w: | |
json.dump(content, w, cls=CompactJSONEncoder, indent=2) | |
original = content | |
with open(args.json, 'r') as f: | |
original = json.load(f) | |
content = copy.deepcopy(original) | |
print("\nUsage: \n - `content` contains json content \n - Use `save()` to save to original path\n") | |
embed() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment