From da3b7b5fea17e2635c2d5c8aff419f96b525f9fe Mon Sep 17 00:00:00 2001 From: Goffi Date: Sat, 25 Jan 2020 21:08:37 +0100 Subject: [PATCH] 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 --- sat_frontends/jp/cmd_event.py | 2 +- sat_frontends/jp/cmd_file.py | 2 +- sat_frontends/jp/common.py | 28 ++++++++++++++++++---------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/sat_frontends/jp/cmd_event.py b/sat_frontends/jp/cmd_event.py index c5c89543..54abf0c5 100644 --- a/sat_frontends/jp/cmd_event.py +++ b/sat_frontends/jp/cmd_event.py @@ -316,7 +316,7 @@ class InviteesList(base.CommandBase): show_table = OUTPUT_OPT_TABLE in self.args.output_opts - table = common.Table.fromDict( + table = common.Table.fromListDict( self.host, data, ("nick",) diff --git a/sat_frontends/jp/cmd_file.py b/sat_frontends/jp/cmd_file.py index 0e4ec0f9..3f841396 100644 --- a/sat_frontends/jp/cmd_file.py +++ b/sat_frontends/jp/cmd_file.py @@ -642,7 +642,7 @@ class ShareList(base.CommandBase): 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, diff --git a/sat_frontends/jp/common.py b/sat_frontends/jp/common.py index 951cfd66..bf61362e 100644 --- a/sat_frontends/jp/common.py +++ b/sat_frontends/jp/common.py @@ -24,6 +24,7 @@ import time 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 @@ class Table(object): - 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 @@ class Table(object): 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 @@ class Table(object): 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 @@ class Table(object): 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 @@ class Table(object): 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 @@ class Table(object): @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 @@ class Table(object): ) # 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)