Skip to content

MKuranowski/table2md

Repository files navigation

table2md

Print tabular data in markdown format

Installation

Tested on Pythons above 3.6+. pip3 install table2md

Usage

from table2md import MarkdownTable

# All following examples print the following table onto stdout:
# | constant | value |
# |----------|-------|
# | e        | 2.71  |
# | pi       | 3.14  |
# | sqrt2    | 1.41  |

# With dictionaries
MarkdownTable.from_dicts([
    {"constant": "e", "value": 2.71},
    {"constant": "pi", "value": 3.14},
    {"constant": "sqrt2", "value": 1.41},
]).print()

# With 2D iterables
MarkdownTable.from_2d_iterable([
    ["constant", "value"],
    ["pi", 6.28],
    ["e", 2.71],
    ["sqrt2", 1.41],
]).print()

# With named tuples
from typing import NamedTuple

class Constant(NamedTuple):
    constant: str
    value: float

MarkdownTable.from_namedtuples([
    Constant("e", 2.71),
    Constant("pi", 3.14),
    Constant("sqrt2", 1.41),
]).print()

MarkdownTable automatically coalesces all values into strings (with str(value)); with the exception of the MarkdownTable.from_dicts, where keys are assumed to be strings.

To use custom formatting, either coalesce values into strings on your own, use your own classes with custom __str__ methods, or use the special MarkdownTable.from_serializable constructor.

It takes an iterable of objects with _fields property and a serialize method. Example:

from table2md import MarkdownTable
from typing import NamedTuple
from datetime import datetime

# Named tuples already provide the _fields property,
# so we only need to implement the serialize method.
class TemperatureReadout(NamedTuple):
    tstamp: datetime
    value: float

    def serialize(self) -> tuple[str, str]:
        return self.tstamp.strftime("%Y-%m-%d %H:%M"), f"{self.value:.1f}"

MarkdownTable.from_serializable([
    TemperatureReadout(datetime(2021, 11, 1, 10, 0, 0), 10.411),
    TemperatureReadout(datetime(2021, 11, 1, 12, 0, 0), 12.782),
    TemperatureReadout(datetime(2021, 11, 1, 14, 0, 0), 11.214),
]).print()
# Output:
# |      tstamp      | value |
# |------------------|-------|
# | 2021-11-01 10:00 | 10.4  |
# | 2021-11-01 12:00 | 12.8  |
# | 2021-11-01 14:00 | 11.2  |

Documentation

MarkdownTable

A class to represent tabular data

  • MarkdownTable(data: List[List[Str]]):
    Initializes a table from a 2D list of strings. 1st row is always the header row. See utility MarkdownTable.from_* helper classmethods. Provided lists are not copied!

  • markdown_table.__str__() -> str:
    Serializes the contained tabular data to a markdown table. First row is assumed to be the header row.

  • markdown_table.validate() -> None:
    Ensures the contained table is good-to-print - that is it has a header; and all rows with data have the same number of cells as the header.
    Raises a sub-class of InvalidData in case invalid state is detected.

  • markdown_table.print(end: str = "", file: SupportsWrite[str] = sys.stdout, flush: bool = False) -> None:
    Validates the table, and then prints it. 'end', 'file' and 'flush' arguments are passed through to the builtin print function.
    Pleas note that the serialized table already has a newline at the end, so end="\n" is not necessary.

  • markdown_table.display() -> None:
    Validates the table, then tries to pretty-print using IPython.display.display_markdown.

    If that is not available, the same as table.print()

  • MarkdownTable.from_2d_iterable(iters: Iterable[Iterable[Any]]) -> MarkdownTable:
    Initializes the table from a 2D iterable. Every cell is saved by calling str(cell). If provided with a 2D list, those lists are copied (this is different to the behavior from the constructor).

  • MarkdownTable.from_dicts(dicts: Iterable[Mapping[str, Any]]) -> MarkdownTable::
    Initializes the table from an iterable of dictionaries. Every value is saved by calling str(cell).
    Only keys from the first dictionary are used; that is any extra key in other dictionaries are ignored. However, if a following dict has a missing key, KeyError is thrown.

  • MarkdownTable.from_namedtuples(named_tuples: Iterable[_NamedTupleLike]) -> MarkdownTable:
    Initializes the table from an iterable of NamedTuples.
    Well, in reality those don't have to be NamedTuples per se; as longs at the objects have a _fields property and one can iterate over those objects this function works fine.
    First object's _fields property is the header row.
    If objects aren't of the same type, ensure all of them have the same amount of fields; otherwise an invalid table is created.

  • MarkdownTable.from_serializable(objects: Iterable[_Serializable]) -> MarkdownTable:
    This is an extension of from_namedtuples; but instead of iterating over those objects directly, obj.serialize() is used to get the string representations of the cells.
    So, as long as objects have the _fields property and a serialize() method; this method works fine.
    First object's _fields property is the header row.
    Ensure all object's serialize() method yield the same amount of cells, otherwise an invalid table is created.

Exceptions

  • InvalidData: Base exception fort use in table validation. Subclasses ValueError.

  • NoData: Exception used when a table has absolutely no data; not even a header row. Subclasses InvalidData.

  • MisalignedRows: Exception used when a table has rows with more/less cells than the header. Subclasses InvalidData.

Protocols/Interfaces

  • SupportsWrite[str]: Anything with a write method accepting a string argument. Implemented by the _typeshed module.

  • _NamedTupleLike: Anything with a _fields property, which is an iterable of strings representing field names; that is itself iterable.

  • _Serializable: Anything with a _fields property, which is an iterable of strings representing field names; and with a serialize() -> Iterable[str] method which returns all the held field values as strings.

About

Print tabular data in markdown format in Python

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages