Skip to content
Closed
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
fa2bf47
Add tests
maximilianruesch Feb 12, 2026
bf94f3c
Be able to add hugr name to functions and declarations
maximilianruesch Feb 12, 2026
b5cc1a2
Add engine function for packaging multiple def ids
maximilianruesch Feb 12, 2026
2da8eb9
Refactor check
maximilianruesch Feb 12, 2026
7d3339f
Allow defining library
maximilianruesch Feb 12, 2026
ea765ab
Add smoketest
maximilianruesch Feb 12, 2026
347b28c
Assert function names
maximilianruesch Feb 12, 2026
f2828ad
Moar todo
maximilianruesch Feb 12, 2026
7b20e42
Clear engine before each group check
maximilianruesch Feb 12, 2026
e299dc2
Add doc string
maximilianruesch Feb 12, 2026
7858aa3
Enable setting hugr name for both structs and functions
maximilianruesch Feb 17, 2026
d27f7f8
Enable the shenanigans for declarations
maximilianruesch Feb 17, 2026
bb79fe1
Enable supporting hugr names with structs
maximilianruesch Feb 17, 2026
884af0c
Add tests
maximilianruesch Feb 17, 2026
4269abd
Remove parent_ty from monomorphization
maximilianruesch Feb 17, 2026
3ae4d2f
Fix test
maximilianruesch Feb 17, 2026
9c96091
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Feb 17, 2026
3d36eab
Change todo
maximilianruesch Feb 17, 2026
8fe7372
Better compile interface
maximilianruesch Feb 17, 2026
15042a1
More todo
maximilianruesch Feb 17, 2026
96dbc86
Always check and compile type members along with their types
maximilianruesch Feb 17, 2026
d95157e
Update smoketest
maximilianruesch Feb 17, 2026
8c1b5a4
Remove todo rn
maximilianruesch Feb 17, 2026
e7764c1
Add visibility to smoketest
maximilianruesch Feb 17, 2026
0f25bed
Add to all
maximilianruesch Feb 17, 2026
6e2444f
Edit doc comments
maximilianruesch Feb 18, 2026
a69325b
More doc
maximilianruesch Feb 18, 2026
138820f
Test doc
maximilianruesch Feb 18, 2026
dcc3b95
Update tests
maximilianruesch Feb 18, 2026
8d8fd68
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Feb 18, 2026
82d72e2
Do something
maximilianruesch Feb 18, 2026
b4aae13
Merge branch 'main' into mr/feat/pass-hugr-names
maximilianruesch Feb 19, 2026
dc5bb69
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Feb 19, 2026
5cea515
Merge branch 'main' into mr/feat/pass-hugr-names
maximilianruesch Feb 23, 2026
39851d2
Implement review changes
maximilianruesch Feb 23, 2026
38738a1
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Feb 23, 2026
b08639f
Include hugr py branch
maximilianruesch Feb 23, 2026
5fb7d6e
Add visibility to functions depending on exported defs
maximilianruesch Feb 23, 2026
9d05998
Update hugr py branch
maximilianruesch Feb 23, 2026
ee9a412
Purge a TODO
maximilianruesch Feb 23, 2026
4e2c1bf
Add more tests
maximilianruesch Feb 23, 2026
1024c14
Merge branch 'main' into mr/feat/pass-hugr-names
maximilianruesch Feb 23, 2026
7a0cd43
Merge lower branch
maximilianruesch Feb 23, 2026
49e8053
Merge branch 'main' into mr/feat/pass-hugr-names
maximilianruesch Feb 24, 2026
d439817
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Feb 24, 2026
172076c
Move everything to link name
maximilianruesch Feb 26, 2026
e3fda71
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Feb 26, 2026
af7a656
Sync lock file
maximilianruesch Mar 4, 2026
319877c
Begin library docs
maximilianruesch Mar 4, 2026
6e4f9c3
Moar docs
maximilianruesch Mar 4, 2026
18f39f9
Propose impls
maximilianruesch Mar 4, 2026
1ae986f
Merge branch 'mr/feat/compile-library' into mr/docs/document-libraries
maximilianruesch Mar 5, 2026
ebcb017
Expand
maximilianruesch Mar 5, 2026
bd70682
Propose Hugr discovery
maximilianruesch Mar 5, 2026
17bda6b
Case Hugr correctly
maximilianruesch Mar 5, 2026
5303842
Open question
maximilianruesch Mar 5, 2026
1dd6653
Collection proposal
maximilianruesch Mar 5, 2026
42f709a
Stub proposal
maximilianruesch Mar 5, 2026
f3a54d5
Add link names
maximilianruesch Mar 5, 2026
2e40f0a
Merge branch 'main' into mr/feat/pass-hugr-names
maximilianruesch Mar 6, 2026
c6d1333
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Mar 6, 2026
ee67cc0
Merge branch 'mr/feat/compile-library' into mr/docs/document-libraries
maximilianruesch Mar 6, 2026
4b9f746
Update to main branch of hugr
maximilianruesch Mar 6, 2026
9b504cb
Merge branch 'mr/feat/compile-library' into mr/docs/document-libraries
maximilianruesch Mar 6, 2026
af04b70
fix: improve wording in overview.md for clarity
maximilianruesch Mar 6, 2026
7b79531
typos
maximilianruesch Mar 6, 2026
31c6d35
More clearly link
maximilianruesch Mar 6, 2026
43d1c20
Add note
maximilianruesch Mar 6, 2026
94e24ee
Add entrypoint note
maximilianruesch Mar 9, 2026
6940a69
Update to local hugr
maximilianruesch Mar 9, 2026
a680d54
Switcheroo
maximilianruesch Mar 9, 2026
0366745
Allow providing libs to emulator
maximilianruesch Mar 9, 2026
3a4adea
Update hugr-py
maximilianruesch Mar 9, 2026
f0a53a9
Merge branch 'main' into mr/feat/pass-hugr-names
maximilianruesch Mar 9, 2026
8af952a
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Mar 9, 2026
9c73124
Update hugr-py
maximilianruesch Mar 9, 2026
302e748
Add dummy decorator
maximilianruesch Mar 10, 2026
ed4f588
Some tests
maximilianruesch Mar 10, 2026
be4354a
Moar tests
maximilianruesch Mar 10, 2026
9310f30
Add precompile test
maximilianruesch Mar 10, 2026
1005c68
Add structural subtyping test
maximilianruesch Mar 10, 2026
57cce96
Unused func duplicate defn test
maximilianruesch Mar 10, 2026
3dac704
Improve docs
maximilianruesch Mar 13, 2026
4624c4d
Name things decorator
maximilianruesch Mar 13, 2026
798cc63
Improve test
maximilianruesch Mar 13, 2026
2dcb141
Common up link name into a superclass
maximilianruesch Mar 13, 2026
17dbd34
Even better
maximilianruesch Mar 13, 2026
4f4d1b9
Merge branch 'mr/feat/pass-hugr-names' into mr/feat/compile-library
maximilianruesch Mar 13, 2026
9f7f58c
Merge branch 'main' into mr/feat/compile-library
maximilianruesch Mar 13, 2026
7d1c193
Add is_decl
maximilianruesch Mar 16, 2026
93a822e
Test file import
maximilianruesch Mar 16, 2026
36c3267
Update hugr-py
maximilianruesch Mar 16, 2026
f949ab1
Add entrypoint tests
maximilianruesch Mar 16, 2026
114c699
Easier tests
maximilianruesch Mar 16, 2026
d87b0cc
Update hugr-py
maximilianruesch Mar 16, 2026
03ef997
Hopefully fix tests
maximilianruesch Mar 16, 2026
4b74d54
Remove unused func
maximilianruesch Mar 16, 2026
d572b84
Build hugr from main instead of branch
maximilianruesch Mar 17, 2026
b455507
Docstrings
maximilianruesch Mar 18, 2026
da2ab2b
Decl as property
maximilianruesch Mar 18, 2026
0141677
update hugr
maximilianruesch Mar 18, 2026
620a768
Test against hugr linking error
maximilianruesch Mar 18, 2026
ac0482e
Reworked reset things
maximilianruesch Mar 18, 2026
88d36e5
Update hugr-py
maximilianruesch Mar 20, 2026
be02ee0
Merge branch 'mr/feat/compile-library' into mr/docs/document-libraries
maximilianruesch Mar 23, 2026
288e410
Remove foreword
maximilianruesch Mar 23, 2026
8439503
Update overview
maximilianruesch Mar 23, 2026
ff7df03
Update stubs
maximilianruesch Mar 23, 2026
9b753f3
Merge branch 'main' into mr/docs/document-libraries
maximilianruesch Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build
1 change: 1 addition & 0 deletions docs/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ mkdir build
touch build/.nojekyll # Disable jekyll to keep files starting with underscores

uv run --group docs sphinx-build -b html ./api-docs ./build/api-docs
uv run --group docs sphinx-build -b html ./library-docs ./build/library-docs
Empty file added docs/library-docs/__init__.py
Empty file.
30 changes: 30 additions & 0 deletions docs/library-docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Configuration file for the Sphinx documentation builder.
# See https://www.sphinx-doc.org/en/master/usage/configuration.html

project = "Guppy Libraries"
copyright = "2026, Quantinuum"
author = "Quantinuum"

extensions = [
"sphinx.ext.napoleon",
"sphinx.ext.autodoc",
"sphinx.ext.coverage",
"sphinx.ext.viewcode",
"sphinx.ext.intersphinx",
"sphinx_copybutton",
"myst_parser",
]

html_theme = "furo"

html_title = "Guppy library docs"

html_theme_options = {}

html_static_path = []

exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

intersphinx_mapping = {
"python": ("https://docs.python.org/3/", None),
}
18 changes: 18 additions & 0 deletions docs/library-docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Guppy Libraries Documentation

An introductory tale into how Guppy libraries (are supposed to) work, how to write them, and how to use them.

```{note}
This docs collection concerns Guppy libraries usage for independently compiling a set of functions to a Hugr package,
which can be independently distributed and e.g. cached for optimization purposes. If you are just looking to open
source your Guppy code, the standard packaging mechanisms of Python suffice, and you can ignore this page.
```

- Foreword

```{toctree}
:maxdepth: 2

overview
proposals
```
199 changes: 199 additions & 0 deletions docs/library-docs/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# Overview

## Defining a library

A Guppy library is, at its simplest, a collection of functions that are compiled together into a Hugr package.
In contrast to the usual executable Hugr packages (like those produced from compiling single entrypoint functions), such
library Hugr packages feature (usually multiple) *public* functions, possibly with arguments and non-``None`` return
types.

A developer may define several functions beyond this collection, for example for internally sharing functionality
between the public functions. Furthermore, developers may want to create different libraries / Hugr packages from a
single codebase, requiring to export different public functions in each such library.
In Guppy, a library is defined by calling the ``guppy.library(...)`` function, passing the functions to be exported as
public.
Any functions reachable via those functions are still included in the Hugr package, but with private visibility.

For example, a library may be defined as follows:

```python
from guppylang import guppy


@guppy
def my_func() -> None:
pass


@guppy
def another_func(x: int) -> None:
pass


@guppy
def a_third_func(x: int) -> int:
return x + 1


# Creates the library object, but does not compile it
library = guppy.library(
my_func,
another_func,
a_third_func,
)
```

For private functions, the name their Hugr nodes receive is not important.
However, public functions need to have a stable (and unique) name for the Hugr to be valid and useful.
Guppy includes a default name inference mechanism based on the fully qualified name of the function (including any
parent types and the module path), but it is also possible to explicitly specify the name (e.g. to avoid conflicts, make
a backward-compatible change, or to provide a more user-friendly name) using the `link_name` argument of the `@guppy`
decorator:

