Table¶
Click Extra provides a way to render tables in the terminal.
Tip
The selected --table-format value and the --sort-by priority list are published on ctx.meta as TABLE_FORMAT and SORT_BY. See the available keys table to read them from your own callbacks.
Here how to use the standalone table rendering option decorator:
import click
from click_extra import pass_context, table_format_option, style, Color
@click.command
@table_format_option
@pass_context
def table_command(ctx):
headers = ("Day", "Temperature")
data = (
(1, 42.9),
("2", None),
(style("Friday", fg=Color.blue), style("Hot 🥵", fg=Color.red, bold=True)),
)
ctx.print_table(data, headers)
As you can see above, this option registers a ready-to-use print_table() method to the context object.
The default help message for this option list all available table formats:
$ table --help
Usage: table [OPTIONS]
Options:
--table-format [aligned|asciidoc|colon-grid|csv|csv-excel|csv-excel-tab|csv-unix|double-grid|double-outline|fancy-grid|fancy-outline|github|grid|heavy-grid|heavy-outline|hjson|html|jira|json|json5|jsonc|latex|latex-booktabs|latex-longtable|latex-raw|mediawiki|mixed-grid|mixed-outline|moinmoin|orgtbl|outline|pipe|plain|presto|pretty|psql|rounded-grid|rounded-outline|rst|simple|simple-grid|simple-outline|textile|toml|tsv|unsafehtml|vertical|xml|yaml|youtrack]
Rendering style of tables.
--help Show this message and exit.
So you can use the --table-format option to change the table format:
$ table --table-format fancy-outline
╒════════╤═════════════╕
│ Day │ Temperature │
╞════════╪═════════════╡
│ 1 │ 42.9 │
│ 2 │ │
│ Friday │ Hot 🥵 │
╘════════╧═════════════╛
$ table --table-format asciidoc
[cols="<8,<13",options="header"]
|====
| Day | Temperature
| 1 | 42.9
| 2 |
| Friday | Hot 🥵
|====
Tip
This example has been selected so you can see how print_table() handles:
Mixed data types (integers, floats,
None, strings)ANSI color codes (added with the
click_extra.style()function)Unicode characters (like the emojis)
Hint
There’s another method called render_table() that is registered in the context alongside print_table().
It works the same way, but instead of printing the table to the console, it returns the rendered table as a string.
Table formats¶
Table formats are aggregated from these sources:
Python’s
csvmodule from the standard libraryPython’s
jsonmodule from the standard libraryhjson(requires the[hjson]extra)tomlkit(requires the[toml]extra)xmltodict(requires the[xml]extra)PyYAML(requires the[yaml]extra)
They’re divided in 2 categories:
Formats that produce plain text output (like ASCII tables, grid tables, etc.) and are often composed of Unicode box-drawing characters, to be displayed in a terminal.
Formats that produce markup language output (like HTML, Markdown, LaTeX, etc.) and are expected to be rendered by a supporting viewer. This category also includes CSV, TSV, and structured serialization formats (HJSON, JSON, JSON5, JSONC, TOML, XML, YAML), which are plain text but meant to be processed by other tools.
Tip
The default rounded-outline format draws its borders with Unicode box-drawing characters (│, ╭, ─, …) and aligns columns with padding. A screen reader announces those separators and the padding gaps as noise, and the column alignment is lost entirely once whitespace is collapsed.
For a screen-reader-friendly rendering, use --table-format plain: it keeps the tabular layout with no borders. For output that another program will parse, use a machine-readable format like csv. The --accessible flag bundles --table-format plain with --no-color in a single switch.
Format ID |
Description |
Implementation |
Markup |
|---|---|---|---|
|
Compact table with single-space column separators and no borders |
Click Extra |
❌ |
|
|
✅ |
|
|
|
✅ |
|
|
CSV with Excel dialect |
|
✅ |
|
CSV with Excel tab dialect |
|
✅ |
|
CSV with Unix dialect |
|
✅ |
|
Double-line grid table |
|
❌ |
|
Double-line outline table |
|
❌ |
|
Grid with Unicode box-drawing characters |
|
❌ |
|
Outline with Unicode box-drawing characters |
|
❌ |
|
|
✅ |
|
|
Grid table with ASCII characters, also supported by Pandoc and reStructuredText |
|
❌ |
|
Heavy-line grid table |
|
❌ |
|
Heavy-line outline table |
|
❌ |
|
HJSON array of objects |
✅ |
|
|
|
✅ |
|
|
|
✅ |
|
|
JSON array of objects |
|
✅ |
|
Alias for |
|
✅ |
|
Alias for |
|
✅ |
|
|
✅ |
|
|
|
✅ |
|
|
|
✅ |
|
|
LaTeX table without escaping |
|
✅ |
|
|
✅ |
|
|
Mixed-line grid table |
|
❌ |
|
Mixed-line outline table |
|
❌ |
|
|
✅ |
|
|
|
✅ |
|
|
Simple outline table |
|
❌ |
|
|
✅ |
|
|
Plain text, no formatting |
|
❌ |
|
Presto SQL output style |
|
❌ |
|
Pretty ASCII table |
|
❌ |
|
PostgreSQL output style |
|
❌ |
|
Rounded grid table |
|
❌ |
|
Rounded outline table |
|
❌ |
|
|
✅ |
|
|
Simple table with spaces, also supported by Pandoc |
|
❌ |
|
Simple grid table |
|
❌ |
|
Simple outline table |
|
❌ |
|
|
✅ |
|
|
TOML array of tables |
✅ |
|
|
|
✅ |
|
|
HTML table without escaping |
|
✅ |
|
Vertical table layout |
|
❌ |
|
XML document |
✅ |
|
|
YAML sequence of mappings |
✅ |
|
|
|
✅ |
Attention
By default, markup formats strip ANSI color codes from the output, to avoid injecting escape sequences into structured content like HTML, LaTeX, or CSV.
If you want to keep them, force the --color option when invoking the command.
Tip
Use the built-in demo subcommands to verify how ANSI codes are handled by each format:
$ uvx click-extra --table-format github styles
$ uvx click-extra --table-format json colors
Plain-text formats preserve ANSI styling. Markup formats strip it unless --color is passed explicitly.
$ table --table-format aligned
Day Temperature
1 42.9
2
Friday Hot 🥵
$ table --table-format asciidoc
[cols="<8,<13",options="header"]
|====
| Day | Temperature
| 1 | 42.9
| 2 |
| Friday | Hot 🥵
|====
$ table --table-format csv
Day,Temperature
1,42.9
2,
Friday,Hot 🥵
$ table --table-format csv-excel
Day,Temperature
1,42.9
2,
Friday,Hot 🥵
$ table --table-format csv-excel-tab
Day Temperature
1 42.9
2
Friday Hot 🥵
$ table --table-format csv-unix
"Day","Temperature"
"1","42.9"
"2",""
"Friday","Hot 🥵"
$ table --table-format double-grid
╔════════╦═════════════╗
║ Day ║ Temperature ║
╠════════╬═════════════╣
║ 1 ║ 42.9 ║
╠════════╬═════════════╣
║ 2 ║ ║
╠════════╬═════════════╣
║ Friday ║ Hot 🥵 ║
╚════════╩═════════════╝
$ table --table-format double-outline
╔════════╦═════════════╗
║ Day ║ Temperature ║
╠════════╬═════════════╣
║ 1 ║ 42.9 ║
║ 2 ║ ║
║ Friday ║ Hot 🥵 ║
╚════════╩═════════════╝
$ table --table-format fancy-grid
╒════════╤═════════════╕
│ Day │ Temperature │
╞════════╪═════════════╡
│ 1 │ 42.9 │
├────────┼─────────────┤
│ 2 │ │
├────────┼─────────────┤
│ Friday │ Hot 🥵 │
╘════════╧═════════════╛
$ table --table-format fancy-outline
╒════════╤═════════════╕
│ Day │ Temperature │
╞════════╪═════════════╡
│ 1 │ 42.9 │
│ 2 │ │
│ Friday │ Hot 🥵 │
╘════════╧═════════════╛
$ table --table-format github
| Day | Temperature |
| :----- | :---------- |
| 1 | 42.9 |
| 2 | |
| Friday | Hot 🥵 |
$ table --table-format grid
+--------+-------------+
| Day | Temperature |
+========+=============+
| 1 | 42.9 |
+--------+-------------+
| 2 | |
+--------+-------------+
| Friday | Hot 🥵 |
+--------+-------------+
$ table --table-format heavy-grid
┏━━━━━━━━┳━━━━━━━━━━━━━┓
┃ Day ┃ Temperature ┃
┣━━━━━━━━╋━━━━━━━━━━━━━┫
┃ 1 ┃ 42.9 ┃
┣━━━━━━━━╋━━━━━━━━━━━━━┫
┃ 2 ┃ ┃
┣━━━━━━━━╋━━━━━━━━━━━━━┫
┃ Friday ┃ Hot 🥵 ┃
┗━━━━━━━━┻━━━━━━━━━━━━━┛
$ table --table-format heavy-outline
┏━━━━━━━━┳━━━━━━━━━━━━━┓
┃ Day ┃ Temperature ┃
┣━━━━━━━━╋━━━━━━━━━━━━━┫
┃ 1 ┃ 42.9 ┃
┃ 2 ┃ ┃
┃ Friday ┃ Hot 🥵 ┃
┗━━━━━━━━┻━━━━━━━━━━━━━┛
$ table --table-format hjson
[
{
Day: 1
Temperature: 42.9
}
{
Day: "2"
Temperature: null
}
{
Day: Friday
Temperature: Hot 🥵
}
]
$ table --table-format html
<table>
<thead>
<tr><th>Day </th><th>Temperature</th></tr>
</thead>
<tbody>
<tr><td>1 </td><td>42.9 </td></tr>
<tr><td>2 </td><td> </td></tr>
<tr><td>Friday</td><td>Hot 🥵 </td></tr>
</tbody>
</table>
$ table --table-format jira
|| Day || Temperature ||
| 1 | 42.9 |
| 2 | |
| Friday | Hot 🥵 |
$ table --table-format json
[
{
"Day": 1,
"Temperature": 42.9
},
{
"Day": "2",
"Temperature": null
},
{
"Day": "Friday",
"Temperature": "Hot 🥵"
}
]
$ table --table-format json5
[
{
"Day": 1,
"Temperature": 42.9
},
{
"Day": "2",
"Temperature": null
},
{
"Day": "Friday",
"Temperature": "Hot 🥵"
}
]
$ table --table-format jsonc
[
{
"Day": 1,
"Temperature": 42.9
},
{
"Day": "2",
"Temperature": null
},
{
"Day": "Friday",
"Temperature": "Hot 🥵"
}
]
$ table --table-format latex
\begin{tabular}{ll}
\hline
Day & Temperature \\
\hline
1 & 42.9 \\
2 & \\
Friday & Hot 🥵 \\
\hline
\end{tabular}
$ table --table-format latex-booktabs
\begin{tabular}{ll}
\toprule
Day & Temperature \\
\midrule
1 & 42.9 \\
2 & \\
Friday & Hot 🥵 \\
\bottomrule
\end{tabular}
$ table --table-format latex-longtable
\begin{longtable}{ll}
\hline
Day & Temperature \\
\hline
\endhead
1 & 42.9 \\
2 & \\
Friday & Hot 🥵 \\
\hline
\end{longtable}
$ table --table-format latex-raw
\begin{tabular}{ll}
\hline
Day & Temperature \\
\hline
1 & 42.9 \\
2 & \\
Friday & Hot 🥵 \\
\hline
\end{tabular}
$ table --table-format mediawiki
{| class="wikitable" style="text-align: left;"
|+ <!-- caption -->
|-
! Day !! Temperature
|-
| 1 || 42.9
|-
| 2 ||
|-
| Friday || Hot 🥵
|}
$ table --table-format mixed-grid
┍━━━━━━━━┯━━━━━━━━━━━━━┑
│ Day │ Temperature │
┝━━━━━━━━┿━━━━━━━━━━━━━┥
│ 1 │ 42.9 │
├────────┼─────────────┤
│ 2 │ │
├────────┼─────────────┤
│ Friday │ Hot 🥵 │
┕━━━━━━━━┷━━━━━━━━━━━━━┙
$ table --table-format mixed-outline
┍━━━━━━━━┯━━━━━━━━━━━━━┑
│ Day │ Temperature │
┝━━━━━━━━┿━━━━━━━━━━━━━┥
│ 1 │ 42.9 │
│ 2 │ │
│ Friday │ Hot 🥵 │
┕━━━━━━━━┷━━━━━━━━━━━━━┙
$ table --table-format moinmoin
|| ''' Day ''' || ''' Temperature ''' ||
|| 1 || 42.9 ||
|| 2 || ||
|| Friday || Hot 🥵 ||
$ table --table-format orgtbl
| Day | Temperature |
|--------+-------------|
| 1 | 42.9 |
| 2 | |
| Friday | Hot 🥵 |
$ table --table-format outline
+--------+-------------+
| Day | Temperature |
+========+=============+
| 1 | 42.9 |
| 2 | |
| Friday | Hot 🥵 |
+--------+-------------+
$ table --table-format pipe
| Day | Temperature |
| :----- | :---------- |
| 1 | 42.9 |
| 2 | |
| Friday | Hot 🥵 |
$ table --table-format plain
Day Temperature
1 42.9
2
Friday Hot 🥵
$ table --table-format presto
Day | Temperature
--------+-------------
1 | 42.9
2 |
Friday | Hot 🥵
$ table --table-format pretty
+--------+-------------+
| Day | Temperature |
+--------+-------------+
| 1 | 42.9 |
| 2 | |
| Friday | Hot 🥵 |
+--------+-------------+
$ table --table-format psql
+--------+-------------+
| Day | Temperature |
|--------+-------------|
| 1 | 42.9 |
| 2 | |
| Friday | Hot 🥵 |
+--------+-------------+
$ table --table-format rounded-grid
╭────────┬─────────────╮
│ Day │ Temperature │
├────────┼─────────────┤
│ 1 │ 42.9 │
├────────┼─────────────┤
│ 2 │ │
├────────┼─────────────┤
│ Friday │ Hot 🥵 │
╰────────┴─────────────╯
$ table --table-format rounded-outline
╭────────┬─────────────╮
│ Day │ Temperature │
├────────┼─────────────┤
│ 1 │ 42.9 │
│ 2 │ │
│ Friday │ Hot 🥵 │
╰────────┴─────────────╯
$ table --table-format rst
====== ===========
Day Temperature
====== ===========
1 42.9
2
Friday Hot 🥵
====== ===========
$ table --table-format simple
Day Temperature
------ -----------
1 42.9
2
Friday Hot 🥵
$ table --table-format simple-grid
┌────────┬─────────────┐
│ Day │ Temperature │
├────────┼─────────────┤
│ 1 │ 42.9 │
├────────┼─────────────┤
│ 2 │ │
├────────┼─────────────┤
│ Friday │ Hot 🥵 │
└────────┴─────────────┘
$ table --table-format simple-outline
┌────────┬─────────────┐
│ Day │ Temperature │
├────────┼─────────────┤
│ 1 │ 42.9 │
│ 2 │ │
│ Friday │ Hot 🥵 │
└────────┴─────────────┘
$ table --table-format textile
|_. Day |_. Temperature |
|<. 1 |<. 42.9 |
|<. 2 |<. |
|<. Friday |<. Hot 🥵 |
$ table --table-format toml
[[record]]
Day = 1
Temperature = 42.9
[[record]]
Day = "2"
[[record]]
Day = "Friday"
Temperature = "Hot 🥵"
$ table --table-format tsv
Day Temperature
1 42.9
2
Friday Hot 🥵
$ table --table-format unsafehtml
<table>
<thead>
<tr><th>Day </th><th>Temperature</th></tr>
</thead>
<tbody>
<tr><td>1 </td><td>42.9 </td></tr>
<tr><td>2 </td><td> </td></tr>
<tr><td>Friday</td><td>Hot 🥵 </td></tr>
</tbody>
</table>
$ table --table-format vertical
***************************[ 1. row ]***************************
Day | 1
Temperature | 42.9
***************************[ 2. row ]***************************
Day | 2
Temperature |
***************************[ 3. row ]***************************
Day | Friday
Temperature | Hot 🥵
$ table --table-format xml
<records>
<record>
<Day>1</Day>
<Temperature>42.9</Temperature>
</record>
<record>
<Day>2</Day>
</record>
<record>
<Day>Friday</Day>
<Temperature>Hot 🥵</Temperature>
</record>
</records>
$ table --table-format yaml
- Day: 1
Temperature: 42.9
- Day: '2'
Temperature: null
- Day: Friday
Temperature: Hot 🥵
$ table --table-format youtrack
|| Day || Temperature ||
| 1 | 42.9 |
| 2 | |
| Friday | Hot 🥵 |
Get table format¶
You can get the ID of the current table format from the context:
import click
from click_extra import echo, pass_context, table_format_option
@click.command
@table_format_option
@pass_context
def vanilla_command(ctx):
format_id = ctx.meta["click_extra.table_format"]
echo(f"Table format: {format_id}")
data = ((1, 87), (2, 80), (3, 79))
headers = ("day", "temperature")
ctx.print_table(data, headers)
$ vanilla --table-format fancy-outline
Table format: fancy-outline
╒═════╤═════════════╕
│ day │ temperature │
╞═════╪═════════════╡
│ 1 │ 87 │
│ 2 │ 80 │
│ 3 │ 79 │
╘═════╧═════════════╛
Data serialization¶
print_data() and serialize_data() handle arbitrary data structures (nested dicts, lists, scalars), unlike print_table() which expects tabular rows and headers. They support the structured serialization formats: JSON, HJSON, YAML, TOML, and XML.
from click_extra import command, pass_context, table_format_option
from click_extra.table import print_data
@command
@table_format_option
@pass_context
def data_command(ctx):
"""Serialize nested data."""
data = {
"city": "Paris",
"population": 2161000,
"landmarks": ["Eiffel Tower", "Louvre", "Notre-Dame"],
}
table_format = ctx.meta["click_extra.table_format"]
print_data(data, table_format)
$ data --table-format json
{
"city": "Paris",
"population": 2161000,
"landmarks": [
"Eiffel Tower",
"Louvre",
"Notre-Dame"
]
}
/home/runner/work/click-extra/click-extra/click_extra/commands.py:485: UserWarning: The parameter --table-format is used more than once. Remove its duplicate as parameters should be unique.
self._resolve_color_eagerly(ctx, args)
/home/runner/work/click-extra/click-extra/.venv/lib/python3.14/site-packages/click/core.py:1262: UserWarning: The parameter --table-format is used more than once. Remove its duplicate as parameters should be unique.
parser = self.make_parser(ctx)
/home/runner/work/click-extra/click-extra/.venv/lib/python3.14/site-packages/cloup/constraints/_support.py:183: UserWarning: The parameter --table-format is used more than once. Remove its duplicate as parameters should be unique.
args = super().parse_args(ctx, args) # type: ignore
$ data --table-format yaml
city: Paris
landmarks:
- Eiffel Tower
- Louvre
- Notre-Dame
population: 2161000
serialize_data() returns the serialized string instead of printing it:
Sorted tables¶
SortByOption adds a --sort-by CLI option whose choices are derived from column definitions. Column definitions are (label, column_id) tuples. Columns with column_id=None are displayed but not offered as sort choices.
The option can be repeated to define a multi-column sort priority: --sort-by name --sort-by age sorts by name first, then breaks ties by age.
When active, SortByOption replaces ctx.print_table with a sorted variant, so the command body doesn’t need any sorting logic.
from click_extra import command, pass_context, table_format_option
from click_extra.table import SortByOption
sort_opt = SortByOption(
("Fruit", "fruit"),
("Count", "count"),
("Notes", None),
)
@command(params=[sort_opt])
@table_format_option
@pass_context
def inventory(ctx):
"""Sortable fruit inventory."""
headers = ("Fruit", "Count", "Notes")
data = [
["Cherry", "50", "seasonal"],
["Apple", "120", ""],
["Banana", "80", "organic"],
]
ctx.print_table(data, headers)
$ inventory --help
Usage: inventory [OPTIONS]
Sortable fruit inventory.
Options:
--sort-by [fruit|count] Sort table by this column. Repeat to set priority.
[default: fruit]
--table-format [aligned|asciidoc|colon-grid|csv|csv-excel|csv-excel-tab|csv-unix|double-grid|double-outline|fancy-grid|fancy-outline|github|grid|heavy-grid|heavy-outline|hjson|html|jira|json|json5|jsonc|latex|latex-booktabs|latex-longtable|latex-raw|mediawiki|mixed-grid|mixed-outline|moinmoin|orgtbl|outline|pipe|plain|presto|pretty|psql|rounded-grid|rounded-outline|rst|simple|simple-grid|simple-outline|textile|toml|tsv|unsafehtml|vertical|xml|yaml|youtrack]
Rendering style of tables. [default: rounded-
outline]
-h, --help Show this message and exit.
$ inventory --table-format rounded-outline --sort-by fruit
╭────────┬───────┬──────────╮
│ Fruit │ Count │ Notes │
├────────┼───────┼──────────┤
│ Apple │ 120 │ │
│ Banana │ 80 │ organic │
│ Cherry │ 50 │ seasonal │
╰────────┴───────┴──────────╯
$ inventory --table-format rounded-outline --sort-by count
╭────────┬───────┬──────────╮
│ Fruit │ Count │ Notes │
├────────┼───────┼──────────┤
│ Apple │ 120 │ │
│ Cherry │ 50 │ seasonal │
│ Banana │ 80 │ organic │
╰────────┴───────┴──────────╯
Repeating --sort-by sets multi-column priority. Here, rows are sorted by count first, then ties broken by fruit name:
$ inventory --table-format rounded-outline --sort-by count --sort-by fruit
╭────────┬───────┬──────────╮
│ Fruit │ Count │ Notes │
├────────┼───────┼──────────┤
│ Apple │ 120 │ │
│ Cherry │ 50 │ seasonal │
│ Banana │ 80 │ organic │
╰────────┴───────┴──────────╯
For programmatic use without a CLI option, render_table() accepts a sort_key callable:
from click_extra import command, echo
from click_extra.table import render_table, TableFormat
@command
def sorted_demo():
"""Render a table sorted alphabetically."""
data = [["Cherry", "50"], ["Apple", "120"], ["Banana", "80"]]
output = render_table(
data,
headers=["Fruit", "Count"],
table_format=TableFormat.ROUNDED_OUTLINE,
sort_key=lambda row: row[0],
)
echo(output)
$ sorted-demo
╭────────┬───────╮
│ Fruit │ Count │
├────────┼───────┤
│ Apple │ 120 │
│ Banana │ 80 │
│ Cherry │ 50 │
╰────────┴───────╯
click_extra.table API¶
classDiagram
Enum <|-- TableFormat
ExtraOption <|-- ColumnsOption
ExtraOption <|-- SortByOption
ExtraOption <|-- TableFormatOption
MultiChoice <|-- ColumnsType
Collection of table rendering utilities.
- class click_extra.table.TableFormat(*values)[source]
Bases:
EnumEnumeration of supported table formats.
Hard-coded to be in alphabetical order. Content of this enum is checked in unit tests.
Warning
The
youtrackformat is missing in action from any official JetBrains documentation. It will be removed in python-tabulate v0.11.- ALIGNED = 'aligned'
- ASCIIDOC = 'asciidoc'
- COLON_GRID = 'colon-grid'
- CSV = 'csv'
- CSV_EXCEL = 'csv-excel'
- CSV_EXCEL_TAB = 'csv-excel-tab'
- CSV_UNIX = 'csv-unix'
- DOUBLE_GRID = 'double-grid'
- DOUBLE_OUTLINE = 'double-outline'
- FANCY_GRID = 'fancy-grid'
- FANCY_OUTLINE = 'fancy-outline'
- GITHUB = 'github'
- GRID = 'grid'
- HEAVY_GRID = 'heavy-grid'
- HEAVY_OUTLINE = 'heavy-outline'
- HJSON = 'hjson'
- HTML = 'html'
- JIRA = 'jira'
- JSON = 'json'
- JSON5 = 'json5'
- JSONC = 'jsonc'
- LATEX = 'latex'
- LATEX_BOOKTABS = 'latex-booktabs'
- LATEX_LONGTABLE = 'latex-longtable'
- LATEX_RAW = 'latex-raw'
- MEDIAWIKI = 'mediawiki'
- MIXED_GRID = 'mixed-grid'
- MIXED_OUTLINE = 'mixed-outline'
- MOINMOIN = 'moinmoin'
- ORGTBL = 'orgtbl'
- OUTLINE = 'outline'
- PIPE = 'pipe'
- PLAIN = 'plain'
- PRESTO = 'presto'
- PRETTY = 'pretty'
- PSQL = 'psql'
- ROUNDED_GRID = 'rounded-grid'
- ROUNDED_OUTLINE = 'rounded-outline'
- RST = 'rst'
- SIMPLE = 'simple'
- SIMPLE_GRID = 'simple-grid'
- SIMPLE_OUTLINE = 'simple-outline'
- TEXTILE = 'textile'
- TOML = 'toml'
- TSV = 'tsv'
- UNSAFEHTML = 'unsafehtml'
- VERTICAL = 'vertical'
- XML = 'xml'
- YAML = 'yaml'
- YOUTRACK = 'youtrack'
- property is_markup: bool
Whether this format is a markup rendering.
Markup formats have ANSI color codes stripped from their output by default. Use the
--colorflag to preserve them.
- click_extra.table.MARKUP_FORMATS = frozenset({TableFormat.ASCIIDOC, TableFormat.CSV, TableFormat.CSV_EXCEL, TableFormat.CSV_EXCEL_TAB, TableFormat.CSV_UNIX, TableFormat.GITHUB, TableFormat.HJSON, TableFormat.HTML, TableFormat.JIRA, TableFormat.JSON, TableFormat.JSON5, TableFormat.JSONC, TableFormat.LATEX, TableFormat.LATEX_BOOKTABS, TableFormat.LATEX_LONGTABLE, TableFormat.LATEX_RAW, TableFormat.MEDIAWIKI, TableFormat.MOINMOIN, TableFormat.ORGTBL, TableFormat.PIPE, TableFormat.RST, TableFormat.TEXTILE, TableFormat.TOML, TableFormat.TSV, TableFormat.UNSAFEHTML, TableFormat.XML, TableFormat.YAML, TableFormat.YOUTRACK})
Subset of table formats that are considered as markup rendering.
- click_extra.table.DEFAULT_FORMAT = TableFormat.ROUNDED_OUTLINE
Default table format, if none is specified.
- click_extra.table.RECORD_KEY = 'record'
Key used for each record in structured formats that require named containers (TOML
[[record]], XML<record>).
- click_extra.table.XML_ROOT_KEY = 'records'
Root element name for XML table output.
- click_extra.table.SERIALIZATION_FORMATS = frozenset({TableFormat.HJSON, TableFormat.JSON, TableFormat.JSON5, TableFormat.JSONC, TableFormat.TOML, TableFormat.XML, TableFormat.YAML})
Structured serialization formats whose renderers escape raw ESC bytes, making post-render
strip_ansi()ineffective.
- click_extra.table.render_table(table_data, headers=None, table_format=None, sort_key=None, **kwargs)[source]
Render a table and return it as a string.
- click_extra.table.print_table(table_data, headers=None, table_format=None, sort_key=None, **kwargs)[source]
Render a table and print it to the console.
For markup formats, ANSI color codes are stripped from cell values before rendering unless
--coloris explicitly set.
- click_extra.table.serialize_data(data, table_format, *, default=None, root_element='records', **kwargs)[source]
Serialize arbitrary Python data to a structured format.
Unlike
render_table()which expects tabular rows and headers, this function accepts any JSON-compatible data structure (dicts, lists, nested combinations) and serializes it to the requested format.Only formats in
SERIALIZATION_FORMATSare supported.- Parameters:
data (
Any) – Arbitrary data to serialize (dicts, lists, scalars).table_format (
TableFormat) – Target serialization format.default (
Callable|None) – Fallback serializer for types not natively supported. Defaults tostr, soPathand similar types are stringified automatically. Set to a custom callable for different behavior.root_element (
str) – Root element name for XML output.kwargs – Extra keyword arguments forwarded to the underlying serializer (like
sort_keysorindentfor JSON).
- Raises:
ValueError – If the format is not a serialization format.
- Return type:
- click_extra.table.print_data(data, table_format, *, default=None, root_element='records', package='click-extra', **kwargs)[source]
Serialize arbitrary Python data and print it to the console.
Wraps
serialize_data()with user-friendly error handling for missing optional dependencies.- Parameters:
data (
Any) – Arbitrary data to serialize.table_format (
TableFormat) – Target serialization format.default (
Callable|None) – Fallback serializer for custom types. Defaults tostr.root_element (
str) – Root element name for XML output.package (
str) – Package name for install instructions in error messages.kwargs – Extra keyword arguments forwarded to the underlying serializer.
- Return type:
- class click_extra.table.TableFormatOption(param_decls=None, type=EnumChoice('aligned', 'asciidoc', 'colon-grid', 'csv', 'csv-excel', 'csv-excel-tab', 'csv-unix', 'double-grid', 'double-outline', 'fancy-grid', 'fancy-outline', 'github', 'grid', 'heavy-grid', 'heavy-outline', 'hjson', 'html', 'jira', 'json', 'json5', 'jsonc', 'latex', 'latex-booktabs', 'latex-longtable', 'latex-raw', 'mediawiki', 'mixed-grid', 'mixed-outline', 'moinmoin', 'orgtbl', 'outline', 'pipe', 'plain', 'presto', 'pretty', 'psql', 'rounded-grid', 'rounded-outline', 'rst', 'simple', 'simple-grid', 'simple-outline', 'textile', 'toml', 'tsv', 'unsafehtml', 'vertical', 'xml', 'yaml', 'youtrack'), default=TableFormat.ROUNDED_OUTLINE, expose_value=False, is_eager=True, help='Rendering style of tables.', **kwargs)[source]
Bases:
ExtraOptionA pre-configured option that is adding a
--table-formatflag to select the rendering style of a table.The selected table format ID is made available in the context in
ctx.meta[click_extra.context.TABLE_FORMAT], and two helper methods are added to the context:ctx.render_table(table_data, headers, **kwargs): renders and returns the table as a string,ctx.print_table(table_data, headers, **kwargs): renders and prints the table to the console.
Where:
table_datais a 2-dimensional iterable of iterables for rows and cells values,headersis a list of string to be used as column headers,**kwargsare any extra keyword arguments supported by the underlying table formatting function.
- class click_extra.table.ColumnSpec(id, label, description='')[source]
Bases:
objectRich description of a single column in a rendered table.
Three fields, all required-by-convention even though
descriptiondefaults to empty so quick prototypes do not have to write a sentence for every column:id: stable, snake_case identifier used by--columnsto address the column, to key structured-format serializations, and to thread state throughclick_extra.context.COLUMNS.label: the human-readable header shown at the top of the rendered table.description: a MyST/Markdown blurb describing what the column represents. Used to auto-generate the column reference in the documentation.
Note
Frozen + slots: instances are immutable and lightweight. Tuples of
ColumnSpecare intended to be defined as module-level constants (likeclick_extra.parameters.ShowParamsOption.TABLE_HEADERS).- id: str
Stable, snake_case identifier addressing this column from CLI flags and code.
- label: str
Human-readable header label rendered at the top of the table.
- description: str
MyST/Markdown description of what the column carries.
Used to auto-generate the Available columns section in the docs via the
show_params_columns_tableMyST substitution. Plain text without inline markup is fine: links and emphasis are optional sugar.
- click_extra.table.render_columns_markdown_table(columns)[source]
Render an iterable of
ColumnSpecas a 2-column Markdown table.Output shape:
| Column | Description | | :--- | :--- | | `Label` | description | ...
Suitable for inlining into MyST documents via
myst_substitutionsso the Available columns reference can be auto-generated from a single source of truth.- Return type:
- click_extra.table.select_columns(columns, selected_ids)[source]
Filter and reorder
columnsaccording toselected_ids.Returns
columnsunchanged whenselected_idsis falsy (no projection). Otherwise yields the matchingColumnSpecin the orderselected_idsspecifies, SQL-SELECT-style. RaisesKeyErrorfor unknown IDs so the caller can convert it into aclick.UsageError.- Return type:
- click_extra.table.select_row(row, selected_ids, canonical_ids)[source]
Build a positional row by reading cells from
rowin the selection order.Falls back to
canonical_idswhenselected_idsis empty / unset, so the row preserves its canonical column order in the absence of any user selection.- Return type:
- class click_extra.table.ColumnsType(accepted_ids=())[source]
Bases:
MultiChoiceColumn-flavored alias of
click_extra.types.MultiChoice.Pins the comma separator and case-sensitive matching (column IDs are snake_case identifiers, not free-form strings), and renames the metavar fallback to
COLUMNSinstead of the genericMULTI. Theaccepted_idsconstructor keyword is a column-flavored alias ofMultiChoice.choices.Initialize the type.
- Parameters:
choices – the accepted values. When non-empty,
convert()rejects unknown tokens withfail. When empty, the type behaves as a pure separator-aware parser and leaves validation to the consumer.separator – the token boundary. Use any single character; this also drives the metavar rendering (
[a<sep>b<sep>c]).case_sensitive – when
False, tokens matchchoicescase-insensitively and the returned tuple holds the canonical (original-case) values fromchoices.
- name: str = 'columns'
the descriptive name of this type
- class click_extra.table.ColumnsOption(param_decls=None, columns=None, type=None, default=(), expose_value=False, is_eager=True, help='Restrict and reorder table columns, SQL SELECT-style. Comma-separated list of column IDs. Default: all columns in canonical order.', **kwargs)[source]
Bases:
ExtraOptionA
--columnsoption that lets users restrict and reorder table columns.Accepts a comma-separated list of column IDs, SQL-
SELECT-style:$ my-cli --columns id,spec,value --show-params
The selection is stored in
ctx.meta[click_extra.context.COLUMNS]and consumed by table-rendering callbacks (likeclick_extra.parameters.ShowParamsOption) to project rows + headers before rendering.Pass
columns=at construction time with the column registry the option should advertise: the help text then lists the accepted IDs and the default selection, and the callback validates the user input against that registry so unknown IDs fail fast with aclick.UsageError. Withoutcolumns=, the option stays generic: it parses any IDs and leaves validation to the downstream consumer.Empty / unset means render every column in canonical order: the default behavior, indistinguishable from not passing
--columnsat all.- columns: tuple[ColumnSpec, ...]
Column registry this option advertises and validates against (may be empty).
- class click_extra.table.SortByOption(*header_defs, param_decls=None, default=None, expose_value=False, cell_key=None, help='Sort table by this column. Repeat to set priority.', **kwargs)[source]
Bases:
ExtraOptionA
--sort-byoption whose choices are derived from column definitions.Stores the selected column IDs in
ctx.meta[click_extra.context.SORT_BY]and bakes a row sort intoctx.print_tableso that table output is automatically sorted, without changing its(table_data, headers)call contract. The option acceptsmultiple=True, so users can repeat--sort-byto define a multi-column sort priority.@command @table_format_option @sort_by_option( ("Package ID", "package_id"), ("Name", "package_name"), ("Manager", "manager_id"), ("Version", None), ) @pass_context def my_cmd(ctx): ctx.print_table(rows, headers)
- init_sort(ctx, param, sort_columns)[source]
Bake the row sort key into
ctx.print_table.Builds the sort key from this option’s column definitions and the selected
sort_columns, then rebindsctx.print_tabletoprint_table()with that key applied. The call contract is the same sorted or not:ctx.print_table(table_data, headers).- Return type: