Skip to content

Commit

Permalink
Reorganized with a package to allow typing to work correctly.
Browse files Browse the repository at this point in the history
Changed default abbreviation in examples to avoid conflict with TensorFlow which resolves #45
  • Loading branch information
anselor committed May 1, 2023
1 parent fea430b commit 5649df8
Show file tree
Hide file tree
Showing 20 changed files with 405 additions and 349 deletions.
52 changes: 31 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Many other modules for formatting tabular data require the developer to create a
objects/data into a structure the formatter can consume. One relatively novel aspect of tableformatter is the ability to directly
receive arbitrary Python objects.

[![Screenshot](tf.png)](https://github.com/python-tableformatter/tableformatter/blob/master/tf.png)
[![Screenshot](tablefmt.png)](https://github.com/python-tableformatter/tableformatter/blob/master/tablefmt.png)


## Main Features
Expand Down Expand Up @@ -51,13 +51,13 @@ to this function is ``rows`` which is an Iterable of Iterables such as a list of
a 2D [numpy](http://www.numpy.org) array. ``generate_table`` outputs a nicely formatted table:

```Python
import tableformatter as tf
import tableformatter as tablefmt

rows = [('A1', 'A2', 'A3', 'A4'),
('B1', 'B2\nB2\nB2', 'B3', 'B4'),
('C1', 'C2', 'C3', 'C4'),
('D1', 'D2', 'D3', 'D4')]
print(tf.generate_table(rows))
print(tablefmt.generate_table(rows))
╔════╤════╤════╤════╗
║ A1 │ A2 │ A3 │ A4 ║
║ B1 │ B2 │ B3 │ B4 ║
Expand Down Expand Up @@ -93,7 +93,7 @@ The second argument to ``generate_table`` named ``columns`` is optional and defi

```Python
cols = ['Col1', 'Col2', 'Col3', 'Col4']
print(tf.generate_table(rows, cols))
print(tablefmt.generate_table(rows, cols))
╔══════╤══════╤══════╤══════╗
║ Col1 │ Col2 │ Col3 │ Col4 ║
╠══════╪══════╪══════╪══════╣
Expand All @@ -116,7 +116,7 @@ Supported grid sytles are:
* **SparseGrid** - sparse grid with no lines at all to conserve both vertical and horizontal space

```Python
print(tf.generate_table(rows, grid_style=tf.FancyGrid()))
print(tablefmt.generate_table(rows, grid_style=tablefmt.FancyGrid()))
╔════╤════╤════╤════╗
║ A1 │ A2 │ A3 │ A4 ║
╟────┼────┼────┼────╢
Expand All @@ -137,7 +137,7 @@ this and print "rows" up-to-down and "columns" left-to-right then that is easily
to ``generate_table``:

```Python
print(tf.generate_table(rows, cols, transpose=True))
print(tablefmt.generate_table(rows, cols, transpose=True))
╔══════╦════╤════╤════╤════╗
║ Col1 ║ A1 │ B1 │ C1 │ D1 ║
║ Col2 ║ A2 │ B2 │ C2 │ D2 ║
Expand Down Expand Up @@ -186,11 +186,11 @@ Possible alignments are all elements within the ``ColumnAlignment`` enum class:
* AlignBottom

```Python
columns = (tf.Column('Col1', cell_halign=tf.ColumnAlignment.AlignLeft),
tf.Column('Col2', cell_halign=tf.ColumnAlignment.AlignRight),
tf.Column('Col3', cell_halign=tf.ColumnAlignment.AlignCenter),
tf.Column('Col4', cell_valign=tf.ColumnAlignment.AlignBottom))
print(tf.generate_table(rows, columns))
columns = (tablefmt.Column('Col1', cell_halign=tablefmt.ColumnAlignment.AlignLeft),
tablefmt.Column('Col2', cell_halign=tablefmt.ColumnAlignment.AlignRight),
tablefmt.Column('Col3', cell_halign=tablefmt.ColumnAlignment.AlignCenter),
tablefmt.Column('Col4', cell_valign=tablefmt.ColumnAlignment.AlignBottom))
print(tablefmt.generate_table(rows, columns))
╔══════╤══════╤══════╤══════╗
║ Col1 │ Col2 │ Col3 │ col4 ║
╠══════╪══════╪══════╪══════╣
Expand All @@ -212,26 +212,36 @@ formatting numbers:
* FormatCommas - Formats a number with comma separators

```Python
import tableformatter.formatters

rows = [(None, None),
('123', '123'),
(123, 123),
(12345, 12345),
(12345678, 12345678),
(1234567890, 1234567890),
(1234567890123, 1234567890123)]
cols = (tf.Column('First', width=20, formatter=tf.FormatBytes(), cell_halign=tf.ColumnAlignment.AlignRight),
tf.Column('Second', formatter=tf.FormatCommas(), cell_halign=tf.ColumnAlignment.AlignRight))
print(tf.generate_table(rows, cols))
cols = (tablefmt.Column('First', width=20, formatter=tableformatter.formatters.FormatBytes(),
cell_halign=tablefmt.ColumnAlignment.AlignRight),
tablefmt.Column('Second', formatter=tableformatter.formatters.FormatCommas(),
cell_halign=tablefmt.ColumnAlignment.AlignRight))
print(tablefmt.generate_table(rows, cols))
╔═══════════╤═══════════════════╗
║ First │ Second ║
╠═══════════╪═══════════════════╣
║ │ ║
123.00 B │ 123
123.00 B │ 123
12.06 KB12,345
11.77 MB12,345,678
1.15 GB1,234,567,890
1.12 TB1,234,567,890,123
123.00
B │ 123
123.00
B │ 123
12.06
KB12, 345
11.77
MB12, 345, 678
1.15
GB1, 234, 567, 890
1.12
TB1, 234, 567, 890, 123
╚═══════════╧═══════════════════╝
```

Expand All @@ -247,7 +257,7 @@ and background color of cell contents.
It is trivial to alternate the background color of each row as follows:
```Python
from colorama import Back
print(generate_table(rows, cols, grid_style=tf.AlternatingRowGrid(Back.GREEN, Back.BLUE)))
print(generate_table(rows, cols, grid_style=tablefmt.AlternatingRowGrid(Back.GREEN, Back.BLUE)))
```
See the [cmd2_tables.py](https://github.com/python-tableformatter/tableformatter/blob/master/examples/cmd2_tables.py) or
[color.py](https://github.com/python-tableformatter/tableformatter/blob/master/examples/color.py) examples for more
Expand Down
59 changes: 33 additions & 26 deletions examples/cmd2_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
from typing import Tuple

import cmd2
import tableformatter as tf
import tableformatter as tablefmt

# Configure colors for when users chooses the "-c" flag to enable color in the table output
import tableformatter.formatters

try:
from colored import bg

Expand Down Expand Up @@ -73,15 +75,17 @@ def two_dec(num: float) -> str:
row.append(row[-2] / row[-1])

# Column headers plus optional formatting info for each column
COLUMNS = [tf.Column('City', width=11, header_halign=tf.ColumnAlignment.AlignCenter),
tf.Column('Province', header_halign=tf.ColumnAlignment.AlignCenter),
COLUMNS = [tablefmt.Column('City', width=11, header_halign=tablefmt.ColumnAlignment.AlignCenter),
tablefmt.Column('Province', header_halign=tablefmt.ColumnAlignment.AlignCenter),
'Country', # NOTE: If you don't need any special effects, you can just pass a string
tf.Column('Continent', cell_halign=tf.ColumnAlignment.AlignCenter),
tf.Column('Population', cell_halign=tf.ColumnAlignment.AlignRight, formatter=tf.FormatCommas()),
tf.Column('Area (km²)', width=7, header_halign=tf.ColumnAlignment.AlignCenter,
cell_halign=tf.ColumnAlignment.AlignRight, formatter=two_dec),
tf.Column('Pop. Density (/km²)', width=12, header_halign=tf.ColumnAlignment.AlignCenter,
cell_halign=tf.ColumnAlignment.AlignRight, formatter=no_dec),
tablefmt.Column('Continent', cell_halign=tablefmt.ColumnAlignment.AlignCenter),
tablefmt.Column('Population',
cell_halign=tablefmt.ColumnAlignment.AlignRight,
formatter=tableformatter.formatters.FormatCommas()),
tablefmt.Column('Area (km²)', width=7, header_halign=tablefmt.ColumnAlignment.AlignCenter,
cell_halign=tablefmt.ColumnAlignment.AlignRight, formatter=two_dec),
tablefmt.Column('Pop. Density (/km²)', width=12, header_halign=tablefmt.ColumnAlignment.AlignCenter,
cell_halign=tablefmt.ColumnAlignment.AlignRight, formatter=no_dec),
]


Expand Down Expand Up @@ -123,16 +127,19 @@ def pop_density(data: CityInfo) -> str:
# If table entries are python objects, all columns must be defined with the object attribute to query for each field
# - attributes can be fields or functions. If a function is provided, the formatter will automatically call
# the function to retrieve the value
OBJ_COLS = [tf.Column('City', attrib='city', header_halign=tf.ColumnAlignment.AlignCenter),
tf.Column('Province', attrib='province', header_halign=tf.ColumnAlignment.AlignCenter),
tf.Column('Country', attrib='country'),
tf.Column('Continent', attrib='continent', cell_halign=tf.ColumnAlignment.AlignCenter),
tf.Column('Population', attrib='get_population', cell_halign=tf.ColumnAlignment.AlignRight,
formatter=tf.FormatCommas()),
tf.Column('Area (km²)', attrib='get_area', width=7, header_halign=tf.ColumnAlignment.AlignCenter,
cell_halign=tf.ColumnAlignment.AlignRight, formatter=two_dec),
tf.Column('Pop. Density (/km²)', width=12, header_halign=tf.ColumnAlignment.AlignCenter,
cell_halign=tf.ColumnAlignment.AlignRight, obj_formatter=pop_density),
OBJ_COLS = [tablefmt.Column('City', attrib='city', header_halign=tablefmt.ColumnAlignment.AlignCenter),
tablefmt.Column('Province', attrib='province', header_halign=tablefmt.ColumnAlignment.AlignCenter),
tablefmt.Column('Country', attrib='country'),
tablefmt.Column('Continent', attrib='continent', cell_halign=tablefmt.ColumnAlignment.AlignCenter),
tablefmt.Column('Population', attrib='get_population', cell_halign=tablefmt.ColumnAlignment.AlignRight,
formatter=tableformatter.formatters.FormatCommas()),
tablefmt.Column('Area (km²)',
attrib='get_area',
width=7,
header_halign=tablefmt.ColumnAlignment.AlignCenter,
cell_halign=tablefmt.ColumnAlignment.AlignRight, formatter=two_dec),
tablefmt.Column('Pop. Density (/km²)', width=12, header_halign=tablefmt.ColumnAlignment.AlignCenter,
cell_halign=tablefmt.ColumnAlignment.AlignRight, obj_formatter=pop_density),
]

EXTREMELY_HIGH_POULATION_DENSITY = 25000
Expand All @@ -142,15 +149,15 @@ def high_density_tuples(row_tuple: Tuple) -> dict:
"""Color rows with extremely high population density red."""
opts = dict()
if len(row_tuple) >= 7 and row_tuple[6] > EXTREMELY_HIGH_POULATION_DENSITY:
opts[tf.TableFormatter.ROW_OPT_TEXT_COLOR] = tf.TableColors.TEXT_COLOR_RED
opts[tablefmt.TableFormatter.ROW_OPT_TEXT_COLOR] = tablefmt.TableColors.TEXT_COLOR_RED
return opts


def high_density_objs(row_obj: CityInfo) -> dict:
"""Color rows with extremely high population density red."""
opts = dict()
if float(pop_density(row_obj)) > EXTREMELY_HIGH_POULATION_DENSITY:
opts[tf.TableFormatter.ROW_OPT_TEXT_COLOR] = tf.TableColors.TEXT_COLOR_RED
opts[tablefmt.TableFormatter.ROW_OPT_TEXT_COLOR] = tablefmt.TableColors.TEXT_COLOR_RED
return opts


Expand All @@ -170,20 +177,20 @@ def ptable(self, rows, columns, grid_args, row_stylist):
:param row_stylist: function to determine how each row gets styled
"""
if grid_args.color:
grid = tf.AlternatingRowGrid(BACK_PRI, BACK_ALT)
grid = tablefmt.AlternatingRowGrid(BACK_PRI, BACK_ALT)
elif grid_args.fancy:
grid = tf.FancyGrid()
grid = tablefmt.FancyGrid()
elif grid_args.sparse:
grid = tf.SparseGrid()
grid = tablefmt.SparseGrid()
else:
grid = None

transpose = False
if grid_args.transpose:
transpose = True

formatted_table = tf.generate_table(rows=rows, columns=columns, grid_style=grid, row_tagger=row_stylist,
transpose=transpose)
formatted_table = tablefmt.generate_table(rows=rows, columns=columns, grid_style=grid, row_tagger=row_stylist,
transpose=transpose)
self.ppaged(formatted_table, chop=True)

table_parser = argparse.ArgumentParser()
Expand Down
4 changes: 2 additions & 2 deletions examples/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
Simple demonstration of TableFormatter with some colored output.
"""
import tableformatter as tf
import tableformatter as tablefmt
from tableformatter import generate_table

try:
Expand All @@ -30,4 +30,4 @@
columns = ('Col1', 'Col2', 'Col3', 'Col4')

print("Table with colorful alternating rows")
print(generate_table(rows, columns, grid_style=tf.AlternatingRowGrid(BACK_GREEN, BACK_BLUE)))
print(generate_table(rows, columns, grid_style=tablefmt.AlternatingRowGrid(BACK_GREEN, BACK_BLUE)))
86 changes: 43 additions & 43 deletions examples/columns.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
Demonstration of all of the per-Column customizations that are available.
"""
import tableformatter as tf
import tableformatter as tablefmt


class MyRowObject(object):
Expand Down Expand Up @@ -75,70 +75,70 @@ def int2word(num, separator="-"):
MyRowObject('D1', 'D2', 7, 5)]


columns = (tf.Column('First', width=20, attrib='field1'),
tf.Column('Second', attrib='field2'),
tf.Column('Num 1', width=3, attrib='get_field3'),
tf.Column('Num 2', attrib='field4'),
tf.Column('Multiplied', obj_formatter=multiply))
columns = (tablefmt.Column('First', width=20, attrib='field1'),
tablefmt.Column('Second', attrib='field2'),
tablefmt.Column('Num 1', width=3, attrib='get_field3'),
tablefmt.Column('Num 2', attrib='field4'),
tablefmt.Column('Multiplied', obj_formatter=multiply))
print("First: Wrapped\nMultiplied: object formatter")
print(tf.generate_table(rows, columns))
print(tablefmt.generate_table(rows, columns))


columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.WRAP_WITH_INDENT),
tf.Column('Second', attrib='field2'),
tf.Column('Num 1', width=3, attrib='get_field3', header_halign=tf.ColumnAlignment.AlignCenter),
tf.Column('Num 2', attrib='field4'),
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
columns = (tablefmt.Column('First', width=20, attrib='field1', wrap_mode=tablefmt.WrapMode.WRAP_WITH_INDENT),
tablefmt.Column('Second', attrib='field2'),
tablefmt.Column('Num 1', width=3, attrib='get_field3', header_halign=tablefmt.ColumnAlignment.AlignCenter),
tablefmt.Column('Num 2', attrib='field4'),
tablefmt.Column('Multiplied', attrib=None, obj_formatter=multiply))
print("First: Wrapped with indent\nNum 1: header align center")
print(tf.generate_table(rows, columns))
print(tablefmt.generate_table(rows, columns))


columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.WRAP_WITH_INDENT,
columns = (tablefmt.Column('First', width=20, attrib='field1', wrap_mode=tablefmt.WrapMode.WRAP_WITH_INDENT,
wrap_prefix='>>> '),
tf.Column('Second', attrib='field2', cell_halign=tf.ColumnAlignment.AlignCenter),
tf.Column('Num 1', width=3, attrib='get_field3', header_halign=tf.ColumnAlignment.AlignRight),
tf.Column('Num 2', attrib='field4', header_valign=tf.ColumnAlignment.AlignTop),
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
tablefmt.Column('Second', attrib='field2', cell_halign=tablefmt.ColumnAlignment.AlignCenter),
tablefmt.Column('Num 1', width=3, attrib='get_field3', header_halign=tablefmt.ColumnAlignment.AlignRight),
tablefmt.Column('Num 2', attrib='field4', header_valign=tablefmt.ColumnAlignment.AlignTop),
tablefmt.Column('Multiplied', attrib=None, obj_formatter=multiply))
print("First: Wrapped with indent, custom wrap prefix\n"
"Second: Header align center\n"
"Num 1: header align right\n"
"Num 2: header align top")
print(tf.generate_table(rows, columns))
print(tablefmt.generate_table(rows, columns))


columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_END),
tf.Column('Second', attrib='field2', cell_padding=3),
tf.Column('Num 1', width=3, attrib='get_field3'),
tf.Column('Num 2', attrib='field4'),
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
columns = (tablefmt.Column('First', width=20, attrib='field1', wrap_mode=tablefmt.WrapMode.TRUNCATE_END),
tablefmt.Column('Second', attrib='field2', cell_padding=3),
tablefmt.Column('Num 1', width=3, attrib='get_field3'),
tablefmt.Column('Num 2', attrib='field4'),
tablefmt.Column('Multiplied', attrib=None, obj_formatter=multiply))
print("First: Truncate end\n"
"Second: cell padding 3 spaces")
print(tf.generate_table(rows, columns))
print(tablefmt.generate_table(rows, columns))


columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_FRONT),
tf.Column('Second', attrib='field2', cell_padding=5, cell_halign=tf.ColumnAlignment.AlignRight),
tf.Column('Num 1', attrib='get_field3'),
tf.Column('Num 2', attrib='field4'),
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
columns = (tablefmt.Column('First', width=20, attrib='field1', wrap_mode=tablefmt.WrapMode.TRUNCATE_FRONT),
tablefmt.Column('Second', attrib='field2', cell_padding=5, cell_halign=tablefmt.ColumnAlignment.AlignRight),
tablefmt.Column('Num 1', attrib='get_field3'),
tablefmt.Column('Num 2', attrib='field4'),
tablefmt.Column('Multiplied', attrib=None, obj_formatter=multiply))
print("First; Truncate Front\n"
"Second: cell align right, cell padding=5")
print(tf.generate_table(rows, columns))
print(tablefmt.generate_table(rows, columns))


columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_MIDDLE),
tf.Column('Second', attrib='field2'),
tf.Column('Num 1', attrib='get_field3'),
tf.Column('Num 2', attrib='field4', cell_valign=tf.ColumnAlignment.AlignBottom),
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
columns = (tablefmt.Column('First', width=20, attrib='field1', wrap_mode=tablefmt.WrapMode.TRUNCATE_MIDDLE),
tablefmt.Column('Second', attrib='field2'),
tablefmt.Column('Num 1', attrib='get_field3'),
tablefmt.Column('Num 2', attrib='field4', cell_valign=tablefmt.ColumnAlignment.AlignBottom),
tablefmt.Column('Multiplied', attrib=None, obj_formatter=multiply))
print("First: Truncate Middle\nNum 2: cell align bottom")
print(tf.generate_table(rows, columns))
print(tablefmt.generate_table(rows, columns))


columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_HARD),
tf.Column('Second', attrib='field2'),
tf.Column('Num 1', attrib='get_field3'),
tf.Column('Num 2', attrib='field4', formatter=int2word),
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
columns = (tablefmt.Column('First', width=20, attrib='field1', wrap_mode=tablefmt.WrapMode.TRUNCATE_HARD),
tablefmt.Column('Second', attrib='field2'),
tablefmt.Column('Num 1', attrib='get_field3'),
tablefmt.Column('Num 2', attrib='field4', formatter=int2word),
tablefmt.Column('Multiplied', attrib=None, obj_formatter=multiply))
print("First: Truncate Hard\nNum 2: Field formatter")
print(tf.generate_table(rows, columns))
print(tablefmt.generate_table(rows, columns))
Loading

0 comments on commit 5649df8

Please sign in to comment.