From f604b516bf8701c5fc405570541127fa0b138232 Mon Sep 17 00:00:00 2001 From: Parsiad Azimzadeh Date: Sat, 25 Sep 2021 00:02:11 -0700 Subject: [PATCH] Initial commit. --- .gitignore | 2 + LICENSE | 20 ++++++++++ README.md | 68 ++++++++++++++++++++++++++++++++++ examples/ode.gif | Bin 0 -> 42141 bytes examples/ode.py | 37 ++++++++++++++++++ logo.png | Bin 0 -> 11682 bytes pyproject.toml | 6 +++ setup.cfg | 26 +++++++++++++ src/lazy_table/__init__.py | 5 +++ src/lazy_table/_lazy_table.py | 67 +++++++++++++++++++++++++++++++++ 10 files changed, 231 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100755 examples/ode.gif create mode 100755 examples/ode.py create mode 100644 logo.png create mode 100644 pyproject.toml create mode 100644 setup.cfg create mode 100644 src/lazy_table/__init__.py create mode 100644 src/lazy_table/_lazy_table.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8968d1e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +lazy_table.egg-info diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f3c4cc5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2021 Parsiad Azimzadeh + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cfa4a66 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +

+ lazy_table +

+ +A [python-tabulate](https://github.com/astanin/python-tabulate) wrapper for producing tables from generators. + +## Motivation + +lazy_table is useful when (*i*) each row of your table is generated by a possibly expensive computation and (*ii*) you want to print rows to the screen as soon as they are available. + +For example, the rows in the table below correspond to [numerically solving an ordinary differential equation](https://en.wikipedia.org/wiki/Numerical_methods_for_ordinary_differential_equations) with progressively more steps. See [examples/ode.py](https://raw.githubusercontent.com/parsiad/lazy-table/master/examples/ode.py) for the code to generate this table. + +![](https://raw.githubusercontent.com/parsiad/lazy-table/master/examples/ode.gif) + +## Installation and usage + +Install lazy_table via pip: + +```console +$ pip install lazy_table +``` + +In your Python code, add + +```python +import lazy_table as lt +``` + +Now, generating your own lazy table is as simple as calling `lt.stream` on a generator that yields one or more lists, where each list is a row of your table (see the example below). + +## Example + +As a toy example, consider printing the first 10 [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number) in a table. +Since this is a relatively cheap operation, we will pretend it is expensive by adding an artificial `sleep(1)` call beteween Fibonacci numbers. + +```python +import time +import lazy_table as lt + +def fib_table(n): + x0, x1 = 0, 1 + yield [0, x0] + yield [1, x1] + for i in range(2, n + 1): + x0, x1 = x1, x0 + x1 + yield [i, x1] + time.sleep(1) # Simulate work + +lt.stream(fib_table(10), headers=['N', 'F_N']) +``` + +Your final table should look like this: + +``` + N F_N +--- ----- + 0 0 + 1 1 + 2 1 + 3 2 + 4 3 + 5 5 + 6 8 + 7 13 + 8 21 + 9 34 + 10 55 +``` diff --git a/examples/ode.gif b/examples/ode.gif new file mode 100755 index 0000000000000000000000000000000000000000..754bda28ceea31b4db56e728143e91c4aa897f02 GIT binary patch literal 42141 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", + "wheel" +] +build-backend = "setuptools.build_meta" diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..ce94745 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,26 @@ +[metadata] +name = lazy-table +version = 0.1.0 +author = Parsiad Azimzadeh +author_email = parsiad.azimzadeh@gmail.com +description = A python-tabulate wrapper for producing tables from generators +long_description = file: README.md +long_description_content_type = text/markdown +url = https://github.com/parsiad/lazy-table +project_urls = + Bug Tracker = https://github.com/parsiad/lazy-table/issues +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: MIT License + Operating System :: OS Independent + +[options] +install_requires = + tabulate +package_dir = + = src +packages = find: +python_requires = >= 3.6 + +[options.packages.find] +where = src diff --git a/src/lazy_table/__init__.py b/src/lazy_table/__init__.py new file mode 100644 index 0000000..dbe5b05 --- /dev/null +++ b/src/lazy_table/__init__.py @@ -0,0 +1,5 @@ +"""A python-tabulate wrapper for producing tables from generators.""" + +__all__ = ['ConsoleArtist', 'stream'] + +from ._lazy_table import ConsoleArtist, stream diff --git a/src/lazy_table/_lazy_table.py b/src/lazy_table/_lazy_table.py new file mode 100644 index 0000000..19fc3d5 --- /dev/null +++ b/src/lazy_table/_lazy_table.py @@ -0,0 +1,67 @@ +import sys + +from tabulate import tabulate + + +class ConsoleArtist: + """Renders a table to the console. + + Parameters + ---------- + clear : bool + Clears the screen every time the table is updated. + out : TextIOBase + Text stream to write to. If unspecified, ``sys.stdout`` is used. + """ + def __init__(self, clear=False, out=sys.stdout): + self._clear = clear + self._n_lines = 0 + self._out = out + + def __call__(self, result): + if self._clear: + self._out.write('\x1b[2J') + else: + self._out.write('\033[F\033[K' * self._n_lines) + self._n_lines = result.count('\n') + 1 + self._out.write(result) + self._out.write('\n') + self._out.flush() + + +def stream(table, artist=None, **kwargs): + """Streams a table. + + kwargs are forwarded to tabulate. + + Examples + -------- + >>> import time + >>> import lazy_table as lt + >>> + >>> def fib_table(n): + ... x0, x1 = 0, 1 + ... yield [0, x0] + ... yield [1, x1] + ... for i in range(2, n + 1): + ... x0, x1 = x1, x0 + x1 + ... yield [i, x1] + ... time.sleep(1) # Simulate work + >>> + >>> lt.stream(fib_table(10), headers=['N', 'F_N']) + + Parameters + ---------- + table : Generator[List[T], None, None] + A generator which yields rows of the table. + artist : callable, optional + A callable of the form ``draw(string)`` which determines how to render the table. If unspecified, + ``lazy_table.Console`` is used. + """ + if artist is None: + artist = ConsoleArtist() + rows = [] + for row in table: + rows.append(row) + t = tabulate(rows, **kwargs) + artist(t)