feat(hugr-py): Allow linking packages and modules from Python#2947
feat(hugr-py): Allow linking packages and modules from Python#2947maximilianruesch merged 17 commits intomainfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2947 +/- ##
==========================================
+ Coverage 83.84% 83.85% +0.01%
==========================================
Files 267 267
Lines 52923 52953 +30
Branches 46854 46869 +15
==========================================
+ Hits 44371 44402 +31
+ Misses 6283 6282 -1
Partials 2269 2269
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:
|
|
Note: I am unsure where to add tests for Also, one could consider whether we should refactor |
hugr-py/rust/linking.rs
Outdated
| .store_with_exts(&mut result, EnvelopeConfig::binary(), &exts_into) | ||
| .unwrap(); | ||
|
|
||
| hugr_core::package::Package::load(&result[..], None) |
There was a problem hiding this comment.
This seems like something we don't want in production, I'd say make it a debug assert, but not sure how that works with maturin
There was a problem hiding this comment.
Oop yeah, that was something that was used for debugging. I will have a look at debug asserts.
There was a problem hiding this comment.
Seems to work as you would expect in regular rust. I pushed it to a debug statement.
| } | ||
|
|
||
| #[pyfunction] | ||
| fn link_modules(module_into: &[u8], module_from: &[u8]) -> PyResult<Vec<u8>> { |
There was a problem hiding this comment.
I notice that we're going to have all three hugrs in memory, which seems like it could be a problem.
I don't really have strong enough rust/pyO3 foo to say the solution, but possibly:
- take as arguments
impl Readerso the files are read here and their contents can be dropped - Take
Packageas argument so we can consume them when they're linked in and release the memory
There was a problem hiding this comment.
I could instead take an owned Vec<u8> if that helps... See https://pyo3.rs/v0.28.2/conversions/tables.html for allowed types / types that have an implementation of the required traits out of the box.
There was a problem hiding this comment.
I modified the param. It seems that the reader trait to read into a hugr is not implemented for a vec though, so I still use a slice. It might also not make much of a difference since Python has no concept of ownership, so I presume the contents are copied anyway. This might actually be more expensive now 😅
There was a problem hiding this comment.
I benchmarked it, and using the QAOA example using Vec<u8 I had about 0.048s per link call (from Python), whereas using &[u8] gave me about 0.031s per link call (probably due to avoiding an unnecessary copy. I reverted the change.
…export (#2964) Does: - Correct / add missing parent module names to the existing modules (as far as I know this is mainly for the specifier displayed when printing the module in e.g. a Python REPL) - Correct module definitions for exception classes (again, I think this only has display / introspection impact) - Add a missing reexport of an exception class in the linking module (and add a test for it from Python to ensure it exists). Related to #2947
## 🤖 New release * `hugr-model`: 0.26.0 -> 0.26.1 * `hugr-core`: 0.26.0 -> 0.26.1 (✓ API compatible changes) * `hugr-llvm`: 0.26.0 -> 0.26.1 * `hugr`: 0.26.0 -> 0.26.1 (✓ API compatible changes) * `hugr-passes`: 0.26.0 -> 0.26.1 (✓ API compatible changes) * `hugr-cli`: 0.26.0 -> 0.26.1 * `hugr-persistent`: 0.5.0 -> 0.5.1 <details><summary><i><b>Changelog</b></i></summary><p> ## `hugr-model` <blockquote> ## [0.26.0](hugr-model-v0.25.7...hugr-model-v0.26.0) - 2026-03-16 ### Testing - Replace model text snapshots with roundtrip tests ([#2933](#2933)) - Add missing width arg in model-call example ([#2945](#2945)) </blockquote> ## `hugr-core` <blockquote> ## [0.26.1](hugr-core-v0.26.0...hugr-core-v0.26.1) - 2026-03-18 ### New Features - *(hugr-py)* Allow linking packages and modules from Python ([#2947](#2947)) ### Refactor - start cleaning up SiblingSubgraph convexity checking ([#2956](#2956)) </blockquote> ## `hugr-llvm` <blockquote> ## [0.26.0](hugr-llvm-v0.25.7...hugr-llvm-v0.26.0) - 2026-03-16 ### New Features - *(llvm)* [**breaking**] Upgrade to LLVM 21 ([#2901](#2901)) - Include private HUGR functions in the local symbol table ([#2831](#2831)) - [**breaking**] TypeRow: add impl From array of Type, remove From<Type> ([#2784](#2784)) ### Refactor - [**breaking**] Remove deprecated Value::Function ([#2928](#2928)) - [**breaking**] Remove deprecated stack_array codegen ([#2929](#2929)) </blockquote> ## `hugr` <blockquote> ## [0.26.1](hugr-v0.26.0...hugr-v0.26.1) - 2026-03-18 ### Bug Fixes - ConstantFold fails when the module contains function declarations ([#2954](#2954)) ### New Features - *(hugr-py)* Allow linking packages and modules from Python ([#2947](#2947)) ### Refactor - start cleaning up SiblingSubgraph convexity checking ([#2956](#2956)) </blockquote> ## `hugr-passes` <blockquote> ## [0.26.1](hugr-passes-v0.26.0...hugr-passes-v0.26.1) - 2026-03-18 ### Bug Fixes - ConstantFold fails when the module contains function declarations ([#2954](#2954)) </blockquote> ## `hugr-cli` <blockquote> ## [0.26.0](hugr-cli-v0.25.7...hugr-cli-v0.26.0) - 2026-03-16 ### Documentation - Move `spec/schema` and `spec/std_extensions` to `resources/` ([#2897](#2897)) ### New Features - [**breaking**] Rename ModelText envelope format to SExpression ([#2927](#2927)) - [**breaking**] TypeRow: add impl From array of Type, remove From<Type> ([#2784](#2784)) </blockquote> ## `hugr-persistent` <blockquote> ## [0.5.0](hugr-persistent-v0.4.7...hugr-persistent-v0.5.0) - 2026-03-16 ### New Features - *(llvm)* [**breaking**] Upgrade to LLVM 21 ([#2901](#2901)) - [**breaking**] TypeRow: add impl From array of Type, remove From<Type> ([#2784](#2784)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/).
🤖 I have created a release *beep* *boop* --- ## [0.16.0](hugr-py-v0.15.4...hugr-py-v0.16.0) (2026-04-01) This release changes the default text serialization format from JSON to `MODEL_WITH_EXTS` (the JSON format is now deprecated). It also adds the ability to link packages and modules from Python, renders operation type arguments in HUGR visualizations, introduces a new `debug_info` module for attaching source-level debug metadata to nodes, and introduces multi-version support in `ExtensionRegistry`, allowing different versions of the same extension to coexist in the same registry. ### ⚠ BREAKING CHANGES * `ExtensionRegistry` may now contain multiple versions of the same extension. `.extensions` is now an iterator of the latest versions instead of a dictionary. `.register_updated` and `.add_extension` have been replaced with a singular `.register`. * Default `EnvelopeConfig` changed from `EnvelopeFormat.JSON` to `EnvelopeFormat.MODEL_WITH_EXTS`. * Substituted `hugr-py/src/hugr/tys.py::_type_str` with `hugr-py/src/hugr/utils.py::name_w_args`. ### Features * Add debug info metadata specification in `hugr-py` ([#2971](#2971)) ([a4da8ef](a4da8ef)) * Allow multiple versions of an extension in an ExtensionRegistry ([#3005](#3005)) ([ee90cd1](ee90cd1)) * Deprecate JSON serialization format ([#2991](#2991)) ([0f7a880](0f7a880)) * Operation parameter rendering in HUGR visualizations ([#2995](#2995)) ([d619148](d619148)) * Allow linking packages and modules from Python ([#2947](#2947)) ([329c243](329c243)) * Make `_composable_pass` and `_scope` public modules ([#2962](#2962)) ([1d6af9a](1d6af9a)), closes [#2961](#2961) * Allow missing ext versions ExtensionDesc metadata ([#2979](#2979)) ([bc1c445](bc1c445)) * Allow dfg conversion in to TrackedDfg ([#2993](#2993)) ([3bd7a88](3bd7a88)) ### Bug Fixes * Allow both _composable_pass and composable_pass imports ([#2965](#2965)) ([0a5664d](0a5664d)) * Allow both _scope and scope imports ([#3003](#3003)) ([de0458c](de0458c)) * Always do extension resolution when loading packages and hugrs ([#2953](#2953)) ([0086d2a](0086d2a)) * Correct pyo3 module definitions and add missing exception class export ([#2964](#2964)) ([3df73f4](3df73f4)) * Include extensions during link serialization ([#2992](#2992)) ([9236e89](9236e89)) * Prefix names with underscores during serialization ([#2989](#2989)) ([8aab636](8aab636)) * Use valid identifiers when constructing AST model ([#2973](#2973)) ([8750a6b](8750a6b)) --- 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]>
Adds capabilities to
hugr-pyto allow linking modules and entire packages together. This is a required feature for Guppy libraries, found in Quantinuum/guppylang#1481, and could be considered the core feature for the same.hugr-coreneeded a slight modification to allow reading a module from an envelope (with all the builtin validation around expecting a single module) while also returning the extensions present in the envelope. The functions are exposed via pyo3 bindings to Python and tested there.