Mercurial > libervia-backend
comparison sat_frontends/jp/common.py @ 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 | d9f328374473 |
children | 9d0df638c8b4 |
comparison
equal
deleted
inserted
replaced
3120:0c29155ac68b | 3121:040ca99e25fe |
---|---|
22 import os.path | 22 import os.path |
23 import time | 23 import time |
24 import tempfile | 24 import tempfile |
25 import asyncio | 25 import asyncio |
26 import shlex | 26 import shlex |
27 import re | |
27 from pathlib import Path | 28 from pathlib import Path |
28 from sat_frontends.jp.constants import Const as C | 29 from sat_frontends.jp.constants import Const as C |
29 from sat.core.i18n import _ | 30 from sat.core.i18n import _ |
30 from sat.core import exceptions | 31 from sat.core import exceptions |
31 from sat.tools.common import regex | 32 from sat.tools.common import regex |
477 the callable will get 2 arguments: | 478 the callable will get 2 arguments: |
478 - current column value | 479 - current column value |
479 - RowData with all columns values | 480 - RowData with all columns values |
480 if may also only use 1 argument, which will then be current col value. | 481 if may also only use 1 argument, which will then be current col value. |
481 the callable must return a string | 482 the callable must return a string |
482 if it's unicode, it will be used with .format and must countain u'{}' which will be replaced with the string | 483 if it's unicode, it will be used with .format and must countain u'{}' which |
484 will be replaced with the string. | |
483 if not None, must have same number of columns as data | 485 if not None, must have same number of columns as data |
484 @param use_buffer(bool): if True, bufferise output instead of printing it directly | 486 @param use_buffer(bool): if True, bufferise output instead of printing it directly |
485 """ | 487 """ |
486 self.host = host | 488 self.host = host |
487 self._buffer = [] if use_buffer else None | 489 self._buffer = [] if use_buffer else None |
493 # rows countains one list per row with columns values | 495 # rows countains one list per row with columns values |
494 self.rows = [] | 496 self.rows = [] |
495 | 497 |
496 size = None | 498 size = None |
497 if headers: | 499 if headers: |
498 row_cls = namedtuple("RowData", headers) | 500 # we use a namedtuple to make the value easily accessible from filters |
501 headers_safe = [re.sub(r'[^a-zA-Z_]', '_', h) for h in headers] | |
502 row_cls = namedtuple("RowData", headers_safe) | |
499 else: | 503 else: |
500 row_cls = tuple | 504 row_cls = tuple |
501 | 505 |
502 for row_data in data: | 506 for row_data in data: |
503 new_row = [] | 507 new_row = [] |
510 else: | 514 else: |
511 try: | 515 try: |
512 col_value = filter_(value, row_cls(*row_data_list)) | 516 col_value = filter_(value, row_cls(*row_data_list)) |
513 except TypeError: | 517 except TypeError: |
514 col_value = filter_(value) | 518 col_value = filter_(value) |
515 # we count size without ANSI code as they will change length of the string | 519 # we count size without ANSI code as they will change length of the |
516 # when it's mostly style/color changes. | 520 # string when it's mostly style/color changes. |
517 col_size = len(regex.ansiRemove(col_value)) | 521 col_size = len(regex.ansiRemove(col_value)) |
518 else: | 522 else: |
519 col_value = str(value) | 523 col_value = str(value) |
520 col_size = len(col_value) | 524 col_size = len(col_value) |
521 new_row.append(col_value) | 525 new_row.append(col_value) |
555 yield default | 559 yield default |
556 else: | 560 else: |
557 raise e | 561 raise e |
558 | 562 |
559 @classmethod | 563 @classmethod |
560 def fromDict(cls, host, data, keys=None, headers=None, filters=None, defaults=None): | 564 def fromListDict( |
561 """Prepare a table to display it | 565 cls, host, data, keys=None, headers=None, filters=None, defaults=None): |
562 | 566 """Create a table from a list of dictionaries |
563 the whole data will be read and kept into memory, | 567 |
564 to be printed | 568 each dictionary is a row of the table, keys being columns names. |
569 the whole data will be read and kept into memory, to be printed | |
565 @param data(list[dict[unicode, unicode]]): data to create the table from | 570 @param data(list[dict[unicode, unicode]]): data to create the table from |
566 @param keys(iterable[unicode], None): keys to get | 571 @param keys(iterable[unicode], None): keys to get |
567 if None, all keys will be used | 572 if None, all keys will be used |
568 @param headers(iterable[unicode], None): name of the columns | 573 @param headers(iterable[unicode], None): name of the columns |
569 names must be in same order as keys | 574 names must be in same order as keys |
577 raise exceptions.DataError("You must specify keys order to used headers") | 582 raise exceptions.DataError("You must specify keys order to used headers") |
578 if keys is None: | 583 if keys is None: |
579 keys = list(data[0].keys()) | 584 keys = list(data[0].keys()) |
580 if headers is None: | 585 if headers is None: |
581 headers = keys | 586 headers = keys |
587 if filters is None: | |
588 filters = {} | |
582 filters = [filters.get(k) for k in keys] | 589 filters = [filters.get(k) for k in keys] |
583 return cls( | 590 return cls( |
584 host, (cls.readDictValues(d, keys, defaults) for d in data), headers, filters | 591 host, (cls.readDictValues(d, keys, defaults) for d in data), headers, filters |
585 ) | 592 ) |
586 | 593 |
648 | 655 |
649 @param show_header(bool): True if header need no be shown | 656 @param show_header(bool): True if header need no be shown |
650 @param show_borders(bool): True if borders need no be shown | 657 @param show_borders(bool): True if borders need no be shown |
651 @param hide_cols(None, iterable(unicode)): columns which should not be displayed | 658 @param hide_cols(None, iterable(unicode)): columns which should not be displayed |
652 @param head_alignment(unicode): how to align headers, can be left, center or right | 659 @param head_alignment(unicode): how to align headers, can be left, center or right |
653 @param columns_alignment(unicode): how to align columns, can be left, center or right | 660 @param columns_alignment(unicode): how to align columns, can be left, center or |
661 right | |
654 @param col_sep(unicode): separator betweens columns | 662 @param col_sep(unicode): separator betweens columns |
655 @param head_line(unicode): character to use to make line under head | 663 @param head_line(unicode): character to use to make line under head |
656 @param disp(callable, None): method to use to display the table | 664 @param disp(callable, None): method to use to display the table |
657 None to use self.host.disp | 665 None to use self.host.disp |
658 """ | 666 """ |
691 self._disp( | 699 self._disp( |
692 top_left + top_sep.join([top * size for size in sizes]) + top_right | 700 top_left + top_sep.join([top * size for size in sizes]) + top_right |
693 ) | 701 ) |
694 | 702 |
695 # headers | 703 # headers |
696 if show_header: | 704 if show_header and self.headers is not None: |
697 self._disp( | 705 self._disp( |
698 left | 706 left |
699 + self._headers(head_sep, headers, sizes, head_alignment, head_style) | 707 + self._headers(head_sep, headers, sizes, head_alignment, head_style) |
700 + right | 708 + right |
701 ) | 709 ) |