Skip to content

Conversation

MicBoucinha
Copy link

Important

We started working on this PR by merging the contributions made in PR#1

Refactoring & Project Structure

  • Refactored enums, class members, and function naming for consistency with official Harp naming conventions
  • Changed namespace to harp and sub-namespace reorganization:
    • harp.communication for communication-related modules
    • harp.protocol for core protocol definitions
    • harp.devices for device-specific implementations (using PEP420 for implicit namespace packages)

Features & Enhancements

  • Updated Harp protocol support with missing features

    • Added support for device serial number and missing registers
    • Improved message handling (arrays, timestamps, error detection) for different payloads
  • Updated currently known Harp devices names

  • Added context manager support to Device

  • Added static factory method HarpMessage.create

  • Changed dump file convention to be at the Device level instead of message level

  • Removed ReadXXXHarpMessage and WriteXXXHarpMessage classes and ReadXXX and WriteXXX static methods from HarpMessage and moved them to Device

  • Removed existing behavior driver because of new harp.behavior namespace package

Documentation

  • Added MkDocs documentation for API, and project structure, and per-device documentation
  • Use numpy style convention for docstrings documentation
  • Added docstrings to all public methods and classes
  • Moved and updated existing examples to docs folder
  • Created GitHub Action to generate documentation (manually triggered)

Documentation here: https://fchampalimaud.github.io/pyharp

Testing

  • Updated some tests as needed

Technical

  • Convert project to uv

Contributors

  • Major contributions by Luís Teixeira and José Grilo

harp.devices

  • Automatically generated python package for each device and respective documentation
  • Added harp.devices namespace package for device-specific implementations

Repository here: https://github.com/fchampalimaud/harp.devices


As mentioned in issue #2, we were really interested in developing the Python Harp ecosystem further.

Our starting point was PR #1, which already had pushed pyharp forward (e.g., by implementing a way to deal with the device's events), and try to build on top of that. At first, we mainly focused on completing what was missing regarding the protocol (e.g., add a generic way to deal with the different payload types) and the interaction with a generic Harp device (e.g., add methods for the missing common registers).

Our goal was to have a simple enough but versatile pyharp interface and we based our rationale to be as similar as possible as the Bonsai.Harp implementation. One way to achieve that was to get inspiration from the CreateMessage Bonsai node to implement the HarpMessage.create static method. Additionally, we added methods for the Device class that allow the users to read/write from/to registers that have different payload types.

Another thing we tried to focus on was documentation. It surely can be improved but, at the moment, we documented every function and class of the project in order to facilitate the API usage and adapted/added some minimal examples that should help the user get started with the pyharp package.

Beyond being possible to connect and interact with a generic Harp device, we also wanted to generate device-specific interfaces. On the one hand, we would like that each Harp device had its own package, so that if, for example, a user just wants to use Harp Behavior, it doesn't need to import a package that contains the interfaces for every board. This would also help when there's individual updates on each device. On the other hand, we would like that every package (including pyharp "core") had the same feeling, in the sense the user would get the implicit idea that every package is part of the same ecosystem. In order to achieve that, we organized the project directories according to PEP420, in which the global ecosystem has the following structure:

harp/
├── communication/
├── data (harp-python content hopefully)
├── protocol/
└── devices/
    ├── behavior/
    ├── device_a/
    ├── ...
    └── device_z/

We also wanted to have a way to generate the device-specific packages automatically, so that we could easily add new devices and keep the documentation up-to-date. For that, we used reflex-generator to generate the device-specific packages based on the device's YAML. Currently, the generated packages are available in the harp.devices repository mentioned above, but we believe that the Python interface should reside in each device's repository. PR#86 to reflex-generator has been submitted to support the Python package generation.

Finally, we abandoned the pyharp name for the package because, unfortunately, someone registered a package in PyPI with the same name. The package name is currently harp-protocol. At the same time, and mostly to keep coherence with the namespace naming convention used on C#/Bonsai side, we decided to change the global namespace to harp.

Known limitations of the PEP420 usage

To allow the usage of PEP420, we cannot have members under harp or harp.devices that are not namespace packages. This means that we cannot have a __init__.py file under those directories. As a consequence, we cannot have any code directly in those paths, which means that we cannot have any imports there.

This also means that the harp-python package cannot currently be installed in the same venv until some changes happen there. Our suggestion at the time was to place it's contents under harp.data and then import it from there. This would allow the harp-python package to be installed in the same venv as harp-protocol and the individual harp devices. We also submitted a PR to the harp-python repository to reflect this change in PR#52.

With these new PRs, we aim to expand the current features of the Python implementation and make it more accessible for new users, helping them adopt and engage with the HARP ecosystem. We also see value in consolidating the Python implementation within the official harp-tech repository, and we’re more than happy to help maintain it. This would help avoid fragmented development efforts and lead to a more unified and robust solution for the community. We will continue iterating on these developments and commit new features to this PR while we work toward a consensus on merging it into the harp-tech repository.

MicBoucinha and others added 25 commits August 5, 2025 09:27
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
…end method

Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
Co-authored-by: José Grilo <jose.grilo@research.fchampalimaud.org>
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ MicBoucinha
❌ ZegCricket
You have signed the CLA already but the status is still pending? Let us recheck it.

@MicBoucinha
Copy link
Author

Hi! We made the following changes since the last meeting:

  • Separate the previous harp-protocol into 2 different packages (harp-protocol and harp-serial), using the uv workspaces feature
  • Implement a strategy to handle timeouts when waiting for a reply from the device (harp.serial.TimeoutStrategy)

Notes

  1. harp-protocol & harp-serial are already released as well as new versions of harp.devices using harp-serial directly.

  2. Documentation is online and updated.

@glopesdev @bruno-f-cruz, feel free to give us feedback where improvements can be done.

Copy link
Member

@bruno-f-cruz bruno-f-cruz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking a stab at this. I left some first pass feedback.
I think we should discuss a bit the architecture of the device API synchronously during one of the meetings. I dont have a specific issue with it, but I am just afraid it may become hard to maintain if each register has its own specific read/write method with a name given without any sort of consistency.

- name: Clone harp.devices repository
uses: actions/checkout@v4
with:
repository: fchampalimaud/harp.devices
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure the package repository should be coupled with the generation of docs for the devices.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the long term, we could consider to separate the docs generation from the packages in different repos. The current solution is not set in stone, but we would like to keep the documentation for the generic device and for the specific devices together.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.vscode should be added to the list

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason we keep the .vscode directory in the repo is because it has the extensions (and respective settings) we actively use for development and that we would like for contributors to use as well. Do you have an alternative suggestion regarding this matter?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be changed to harp-tech, similar to what happens with the other software packages

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can change it when the move of the repo to harp-tech is imminent.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what this config file is for? But should likely be ignored?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was inherited from the AIND fork, but we agree it can be removed.

@@ -1,6 +1,7 @@
MIT License

Copyright (c) 2020 OEPS & Filipe Carvalho
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider making this standard with the copyright in the other software packages.

https://github.com/harp-tech/harp-python/blob/3d97d0b800533e4821896f744e52569c6413c6f7/LICENSE#L3

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, same as answered previously,

We can change it when the move of the repo to harp-tech is imminent.

self,
serial_port: str,
dump_file_path: Optional[str] = None,
read_timeout_s: float = 1,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify the name to: timeout

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

Comment on lines +114 to +115
_TODO_
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not up to date with the signature

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! We will update it.

Comment on lines +176 to +178
# open file if it is defined
if self._dump_file_path is not None:
self._dump_file = open(self._dump_file_path, "ab")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I follow how you would want to use this.
I can see cases where users may want to skip querying the device for metadata, but this suggests that a valid use-case is to cache it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to look at this more carefully. We can discuss it further.

reply = self.send(HarpMessage.create(MessageType.READ, address, PayloadType.U8))
return OperationMode(reply.payload & OperationCtrl.OP_MODE)

def dump_registers(self) -> list:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should discuss a bit this API synchronously during one of the meetings. I dont dislike this but it has the potential to grow a bit out of control.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was only for this specific register where we don't know yet how to constrain the user's input regarding the OP_MODE to be of type OperationCtrl. In terms of usage, for this particular register, having the separated method made more sense. But we should discuss it further.

@@ -0,0 +1,22 @@
repos:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest turning this into an action instead of a pre-commit.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why an action only?
I might be missing something, but personally, I prefer to have checks locally before committing when possible.
We can discuss this further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants