def prettyText(text,design): if isinstance(design,str): return terminal.AnsiText(text,[design]) elif isinstance(design,list): return terminal.AnsiText(text,design) else: return text
def testAnsiText(self): self.assertEqual('\033[0mhello world\033[0m', terminal.AnsiText('hello world')) self.assertEqual('\033[31mhello world\033[0m', terminal.AnsiText('hello world', ['red'])) self.assertEqual('\033[31;46mhello world', terminal.AnsiText( 'hello world', ['red', 'bg_cyan'], False))
def testFormattedTableColoredCells(self): t = texttable.TextTable() t.header = ('LSP', 'Name') t.Append((terminal.AnsiText('col1', ['yellow']), 'col2')) t.Append(('col1', 'col2')) self.failUnlessEqual( ' LSP Name \n' '============\n' ' \033[33mcol1\033[0m col2 \n' ' col1 col2 \n', t.FormattedTable())
def testFormattedTableColoredMultilineCells(self): t = texttable.TextTable() t.header = ('LSP', 'Name') t.Append((terminal.AnsiText('col1 boembabies', ['yellow']), 'col2')) t.Append(('col1', 'col2')) self.failUnlessEqual( ' LSP Name \n' '====================\n' ' \033[33mcol1 col2 \n' ' boembabies\033[0m \n' '--------------------\n' ' col1 col2 \n', t.FormattedTable(width=20))
def testSmallestColSize(self): t = texttable.TextTable() self.failUnlessEqual(1, t._SmallestColSize('a')) self.failUnlessEqual(2, t._SmallestColSize('a bb')) self.failUnlessEqual(4, t._SmallestColSize('a cccc bb')) self.failUnlessEqual(0, t._SmallestColSize('')) self.failUnlessEqual(1, t._SmallestColSize('a\tb')) self.failUnlessEqual(1, t._SmallestColSize('a\nb\tc')) self.failUnlessEqual(3, t._SmallestColSize('a\nbbb\n\nc')) # Check if _SmallestColSize is not influenced by ANSI colors. self.failUnlessEqual( 3, t._SmallestColSize('bbb ' + terminal.AnsiText('bb', ['red'])))
def testFormattedTableColoredHeaders(self): t = texttable.TextTable() t.header = (terminal.AnsiText('LSP', ['yellow']), 'Name') t.Append(('col1', 'col2')) t.Append(('col1', 'col2')) self.failUnlessEqual( ' \033[33mLSP\033[0m Name \n' '============\n' ' col1 col2 \n' ' col1 col2 \n', t.FormattedTable()) self.failUnlessEqual(' col1 col2 \n' ' col1 col2 \n', t.FormattedTable(display_header=False))
def FormattedTable(self, width=80, force_display=False, ml_delimiter=True, color=True, display_header=True, columns=None): """Returns whole table, with whitespace padding and row delimiters. Args: width: An int, the max width we want the table to fit in. force_display: A bool, if set to True will display table when the table can't be made to fit to the width. ml_delimiter: A bool, if set to False will not display the multi-line delimiter. color: A bool. If true, display any colours in row.colour. display_header: A bool. If true, display header. columns: A list of str, show only columns with these names. Returns: A string. The tabled output. Raises: TableError: Width too narrow to display table. """ def _FilteredCols(): """Returns list of column names to display.""" if not columns: return self._Header().values return [col for col in self._Header().values if col in columns] # Largest is the biggest data entry in a column. largest = {} # Smallest is the same as above but with linewrap i.e. largest unbroken # word in the data stream. smallest = {} # largest == smallest for a column with a single word of data. # Initialise largest and smallest for all columns. for key in _FilteredCols(): largest[key] = 0 smallest[key] = 0 # Find the largest and smallest values. # Include Title line in equation. # pylint: disable=E1103 for row in self._table: for key, value in row.items(): if key not in _FilteredCols(): continue # Convert lists into a string. if isinstance(value, list): value = ', '.join(value) value = terminal.StripAnsiText(value) largest[key] = max(len(value), largest[key]) smallest[key] = max(self._SmallestColSize(value), smallest[key]) # pylint: enable-msg=E1103 min_total_width = 0 multi_word = [] # Bump up the size of each column to include minimum pad. # Find all columns that can be wrapped (multi-line). # And the minimum width needed to display all columns (even if wrapped). for key in _FilteredCols(): # Each column is bracketed by a space on both sides. # So increase size required accordingly. largest[key] += 2 smallest[key] += 2 min_total_width += smallest[key] # If column contains data that 'could' be split over multiple lines. if largest[key] != smallest[key]: multi_word.append(key) # Check if we have enough space to display the table. if min_total_width > width and not force_display: raise TableError('Width too narrow to display table.') # We have some columns that may need wrapping over several lines. if multi_word: # Find how much space is left over for the wrapped columns to use. # Also find how much space we would need if they were not wrapped. # These are 'spare_width' and 'desired_width' respectively. desired_width = 0 spare_width = width - min_total_width for key in multi_word: spare_width += smallest[key] desired_width += largest[key] # Scale up the space we give each wrapped column. # Proportional to its size relative to 'desired_width' for all columns. # Rinse and repeat if we changed the wrap list in this iteration. # Once done we will have a list of columns that definitely need wrapping. done = False while not done: done = True for key in multi_word: # If we scale past the desired width for this particular column, # then give it its desired width and remove it from the wrapped list. if (largest[key] <= round((largest[key] / float(desired_width)) * spare_width)): smallest[key] = largest[key] multi_word.remove(key) spare_width -= smallest[key] desired_width -= largest[key] done = False # If we scale below the minimum width for this particular column, # then leave it at its minimum and remove it from the wrapped list. elif (smallest[key] >= round((largest[key] / float(desired_width)) * spare_width)): multi_word.remove(key) spare_width -= smallest[key] desired_width -= largest[key] done = False # Repeat the scaling algorithm with the final wrap list. # This time we assign the extra column space by increasing 'smallest'. for key in multi_word: smallest[key] = int(round((largest[key] / float(desired_width)) * spare_width)) total_width = 0 row_count = 0 result_dict = {} # Format the header lines and add to result_dict. # Find what the total width will be and use this for the ruled lines. # Find how many rows are needed for the most wrapped line (row_count). for key in _FilteredCols(): result_dict[key] = self._TextJustify(key, smallest[key]) if len(result_dict[key]) > row_count: row_count = len(result_dict[key]) total_width += smallest[key] # Store header in header_list, working down the wrapped rows. header_list = [] for row_idx in xrange(row_count): for key in _FilteredCols(): try: header_list.append(result_dict[key][row_idx]) except IndexError: # If no value than use whitespace of equal size. header_list.append(' '*smallest[key]) header_list.append('\n') # Format and store the body lines result_dict = {} body_list = [] # We separate multi line rows with a single line delimiter. prev_muli_line = False # Unless it is the first line in which there is already the header line. first_line = True for row in self: row_count = 0 for key, value in row.items(): if key not in _FilteredCols(): continue # Convert field contents to a string. if isinstance(value, list): value = ', '.join(value) # Store results in result_dict and take note of wrapped line count. result_dict[key] = self._TextJustify(value, smallest[key]) if len(result_dict[key]) > row_count: row_count = len(result_dict[key]) if row_count > 1: prev_muli_line = True # If current or prior line was multi-line then include delimiter. if not first_line and prev_muli_line and ml_delimiter: body_list.append('-'*total_width + '\n') if row_count == 1: # Our current line was not wrapped, so clear flag. prev_muli_line = False row_list = [] for row_idx in xrange(row_count): for key in _FilteredCols(): try: row_list.append(result_dict[key][row_idx]) except IndexError: # If no value than use whitespace of equal size. row_list.append(' '*smallest[key]) row_list.append('\n') if color and row.color is not None: body_list.append( terminal.AnsiText(''.join(row_list)[:-1], command_list=row.color)) body_list.append('\n') else: body_list.append(''.join(row_list)) first_line = False header = ''.join(header_list) + '='*total_width if color and self._Header().color is not None: header = terminal.AnsiText(header, command_list=self._Header().color) # Add double line delimiter between header and main body. if display_header: return '%s\n%s' % (header, ''.join(body_list)) return '%s' % ''.join(body_list)