Skip to content

Instantly share code, notes, and snippets.

@Varal7
Created October 1, 2021 20:19
Show Gist options
  • Save Varal7/798f940d98b9ebb66094547ef0ca809c to your computer and use it in GitHub Desktop.
Save Varal7/798f940d98b9ebb66094547ef0ca809c to your computer and use it in GitHub Desktop.
#!/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