blob: 74487ae5b6e37ab8a23cc5af92b917d473b1acc6 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
"""
Tabular formatting utilities.
"""
import os
from datetime import datetime
from prettytable import PrettyTable
from .env import logger
def print_data(columns, items, header_text,
column_formatters=None, col_max_width=None, defaults=None):
"""
Prints data in a tabular form.
:param columns: columns of the table, e.g. ``['id','name']``
:type columns: iterable of basestring
:param items: each element must have keys or attributes corresponding to the ``columns`` items,
e.g. ``[{'id':'123', 'name':'Pete'}]``
:type data: [{:obj:`basestring`: :obj:`basestring`}]
:param column_formatters: maps column name to formatter, a function that may manipulate the
string values printed for this column, e.g. ``{'created_at': timestamp_formatter}``
:type column_formatters: {:obj:`basestring`: :obj:`function`}
:param col_max_width: maximum width of table
:type col_max_width: int
:param defaults: default values for keys that don't exist in the data itself, e.g.
``{'serviceId':'123'}``
:type defaults: {:obj:`basestring`: :obj:`basestring`}
"""
if items is None:
items = []
elif not isinstance(items, list):
items = [items]
pretty_table = _generate(columns, data=items, column_formatters=column_formatters,
defaults=defaults)
if col_max_width:
pretty_table.max_width = col_max_width
_log(header_text, pretty_table)
def _log(title, table):
logger.info('{0}{1}{0}{2}{0}'.format(os.linesep, title, table))
def _generate(cols, data, column_formatters=None, defaults=None):
"""
Return a new PrettyTable instance representing the list.
:param cols: columns of the table, e.g. ``['id','name']``
:type cols: iterable of :obj:`basestring`
:param data: each element must have keys or attributes corresponding to the ``cols`` items,
e.g. ``[{'id':'123', 'name':'Pete'}]``
:type data: [{:obj:`basestring`: :obj:`basestring`}]
:param column_formatters: maps column name to formatter, a function that may manipulate the
string values printed for this column, e.g. ``{'created_at': timestamp_formatter}``
:type column_formatters: {:obj:`basestring`: :obj:`function`}
:param defaults: default values for keys that don't exist in the data itself, e.g.
``{'serviceId':'123'}``
:type defaults: {:obj:`basestring`: :obj:`basestring`}
"""
def get_values_per_column(column, row_data):
if hasattr(row_data, column) or (isinstance(row_data, dict) and column in row_data):
val = row_data[column] if isinstance(row_data, dict) else getattr(row_data, column)
if val and isinstance(val, list):
val = [str(element) for element in val]
val = ','.join(val)
elif val is None or isinstance(val, list):
# don't print `[]` or `None` (but do print `0`, `False`, etc.)
val = ''
if column in column_formatters:
# calling the user's column formatter to manipulate the value
val = column_formatters[column](val)
return val
else:
return defaults.get(column)
column_formatters = column_formatters or dict()
defaults = defaults or dict()
pretty_table = PrettyTable(list(cols))
for datum in data:
values_row = []
for col in cols:
values_row.append(get_values_per_column(col, datum))
pretty_table.add_row(values_row)
return pretty_table
def timestamp_formatter(value):
try:
datetime.strptime(value[:10], '%Y-%m-%d')
return value.replace('T', ' ').replace('Z', ' ')
except ValueError:
# not a timestamp
return value
def trim_formatter_generator(max_length):
def trim_formatter(value):
if len(value) >= max_length:
value = '{0}..'.format(value[:max_length - 2])
return value
return trim_formatter