Skip to content

Parser Layer

Converts JSONL device responses into typed Python objects.


Design Intent

The OSECHI detector firmware evolves independently of the library. New fields appear without warning. DeviceResponse uses Pydantic's extra="allow" to accept any JSON object without a schema change — known fields get type-checked, unknown fields pass through transparently.


DeviceResponse

A Pydantic model with three fixed fields and open-ended extras:

Field Type Description
type str "response" or "event" (required)
status str \| None "ok" or "error"
received_us int \| None Host-side receipt timestamp (microseconds)
(any) (any) Additional fields from firmware accepted as-is

Access any field via dot notation:

response = parse_jsonl('{"type":"response","status":"ok","version":"1.10.1"}')
print(response.type)     # "response"
print(response.version)  # "1.10.1"  ← extra field, no schema change needed

Or as a dict:

data = response.model_dump()       # all fields as dict
json_str = response.model_dump_json()  # JSON string

ResponseParser

Static methods for parsing and validation:

  • parse_jsonl(line) — deserialize one JSON line into DeviceResponse
  • validate_response(data) — validate a dict against the model

parse_jsonl() is also exported at the top level as a convenience function.


parse_thresholds

parse_thresholds(text) converts the CLI threshold string format into a channel→value dict:

from kazunoko import parse_thresholds

thresholds = parse_thresholds("1:300;2:320;3:310")
# → {1: 300, 2: 320, 3: 310}

This is used by Measure and the measure CLI command to configure multiple channels at once.


Why not a fixed schema?

A stricter model (explicit fields for every device attribute) would break every time firmware adds a field. extra="allow" means the library never needs an update just because the firmware does — the new fields are simply available as attributes. Validation still catches the fields that matter (type is always required).