philiprehberger-text-table
Render data as clean ASCII/Unicode tables in the terminal with zero configuration.
Installation
pip install philiprehberger-text-table
Usage
from philiprehberger_text_table import table
headers = ["Name", "Age", "City"]
rows = [
["Alice", 30, "New York"],
["Bob", 25, "London"],
["Charlie", 35, "Tokyo"],
]
print(table(headers, rows))
Output:
┌─────────┬─────┬──────────┐
│ Name │ Age │ City │
├─────────┼─────┼──────────┤
│ Alice │ 30 │ New York │
│ Bob │ 25 │ London │
│ Charlie │ 35 │ Tokyo │
└─────────┴─────┴──────────┘
From dictionaries
from philiprehberger_text_table import from_dicts
data = [
{"name": "Alice", "score": 95},
{"name": "Bob", "score": 87},
]
print(from_dicts(data))
From dataclasses
from dataclasses import dataclass
from philiprehberger_text_table import from_dataclasses
@dataclass
class Person:
name: str
age: int
print(from_dataclasses([Person("Alice", 30), Person("Bob", 25)]))
Field names become the headers. Passing anything other than dataclass instances raises TypeError; an empty list returns "".
Title and footer
headers = ["Item", "Qty", "Price"]
rows = [["Apple", 3, 1.5], ["Banana", 12, 0.25]]
print(table(headers, rows, title="Fruit Stand", footer=["Total", 15, ""]))
Output:
┌──────────────────────┐
│ Fruit Stand │
├────────┬─────┬───────┤
│ Item │ Qty │ Price │
├────────┼─────┼───────┤
│ Apple │ 3 │ 1.5 │
│ Banana │ 12 │ 0.25 │
├────────┼─────┼───────┤
│ Total │ 15 │ │
└────────┴─────┴───────┘
The title is centered across the full table width; if it is wider than the table, the last column widens to fit, and max_width truncates it like any cell. The footer must have one cell per header (ValueError otherwise), counts toward column widths, and uses each column's alignment. In "minimal" and "compact" styles the footer sits below a dashed separator and the title is a centered line. In "markdown" the title is a plain line followed by a blank line, and the footer is the last row with no extra separator (Markdown tables allow only one delimiter row).
From CSV
from philiprehberger_text_table import from_csv
print(from_csv("data.csv"))
Styles
# ASCII style
print(table(headers, rows, style="ascii"))
# Markdown style
print(table(headers, rows, style="markdown"))
# Minimal style (no borders)
print(table(headers, rows, style="minimal"))
# Compact style (no outer borders)
print(table(headers, rows, style="compact"))
# Rounded Unicode corners
print(table(headers, rows, style="rounded"))
# Double-line borders
print(table(headers, rows, style="double"))
Column alignment
# Override auto-detection for all columns
print(table(headers, rows, align="center"))
# Per-column alignment
print(table(headers, rows, align=["left", "center", "right"]))
From CSV string
from philiprehberger_text_table import from_csv_string
csv_data = "Name,Age\nAlice,30\nBob,25"
print(from_csv_string(csv_data))
From JSON
from philiprehberger_text_table import from_json, from_json_string
# List of dicts (keys become headers)
print(from_json_string('[{"name":"Alice","age":30},{"name":"Bob","age":25}]'))
# List of lists (first inner list is the header row)
print(from_json_string('[["Name","Age"],["Alice",30],["Bob",25]]'))
# Read from a file
print(from_json("data.json"))
Truncation
print(table(headers, rows, max_width=10))
Round-tripping CSV
from philiprehberger_text_table import to_csv, from_csv
csv_text = to_csv(
[["Alice", 30], ["Bob", 25]],
headers=["Name", "Age"],
file="people.csv", # optional — also writes to disk
)
print(csv_text)
# Name,Age
# Alice,30
# Bob,25
# Re-read and render
print(from_csv("people.csv"))
Round-tripping JSON
from philiprehberger_text_table import to_json, from_json_string
json_text = to_json(
[["Alice", 30], ["Bob", 25]],
headers=["name", "age"], # omit for a plain array of arrays
)
print(json_text)
# [
# {"name": "Alice", "age": 30},
# {"name": "Bob", "age": 25}
# ]
# Re-render as a table
print(from_json_string(json_text))
Computing column widths
from philiprehberger_text_table import column_widths
widths = column_widths(["name", "count"], [["alice", 100], ["bob", 5]])
# [5, 5] — max of header and cell str-lengths per column
API
| Function / Class | Description |
|---|---|
table(headers, rows, *, style="unicode", max_width=None, align=None, title=None, footer=None) |
Render a table from headers and row data, with an optional centered title and summary footer row |
from_dicts(data, *, style="unicode", max_width=None, align=None, title=None, footer=None) |
Render a table from a list of dictionaries |
from_dataclasses(items, *, style="unicode", max_width=None, align=None, title=None, footer=None) |
Render a table from a list of dataclass instances (field names become headers) |
from_csv(path, *, style="unicode", max_width=None, align=None, title=None, footer=None) |
Read a CSV file and render as a table |
from_csv_string(text, *, style="unicode", max_width=None, align=None, title=None, footer=None) |
Render a table from CSV string content |
from_json(path, *, style="unicode", max_width=None, align=None, title=None, footer=None) |
Read a JSON file and render as a table (list of dicts or list of lists) |
from_json_string(text, *, style="unicode", max_width=None, align=None, title=None, footer=None) |
Render a table from a JSON string |
to_csv(rows, *, headers=None, file=None) |
Render rows back to a CSV string (round-trips with from_csv); optionally writes to a file |
to_json(rows, *, headers=None, file=None, indent=2) |
Render rows to a JSON string (round-trips with from_json); optionally writes to a file |
column_widths(headers, rows) |
Return the per-column widths the renderer would compute |
Style values
| Style | Description |
|---|---|
"unicode" |
Box-drawing borders (default) |
"rounded" |
Box-drawing borders with rounded corners |
"double" |
Double-line box-drawing borders |
"ascii" |
+, -, and | borders |
"markdown" |
GitHub-flavored Markdown table |
"minimal" |
No borders, dashed header separator |
"compact" |
Inner separators only, no outer borders |
Alignment values
| Alignment | Description |
|---|---|
None |
Auto-detect (default): numeric columns right-aligned, others left-aligned |
"left" |
Left-align cells |
"right" |
Right-align cells |
"center" |
Center cells |
Development
pip install -e .
python -m pytest tests/ -v
Support
If you find this project useful:
License
Metadata
Release files for philiprehberger-text-table 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| philiprehberger_text_table-0.6.0.tar.gz | 199.8 kB | Without provenance | Details for philiprehberger_text_table-0.6.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| philiprehberger_text_table-0.6.0-py3-none-any.whl | Python 3 | none | any | Details for philiprehberger_text_table-0.6.0-py3-none-any.whl |
Total release size: 209.9 kB
Release files / philiprehberger_text_table-0.6.0.tar.gz
| Download URL | philiprehberger_text_table-0.6.0.tar.gz |
|---|---|
| Size | 199.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
89c39233a791c51605f78fe5a520220ba6a8bdaab572b72710c23a1ccc068e33
|
|
BLAKE2b-256 checksum How to use checksums |
91457fbb068c2ef5dc83a9234aea8f96d3ae9b2d33bb4845243251030f652f50
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / philiprehberger_text_table-0.6.0-py3-none-any.whl
| Download URL | philiprehberger_text_table-0.6.0-py3-none-any.whl |
|---|---|
| Size | 10.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
434243256dfe17dd8e604a34f8653c81b50c60aa2c18624ca91e2be295adef0c
|
|
BLAKE2b-256 checksum How to use checksums |
be6a8c243031adcc283ee573a5fd899791452be13c979f3e737fb1956f25d47e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Security for philiprehberger-text-table 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.