Skip to content

Formatter Layer

Converts device responses into human-readable and machine-parseable output formats.


Design Intent

Output formatting is separated from device communication so that the same response object can be rendered in any format without touching the device or parser layers. ResponseView and ResponseFormatter are only used at the presentation boundary (CLI output, script output).


ResponseView

ResponseView wraps a DeviceResponse and provides two perspectives:

Perspective Description Access
raw Original nested structure from the device view.raw
flat Flattened with underscore-separated keys view.flat

Flattening happens automatically in __post_init__. For example, a nested field {"ch": {"signal": 42}} becomes ch_signal: 42 in the flat perspective.

Why two perspectives?

  • raw preserves the original device response structure, useful when passing data downstream or serializing to JSON.
  • flat produces script-friendly column names (no dots or brackets), useful for CSV/TSV output and shell pipelines.
from kazunoko import ResponseView

view = ResponseView(response)
print(view.raw.type)       # "event"
print(view.flat.ch_signal) # 42  ← flattened key

ResponseFormatter

Renders a DeviceResponse in one of the supported output formats:

Format Description
table Rich-formatted table (default)
jsonl One JSON object per line
json Pretty-printed JSON
csv Comma-separated values
ssv Space-separated values
tsv Tab-separated values
ltsv Labeled Tab-Separated Values
from kazunoko import ResponseFormatter, ResponseView

view = ResponseView(response)
ResponseFormatter.display(view.flat, format="csv")

The CLI exposes format selection via --format and perspective selection via --use-flat / --use-raw.


Output stream convention

All formatted data goes to stdout; status messages and progress go to stderr. This separation allows shell users to redirect data and logs independently:

kazunoko read 100 > events.jsonl 2> run.log