64 lines
1.6 KiB
Python
64 lines
1.6 KiB
Python
from abc import ABC, abstractmethod
|
|
|
|
|
|
class TableFormatter(ABC):
|
|
_formats = {}
|
|
|
|
@classmethod
|
|
def __init_subclass__(cls):
|
|
name = cls.__module__.split('.')[-1]
|
|
TableFormatter._formats[name] = cls
|
|
|
|
@abstractmethod
|
|
def headings(self, headers):
|
|
pass
|
|
|
|
@abstractmethod
|
|
def row(self, rowdata):
|
|
pass
|
|
|
|
|
|
class ColumnFormatMixin:
|
|
formats = []
|
|
|
|
def row(self, rowdata):
|
|
rowdata = [(fmt % d) for fmt, d in zip(self.formats, rowdata)]
|
|
super().row(rowdata)
|
|
|
|
|
|
class UpperHeadersMixin:
|
|
def headings(self, headers):
|
|
super().headings([h.upper() for h in headers])
|
|
|
|
|
|
def create_formatter(name, column_formats=None, upper_headers=False):
|
|
if not name:
|
|
raise ValueError(f'formatter named "{name}" not implemented')
|
|
if name not in TableFormatter._formats:
|
|
__import__(f'{__package__}.{name}')
|
|
formatter = TableFormatter._formats.get(name)
|
|
if not formatter:
|
|
raise RuntimeError(f'Unknown format {name}')
|
|
|
|
if upper_headers:
|
|
class _UpperFormatter(UpperHeadersMixin, formatter):
|
|
pass
|
|
|
|
formatter = _UpperFormatter
|
|
if column_formats:
|
|
|
|
class _ColumnFormatter(ColumnFormatMixin, formatter):
|
|
formats = column_formats
|
|
|
|
formatter = _ColumnFormatter
|
|
return formatter()
|
|
|
|
|
|
def print_table(records, fields, formatter):
|
|
if not isinstance(formatter, TableFormatter):
|
|
raise TypeError("expected a TableFormatter")
|
|
|
|
formatter.headings(fields)
|
|
for record in records:
|
|
formatter.row([getattr(record, fieldname) for fieldname in fields])
|