Source code for taurus.core.util.tablepprint

#!/usr/bin/env python

#############################################################################
##
# This file is part of Taurus
##
# http://taurus-scada.org
##
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
##
# Taurus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
##
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
##
#############################################################################

"""Adapted from http://code.activestate.com/recipes/267662/"""
from __future__ import print_function
from future import standard_library
standard_library.install_aliases()
from builtins import zip
from builtins import str
from builtins import range
from functools import reduce
import operator
import re
import math

__docformat__ = "restructuredtext"


[docs]def indent(rows, hasHeader=False, headerChar='-', delim=' | ', justify='left', separateRows=False, prefix='', postfix='', wrapfunc=lambda x: x): """Indents a table by column. :param rows: A sequence of sequences of items, one sequence per row. :param hasHeader: True if the first row consists of the columns' names. :param headerChar: Character to be used for the row separator line (if hasHeader==True or separateRows==True). :param delim: The column delimiter. :param justify: Determines how are data justified in their column. Valid values are 'left','right' and 'center'. :param separateRows: True if rows are to be separated by a line of 'headerChar's. :param prefix: A string prepended to each printed row. :param postfix: A string appended to each printed row. :param wrapfunc: A function f(text) for wrapping text; each element in the table is first wrapped by this function. :return: a list of strings. One for each row of the table """ # closure for breaking logical rows to physical, using wrapfunc def rowWrapper(row): newRows = [wrapfunc(item).split('\n') for item in row] return [[substr or '' for substr in item] for item in list(*newRows)] # break each logical row into one or more physical ones logicalRows = [rowWrapper(row) for row in rows] # columns of physical rows columns = list(*reduce(operator.add, logicalRows)) # get the maximum of each column by the string length of its items maxWidths = [max([len(str(item)) for item in column]) for column in columns] if separateRows or hasHeader: rowSeparator = headerChar * (len(prefix) + len(postfix) + sum(maxWidths) + len(delim) * (len(maxWidths) - 1)) else: rowSeparator = "<ERR>" # select the appropriate justify method justify = {'center': str.center, 'right': str.rjust, 'left': str.ljust}[justify.lower()] output = [] if separateRows: output.append(rowSeparator) for physicalRows in logicalRows: for row in physicalRows: line = prefix line += delim.join([justify(str(item), width) for (item, width) in zip(row, maxWidths)]) line += postfix output.append(line) if separateRows or hasHeader: output.append(rowSeparator) hasHeader = False return output
# written by Mike Brown # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
[docs]def wrap_onspace(text, width): """A word-wrap function that preserves existing line breaks and most spaces in the text. Expects that existing line breaks are posix newlines (\\\\n). """ return reduce(lambda line, word, width=width: '%s%s%s' % (line, ' \n'[(len(line[line.rfind('\n') + 1:]) + len(word.split('\n', 1)[0] ) >= width)], word), text.split(' ') )
[docs]def wrap_onspace_strict(text, width): """Similar to wrap_onspace, but enforces the width constraint: words longer than width are split.""" wordRegex = re.compile(r'\S{' + str(width) + r',}') return wrap_onspace(wordRegex.sub(lambda m: wrap_always(m.group(), width), text), width)
[docs]def wrap_always(text, width): """A simple word-wrap function that wraps text on exactly width characters. It doesn't split the text in words.""" return '\n'.join([text[width * i:width * (i + 1)] for i in range(int(math.ceil(1. * len(text) / width)))])
if __name__ == '__main__': labels = ('First Name', 'Last Name', 'Age', 'Position') data = \ '''John,Smith,24,Software Engineer Mary,Brohowski,23,Sales Manager Aristidis,Papageorgopoulos,28,Senior Reseacher''' rows = [row.strip().split(',') for row in data.splitlines()] print('Without wrapping function\n') for l in indent([labels] + rows, hasHeader=True): print(l) # test indent with different wrapping functions width = 10 for wrapper in (wrap_always, wrap_onspace, wrap_onspace_strict): print('Wrapping function: %s(x,width=%d)\n' % (wrapper.__name__, width)) o = indent([labels] + rows, headerChar='=', hasHeader=True, separateRows=False, prefix='|', postfix='|', delim=' ', wrapfunc=lambda x: wrapper(x, width)) for l in o: print(l) # output: # # Without wrapping function # # First Name | Last Name | Age | Position #------------------------------------------------------- # John | Smith | 24 | Software Engineer # Mary | Brohowski | 23 | Sales Manager # Aristidis | Papageorgopoulos | 28 | Senior Reseacher # # Wrapping function: wrap_always(x,width=10) # #---------------------------------------------- #| First Name | Last Name | Age | Position | #---------------------------------------------- #| John | Smith | 24 | Software E | #| | | | ngineer | #---------------------------------------------- #| Mary | Brohowski | 23 | Sales Mana | #| | | | ger | #---------------------------------------------- #| Aristidis | Papageorgo | 28 | Senior Res | #| | poulos | | eacher | #---------------------------------------------- # # Wrapping function: wrap_onspace(x,width=10) # #--------------------------------------------------- #| First Name | Last Name | Age | Position | #--------------------------------------------------- #| John | Smith | 24 | Software | #| | | | Engineer | #--------------------------------------------------- #| Mary | Brohowski | 23 | Sales | #| | | | Manager | #--------------------------------------------------- #| Aristidis | Papageorgopoulos | 28 | Senior | #| | | | Reseacher | #--------------------------------------------------- # # Wrapping function: wrap_onspace_strict(x,width=10) # #--------------------------------------------- #| First Name | Last Name | Age | Position | #--------------------------------------------- #| John | Smith | 24 | Software | #| | | | Engineer | #--------------------------------------------- #| Mary | Brohowski | 23 | Sales | #| | | | Manager | #--------------------------------------------- #| Aristidis | Papageorgo | 28 | Senior | #| | poulos | | Reseacher | #---------------------------------------------