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 intoDeviceResponsevalidate_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).