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
119
120
121
122
123
124
125
126
|
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import re
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
import sys
from codecs import open
from itertools import izip_longest
def get_widths(table, formats, padding):
columns = izip_longest(*table, fillvalue="")
return [max(len(format_entry(entry, format_string, padding))
for entry in column)
for column, format_string in zip(columns, formats)]
def add_widths(formats, widths, padding):
return [add_width(format_string, width - sum(padding))
for format_string, width in zip(formats, widths)]
def top_rule(widths, corners, hor):
return (corners[0] + corners[1].join(hor * width for width in widths)
+ corners[2])
def inner_rule(widths, corners, hor):
return (corners[3] + corners[4].join(hor * width for width in widths)
+ corners[5])
def bottom_rule(widths, corners, hor):
return (corners[6] + corners[7].join(hor * width for width in widths)
+ corners[8])
def format_entry(entry, format_string, padding):
format_string = "{0:" + format_string + "}"
return " " * padding[0] + format_string.format(entry) + " " * padding[1]
def format_row(row, formats, padding, ver):
return (ver + ver.join(format_entry(entry, format_string, padding)
for entry, format_string in zip(row, formats))
+ ver)
def add_width(format_string, width):
regexp = r",?(\.\d+)?(b|c|d|e|E|f|F|g|G|n|o|s|x|X|%)?"
match = re.match(regexp, format_string)
begin, end = match.span()
if end - begin > 0:
return format_string[:begin] + str(width) + format_string[begin:]
else:
return format_string + str(width)
def print_table(table, formats=None, padding=(1, 1), corners="┌┬┐├┼┤└┴┘",
header_corners="╒╤╕╞╪╡", header_hor="═", header_ver="│",
header=False, hor="─", ver="│"):
if not formats:
formats = [""] * len(table[-1])
elif type(formats) is unicode:
formats = [formats] * len(table[-1])
if len(corners) == 1:
corners = corners * 9
widths = get_widths(table, formats, padding)
formats = add_widths(formats, widths, padding)
if header:
print top_rule(widths, header_corners, header_hor)
print format_row(table[0], formats, padding, header_ver)
print inner_rule(widths, header_corners, header_hor)
table = table[1:]
else:
print top_rule(widths, corners, hor)
print ("\n" + inner_rule(widths, corners, hor)
+ "\n").join(format_row(row, formats, padding, ver)
for row in table)
print bottom_rule(widths, corners, hor)
def main():
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter,
description="Render tab separated data as \
a table.")
parser.add_argument("--hor", help="horizontal line character",
metavar="CHAR", default="─")
parser.add_argument("--ver", help="vertical line character",
metavar="CHAR", default="│")
parser.add_argument("--corners", help="corner characters", metavar="CHARS",
default="┌┬┐├┼┤└┴┘")
parser.add_argument("--padding", help="left and right horizontal padding \
lenghts", nargs=2, type=int, metavar="<n>",
default=[1, 1])
parser.add_argument("--format", help="format string for the table entries",
default="", dest="formats", metavar="FORMAT",
type=unicode)
parser.add_argument("--header", help="format first row as header",
action="store_true")
parser.add_argument("--hhor", help="horizontal line character \
for the header row", metavar="CHAR", dest="header_hor",
default="═")
parser.add_argument("--hver", help="vertical line character \
for the header row", metavar="CHAR", dest="header_ver",
default="│")
parser.add_argument("--hcorners", help="corner characters for \
the header row", metavar="CHARS",
dest="header_corners", default="╒╤╕╞╪╡")
parser.add_argument("file", help="file to render or - to read from STDIN",
nargs="?", default="-", metavar="FILE")
parser.add_argument("--version", "-v", action="version",
version="%(prog)s 0.1")
args = parser.parse_args()
if args.file == "-":
args.file = sys.stdin
else:
args.file = open(args.file, encoding="utf-8")
table = [line.strip().split("\t") for line in args.file.readlines()]
args = vars(args)
del args["file"]
print_table(table, **args)
if __name__ == "__main__":
main()
|