enhacements to FormattedOutput (#1376)
* enhacements to FormattedOutput * flake8 complain
This commit is contained in:
parent
7bf0fe3c56
commit
68d89a07df
|
|
@ -2,45 +2,83 @@ import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Union, List, Any
|
from typing import Dict, Union, List, Any, Callable
|
||||||
|
|
||||||
from .storage import storage
|
from .storage import storage
|
||||||
|
from dataclasses import asdict, is_dataclass
|
||||||
|
|
||||||
|
|
||||||
class FormattedOutput:
|
class FormattedOutput:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def values(cls, o: Any) -> Dict[str, Any]:
|
def values(cls, o: Any, class_formatter: str = None, filter_list: List[str] = None) -> Dict[str, Any]:
|
||||||
if hasattr(o, 'as_json'):
|
""" the original values returned a dataclass as dict thru the call to some specific methods
|
||||||
|
this version allows thru the parameter class_formatter to call a dynamicly selected formatting method.
|
||||||
|
Can transmit a filter list to the class_formatter,
|
||||||
|
"""
|
||||||
|
if class_formatter:
|
||||||
|
# if invoked per reference it has to be a standard function or a classmethod.
|
||||||
|
# A method of an instance does not make sense
|
||||||
|
if callable(class_formatter):
|
||||||
|
return class_formatter(o, filter_list)
|
||||||
|
# if is invoked by name we restrict it to a method of the class. No need to mess more
|
||||||
|
elif hasattr(o, class_formatter) and callable(getattr(o, class_formatter)):
|
||||||
|
func = getattr(o, class_formatter)
|
||||||
|
return func(filter_list)
|
||||||
|
# kept as to make it backward compatible
|
||||||
|
elif hasattr(o, 'as_json'):
|
||||||
return o.as_json()
|
return o.as_json()
|
||||||
elif hasattr(o, 'json'):
|
elif hasattr(o, 'json'):
|
||||||
return o.json()
|
return o.json()
|
||||||
|
elif is_dataclass(o):
|
||||||
|
return asdict(o)
|
||||||
else:
|
else:
|
||||||
return o.__dict__
|
return o.__dict__
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def as_table(cls, obj: List[Any]) -> str:
|
def as_table(cls, obj: List[Any], class_formatter: Union[str, Callable] = None, filter_list: List[str] = None) -> str:
|
||||||
|
""" variant of as_table (subtly different code) which has two additional parameters
|
||||||
|
filter which is a list of fields which will be shon
|
||||||
|
class_formatter a special method to format the outgoing data
|
||||||
|
|
||||||
|
A general comment, the format selected for the output (a string where every data record is separated by newline)
|
||||||
|
is for compatibility with a print statement
|
||||||
|
As_table_filter can be a drop in replacement for as_table
|
||||||
|
"""
|
||||||
|
raw_data = [cls.values(o, class_formatter, filter_list) for o in obj]
|
||||||
|
# determine the maximum column size
|
||||||
column_width: Dict[str, int] = {}
|
column_width: Dict[str, int] = {}
|
||||||
for o in obj:
|
for o in raw_data:
|
||||||
for k, v in cls.values(o).items():
|
for k, v in o.items():
|
||||||
column_width.setdefault(k, 0)
|
if not filter_list or k in filter_list:
|
||||||
column_width[k] = max([column_width[k], len(str(v)), len(k)])
|
column_width.setdefault(k, 0)
|
||||||
|
column_width[k] = max([column_width[k], len(str(v)), len(k)])
|
||||||
|
|
||||||
|
if not filter_list:
|
||||||
|
filter_list = (column_width.keys())
|
||||||
|
# create the header lines
|
||||||
output = ''
|
output = ''
|
||||||
for key, width in column_width.items():
|
key_list = []
|
||||||
|
for key in filter_list:
|
||||||
|
width = column_width[key]
|
||||||
key = key.replace('!', '')
|
key = key.replace('!', '')
|
||||||
output += key.ljust(width) + ' | '
|
key_list.append(key.ljust(width))
|
||||||
|
output += ' | '.join(key_list) + '\n'
|
||||||
output = output[:-3] + '\n'
|
|
||||||
output += '-' * len(output) + '\n'
|
output += '-' * len(output) + '\n'
|
||||||
|
|
||||||
for o in obj:
|
# create the data lines
|
||||||
for k, v in cls.values(o).items():
|
for record in raw_data:
|
||||||
if '!' in k:
|
obj_data = []
|
||||||
v = '*' * len(str(v))
|
for key in filter_list:
|
||||||
output += str(v).ljust(column_width[k]) + ' | '
|
width = column_width.get(key, len(key))
|
||||||
output = output[:-3]
|
value = record.get(key, '')
|
||||||
output += '\n'
|
if '!' in key:
|
||||||
|
value = '*' * width
|
||||||
|
if isinstance(value,(int, float)) or (isinstance(value, str) and value.isnumeric()):
|
||||||
|
obj_data.append(str(value).rjust(width))
|
||||||
|
else:
|
||||||
|
obj_data.append(str(value).ljust(width))
|
||||||
|
output += ' | '.join(obj_data) + '\n'
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue