blob: 9053594e3373d77c458c0ab0afc27af021eebfde [file] [log] [blame]
Zsolt Haraszti80175202016-12-24 00:17:51 -08001#
2# Copyright 2016 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16import sys
17
Zsolt Haraszti85f12852016-12-24 08:30:58 -080018from google.protobuf.internal.containers import RepeatedCompositeFieldContainer
Zsolt Haraszti80175202016-12-24 00:17:51 -080019from google.protobuf.message import Message
20from termcolor import colored
21
22_printfn = lambda l: sys.stdout.write(l + '\n')
23
24
25class TablePrinter(object):
26 """Simple tabular data printer utility. For usage, see bottom of file"""
27
28 def __init__(self):
29 self.max_field_lengths = {}
30 self.field_names = {}
31 self.cell_values = {}
32
33 def add_cell(self, row_number, field_key, field_name, value):
34 if not isinstance(value, str):
35 value = str(value)
36 self._add_field_type(field_key, field_name)
37 row = self.cell_values.setdefault(row_number, {})
38 row[field_key] = value
39 self._update_max_length(field_key, value)
40
Zsolt Haraszti85f12852016-12-24 08:30:58 -080041 def number_of_rows(self):
42 return len(self.cell_values)
43
Zsolt Haraszti80175202016-12-24 00:17:51 -080044 def print_table(self, header=None, printfn=_printfn, dividers=10):
45
46 if header is not None:
47 printfn(header)
48
49 field_keys = sorted(self.field_names.keys())
50
51 if not field_keys:
52 printfn('table empty')
53 return
54
55 def p_sep():
56 printfn('+' + '+'.join(
57 [(self.max_field_lengths[k] + 2) * '-'
58 for k in field_keys]) + '+')
59
60 p_sep()
61
62 printfn('| ' + ' | '.join(
63 '%%%ds' % self.max_field_lengths[k] % self.field_names[k]
64 for k in field_keys) + ' |')
65 p_sep()
66
67 for i in range(len(self.cell_values)):
68 row = self.cell_values[i]
69 printfn(colored('| ' + ' | '.join(
70 '%%%ds' % self.max_field_lengths[k] % row.get(k, '')
71 for k in field_keys
72 ) + ' |'))
73 if not ((i + 1) % dividers):
74 p_sep()
75
76 if (i + 1) % dividers:
77 p_sep()
78
79 def _update_max_length(self, field_key, string):
80 length = len(string)
81 if length > self.max_field_lengths.get(field_key, 0):
82 self.max_field_lengths[field_key] = length
83
84 def _add_field_type(self, field_key, field_name):
85 if field_key not in self.field_names:
86 self.field_names[field_key] = field_name
87 self._update_max_length(field_key, field_name)
Sergio Slobodrianb5ef3482017-03-17 16:56:16 -040088 else:
89 assert self.field_names[field_key] == field_name
Zsolt Haraszti80175202016-12-24 00:17:51 -080090
91
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -040092def print_pb_list_as_table(header, items, fields_to_omit=None,
Sergio Slobodriana95f99b2017-03-21 10:22:47 -040093 printfn=_printfn, dividers=10, show_nulls=False):
Zsolt Haraszti80175202016-12-24 00:17:51 -080094 from cli.utils import pb2dict
95
96 t = TablePrinter()
97 for row, obj in enumerate(items):
98 assert isinstance(obj, Message)
99
khenaidoo079a7762017-10-26 21:42:05 -0400100 def set_row(_row, field, field_name, value, t, prefix,
101 fields_to_omit, number):
102 fname = prefix + field.name
103 if fname in fields_to_omit:
104 return
105 if isinstance(value, Message):
106 add(_row, value, fname + '.',
107 100 * (number + field.number))
108 else:
109 t.add_cell(_row, number + field.number, fname,
110 field_name)
111
Zsolt Haraszti80175202016-12-24 00:17:51 -0800112 def add(_row, pb, prefix='', number=0):
113 d = pb2dict(pb)
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400114 if show_nulls:
115 fields = pb.DESCRIPTOR.fields
khenaidoo079a7762017-10-26 21:42:05 -0400116 for field in fields:
117 set_row(_row,
118 field,
119 d.get(field.name),
120 getattr(pb, field.name),
121 t,
122 prefix,
123 fields_to_omit,
124 number)
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400125 else:
khenaidoo079a7762017-10-26 21:42:05 -0400126 fields = pb.ListFields()
127 for (field, value) in fields:
128 set_row(_row,
129 field,
130 d.get(field.name),
131 value,
132 t,
133 prefix,
134 fields_to_omit,
135 number)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800136 add(row, obj)
137
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400138 t.print_table(header, printfn, dividers)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800139
140
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400141def print_pb_as_table(header, pb, fields_to_omit={}, printfn=_printfn,
142 show_nulls=False):
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800143 from cli.utils import pb2dict
144
khenaidoo079a7762017-10-26 21:42:05 -0400145 def set_cell(pb, field, value, t, prefix, fields_to_omit):
146 fname = prefix + field.name
147 if fname in fields_to_omit:
148 return
149 if isinstance(value, Message):
150 pr(value, fname + '.')
151 elif isinstance(value, RepeatedCompositeFieldContainer):
152 row = t.number_of_rows()
153 t.add_cell(row, 0, 'field', fname)
154 t.add_cell(row, 1, 'value', '{} item(s)'.format((field.name)))
155 else:
156 row = t.number_of_rows()
157 t.add_cell(row, 0, 'field', fname)
158 t.add_cell(row, 1, 'value', field.name)
159
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800160 t = TablePrinter()
161
162 def pr(_pb, prefix=''):
163 d = pb2dict(_pb)
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400164 if show_nulls:
165 fields = _pb.DESCRIPTOR.fields
khenaidoo079a7762017-10-26 21:42:05 -0400166 for field in sorted(fields, key=lambda f: f.number):
167 set_cell(_pb,
168 field,
169 getattr(_pb, field.name),
170 t,
171 prefix,
172 fields_to_omit)
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400173 else:
khenaidoo079a7762017-10-26 21:42:05 -0400174 fields = _pb.ListFields()
175 for (field, value) in sorted(fields, key=lambda (f, v): f.number):
176 set_cell(_pb,
177 field,
178 value,
179 t,
180 prefix,
181 fields_to_omit)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800182
183 pr(pb)
184
185 t.print_table(header, printfn)
186
khenaidoo079a7762017-10-26 21:42:05 -0400187
Zsolt Haraszti80175202016-12-24 00:17:51 -0800188if __name__ == '__main__':
189 import random
khenaidoo079a7762017-10-26 21:42:05 -0400190
Zsolt Haraszti80175202016-12-24 00:17:51 -0800191 t = TablePrinter()
192 for row in range(10):
193 t.add_cell(row, 0, 'id', row + 100)
194 t.add_cell(row, 1, 'name', 'Joe Somebody')
195 t.add_cell(row, 2, 'ows', '${}'.format(random.randint(10, 100000)))
196 t.print_table()