| # 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 |