Sometime pprint module is not enough for formatting data for console or log file output. This module provide function which fill the gap.
Sample function call:
nums = [ '1', '2', '3', '4' ]
speeds = [ '100', '10000', '1500', '12' ]
desc = [ '', 'label 1', 'none', 'very long description' ]
lines = format_table( [(nums, ALIGN_RIGHT|PADDING_ALL, 'NUM'),
(speeds, ALIGN_RIGHT|PADDING_ALL, 'SPEED'),
(desc, ALIGN_LEFT|PADDING_ALL, 'DESC')] )
Output:
=======================================
| NUM | SPEED | DESC |
=======================================
| 1 | 100 | |
| 2 | 10000 | label 1 |
| 3 | 1500 | none |
| 4 | 12 | very long description |
=======================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | # -*- coding: Windows-1251 -*-
'''
texttable -- render text tables for console, log files etc
'''
__author__ = 'Denis Barmenkov <denis.barmenkov@gmail.com>'
__source__ = 'http://code.activestate.com/recipes/577202-render-tables-for-text-interface/'
import types
# Align center is not supported because of the terrible form :)
ALIGN_RIGHT = 0x0001
ALIGN_LEFT = 0x0002
PADDING_LEFT = 0x0010
PADDING_RIGHT = 0x0020
PADDING_ALL = PADDING_LEFT | PADDING_RIGHT
def _rpad_to_maxlen(slist, padchar=' '):
maxlen = max(map(len, slist))
res = map(lambda s: s + padchar * (maxlen - len(s)), slist)
return res
def _lpad_to_maxlen(slist, padchar=' '):
maxlen = max(map(len, slist))
res = map(lambda s: padchar * (maxlen - len(s)) + s, slist)
return res
def test_mask(mask, flag):
'''
tests mask for all bits of flag set
'''
return mask & flag == flag
def _align_para(para, mode):
if test_mask(mode, ALIGN_RIGHT):
para = _lpad_to_maxlen(para) # little confusing: right align == left padding
elif test_mask(mode, ALIGN_LEFT):
para = _rpad_to_maxlen(para)
else:
raise ValueError, "NO ALIGN SPECIFIED!"
if test_mask(mode, PADDING_LEFT):
para = map(lambda x: ' ' + x, para)
if test_mask(mode, PADDING_RIGHT):
para = map(lambda x: x + ' ', para)
return para
def _glue_cols(col1, col2):
return map(lambda x: '%s|%s' % (x[0], x[1]), zip(col1, col2))
def _has_column_headers(cols):
fail_count = 0
for c in cols:
try:
a = c[2]
except IndexError:
fail_count += 1
return fail_count == 0
def _join_to_list(*arguments):
'''
join all parameters to one list,
expanding lists and tuples
'''
res = list()
for arg in arguments:
if isinstance(arg, types.ListType):
res.extend(arg)
elif isinstance(arg, types.TupleType):
res.extend(list(arg))
else:
res.append(arg)
return res
def format_table(cols):
# 1. aligning data
if len(cols) == 0:
return list()
header_present = _has_column_headers(cols)
if header_present:
# prefix all data with headers // TODO: alignment set to center
cols = map(lambda x: [_join_to_list(x[2], x[0]), x[1] ], cols)
cols2 = map(lambda x: _align_para(x[0], x[1]), cols)
if len(cols2) == 0:
return list()
empty_vert_border = [ '' ] * len(cols2[0])
cols2.append(empty_vert_border)
cols2.insert(0, empty_vert_border)
glued_cols = reduce(_glue_cols, cols2)
if len(glued_cols) == 0:
return list()
border = '=' * len(glued_cols[0])
glued_cols.insert(0, border)
glued_cols.append(border)
if header_present:
glued_cols.insert(2, border) # insert delimiter berween header and values
return glued_cols
def demo():
nums = [ '1', '2', '3', '4' ]
speeds = [ '100', '10000', '1500', '12' ]
desc = [ '', 'label 1', 'none', 'very long description' ]
lines = format_table( [(nums, ALIGN_RIGHT|PADDING_ALL, 'NUM'),
(speeds, ALIGN_RIGHT|PADDING_ALL, 'SPEED'),
(desc, ALIGN_LEFT|PADDING_ALL, 'DESC')] )
print '\n'.join(lines)
if __name__ == '__main__':
demo()
|
How about this one?
Cheaper and much more clearer version, thank you!
But: padding functionality throw out yield statements are too complex (or unavailable) for old Python versions :)
and this one?
Improved version of Metal's code:
Result example:
Further refined for readability, consolidate to one class, and to avoid subclassing list
I had put up this one http://code.activestate.com/recipes/578105-output-data-in-tabular-form/