mrkeyoor.com_
Wed 23 Sept 00:32 UTC
PyPIUtilsupdated 22 Sept 2026

texttable review

texttable 1.7.0 turns Python rows into one ASCII-style table string. Its `Texttable` object controls the header, fixed widths, horizontal and vertical alignment, numeric formatting, precision, drawing characters, and border or separator lines. Multiline cells work, while optional `wcwidth` or `cjkwrap` installations improve some emoji and CJK width calculations. The package does not stream rows, track terminal resizing, style ANSI output, or export Markdown and HTML. Version 1.7.0 added the boolean column datatype.

Verdict

texttable 1.7.0 installed in 0.2 seconds, used 1 MB, and imported in 0.06 seconds in our sandbox with 0 dependencies and 0 audit findings. Keep it for bounded plain-text reports; start elsewhere when output needs typing, live terminal behavior, deterministic complex Unicode, or several export formats.

We installed it

Lab card: what happened when we installed texttableScreenshot of texttable documentation
Install✓ · 0.2s1 package on disk · 1 MB
Importimport texttable in 0.06s · pure Python
Known vulns0(pip-audit)

Answers from our run

Does texttable install cleanly?

Yes. In a fresh container with an empty cache, pip install texttable finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.

What does texttable need to run?

Python 3.x, and nothing compiled: it is pure Python. In our run import texttable succeeded in 0.06s.

texttable or tabulate: which should you use?

tabulate: Choose it when one dataset must render in Markdown, HTML, grid, and database-style formats. texttable 1.7.0 installed in 0.2 seconds, used 1 MB, and imported in 0.06 seconds in our sandbox with 0 dependencies and 0 audit findings.

When should you not use texttable?

The terminal UI needs colors, hyperlinks, progress, or live refresh. texttable returns static plain text and has no console capability layer.

API stability5/5The constructor plus `add_row`, `add_rows`, `header`, `draw`, `reset`, and the `set_cols_*` methods have stayed recognizable for years. Version 1.7.0 added a boolean datatype instead of redesigning the object. That is good news for old scripts and transitive users. Stability comes partly from a narrow, mostly finished surface, though the missing required-Python metadata and absent typing marker leave compatibility checks to import tests rather than published declarations.
Docs2/5The README contains two full examples and a pydoc-style method listing with datatype letters, alignment codes, decoration flags, array order, and constructor defaults. It explicitly mentions optional `wcwidth` and `cjkwrap` behavior. There is no separate current documentation site, and the generated-looking reference retains old Python-era presentation. Error cases, ANSI escape handling, large-output memory, and deterministic Unicode environments require inference or source reading rather than a production guide.
Maintenance2/5GitHub reports an unarchived repository with 360 stars and 0 open issues or pull requests. PyPI uploaded 1.7.0 on October 3, 2023, and the last repository push was later that same day. A zero queue does not prove current maintenance when code and releases have both been still for almost three years. The small API may simply be finished, but teams needing quick compatibility fixes should treat the date as a real support risk.
Ecosystem3/5The supplied weekly count is 6,187,319 downloads, while our install confirmed a single MIT-licensed package with no required dependencies. Optional `wcwidth` and `cjkwrap` address parts of terminal-width calculation without becoming mandatory. The surrounding feature ecosystem is intentionally small: the project does not document an official Markdown or HTML renderer, styling layer, terminal abstraction, dataframe adapter, or typing companion. High installation volume can therefore reflect transitive use more than new direct adoption.

Use it if

  • A script, log, or test needs a small fixed-width text table with no required runtime dependencies.
  • Each column needs explicit alignment, wrapping width, datatype, or number precision.
  • The complete result is small enough to assemble as one string before printing or logging.
  • Existing code already depends on `Texttable` and its stable setter-based interface.
Skip it if

Setup reality

We installed texttable 1.7.0 in 0.2 seconds in a fresh Python 3.12 Bookworm sandbox. It left 1 package and 1 MB on disk, and pip-audit found 0 known vulnerabilities. The MIT-licensed distribution is pure Python, declares 0 direct dependencies, does not specify a Python floor, has no py.typed marker, and completed import texttable in 0.06 seconds.

