blob: f91b1f063fbeccb699a9becbd470eff813689c19 [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
18from google.protobuf.message import Message
19from termcolor import colored
20
21_printfn = lambda l: sys.stdout.write(l + '\n')
22
23
24class TablePrinter(object):
25 """Simple tabular data printer utility. For usage, see bottom of file"""
26
27 def __init__(self):
28 self.max_field_lengths = {}
29 self.field_names = {}
30 self.cell_values = {}
31
32 def add_cell(self, row_number, field_key, field_name, value):
33 if not isinstance(value, str):
34 value = str(value)
35 self._add_field_type(field_key, field_name)
36 row = self.cell_values.setdefault(row_number, {})
37 row[field_key] = value
38 self._update_max_length(field_key, value)
39
Zsolt Haraszti85f12852016-12-24 08:30:58 -080040 def number_of_rows(self):
41 return len(self.cell_values)
42
Zsolt Haraszti80175202016-12-24 00:17:51 -080043 def print_table(self, header=None, printfn=_printfn, dividers=10):
44
45 if header is not None:
46 printfn(header)
47
48 field_keys = sorted(self.field_names.keys())
49
50 if not field_keys:
51 printfn('table empty')
52 return
53
54 def p_sep():
55 printfn('+' + '+'.join(
56 [(self.max_field_lengths[k] + 2) * '-'
57 for k in field_keys]) + '+')
58
59 p_sep()
60
61 printfn('| ' + ' | '.join(
62 '%%%ds' % self.max_field_lengths[k] % self.field_names[k]
63 for k in field_keys) + ' |')
64 p_sep()
65
66 for i in range(len(self.cell_values)):
67 row = self.cell_values[i]
68 printfn(colored('| ' + ' | '.join(
69 '%%%ds' % self.max_field_lengths[k] % row.get(k, '')
70 for k in field_keys
71 ) + ' |'))
72 if not ((i + 1) % dividers):
73 p_sep()
74
75 if (i + 1) % dividers:
76 p_sep()
77
78 def _update_max_length(self, field_key, string):
79 length = len(string)
80 if length > self.max_field_lengths.get(field_key, 0):
81 self.max_field_lengths[field_key] = length
82
83 def _add_field_type(self, field_key, field_name):
84 if field_key not in self.field_names:
85 self.field_names[field_key] = field_name
86 self._update_max_length(field_key, field_name)
Sergio Slobodrianb5ef3482017-03-17 16:56:16 -040087 else:
88 assert self.field_names[field_key] == field_name
Zsolt Haraszti80175202016-12-24 00:17:51 -080089
90
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -040091def print_pb_list_as_table(header, items, fields_to_omit=None,
Jonathan Hart7d4a23d2018-06-28 07:36:28 -070092 printfn=_printfn, dividers=10, show_nulls=False,
93 presfns={}):
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
khenaidooa00efaf2017-11-15 16:17:10 -0500100 def set_row(pd_dict, _row, field, value, t, prefix,
khenaidoo079a7762017-10-26 21:42:05 -0400101 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:
Jonathan Hart7d4a23d2018-06-28 07:36:28 -0700109 presentationfn = presfns[fname] if fname in presfns else lambda x: x
khenaidoo079a7762017-10-26 21:42:05 -0400110 t.add_cell(_row, number + field.number, fname,
Jonathan Hart7d4a23d2018-06-28 07:36:28 -0700111 presentationfn(pd_dict.get(field.name)))
khenaidoo079a7762017-10-26 21:42:05 -0400112
Zsolt Haraszti80175202016-12-24 00:17:51 -0800113 def add(_row, pb, prefix='', number=0):
114 d = pb2dict(pb)
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400115 if show_nulls:
116 fields = pb.DESCRIPTOR.fields
khenaidoo079a7762017-10-26 21:42:05 -0400117 for field in fields:
khenaidooa00efaf2017-11-15 16:17:10 -0500118 set_row(d,
119 _row,
khenaidoo079a7762017-10-26 21:42:05 -0400120 field,
khenaidoo079a7762017-10-26 21:42:05 -0400121 getattr(pb, field.name),
122 t,
123 prefix,
124 fields_to_omit,
125 number)
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400126 else:
khenaidoo079a7762017-10-26 21:42:05 -0400127 fields = pb.ListFields()
128 for (field, value) in fields:
khenaidooa00efaf2017-11-15 16:17:10 -0500129 set_row(d,
130 _row,
khenaidoo079a7762017-10-26 21:42:05 -0400131 field,
khenaidoo079a7762017-10-26 21:42:05 -0400132 value,
133 t,
134 prefix,
135 fields_to_omit,
136 number)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800137 add(row, obj)
138
Sergio Slobodrian901bf4e2017-03-17 12:54:39 -0400139 t.print_table(header, printfn, dividers)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800140
141
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400142def print_pb_as_table(header, pb, fields_to_omit={}, printfn=_printfn,
143 show_nulls=False):
khenaidooa00efaf2017-11-15 16:17:10 -0500144
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800145 from cli.utils import pb2dict
146
khenaidooa00efaf2017-11-15 16:17:10 -0500147 def is_repeated_item(msg):
148 return hasattr(msg, "extend")
149
khenaidoo079a7762017-10-26 21:42:05 -0400150 def set_cell(pb, field, value, t, prefix, fields_to_omit):
khenaidooa00efaf2017-11-15 16:17:10 -0500151 d = pb2dict(pb)
khenaidoo079a7762017-10-26 21:42:05 -0400152 fname = prefix + field.name
khenaidooa00efaf2017-11-15 16:17:10 -0500153
khenaidoo079a7762017-10-26 21:42:05 -0400154 if fname in fields_to_omit:
155 return
156 if isinstance(value, Message):
157 pr(value, fname + '.')
khenaidooa00efaf2017-11-15 16:17:10 -0500158 elif is_repeated_item(value): # handles any list
khenaidoo079a7762017-10-26 21:42:05 -0400159 row = t.number_of_rows()
160 t.add_cell(row, 0, 'field', fname)
khenaidooa00efaf2017-11-15 16:17:10 -0500161 t.add_cell(row, 1, 'value',
162 '{} item(s)'.format(len(d.get(field.name))))
khenaidoo079a7762017-10-26 21:42:05 -0400163 else:
164 row = t.number_of_rows()
165 t.add_cell(row, 0, 'field', fname)
khenaidooa00efaf2017-11-15 16:17:10 -0500166 t.add_cell(row, 1, 'value', value)
167
khenaidoo079a7762017-10-26 21:42:05 -0400168
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800169 t = TablePrinter()
170
171 def pr(_pb, prefix=''):
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400172 if show_nulls:
173 fields = _pb.DESCRIPTOR.fields
khenaidoo079a7762017-10-26 21:42:05 -0400174 for field in sorted(fields, key=lambda f: f.number):
175 set_cell(_pb,
176 field,
177 getattr(_pb, field.name),
178 t,
179 prefix,
180 fields_to_omit)
Sergio Slobodriana95f99b2017-03-21 10:22:47 -0400181 else:
khenaidoo079a7762017-10-26 21:42:05 -0400182 fields = _pb.ListFields()
183 for (field, value) in sorted(fields, key=lambda (f, v): f.number):
184 set_cell(_pb,
185 field,
186 value,
187 t,
188 prefix,
189 fields_to_omit)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800190
191 pr(pb)
192
193 t.print_table(header, printfn)
194
khenaidoo079a7762017-10-26 21:42:05 -0400195
Zsolt Haraszti80175202016-12-24 00:17:51 -0800196if __name__ == '__main__':
197 import random
khenaidoo079a7762017-10-26 21:42:05 -0400198
Zsolt Haraszti80175202016-12-24 00:17:51 -0800199 t = TablePrinter()
200 for row in range(10):
201 t.add_cell(row, 0, 'id', row + 100)
202 t.add_cell(row, 1, 'name', 'Joe Somebody')
203 t.add_cell(row, 2, 'ows', '${}'.format(random.randint(10, 100000)))
204 t.print_table()