Changes to the table management functions yet again to change the
implementation to a more elegant solution that won't fail when devices
are disabled. The omission of null fields is also no longer required
since the table printing now provides a choice on whether null fields
are shown or not. Null fields are fields that = 0/empty/False.

Change-Id: Ib3576f25d14143c160eb066dd954d6f84f84b358
diff --git a/cli/device.py b/cli/device.py
index d503c48..37513df 100644
--- a/cli/device.py
+++ b/cli/device.py
@@ -75,28 +75,13 @@
 
     def do_show(self, line):
         """Show detailed device information"""
-        omit_fields = {
-            'pm_configs',
-            'flows',
-            'flow_groups',
-            'ports',
-            'parent_port_no',
-            'reason',
-            'vlan',
-            'parent_id',
-            'root',
-            'type',
-            'vendor',
-            'id'
-        }
         print_pb_as_table('Device {}'.format(self.device_id),
-                          self.get_device(depth=-1), omit_fields)
+                          self.get_device(depth=-1))
 
     def do_ports(self, line):
         """Show ports of device"""
         device = self.get_device(depth=-1)
         omit_fields = {
-            'peers'
         }
         print_pb_list_as_table('Device ports:', device.ports,
                                omit_fields, self.poutput)
@@ -249,7 +234,7 @@
 
         omit_fields = {'groups', 'metrics', 'id'}
         print_pb_as_table('PM Config:', self.pm_config_last, omit_fields,
-                          self.poutput)
+                          self.poutput,show_nulls=True)
         if self.pm_config_last.grouped:
             #self.poutput("Supported metric groups:")
             for g in self.pm_config_last.groups:
@@ -257,7 +242,8 @@
                     omit_fields = {'metrics'}
                 else:
                     omit_fields = {'group_freq','metrics'}
-                print_pb_as_table('', g, omit_fields, self.poutput) 
+                print_pb_as_table('', g, omit_fields, self.poutput,
+                                  show_nulls=True)
                 if g.enabled:
                     state = 'enabled'
                 else:
@@ -265,7 +251,7 @@
                 print_pb_list_as_table(
                     'Metric group {} is {}'.format(g.name,state),
                     g.metrics, {'enabled', 'sample_freq'}, self.poutput,
-                    dividers=100)
+                    dividers=100, show_nulls=True)
         else:
             if self.pm_config_last.freq_override:
                 omit_fields = {}
diff --git a/cli/logical_device.py b/cli/logical_device.py
index 9efd6ae..f3a3f7e 100644
--- a/cli/logical_device.py
+++ b/cli/logical_device.py
@@ -63,24 +63,8 @@
 
     def do_show(self, _):
         """Show detailed logical device information"""
-        omit_fields = {
-            'flow_groups',
-            'flows',
-            'ports',
-            'switch_features.auxiliary_id',
-            'switch_features.capabilities',
-            'switch_features.datapath_id',
-            'switch_features.n_buffers',
-            'switch_features.n_tables',
-            'desc.dp_desc',
-            'desc.hw_desc',
-            'desc.mfr_desc',
-            'desc.serial_num',
-            'desc.sw_desc',
-            'datapath_id'
-        }
         print_pb_as_table('Logical device {}'.format(self.logical_device_id),
-                          self.get_logical_device(depth=-1), omit_fields)
+                          self.get_logical_device(depth=-1))
 
     def do_ports(self, _):
         """Show ports of logical device"""
@@ -88,9 +72,7 @@
         omit_fields = {
             'ofp_port.advertised',
             'ofp_port.peer',
-            'ofp_port.max_speed',
-            'ofp_port.supported',
-            'ofp_port.config'
+            'ofp_port.max_speed'
         }
         print_pb_list_as_table('Logical device ports:', device.ports,
                                omit_fields, self.poutput)
@@ -121,13 +103,7 @@
             'hardware_version',
             'software_version',
             'firmware_version',
-            'serial_number',
-            'parent_port_no',
-            'vlan',
-            'ports',
-            'reason',
-            'root',
-            'parent_id'
+            'serial_number'
         }
         print_pb_list_as_table('Devices:', devices, omit_fields, self.poutput)
 
diff --git a/cli/main.py b/cli/main.py
index c31000c..ec84bf5 100755
--- a/cli/main.py
+++ b/cli/main.py
@@ -176,13 +176,7 @@
             'hardware_version',
             'software_version',
             'firmware_version',
-            'serial_number',
-            'parent_port_no',
-            'vlan',
-            'ports',
-            'reason',
-            'root',
-            'parent_id'
+            'serial_number'
         }
         print_pb_list_as_table('Devices:', devices, omit_fields, self.poutput)
 
@@ -196,13 +190,7 @@
             'desc.sw_desc',
             'desc.dp_desc',
             'desc.serial_number',
-            'desc.serial_num',
-            'switch_features.n_buffers',
-            'switch_features.n_tables',
-            'switch_features.auxiliary_id',
-            'switch_features.datapath_id',
-            'switch_features.capabilities',
-            'ports'
+            'switch_features.capabilities'
         }
         print_pb_list_as_table('Logical devices:', res.items, omit_fields,
                                self.poutput)
diff --git a/cli/table.py b/cli/table.py
index 6db53bc..c3cf94d 100644
--- a/cli/table.py
+++ b/cli/table.py
@@ -90,7 +90,7 @@
 
 
 def print_pb_list_as_table(header, items, fields_to_omit=None,
-                           printfn=_printfn, dividers=10):
+                           printfn=_printfn, dividers=10, show_nulls=False):
     from cli.utils import pb2dict
 
     t = TablePrinter()
@@ -99,59 +99,44 @@
 
         def add(_row, pb, prefix='', number=0):
             d = pb2dict(pb)
-            l=[]
-            for field in sorted(pb._fields, key=lambda f: f.number):
-                l.append(field.name)
-            for field in d:
-                if field not in l:
-                    l.append(field)
-
-            field_number = 0
-            #for field in pb._fields:
-            for field in sorted(d, key=lambda f: l.index(f)):
-                #fname = prefix + field.name
-                fname = prefix + field
+            if show_nulls:
+                fields = pb.DESCRIPTOR.fields
+            else:
+                fields = pb._fields
+            for field in fields:
+                fname = prefix + field.name
                 if fname in fields_to_omit:
                     continue
-                #value = getattr(pb, field.name)
-                value = getattr(pb, field)
+                value = getattr(pb, field.name)
                 if isinstance(value, Message):
                     add(_row, value, fname + '.',
-                        100 * (number + field_number))
-                        #100 * (number + field.number))
+                        100 * (number + field.number))
                 else:
-                    t.add_cell(_row, number + field_number, fname,
-                               d.get(field))
-                    #t.add_cell(_row, number + field.number, fname,
-                    #           d.get(field.name))
-                field_number += 1
+                    t.add_cell(_row, number + field.number, fname,
+                               d.get(field.name))
 
         add(row, obj)
 
     t.print_table(header, printfn, dividers)
 
 
-def print_pb_as_table(header, pb, fields_to_omit={}, printfn=_printfn):
+def print_pb_as_table(header, pb, fields_to_omit={}, printfn=_printfn,
+                      show_nulls=False):
     from cli.utils import pb2dict
 
     t = TablePrinter()
 
     def pr(_pb, prefix=''):
         d = pb2dict(_pb)
-        l=[]
-        for field in sorted(pb._fields, key=lambda f: f.number):
-            l.append(field.name)
-        for field in d:
-            if field not in l:
-                l.append(field)
-        #for field in sorted(_pb._fields, key=lambda f: f.number):
-        for field in sorted(d, key=lambda f: l.index(f)):
-            #fname = prefix + field.name
-            fname = prefix + field
+        if show_nulls:
+            fields = _pb.DESCRIPTOR.fields
+        else:
+            fields = _pb._fields
+        for field in sorted(fields, key=lambda f: f.number):
+            fname = prefix + field.name
             if fname in fields_to_omit:
                 continue
-            #value = getattr(_pb, field.name)
-            value = getattr(_pb, field)
+            value = getattr(_pb, field.name)
             if isinstance(value, Message):
                 pr(value, fname + '.')
             elif isinstance(value, RepeatedCompositeFieldContainer):
@@ -162,8 +147,7 @@
             else:
                 row = t.number_of_rows()
                 t.add_cell(row, 0, 'field', fname)
-                #t.add_cell(row, 1, 'value', d.get(field.name))
-                t.add_cell(row, 1, 'value', d.get(field))
+                t.add_cell(row, 1, 'value', d.get(field.name))
 
     pr(pb)