https://github.com/tmarktaylor/monotable
ASCII table with per column format specs, multi-line content, plug-in format functions, column width control.
https://github.com/tmarktaylor/monotable
ascii-table dataclass
Last synced: 3 months ago
JSON representation
ASCII table with per column format specs, multi-line content, plug-in format functions, column width control.
- Host: GitHub
- URL: https://github.com/tmarktaylor/monotable
- Owner: tmarktaylor
- License: apache-2.0
- Created: 2017-03-20T17:03:11.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2024-09-14T15:14:23.000Z (almost 2 years ago)
- Last Synced: 2025-09-28T15:04:50.493Z (9 months ago)
- Topics: ascii-table, dataclass
- Language: Python
- Homepage: https://github.com/tmarktaylor/monotable/blob/v3.2.0/README.md
- Size: 465 KB
- Stars: 4
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: contributing.md
- License: LICENSE
Awesome Lists containing this project
README
# monotable
ASCII table with per column format specs, multi-line content,
formatting directives, column width control.
Dataclass to ASCII table printer.
## default branch status
[](http://www.apache.org/licenses/LICENSE-2.0)
[](https://pypi.python.org/pypi/monotable)
[](https://pypi.python.org/pypi/monotable)
[](https://github.com/tmarktaylor/monotable/actions/workflows/ci.yml)
[](https://monotable.readthedocs.io/en/latest/?badge=latest)
[](https://codecov.io/gh/tmarktaylor/monotable)
[Docs](https://monotable.readthedocs.io/en/latest/) |
[Repos](https://github.com/tmarktaylor/monotable) |
[Codecov](https://codecov.io/gh/tmarktaylor/monotable?branch=master) |
[License](https://github.com/tmarktaylor/monotable/blob/master/LICENSE)
## Sample usage
```python
from monotable import mono
headings = ["purchased\nparrot\nheart rate", "life\nstate"]
# > is needed to right align None cell since it auto-aligns to left.
# monotable uses empty string to format the second column.
formats = [">(none=rest).0f"]
cells = [
[0, "demised"],
[0.0, "passed on"],
[None, "is no more"],
[-1],
[0, "ceased to be"],
]
print(
mono(
headings,
formats,
cells,
title="Complaint\n(registered)",
# top guideline is equals, heading is period, bottom is omitted.
guideline_chars="=. ",
)
)
```
sample output:
```expected-output
Complaint
(registered)
========================
purchased
parrot life
heart rate state
........................
0 demised
0 passed on
rest is no more
-1
0 ceased to be
```
## Dataclass to ASCII Table printer
```python
from dataclasses import dataclass, field
from enum import auto, Enum
from monotable import dataclass_print
from monotable import dataclass_format
from monotable import stow
```
### Print a dataclass instance
Print a dataclass as an ASCII table. The field names are left
justified in the left column. The values are right justified
in the right column.
```python
@dataclass
class CurrentConditions:
temperature: float
humidity: float
heat_index: int
weather_data = CurrentConditions(80.0, 0.71, 83)
dataclass_print(weather_data)
```
```expected-output
CurrentConditions
-----------------
temperature 80.0
humidity 0.71
heat_index 83
-----------------
```
### Title
The table title defaults to the class name. The string passed
to the "title" keyword is prepended to the class name.
```python
dataclass_print(weather_data, title="Airport")
```
```expected-output
Airport : CurrentConditions
-----------------
temperature 80.0
humidity 0.71
heat_index 83
-----------------
```
### Format and print later
Call dataclass_format() to print or log later.
```python
text = dataclass_format(weather_data, title="Airport")
print(text)
```
```expected-output
Airport : CurrentConditions
-----------------
temperature 80.0
humidity 0.71
heat_index 83
-----------------
```
### Add a format spec to a dataclass field
Specify formatting for a data class field as shown for
the field() call in place of the default value for the
humidity field below.
The function stow() assigns the dict {"spec": ".0%"} to
the field's metadata dict as the value for the key
"monotable".
The code internally applies this f-string: f"{value:{spec}}"
to format the value.
```python
@dataclass
class SpecCurrentConditions:
temperature: float
humidity: float = field(metadata=stow(spec=".0%"))
heat_index: int
weather_data = SpecCurrentConditions(80.0, 0.71, 83)
dataclass_print(weather_data)
```
```expected-output
SpecCurrentConditions
-----------------
temperature 80.0
humidity 71%
heat_index 83
-----------------
```
### Add a format function to a dataclass field
Specify a format function to do the formatting for a field.
Set the 'spec' key to a callable.
The function takes the field value as the parameter and returns a string.
The string is printed in the table. Note that just the enumeration
name "E" is printed instead of "Direction.E".
```python
class Direction(Enum):
N = auto()
E = auto()
S = auto()
W = auto()
@dataclass
class Wind:
speed: int
direction: Direction = field(metadata=stow(spec=lambda x: x.name))
wind_data = Wind(speed=11,direction=Direction.E)
dataclass_print(wind_data)
```
```expected-output
Wind
-------------
speed 11
direction E
-------------
```
### Add text to embellish a field name
Set the 'help' key to add text immediately after the field name.
This is printed in the table left column:
- dataclass field name
- 2 spaces
- 'help' key value.
```python
@dataclass
class MoreConditions:
visibility: float = field(metadata=stow(help="(mi)",spec=".2f"))
dewpoint: int = field(metadata=stow(help="(degF)"))
more_data = MoreConditions(visibility=10.00,dewpoint=71)
dataclass_print(more_data)
```
```expected-output
MoreConditions
-----------------------
visibility (mi) 10.00
dewpoint (degF) 71
-----------------------
```
### When a dataclass field value is also dataclass
An additional ASCII table is printed for each nested dataclass.
The table is below and indented two spaces for each level of nesting.
```python
@dataclass
class MoreCurrentConditions:
temperature: float
humidity: float
heat_index: int
wind: Wind = field(metadata=stow(help="(2pm)"))
more_weather_data = MoreCurrentConditions(
80.0, 0.71, 83, Wind(11, Direction.E)
)
dataclass_print(more_weather_data)
```
The class name is printed in place of the value. The value of
the wind field is printed in a second table below the first
and indented two spaces.
```expected-output
MoreCurrentConditions
-----------------
temperature 80.0
humidity 0.71
heat_index 83
wind (2pm) Wind
-----------------
MoreCurrentConditions.wind (2pm) : Wind
-------------
speed 11
direction E
-------------
```
#### Omit printing a nested dataclass
To prevent levels of nested dataclasses from printing pass
keyword parameter max_depth. 1 means just print the top
level of dataclass. Note that only the classname of
the wind field value is printed.
```python
dataclass_print(more_weather_data, max_depth=1)
```
```expected-output
MoreCurrentConditions
-----------------
temperature 80.0
humidity 0.71
heat_index 83
wind (2pm) Wind
-----------------
```
#### Print a bordered ASCII table
dataclass_print() passes extra keyword arguments to monotable.mono().
See monotable.mono()'s documentation. Some examples are below.
```python
dataclass_print(more_weather_data, max_depth=1, bordered=True)
```
```expected-output
MoreCurrentConditions
+-------------+------+
| temperature | 80.0 |
+-------------+------+
| humidity | 0.71 |
+-------------+------+
| heat_index | 83 |
+-------------+------+
| wind (2pm) | Wind |
+-------------+------+
```
#### Print ASCII table with indent
```python
dataclass_print(more_weather_data, max_depth=1, indent="....")
```
```expected-output
....MoreCurrentConditions
....-----------------
....temperature 80.0
....humidity 0.71
....heat_index 83
....wind (2pm) Wind
....-----------------
```
#### Change the column alignment
```python
dataclass_print(more_weather_data, max_depth=1, formats=(">", "<"))
```
```expected-output
MoreCurrentConditions
-----------------
temperature 80.0
humidity 0.71
heat_index 83
wind (2pm) Wind
-----------------
```
#### Print a nested dataclass that has a callable spec
For a dataclass field value, set the monotable field metadata
"spec" key to a function so that the value is printed in the top
level table rather than below as a separate table.
Note- This example is coded in Python REPL style so it can be tested
by the PYPI project phmutest using --replmode.
```python
>>> from dataclasses import dataclass, field
>>> from enum import auto, Enum
>>>
>>> from monotable import dataclass_print
>>> from monotable import stow
>>>
>>> class Direction(Enum):
... N = auto()
... E = auto()
... S = auto()
... W = auto()
>>>
>>> @dataclass
... class Wind:
... speed: int
... direction: Direction = field(metadata=stow(spec=lambda x: x.name))
>>>
>>> @dataclass
... class WindInline:
... temperature: float
... humidity: float
... heat_index: int
... wind: Wind = field(metadata=stow(spec=str))
>>> wind = Wind(11, Direction.E)
>>> wind_inline = WindInline(80.0, 0.71, 83, wind)
>>> dataclass_print(wind_inline)
WindInline
-------------------------------------------------------
temperature 80.0
humidity 0.71
heat_index 83
wind Wind(speed=11, direction=)
-------------------------------------------------------
```
#### Left align the title
Note "<" at the start of title= specifies left alignment.
monotable detects alignment from the first character of the title.
```python
>>> dataclass_print(wind_inline, title=")
-------------------------------------------------------
```
#### Recipe to do dataclass_print as a mixin class.
```python
from typing import Any, Tuple
class DCPrint:
"""Mixin class for dataclass to add member function dcprint()."""
# This should be the same signature as dataclass_print()
# where dataclass_instance is replaced by self.
def dcprint(
self,
*,
# note- These 2 keyword args are monotable positional args.
formats: Tuple[str, str] = ("", ">"),
title: str = "", # monotable title prefix
**monotable_kwargs: Any, # keyword args passed to monotable.mono().
) -> None:
dataclass_print(
self,
formats=formats,
title=title,
**monotable_kwargs,
)
```
Add DCPrint as a base class to the dataclass definition.
```python
@dataclass
class Temperatures(DCPrint):
high: int
low: int
temps = Temperatures(high=77, low=60)
temps.dcprint(title="High/Low Temperature")
```
```expected-output
High/Low Temperature : Temperatures
--------
high 77
low 60
--------
```
#### Copy of 2 earlier examples in REPL for testing on Python 3.7
```python
>>> @dataclass
... class MoreConditions:
... visibility: float = field(metadata=stow(help="(mi)",spec=".2f"))
... dewpoint: int = field(metadata=stow(help="(degF)"))
>>>
>>> more_data = MoreConditions(visibility=10.00,dewpoint=71)
>>> dataclass_print(more_data)
MoreConditions
-----------------------
visibility (mi) 10.00
dewpoint (degF) 71
-----------------------
>>>
>>> @dataclass
... class MoreCurrentConditions:
... temperature: float
... humidity: float
... heat_index: int
... wind: Wind = field(metadata=stow(help="(2pm)"))
>>>
>>> more_weather_data = MoreCurrentConditions(
... 80.0, 0.71, 83, Wind(11, Direction.E)
... )
>>> dataclass_print(more_weather_data)
MoreCurrentConditions
-----------------
temperature 80.0
humidity 0.71
heat_index 83
wind (2pm) Wind
-----------------
MoreCurrentConditions.wind (2pm) : Wind
-------------
speed 11
direction E
-------------
```