comparison frontends/src/jp/common.py @ 2345:c57bc0fe17d9

jp (common): added use_buffer argument in Table: when use_buffer is True, the Table is not printed but put in a buffer. A unicode string can then be computed when string property is used.
author Goffi <goffi@goffi.org>
date Wed, 23 Aug 2017 00:10:09 +0200
parents 78ffb9ce57a4
children 3c0a3fae1862
comparison
equal deleted inserted replaced
2344:78ffb9ce57a4 2345:c57bc0fe17d9
503 return pubsub_service, pubsub_node, pubsub_item, content_file_path, content_file_obj 503 return pubsub_service, pubsub_node, pubsub_item, content_file_path, content_file_obj
504 504
505 505
506 class Table(object): 506 class Table(object):
507 507
508 def __init__(self, host, data, headers=None, filters=None): 508 def __init__(self, host, data, headers=None, filters=None, use_buffer=False):
509 """ 509 """
510 @param data(list[list]): table data 510 @param data(list[list]): table data
511 all lines must have the same number of columns 511 all lines must have the same number of columns
512 @param headers(iterable[unicode], None): names/titles of the columns 512 @param headers(iterable[unicode], None): names/titles of the columns
513 if not None, must have same number of columns as data 513 if not None, must have same number of columns as data
514 @param filters(iterable[(callable, unicode)], None): values filters 514 @param filters(iterable[(callable, unicode)], None): values filters
515 the callable will get col value as argument and must return a string 515 the callable will get col value as argument and must return a string
516 if it's unicode, it will be used with .format and must countain u'{}' which will be replaced with the string 516 if it's unicode, it will be used with .format and must countain u'{}' which will be replaced with the string
517 if not None, must have same number of columns as data 517 if not None, must have same number of columns as data
518 @param use_buffer(bool): if True, bufferise output instead of printing it directly
518 """ 519 """
519 self.host = host 520 self.host = host
521 self._buffer = [] if use_buffer else None
520 # headers are columns names/titles, can be None 522 # headers are columns names/titles, can be None
521 self.headers = headers 523 self.headers = headers
522 # sizes fof columns without headers, 524 # sizes fof columns without headers,
523 # headers may be larger 525 # headers may be larger
524 self.sizes = [] 526 self.sizes = []
557 559
558 if not data and headers is not None: 560 if not data and headers is not None:
559 # the table is empty, we print headers at their lenght 561 # the table is empty, we print headers at their lenght
560 self.sizes = [len(h) for h in headers] 562 self.sizes = [len(h) for h in headers]
561 563
564 @property
565 def string(self):
566 if self._buffer is None:
567 raise exceptions.InternalError(u'buffer must be used to get a string')
568 return u'\n'.join(self._buffer)
569
562 @staticmethod 570 @staticmethod
563 def readDictValues(data, keys, defaults=None): 571 def readDictValues(data, keys, defaults=None):
564 if defaults is None: 572 if defaults is None:
565 defaults = {} 573 defaults = {}
566 for key in keys: 574 for key in keys:
623 if style: 631 if style:
624 args = style + [rendered] 632 args = style + [rendered]
625 rendered = A.color(*args) 633 rendered = A.color(*args)
626 headers.append(rendered) 634 headers.append(rendered)
627 return head_sep.join(headers) 635 return head_sep.join(headers)
636
637 def _disp(self, data):
638 """output data (can be either bufferised or printed)"""
639 if self._buffer is not None:
640 self._buffer.append(data)
641 else:
642 self.host.disp(data)
628 643
629 def display(self, 644 def display(self,
630 head_alignment = u'left', 645 head_alignment = u'left',
631 columns_alignment = u'left', 646 columns_alignment = u'left',
632 head_style = None, 647 head_style = None,
645 head_line_sep=u'┄┼┄', 660 head_line_sep=u'┄┼┄',
646 head_line_right=u'┤', 661 head_line_right=u'┤',
647 bottom_left=u'└', 662 bottom_left=u'└',
648 bottom=None, 663 bottom=None,
649 bottom_sep=u'─┴─', 664 bottom_sep=u'─┴─',
650 bottom_right=u'┘' 665 bottom_right=u'┘',
651 ): 666 ):
652 """Print the table 667 """Print the table
653 668
654 @param show_header(bool): True if header need no be shown 669 @param show_header(bool): True if header need no be shown
655 @param show_borders(bool): True if borders need no be shown 670 @param show_borders(bool): True if borders need no be shown
656 @param head_alignment(unicode): how to align headers, can be left, center or right 671 @param head_alignment(unicode): how to align headers, can be left, center or right
657 @param columns_alignment(unicode): how to align columns, can be left, center or right 672 @param columns_alignment(unicode): how to align columns, can be left, center or right
658 @param col_sep(unicode): separator betweens columns 673 @param col_sep(unicode): separator betweens columns
659 @param head_line(unicode): character to use to make line under head 674 @param head_line(unicode): character to use to make line under head
675 @param disp(callable, None): method to use to display the table
676 None to use self.host.disp
660 """ 677 """
661 col_sep_size = len(regex.ansiRemove(col_sep)) 678 col_sep_size = len(regex.ansiRemove(col_sep))
662 if right is None: 679 if right is None:
663 right = left 680 right = left
664 if top_sep is None: 681 if top_sep is None:
671 bottom_sep = col_sep_size * bottom 688 bottom_sep = col_sep_size * bottom
672 if not show_borders: 689 if not show_borders:
673 left = right = head_line_left = head_line_right = u'' 690 left = right = head_line_left = head_line_right = u''
674 # top border 691 # top border
675 if show_borders: 692 if show_borders:
676 self.host.disp( 693 self._disp(
677 top_left 694 top_left
678 + top_sep.join([top*size for size in self.sizes]) 695 + top_sep.join([top*size for size in self.sizes])
679 + top_right 696 + top_right
680 ) 697 )
681 698
682 # headers 699 # headers
683 if show_header: 700 if show_header:
684 self.host.disp( 701 self._disp(
685 left 702 left
686 + self._headers(head_sep, head_alignment, head_style) 703 + self._headers(head_sep, head_alignment, head_style)
687 + right 704 + right
688 ) 705 )
689 # header line 706 # header line
690 self.host.disp( 707 self._disp(
691 head_line_left 708 head_line_left
692 + head_line_sep.join([head_line*size for size in self.sizes]) 709 + head_line_sep.join([head_line*size for size in self.sizes])
693 + head_line_right 710 + head_line_right
694 ) 711 )
695 712
702 alignment = lambda idx, s: ansi_rjust(s, self.sizes[idx]) 719 alignment = lambda idx, s: ansi_rjust(s, self.sizes[idx])
703 else: 720 else:
704 raise exceptions.InternalError(u'bad columns alignment argument') 721 raise exceptions.InternalError(u'bad columns alignment argument')
705 722
706 for row in self.rows: 723 for row in self.rows:
707 self.host.disp(left + col_sep.join([alignment(idx,c) for idx,c in enumerate(row)]) + right) 724 self._disp(left + col_sep.join([alignment(idx,c) for idx,c in enumerate(row)]) + right)
708 725
709 if show_borders: 726 if show_borders:
710 # bottom border 727 # bottom border
711 self.host.disp( 728 self._disp(
712 bottom_left 729 bottom_left
713 + bottom_sep.join([bottom*size for size in self.sizes]) 730 + bottom_sep.join([bottom*size for size in self.sizes])
714 + bottom_right 731 + bottom_right
715 ) 732 )
733 # we return self so string can be used after display (table.display().string)
734 return self
716 735
717 def display_blank(self, **kwargs): 736 def display_blank(self, **kwargs):
718 """Display table without visible borders""" 737 """Display table without visible borders"""
719 kwargs_ = {'col_sep':u' ', 'head_line_sep':u' ', 'show_borders':False} 738 kwargs_ = {'col_sep':u' ', 'head_line_sep':u' ', 'show_borders':False}
720 kwargs_.update(kwargs) 739 kwargs_.update(kwargs)
721 self.display(self, 740 return self.display(self,
722 **kwargs_ 741 **kwargs_
723 ) 742 )