00001
00002
00003
00004
00005
00006 import cStringIO,operator
00007 def indent(rows,hasHeader=False,headerChar='-',delim=' | ',justify='center',
00008 separateRows=False,prefix='',postfix='',wrapfunc=lambda x:x):
00009 """
00010 Indents a table by column.
00011 - rows: A sequence of sequences of items, one sequence per row.
00012 - hadHeader: True if the first row consists of the column's names.
00013 - headerChar: Character to be used for the row separator line
00014 (if hasHeader==True or separateRows==True).
00015 - delim: The column delimiter.
00016 - justify: Determines how are data justified in their column.
00017 Valid values are 'left','right','center'.
00018 - separateRows: True if rows are to be separated by a line of 'headerChar's.
00019 - prefix: A string prepended to each printed row.
00020 - postfix: A string appended to each printed row.
00021 - wrapfunc: A function f(text) for wrapping text; each element in the table is first wrapped by this function.
00022 """
00023
00024
00025 def rowWrapper(row):
00026 newRows=[wrapfunc(item).split('\n') for item in row]
00027
00028
00029
00030 return [[substr or '' for substr in item] for item in map(None,*newRows)]
00031
00032 logicalRows = [rowWrapper(row) for row in rows]
00033
00034 columns = map(None,*reduce(operator.add,logicalRows))
00035
00036 maxWidths = [max([len(str(item)) for item in column]) for column in columns]
00037 rowSeparator = headerChar * (len(prefix) + len(postfix) + sum(maxWidths) + len(delim)*(len(maxWidths)-1))
00038
00039 justify = {'center':str.center,'right':str.rjust,'left':str.ljust}[justify.lower()]
00040 output=cStringIO.StringIO()
00041 if separateRows: print >> output,rowSeparator
00042 for physicalRows in logicalRows:
00043 for row in physicalRows:
00044 print >> output, prefix+delim.join([justify(str(item),width) for (item,width) in zip(row,maxWidths)])+postfix
00045 if separateRows or hasHeader: print >> output, rowSeparator; hasHeader=False
00046 return output.getvalue()
00047
00048 if __name__ == '__main__':
00049 from wordWrappers import wrap_always,wrap_onspace,wrap_onspace_strict
00050 labels=('First Name','Last Name','Age','Position')
00051 data="""John,Smith,24,Software Engineer
00052 Mary,Brohowski,23,Sales Manager
00053 Aristidis,Papageorgopoulos,28,Senior Reseacher"""
00054 rows=[row.strip().split(',') for row in data.splitlines()]
00055 print rows
00056 print 'without wrapping function\n'
00057 print 'raw input: ',[labels]+rows
00058 print indent([labels]+rows,hasHeader=True)
00059 width=10
00060 for wrapper in (wrap_always,wrap_onspace,wrap_onspace_strict):
00061 print 'Wrapping function: %s(x,width=%d)\n'%(wrapper.__name__,width)
00062 print indent([labels]+rows,hasHeader=True,separateRows=True,prefix='| ',postfix=' |',wrapfunc=lambda x: wrapper(x,width))
00063
00064 lumidata=[\
00065 ('%-*s'%(8,'run'),'%-*s'%(8,'first'),'%-*s'%(8,'last'),'%-*s'%(10,'delivered'),'%-*s'%(10,'recorded'),'%-*s'%(20,'recorded\nmypathdfdafddafd')),\
00066 ['%d'%(132440),'%d'%(23),'%d'%(99),'%.2f'%(2.345),'%.2f'%(1.23),'%.2f'%(0.5678)],\
00067 ['%d'%(132442),'%d'%(1),'%d'%(20),'%.2f'%(2.345),'%.2f'%(1.23),'%.2f'%(0.5678)],\
00068 ['','%d'%(27),'%d'%(43),'%.2f'%(2.345),'%.2f'%(1.23),'%.2f'%(0.5678)]\
00069 ]
00070 lumiheader=[('%-*s'%(30,'Lumi Sections'),'%-*s'%(46,'Luminosity'))]
00071 headerwidth=46
00072 print indent(lumiheader,hasHeader=True,separateRows=False,prefix='| ',postfix='',wrapfunc=lambda x: wrap_always(x,headerwidth))
00073 lumifooter=[('%-*s'%(24,'189'),'%-*s'%(10,'17.89'),'%-*s'%(10,'16.1'),'%-*s'%(20,'3.47'))]
00074 width=20
00075 print indent(lumidata,hasHeader=True,separateRows=False,prefix='| ',postfix='',wrapfunc=lambda x: wrap_onspace_strict(x,width))
00076 print
00077 print indent(lumifooter,hasHeader=False,separateRows=True,prefix=' total: ',postfix='',delim=' | ',wrapfunc=lambda x: wrap_always(x,25))