Jiri Stransky 774fa137c8 Print functions take output file parameter
Functions print_dict and print_list take outfile parameter (file where
to print output). This indirection allows for testing without patching
sys.stdout (patching stdout can break debugging tools).

Change-Id: Id4b76c5b7d9a8509eb0c662b498855cf9b261a82
2013-10-16 13:54:48 +02:00

149 lines
5.5 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
import sys
import prettytable
def pretty_choice_list(l):
return ', '.join("'%s'" % i for i in l)
def print_list(objs, fields, formatters={}, custom_labels={}, sortby=0,
outfile=sys.stdout):
'''Prints a list of objects.
:param objs: list of objects to print
:param fields: list of attributes of the objects to print;
attributes beginning with '!' have a special meaning - they
should be used with custom field labels and formatters only,
and the formatter receives the whole object
:param formatters: dict of functions that perform pre-print
formatting of attributes (keys are strings from `fields`
parameter, values are functions that take one parameter - the
attribute)
:param custom_labels: dict of label overrides for fields (keys are
strings from `fields` parameter, values are custom labels -
headers of the table)
'''
field_labels = [custom_labels.get(f, f) for f in fields]
pt = prettytable.PrettyTable([f for f in field_labels],
caching=False, print_empty=False)
pt.align = 'l'
for o in objs:
row = []
for field in fields:
if field[0] == '!': # custom field
if field in formatters:
row.append(formatters[field](o))
else:
raise KeyError(
'Custom field "%s" needs a formatter.' % field)
else: # attribute-based field
if hasattr(o, field) and field in formatters:
row.append(formatters[field](getattr(o, field)))
else:
row.append(getattr(o, field, ''))
pt.add_row(row)
print(pt.get_string(sortby=field_labels[sortby]), file=outfile)
def print_dict(d, formatters={}, custom_labels={}, outfile=sys.stdout):
'''Prints a dict.
:param d: dict to print
:param formatters: dict of functions that perform pre-print
formatting of dict values (keys are keys from `d` parameter,
values are functions that take one parameter - the dict value
to format)
:param custom_labels: dict of label overrides for keys (keys are
keys from `d` parameter, values are custom labels)
'''
pt = prettytable.PrettyTable(['Property', 'Value'],
caching=False, print_empty=False)
pt.align = 'l'
for field in d.keys():
label = custom_labels.get(field, field)
if field in formatters:
pt.add_row([label, formatters[field](d[field])])
else:
pt.add_row([label, d[field]])
print(pt.get_string(sortby='Property'), file=outfile)
def attr_proxy(attr, formatter=lambda a: a, allow_undefined=True):
'''Creates a new formatter function. It will format an object for
output by printing it's attribute or running another formatter on
that attribute.
:param attr: name of the attribute to look for on an object
:param formatter: formatter to run on that attribute (if not given,
the attribute is returned as-is)
:param allow_undefined: if true, the created function will return
None if `attr` is not defined on the formatted object
'''
def formatter_proxy(obj):
try:
attr_value = getattr(obj, attr)
except AttributeError as e:
if allow_undefined:
return None
else:
raise e
return formatter(attr_value)
return formatter_proxy
def capacities_formatter(capacities):
'''Formats a list of capacities for output. Capacity is a dict
containing 'name', 'value' and 'unit' keys.
'''
sorted_capacities = sorted(capacities,
key=lambda c: c['name'])
return '\n'.join(['{0}: {1} {2}'.format(c['name'], c['value'], c['unit'])
for c in sorted_capacities])
def links_formatter(links):
'''Formats a list of links. Link is a dict that has 'href' and
'rel' keys.
'''
sorted_links = sorted(links, key=lambda l: l['rel'])
return '\n'.join(['{0}: {1}'.format(l['rel'], l['href'])
for l in sorted_links])
def resource_links_formatter(links):
'''Formats an array of resource links. Resource link is a dict
with keys 'id' and 'links'. Under 'links' key there is an array of
links. Link is a dict with 'href' and 'rel' keys. Currently we
expect only one link to be in the array, so we print the first
one. (We cannot fetch by 'rel', values in 'rel' are not used
consistently.)
'''
sorted_links = sorted(links, key=lambda l: l['id'])
return '\n'.join(['{0}: {1}'.format(l['id'], l['links'][0]['href'])
for l in sorted_links])
def resource_link_formatter(link):
'''Formats one resource link. See docs of
`resource_links_formatter` for more details.
'''
return resource_links_formatter([link])