mirror of
https://github.com/KevinMidboe/tableprint.git
synced 2025-10-29 18:00:16 +00:00
Merge branch 'master' into contextmanager
This commit is contained in:
@@ -3,6 +3,7 @@ python:
|
|||||||
- "2.7"
|
- "2.7"
|
||||||
- "3.4"
|
- "3.4"
|
||||||
- "3.5"
|
- "3.5"
|
||||||
|
- "3.6"
|
||||||
install:
|
install:
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
|
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -14,6 +14,6 @@ test:
|
|||||||
nosetests -v --with-coverage --cover-package=tableprint --logging-level=INFO
|
nosetests -v --with-coverage --cover-package=tableprint --logging-level=INFO
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf tableprint.egg-info
|
rm -R tableprint.egg-info
|
||||||
rm -f *.pyc
|
rm -f tableprint/*.pyc
|
||||||
rm -rf __pycache__
|
rm -R tableprint/__pycache__/
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ Hosted at Read The Docs: [tableprint.readthedocs.org](http://tableprint.readthed
|
|||||||
- `six`
|
- `six`
|
||||||
|
|
||||||
## Version
|
## 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.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.4.0 (May 3 2016) Adds a 'block' style
|
||||||
- 0.3.2 (May 3 2016) Adds a test suite
|
- 0.3.2 (May 3 2016) Adds a test suite
|
||||||
|
|||||||
35
setup.py
35
setup.py
@@ -1,29 +1,29 @@
|
|||||||
|
import re
|
||||||
|
import os
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
|
|
||||||
|
__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
|
||||||
|
with open(os.path.join(__location__, 'tableprint/metadata.py'), 'r') as f:
|
||||||
|
metadata = dict(re.findall("__([a-z_]+)__\s*=\s*'([^']+)'", f.read()))
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='tableprint',
|
name='tableprint',
|
||||||
|
url=metadata['url'],
|
||||||
|
version=metadata['version'],
|
||||||
|
|
||||||
# Versions should comply with PEP440. For a discussion on single-sourcing
|
author=metadata['author'],
|
||||||
# the version across setup.py and the project code, see
|
author_email=metadata['author_email'],
|
||||||
# https://packaging.python.org/en/latest/single_source_version.html
|
|
||||||
version='0.6.1',
|
|
||||||
|
|
||||||
description='Pretty console printing of tabular data',
|
license=metadata['license'],
|
||||||
|
|
||||||
|
description=metadata['description'],
|
||||||
long_description='''Formatted console printing of tabular data.
|
long_description='''Formatted console printing of tabular data.
|
||||||
tableprint lets you easily print formatted tables of data.
|
tableprint lets you easily print formatted tables of data.
|
||||||
Unlike other modules, you can print single rows of data at a time
|
Unlike other modules, you can print single rows of data at a time
|
||||||
(useful for printing ongoing computation results).''',
|
(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',
|
|
||||||
|
|
||||||
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
||||||
classifiers=[
|
classifiers=[
|
||||||
# How mature is this project? Common values are
|
# How mature is this project? Common values are
|
||||||
@@ -44,6 +44,7 @@ setup(
|
|||||||
'Programming Language :: Python :: 2.7',
|
'Programming Language :: Python :: 2.7',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.4',
|
||||||
'Programming Language :: Python :: 3.5',
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
],
|
],
|
||||||
|
|
||||||
# What does your project relate to?
|
# What does your project relate to?
|
||||||
@@ -51,8 +52,7 @@ setup(
|
|||||||
|
|
||||||
# You can just specify the packages manually here if your project is
|
# You can just specify the packages manually here if your project is
|
||||||
# simple. Or you can use find_packages().
|
# simple. Or you can use find_packages().
|
||||||
packages=[],
|
packages=['tableprint'],
|
||||||
py_modules=['tableprint'],
|
|
||||||
|
|
||||||
# List run-time dependencies here. These will be installed by pip when your
|
# 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
|
# project is installed. For an analysis of "install_requires" vs pip's
|
||||||
@@ -67,5 +67,4 @@ setup(
|
|||||||
'dev': [],
|
'dev': [],
|
||||||
'test': ['pytest', 'coverage'],
|
'test': ['pytest', 'coverage'],
|
||||||
},
|
},
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
8
tableprint/__init__.py
Normal file
8
tableprint/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Tableprint
|
||||||
|
"""
|
||||||
|
from .metadata import __author__, __version__
|
||||||
|
from .printer import *
|
||||||
|
from .style import *
|
||||||
|
from .utils import *
|
||||||
15
tableprint/metadata.py
Normal file
15
tableprint/metadata.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Version info
|
||||||
|
__version__ = '0.6.9'
|
||||||
|
__license__ = 'MIT'
|
||||||
|
|
||||||
|
# Project description(s)
|
||||||
|
__description__ = 'Pretty console printing of tabular data'
|
||||||
|
|
||||||
|
# The project's main homepage.
|
||||||
|
__url__ = 'https://github.com/nirum/tableprint'
|
||||||
|
|
||||||
|
# Author details
|
||||||
|
__author__ = 'Niru Maheswaranathan'
|
||||||
|
__author_email__ = 'niru@fastmail.com'
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Tableprint
|
Table printing
|
||||||
|
|
||||||
A module to print and display formatted tables of data
|
A module to print and display formatted tables of data
|
||||||
|
|
||||||
@@ -11,58 +11,18 @@ Usage
|
|||||||
>>> tableprint.table(data, headers)
|
>>> tableprint.table(data, headers)
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function, unicode_literals
|
from __future__ import print_function, unicode_literals
|
||||||
from six import string_types
|
|
||||||
from collections import namedtuple
|
|
||||||
from numbers import Number
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
from numbers import Number
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from six import string_types
|
||||||
|
|
||||||
__all__ = ('table', 'header', 'row', 'hr', 'top', 'bottom',
|
from .style import LineStyle, STYLES
|
||||||
'banner', 'dataframe', 'humantime', 'styles')
|
from .utils import ansi_len, format_line
|
||||||
__version__ = '0.5.4'
|
|
||||||
|
__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'
|
STYLE = 'round'
|
||||||
WIDTH = 11
|
WIDTH = 11
|
||||||
FMT = '5g'
|
FMT = '5g'
|
||||||
@@ -130,10 +90,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)
|
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)
|
ncols = len(data[0]) if headers is None else len(headers)
|
||||||
tablestyle = styles[style]
|
tablestyle = STYLES[style]
|
||||||
|
|
||||||
# Initialize with a hr or the header
|
# 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)]
|
if headers is None else [header(headers, width, style)]
|
||||||
|
|
||||||
# parse each row
|
# parse each row
|
||||||
@@ -141,7 +101,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
|
# only add the final border if there was data in the table
|
||||||
if len(data) > 0:
|
if len(data) > 0:
|
||||||
tablestr += [hr(ncols, width, tablestyle.bottom)]
|
tablestr += [hrule(ncols, width, tablestyle.bottom)]
|
||||||
|
|
||||||
# print the table
|
# print the table
|
||||||
out.write('\n'.join(tablestr) + '\n')
|
out.write('\n'.join(tablestr) + '\n')
|
||||||
@@ -160,24 +120,24 @@ def header(headers, width=WIDTH, style=STYLE, add_hr=True):
|
|||||||
The width of each column (Default: 11)
|
The width of each column (Default: 11)
|
||||||
|
|
||||||
style : string or tuple, optional
|
style : string or tuple, optional
|
||||||
A formatting style (see styles)
|
A formatting style (see STYLES)
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
headerstr : string
|
headerstr : string
|
||||||
A string consisting of the full header row to print
|
A string consisting of the full header row to print
|
||||||
"""
|
"""
|
||||||
tablestyle = styles[style]
|
tablestyle = STYLES[style]
|
||||||
|
|
||||||
# string formatter
|
# 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
|
# build the formatted str
|
||||||
headerstr = _format_line(data, tablestyle.row)
|
headerstr = format_line(data, tablestyle.row)
|
||||||
|
|
||||||
if add_hr:
|
if add_hr:
|
||||||
upper = hr(len(headers), width, tablestyle.top)
|
upper = hrule(len(headers), width, tablestyle.top)
|
||||||
lower = hr(len(headers), width, tablestyle.below_header)
|
lower = hrule(len(headers), width, tablestyle.below_header)
|
||||||
headerstr = '\n'.join([upper, headerstr, lower])
|
headerstr = '\n'.join([upper, headerstr, lower])
|
||||||
|
|
||||||
return headerstr
|
return headerstr
|
||||||
@@ -205,9 +165,9 @@ def row(values, width=WIDTH, format_spec=FMT, style=STYLE):
|
|||||||
rowstr : string
|
rowstr : string
|
||||||
A string consisting of the full row of data to print
|
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"
|
"format_spec must be a string or list of strings"
|
||||||
|
|
||||||
if isinstance(format_spec, string_types):
|
if isinstance(format_spec, string_types):
|
||||||
@@ -220,7 +180,7 @@ def row(values, width=WIDTH, format_spec=FMT, style=STYLE):
|
|||||||
datum, prec = val
|
datum, prec = val
|
||||||
|
|
||||||
if isinstance(datum, string_types):
|
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):
|
elif isinstance(datum, Number):
|
||||||
return ('{:>%i.%s}' % (width, prec)).format(datum)
|
return ('{:>%i.%s}' % (width, prec)).format(datum)
|
||||||
@@ -232,10 +192,10 @@ def row(values, width=WIDTH, format_spec=FMT, style=STYLE):
|
|||||||
data = map(mapdata, zip(values, format_spec))
|
data = map(mapdata, zip(values, format_spec))
|
||||||
|
|
||||||
# build the row string
|
# 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
|
"""Returns a formatted string used as a border between table rows
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@@ -261,12 +221,12 @@ def hr(n, width=WIDTH, linestyle=LineStyle('', '─', '─', '')):
|
|||||||
|
|
||||||
def top(n, width=WIDTH, style=STYLE):
|
def top(n, width=WIDTH, style=STYLE):
|
||||||
"""Prints the top row of a table"""
|
"""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):
|
def bottom(n, width=WIDTH, style=STYLE):
|
||||||
"""Prints the top row of a table"""
|
"""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):
|
def banner(message, width=30, style='banner', out=sys.stdout):
|
||||||
@@ -299,70 +259,3 @@ def dataframe(df, **kwargs):
|
|||||||
A pandas DataFrame with the table to print
|
A pandas DataFrame with the table to print
|
||||||
"""
|
"""
|
||||||
table(np.array(df), list(df.columns), **kwargs)
|
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
|
|
||||||
49
tableprint/style.py
Normal file
49
tableprint/style.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Table styles
|
||||||
|
"""
|
||||||
|
from __future__ import print_function, unicode_literals
|
||||||
|
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(' ', '', ' ', ' '),
|
||||||
|
),
|
||||||
|
}
|
||||||
76
tableprint/utils.py
Normal file
76
tableprint/utils.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Tableprint utilities
|
||||||
|
"""
|
||||||
|
from __future__ import print_function, unicode_literals
|
||||||
|
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
|
||||||
@@ -5,6 +5,7 @@ import pytest
|
|||||||
|
|
||||||
|
|
||||||
def test_borders():
|
def test_borders():
|
||||||
|
"""Tests printing of the top and bottom borders"""
|
||||||
|
|
||||||
# top
|
# top
|
||||||
assert top(5, width=2, style='round') == '╭──┬──┬──┬──┬──╮'
|
assert top(5, width=2, style='round') == '╭──┬──┬──┬──┬──╮'
|
||||||
@@ -16,11 +17,12 @@ def test_borders():
|
|||||||
|
|
||||||
|
|
||||||
def test_row():
|
def test_row():
|
||||||
|
"""Tests printing of a single row of data"""
|
||||||
|
|
||||||
# valid
|
# valid
|
||||||
assert row("abc", width=3, style='round') == '│ a│ b│ c│'
|
assert row("abc", width=3, style='round') == '│ a│ b│ c│'
|
||||||
assert row([1, 2, 3], width=3, style='clean') == ' 1 2 3 '
|
assert row([1, 2, 3], width=3, style='clean') == ' 1 2 3 '
|
||||||
|
|
||||||
# invalid
|
# invalid
|
||||||
with pytest.raises(ValueError) as context:
|
with pytest.raises(ValueError):
|
||||||
row([{}])
|
row([{}])
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from tableprint import table, banner, dataframe, hr
|
from tableprint import table, banner, dataframe, hrule
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ def test_frame():
|
|||||||
def __init__(self, data, headers):
|
def __init__(self, data, headers):
|
||||||
self.data = data
|
self.data = data
|
||||||
self.columns = headers
|
self.columns = headers
|
||||||
|
|
||||||
def __array__(self):
|
def __array__(self):
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
@@ -44,8 +45,8 @@ def test_banner():
|
|||||||
assert output.getvalue() == '╒═╕\n│!│\n╘═╛\n'
|
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 len(output) == 11
|
||||||
assert '───────────'
|
assert '───────────'
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
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
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
def test_format_line():
|
def test_format_line():
|
||||||
|
|
||||||
# using ASCII
|
# using ASCII
|
||||||
assert _format_line(['foo', 'bar'], LineStyle('(', '_', '+', ')')) == '(foo+bar)'
|
assert format_line(['foo', 'bar'], LineStyle('(', '_', '+', ')')) == '(foo+bar)'
|
||||||
assert _format_line("abc", LineStyle('[', '*', '.', ']')) == '[a.b.c]'
|
assert format_line("abc", LineStyle('[', '*', '.', ']')) == '[a.b.c]'
|
||||||
assert _format_line(["_"], LineStyle('o', '', '!', 'o')) == 'o_o'
|
assert format_line(["_"], LineStyle('o', '', '!', 'o')) == 'o_o'
|
||||||
assert _format_line([], LineStyle(':', '', '', ')')) == ':)'
|
assert format_line([], LineStyle(':', '', '', ')')) == ':)'
|
||||||
|
|
||||||
# using unicode
|
# using unicode
|
||||||
assert _format_line(['.', '.', '.'], LineStyle('★', '_', '╳', '☆')) == '★.╳.╳.☆'
|
assert format_line(['.', '.', '.'], LineStyle('★', '_', '╳', '☆')) == '★.╳.╳.☆'
|
||||||
assert _format_line("☚☛", LineStyle('♪', '*', '♩', '♫')) == '♪☚♩☛♫'
|
assert format_line("☚☛", LineStyle('♪', '*', '♩', '♫')) == '♪☚♩☛♫'
|
||||||
|
|
||||||
|
|
||||||
def test_humantime():
|
def test_humantime():
|
||||||
|
|||||||
Reference in New Issue
Block a user