changeset 3121:040ca99e25fe

jp (common): various Table fixes: - renamed fromDict to more accurate fromListDict - fixed handling of None filter in fromListDict - fixes show_header when no header exist - escape headers when using namedtuple, so it won't fail
author Goffi <goffi@goffi.org>
date Sat, 25 Jan 2020 21:08:37 +0100
parents 0c29155ac68b
children 4486d72658b9
files sat_frontends/jp/cmd_event.py sat_frontends/jp/cmd_file.py sat_frontends/jp/common.py
diffstat 3 files changed, 20 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/sat_frontends/jp/cmd_event.py	Sat Jan 25 21:08:32 2020 +0100
+++ b/sat_frontends/jp/cmd_event.py	Sat Jan 25 21:08:37 2020 +0100
@@ -316,7 +316,7 @@
 
         show_table = OUTPUT_OPT_TABLE in self.args.output_opts
 
-        table = common.Table.fromDict(
+        table = common.Table.fromListDict(
             self.host,
             data,
             ("nick",)
--- a/sat_frontends/jp/cmd_file.py	Sat Jan 25 21:08:32 2020 +0100
+++ b/sat_frontends/jp/cmd_file.py	Sat Jan 25 21:08:37 2020 +0100
@@ -642,7 +642,7 @@
             show_header = True
             keys = ("name", "type", "size", "file_hash")
             headers = ("name", "type", "size", "hash")
-        table = common.Table.fromDict(
+        table = common.Table.fromListDict(
             self.host,
             files_data,
             keys=keys,
--- a/sat_frontends/jp/common.py	Sat Jan 25 21:08:32 2020 +0100
+++ b/sat_frontends/jp/common.py	Sat Jan 25 21:08:37 2020 +0100
@@ -24,6 +24,7 @@
 import tempfile
 import asyncio
 import shlex
+import re
 from pathlib import Path
 from sat_frontends.jp.constants import Const as C
 from sat.core.i18n import _
@@ -479,7 +480,8 @@
                 - RowData with all columns values
             if may also only use 1 argument, which will then be current col value.
             the callable must return a string
-            if it's unicode, it will be used with .format and must countain u'{}' which will be replaced with the string
+            if it's unicode, it will be used with .format and must countain u'{}' which
+            will be replaced with the string.
             if not None, must have same number of columns as data
         @param use_buffer(bool): if True, bufferise output instead of printing it directly
         """
@@ -495,7 +497,9 @@
 
         size = None
         if headers:
-            row_cls = namedtuple("RowData", headers)
+            # we use a namedtuple to make the value easily accessible from filters
+            headers_safe = [re.sub(r'[^a-zA-Z_]', '_', h) for h in headers]
+            row_cls = namedtuple("RowData", headers_safe)
         else:
             row_cls = tuple
 
@@ -512,8 +516,8 @@
                             col_value = filter_(value, row_cls(*row_data_list))
                         except TypeError:
                             col_value = filter_(value)
-                    # we count size without ANSI code as they will change length of the string
-                    # when it's mostly style/color changes.
+                    # we count size without ANSI code as they will change length of the
+                    # string when it's mostly style/color changes.
                     col_size = len(regex.ansiRemove(col_value))
                 else:
                     col_value = str(value)
@@ -557,11 +561,12 @@
                     raise e
 
     @classmethod
-    def fromDict(cls, host, data, keys=None, headers=None, filters=None, defaults=None):
-        """Prepare a table to display it
+    def fromListDict(
+        cls, host, data, keys=None, headers=None, filters=None, defaults=None):
+        """Create a table from a list of dictionaries
 
-        the whole data will be read and kept into memory,
-        to be printed
+        each dictionary is a row of the table, keys being columns names.
+        the whole data will be read and kept into memory, to be printed
         @param data(list[dict[unicode, unicode]]): data to create the table from
         @param keys(iterable[unicode], None): keys to get
             if None, all keys will be used
@@ -579,6 +584,8 @@
             keys = list(data[0].keys())
         if headers is None:
             headers = keys
+        if filters is None:
+            filters = {}
         filters = [filters.get(k) for k in keys]
         return cls(
             host, (cls.readDictValues(d, keys, defaults) for d in data), headers, filters
@@ -650,7 +657,8 @@
         @param show_borders(bool): True if borders need no be shown
         @param hide_cols(None, iterable(unicode)): columns which should not be displayed
         @param head_alignment(unicode): how to align headers, can be left, center or right
-        @param columns_alignment(unicode): how to align columns, can be left, center or right
+        @param columns_alignment(unicode): how to align columns, can be left, center or
+            right
         @param col_sep(unicode): separator betweens columns
         @param head_line(unicode): character to use to make line under head
         @param disp(callable, None): method to use to display the table
@@ -693,7 +701,7 @@
             )
 
         # headers
-        if show_header:
+        if show_header and self.headers is not None:
             self._disp(
                 left
                 + self._headers(head_sep, headers, sizes, head_alignment, head_style)