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?
rawpreserves the original device response structure, useful when passing data downstream or serializing to JSON.flatproduces 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: