Structured writing to console, such as a table

Peter Otten __peter__ at web.de
Mon Sep 1 23:39:34 CEST 2003


Raaijmakers, Vincent (IndSys, GE Interlogix) wrote:

> Before I reinvent this wheel... please give me some tips, references, 
> examples...

I wrote the following some months ago, but never really finished it, so it's
not the kind of code you would want to publish on glossy paper. Anyway,
hoping that nobody is watching, I quote it below :-)
I've added two contrived examples only now to give you an idea how to use
it.

Peter

<code>

class StringCol(object):
    def __init__(self, caption, extract, format=str):
        self.caption = caption
        if callable(extract):
            self.extract = extract
        elif type(extract) == type(""):
            self.extract = lambda row: getattr(row, extract)
        else:
            assert type(extract) == type(1), "extract must be callable,
attribute name or column index"
            self.extract = lambda row: row[extract]
        self.format = format
    def init(self):
        self.width = len(self.caption)
    def add(self, row):
        s = self.format(self.extract(row))
        self.width = max(self.width, len(s))
    def formatValue(self, row):
        return self.format(self.extract(row)).ljust(self.width)
    def formatCaption(self):
        return self.caption.ljust(self.width)
    def formatTotal(self):
        return " ".ljust(self.width)
    def formatDash(self, char="-"):
        assert len(char) == 1, "only one char, please"
        return char * self.width
    def done(self):
        pass

class NumCol(StringCol):
    SUM = 1
    ACCUMULATE = 2
    def __init__(self, caption, extract, format=str, action=None):
        StringCol.__init__(self, caption, extract, format)
        self.action = action
        #print ">>>>>>>>>>>>", self.action
    def init(self):
        StringCol.init(self)
        self.total = 0
        self.value = 0
    def add(self, row):
        self.total += self.extract(row)
    def formatValue(self, row):
        if self.action == NumCol.ACCUMULATE:
            #print "hi"
            self.total += self.extract(row)
            value = self.total
        else:
            value = self.extract(row)
        return self.format(value).rjust(self.width)

    def formatCaption(self):
        return self.caption.rjust(self.width)
    def formatTotal(self):
        return self.format(self.total).rjust(self.width)
    def done(self):
        self.width = max(self.width, len(self.format(self.total)))
        if self.action == NumCol.ACCUMULATE:
            self.total = 0

def printTable(columnDefs, rows, seps=("| ", " | ", " |"), dest=None):
#def printTable(columnDefs, rows, seps=("", "   ", ""), dest=None):
    if type(seps) == type((None,)):
        #from otten.generic.struct import Struct
        class Struct:
            def __init__(self, **kwd):
                self.__dict__.update(kwd)
        seps = Struct(left=seps[0], mid=seps[1], right=seps[2])
    if dest is None:
        import sys
        dest = sys.stdout

    # dry-run to determine column widths
    for col in columnDefs:
        col.init()
    for row in rows:
        for col in columnDefs:
            col.add(row)
    for col in columnDefs:
        col.done()
    # end dry-run

    def formatValue(col):
        return col.formatValue(row)
    def formatTotal(col):
        return col.formatTotal()
    def formatCaption(col):
        return col.formatCaption()
    def formatDash(col):
        return col.formatDash()
    def printRow(fmt, seps=seps):
        dest.write(seps.left)
        continued = False
        for col in columnDefs:
            if continued:
                dest.write(seps.mid)
            else:
                continued = True
            dest.write(fmt(col))
        dest.write(seps.right)
        dest.write("\n")
    dashSeps = Struct(left="-" * len(seps.left), mid="-" * len(seps.mid),
right="-" * len(seps.right))
    printRow(formatCaption)
    printRow(formatDash, dashSeps)
    for row in rows:
        printRow(formatValue)
    printRow(formatDash, dashSeps)
    printRow(formatTotal)
    printRow(formatDash, dashSeps)
    #print "=" * width



if __name__ == "__main__":
    # list of rows
    table = [
        ["a", 1, 2, 3],
        ["bbbbb", 1000000, 2222222, 33],
    ]
    printTable(
        [StringCol("First", 0),
         NumCol("Second", 1),
         NumCol("Forth", 3)],
        table)

    # list of objects
    class Test:
        def __init__(self, n, a):
            self.name = n
            self.age = a

    table2 = [ Test("peter", 20), Test("john", 111), Test("sue", 30) ]
    print
    printTable(
        [StringCol("Name", "name"),
         NumCol("Age**2", lambda row: row.age*row.age, action=NumCol.SUM),
         NumCol("SigmaAge", "age", action=NumCol.ACCUMULATE),
         NumCol("Age", "age")
        ],
        table2)

</code>







More information about the Python-list mailing list