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 functools import reduce
import operator
import re
import math

__docformat__ = "restructuredtext"

__all__ = ["indent", "wrap_always", "wrap_onspace", "wrap_onspace_strict"]


[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.0 * 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 label in indent([labels] + rows, hasHeader=True): print(label) # 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 label in o: print(label) # 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 | # ---------------------------------------------