Motivation
In #9, harp.data.read(source) reads a single register file schema-free, inferring the native layout from the first frame. It has no notion of a device: it does not know register names, addresses, or typed decoding (enums, bit masks, named payloadSpec members). To load a whole dataset with typed, named columns you currently need the register classes and must call parse_to_dataframe per register yourself.
harp-python covered this with create_reader(device.yml), which parsed a schema and generated per-register readers at runtime. We do not want to reintroduce a Python-side generator: register classes are now emitted by the external harp-tech/generators, and harp.device is an example of that output.
Proposal
Add a device-driven reader factory to harp.data that consumes a generated device rather than a schema, mirroring the pattern the serial package already uses.
harp.serial establishes the shape — the generated code is the input, the package supplies only the plumbing:
from harp.serial import open_serial_device
import behavior
with open_serial_device(behavior.Device, port="COM3") as dev:
dev.read(behavior.WhoAmI)
open_serial_device(device_class, *, port=...) takes a generated harp.device.Device subclass and composes it with a transport. The data reader should follow the same shape — take a generated device (its Device class and/or REGISTER_MAP) and produce per-register DataFrame readers:
from harp.data import create_reader
import behavior
reader = create_reader(behavior.Device, root="my_dataset")
who = reader.read(WhoAmI) # default path from the register name, returns a dataframe
ann = reader.read_stream(bytes) # infers the address and returns the parsed type?
We should really consider whether we want to have an inversion in the API (i.e. device.WhoAmI.read()) like we mentioned before and like it exists in harp-python. I have mixed feelings.
Motivation
In #9,
harp.data.read(source)reads a single register file schema-free, inferring the native layout from the first frame. It has no notion of a device: it does not know register names, addresses, or typed decoding (enums, bit masks, namedpayloadSpecmembers). To load a whole dataset with typed, named columns you currently need the register classes and must callparse_to_dataframeper register yourself.harp-python covered this with
create_reader(device.yml), which parsed a schema and generated per-register readers at runtime. We do not want to reintroduce a Python-side generator: register classes are now emitted by the external harp-tech/generators, andharp.deviceis an example of that output.Proposal
Add a device-driven reader factory to
harp.datathat consumes a generated device rather than a schema, mirroring the pattern the serial package already uses.harp.serialestablishes the shape — the generated code is the input, the package supplies only the plumbing:open_serial_device(device_class, *, port=...)takes a generatedharp.device.Devicesubclass and composes it with a transport. The data reader should follow the same shape — take a generated device (itsDeviceclass and/orREGISTER_MAP) and produce per-register DataFrame readers:We should really consider whether we want to have an inversion in the API (i.e.
device.WhoAmI.read()) like we mentioned before and like it exists in harp-python. I have mixed feelings.