rewrite of the formatters system

This commit is contained in:
Romain Bignon 2012-04-03 22:40:18 +02:00
commit fc849995f4
22 changed files with 441 additions and 580 deletions

View file

@ -28,15 +28,18 @@ class CSVFormatter(IFormatter):
def __init__(self, field_separator=u';'):
IFormatter.__init__(self)
self.field_separator = field_separator
self.count = 0
self.started = False
def flush(self):
pass
self.started = False
def format_obj(self, obj, alias):
item = self.to_dict(obj)
def format_dict(self, item):
result = u''
if self.count == 0:
if not self.started:
result += self.field_separator.join(item.iterkeys()) + '\n'
self.count += 1
self.started = True
result += self.field_separator.join(unicode(v) for v in item.itervalues())
return result

View file

@ -47,7 +47,7 @@ else:
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
from weboob.capabilities.base import CapBaseObject, FieldNotFound
from weboob.capabilities.base import CapBaseObject
from weboob.tools.ordereddict import OrderedDict
from weboob.tools.application.console import ConsoleApplication
@ -78,10 +78,9 @@ class IFormatter(object):
BOLD = property(get_bold)
NC = property(get_nc)
def __init__(self, display_keys=True, display_header=True, return_only=False, outfile=sys.stdout):
def __init__(self, display_keys=True, display_header=True, outfile=sys.stdout):
self.display_keys = display_keys
self.display_header = display_header
self.return_only = return_only
self.interactive = False
self.print_lines = 0
self.termrows = 0
@ -94,7 +93,7 @@ class IFormatter(object):
else:
self.termrows = int(subprocess.Popen('stty size', shell=True, stdout=subprocess.PIPE).communicate()[0].split()[0])
def after_format(self, formatted):
def output(self, formatted):
if self.outfile != sys.stdout:
with open(self.outfile, "a+") as outfile:
outfile.write(formatted.encode('utf-8'))
@ -113,47 +112,45 @@ class IFormatter(object):
print line
self.print_lines += 1
def build_id(self, v, backend_name):
return u'%s@%s' % (unicode(v), backend_name)
def start_format(self, **kwargs):
pass
def flush(self):
raise NotImplementedError()
pass
def format(self, obj, selected_fields=None):
def format(self, obj, selected_fields=None, alias=None):
"""
Format an object to be human-readable.
An object has fields which can be selected.
If the object provides an iter_fields() method, the formatter will
call it. It can be used to specify the fields order.
@param obj [object] object to format
@param selected_fields [tuple] fields to display. If None, all fields are selected
@return a string of the formatted object
:param obj: object to format
:type obj: CapBaseObject
:param selected_fields: fields to display. If None, all fields are selected
:type selected_fields: tuple
:param alias: an alias to use instead of the object's ID
:type alias: unicode
"""
assert isinstance(obj, (dict, CapBaseObject, tuple)), 'Object is unexpected type "%r"' % obj
assert isinstance(obj, CapBaseObject), 'Object is unexpected type "%r"' % obj
if isinstance(obj, dict):
item = obj
elif isinstance(obj, tuple):
item = OrderedDict([(k, v) for k, v in obj])
else:
item = self.to_dict(obj, selected_fields)
if item is None:
return None
if selected_fields is not None and not '*' in selected_fields:
obj = obj.copy()
for name, value in obj.iter_fields():
if not name in selected_fields:
delattr(obj, name)
if self.MANDATORY_FIELDS:
missing_fields = set(self.MANDATORY_FIELDS) - set(item.keys())
missing_fields = set(self.MANDATORY_FIELDS) - set([name for name, value in obj.iter_fields()])
if missing_fields:
raise MandatoryFieldsNotFound(missing_fields)
formatted = self.format_dict(item=item)
formatted = self.format_obj(obj, alias)
if formatted:
self.after_format(formatted)
self.output(formatted)
return formatted
def format_dict(self, item):
def format_obj(self, obj, alias=None):
"""
Format an object to be human-readable.
Format a dict to be human-readable. The dict is already simplified
if user provides selected fields.
Called by format().
@ -164,31 +161,37 @@ class IFormatter(object):
"""
raise NotImplementedError()
def set_header(self, string):
if self.display_header:
print string.encode('utf-8')
def to_dict(self, obj, selected_fields=None):
def iter_select(d):
if selected_fields is None or '*' in selected_fields:
fields = d.iterkeys()
else:
fields = selected_fields
for key in fields:
try:
value = d[key]
except KeyError:
raise FieldNotFound(obj, key)
yield key, value
def to_dict(self, obj):
def iter_decorate(d):
for key, value in d:
if key == 'id' and obj.backend is not None:
value = self.build_id(value, obj.backend)
value = obj.fullid
yield key, value
fields_iterator = obj.iter_fields()
d = OrderedDict(iter_decorate(fields_iterator))
return OrderedDict((k, v) for k, v in iter_select(d))
return OrderedDict(iter_decorate(fields_iterator))
class PrettyFormatter(IFormatter):
def format_obj(self, obj, alias):
title = self.get_title(obj)
desc = self.get_description(obj)
if desc is None:
title = '%s%s%s' % (self.NC, title, self.BOLD)
if alias is not None:
result = u'%s* (%s) %s (%s)%s' % (self.BOLD, alias, title, obj.backend, self.NC)
else:
result = u'%s* (%s) %s%s' % (self.BOLD, obj.fullid, title, self.NC)
if desc is not None:
result += u'\n\t%s' % desc
return result
def get_title(self, obj):
raise NotImplementedError()
def get_description(self, obj):
return None

