Skip to content

Instantly share code, notes, and snippets.

@sebastian-philipp
Created November 29, 2018 13:06
Show Gist options
  • Select an option

  • Save sebastian-philipp/8265059ea9241e2e8b65de0652e6a81f to your computer and use it in GitHub Desktop.

Select an option

Save sebastian-philipp/8265059ea9241e2e8b65de0652e6a81f to your computer and use it in GitHub Desktop.
json_to_plain.py -- convert any JSON to plain text.
import json
from prettytable import PrettyTable
from functools import reduce
from orchestrator import InventoryDevice, InventoryNode, ServiceDescription
d = [
{
"path": "/dev/nvme0n1",
"sys_api": {
"removable": "0",
"ro": "0",
"vendor": "",
"model": "KXG50ZNV512G NVMe TOSHIBA 512GB",
"rev": "",
"sas_address": "",
"sas_device_handle": "",
"sectors": 0,
"size": 512110190592,
"support_discard": "",
"partitions": {
"nvme0n1p1": {
"start": "2048",
"sectors": "1024000",
"sectorsize": 512,
"size": "500.00 MB"
}
},
"rotational": "0",
"nr_requests": "1023",
"scheduler_mode": "none",
"sectorsize": "512",
"human_readable_size": "476.94 GB",
"path": "/dev/nvme0n1",
"locked": 1
},
"available": False,
"rejected_reasons": [
"locked"
],
"lvs": []
},
{
"path": "/dev/sda",
"sys_api": {
"removable": "0",
"ro": "0",
"vendor": "ATA",
"model": "ST2000LM007-1R81",
"rev": "SDM2",
"sas_address": "",
"sas_device_handle": "",
"sectors": 0,
"size": 2000398934016,
"support_discard": "",
"partitions": {
"sda1": {
"start": "2048",
"sectors": "3907026944",
"sectorsize": 512,
"size": "1.82 TB"
}
},
"rotational": "1",
"nr_requests": "128",
"scheduler_mode": "cfq",
"sectorsize": "512",
"human_readable_size": "1.82 TB",
"path": "/dev/sda",
"locked": 1
},
"available": False,
"rejected_reasons": [
"locked"
],
"lvs": []
}
]
class Section(object):
def __init__(self, heading, content):
self.depth, self.heading, self.content = 0, Leaf(heading), flatten(content)
def __str__(self):
return '\n'.join([str(self.heading), str(self.content)])
def __repr__(self):
return "Section({}, {})".format(repr(self.heading), repr(self.content))
def adjust_pretty_table(self, can_be_a_table):
return self.content.adjust_pretty_table(can_be_a_table)
def adjust_depth(self, depth):
self.depth = depth
self.heading.adjust_depth(depth)
self.content.adjust_depth(depth + 1)
class GenericTable(object):
def __init__(self, rows):
self.depth = 0
self.data = [{k: flatten(v) for (k, v) in row.items()} for row in rows]
self.table_header = sorted(reduce(lambda x, y: x | set(y), self.data, set()))
self.is_pretty_table = len(self.table_header) > 4
self.flat_data = None # type: GenericList
def __str__(self):
if self.is_pretty_table:
return str(self.to_pretty_table())
if not self.data:
return '{}[]'.format(' ' * 4 * self.depth)
return str(self.flat_data)
def __repr__(self):
return "GenericTable({})".format(repr(self.data))
def to_pretty_table(self):
def to_row(d):
return [(d[h] if h in d else '') for h in self.table_header]
table = PrettyTable(header_style='upper')
table.field_names = self.table_header
table.align = 'l'
table.border = False
# table.hrules = ALL
for d in self.data:
table.add_row(to_row(d))
return table
def adjust_pretty_table(self, can_be_a_table):
contains_pretty = any(any(e.adjust_pretty_table(False) for e in row.values()) for row in self.data)
if contains_pretty:
self.is_pretty_table = False
elif can_be_a_table:
self.is_pretty_table = True
return contains_pretty or self.is_pretty_table
def adjust_depth(self, depth):
self.depth = depth
if self.is_pretty_table:
for row in self.data:
for e in row.values():
e.adjust_depth(0)
else:
self.flat_data = GenericList(self.data)
self.flat_data.adjust_depth(self.depth)
class GenericList(object):
def __init__(self, data):
self.depth = 0
self.data = [flatten(e) for e in data]
def __str__(self):
return '\n'.join(str(r) for r in self.data)
def __repr__(self):
return "GenericList({})".format(repr(self.data))
def adjust_pretty_table(self, can_be_a_table):
return any(s.adjust_pretty_table(can_be_a_table) for s in self.data)
def adjust_depth(self, depth):
self.depth = depth
for e in self.data:
e.adjust_depth(depth + 1)
class GenericRow(object):
def __init__(self, data):
self.depth = 0
self.data = [Section(k, v) for (k, v) in sorted(data.items())]
def __str__(self):
return '\n'.join(str(r) for r in self.data)
def __repr__(self):
return "GenericRow({})".format(repr(self.data))
def adjust_pretty_table(self, can_be_a_table):
return any(s.adjust_pretty_table(can_be_a_table) for s in self.data)
def adjust_depth(self, depth):
self.depth = depth
for s in self.data:
s.adjust_depth(depth + 1)
class Leaf(object):
def __init__(self, data):
self.data, self.depth = data, 0
def __str__(self):
s = self.data if isinstance(self.data, str) else json.dumps(self.data)
return '{}{}'.format(' ' * 4 * self.depth, s)
def __repr__(self):
return "Leaf({})".format(repr(self.data))
def adjust_pretty_table(self, _can_be_a_table):
return False
def adjust_depth(self, depth):
self.depth = depth
def flatten(data):
def is_table():
return isinstance(data, list) and all((isinstance(r, dict) or isinstance(r, GenericRow) for r in data))
if isinstance(data, (Section, Leaf, GenericRow, GenericList, GenericTable)):
return data
if is_table():
return GenericTable(data)
if isinstance(data, list):
return GenericList(data)
if isinstance(data, dict):
return GenericRow(data)
return Leaf(data)
def flatten_orchestrator(data):
try:
if data._uuid == InventoryNode._uuid:
return {'name': data.name, 'devices': [flatten_orchestrator(d) for d in data.devices]}
if data._uuid == InventoryDevice._uuid:
return dict(type=data.type, blank=data.blank, id=data.id, size=data.size, **data.extended)
if data._uuid == ServiceDescription._uuid:
return {
'nodename': data.nodename,
'container_id': data.container_id,
'daemon_name': data.daemon_name,
'service_type': data.service_type,
}
except AttributeError:
pass
if isinstance(data, list):
return [flatten_orchestrator(e) for e in data]
if isinstance(data, dict):
return {k:flatten_orchestrator(v) for (k,v) in data.items()}
return data
def json_to_plain(data):
data = flatten_orchestrator(data)
content = flatten(data)
#return repr(content)
content.adjust_pretty_table(True)
content.adjust_depth(0)
return str(content)
print(json_to_plain(d))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment