diff --git a/README.md b/README.md index 5d01409..b8f4349 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Hosted at Read The Docs: [tableprint.readthedocs.org](http://tableprint.readthed - `six` ## Version -- 0.7.0 (May 25 2017) Adds support for variable widths across columns +- 0.7.0 (May 26 2017) Adds a TableContext context manager for easy creation of dynamic tables (tables that update periodically). Adds the ability to pass a list or tuple of widths to specify different widths for different columns - 0.6.9 (May 25 2017) Splitting the tableprint.py module into a pacakge with multiple files - 0.6.7 (May 25 2017) Fixes some bugs with ANSI escape sequences - 0.5.0 (Sept 29 2016) Better handling of ANSI escape sequences in table rows diff --git a/tableprint/printer.py b/tableprint/printer.py index a595b29..994120b 100644 --- a/tableprint/printer.py +++ b/tableprint/printer.py @@ -21,13 +21,56 @@ from six import string_types from .style import LineStyle, STYLES from .utils import ansi_len, format_line, parse_width -__all__ = ('table', 'header', 'row', 'hrule', 'top', 'bottom', 'banner', 'dataframe') +__all__ = ('table', 'header', 'row', 'hrule', 'top', 'bottom', 'banner', 'dataframe', 'TableContext') STYLE = 'round' WIDTH = 11 FMT = '5g' +class TableContext: + def __init__(self, headers, width=WIDTH, style=STYLE, add_hr=True, out=sys.stdout): + """Context manager for table printing + + Parameters + ---------- + headers : array_like + A list of N strings consisting of the header of each of the N columns + + width : int or array_like, optional + The width of each column in the table (Default: 11) + + style : string or tuple, optional + A formatting style. (Default: 'round') + + add_hr : boolean, optional + Whether or not to add a horizontal rule (hr) after the headers + + Usage + ----- + >>> with TableContext("ABC") as t: + for k in range(10): + t.row(np.random.randn(3)) + """ + self.out = out + self.config = {'width': width, 'style': style} + self.headers = header(headers, add_hr=add_hr, **self.config) + self.bottom = bottom(len(headers), **self.config) + + def __call__(self, data): + self.out.write(row(data, **self.config) + '\n') + self.out.flush() + + def __enter__(self): + self.out.write(self.headers + '\n') + self.out.flush() + return self + + def __exit__(self, *exc): + self.out.write(self.bottom + '\n') + self.out.flush() + + def table(data, headers=None, format_spec=FMT, width=WIDTH, style=STYLE, out=sys.stdout): """Print a table with the given data diff --git a/tests/test_io.py b/tests/test_io.py index ac7b5fd..2c2ceb9 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -1,12 +1,21 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from tableprint import table, banner, dataframe, hrule +from tableprint import table, banner, dataframe, hrule, TableContext from io import StringIO import numpy as np -def test_table(): +def test_context(): + """Tests the table context manager""" + output = StringIO() + with TableContext('ABC', style='round', width=5, out=output) as t: + t([1, 2, 3]) + t([4, 5, 6]) + assert output.getvalue() == '╭─────┬─────┬─────╮\n│ A │ B │ C │\n├─────┼─────┼─────┤\n│ 1│ 2│ 3│\n│ 4│ 5│ 6│\n╰─────┴─────┴─────╯\n' + +def test_table(): + """Tests the table function""" output = StringIO() table([[1, 2, 3], [4, 5, 6]], 'ABC', style='round', width=5, out=output) assert output.getvalue() == '╭─────┬─────┬─────╮\n│ A │ B │ C │\n├─────┼─────┼─────┤\n│ 1│ 2│ 3│\n│ 4│ 5│ 6│\n╰─────┴─────┴─────╯\n' @@ -17,7 +26,7 @@ def test_table(): def test_frame(): - + """Tests the dataframe function""" # mock of a pandas DataFrame class DataFrame: def __init__(self, data, headers): @@ -35,7 +44,7 @@ def test_frame(): def test_banner(): - + """Tests the banner function""" output = StringIO() banner('hello world', style='clean', width=11, out=output) assert output.getvalue() == ' ─────────── \n hello world \n ─────────── \n' @@ -46,7 +55,7 @@ def test_banner(): def test_hrule(): - + """Tests the hrule function""" output = hrule(1, width=11) assert len(output) == 11 assert '───────────'