From 42fe14db2b1b7066255865ebce182e9ead575632 Mon Sep 17 00:00:00 2001 From: Cristi Libotean Date: Thu, 14 Sep 2017 15:00:31 +0300 Subject: [PATCH 1/5] Added ability to add separators as a row inside the table. Separators can be inserted by adding a single element list containing the SEPARATOR text; whenever a SEPARATOR is encountered a horizontal line will be written instead --- example2.py | 15 +++++++ terminaltables/__init__.py | 1 + terminaltables/base_table.py | 9 +++-- terminaltables/width_and_alignment.py | 6 +++ tests/test_base_table/test_table.py | 40 +++++++++++++++++++ .../test_max_dimensions.py | 13 +++++- .../test_table_width.py | 3 +- .../test_visible_width.py | 5 ++- 8 files changed, 85 insertions(+), 7 deletions(-) diff --git a/example2.py b/example2.py index 51644f88..e0b63818 100755 --- a/example2.py +++ b/example2.py @@ -9,6 +9,7 @@ from colorclass import Color, Windows from terminaltables import SingleTable +from terminaltables import SEPARATOR def table_server_timings(): @@ -60,6 +61,16 @@ def table_abcd(): return '\n'.join(combined) +def table_separators(): + table_data = [["X", "Y"]] + for x in range(0, 3): + for y in range(0, 5): + table_data.append([Color("{autoyellow}" + str(x) + "{/autoyellow}"), Color(str(y))]) + table_data.append([SEPARATOR]) + table_instance = SingleTable(table_data, "Separators") + return table_instance.table + + def main(): """Main function.""" Windows.enable(auto_colors=True, reset_atexit=True) # Does nothing if not on Windows. @@ -76,6 +87,10 @@ def main(): print(table_abcd()) print() + # Separators + print(table_separators()) + print() + # Instructions. table_instance = SingleTable([['Obey Obey Obey Obey']], 'Instructions') print(table_instance.table) diff --git a/terminaltables/__init__.py b/terminaltables/__init__.py index 6cea8138..9307dcce 100644 --- a/terminaltables/__init__.py +++ b/terminaltables/__init__.py @@ -11,6 +11,7 @@ from terminaltables.other_tables import DoubleTable # noqa from terminaltables.other_tables import SingleTable # noqa from terminaltables.other_tables import PorcelainTable # noqa +from terminaltables.width_and_alignment import SEPARATOR # noqa __author__ = '@Robpol86' __license__ = 'MIT' diff --git a/terminaltables/base_table.py b/terminaltables/base_table.py index 281d5a3d..86b14f93 100644 --- a/terminaltables/base_table.py +++ b/terminaltables/base_table.py @@ -1,7 +1,7 @@ """Base table class. Define just the bare minimum to build tables.""" from terminaltables.build import build_border, build_row, flatten -from terminaltables.width_and_alignment import align_and_pad_cell, max_dimensions +from terminaltables.width_and_alignment import align_and_pad_cell, max_dimensions, SEPARATOR class BaseTable(object): @@ -191,8 +191,9 @@ def gen_table(self, inner_widths, inner_heights, outer_widths): style = 'footing' else: style = 'row' - for line in self.gen_row_lines(row, style, inner_widths, inner_heights[i]): - yield line + if SEPARATOR not in row: + for line in self.gen_row_lines(row, style, inner_widths, inner_heights[i]): + yield line # If this is the last row then break. No separator needed. if i == last_row_index: break @@ -203,7 +204,7 @@ def gen_table(self, inner_widths, inner_heights, outer_widths): elif self.inner_footing_row_border and i == before_last_row_index: yield self.horizontal_border('footing', outer_widths) # Yield row separator. - elif self.inner_row_border: + elif self.inner_row_border or SEPARATOR in row: yield self.horizontal_border('row', outer_widths) # Yield bottom border. diff --git a/terminaltables/width_and_alignment.py b/terminaltables/width_and_alignment.py index 057e800f..0d205262 100644 --- a/terminaltables/width_and_alignment.py +++ b/terminaltables/width_and_alignment.py @@ -5,6 +5,8 @@ from terminaltables.terminal_io import terminal_size + +SEPARATOR = "" RE_COLOR_ANSI = re.compile(r'(\033\[[\d;]+m)') @@ -20,6 +22,10 @@ def visible_width(string): :return: String's width. :rtype: int """ + # separator has no width + if SEPARATOR in string: + return 0 + if '\033' in string: string = RE_COLOR_ANSI.sub('', string) diff --git a/tests/test_base_table/test_table.py b/tests/test_base_table/test_table.py index c5b5a89b..441a46f2 100644 --- a/tests/test_base_table/test_table.py +++ b/tests/test_base_table/test_table.py @@ -6,6 +6,7 @@ from termcolor import colored from terminaltables.base_table import BaseTable +from terminaltables.width_and_alignment import SEPARATOR def test_ascii(): @@ -32,6 +33,45 @@ def test_ascii(): assert actual == expected +def test_separators(): + """Test with SEPARATORs thrown in the mix.""" + table_data = [ + # vegetables + ['Name', 'Color', 'Type'], + ['Lettuce', 'green', 'vegetable'], + ['Potato', 'yellow', 'vegetable'], + ['Carrot', 'red', 'vegetable'], + # fruits + [SEPARATOR], + ['Tomato', 'red', 'fruit'], + ['Durian', 'yellow', 'fruit'], + # nuts + [SEPARATOR], + ['Avocado', 'green', 'nut'], + ['Wallnut', 'brown', 'nut'], + ] + + table = BaseTable(table_data) + actual = table.table + expected = ( + '+---------+--------+-----------+\n' + '| Name | Color | Type |\n' + '+---------+--------+-----------+\n' + '| Lettuce | green | vegetable |\n' + '| Potato | yellow | vegetable |\n' + '| Carrot | red | vegetable |\n' + '+---------+--------+-----------+\n' + '| Tomato | red | fruit |\n' + '| Durian | yellow | fruit |\n' + '+---------+--------+-----------+\n' + '| Avocado | green | nut |\n' + '| Wallnut | brown | nut |\n' + '+---------+--------+-----------+' + ) + + assert actual == expected + + def test_int(): """Test with integers instead of strings.""" table_data = [ diff --git a/tests/test_width_and_alignment/test_max_dimensions.py b/tests/test_width_and_alignment/test_max_dimensions.py index fc97883a..89af5dfa 100644 --- a/tests/test_width_and_alignment/test_max_dimensions.py +++ b/tests/test_width_and_alignment/test_max_dimensions.py @@ -6,7 +6,7 @@ from colorclass import Color from termcolor import colored -from terminaltables.width_and_alignment import max_dimensions +from terminaltables.width_and_alignment import max_dimensions, SEPARATOR @pytest.mark.parametrize('table_data,expected_w,expected_h', [ @@ -43,6 +43,17 @@ def test_single_line(): assert max_dimensions(table_data, 2, 2) == ([10, 5, 9], [1, 1, 1, 1, 1], [14, 9, 13], [1, 1, 1, 1, 1]) +def test_separator(): + """Test separator inside table""" + table_data = [ + ['Name', 'Color', 'Type'], + [SEPARATOR], + ['Avocado', 'green', 'nut'], + ] + + assert max_dimensions(table_data, 1, 1) == ([7, 5, 4], [1, 1, 1], [9, 7, 6], [1, 1, 1]) + + def test_multi_line(): """Test heights.""" table_data = [ diff --git a/tests/test_width_and_alignment/test_table_width.py b/tests/test_width_and_alignment/test_table_width.py index 58187896..0461e3f8 100644 --- a/tests/test_width_and_alignment/test_table_width.py +++ b/tests/test_width_and_alignment/test_table_width.py @@ -1,11 +1,12 @@ """Test function in module.""" -from terminaltables.width_and_alignment import max_dimensions, table_width +from terminaltables.width_and_alignment import max_dimensions, table_width, SEPARATOR def test_empty(): """Test with zero-length cells.""" assert table_width(max_dimensions([['']])[2], 0, 0) == 0 + assert table_width(max_dimensions([[SEPARATOR]])[2], 0, 0) == 0 assert table_width(max_dimensions([['', '', '']])[2], 0, 0) == 0 assert table_width(max_dimensions([['', '', ''], ['', '', '']])[2], 0, 0) == 0 diff --git a/tests/test_width_and_alignment/test_visible_width.py b/tests/test_width_and_alignment/test_visible_width.py index 79cebcb7..bf720985 100644 --- a/tests/test_width_and_alignment/test_visible_width.py +++ b/tests/test_width_and_alignment/test_visible_width.py @@ -6,7 +6,7 @@ from colorclass import Color from termcolor import colored -from terminaltables.width_and_alignment import visible_width +from terminaltables.width_and_alignment import visible_width, SEPARATOR @pytest.mark.parametrize('string,expected', [ @@ -18,6 +18,9 @@ ('معرب', 4), ('hello 世界', 10), + # separator + (SEPARATOR, 0), + # str+ansi ('\x1b[34mhello, world\x1b[39m', 12), ('\x1b[34m世界你好\x1b[39m', 8), From 04f85b1e018ba5d1ef323be95bd45657cd58f070 Mon Sep 17 00:00:00 2001 From: Cristi Libotean Date: Thu, 14 Sep 2017 16:12:03 +0300 Subject: [PATCH 2/5] Reworked condition --- terminaltables/base_table.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/terminaltables/base_table.py b/terminaltables/base_table.py index 86b14f93..bf6385c1 100644 --- a/terminaltables/base_table.py +++ b/terminaltables/base_table.py @@ -194,6 +194,8 @@ def gen_table(self, inner_widths, inner_heights, outer_widths): if SEPARATOR not in row: for line in self.gen_row_lines(row, style, inner_widths, inner_heights[i]): yield line + else: + yield self.horizontal_border('row', outer_widths) # If this is the last row then break. No separator needed. if i == last_row_index: break @@ -204,7 +206,7 @@ def gen_table(self, inner_widths, inner_heights, outer_widths): elif self.inner_footing_row_border and i == before_last_row_index: yield self.horizontal_border('footing', outer_widths) # Yield row separator. - elif self.inner_row_border or SEPARATOR in row: + elif self.inner_row_border: yield self.horizontal_border('row', outer_widths) # Yield bottom border. From e81deb721720864260e586510bce81225a25e613 Mon Sep 17 00:00:00 2001 From: Cristi Libotean Date: Thu, 14 Sep 2017 16:27:58 +0300 Subject: [PATCH 3/5] Fixed lint problems --- example2.py | 4 ++-- tests/test_width_and_alignment/test_max_dimensions.py | 2 +- tests/test_width_and_alignment/test_table_width.py | 2 +- tests/test_width_and_alignment/test_visible_width.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example2.py b/example2.py index e0b63818..9c497dbe 100755 --- a/example2.py +++ b/example2.py @@ -8,8 +8,7 @@ from colorclass import Color, Windows -from terminaltables import SingleTable -from terminaltables import SEPARATOR +from terminaltables import SEPARATOR, SingleTable def table_server_timings(): @@ -62,6 +61,7 @@ def table_abcd(): def table_separators(): + """Return table string to be printed, including separators""" table_data = [["X", "Y"]] for x in range(0, 3): for y in range(0, 5): diff --git a/tests/test_width_and_alignment/test_max_dimensions.py b/tests/test_width_and_alignment/test_max_dimensions.py index 89af5dfa..b1e7f5f6 100644 --- a/tests/test_width_and_alignment/test_max_dimensions.py +++ b/tests/test_width_and_alignment/test_max_dimensions.py @@ -44,7 +44,7 @@ def test_single_line(): def test_separator(): - """Test separator inside table""" + """Test separator inside table.""" table_data = [ ['Name', 'Color', 'Type'], [SEPARATOR], diff --git a/tests/test_width_and_alignment/test_table_width.py b/tests/test_width_and_alignment/test_table_width.py index 0461e3f8..9389dffe 100644 --- a/tests/test_width_and_alignment/test_table_width.py +++ b/tests/test_width_and_alignment/test_table_width.py @@ -1,6 +1,6 @@ """Test function in module.""" -from terminaltables.width_and_alignment import max_dimensions, table_width, SEPARATOR +from terminaltables.width_and_alignment import max_dimensions, SEPARATOR, table_width def test_empty(): diff --git a/tests/test_width_and_alignment/test_visible_width.py b/tests/test_width_and_alignment/test_visible_width.py index bf720985..147d9026 100644 --- a/tests/test_width_and_alignment/test_visible_width.py +++ b/tests/test_width_and_alignment/test_visible_width.py @@ -6,7 +6,7 @@ from colorclass import Color from termcolor import colored -from terminaltables.width_and_alignment import visible_width, SEPARATOR +from terminaltables.width_and_alignment import SEPARATOR, visible_width @pytest.mark.parametrize('string,expected', [ From 188088851ce7595cd0b1a5fd6bf31d7c8ee56312 Mon Sep 17 00:00:00 2001 From: Cristi Libotean Date: Thu, 14 Sep 2017 16:31:18 +0300 Subject: [PATCH 4/5] Undit the period fix by accident --- example2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example2.py b/example2.py index 9c497dbe..394bae31 100755 --- a/example2.py +++ b/example2.py @@ -61,7 +61,7 @@ def table_abcd(): def table_separators(): - """Return table string to be printed, including separators""" + """Return table string to be printed, including separators.""" table_data = [["X", "Y"]] for x in range(0, 3): for y in range(0, 5): From a3ad7f28fcf6db819ec0ee016167573241c17bfe Mon Sep 17 00:00:00 2001 From: Cristi Libotean Date: Thu, 14 Sep 2017 16:43:08 +0300 Subject: [PATCH 5/5] Reworked condition back again, too complex --- terminaltables/base_table.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/terminaltables/base_table.py b/terminaltables/base_table.py index bf6385c1..86b14f93 100644 --- a/terminaltables/base_table.py +++ b/terminaltables/base_table.py @@ -194,8 +194,6 @@ def gen_table(self, inner_widths, inner_heights, outer_widths): if SEPARATOR not in row: for line in self.gen_row_lines(row, style, inner_widths, inner_heights[i]): yield line - else: - yield self.horizontal_border('row', outer_widths) # If this is the last row then break. No separator needed. if i == last_row_index: break @@ -206,7 +204,7 @@ def gen_table(self, inner_widths, inner_heights, outer_widths): elif self.inner_footing_row_border and i == before_last_row_index: yield self.horizontal_border('footing', outer_widths) # Yield row separator. - elif self.inner_row_border: + elif self.inner_row_border or SEPARATOR in row: yield self.horizontal_border('row', outer_widths) # Yield bottom border.