View file

@ -34,14 +34,12 @@ class MultilineFormatter(IFormatter):
def flush(self):
pass
def format_dict(self, item):
def format_obj(self, obj, alias):
item = self.to_dict(obj)
result = u'\n'.join(u'%s%s' % (
(u'%s%s' % (k, self.key_value_separator) if self.display_keys else ''), v)
for k, v in item.iteritems() if (v is not NotLoaded and v is not NotAvailable))
if len(item) > 1:
result += self.after_item
return result
def set_header(self, string):
if self.display_header:
print string.encode('utf-8')

View file

@ -30,10 +30,8 @@ class SimpleFormatter(IFormatter):
self.field_separator = field_separator
self.key_value_separator = key_value_separator
def flush(self):
pass
def format_dict(self, item):
def format_obj(self, obj, alias):
item = self.to_dict(obj)
return self.field_separator.join(u'%s%s' % (
(u'%s%s' % (k, self.key_value_separator) if self.display_keys else ''), v)
for k, v in item.iteritems())

View file

@ -31,18 +31,18 @@ __all__ = ['TableFormatter', 'HTMLTableFormatter']
class TableFormatter(IFormatter):
HTML = False
def __init__(self, display_keys=True, return_only=False):
IFormatter.__init__(self, display_keys=display_keys, return_only=return_only)
def __init__(self):
IFormatter.__init__(self)
self.queue = []
self.keys = None
self.header = None
def after_format(self, formatted):
if self.keys is None:
self.keys = formatted.keys()
self.queue.append(formatted.values())
def flush(self):
s = self.get_formatted_table()
if s is not None:
print s.encode('utf-8')
def get_formatted_table(self):
if len(self.queue) == 0:
return
@ -80,14 +80,14 @@ class TableFormatter(IFormatter):
self.queue = []
if self.return_only:
return s
else:
print s.encode('utf-8')
return s
def format_dict(self, item):
# format is done in self.flush() by prettytable
return item
def format_obj(self, obj, alias):
item = self.to_dict(obj)
if self.keys is None:
self.keys = item.keys()
self.queue.append(item.values())
def set_header(self, string):
self.header = string

View file

@ -43,11 +43,8 @@ class WebBrowser(gtk.Window):
class WebkitGtkFormatter(HTMLTableFormatter):
def __init__(self):
HTMLTableFormatter.__init__(self, return_only=True)
def flush(self):
table_string = HTMLTableFormatter.flush(self)
table_string = self.get_formatted_table()
js_filepaths = []
js_filepaths.append(get_javascript('jquery'))
js_filepaths.append(get_javascript('tablesorter'))