This commit cleans up the python directory to ensure the adapters
and the cli runs properly.

Change-Id: Ic68a3ecd1f16a5af44296e3c020c808b185f4c18
diff --git a/python/cli/table.py b/python/cli/table.py
new file mode 100644
index 0000000..7e6a4d8
--- /dev/null
+++ b/python/cli/table.py
@@ -0,0 +1,204 @@
+#
+# Copyright 2016 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import sys
+
+from google.protobuf.message import Message
+from termcolor import colored
+
+_printfn = lambda l: sys.stdout.write(l + '\n')
+
+
+class TablePrinter(object):
+    """Simple tabular data printer utility. For usage, see bottom of file"""
+
+    def __init__(self):
+        self.max_field_lengths = {}
+        self.field_names = {}
+        self.cell_values = {}
+
+    def add_cell(self, row_number, field_key, field_name, value):
+        if not isinstance(value, str):
+            value = str(value)
+        self._add_field_type(field_key, field_name)
+        row = self.cell_values.setdefault(row_number, {})
+        row[field_key] = value
+        self._update_max_length(field_key, value)
+
+    def number_of_rows(self):
+        return len(self.cell_values)
+
+    def print_table(self, header=None, printfn=_printfn, dividers=10):
+
+        if header is not None:
+            printfn(header)
+
+        field_keys = sorted(self.field_names.keys())
+
+        if not field_keys:
+            printfn('table empty')
+            return
+
+        def p_sep():
+            printfn('+' + '+'.join(
+                [(self.max_field_lengths[k] + 2) * '-'
+                 for k in field_keys]) + '+')
+
+        p_sep()
+
+        printfn('| ' + ' | '.join(
+            '%%%ds' % self.max_field_lengths[k] % self.field_names[k]
+            for k in field_keys) + ' |')
+        p_sep()
+
+        for i in range(len(self.cell_values)):
+            row = self.cell_values[i]
+            printfn(colored('| ' + ' | '.join(
+                '%%%ds' % self.max_field_lengths[k] % row.get(k, '')
+                for k in field_keys
+            ) + ' |'))
+            if not ((i + 1) % dividers):
+                p_sep()
+
+        if (i + 1) % dividers:
+            p_sep()
+
+    def _update_max_length(self, field_key, string):
+        length = len(string)
+        if length > self.max_field_lengths.get(field_key, 0):
+            self.max_field_lengths[field_key] = length
+
+    def _add_field_type(self, field_key, field_name):
+        if field_key not in self.field_names:
+            self.field_names[field_key] = field_name
+            self._update_max_length(field_key, field_name)
+        else:
+            assert self.field_names[field_key] == field_name
+
+
+def print_pb_list_as_table(header, items, fields_to_omit=None,
+                           printfn=_printfn, dividers=10, show_nulls=False,
+                           presfns={}):
+    from utils import pb2dict
+
+    t = TablePrinter()
+    for row, obj in enumerate(items):
+        assert isinstance(obj, Message)
+
+        def set_row(pd_dict, _row, field, value, t, prefix,
+                      fields_to_omit, number):
+            fname = prefix + field.name
+            if fname in fields_to_omit:
+                return
+            if isinstance(value, Message):
+                add(_row, value, fname + '.',
+                    100 * (number + field.number))
+            else:
+                presentationfn = presfns[fname] if fname in presfns else lambda x: x
+                t.add_cell(_row, number + field.number, fname,
+                           presentationfn(pd_dict.get(field.name)))
+
+        def add(_row, pb, prefix='', number=0):
+            d = pb2dict(pb)
+            if show_nulls:
+                fields = pb.DESCRIPTOR.fields
+                for field in fields:
+                    set_row(d,
+                            _row,
+                            field,
+                            getattr(pb, field.name),
+                            t,
+                            prefix,
+                            fields_to_omit,
+                            number)
+            else:
+                fields = pb.ListFields()
+                for (field, value) in fields:
+                    set_row(d,
+                            _row,
+                            field,
+                            value,
+                            t,
+                            prefix,
+                            fields_to_omit,
+                            number)
+        add(row, obj)
+
+    t.print_table(header, printfn, dividers)
+
+
+def print_pb_as_table(header, pb, fields_to_omit={}, printfn=_printfn,
+                      show_nulls=False):
+
+    from utils import pb2dict
+
+    def is_repeated_item(msg):
+        return hasattr(msg, "extend")
+
+    def set_cell(pb, field, value, t, prefix, fields_to_omit):
+        d = pb2dict(pb)
+        fname = prefix + field.name
+
+        if fname in fields_to_omit:
+            return
+        if isinstance(value, Message):
+            pr(value, fname + '.')
+        elif is_repeated_item(value): # handles any list
+            row = t.number_of_rows()
+            t.add_cell(row, 0, 'field', fname)
+            t.add_cell(row, 1, 'value',
+                       '{} item(s)'.format(len(d.get(field.name))))
+        else:
+            row = t.number_of_rows()
+            t.add_cell(row, 0, 'field', fname)
+            t.add_cell(row, 1, 'value', value)
+
+
+    t = TablePrinter()
+
+    def pr(_pb, prefix=''):
+        if show_nulls:
+            fields = _pb.DESCRIPTOR.fields
+            for field in sorted(fields, key=lambda f: f.number):
+                set_cell(_pb,
+                        field,
+                        getattr(_pb, field.name),
+                        t,
+                        prefix,
+                        fields_to_omit)
+        else:
+            fields = _pb.ListFields()
+            for (field, value) in sorted(fields, key=lambda (f, v): f.number):
+                set_cell(_pb,
+                        field,
+                        value,
+                        t,
+                        prefix,
+                        fields_to_omit)
+
+    pr(pb)
+
+    t.print_table(header, printfn)
+
+
+if __name__ == '__main__':
+    import random
+
+    t = TablePrinter()
+    for row in range(10):
+        t.add_cell(row, 0, 'id', row + 100)
+        t.add_cell(row, 1, 'name', 'Joe Somebody')
+        t.add_cell(row, 2, 'ows', '${}'.format(random.randint(10, 100000)))
+    t.print_table()