Skip to content

Commit e6f5fe9

Browse files
committed
Add harp-python migration guide
1 parent 371a0fb commit e6f5fe9

2 files changed

Lines changed: 190 additions & 0 deletions

File tree

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# Migrating from harp-python
2+
3+
`harp-data` is the successor to `harp-python` for reading Harp binary data files into
4+
pandas DataFrames. The core concepts are unchanged — device schemas, register maps,
5+
binary files — but the API has been reorganized to separate data reading from device
6+
communication.
7+
8+
This guide covers the three workflows most users relied on in `harp-python`.
9+
10+
---
11+
12+
## Swap the package
13+
14+
Replace the old dependency:
15+
16+
```sh title="Before"
17+
pip install harp-python
18+
```
19+
20+
```sh title="After"
21+
pip install harp-data
22+
```
23+
24+
If you want the full toolkit — serial transport, device client, and data reading — install
25+
the umbrella package instead:
26+
27+
```sh
28+
pip install harp
29+
```
30+
31+
---
32+
33+
## Loading a device schema at runtime
34+
35+
In `harp-python`, `harp.create_reader()` accepted a dataset folder and handled
36+
schema loading internally. `create_dataset_reader` is the direct replacement — it
37+
finds the `device.yml` inside the folder automatically:
38+
39+
```python title="Before"
40+
import harp
41+
42+
reader = harp.create_reader("session.harp")
43+
```
44+
45+
```python title="After"
46+
from harp.data import create_dataset_reader
47+
48+
reader = create_dataset_reader("session.harp")
49+
```
50+
51+
If the schema lives outside the data folder, pass it explicitly:
52+
53+
```python
54+
reader = create_dataset_reader("session.harp", schema="/path/to/device.yml")
55+
```
56+
57+
### Accessing the device module
58+
59+
The reader holds a reference to the compiled device module at `reader.device_module`.
60+
Use it to look up register classes by name — no need to keep a separate variable:
61+
62+
```python
63+
reader = create_dataset_reader("session.harp")
64+
65+
# access any register class through the reader
66+
df = reader.read(reader.device_module.AnalogData)
67+
```
68+
69+
!!! note
70+
The old `harp.read_schema()` had no direct equivalent you needed to call separately.
71+
`create_dataset_reader` handles schema loading in one step, matching the convenience
72+
of the original API.
73+
74+
---
75+
76+
## Reading a single register
77+
78+
The old API gave you attribute access on the reader — `reader.AnalogData.read()`. The
79+
new API inverts this: you call `reader.read()` and pass the register class or its
80+
address as the argument.
81+
82+
```python title="Before"
83+
# by attribute name
84+
df = reader.AnalogData.read()
85+
86+
# by name string
87+
df = reader.registers["AnalogData"].read()
88+
89+
# by address
90+
df = reader.registers[44].read()
91+
```
92+
93+
```python title="After"
94+
# by register class (accessed through the reader)
95+
df = reader.read(reader.device_module.AnalogData)
96+
97+
# by address
98+
df = reader.read(44)
99+
```
100+
101+
### Absolute timestamps
102+
103+
The `epoch` parameter moves from the reader constructor into the `read()` call:
104+
105+
```python title="Before"
106+
reader = harp.create_reader("session.harp", epoch=harp.REFERENCE_EPOCH)
107+
df = reader.AnalogData.read()
108+
```
109+
110+
```python title="After"
111+
from harp.data import REFERENCE_EPOCH
112+
113+
df = reader.read(reader.device_module.AnalogData, epoch=REFERENCE_EPOCH)
114+
```
115+
116+
### Reading the whole session at once
117+
118+
`read_all()` returns a dictionary of DataFrames keyed by register name. Registers
119+
with no corresponding `.bin` file are skipped:
120+
121+
```python
122+
everything: dict[str, pd.DataFrame] = reader.read_all()
123+
```
124+
125+
### Parameter reference
126+
127+
| harp-python | harp-data | Notes |
128+
|---|---|---|
129+
| `keep_type=True` | `message_type=True` | Renamed |
130+
| `epoch=REFERENCE_EPOCH` | `epoch=REFERENCE_EPOCH` | Same |
131+
| `epoch=None` | `epoch=None` (default) | Float seconds; same |
132+
|| `decode_enums=True` | New: enum fields as `pd.Categorical` |
133+
|| `demux_bit_masks=False` | New: expand bitmask flags into one column per flag |
134+
135+
---
136+
137+
## Schemaless read
138+
139+
If you have a raw `.bin` file and no schema — or you just want to inspect the data
140+
quickly — the `read()` function works the same as before. Only the import path and
141+
one parameter name change:
142+
143+
```python title="Before"
144+
import harp
145+
146+
df = harp.read("Behavior_44.bin")
147+
df = harp.read("Behavior_44.bin", keep_type=True)
148+
```
149+
150+
```python title="After"
151+
from harp.data import read
152+
153+
df = read("Behavior_44.bin")
154+
df = read("Behavior_44.bin", message_type=True)
155+
```
156+
157+
Both functions infer the payload type and element count automatically from the first
158+
frame — no register metadata needed.
159+
160+
---
161+
162+
## Going further: static device packages
163+
164+
Loading a YAML at runtime is convenient, but for production workflows — or when you
165+
want IDE autocompletion and type safety — Harp device packages are pre-compiled Python
166+
modules that give you the same interface without any schema parsing at startup.
167+
168+
A static device package installs its register map as a proper Python module. You
169+
import it, pass it directly to `DatasetReader`, and the rest of the API is identical:
170+
171+
```python
172+
pip install harp-device-behavior
173+
```
174+
175+
```python
176+
from harp.device.behavior import device as behavior
177+
from harp.data import DatasetReader
178+
179+
reader = DatasetReader(behavior, "session.harp")
180+
181+
# everything works the same
182+
df = reader.read(behavior.AnalogData)
183+
everything = reader.read_all()
184+
```
185+
186+
The static module is faster to start up and ships with stubs for autocompletion. See
187+
[Generating Registers from a Schema](../examples/create_device_module/create_device_module.md)
188+
for how device modules are structured.

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ nav:
7979
- Subscribing to Events: examples/subscribing_to_events/subscribing_to_events.md
8080
- Reading a Whole Dataset Folder: examples/read_dataset/read_dataset.md
8181
- Reading Data into a DataFrame: examples/read_data_to_dataframe/read_data_to_dataframe.md
82+
- Articles:
83+
- Migrating from harp-python: articles/migrating_from_harp_python.md
8284
- API:
8385
- Protocol: api/protocol.md
8486
- Serial: api/serial.md

0 commit comments

Comments
 (0)