From 5cfa62253f853d7627bdc95a36ccdef99e3b0302 Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 11:40:22 -0700 Subject: [PATCH 01/13] Using metadata.py to manage version number and other metadata --- metadata.py | 18 ++++++++++++++++++ setup.py | 30 ++++++++---------------------- tableprint.py | 2 +- 3 files changed, 27 insertions(+), 23 deletions(-) create mode 100644 metadata.py diff --git a/metadata.py b/metadata.py new file mode 100644 index 0000000..6e05b69 --- /dev/null +++ b/metadata.py @@ -0,0 +1,18 @@ +# Version info +__name__ = 'tableprint' +__version__ = '0.6.1' +__license__ = 'MIT' + +# Project description(s) +__description__ = 'Pretty console printing of tabular data' +__long_description__ = '''Formatted console printing of tabular data. + tableprint lets you easily print formatted tables of data. + Unlike other modules, you can print single rows of data at a time + (useful for printing ongoing computation results).''' + +# The project's main homepage. +__url__ = 'https://github.com/nirum/tableprint' + +# Author details +__author__ = 'Niru Maheswaranathan' +__author_email__ = 'niru@fastmail.com' diff --git a/setup.py b/setup.py index bab43c2..5363840 100644 --- a/setup.py +++ b/setup.py @@ -1,28 +1,13 @@ +import re from setuptools import setup + +with open('metadata.py', 'r') as f: + metadata = dict(re.findall("", f.read())) + + setup( - name='tableprint', - - # Versions should comply with PEP440. For a discussion on single-sourcing - # the version across setup.py and the project code, see - # https://packaging.python.org/en/latest/single_source_version.html - version='0.6.1', - - description='Pretty console printing of tabular data', - long_description='''Formatted console printing of tabular data. - tableprint lets you easily print formatted tables of data. - Unlike other modules, you can print single rows of data at a time - (useful for printing ongoing computation results).''', - - # The project's main homepage. - url='https://github.com/nirum/tableprint', - - # Author details - author='Niru Maheswaranathan', - author_email='niru@fastmail.com', - - # Choose your license - license='MIT', + **metadata, # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ @@ -44,6 +29,7 @@ setup( 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', ], # What does your project relate to? diff --git a/tableprint.py b/tableprint.py index 5870e53..545d895 100644 --- a/tableprint.py +++ b/tableprint.py @@ -11,6 +11,7 @@ Usage >>> tableprint.table(data, headers) """ from __future__ import print_function, unicode_literals +from metadata import __version__ from six import string_types from collections import namedtuple from numbers import Number @@ -20,7 +21,6 @@ import numpy as np __all__ = ('table', 'header', 'row', 'hr', 'top', 'bottom', 'banner', 'dataframe', 'humantime', 'styles') -__version__ = '0.5.4' # set up table styles LineStyle = namedtuple('LineStyle', ('begin', 'hline', 'sep', 'end')) From 14242b7e8d49b4536e914d22e40f7f5db8b273f6 Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 11:42:30 -0700 Subject: [PATCH 02/13] Updates README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a3fea49..501ba41 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Hosted at Read The Docs: [tableprint.readthedocs.org](http://tableprint.readthed - `six` ## Version +- 0.6.2 (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 - 0.4.0 (May 3 2016) Adds a 'block' style - 0.3.2 (May 3 2016) Adds a test suite From 4a084afb41ae43d00430517a4ddf6344ad595b9c Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 11:47:42 -0700 Subject: [PATCH 03/13] :bug:fix in setup.py --- metadata.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/metadata.py b/metadata.py index 6e05b69..853e753 100644 --- a/metadata.py +++ b/metadata.py @@ -1,6 +1,6 @@ # Version info __name__ = 'tableprint' -__version__ = '0.6.1' +__version__ = '0.6.3' __license__ = 'MIT' # Project description(s) diff --git a/setup.py b/setup.py index 5363840..84c70e7 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import setup with open('metadata.py', 'r') as f: - metadata = dict(re.findall("", f.read())) + metadata = dict(re.findall("__([a-z]+)__\s*=\s*'([^']+)'", f.read())) setup( From 4fc0df2402da48d1b8a88150237e88aed2904fa7 Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 11:53:24 -0700 Subject: [PATCH 04/13] :bug:fix in metadata regex --- metadata.py | 2 +- setup.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/metadata.py b/metadata.py index 853e753..4617958 100644 --- a/metadata.py +++ b/metadata.py @@ -1,6 +1,6 @@ # Version info __name__ = 'tableprint' -__version__ = '0.6.3' +__version__ = '0.6.4' __license__ = 'MIT' # Project description(s) diff --git a/setup.py b/setup.py index 84c70e7..4c75c86 100644 --- a/setup.py +++ b/setup.py @@ -3,12 +3,10 @@ from setuptools import setup with open('metadata.py', 'r') as f: - metadata = dict(re.findall("__([a-z]+)__\s*=\s*'([^']+)'", f.read())) + metadata = dict(re.findall("__([a-z_]+)__\s*=\s*'([^']+)'", f.read())) setup( - **metadata, - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ # How mature is this project? Common values are @@ -54,4 +52,5 @@ setup( 'test': ['pytest', 'coverage'], }, + **metadata, ) From 2ef7ba6b490282c9e6cfdf82ea220772bf67d1ba Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 11:55:02 -0700 Subject: [PATCH 05/13] :bug:fix in setup.py --- metadata.py | 6 +----- setup.py | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/metadata.py b/metadata.py index 4617958..d0d0ed3 100644 --- a/metadata.py +++ b/metadata.py @@ -1,14 +1,10 @@ # Version info __name__ = 'tableprint' -__version__ = '0.6.4' +__version__ = '0.6.5' __license__ = 'MIT' # Project description(s) __description__ = 'Pretty console printing of tabular data' -__long_description__ = '''Formatted console printing of tabular data. - tableprint lets you easily print formatted tables of data. - Unlike other modules, you can print single rows of data at a time - (useful for printing ongoing computation results).''' # The project's main homepage. __url__ = 'https://github.com/nirum/tableprint' diff --git a/setup.py b/setup.py index 4c75c86..b1880ee 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,11 @@ with open('metadata.py', 'r') as f: setup( + long_description='''Formatted console printing of tabular data. + tableprint lets you easily print formatted tables of data. + Unlike other modules, you can print single rows of data at a time + (useful for printing ongoing computation results).''', + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ # How mature is this project? Common values are From d7732f2f0eab578b8f99f791f0c09f1554aa113a Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 12:04:47 -0700 Subject: [PATCH 06/13] Explicit unpacking of metadata in setup.py for 2.7/3.4 support --- .travis.yml | 1 + metadata.py | 2 +- setup.py | 12 ++++++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ccb0641..a5cd9b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ python: - "2.7" - "3.4" - "3.5" + - "3.6" install: - sudo apt-get update - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then diff --git a/metadata.py b/metadata.py index d0d0ed3..3ac26a5 100644 --- a/metadata.py +++ b/metadata.py @@ -1,6 +1,6 @@ # Version info __name__ = 'tableprint' -__version__ = '0.6.5' +__version__ = '0.6.6' __license__ = 'MIT' # Project description(s) diff --git a/setup.py b/setup.py index b1880ee..00d1be5 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,16 @@ with open('metadata.py', 'r') as f: setup( + name=metadata['name'], + url=metadata['url'], + version=metadata['version'], + + author=metadata['author'], + author_email=metadata['author_email'], + + license=metadata['license'], + + description=metadata['description'], long_description='''Formatted console printing of tabular data. tableprint lets you easily print formatted tables of data. Unlike other modules, you can print single rows of data at a time @@ -56,6 +66,4 @@ setup( 'dev': [], 'test': ['pytest', 'coverage'], }, - - **metadata, ) From 412e02b297d90b5f1367cb3c5dcdee4c557e291b Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 12:08:23 -0700 Subject: [PATCH 07/13] Updates README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 501ba41..36c7fd1 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.6.2 (May 25 2017) Fixes some bugs with ANSI escape sequences +- 0.6.6 (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 - 0.4.0 (May 3 2016) Adds a 'block' style - 0.3.2 (May 3 2016) Adds a test suite From d7596f611fe7f3dd617669e57070948a7bc09009 Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 12:42:48 -0700 Subject: [PATCH 08/13] Better reading of path to metadata.py file in setup.py --- README.md | 2 +- metadata.py | 2 +- setup.py | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 36c7fd1..265bf72 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.6.6 (May 25 2017) Fixes some bugs with ANSI escape sequences +- 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 - 0.4.0 (May 3 2016) Adds a 'block' style - 0.3.2 (May 3 2016) Adds a test suite diff --git a/metadata.py b/metadata.py index 3ac26a5..5611083 100644 --- a/metadata.py +++ b/metadata.py @@ -1,6 +1,6 @@ # Version info __name__ = 'tableprint' -__version__ = '0.6.6' +__version__ = '0.6.7' __license__ = 'MIT' # Project description(s) diff --git a/setup.py b/setup.py index 00d1be5..88150cf 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,10 @@ import re +import os from setuptools import setup -with open('metadata.py', 'r') as f: +__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))) +with open(os.path.join(__location__, 'metadata.py'), 'r') as f: metadata = dict(re.findall("__([a-z_]+)__\s*=\s*'([^']+)'", f.read())) From 6e94c9e99c1c61172a3e6df56626aefb16ca2886 Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 15:02:14 -0700 Subject: [PATCH 09/13] converting tableprint from a module to a package --- Makefile | 6 +- setup.py | 3 +- tableprint/__init__.py | 8 ++ metadata.py => tableprint/metadata.py | 2 + tableprint.py => tableprint/printer.py | 157 ++++--------------------- tableprint/style.py | 48 ++++++++ tableprint/utils.py | 75 ++++++++++++ tests/test_functions.py | 4 +- tests/test_io.py | 7 +- tests/test_utils.py | 15 +-- 10 files changed, 177 insertions(+), 148 deletions(-) create mode 100644 tableprint/__init__.py rename metadata.py => tableprint/metadata.py (93%) rename tableprint.py => tableprint/printer.py (53%) create mode 100644 tableprint/style.py create mode 100644 tableprint/utils.py diff --git a/Makefile b/Makefile index 6846c6a..8fa9d46 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,6 @@ test: nosetests -v --with-coverage --cover-package=tableprint --logging-level=INFO clean: - rm -rf tableprint.egg-info - rm -f *.pyc - rm -rf __pycache__ + rm -R tableprint.egg-info + rm -f tableprint/*.pyc + rm -R tableprint/__pycache__/ diff --git a/setup.py b/setup.py index 88150cf..645db5f 100644 --- a/setup.py +++ b/setup.py @@ -52,8 +52,7 @@ setup( # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). - packages=[], - py_modules=['tableprint'], + packages=['tableprint'], # List run-time dependencies here. These will be installed by pip when your # project is installed. For an analysis of "install_requires" vs pip's diff --git a/tableprint/__init__.py b/tableprint/__init__.py new file mode 100644 index 0000000..9ad1910 --- /dev/null +++ b/tableprint/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +""" +Tableprint +""" +from .metadata import __author__, __version__ +from .printer import * +from .style import * +from .utils import * diff --git a/metadata.py b/tableprint/metadata.py similarity index 93% rename from metadata.py rename to tableprint/metadata.py index 5611083..d67573f 100644 --- a/metadata.py +++ b/tableprint/metadata.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + # Version info __name__ = 'tableprint' __version__ = '0.6.7' diff --git a/tableprint.py b/tableprint/printer.py similarity index 53% rename from tableprint.py rename to tableprint/printer.py index 545d895..f29ba82 100644 --- a/tableprint.py +++ b/tableprint/printer.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Tableprint +Table printing A module to print and display formatted tables of data @@ -11,58 +11,18 @@ Usage >>> tableprint.table(data, headers) """ from __future__ import print_function, unicode_literals -from metadata import __version__ -from six import string_types -from collections import namedtuple -from numbers import Number + import sys -import re +from numbers import Number + import numpy as np +from six import string_types -__all__ = ('table', 'header', 'row', 'hr', 'top', 'bottom', - 'banner', 'dataframe', 'humantime', 'styles') +from .style import LineStyle, STYLES +from .utils import ansi_len, format_line + +__all__ = ('table', 'header', 'row', 'hrule', 'top', 'bottom', 'banner', 'dataframe') -# set up table styles -LineStyle = namedtuple('LineStyle', ('begin', 'hline', 'sep', 'end')) -TableStyle = namedtuple('TableStyle', ('top', 'below_header', 'bottom', 'row')) -styles = { - 'grid': TableStyle( - top=LineStyle('+', '-', '+', '+'), - below_header=LineStyle('+', '-', '+', '+'), - bottom=LineStyle('+', '-', '+', '+'), - row=LineStyle('|', '', '|', '|'), - ), - 'fancy_grid': TableStyle( - top=LineStyle('╒', '═', '╤', '╕'), - below_header=LineStyle('╞', '═', '╪', '╡'), - bottom=LineStyle("╘", "═", "╧", "╛"), - row=LineStyle('│', '', '│', '│'), - ), - 'clean': TableStyle( - top=LineStyle(' ', '─', ' ', ' '), - below_header=LineStyle(' ', '─', ' ', ' '), - bottom=LineStyle(" ", "─", " ", " "), - row=LineStyle(' ', '', ' ', ' '), - ), - 'round': TableStyle( - top=LineStyle('╭', '─', '┬', '╮'), - below_header=LineStyle('├', '─', '┼', '┤'), - bottom=LineStyle('╰', '─', '┴', '╯'), - row=LineStyle('│', '', '│', '│'), - ), - 'banner': TableStyle( - top=LineStyle('╒', '═', '╤', '╕'), - below_header=LineStyle("╘", "═", "╧", "╛"), - bottom=LineStyle("╘", "═", "╧", "╛"), - row=LineStyle('│', '', '│', '│'), - ), - 'block': TableStyle( - top=LineStyle('◢', '■', '■', '◣'), - below_header=LineStyle(' ', '━', '━', ' '), - bottom=LineStyle('◥', '■', '■', '◤'), - row=LineStyle(' ', '', ' ', ' '), - ), -} STYLE = 'round' WIDTH = 11 FMT = '5g' @@ -92,10 +52,10 @@ def table(data, headers=None, format_spec=FMT, width=WIDTH, style=STYLE, out=sys A file handle or object that has write() and flush() methods (Default: sys.stdout) """ ncols = len(data[0]) if headers is None else len(headers) - tablestyle = styles[style] + tablestyle = STYLES[style] # Initialize with a hr or the header - tablestr = [hr(ncols, width, tablestyle.top)] \ + tablestr = [hrule(ncols, width, tablestyle.top)] \ if headers is None else [header(headers, width, style)] # parse each row @@ -103,7 +63,7 @@ def table(data, headers=None, format_spec=FMT, width=WIDTH, style=STYLE, out=sys # only add the final border if there was data in the table if len(data) > 0: - tablestr += [hr(ncols, width, tablestyle.bottom)] + tablestr += [hrule(ncols, width, tablestyle.bottom)] # print the table out.write('\n'.join(tablestr) + '\n') @@ -122,24 +82,24 @@ def header(headers, width=WIDTH, style=STYLE, add_hr=True): The width of each column (Default: 11) style : string or tuple, optional - A formatting style (see styles) + A formatting style (see STYLES) Returns ------- headerstr : string A string consisting of the full header row to print """ - tablestyle = styles[style] + tablestyle = STYLES[style] # string formatter - data = map(lambda x: ('{:^%d}' % (width + _ansi_len(x))).format(x), headers) + data = map(lambda x: ('{:^%d}' % (width + ansi_len(x))).format(x), headers) # build the formatted str - headerstr = _format_line(data, tablestyle.row) + headerstr = format_line(data, tablestyle.row) if add_hr: - upper = hr(len(headers), width, tablestyle.top) - lower = hr(len(headers), width, tablestyle.below_header) + upper = hrule(len(headers), width, tablestyle.top) + lower = hrule(len(headers), width, tablestyle.below_header) headerstr = '\n'.join([upper, headerstr, lower]) return headerstr @@ -167,9 +127,9 @@ def row(values, width=WIDTH, format_spec=FMT, style=STYLE): rowstr : string A string consisting of the full row of data to print """ - tablestyle = styles[style] + tablestyle = STYLES[style] - assert isinstance(format_spec, string_types) | (type(format_spec) is list), \ + assert isinstance(format_spec, string_types) | isinstance(format_spec, list), \ "format_spec must be a string or list of strings" if isinstance(format_spec, string_types): @@ -182,7 +142,7 @@ def row(values, width=WIDTH, format_spec=FMT, style=STYLE): datum, prec = val if isinstance(datum, string_types): - return ('{:>%i}' % (width + _ansi_len(datum))).format(datum) + return ('{:>%i}' % (width + ansi_len(datum))).format(datum) elif isinstance(datum, Number): return ('{:>%i.%s}' % (width, prec)).format(datum) @@ -194,10 +154,10 @@ def row(values, width=WIDTH, format_spec=FMT, style=STYLE): data = map(mapdata, zip(values, format_spec)) # build the row string - return _format_line(data, tablestyle.row) + return format_line(data, tablestyle.row) -def hr(n, width=WIDTH, linestyle=LineStyle('', '─', '─', '')): +def hrule(n=1, width=WIDTH, linestyle=LineStyle('', '─', '─', '')): """Returns a formatted string used as a border between table rows Parameters @@ -223,12 +183,12 @@ def hr(n, width=WIDTH, linestyle=LineStyle('', '─', '─', '')): def top(n, width=WIDTH, style=STYLE): """Prints the top row of a table""" - return hr(n, width, linestyle=styles[style].top) + return hrule(n, width, linestyle=STYLES[style].top) def bottom(n, width=WIDTH, style=STYLE): """Prints the top row of a table""" - return hr(n, width, linestyle=styles[style].bottom) + return hrule(n, width, linestyle=STYLES[style].bottom) def banner(message, width=30, style='banner', out=sys.stdout): @@ -261,70 +221,3 @@ def dataframe(df, **kwargs): A pandas DataFrame with the table to print """ table(np.array(df), list(df.columns), **kwargs) - - -def humantime(t): - """Converts a time in seconds to a reasonable human readable time - - Parameters - ---------- - t : float - The number of seconds - - Returns - ------- - time : string - The human readable formatted value of the given time - """ - try: - t = float(t) - except (ValueError, TypeError): - raise ValueError("Input must be numeric") - - # weeks - if t >= 7*60*60*24: - weeks = np.floor(t / (7.*60.*60.*24.)) - timestr = "{:g} weeks, ".format(weeks) + humantime(t % (7*60*60*24)) - - # days - elif t >= 60*60*24: - days = np.floor(t / (60.*60.*24.)) - timestr = "{:g} days, ".format(days) + humantime(t % (60*60*24)) - - # hours - elif t >= 60*60: - hours = np.floor(t / (60.*60.)) - timestr = "{:g} hours, ".format(hours) + humantime(t % (60*60)) - - # minutes - elif t >= 60: - minutes = np.floor(t / 60.) - timestr = "{:g} min., ".format(minutes) + humantime(t % 60) - - # seconds - elif (t >= 1) | (t == 0): - timestr = "{:g} s".format(t) - - # milliseconds - elif t >= 1e-3: - timestr = "{:g} ms".format(t*1e3) - - # microseconds - elif t >= 1e-6: - timestr = "{:g} \u03BCs".format(t*1e6) - - # nanoseconds or smaller - else: - timestr = "{:g} ns".format(t*1e9) - - return timestr - - -def _ansi_len(string): - """Extra length due to any ANSI sequences in the string.""" - return len(string) - len(re.compile(r'\x1b[^m]*m').sub('', string)) - - -def _format_line(data, linestyle): - """Formats a list of elements using the given line style""" - return linestyle.begin + linestyle.sep.join(data) + linestyle.end diff --git a/tableprint/style.py b/tableprint/style.py new file mode 100644 index 0000000..162295e --- /dev/null +++ b/tableprint/style.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +""" +Table styles +""" +from collections import namedtuple + +__all__ = ('STYLES', 'LineStyle', 'TableStyle') + +LineStyle = namedtuple('LineStyle', ('begin', 'hline', 'sep', 'end')) +TableStyle = namedtuple('TableStyle', ('top', 'below_header', 'bottom', 'row')) +STYLES = { + 'grid': TableStyle( + top=LineStyle('+', '-', '+', '+'), + below_header=LineStyle('+', '-', '+', '+'), + bottom=LineStyle('+', '-', '+', '+'), + row=LineStyle('|', '', '|', '|'), + ), + 'fancy_grid': TableStyle( + top=LineStyle('╒', '═', '╤', '╕'), + below_header=LineStyle('╞', '═', '╪', '╡'), + bottom=LineStyle("╘", "═", "╧", "╛"), + row=LineStyle('│', '', '│', '│'), + ), + 'clean': TableStyle( + top=LineStyle(' ', '─', ' ', ' '), + below_header=LineStyle(' ', '─', ' ', ' '), + bottom=LineStyle(" ", "─", " ", " "), + row=LineStyle(' ', '', ' ', ' '), + ), + 'round': TableStyle( + top=LineStyle('╭', '─', '┬', '╮'), + below_header=LineStyle('├', '─', '┼', '┤'), + bottom=LineStyle('╰', '─', '┴', '╯'), + row=LineStyle('│', '', '│', '│'), + ), + 'banner': TableStyle( + top=LineStyle('╒', '═', '╤', '╕'), + below_header=LineStyle("╘", "═", "╧", "╛"), + bottom=LineStyle("╘", "═", "╧", "╛"), + row=LineStyle('│', '', '│', '│'), + ), + 'block': TableStyle( + top=LineStyle('◢', '■', '■', '◣'), + below_header=LineStyle(' ', '━', '━', ' '), + bottom=LineStyle('◥', '■', '■', '◤'), + row=LineStyle(' ', '', ' ', ' '), + ), +} diff --git a/tableprint/utils.py b/tableprint/utils.py new file mode 100644 index 0000000..4efe295 --- /dev/null +++ b/tableprint/utils.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +""" +Tableprint utilities +""" +import re +import numpy as np + +__all__ = ('humantime',) + + +def humantime(time): + """Converts a time in seconds to a reasonable human readable time + + Parameters + ---------- + t : float + The number of seconds + + Returns + ------- + time : string + The human readable formatted value of the given time + """ + try: + time = float(time) + except (ValueError, TypeError): + raise ValueError("Input must be numeric") + + # weeks + if time >= 7 * 60 * 60 * 24: + weeks = np.floor(time / (7 * 60 * 60 * 24)) + timestr = "{:g} weeks, ".format(weeks) + humantime(time % (7 * 60 * 60 * 24)) + + # days + elif time >= 60 * 60 * 24: + days = np.floor(time / (60 * 60 * 24)) + timestr = "{:g} days, ".format(days) + humantime(time % (60 * 60 * 24)) + + # hours + elif time >= 60 * 60: + hours = np.floor(time / (60 * 60)) + timestr = "{:g} hours, ".format(hours) + humantime(time % (60 * 60)) + + # minutes + elif time >= 60: + minutes = np.floor(time / 60.) + timestr = "{:g} min., ".format(minutes) + humantime(time % 60) + + # seconds + elif (time >= 1) | (time == 0): + timestr = "{:g} s".format(time) + + # milliseconds + elif time >= 1e-3: + timestr = "{:g} ms".format(time * 1e3) + + # microseconds + elif time >= 1e-6: + timestr = "{:g} \u03BCs".format(time * 1e6) + + # nanoseconds or smaller + else: + timestr = "{:g} ns".format(time * 1e9) + + return timestr + + +def ansi_len(string): + """Extra length due to any ANSI sequences in the string.""" + return len(string) - len(re.compile(r'\x1b[^m]*m').sub('', string)) + + +def format_line(data, linestyle): + """Formats a list of elements using the given line style""" + return linestyle.begin + linestyle.sep.join(data) + linestyle.end diff --git a/tests/test_functions.py b/tests/test_functions.py index f14755b..35bbaa2 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -5,6 +5,7 @@ import pytest def test_borders(): + """Tests printing of the top and bottom borders""" # top assert top(5, width=2, style='round') == '╭──┬──┬──┬──┬──╮' @@ -16,11 +17,12 @@ def test_borders(): def test_row(): + """Tests printing of a single row of data""" # valid assert row("abc", width=3, style='round') == '│ a│ b│ c│' assert row([1, 2, 3], width=3, style='clean') == ' 1 2 3 ' # invalid - with pytest.raises(ValueError) as context: + with pytest.raises(ValueError): row([{}]) diff --git a/tests/test_io.py b/tests/test_io.py index b443eda..ac7b5fd 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from tableprint import table, banner, dataframe, hr +from tableprint import table, banner, dataframe, hrule from io import StringIO import numpy as np @@ -23,6 +23,7 @@ def test_frame(): def __init__(self, data, headers): self.data = data self.columns = headers + def __array__(self): return self.data @@ -44,8 +45,8 @@ def test_banner(): assert output.getvalue() == '╒═╕\n│!│\n╘═╛\n' -def test_hr(): +def test_hrule(): - output = hr(1, width=11) + output = hrule(1, width=11) assert len(output) == 11 assert '───────────' diff --git a/tests/test_utils.py b/tests/test_utils.py index 3a83ae2..92e3cc9 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,20 +1,21 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from tableprint import humantime, _format_line, LineStyle +from tableprint import humantime, LineStyle +from tableprint.utils import format_line import pytest def test_format_line(): # using ASCII - assert _format_line(['foo', 'bar'], LineStyle('(', '_', '+', ')')) == '(foo+bar)' - assert _format_line("abc", LineStyle('[', '*', '.', ']')) == '[a.b.c]' - assert _format_line(["_"], LineStyle('o', '', '!', 'o')) == 'o_o' - assert _format_line([], LineStyle(':', '', '', ')')) == ':)' + assert format_line(['foo', 'bar'], LineStyle('(', '_', '+', ')')) == '(foo+bar)' + assert format_line("abc", LineStyle('[', '*', '.', ']')) == '[a.b.c]' + assert format_line(["_"], LineStyle('o', '', '!', 'o')) == 'o_o' + assert format_line([], LineStyle(':', '', '', ')')) == ':)' # using unicode - assert _format_line(['.', '.', '.'], LineStyle('★', '_', '╳', '☆')) == '★.╳.╳.☆' - assert _format_line("☚☛", LineStyle('♪', '*', '♩', '♫')) == '♪☚♩☛♫' + assert format_line(['.', '.', '.'], LineStyle('★', '_', '╳', '☆')) == '★.╳.╳.☆' + assert format_line("☚☛", LineStyle('♪', '*', '♩', '♫')) == '♪☚♩☛♫' def test_humantime(): From a8c196df97654bd60a872c59acddd893a06f57fc Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 15:03:18 -0700 Subject: [PATCH 10/13] removing __name__ from metadata --- setup.py | 2 +- tableprint/metadata.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 645db5f..9257ba1 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ with open(os.path.join(__location__, 'metadata.py'), 'r') as f: setup( - name=metadata['name'], + name='tableprint', url=metadata['url'], version=metadata['version'], diff --git a/tableprint/metadata.py b/tableprint/metadata.py index d67573f..c745d13 100644 --- a/tableprint/metadata.py +++ b/tableprint/metadata.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- # Version info -__name__ = 'tableprint' -__version__ = '0.6.7' +__version__ = '0.6.8' __license__ = 'MIT' # Project description(s) From 721cba721b9565f691ba3822ba79162f6c7bd1ad Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 15:04:49 -0700 Subject: [PATCH 11/13] :bug:fix in metadata.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9257ba1..73fe1a5 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import setup __location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))) -with open(os.path.join(__location__, 'metadata.py'), 'r') as f: +with open(os.path.join(__location__, 'tableprint/metadata.py'), 'r') as f: metadata = dict(re.findall("__([a-z_]+)__\s*=\s*'([^']+)'", f.read())) From c0ce08c5d71a283861fdb9e5e50e1daf4c1456ed Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 15:09:56 -0700 Subject: [PATCH 12/13] fixing unicode 2.7 :bug: --- tableprint/metadata.py | 2 +- tableprint/style.py | 1 + tableprint/utils.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tableprint/metadata.py b/tableprint/metadata.py index c745d13..a0a705b 100644 --- a/tableprint/metadata.py +++ b/tableprint/metadata.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Version info -__version__ = '0.6.8' +__version__ = '0.6.9' __license__ = 'MIT' # Project description(s) diff --git a/tableprint/style.py b/tableprint/style.py index 162295e..35dc92d 100644 --- a/tableprint/style.py +++ b/tableprint/style.py @@ -2,6 +2,7 @@ """ Table styles """ +from __future__ import print_function, unicode_literals from collections import namedtuple __all__ = ('STYLES', 'LineStyle', 'TableStyle') diff --git a/tableprint/utils.py b/tableprint/utils.py index 4efe295..9dd4e1d 100644 --- a/tableprint/utils.py +++ b/tableprint/utils.py @@ -2,6 +2,7 @@ """ Tableprint utilities """ +from __future__ import print_function, unicode_literals import re import numpy as np From cdcdf87d8e7778bb463a66c6b40f1d822b4f8ae8 Mon Sep 17 00:00:00 2001 From: Niru Maheswaranathan Date: Thu, 25 May 2017 15:10:56 -0700 Subject: [PATCH 13/13] Updates README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 265bf72..749b16d 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Hosted at Read The Docs: [tableprint.readthedocs.org](http://tableprint.readthed - `six` ## Version +- 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 - 0.4.0 (May 3 2016) Adds a 'block' style