Skip to content

Commit 54a4cd5

Browse files
authored
Review documentation ahead of the release (#35)
Module-level directives for harp.protocol and harp.device.core give every public name an API page entry, replacing the per-name core directives. The address-call idiom is now documented in the harp-protocol README, showing how a register base with an address reaches a payload no schema names, such as R_UID and R_TAG. The five package READMEs gain the closing license and contribution sentence. tests/test_packaging.py asserts that each published package declares a readme, a license, classifiers, urls and authors, and that every declared license file matches the repository one, since PEP 639 requires a copy per package.
1 parent 65a736e commit 54a4cd5

10 files changed

Lines changed: 63 additions & 18 deletions

File tree

docs/api/data.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
---
44

55
::: harp.data.open_dataset
6+
::: harp.data.read
67
::: harp.data.DatasetReader
78
::: harp.data.default_file_resolver
89
::: harp.data.parse_to_dataframe

docs/api/device.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44

55
::: harp.device.client.Device
66
::: harp.device.client.DeviceError
7+
::: harp.device.client.Subscription
8+
::: harp.device.client.EventHandler
79
::: harp.device.client.HarpFramer
810
::: harp.device.client.ITransport
911
::: harp.device.client.TransportError
1012
::: harp.device.schema.create_device_module
1113
::: harp.device.schema.parse_device_schema
1214
::: harp.device.schema.ConverterContext
13-
::: harp.device.core.REGISTER_MAP
14-
::: harp.device.core.OperationControl
15-
::: harp.device.core.OperationMode
16-
::: harp.device.core.ResetDevice
17-
::: harp.device.core.ResetFlags
18-
::: harp.device.core.ClockConfiguration
19-
::: harp.device.core.ClockConfigurationFlags
15+
::: harp.device.schema.DeviceModule
16+
::: harp.device.schema.DeviceModuleLike
17+
::: harp.device.core

docs/api/protocol.md

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,4 @@
22

33
---
44

5-
::: harp.protocol.MessageType
6-
::: harp.protocol.PayloadType
7-
::: harp.protocol.HarpMessage
8-
::: harp.protocol.RegisterBase
9-
::: harp.protocol.StructPayload
10-
::: harp.protocol.AnonymousPayload
11-
::: harp.protocol.Field
12-
::: harp.protocol.GroupMask
13-
::: harp.protocol.BitMask
14-
::: harp.protocol.Converter
5+
::: harp.protocol

src/packages/harp-benchmarks/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,5 @@ Equivalent module invocations: `uv run python -m harp.benchmarks.benchmark` / `u
4545
- **re-read**, file re-read from disk on every run, the real-world "load a dump" path, which includes disk.
4646

4747
The report also decomposes `parse_to_dataframe` into `parse_bulk` plus `payload_as_columns` plus pandas overhead.
48+
49+
`harp-benchmarks` is released as open source under the [MIT license](https://github.com/harp-tech/python/blob/main/LICENSE). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/harp-tech/python).

src/packages/harp-data/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,5 @@ from harp import data
9595

9696
data.to_file(AnalogData, values, "AnalogData.bin", timestamps=seconds)
9797
```
98+
99+
`harp-data` is released as open source under the [MIT license](https://github.com/harp-tech/python/blob/main/LICENSE). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/harp-tech/python).

src/packages/harp-device/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,5 @@ schema.create_device_module(yml_text, converters={"DataConverter": DataConverter
7070
```
7171

7272
`parse_device_schema(yml_text)` is also public, returning the parsed schema model without a module: registers, masks, and optional device identity.
73+
74+
`harp-device` is released as open source under the [MIT license](https://github.com/harp-tech/python/blob/main/LICENSE). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/harp-tech/python).

src/packages/harp-device/src/harp/device/client/_device.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ def _remove_subscription(self, sub: "Subscription") -> None:
324324
def _event_loop(self) -> None:
325325
while True:
326326
msg = self._event_queue.get()
327-
if msg is None: # shutdown sentinel
327+
if msg is None: # shutdown marker
328328
break
329329
self._deliver_event(msg)
330330

src/packages/harp-protocol/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,20 @@ np.uint16(65535) + 1 # RuntimeWarning: overflow encountered in scalar add
3030

3131
Numpy scalars behave like plain Python numbers in arithmetic, comparison and formatting. Use `int()` or `float()` where a built-in type is required.
3232

33+
## Reading an address no schema describes
34+
35+
A register class is normally declared with its address, as above, or generated from a `device.yml`. Calling a register base with an address instead builds a one-off register for that address, which is how a payload outside any schema is read and written:
36+
37+
```python
38+
from harp.protocol import RegisterU8Array, RegisterU16
39+
40+
uid = RegisterU8Array(0x10, length=16) # R_UID, named by no schema
41+
tag = RegisterU8Array(0x11, length=16) # R_TAG, the firmware git hash
42+
version = RegisterU16(0x08) # any address, as a scalar
43+
```
44+
45+
The result is an ordinary register, so it goes through `read` and `write` on a device exactly as a declared one does. `length` is keyword-only for the array form, and it is the element count rather than a byte count. An already-addressed register rejects the call, so `WhoAmI(44)` raises rather than quietly producing a register at another address.
46+
3347
It carries no transport or device logic. See [`harp-device`](https://github.com/harp-tech/python/tree/main/src/packages/harp-device) for the device layer.
48+
49+
`harp-protocol` is released as open source under the [MIT license](https://github.com/harp-tech/python/blob/main/LICENSE). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/harp-tech/python).

src/packages/harp-serial/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ with serial.open_device(behavior, port="COM3") as device:
1717
```
1818

1919
Passing a device module validates the device identity on open. Pass a `Device` subclass instead to preserve its own type, or omit the argument entirely for schema-free access, which skips the identity check.
20+
21+
`harp-serial` is released as open source under the [MIT license](https://github.com/harp-tech/python/blob/main/LICENSE). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/harp-tech/python).

tests/test_packaging.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import tomllib
2+
from pathlib import Path
3+
4+
import pytest
5+
6+
ROOT = Path(__file__).resolve().parents[1]
7+
PUBLISHED = ("harp-protocol", "harp-device", "harp-serial", "harp-data")
8+
9+
10+
def _manifest(package: str) -> dict:
11+
path = ROOT / "src" / "packages" / package / "pyproject.toml"
12+
return tomllib.loads(path.read_text(encoding="utf-8"))["project"]
13+
14+
15+
@pytest.mark.parametrize("package", PUBLISHED)
16+
def test_declared_license_files_match_repository_license(package: str):
17+
# PEP 639 forbids a parent directory reference in license-files, so each package
18+
# keeps its own copy. Nothing stops the copies drifting except this.
19+
expected = (ROOT / "LICENSE").read_bytes()
20+
declared = _manifest(package)["license-files"]
21+
assert declared, f"{package} declares no license file"
22+
for name in declared:
23+
assert (ROOT / "src" / "packages" / package / name).read_bytes() == expected
24+
25+
26+
@pytest.mark.parametrize("package", PUBLISHED)
27+
def test_published_package_declares_metadata(package: str):
28+
# A published package with no readme or license renders as a blank project page.
29+
project = _manifest(package)
30+
for key in ("readme", "license", "license-files", "classifiers", "urls", "authors"):
31+
assert key in project, f"{package} declares no {key}"

0 commit comments

Comments
 (0)