Usage

The enum-table directive takes the import path of an enumeration and renders a table with a row for each member. It is designed for dataclass enums, where each field of the dataclass becomes a column. By default the columns are:

  1. name - the member’s name.

  2. dataclass fields - if the enum mixes in a dataclass or its values are dataclasses or named tuples.

  3. value - the member’s value, only included when the values are not dataclasses or named tuples.

  4. enum-properties properties - a special case, in the order they are declared.

  5. doc - member docstrings, if any member has one.

Dataclass Enums

Mixing a dataclass into an enumeration makes each member a dataclass instance. Each field is rendered as a column:

@dataclass(frozen=True)
class PlanetData:
    mass: float
    """Mass in kilograms."""

    radius: float
    """Radius in meters."""

    #: Number of known moons.
    moons: int


class Planet(PlanetData, Enum):
    MERCURY = 3.303e23, 2.4397e6, 0
    VENUS = 4.869e24, 6.0518e6, 0
    EARTH = 5.976e24, 6.37814e6, 1
    MARS = 6.421e23, 3.3972e6, 2
.. enum-table:: examples.Planet
   :caption: The inner planets.
The inner planets.

name

mass

radius

moons

MERCURY

3.303e+23

2439700.0

0

VENUS

4.869e+24

6051800.0

0

EARTH

5.976e+24

6378140.0

1

MARS

6.421e+23

3397200.0

2

Dataclass Values

Enumerations whose values are dataclass (or namedtuple()) instances are rendered the same way. The value’s fields replace the value column:

@dataclass(frozen=True)
class RGB:
    red: int
    green: int
    blue: int


class Color(Enum):
    RED = RGB(255, 0, 0)
    GREEN = RGB(0, 255, 0)
    BLUE = RGB(0, 0, 255)
.. enum-table:: examples.Color

name

red

green

blue

RED

255

0

0

GREEN

0

255

0

BLUE

0

0

255

Member Docstrings

If any member in the table has a docstring, the docstrings are added in a column called doc. Docstrings are found the same way autodoc finds them: a string literal immediately after the member, or a #: comment before it. A __doc__ attribute set on the member itself (for example by the enum’s __init__) takes precedence. Members without a docstring have an empty cell.

class Severity(IntEnum):
    DEBUG = 10
    """Diagnostic detail, usually disabled in production."""

    INFO = 20
    """Routine operational messages."""

    #: Something unexpected happened that the application **recovered** from.
    WARNING = 30

    ERROR = 40
    """A failure that needs attention.

    See :ref:`usage` for how to render these tables."""

    CRITICAL = 50
.. enum-table:: examples.Severity

name

value

doc

DEBUG

10

Diagnostic detail, usually disabled in production.

INFO

20

Routine operational messages.

WARNING

30

Something unexpected happened that the application recovered from.

ERROR

40

A failure that needs attention.

See Usage for how to render these tables.

CRITICAL

50

Docstrings are parsed as reStructuredText, so inline markup, cross references and multiple paragraphs work. CSV and JSON downloads contain the rendered text of the docstring.

  • The doc column is appended after the other columns. If a column with the same name already exists (e.g. a dataclass field called doc) the docstrings override it in place.

  • Use enum-table:doc-column to give the column a different name, for example if you want to keep a doc field as well as the docstrings.

  • Use enum-table:docs to turn the doc column off. The column name is then an ordinary column again.

  • When enum-table:columns is given, the doc column is only included where it is listed.

  • Only the rendered members are considered. If none of them has a docstring there is no doc column.

.. enum-table:: examples.Severity
   :doc-column: description
   :headers: description=Description

.. enum-table:: examples.Severity
   :docs: false

Column Legend

Set enum-table:legend to describe the table’s columns in a legend beneath it. Column descriptions come from the docstrings of the attributes behind each column:

  • dataclass fields - a string literal immediately after the field, a #: comment before it, or dataclasses.field(doc=...) on Python 3.14+. Fields inherited from base dataclasses are included.

  • enum-properties properties - docstrings on the property annotations (see enum-properties Enums).

  • named tuple fields, and properties defined with @property (their __doc__).

Only documented columns are listed, in column order and labeled with their headers. If no rendered column is documented, there is no legend. Descriptions are parsed as reStructuredText.

.. enum-table:: examples.Planet
   :legend:

name

mass

radius

moons

MERCURY

3.303e+23

2439700.0

0

VENUS

4.869e+24

6051800.0

0

EARTH

5.976e+24

6378140.0

1

MARS

6.421e+23

3397200.0

2

mass

Mass in kilograms.

radius

Radius in meters.

moons

Number of known moons.

The legend is a definition list, so it renders in every builder, including PDF. In HTML the table is linked to its legend with aria-describedby so screen readers announce the descriptions with the table. Legends are off by default.

Note

Column descriptions are rendered as a visible legend rather than as tooltips on the headers because tooltips (title attributes) are only available to mouse users and are not reliably announced by screen readers.

Selecting Columns

Use enum-table:columns to choose which columns are shown and in what order. Columns may be any attribute on the member (including properties and methods decorated with @property) or a dotted path. Attributes that are not found on the member are looked up on the member’s value. Use enum-table:exclude to drop columns from the defaults instead.