```python
from guppylang import guppy


@guppy(link_name="my.custom.link.name")
def my_func() -> None:
pass
```

The following are not yet supported:

- Exporting generic functions of any kind (see the [proposal](proposals/generic.md))
- Automatically collecting functions to be included in a library (see the [proposal](proposals/collection.md))

## Compiling a library and creating stubs

Once a library object is created, it can be compiled into a Hugr package, which can be distributed and used
independently of the source code:

```python
from guppylang import guppy
from hugr.package import Package

library = guppy.library(...) # As above

# Hugr package contains any specified functions as public, and otherwise reachable functions as private
hugr_package: Package = library.compile()
with open("library.hugr", "wb") as f:
f.write(hugr_package.to_bytes())
```

However, this Hugr package does not expose an interface that can be programmed against by consumers of the library *in
Guppy*. For this, the library author must define *stubs* for all exposed functions, utilising `@guppy.declare(...)`
decorators.

For the example above, this would look like:

```python
from guppylang import guppy


@guppy.declare
def my_func() -> None: ...


@guppy.declare
def another_func(x: int) -> None: ...


@guppy.declare
def a_third_func(x: int) -> int: ...
```

Creation of these stubs is a manual process; it is currently not possible to automatically generate stubs for a
library or validate that definitions faithfully implement their corresponding stubs (see the
[proposal](proposals/stubs.md) for both). Furthermore, it is currently not possible to define the stubs, and
subsequently reference the stubs in the library function definitions for easier consistency checks (see the
[proposal](proposals/impls.md) for that).

Finally, these stubs (in `*.pyi` files) should be distributed using regular Python packaging mechanisms, so that users
of the library can install and program against them. This distribution may or may not contain the Hugr package as well.

## Using a library

Let's call the library in the example above `super_guppy`.
That is, the library author has published a distribution containing the stubs above, to be imported `from super_guppy`.
A consumer of the library has installed that distribution using their favourite package manager (either from an index,
or by downloading the stub repository).

The consumer may now program against the API as follows:

```python
from guppylang import guppy
from guppylang.std.builtins import result
from super_guppy import my_func, a_third_func


@guppy
def consumer_func() -> None:
my_func()
result("library_call", a_third_func(5))


@guppy
def main() -> None:
consumer_func()
```

In this case, the consumer aims to create an executable Hugr package (e.g. by calling `main.compile()` and creating a
package with a single, argument-less entrypoint). However, the created Hugr package is incomplete: It lacks the function
bodies of the library functions, and thus cannot be executed.

Thus, `hugr-py` MUST provide means to link the library Hugr package into the consumer Hugr package. The proposed
mechanism for this is to allow operations on Hugr packages that (a) allow to add modules and extensions from other
packages, and (b) allow to combine multiple modules inside the same package into a single module. In code, this may look
like:

```python
from hugr.package import Package

package_a: Package = ...
package_b: Package = ...
package_c: Package = ...

# (a) add modules and extensions from other packages
package_a.add_from(package_b).add_from(package_c)

# (b) combine multiple modules into a single module inside the package
package_a.link_modules()
Comment thread
maximilianruesch marked this conversation as resolved.
Outdated
# Now package_a contains a single module with all the functions
# from package_a, package_b, and package_c
Comment thread
maximilianruesch marked this conversation as resolved.
```

There are no guarantees about the order of modules being linked together, or whether that is pairwise or all at once.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If we reject duplicate definitions then the order generally only affects what error is reported, rather than whether there is an error or what the resulting Hugr looks like in case of success, so fine :)

A package may also expose more fine-grained control over the linking process, for example by allowing to "link" in
entire packages, steering the reduction ordering:

```python
# Extensions and modules are added from package_b,
# and its module is linked into the module of package_a
package_a.link(package_b)

# In the future, keywords may be added to allow e.g. privatization of all
# functions from package_b (i.e. swallowing), so for example:
package_a.link(package_b, privatize=True)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or possibly something funky like package_a.link(Privatize(package_b), ReplaceFuncsWithExisting(package_c)) where Privatize/... have a type of LinkingDirective (i.e. are not funcs producing a Hugr/Package)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I will leave that to be figured out by future implementors

```

```{note}
It is yet unclear whether this process should be done in-place or producing copies (which may cause a significant slowdown).
```

For convenience, the
library Hugr package may be provided to the consumer program executor, so that it can be automatically linked in before
compiling to binary. For example, using selene, this may look like:

```python
main.emulator(n_qubits=0, libraries=[hugr_package]).with_shots(100).run()
```

Currently, Hugr packages have to be manually downloaded / imported from whatever distribution mechanism the library
author chose. In the future, library authors may opt to distribute Hugr packages in Python wheels as well, and have
consuming code auto-collect these from the Python environment (see the [proposal](proposals/discovery.md) for this).

```{note}
A consumer of `super_guppy` may as well be another library author. Dependency of a library should be specified as usual
in Python requirements by depending on the header distributions (or through other common mechanisms).
```
9 changes: 9 additions & 0 deletions docs/library-docs/proposals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Proposals

A collection of proposals for QOL features related to Guppy libraries.

```{toctree}
:glob:

proposals/*
```
82 changes: 82 additions & 0 deletions docs/library-docs/proposals/collection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# (Proposal) More ways to define a library / auto-collection

Currently, functions must be manually fed into `guppy.library(...)` to be included in the library. This proposal
concerns additional ways to define (members of) a library, and automatically collect functions to be included in it.

A potential addition would be a `@guppy(export=...)` argument, that registers the function to be included in *the*
library in some global Guppy store (like the `DEF_STORE`). A function could then be included simply by adding that
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

a "global library" is a bit confusing - this still would require some notion of a specific library the function is exported in. The string method below addresses this, but passing in library objects rather than strings seems preferable

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This seems very similar to how GuppyModules were handled.

argument, e.g.:

```python
from guppylang import guppy


@guppy(export=True)
def included() -> None:
...


@guppy # or @guppy(export=False) for explicit exclusion
def not_included() -> None:
...
```

This is similar to a `public` / `private` modifier, and indirectly determines the visibility of the function in the Hugr
package. It may be added to `@guppy.struct` and `@guppy.enum` as well, to include the functions on these constructs in
the library as public as well.

A call to `guppy.library` could then be simplified to an explicit opt-in to auto-collection:

```python
from guppylang import guppy

# ... the functions above ...

# Includes `included`, but not `not_included` as a public member.
library = guppy.library(auto_collect=True)
```

## Optional: Keys

In addition to supporting `True | False | None` for the `export` argument, it may be useful to support string keys as
well, to allow for more fine-grained control over the produced packages in which the function is included (concerning
both the visibility in the produced Hugr package and the stubs that are generated, e.g.
through [the stub proposal](stubs.md)).

For example, one may want to include certain (core) functions in all versions of the library, but specify certain sets
of functions to be included (akin to `extras` from Python packages):

```python
from guppylang import guppy


@guppy(export=True)
def included_in_all_libs() -> None:
...


@guppy(export='key1')
def included_when_key_1() -> None:
...


@guppy(export='key2')
def included_when_key_2() -> None:
...


@guppy(export='key3')
def included_when_key_3() -> None:
...
```

Auto-collection may then take a range of keys to include:

```python
from guppylang import guppy

# ... the functions above ...

# Includes all functions with export=True, export='key1', and export='key2', but not export='key3'
library = guppy.library(auto_collect=['key1', 'key2'])
```
Loading
Loading