There are no credentials or config files. Defaults still decide output: maximum width is 80, decorations are enabled, automatic typing may reinterpret strings, float precision is 3, and add_rows() consumes its first row as the header unless header=False. Set the schema before adding data. A header, row, alignment, datatype, or width array with the wrong number of cells raises ArraySizeError.

Use datatype t for identifiers such as 00123; automatic formatting can treat them as numbers and lose meaningful presentation. set_cols_width() fixes per-column wrapping, while max_width=0 disables the overall automatic limit. Multiline cells use the selected vertical alignment. Optional wcwidth improves emoji width handling and cjkwrap affects CJK wrapping, so install the same extras in CI and production if snapshots must match.

draw() builds and returns the entire table. That is convenient for a short report and wasteful for a very large query result because output is not incremental. The library does not understand ANSI escape sequences, a resized terminal, sorting, pagination, or alternate serialization formats. Keep raw records separate, render only the bounded page you need, and test representative Unicode rather than assuming visible width equals Python string length.

Patterns

Build a table with a header and rows draw-basic-table

from texttable import Texttable

table = Texttable()
table.header(['Name', 'Age'])
table.add_row(['Ada', 36])
table.add_row(['Grace', 40])
print(table.draw())

`draw()` returns one complete string. Send it to the logger once so prefixes are not inserted on every visual row.

Add a batch without consuming its first row as a header add-rows-without-header

table = Texttable()
table.header(['Name', 'Score'])
table.add_rows([['Ada', 98], ['Grace', 95]], header=False)

`add_rows()` assumes its first item is a header unless `header=False` is explicit.

Set horizontal and vertical alignment align-columns

table.set_cols_align(['l', 'r', 'c'])
table.set_cols_valign(['t', 'm', 'b'])

Both arrays need exactly one setting per column; a mismatch raises `ArraySizeError`.

Control numeric and text formatting format-column-types

table.set_cols_dtype([
    't',  # preserve identifiers as text
    'i',  # integer
    'f',  # fixed-point float
    'b',  # boolean
])
table.set_precision(2)

Automatic typing can reinterpret `00123`, so declare identifier columns as text before adding values.

Wrap cells at explicit column widths set-column-widths

table = Texttable(max_width=0)
table.set_cols_width([12, 36, 8])

`max_width=0` removes the overall limit while these explicit widths continue to wrap individual columns.

Draw only borders and a header separator choose-decoration

from texttable import Texttable

table.set_deco(Texttable.BORDER | Texttable.HEADER)

Decoration constants combine with bitwise OR. Omitting `VLINES` and `HLINES` removes the internal rules.

Change the four drawing characters customize-border-characters

table.set_chars(['-', '|', '+', '='])

The order is horizontal, vertical, corner, then header. Wide glyphs can still upset the width calculation.

Use a callable as a column datatype format-with-callable

def dollars(value):
    return f'${value:,.2f}'

table.set_cols_dtype(['t', dollars])
table.add_rows([['Item', 'Price'], ['Cable', 12.5]])

A datatype callable must return a string for every cell, including whatever null representation your rows contain.

Reset rows and header before another report reuse-table

print(table.draw())

table.reset()
table.header(['Key', 'Value'])
table.add_row(['status', 'ok'])

`reset()` removes both data and header. Define the next report's header before appending new rows.

Catch a mismatched row shape handle-schema-error

from texttable import ArraySizeError

try:
    table.add_row(['too', 'many', 'cells'])
except ArraySizeError as exc:
    raise ValueError('row does not match table columns') from exc

One malformed row prevents final rendering, so normalize record lengths before they reach `Texttable`.

Alternatives

PackageRegistryPick it when
tabulatePyPIChoose it when one dataset must render in Markdown, HTML, grid, and database-style formats.
prettytablePyPIChoose it for sorting, field selection, and a larger table object with several output styles.
richPyPIChoose it for colored, console-aware tables inside a live or styled terminal interface.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.