项目作者: tmarktaylor

项目描述 :
ASCII table with per column format specs, multi-line content, plug-in format functions, column width control.
高级语言: Python
项目地址: git://github.com/tmarktaylor/monotable.git
创建时间: 2017-03-20T17:03:11Z
项目社区:https://github.com/tmarktaylor/monotable

开源协议:Apache License 2.0

下载


monotable

ASCII table with per column format specs, multi-line content,
formatting directives, column width control.

Dataclass to ASCII table printer.

default branch status



CI Test
readthedocs
codecov

Docs |
Repos |
Codecov |
License

Sample usage

  1. from monotable import mono
  2. headings = ["purchased\nparrot\nheart rate", "life\nstate"]
  3. # > is needed to right align None cell since it auto-aligns to left.
  4. # monotable uses empty string to format the second column.
  5. formats = [">(none=rest).0f"]
  6. cells = [
  7. [0, "demised"],
  8. [0.0, "passed on"],
  9. [None, "is no more"],
  10. [-1],
  11. [0, "ceased to be"],
  12. ]
  13. print(
  14. mono(
  15. headings,
  16. formats,
  17. cells,
  18. title="Complaint\n(registered)",
  19. # top guideline is equals, heading is period, bottom is omitted.
  20. guideline_chars="=. ",
  21. )
  22. )

sample output:

  1. Complaint
  2. (registered)
  3. ========================
  4. purchased
  5. parrot life
  6. heart rate state
  7. ........................
  8. 0 demised
  9. 0 passed on
  10. rest is no more
  11. -1
  12. 0 ceased to be

Dataclass to ASCII Table printer

  1. from dataclasses import dataclass, field
  2. from enum import auto, Enum
  3. from monotable import dataclass_print
  4. from monotable import dataclass_format
  5. 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.

  1. @dataclass
  2. class CurrentConditions:
  3. temperature: float
  4. humidity: float
  5. heat_index: int
  6. weather_data = CurrentConditions(80.0, 0.71, 83)
  7. dataclass_print(weather_data)
  1. CurrentConditions
  2. -----------------
  3. temperature 80.0
  4. humidity 0.71
  5. heat_index 83
  6. -----------------

Title

The table title defaults to the class name. The string passed
to the “title” keyword is prepended to the class name.

  1. dataclass_print(weather_data, title="Airport")
  1. Airport : CurrentConditions
  2. -----------------
  3. temperature 80.0
  4. humidity 0.71
  5. heat_index 83
  6. -----------------

Format and print later

Call dataclass_format() to print or log later.

  1. text = dataclass_format(weather_data, title="Airport")
  2. print(text)
  1. Airport : CurrentConditions
  2. -----------------
  3. temperature 80.0
  4. humidity 0.71
  5. heat_index 83
  6. -----------------

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.

  1. @dataclass
  2. class SpecCurrentConditions:
  3. temperature: float
  4. humidity: float = field(metadata=stow(spec=".0%"))
  5. heat_index: int
  6. weather_data = SpecCurrentConditions(80.0, 0.71, 83)
  7. dataclass_print(weather_data)
  1. SpecCurrentConditions
  2. -----------------
  3. temperature 80.0
  4. humidity 71%
  5. heat_index 83
  6. -----------------

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”.

  1. class Direction(Enum):
  2. N = auto()
  3. E = auto()
  4. S = auto()
  5. W = auto()
  6. @dataclass
  7. class Wind:
  8. speed: int
  9. direction: Direction = field(metadata=stow(spec=lambda x: x.name))
  10. wind_data = Wind(speed=11,direction=Direction.E)
  11. dataclass_print(wind_data)
  1. Wind
  2. -------------
  3. speed 11
  4. direction E
  5. -------------

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.
  1. @dataclass
  2. class MoreConditions:
  3. visibility: float = field(metadata=stow(help="(mi)",spec=".2f"))
  4. dewpoint: int = field(metadata=stow(help="(degF)"))
  5. more_data = MoreConditions(visibility=10.00,dewpoint=71)
  6. dataclass_print(more_data)
  1. MoreConditions
  2. -----------------------
  3. visibility (mi) 10.00
  4. dewpoint (degF) 71
  5. -----------------------

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.

  1. @dataclass
  2. class MoreCurrentConditions:
  3. temperature: float
  4. humidity: float
  5. heat_index: int
  6. wind: Wind = field(metadata=stow(help="(2pm)"))
  7. more_weather_data = MoreCurrentConditions(
  8. 80.0, 0.71, 83, Wind(11, Direction.E)
  9. )
  10. 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.

  1. MoreCurrentConditions
  2. -----------------
  3. temperature 80.0
  4. humidity 0.71
  5. heat_index 83
  6. wind (2pm) Wind
  7. -----------------
  8. MoreCurrentConditions.wind (2pm) : Wind
  9. -------------
  10. speed 11
  11. direction E
  12. -------------

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.

  1. dataclass_print(more_weather_data, max_depth=1)
  1. MoreCurrentConditions
  2. -----------------
  3. temperature 80.0
  4. humidity 0.71
  5. heat_index 83
  6. wind (2pm) Wind
  7. -----------------

Print a bordered ASCII table