class Priority(IntEnum):
    LOW = 1
    MEDIUM = 5
    HIGH = 10

    @property
    def urgent(self) -> bool:
        return self >= Priority.HIGH
.. enum-table:: examples.Priority
   :columns: name, value, urgent
   :headers: name=Priority, value=Weight, urgent=Urgent?

Priority

Weight

Urgent?

LOW

1

False

MEDIUM

5

False

HIGH

10

True

Selecting Members

Use enum-table:members to choose which members are shown and in what order and enum-table:exclude-members to drop members.

.. enum-table:: examples.Planet
   :members: EARTH, MARS
   :exclude: moons

name

mass

radius

EARTH

5.976e+24

6378140.0

MARS

6.421e+23

3397200.0

Formatting Cells

By default cells are converted to text with format_value(). Enum members render as ClassName.MEMBER, sequences render as comma separated values and name cells render as inline literals. You can change how cells render by supplying a formatter function, either for all tables with the enum_table_formatter configuration value or for a single table with the enum-table:formatter option. Formatters are passed the member, the column name and the raw value. They may return text, a docutils node or None to fall back to the default formatting:

def planet_formatter(member: Enum, column: str, value: t.Any):
    if column in ("mass", "radius"):
        unit = "kg" if column == "mass" else "m"
        return nodes.Text(f"{value:.3e} {unit}")
    return None  # use the default formatting
.. enum-table:: examples.Planet
   :formatter: examples.planet_formatter

name

mass

radius

moons

MERCURY

3.303e+23 kg

2.440e+06 m

0

VENUS

4.869e+24 kg

6.052e+06 m

0

EARTH

5.976e+24 kg

6.378e+06 m

1

MARS

6.421e+23 kg

3.397e+06 m

2

Downloads

Tables can offer download buttons for CSV and JSON versions of their data. Downloads are off by default. Turn them on for every table with enum_table_download:

# conf.py
enum_table_download = True  # or a list of formats, e.g. ["json"]

HTML builders render the buttons below the table. Other builders (e.g. LaTeX/PDF, text and epub) omit them. Tables render natively in every builder, including PDF.

  • CSV files contain the header row and the display text of every cell, exactly as rendered.

  • JSON files contain an object keyed by member name. Each member maps to an object keyed by column name (the name column is omitted since it is the key). Native JSON types (strings, numbers, booleans and null) are preserved. Lists, tuples, dicts, dataclasses and named tuples are converted to their JSON equivalents, and any other values use their display text. For example:

    {
      "MERCURY": {"mass": 3.303e+23, "radius": 2439700.0, "moons": 0},
      "VENUS": {"mass": 4.869e+24, "radius": 6051800.0, "moons": 0}
    }
    

Use enum-table:download to override the setting for a single table, either to add downloads to a table when they are off globally or to remove them when they are on. Given without a value it offers every format:

.. enum-table:: examples.Planet
   :download:

.. enum-table:: examples.Planet
   :download: json

.. enum-table:: examples.Planet
   :download: none

Theme Styling

Tables are ordinary Sphinx tables, so they are styled by your html theme. The extension adds a small theme-neutral stylesheet for the layout of the legend and the download buttons, and extra styles for themes it knows:

  • furo - striped rows, a row hover highlight, left-aligned headers and a visible table edge in dark mode. These use furo’s color variables, so they follow its light, dark and auto modes.

Every rendered table is a table.enum-table inside a div.enum-table-container. To change the styling, add your own stylesheet with html_css_files, it is loaded after the extension’s stylesheets:

# conf.py
html_static_path = ["_static"]
html_css_files = ["custom.css"]
/* _static/custom.css - turn off the striped rows */
.enum-table-container table.enum-table > tbody > tr:nth-child(even) {
    background: none;
}

enum-properties Enums

enum-properties enums are supported as a special case. Each declared property is rendered as a column after the value column (and after any dataclass fields if the enum also mixes in a dataclass). enum-properties is not a dependency of this extension. Its enums are detected automatically. Docstrings on the property annotations describe their columns in the column legend.

class Shade(EnumProperties):
    label: t.Annotated[str, Symmetric()]
    """A human readable label."""

    hex: t.Annotated[str, Symmetric(case_fold=True)]
    """The hex color code, without a leading ``#``."""

    RED = 1, "Red", "ff0000"
    GREEN = 2, "Green", "00ff00"
    BLUE = 3, "Blue", "0000ff"
.. enum-table:: examples.Shade
   :legend:

name

value

label

hex

RED

1

Red

ff0000

GREEN

2

Green

00ff00

BLUE

3

Blue

0000ff

label

A human readable label.

hex

The hex color code, without a leading #.

Cross Referencing

Give a table a enum-table:name to reference it with ref or, when numfig is enabled and the table has a caption, numref.

.. enum-table:: examples.Planet
   :caption: The inner planets.
   :name: planets

See :ref:`planets`.

Named tables are added to the project’s intersphinx inventory as std:label entries, so other projects can link to them too (e.g. :ref:`yourdocs:planets`). Tables without a name are not in the inventory.

Note

The directive only documents the enumeration as a table. It does not register the enum class or its members as Python objects, so roles like py:class and py:attr will not resolve to the table (locally or through intersphinx). Member names and enum-valued cells are rendered as text, not links. To make the enum and its members referenceable, also document them with autodoc (e.g. autoclass) and those references will resolve to the autodoc entries.