feat(hugr-py): Define typed Metadata protocol#2765
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2765 +/- ##
==========================================
+ Coverage 83.67% 83.70% +0.02%
==========================================
Files 266 267 +1
Lines 53333 53461 +128
Branches 47587 47587
==========================================
+ Hits 44629 44748 +119
- Misses 6297 6306 +9
Partials 2407 2407
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
7460a59 to
2f2572b
Compare
2f2572b to
e6d329a
Compare
maximilianruesch
left a comment
There was a problem hiding this comment.
Thanks, this will be a very useful addition! I have a bunch of suggested changes, some more nitty, some questions, some remarks for later.
hugr-py/src/hugr/metadata.py
Outdated
| @classmethod | ||
| def to_json(cls, value: GeneratorDesc) -> dict[str, str]: | ||
| return value._to_json() | ||
|
|
||
| @classmethod | ||
| def from_json(cls, value: Any) -> GeneratorDesc: | ||
| return GeneratorDesc._from_json(value) |
There was a problem hiding this comment.
If we have a lot of "simple" metadata keys that do not require special validation (only calling the JSON serialize / deserialize of their wrapped type), we might want to think about creating something like a mixin for such cases to reduce boilerplate / verbosity. I do think we need a bit more data / keys to assess what the best solution for this is, so there is no need to refactor this right now.
There was a problem hiding this comment.
👍
For native-type metadata (ints, strings, lists, and dicts) there's no need to override these methods. But yeah, it'd be nice to have a deserialize/_serialize`
I guess we could use pydantic for that? It's a bit annoying that we're starting from the already-loaded object rather than a json string.
There was a problem hiding this comment.
I have not yet used pydantic, but it strikes me as very powerful. If we adopt it, we should assess whether there is considerable overhead to serialization / deserialization that is not ignorable in the context of hugr-py.
hugr-py/src/hugr/metadata.py
Outdated
| @classmethod | ||
| def to_json(cls, value: list[ExtensionDesc]) -> list[dict[str, str]]: | ||
| return [e._to_json() for e in value] | ||
|
|
||
| @classmethod | ||
| def from_json(cls, value: Any) -> list[ExtensionDesc]: | ||
| if not isinstance(value, list): | ||
| msg = ( | ||
| "Expected UsedExtensions metadata to be a list," | ||
| + f" but got {type(value)}" | ||
| ) | ||
| raise TypeError(msg) | ||
| return [ExtensionDesc._from_json(e) for e in value] |
There was a problem hiding this comment.
Similar to the mixin suggestion, lists of wrapped types may be another example of a common pattern that could occur multiple times.
hugr-py/src/hugr/envelope.py
Outdated
| name: str | ||
| version: Version | None | ||
|
|
||
| def _to_json(self) -> dict[str, str]: |
There was a problem hiding this comment.
Is it useful to have a protocol for _to_json and _from_json? Also, should these be non-private since they are called from outside the class?
There was a problem hiding this comment.
I wanted to keep the PR simple and focused on the metadata protocol for now.
We should probably look into serializable protocols for the value types. (does pydantic help here?), but I'll leave it for later.
The _to/_from_json shouldn't normally be called by users. I'd love to have a pub(crate) attribute here...
There was a problem hiding this comment.
While its true that a user has no benefit to calling these methods, there is no harm either, since its either read-only or a constructing method, i.e. they cannot violate any contracts with using these methods. I am unsure as to what the policy of this repo is, i.e. whether a cleaner user interface or adhering to general Python guidelines has a higher priority.
There was a problem hiding this comment.
Removed the _ from these
maximilianruesch
left a comment
There was a problem hiding this comment.
A preliminary LGTM on the code, save for the last comment on _to_json visibility, and some failing coverage checks (which imo one should address in some way, since the code contains many paths).
|
Lettuce wait for CI 🥬 (it is done) |
🤖 I have created a release *beep* *boop* --- ## [0.15.4](hugr-py-v0.15.3...hugr-py-v0.15.4) (2026-02-20) ### Features * **hugr-py:** Define typed Metadata protocol ([#2765](#2765)) ([4390230](4390230)) ### Bug Fixes * Add truncation options for node and edge labels in rendering ([#2885](#2885)) ([25c625d](25c625d)) * used_extensions should include transitive requirements ([#2891](#2891)) ([18e78e4](18e78e4)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: Agustín Borgna <[email protected]>
## 🤖 New release * `hugr-model`: 0.25.5 -> 0.25.6 (✓ API compatible changes) * `hugr-core`: 0.25.5 -> 0.25.6 (✓ API compatible changes) * `hugr-llvm`: 0.25.5 -> 0.25.6 (✓ API compatible changes) * `hugr-passes`: 0.25.5 -> 0.25.6 (✓ API compatible changes) * `hugr`: 0.25.5 -> 0.25.6 (✓ API compatible changes) * `hugr-cli`: 0.25.5 -> 0.25.6 (✓ API compatible changes) * `hugr-persistent`: 0.4.5 -> 0.4.6 <details><summary><i><b>Changelog</b></i></summary><p> ## `hugr-model` <blockquote> ## [0.25.6](hugr-model-v0.25.5...hugr-model-v0.25.6) - 2026-02-20 ### New Features - Remove size limitation for binary envelopes ([#2880](#2880)) </blockquote> ## `hugr-core` <blockquote> ## [0.25.6](hugr-core-v0.25.5...hugr-core-v0.25.6) - 2026-02-20 ### Bug Fixes - Canonicalize more ([#2839](#2839)) - used_extensions should include transitive requirements ([#2891](#2891)) ### New Features - Add s expression format to envelope formats ([#2864](#2864)) - added hash.rs, updated imports ([#2840](#2840)) - *(hugr-py)* Define typed Metadata protocol ([#2765](#2765)) - Add a `NodeTemplate::call_to_function` helper ([#2878](#2878)) - Remove size limitation for binary envelopes ([#2880](#2880)) </blockquote> ## `hugr-llvm` <blockquote> ## [0.25.6](hugr-llvm-v0.25.5...hugr-llvm-v0.25.6) - 2026-02-20 ### New Features - Add error context when lowering hugrs to LLVM ([#2869](#2869)) </blockquote> ## `hugr-passes` <blockquote> ## [0.25.6](hugr-passes-v0.25.5...hugr-passes-v0.25.6) - 2026-02-20 ### Bug Fixes - Panic on UntuplePass when nodes had order edges ([#2883](#2883)) ### New Features - added hash.rs, updated imports ([#2840](#2840)) - Add a `NodeTemplate::call_to_function` helper ([#2878](#2878)) </blockquote> ## `hugr` <blockquote> ## [0.25.6](hugr-v0.25.5...hugr-v0.25.6) - 2026-02-20 ### Bug Fixes - Panic on UntuplePass when nodes had order edges ([#2883](#2883)) - Canonicalize more ([#2839](#2839)) - used_extensions should include transitive requirements ([#2891](#2891)) ### New Features - Add s expression format to envelope formats ([#2864](#2864)) - *(hugr-py)* Define typed Metadata protocol ([#2765](#2765)) - Add a `NodeTemplate::call_to_function` helper ([#2878](#2878)) - added hash.rs, updated imports ([#2840](#2840)) - Remove size limitation for binary envelopes ([#2880](#2880)) </blockquote> ## `hugr-cli` <blockquote> ## [0.25.6](hugr-cli-v0.25.5...hugr-cli-v0.25.6) - 2026-02-20 ### New Features - Add s expression format to envelope formats ([#2864](#2864)) </blockquote> ## `hugr-persistent` <blockquote> ## [0.4.0](hugr-persistent-v0.3.4...hugr-persistent-v0.4.0) - 2025-12-22 ### New Features - [**breaking**] Remove `RootCheckable` ([#2704](#2704)) - [**breaking**] Bump MSRV to Rust 1.89 ([#2747](#2747)) - [**breaking**] Type-safe access for node metadata ([#2755](#2755)) ### Refactor - [**breaking**] Remove multiple deprecated definitions ([#2751](#2751)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/).
Adds a
Metadataprotocol similar to the one in the rust side, and exports the rust key definitions.Depends on #2764Closes #2757