Created
December 26, 2016 09:39
-
-
Save deanishe/62e0d31fe0344f3d4f9b939ef6864a03 to your computer and use it in GitHub Desktop.
Simple table printer for shell output
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# encoding: utf-8 | |
# | |
# Copyright (c) 2016 Dean Jackson <[email protected]> | |
# | |
# MIT Licence. See http://opensource.org/licenses/MIT | |
# | |
# Created on 2016-12-19 | |
# | |
"""Text table. | |
Nicely-formatted text table for the terminal. Smart alignment of numbers. | |
""" | |
from __future__ import print_function, absolute_import | |
import re | |
def unicodify(obj): | |
if isinstance(obj, unicode): | |
return obj | |
if isinstance(obj, str): | |
return obj.decode('utf-8') | |
return unicode(obj) | |
class Table(object): | |
def __init__(self, titles=None): | |
self.centred_titles = True | |
self.rows = [] | |
self._titlerows = [] | |
self._size = 0 | |
if titles: | |
self.add_row(titles, True) | |
def add_row(self, row, title=False): | |
self.rows.append(row) | |
if title: | |
self._titlerows.append(True) | |
else: | |
self._titlerows.append(False) | |
def __unicode__(self): | |
# Calculate column parameters | |
ncols = max([len(r) for r in self.rows]) | |
widths = [0] * ncols # width of each column | |
formats = [None] * ncols # format string for each column | |
# calculate column widths | |
for r in self.rows: | |
for i, n in enumerate([len(unicodify(c)) for c in r]): | |
widths[i] = max([widths[i], n]) | |
# Widget | |
hr = [(u'-' * w) for w in widths] | |
hr = u'---'.join(hr) | |
# Get row data formatted to length | |
lines = [] | |
for y, r in enumerate(self.rows): | |
title = self._titlerows[y] | |
objs = list(r) | |
while len(objs) < ncols: # Ensure row is long enough | |
objs.append(u'') | |
# Format each cell | |
data = [] | |
for i, o in enumerate(objs): | |
u = unicodify(o) | |
w = widths[i] | |
# Column formatting | |
# left-align by default | |
fmt = u'{{:{}s}}'.format(w) | |
if title and self.centred_titles: # centre-align titles | |
fmt = u'{{:^{}s}}'.format(w) | |
elif u.strip(): # Use or determine default for this column | |
if formats[i]: | |
fmt = formats[i] | |
elif re.match(r'[$€£]?\s*[0-9,.% ]+', u): # number | |
fmt = u'{{:>{}s}}'.format(w) | |
# Save as default for this column | |
formats[i] = fmt | |
u = fmt.format(u) | |
data.append(u) | |
# Combine cells into text for row | |
u = u' | '.join(data) | |
lines.append(u) | |
if title: | |
lines.append(hr) | |
return u'\n'.join([s.rstrip() for s in lines]) | |
def __str__(self): | |
return self.__unicode__().encode('utf-8') | |
if __name__ == '__main__': | |
data = [ | |
('Dave Smith', 22, 'carpenter'), | |
('Ronald McDonald', 7, 'schoolboy'), | |
('Davy Jones', 57, 'boxer'), | |
('Reggie Becker', 83), | |
('Ricky Bobby', 28, 'racing driver', 'fraud'), | |
('Spanish Harlan', 22, 'DJ', '100', '$30'), | |
('Fast Howie', 42, 'gunfighter', '27 kills', 'dolla dolla'), | |
] | |
t = Table(titles=['Name', 'Current Age', 'Occupation']) | |
for row in data: | |
t.add_row(row) | |
print(t) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment