Structured writing to console, such as a table
Peter Otten
__peter__ at web.de
Mon Sep 1 17:39:34 EDT 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