dataclass_print() passes extra keyword arguments to monotable.mono().
See monotable.mono()’s documentation. Some examples are below.

  1. dataclass_print(more_weather_data, max_depth=1, bordered=True)
  1. MoreCurrentConditions
  2. +-------------+------+
  3. | temperature | 80.0 |
  4. +-------------+------+
  5. | humidity | 0.71 |
  6. +-------------+------+
  7. | heat_index | 83 |
  8. +-------------+------+
  9. | wind (2pm) | Wind |
  10. +-------------+------+

Print ASCII table with indent

  1. dataclass_print(more_weather_data, max_depth=1, indent="....")
  1. ....MoreCurrentConditions
  2. ....-----------------
  3. ....temperature 80.0
  4. ....humidity 0.71
  5. ....heat_index 83
  6. ....wind (2pm) Wind
  7. ....-----------------

Change the column alignment

  1. dataclass_print(more_weather_data, max_depth=1, formats=(">", "<"))
  1. MoreCurrentConditions
  2. -----------------
  3. temperature 80.0
  4. humidity 0.71
  5. heat_index 83
  6. wind (2pm) Wind
  7. -----------------

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.

  1. >>> from dataclasses import dataclass, field
  2. >>> from enum import auto, Enum
  3. >>>
  4. >>> from monotable import dataclass_print
  5. >>> from monotable import stow
  6. >>>
  7. >>> class Direction(Enum):
  8. ... N = auto()
  9. ... E = auto()
  10. ... S = auto()
  11. ... W = auto()
  12. >>>
  13. >>> @dataclass
  14. ... class Wind:
  15. ... speed: int
  16. ... direction: Direction = field(metadata=stow(spec=lambda x: x.name))
  17. >>>
  18. >>> @dataclass
  19. ... class WindInline:
  20. ... temperature: float
  21. ... humidity: float
  22. ... heat_index: int
  23. ... wind: Wind = field(metadata=stow(spec=str))
  24. >>> wind = Wind(11, Direction.E)
  25. >>> wind_inline = WindInline(80.0, 0.71, 83, wind)
  26. >>> dataclass_print(wind_inline)
  27. WindInline
  28. -------------------------------------------------------
  29. temperature 80.0
  30. humidity 0.71
  31. heat_index 83
  32. wind Wind(speed=11, direction=<Direction.E: 2>)
  33. -------------------------------------------------------

Left align the title

Note “<” at the start of title= specifies left alignment.
monotable detects alignment from the first character of the title.

  1. >>> dataclass_print(wind_inline, title="<Left Aligned Title")
  2. Left Aligned Title : WindInline
  3. -------------------------------------------------------
  4. temperature 80.0
  5. humidity 0.71
  6. heat_index 83
  7. wind Wind(speed=11, direction=<Direction.E: 2>)
  8. -------------------------------------------------------

Recipe to do dataclass_print as a mixin class.

  1. from typing import Any, Tuple
  2. class DCPrint:
  3. """Mixin class for dataclass to add member function dcprint()."""
  4. # This should be the same signature as dataclass_print()
  5. # where dataclass_instance is replaced by self.
  6. def dcprint(
  7. self,
  8. *,
  9. # note- These 2 keyword args are monotable positional args.
  10. formats: Tuple[str, str] = ("", ">"),
  11. title: str = "", # monotable title prefix
  12. **monotable_kwargs: Any, # keyword args passed to monotable.mono().
  13. ) -> None:
  14. dataclass_print(
  15. self,
  16. formats=formats,
  17. title=title,
  18. **monotable_kwargs,
  19. )

Add DCPrint as a base class to the dataclass definition.

  1. @dataclass
  2. class Temperatures(DCPrint):
  3. high: int
  4. low: int
  5. temps = Temperatures(high=77, low=60)
  6. temps.dcprint(title="High/Low Temperature")
  1. High/Low Temperature : Temperatures
  2. --------
  3. high 77
  4. low 60
  5. --------

Copy of 2 earlier examples in REPL for testing on Python 3.7

  1. >>> @dataclass
  2. ... class MoreConditions:
  3. ... visibility: float = field(metadata=stow(help="(mi)",spec=".2f"))
  4. ... dewpoint: int = field(metadata=stow(help="(degF)"))
  5. >>>
  6. >>> more_data = MoreConditions(visibility=10.00,dewpoint=71)
  7. >>> dataclass_print(more_data)
  8. MoreConditions
  9. -----------------------
  10. visibility (mi) 10.00
  11. dewpoint (degF) 71
  12. -----------------------
  13. >>>
  14. >>> @dataclass
  15. ... class MoreCurrentConditions:
  16. ... temperature: float
  17. ... humidity: float
  18. ... heat_index: int
  19. ... wind: Wind = field(metadata=stow(help="(2pm)"))
  20. >>>
  21. >>> more_weather_data = MoreCurrentConditions(
  22. ... 80.0, 0.71, 83, Wind(11, Direction.E)
  23. ... )
  24. >>> dataclass_print(more_weather_data)
  25. MoreCurrentConditions
  26. -----------------
  27. temperature 80.0
  28. humidity 0.71
  29. heat_index 83
  30. wind (2pm) Wind
  31. -----------------
  32. <BLANKLINE>
  33. MoreCurrentConditions.wind (2pm) : Wind
  34. -------------
  35. speed 11
  36. direction E
  37. -------------