Skip to content

Hugr.to_bytes should include required extensions #2841

@aborgna-q

Description

@aborgna-q

Package definitions include a manually-defined list of extensions required to load the hugr,
that gets included in the envelope when calling Package.to_bytes/to_str.

When encoding a standalone Hugr, we wrap it in a Package with an empty list of extensions before encoding it.

Now that we can compute the list of extensions used by a hugr dinamically (#2817), we could automatically add those to the created package to ensure that the envelope can be loaded by any target.

I'd propose adding a new parameter to Hugr.to_bytes and to_str,

class Hugr:
    def to_bytes(self, (...), *, include_extensions: ExtensionRegistry | None = None) -> bytes: ...
    def to_str(self, (...), *, include_extensions: ExtensionRegistry | None = None) -> str: ...

If include_extensions is None, we run used_extensions and add any non-prelude ones to the package. Otherwise we embed the given registry.

If one wants better control over the included extensions, it's always possible to create a package manually with the desired bundled extensions.


Note that this behaviour differs from the rust definition, where the default store explicitly omits storing extra extensions.

hugr/hugr-core/src/hugr.rs

Lines 184 to 204 in a21e818

/// Store the HUGR in an Envelope.
///
/// The Envelope will not include any extension definition, and will require
/// an adequate [`ExtensionRegistry`] to be loaded (see [`Hugr::load`]).
/// Use [`Hugr::store_with_exts`] to include additional extensions in the
/// Envelope.
pub fn store(&self, writer: impl io::Write, config: EnvelopeConfig) -> Result<(), WriteError> {
self.store_with_exts(writer, config, &EMPTY_REG)
}
/// Store the HUGR in an Envelope.
///
/// The Envelope will embed the definitions of the extensions in the
/// `extensions` registry. Any other extension used in the HUGR definition
/// must be passed to [`Hugr::load`] to load back the HUGR.
pub fn store_with_exts(
&self,
writer: impl io::Write,
config: EnvelopeConfig,
extensions: &ExtensionRegistry,
) -> Result<(), WriteError> {

The rust interface in general provides finer control over the compiler behaviour, but for the python side we should err on the side of intuitiveness.
If I to_bytes a hugr I would expect it can be loaded afterwards wherever I need it. Trimming the extensions included in the envelope should be a later size-optimization.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions