-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtable.py
More file actions
121 lines (103 loc) · 2.72 KB
/
table.py
File metadata and controls
121 lines (103 loc) · 2.72 KB
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
from typing import Union
class Table:
"""
Displays data in a table format
"""
def __init__(self, columns: Union[list, None] = None):
"""
Initialize the table with the columns to display
:param columns:
"""
self.header = columns
"""
List of table headers to render, or None to omit
"""
self.align = []
"""
Alignment for each column, l = left, c = center, r = right
eg: if a table has 3 columns and the first and last should be right aligned:
table.align = ['r', 'l', 'r']
"""
self.data = []
"""
List of text data to display, add more with `add()`
"""
self.borders = True
"""
Set to False to disable borders ("|") around the table
"""
def _text_width(self, string: str) -> int:
"""
Get the visual width of a string, taking into account extended ASCII characters
:param string:
:return:
"""
width = 0
for char in string:
if ord(char) > 127:
width += 2
else:
width += 1
return width
def add(self, row: list):
self.data.append(row)
def render(self):
"""
Render the table with the given list of services
:param services: Services[]
:return:
"""
rows = []
col_lengths = []
if self.header is not None:
row = []
for col in self.header:
col_lengths.append(self._text_width(col))
row.append(col)
rows.append(row)
else:
col_lengths = [0] * len(self.data[0])
if self.borders and self.header is not None:
rows.append(['-BORDER-'] * len(self.header))
for row_data in self.data:
row = []
for i in range(len(row_data)):
val = str(row_data[i])
row.append(val)
col_lengths[i] = max(col_lengths[i], self._text_width(val))
rows.append(row)
for row in rows:
vals = []
is_border = False
if self.borders and self.header and row[0] == '-BORDER-':
is_border = True
for i in range(len(row)):
if i < len(self.align):
align = self.align[i] if self.align[i] != '' else 'l'
else:
align = 'l'
# Adjust the width of the total column width by the difference of icons within the text
# This is required because icons are 2-characters in visual width.
if is_border:
width = col_lengths[i]
if align == 'r':
vals.append(' %s:' % ('-' * width,))
elif align == 'c':
vals.append(':%s:' % ('-' * width,))
else:
vals.append(' %s ' % ('-' * width,))
else:
width = col_lengths[i] - (self._text_width(row[i]) - len(row[i]))
if align == 'r':
vals.append(row[i].rjust(width))
elif align == 'c':
vals.append(row[i].center(width))
else:
vals.append(row[i].ljust(width))
if self.borders:
if is_border:
print('|%s|' % '|'.join(vals))
else:
print('| %s |' % ' | '.join(vals))
else:
print(' %s' % ' '.join(vals))