class OutFormat: def __init__(self, data): self.spans = { } self.rows = [ ] for row in data: vals = { } for field in row: vals[field] = self.normalize(row[field]) if field in self.spans: self.spans[field] = max(self.spans[field], len(vals[field])) else: self.spans[field] = max(len(field), len(vals[field])) self.rows.append(vals) self.cols = list(self.spans.keys()) def normalize(self, field): if type(field) == list: return ", ".join(field) else: return str(field) def render(self): # FIXME: consider if this should do anything pass class Basic(OutFormat): def __init__(self, data): super().__init__(data) self.top = { "left": "+", "right": "+", "divide": "+", "fill": "-" } self.base = { "left": "+", "right": "+", "divide": "+", "fill": "-" } self.sep = { "left": "|", "right": "|", "divide": "+", "fill": "-" } self.row = { "left": "|", "right": "|", "divide": "|", "fill": " " } def render(self): sep = "" top = "" hdr = "" base = "" fill = self.row["fill"] for col in self.cols: width = self.spans[col] + 2 sep += self.sep["divide"] + self.sep["fill"] * width top += self.top["divide"] + self.top["fill"] * width hdr += self.row["divide"] + fill + col.ljust(width - 1, fill) base += self.base["divide"] + self.base["fill"] * width sep = self.sep["left"] + sep[1:] + self.sep["right"] + "\n" top = self.top["left"] + top[1:] + self.top["right"] + "\n" hdr = self.row["left"] + hdr[1:] + self.row["right"] + "\n" base = self.base["left"] + base[1:] + self.base["right"] lines = [ ] for row in self.rows: line = "" for col in self.cols: width = self.spans[col] + 2 if col in row: line += self.row["divide"] + fill + row[col].ljust(width - 1, fill) else: line += slef.row["divide"] + fill * width lines.append(self.row["left"] + line[1:] + self.row["right"] + "\n") return top + sep.join([hdr, *lines]) + base class Table(Basic): def __init__(self, data): super().__init__(data) self.top = { "left": "\u250F", "right": "\u2513", "divide": "\u2533", "fill": "\u2501" } self.base = { "left": "\u2517", "right": "\u251B", "divide": "\u253B", "fill": "\u2501" } self.sep = { "left": "\u2523", "right": "\u252B", "divide": "\u254B", "fill": "\u2501" } self.row = { "left": "\u2503", "right": "\u2503", "divide": "\u2503", "fill": " " } class Json(OutFormat): pass class Csv(OutFormat): pass FORMATS = { "basic": Basic, "table": Table, "json": Json, "csv": Csv }