Package: txtble
GitHub|PyPI|Issues|ChangelogContentsInstallationExamplesAPITxtbleConfiguration OptionsBorderStyleOthertxtbleis yet another Python library for creating plain-text tables.  (All
the good names were taken, OK?)  Pass in a list of lists of strings (or other
stringable things) and get out something nice like:+---------+----------+------------------+
|Month    |Birthstone|Birth Flower      |
+---------+----------+------------------+
|January  |Garnet    |Carnation         |
|February |Amethyst  |Violet            |
|March    |Aquamarine|Jonquil           |
|April    |Diamond   |Sweetpea          |
|May      |Emerald   |Lily Of The Valley|
|June     |Pearl     |Rose              |
|July     |Ruby      |Larkspur          |
|August   |Peridot   |Gladiolus         |
|September|Sapphire  |Aster             |
|October  |Opal      |Calendula         |
|November |Topaz     |Chrysanthemum     |
|December |Turquoise |Narcissus         |
+---------+----------+------------------+Features:Rows can be passed as lists ordictsANSI color awareUnicode fullwidth & combining character awareControl the horizontal (left, center, & right) and vertical (top, middle, &
bottom) alignment of textAlign numbers along their decimal pointsCustomize characters used for drawing bordersToggle inter-row, inter-column, and outer bordersSet the value used to fill out ragged rowsPad cells on the left & rightSet column widths, with long lines wrapped to fitConfigure howNonevalues are displayedType annotationsInstallationtxtblerequires Python 3.7 or higher.  Just usepipfor Python 3 (You have pip, right?) to installtxtbleand its dependencies:python3 -m pip install txtbleExamplesConstruct & show a basic table:>>> from txtble import Txtble
>>> # Taken from /usr/share/misc/birthtoken.gz in Ubuntu Xenial's miscfiles package:
>>> HEADERS = ['Month', 'Birthstone', 'Birth Flower']
>>> DATA = [
...     ['January',   'Garnet',     'Carnation'],
...     ['February',  'Amethyst',   'Violet'],
...     ['March',     'Aquamarine', 'Jonquil'],
...     ['April',     'Diamond',    'Sweetpea'],
...     ['May',       'Emerald',    'Lily Of The Valley'],
...     ['June',      'Pearl',      'Rose'],
...     ['July',      'Ruby',       'Larkspur'],
...     ['August',    'Peridot',    'Gladiolus'],
...     ['September', 'Sapphire',   'Aster'],
...     ['October',   'Opal',       'Calendula'],
...     ['November',  'Topaz',      'Chrysanthemum'],
...     ['December',  'Turquoise',  'Narcissus'],
... ]
>>> tbl = Txtble(DATA, headers=HEADERS)
>>> print(tbl)
+---------+----------+------------------+
|Month    |Birthstone|Birth Flower      |
+---------+----------+------------------+
|January  |Garnet    |Carnation         |
|February |Amethyst  |Violet            |
|March    |Aquamarine|Jonquil           |
|April    |Diamond   |Sweetpea          |
|May      |Emerald   |Lily Of The Valley|
|June     |Pearl     |Rose              |
|July     |Ruby      |Larkspur          |
|August   |Peridot   |Gladiolus         |
|September|Sapphire  |Aster             |
|October  |Opal      |Calendula         |
|November |Topaz     |Chrysanthemum     |
|December |Turquoise |Narcissus         |
+---------+----------+------------------+The table can also be constructed like this:>>> tbl = Txtble(headers=HEADERS)
>>> tbl.extend(DATA)Or like this:>>> tbl = Txtble(headers=HEADERS)
>>> for row in DATA:
...     tbl.append(row)Or even like this:>>> tbl = Txtble(DATA)
>>> tbl.headers = HEADERSThe rows of the table can be lists of values (as seen above) ordicts that
map header names to values:>>> tbl = Txtble(
...     headers = ["Red", "Green", "Blue"],
...     data    = [
...         {"Red": "Ruby", "Green": "Emerald", "Blue": "Sapphire"},
...         {"Red": "Fire", "Green": "Earth",   "Blue": "Water"},
...     ],
... )
>>> print(tbl)
+----+-------+--------+
|Red |Green  |Blue    |
+----+-------+--------+
|Ruby|Emerald|Sapphire|
|Fire|Earth  |Water   |
+----+-------+--------+Missingdictkeys can be filled in with thedict_filloption (Without it,
you’d get aKeyErrorhere):>>> tbl = Txtble(
...     headers = ["Red", "Green", "Blue"],
...     data    = [
...         {"Red": "Ruby", "Green": "Emerald", "Blue": "Sapphire"},
...         {"Red": "Fire", "Green": "Earth",   "Blue": "Water"},
...         {"Red": "Hot",                      "Blue": "Cold"},
...     ],
...     dict_fill = 'UNKNOWN',
... )
>>> print(tbl)
+----+-------+--------+
|Red |Green  |Blue    |
+----+-------+--------+
|Ruby|Emerald|Sapphire|
|Fire|Earth  |Water   |
|Hot |UNKNOWN|Cold    |
+----+-------+--------+The number of columns is automatically set to the length of the longest row:>>> tbl = Txtble([
...     ['1', '1'],
...     ['Z_6', '1', 'x', 'x^2', 'x^3', 'x^4', 'x^5'],
...     ['S_3', '1', 'a', 'b', 'aba', 'ba', 'ab'],
...     ['Z_4', '1', 'x', 'x^2', 'x^3'],
...     ['V_4', '1', 'a', 'b', 'ab'],
... ])
>>> print(tbl)
+---+-+-+---+---+---+---+
|1  |1| |   |   |   |   |
|Z_6|1|x|x^2|x^3|x^4|x^5|
|S_3|1|a|b  |aba|ba |ab |
|Z_4|1|x|x^2|x^3|   |   |
|V_4|1|a|b  |ab |   |   |
+---+-+-+---+---+---+---+… unless you’ve specified a header row, which puts a limit on the number of
columns:>>> tbl.headers = ['Group', 'Elements']
>>> print(tbl)
+-----+--------+
|Group|Elements|
+-----+--------+
|1    |1       |
|Z_6  |1       |
|S_3  |1       |
|Z_4  |1       |
|V_4  |1       |
+-----+--------+… unless you’vealsospecified aheader_fillto use as the header for
extra columns:>>> tbl.header_fill = 'Extra!'
>>> print(tbl)
+-----+--------+------+------+------+------+------+
|Group|Elements|Extra!|Extra!|Extra!|Extra!|Extra!|
+-----+--------+------+------+------+------+------+
|1    |1       |      |      |      |      |      |
|Z_6  |1       |x     |x^2   |x^3   |x^4   |x^5   |
|S_3  |1       |a     |b     |aba   |ba    |ab    |
|Z_4  |1       |x     |x^2   |x^3   |      |      |
|V_4  |1       |a     |b     |ab    |      |      |
+-----+--------+------+------+------+------+------+You can set the widths of columns; long lines will be wrapped to fit:>>> tbl = Txtble(
...     headers=['Short Text', 'Long Text'],
...     data=[
...         [
...             'Hi there!',
...             'Lorem ipsum dolor sit amet, consectetur adipisicing elit',
...         ]
...     ],
...     widths=[20, 20],
... )
>>> print(tbl)
+--------------------+--------------------+
|Short Text          |Long Text           |
+--------------------+--------------------+
|Hi there!           |Lorem ipsum dolor   |
|                    |sit amet,           |
|                    |consectetur         |
|                    |adipisicing elit    |
+--------------------+--------------------+You can align column text to the left, right, or center:>>> tbl = Txtble(DATA, headers=HEADERS, align=['r', 'c', 'l'])
>>> print(tbl)
+---------+----------+------------------+
|    Month|Birthstone|Birth Flower      |
+---------+----------+------------------+
|  January|  Garnet  |Carnation         |
| February| Amethyst |Violet            |
|    March|Aquamarine|Jonquil           |
|    April| Diamond  |Sweetpea          |
|      May| Emerald  |Lily Of The Valley|
|     June|  Pearl   |Rose              |
|     July|   Ruby   |Larkspur          |
|   August| Peridot  |Gladiolus         |
|September| Sapphire |Aster             |
|  October|   Opal   |Calendula         |
| November|  Topaz   |Chrysanthemum     |
| December|Turquoise |Narcissus         |
+---------+----------+------------------+Numbers in the same column can be aligned on their decimal point with the'n'alignment:>>> tbl = Txtble(
...     headers=['Thing', 'Value'],
...     data=[
...         ['Foo', 12345],
...         ['Bar', 1234.5],
...         ['Baz', 123.45],
...         ['Quux', 12.345],
...         ['Glarch', 1.2345],
...         ['Gnusto', .12345],
...     ],
...     align=['l', 'n'],
... )
>>> print(tbl)
+------+-----------+
|Thing |Value      |
+------+-----------+
|Foo   |12345      |
|Bar   | 1234.5    |
|Baz   |  123.45   |
|Quux  |   12.345  |
|Glarch|    1.2345 |
|Gnusto|    0.12345|
+------+-----------+Unicode works too, even fullwidth characters and combining characters:>>> tbl = Txtble(
...     headers=['Wide', 'Accented'],
...     data=[
...         [
...             u'\uFF37\uFF49\uFF44\uFF45',
...             u'A\u0301c\u0301c\u0301e\u0301n\u0301t\u0301e\u0301d\u0301',
...         ]
...     ]
... )
>>> print(tbl)
+--------+--------+
|Wide    |Accented|
+--------+--------+
|Ｗｉｄｅ|Áććéńt́éd́|
+--------+--------+You can configure the borders and make them fancy:>>> from txtble import ASCII_EQ_BORDERS
>>> tbl = Txtble(
...     DATA,
...     headers       = HEADERS,
...     header_border = ASCII_EQ_BORDERS,
...     row_border    = True,
... )
>>> print(tbl)
+---------+----------+------------------+
|Month    |Birthstone|Birth Flower      |
+=========+==========+==================+
|January  |Garnet    |Carnation         |
+---------+----------+------------------+
|February |Amethyst  |Violet            |
+---------+----------+------------------+
|March    |Aquamarine|Jonquil           |
+---------+----------+------------------+
|April    |Diamond   |Sweetpea          |
+---------+----------+------------------+
|May      |Emerald   |Lily Of The Valley|
+---------+----------+------------------+
|June     |Pearl     |Rose              |
+---------+----------+------------------+
|July     |Ruby      |Larkspur          |
+---------+----------+------------------+
|August   |Peridot   |Gladiolus         |
+---------+----------+------------------+
|September|Sapphire  |Aster             |
+---------+----------+------------------+
|October  |Opal      |Calendula         |
+---------+----------+------------------+
|November |Topaz     |Chrysanthemum     |
+---------+----------+------------------+
|December |Turquoise |Narcissus         |
+---------+----------+------------------+… orveryfancy:>>> from txtble import DOUBLE_BORDERS
>>> tbl = Txtble(DATA, headers=HEADERS, border_style=DOUBLE_BORDERS)
>>> print(tbl)
╔═════════╦══════════╦══════════════════╗
║Month    ║Birthstone║Birth Flower      ║
╠═════════╬══════════╬══════════════════╣
║January  ║Garnet    ║Carnation         ║
║February ║Amethyst  ║Violet            ║
║March    ║Aquamarine║Jonquil           ║
║April    ║Diamond   ║Sweetpea          ║
║May      ║Emerald   ║Lily Of The Valley║
║June     ║Pearl     ║Rose              ║
║July     ║Ruby      ║Larkspur          ║
║August   ║Peridot   ║Gladiolus         ║
║September║Sapphire  ║Aster             ║
║October  ║Opal      ║Calendula         ║
║November ║Topaz     ║Chrysanthemum     ║
║December ║Turquoise ║Narcissus         ║
╚═════════╩══════════╩══════════════════╝See the following documentation for more information:APITxtbleTxtble(data=(),**kwargs)Create a newTxtbleobject.  The table’s data may be passed to the
constructor as an iterable of rows of values, where each row is either an
iterable of cell values or a mapping from header names to cell values;
otherwise, the data starts out empty.  In either case, further data rows can
be added via theappend()andextend()methods.**kwargsare used to configure theTxtbleinstance; see
“Configuration Options” below.tbl.append(row)Add a new data row at the bottom of the table.rowcan be either an
iterable of cell values or a mapping from header names to cell values.tbl.extend(rows)Add zero or more new data rows at the bottom of the tabletbl.show()orstr(tbl)Convert theTxtbleinstance to a string showing a plain text table.
Table cells and filler values that are not already strings are converted by
callingstr()on them; the exceptions areNonevalues, which are
displayed according to thenone_stroption (see below).  All tab
characters are expanded to spaces before building the table.  If any of the
resulting strings have indeterminate width (i.e., ifwcwidth.wcswidth()returns a negative number for any of them), anIndeterminateWidthError(a subclass ofValueError) is raised.Note that the resulting string will likely contain one or more embedded
newlines, but (outside of some very odd cases) it will not end with a
newline.  This means that you can doprint(tbl)and there won’t be a
blank line added at the end.Configuration OptionsThese options can be set either as keywords passed to theTxtbleconstructor or as attributes on aTxtbleinstance:tbl = Txtble(data, border=False)
# Same as:
tbl = Txtble(data)
tbl.border = Falsealign: Union[str, Sequence[str]] = ()A sequence of alignment specifiers indicating how the contents of each
column, in order, should be horizontally aligned.  The alignment specifiers
are'l'(left alignment),'c'(centered alignment), and'r'(right alignment).alignmay optionally be set to a single alignment
specifier to cause all columns to be aligned in that way.An alignment specifier may optionally include'n'to cause all numbers
in the relevant column to be aligned on their decimal point; the'l','c', or'r'then determines how the “block” of numbers is aligned as
a whole (This is generally only relevant if the column also contains a
string value longer than any of the numbers).  An alignment specifier of
just'n'is equivalent to'ln'or'nl'.align_fill: str = 'l'If there are more columns than there are entries inalign, the extra
columns will have their alignment set toalign_fill.border: Union[bool, BorderStyle] = TrueWhether to draw a border around the edge of the table.bordermay
optionally be set to aBorderStyleinstance to set the characters used
for drawing the border around the edge of the table.  Individual edges can
be toggled or stylized by setting thebottom_border,left_border,right_border, andtop_borderoptions.border_style: BorderStyle = ASCII_BORDERSABorderStyleinstance specifying the characters to use for drawing all
of the table’s borders & rules.  The border style can be overridden for
individual borders by setting their respective options (border,column_border, etc.) toBorderStyleinstances.  See “BorderStyle”
below for more information.bottom_border: Union[bool, BorderStyle, None] = NoneWhether to draw a border along the bottom edge of the table.  The default
value ofNonemeans to inherit the value set forborder.bottom_bordermay optionally be set to aBorderStyleinstance to set
the characters used for drawing the border along the bottom edge.break_long_words: bool = TrueWhether to force a line break in the middle of a word if said word is too
long for the column’s widthbreak_on_hyphens: bool = TrueWhether to break on hyphens in addition to whitespace when wrapping textcolumn_border: Union[bool, BorderStyle] = TrueWhether to draw a vertical rule between individual columns.column_bordermay optionally be set to aBorderStyleinstance to set
the characters used for drawing the vertical rules between columns.columns: Optional[int] = NoneAn optional positive integer.  When set, show exactly the given number of
columns per row, adding cells withrow_filland discarding extra cells
as needed.  Ifheadersis also set, its length must equalcolumnsor
else aValueErroris raised.  Setting bothcolumnsandheaderscausesheader_fillto be ignored.dict_fill: AnyIf a header name does not appear as a key in adict/mapping row, the value
ofdict_fillwill be used for the corresponding cell value.  Ifdict_fillis not set, a missing key will cause aKeyErrorto be
raised.header_border: Union[bool, BorderStyle, None] = NoneWhether to draw a horizontal rule above the data rows, below the header row
(if any).  The default value ofNonemeans that the border will be drawn
if & only ifheadersis non-None.header_bordermay optionally be
set to aBorderStyleinstance to set the characters used for drawing the
horizontal rule above the data rows.IfheadersisNoneandtop_borderis set to a true value (or
inherits a true value fromborder), the header border will not be drawn.header_fill: Any = NoneWhenheadersis non-NoneandcolumnsisNone, this option
determines how rows with more columns than there are headers are handled.
Whenheader_fill=None, any extra columns are discarded from long rows.
For all other values, the header row will be extended to the length of the
longest data row, and the new header cells will contain theheader_fillvalue.headers: Optional[list] = NoneAn optional list of cell values to display in a row at the top of the table.
Setting this option also implicitly sets a minimum number of columns per
row; seeheader_fillfor allowing extra columns.Ifheadersis set to an empty list,header_fillmust be set to a
non-Nonevalue or else aValueErrorwill be raised upon trying to render
theTxtble.left_border: Union[bool, BorderStyle, None] = NoneWhether to draw a border along the left edge of the table.  The default
value ofNonemeans to inherit the value set forborder.left_bordermay optionally be set to aBorderStyleinstance to set
the characters used for drawing the border along the left edge.left_padding: Union[int, str, None] = NonePadding to insert on the left of every table cell.  This can be either an
integer (to insert that many space characters) or a string.  If a string, it
may not contain any newlines.  The default value ofNonemeans to inherit
the value set forpadding.len_func:Optional[Callable[[str],int]]The function to use for calculating how many terminal cells wide a string
is; it should take one string argument and return a width.  Returning a
negative width causesTxtbleto raise anIndeterminateWidthError.
The default value (also used when set toNone) iswith_color_stripped(wcwidth.wcswidth)(See “Other” below).none_str: Any = ''The string to display in place ofNonevalues (Settingnone_str=Noneis the same as setting it to'None')padding: Union[int, str] = 0Padding to insert on the left & right of every table cell.  This can be
either an integer (to insert that many space characters) or a string.  If a
string, it may not contain any newlines.  Padding for the left and right of
table cells can be specified separately via theleft_paddingandright_paddingoptions.right_border: Union[bool, BorderStyle, None] = NoneWhether to draw a border along the right edge of the table.  The default
value ofNonemeans to inherit the value set forborder.right_bordermay optionally be set to aBorderStyleinstance to set
the characters used for drawing the border along the right edge.right_padding: Union[int, str, None] = NonePadding to insert on the right of every table cell.  This can be either an
integer (to insert that many space characters) or a string.  If a string, it
may not contain any newlines.  The default value ofNonemeans to inherit
the value set forpadding.row_border: Union[bool, BorderStyle] = FalseWhether to draw horizontal rules between data rows.row_bordermay
optionally be set to aBorderStyleinstance to set the characters used
for drawing the horizontal rules between data rows.row_fill: Any = ''If the rows of a table differ in number of columns, cells are added to the
shorter rows until they all line up, and the added cells containrow_fillas their value.rstrip: bool = TrueWhenborder=False, settingrstrip=Falsewill cause the last cell of
each row to still be padded with trailing whitespace andpaddingin
order to reach the full column width.  (Normally, this whitespace andpaddingis omitted whenborder=Falseas there is no end-of-line
border to align.)  This option is useful if you wish to append text to one
or more lines of the output and have it appear strictly outside the table.top_border: Union[bool, BorderStyle, None] = NoneWhether to draw a border along the top edge of the table.  The default value
ofNonemeans to inherit the value set forborder.top_bordermay
optionally be set to aBorderStyleinstance to set the characters used
for drawing the border along the top edge.valign: Union[str, Sequence[str]] = ()A sequence of vertical alignment specifiers indicating how the contents of
each column, in order, should be vertically aligned.  The vertical alignment
specifiers are't'(top alignment),'m'(middle alignment), and'b'(bottom alignment).valignmay optionally be set to a single
vertical alignment specifier to cause all columns to be vertically aligned
in that way.valign_fill: str = 't'If there are more columns than there are entries invalign, the extra
columns will have their vertical alignment set tovalign_fill.width_fill: Optional[int] = NoneIf there are more columns than there are entries inwidths, the extra
columns will have their widths set towidth_fill.widths: Union[int,Sequence[Optional[int]],None] = ()A sequence of integers specifying the width of each column, in order.  Lines
wider than the given width will be wrapped; the wrapping can be configured
via thebreak_long_wordsandbreak_on_hyphensoptions.  A width ofNonedisables wrapping for that column and causes the column’s width to be
set to the width of the longest line.widthsmay optionally be set to a
single width to cause all columns to be that wide.wrap_func:Optional[Callable[[str,int],Iterable[str]]]= NoneThe function to use for wrapping long lines; it should take a string and a
width and return an iterable of strings.  The default value ofNonecauses
a custom function to be used that properly handles fullwidth characters,
ANSI color escape sequences, etc.; if your table contains such strings, any
user-suppliedwrap_funcmust be able to handle them as well.  Whenwrap_funcis set to a user-supplied value, thebreak_long_wordsandbreak_on_hyphensoptions are ignored.BorderStyleTheBorderStyleclass is anamedtuplelisting the strings to use for
drawing a table’s borders & rules.  Its attributes are:AttributeDescriptionExamplehlinehorizontal line─vlinevertical line│ulcornerupper-left box corner┌urcornerupper-right box corner┐llcornerlower-left box corner└lrcornerlower-right box corner┘vrteetee pointing right├vlteetee pointing left┤dhteetee pointing down┬uhteetee pointing up┴pluscross/four-way joint┼txtbleprovides the following predefinedBorderStyleinstances:ASCII_BORDERSThe default border style.  Draws borders using only the ASCII characters-,|, and+:+-+-+
|A|B|
+-+-+
|C|D|
+-+-+ASCII_EQ_BORDERSLikeASCII_BORDERS, but uses=in place of-:+=+=+
|A|B|
+=+=+
|C|D|
+=+=+LIGHT_BORDERSUses the light box drawing characters:┌─┬─┐
|A|B|
├─┼─┤
|C|D|
└─┴─┘HEAVY_BORDERSUses the heavy box drawing characters:┏━┳━┓
┃A┃B┃
┣━╋━┫
┃C┃D┃
┗━┻━┛DOUBLE_BORDERSUses the double box drawing characters:╔═╦═╗
║A║B║
╠═╬═╣
║C║D║
╚═╩═╝DOT_BORDERSUses⋯,⋮, and·:·⋯·⋯·
⋮A⋮B⋮
·⋯·⋯·
⋮C⋮D⋮
·⋯·⋯·If you define your own custom instances ofBorderStyle, they must adhere to
the following rules:Thehlinestring must be exactly one terminal column wide (the same width
as a space character).All strings other thanhlinemust be the same width.No string may contain a newline.OtherIndeterminateWidthErrorSubclass ofValueError.  Raised when a string is reported as having
negative/indeterminate width.  (For the defaultlen_func, this happens
when the string contains a DEL or a C0 or C1 control character other than a
tab, newline, or ANSI color escape sequence.)  The string in question is
available as the exception’sstringattribute.NumericWidthOverflowErrorSubclass ofValueError.  Raised when a column has a non-Nonewidth,
the column’salignvalue contains'n', and aligning the numbers in
the column along their decimal points would cause one or more cells to
exceed the column’s width.UnterminatedColorErrorSubclass ofValueError.  Raised bywith_color_strippedupon
encountering an ANSI color escape sequence that is not eventually terminated
by a reset/sgr0 sequence.  The string in question is available as the
exception’sstringattribute.with_color_strippedA function decorator for applying tolenor imitators thereof that
strips ANSI color sequences from a single string argument before passing it
on.  If any color sequences are not followed by a reset sequence, anUnterminatedColorErroris raised.