Skip to content

Add Python device interface generator#119

Open
glopesdev wants to merge 3 commits into
harp-tech:mainfrom
glopesdev:python-interface-generator
Open

Add Python device interface generator#119
glopesdev wants to merge 3 commits into
harp-tech:mainfrom
glopesdev:python-interface-generator

Conversation

@glopesdev

Copy link
Copy Markdown
Contributor

Add a PythonGenerator class that produces a Python device interface module from device metadata, giving the generator set a third target alongside the existing C# and firmware generators. The generated module targets the register and payload DSL of the new pyharp unified API introduced in harp-tech/pyharp#5, so an existing device.yml can produce a ready-to-use Python interface with no hand-written register code.

The module mirrors the conventions of the pyharp hand-written reference:

  • IntEnum and IntFlag types for group masks and bit masks.
  • Payload classes for structured registers, using StructPayload with GroupMask, BitFlag, and Field descriptors, and for converter-backed registers, using AnonymousPayload.
  • Register classes deriving from the appropriate Register* base, plus an address-to-class REGISTER_MAP. Application devices merge the core register map imported from harp.device.
  • Enum member and payload field names in canonical Python casing, SCREAMING_SNAKE_CASE members and snake_case fields, produced through the same firmware naming convention used by the C firmware generator.

User-supplied converters are imported from a companion .converters module, the Python analog of the partial-method stubs the C# generator emits.

Validation

  • Expected-output tests compare the generated core and device modules against committed reference files.
  • A cross-stack interop test writes Harp binary frames through the generated C# interface, then reads them back through the generated Python interface to verify the two stacks agree on every public register. It runs via uv on the release CI legs, one per OS, so upstream pyharp changes that break cross-platform behavior are caught.

Notes

  • This first pass emits the register and payload DSL only; package scaffolding is out of scope.
  • The intermediate model types are internal, matching the C# and firmware generators, so the only new public surface is PythonGenerator and PythonImplementation.
  • The output targets the in-progress pyharp unified API, currently pinned to a commit of the refactor-unified-api branch, so the interface may need adjustment as that API settles before a pyharp release.

Add a PythonGenerator class that produces a Python device interface
module from device metadata, alongside the existing C# and firmware
generators. The generated module targets the pyharp register and
payload DSL and emits IntEnum and IntFlag types for group and bit
masks, payload classes for structured and converter-backed registers,
register classes, and an address-to-class REGISTER_MAP. Application
devices merge the core register map, and member and field names follow
canonical Python casing through the shared firmware naming convention.

Add expected-output tests for the core and device metadata and a
cross-stack interop test that writes Harp binary frames through the
generated C# interface, then reads them back through the generated
Python interface to verify the two stacks agree.
@glopesdev glopesdev added the feature New planned feature label Jun 27, 2026
Comment thread tests/ExpectedOutput/core.py
Comment thread tests/Python/pyproject.toml Outdated
Switch the interop test bulk-parse check from read_dataframe in
harp-data to RegisterBase.parse_bulk in harp-protocol, and drop the
harp-data dependency from the test project. The per-frame parse and
value assertions are unchanged.
Regenerate the Python interface against the redesigned pyharp register
and payload DSL. Whole-register bit and group masks now unwrap to their
enum type: the payload is an AnonymousPayload with a single __value__
field and the register parses to the IntFlag or IntEnum directly,
replacing the previous struct of boolean fields. Masked boolean
sub-fields now use a BoolConverter field with a mask, since BitFlag was
removed upstream, and string and converter registers adopt the same
AnonymousPayload __value__ form.

Bump the interop test pin to the matching pyharp commit and simplify
the cross-stack comparison, which now checks mask registers as a plain
integer on both sides.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New planned feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants