diff --git a/CHANGELOG b/CHANGELOG index 5e5e54d..bc1383d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ Changelog ========= +TBD +--- + +* Output as generator + Version 0.2.3 ------------- diff --git a/cli_helpers/tabular_output/delimited_output_adapter.py b/cli_helpers/tabular_output/delimited_output_adapter.py index cff05c2..2f28e66 100644 --- a/cli_helpers/tabular_output/delimited_output_adapter.py +++ b/cli_helpers/tabular_output/delimited_output_adapter.py @@ -12,11 +12,21 @@ preprocessors = (override_missing_value, bytes_to_string) +class linewriter(object): + def __init__(self): + self.reset() + + def reset(self): + self.line = None + + def write(self, d): + self.line = d + + def adapter(data, headers, table_format='csv', **kwargs): """Wrap the formatting inside a function for TabularOutputFormatter.""" keys = ('dialect', 'delimiter', 'doublequote', 'escapechar', - 'lineterminator', 'quotechar', 'quoting', 'skipinitialspace', - 'strict') + 'quotechar', 'quoting', 'skipinitialspace', 'strict') if table_format == 'csv': delimiter = ',' elif table_format == 'tsv': @@ -24,13 +34,15 @@ def adapter(data, headers, table_format='csv', **kwargs): else: raise ValueError('Invalid table_format specified.') - ckwargs = {'delimiter': delimiter} + ckwargs = {'delimiter': delimiter, 'lineterminator': ''} ckwargs.update(filter_dict_by_key(kwargs, keys)) - with contextlib.closing(StringIO()) as content: - writer = csv.writer(content, **ckwargs) - writer.writerow(headers) - for row in data: - writer.writerow(row) + l = linewriter() + writer = csv.writer(l, **ckwargs) + writer.writerow(headers) + yield l.line - return content.getvalue() + for row in data: + l.reset() + writer.writerow(row) + yield l.line diff --git a/cli_helpers/tabular_output/tabulate_adapter.py b/cli_helpers/tabular_output/tabulate_adapter.py index 1b3d088..1466d19 100644 --- a/cli_helpers/tabular_output/tabulate_adapter.py +++ b/cli_helpers/tabular_output/tabulate_adapter.py @@ -27,4 +27,4 @@ def adapter(data, headers, table_format=None, preserve_whitespace=False, tabulate.PRESERVE_WHITESPACE = preserve_whitespace - return tabulate.tabulate(data, headers, **tkwargs) + return iter(tabulate.tabulate(data, headers, **tkwargs).split('\n')) diff --git a/cli_helpers/tabular_output/terminaltables_adapter.py b/cli_helpers/tabular_output/terminaltables_adapter.py index 1a34d4d..48bc2cf 100644 --- a/cli_helpers/tabular_output/terminaltables_adapter.py +++ b/cli_helpers/tabular_output/terminaltables_adapter.py @@ -25,4 +25,10 @@ def adapter(data, headers, table_format=None, **kwargs): table = table_format_handler[table_format] t = table([headers] + list(data), **filter_dict_by_key(kwargs, keys)) - return t.table + + dimensions = terminaltables.width_and_alignment.max_dimensions( + t.table_data, + t.padding_left, + t.padding_right)[:3] + for r in t.gen_table(*dimensions): + yield ''.join(r) diff --git a/cli_helpers/tabular_output/vertical_table_adapter.py b/cli_helpers/tabular_output/vertical_table_adapter.py index 82bcb5b..a359f7d 100644 --- a/cli_helpers/tabular_output/vertical_table_adapter.py +++ b/cli_helpers/tabular_output/vertical_table_adapter.py @@ -57,11 +57,7 @@ def vertical_table(data, headers, sep_title='{n}. row', sep_character='*', output = [] for i, result in enumerate(formatted_rows): - output.append(_get_separator(i, sep_title, sep_character, sep_length)) - output.append(result) - output.append('\n') - - return ''.join(output) + yield _get_separator(i, sep_title, sep_character, sep_length) + result def adapter(data, headers, **kwargs): diff --git a/tests/tabular_output/test_delimited_output_adapter.py b/tests/tabular_output/test_delimited_output_adapter.py index ae2c8b3..b5b1cd5 100644 --- a/tests/tabular_output/test_delimited_output_adapter.py +++ b/tests/tabular_output/test_delimited_output_adapter.py @@ -15,24 +15,25 @@ def test_csv_wrapper(): data = [['abc', '1'], ['d', '456']] headers = ['letters', 'number'] output = delimited_output_adapter.adapter(iter(data), headers) - assert output == dedent('''\ - letters,number\r\n\ - abc,1\r\n\ - d,456\r\n''') + assert "\n".join(output) == dedent('''\ + letters,number\n\ + abc,1\n\ + d,456''') # Test tab-delimited output. data = [['abc', '1'], ['d', '456']] headers = ['letters', 'number'] output = delimited_output_adapter.adapter( iter(data), headers, table_format='tsv') - assert output == dedent('''\ - letters\tnumber\r\n\ - abc\t1\r\n\ - d\t456\r\n''') + assert "\n".join(output) == dedent('''\ + letters\tnumber\n\ + abc\t1\n\ + d\t456''') with pytest.raises(ValueError): output = delimited_output_adapter.adapter( iter(data), headers, table_format='foobar') + list(output) def test_unicode_with_csv(): @@ -40,8 +41,8 @@ def test_unicode_with_csv(): data = [['观音', '1'], ['Ποσειδῶν', '456']] headers = ['letters', 'number'] output = delimited_output_adapter.adapter(data, headers) - assert output == dedent('''\ - letters,number\r\n\ - 观音,1\r\n\ - Ποσειδῶν,456\r\n''') + assert "\n".join(output) == dedent('''\ + letters,number\n\ + 观音,1\n\ + Ποσειδῶν,456''') diff --git a/tests/tabular_output/test_output_formatter.py b/tests/tabular_output/test_output_formatter.py index df0dc98..7527a45 100644 --- a/tests/tabular_output/test_output_formatter.py +++ b/tests/tabular_output/test_output_formatter.py @@ -26,8 +26,8 @@ def test_tabular_output_formatter(): | hi | 1.1 | +------+---------+''') - assert expected == TabularOutputFormatter().format_output( - iter(data), headers, format_name='ascii') + assert expected == "\n".join(TabularOutputFormatter().format_output( + iter(data), headers, format_name='ascii')) def test_tabular_format_output_wrapper(): @@ -44,8 +44,8 @@ def test_tabular_format_output_wrapper(): | 3 | Joe | +----+------+''') - assert expected == format_output(iter(data), headers, format_name='ascii', - missing_value='N/A') + assert expected == "\n".join(format_output(iter(data), headers, format_name='ascii', + missing_value='N/A')) def test_additional_preprocessors(): @@ -70,9 +70,9 @@ def hello_world_data(data): | hello! | hello, world | +--------+--------------+''') - assert expected == TabularOutputFormatter().format_output( + assert expected == "\n".join(TabularOutputFormatter().format_output( iter(data), headers, format_name='ascii', preprocessors=(hello_world,), - missing_value='hello') + missing_value='hello')) def test_format_name_attribute(): @@ -108,7 +108,10 @@ def test_tabulate_ansi_escape_in_default_value(): missing_value='\x1b[38;5;10mNULL\x1b[39m') unstyled = format_output(iter(data), headers, format_name='psql', missing_value='NULL') - assert strip_ansi(styled) == unstyled + + stripped_styled = [strip_ansi(s) for s in styled] + + assert list(unstyled) == stripped_styled def test_get_type(): @@ -144,5 +147,8 @@ def test_enforce_iterable(): for format_name in formatter.supported_formats: formatter.format_name = format_name - formatted = formatter.format_output(zip(loremipsum), ['lorem']) - assert len(formatted) > 0 + try: + formatted = next(formatter.format_output( + zip(loremipsum), ['lorem'])) + except TypeError: + assert False, "{0} doesn't return iterable".format(format_name) diff --git a/tests/tabular_output/test_tabulate_adapter.py b/tests/tabular_output/test_tabulate_adapter.py index bd7ef21..9f626c8 100644 --- a/tests/tabular_output/test_tabulate_adapter.py +++ b/tests/tabular_output/test_tabulate_adapter.py @@ -12,7 +12,7 @@ def test_tabulate_wrapper(): data = [['abc', 1], ['d', 456]] headers = ['letters', 'number'] output = tabulate_adapter.adapter(iter(data), headers, table_format='psql') - assert output == dedent('''\ + assert "\n".join(output) == dedent('''\ +-----------+----------+ | letters | number | |-----------+----------| @@ -26,7 +26,7 @@ def test_markup_format(): data = [['abc', 1], ['d', 456]] headers = ['letters', 'number'] output = tabulate_adapter.adapter(iter(data), headers, table_format='mediawiki') - assert output == dedent('''\ + assert "\n".join(output) == dedent('''\ {| class="wikitable" style="text-align: left;" |+ |- diff --git a/tests/tabular_output/test_terminaltables_adapter.py b/tests/tabular_output/test_terminaltables_adapter.py index f78160f..070e8cd 100644 --- a/tests/tabular_output/test_terminaltables_adapter.py +++ b/tests/tabular_output/test_terminaltables_adapter.py @@ -13,7 +13,7 @@ def test_terminal_tables_adapter(): headers = ['letters', 'number'] output = terminaltables_adapter.adapter( iter(data), headers, table_format='ascii') - assert output == dedent('''\ + assert "\n".join(output) == dedent('''\ +---------+--------+ | letters | number | +---------+--------+ diff --git a/tests/tabular_output/test_vertical_table_adapter.py b/tests/tabular_output/test_vertical_table_adapter.py index 2be2aa7..8b5e18c 100644 --- a/tests/tabular_output/test_vertical_table_adapter.py +++ b/tests/tabular_output/test_vertical_table_adapter.py @@ -17,9 +17,9 @@ def test_vertical_table(): age | 123 ***************************[ 2. row ]*************************** name | world - age | 456 - """) - assert expected == vertical_table_adapter.adapter(results, ('name', 'age')) + age | 456""") + assert expected == "\n".join( + vertical_table_adapter.adapter(results, ('name', 'age'))) def test_vertical_table_customized(): @@ -32,8 +32,7 @@ def test_vertical_table_customized(): age | 47 -[ PERSON 2 ]----- name | jill - age | 50 - """) - assert expected == vertical_table_adapter.adapter( + age | 50""") + assert expected == "\n".join(vertical_table_adapter.adapter( results, ('name', 'age'), sep_title='PERSON {n}', - sep_character='-', sep_length=(1, 5)) + sep_character='-', sep_length=(1, 5)))