Skip to content

Commit aba0f0e

Browse files
♻️ Replace pybind11 with nanobind (#1383)
## Description This PR fully replaces `pybind11` with `nanobind`. This change will allow us to ship stable ABI wheels, saving us PyPI space. ## Checklist: - [x] The pull request only contains commits that are focused and relevant to this change. - [x] ~I have added appropriate tests that cover the new/changed functionality.~ - [x] I have updated the documentation to reflect these changes. - [x] I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals. - [x] I have added migration instructions to the upgrade guide (if needed). - [x] The changes follow the project's style guidelines and introduce no new warnings. - [x] The changes are fully tested and pass the CI checks. - [x] I have reviewed my own code changes. --------- Signed-off-by: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Signed-off-by: burgholzer <burgholzer@me.com> Co-authored-by: burgholzer <burgholzer@me.com>
1 parent 3ed1da8 commit aba0f0e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+6846
-3693
lines changed

.clang-tidy

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ Checks: |
3030
readability-*,
3131
-readability-identifier-length,
3232
-readability-magic-numbers,
33-
-readability-function-cognitive-complexity
33+
-readability-function-cognitive-complexity,
34+
-*-prefer-static-over-anonymous-namespace
3435
3536
CheckOptions:
3637
- key: readability-identifier-naming.ClassCase
@@ -73,5 +74,3 @@ CheckOptions:
7374
value: CamelCase
7475
- key: readability-identifier-naming.VariableCase
7576
value: camelBack
76-
- key: misc-include-cleaner.IgnoreHeaders
77-
value: pybind11/detail/.*

.github/workflows/cd.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ permissions:
1212
jobs:
1313
build-sdist:
1414
name: 🐍 Packaging
15-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging-sdist.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
15+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging-sdist.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
1616

1717
# Builds wheels on all supported platforms using cibuildwheel.
1818
# The wheels are uploaded as GitHub artifacts `dev-cibw-*` or `cibw-*`, depending on whether
@@ -31,7 +31,7 @@ jobs:
3131
windows-2022,
3232
windows-11-arm,
3333
]
34-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging-wheel-cibuildwheel.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
34+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging-wheel-cibuildwheel.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
3535
with:
3636
runs-on: ${{ matrix.runs-on }}
3737

.github/workflows/ci.yml

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ concurrency:
1414
jobs:
1515
change-detection:
1616
name: 🔍 Change
17-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-change-detection.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
17+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-change-detection.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
1818

1919
cpp-tests-ubuntu:
2020
name: 🇨‌ Test 🐧
@@ -30,7 +30,7 @@ jobs:
3030
- runs-on: ubuntu-24.04
3131
compiler: gcc
3232
config: Debug
33-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-ubuntu.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
33+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-ubuntu.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
3434
with:
3535
runs-on: ${{ matrix.runs-on }}
3636
compiler: ${{ matrix.compiler }}
@@ -50,7 +50,7 @@ jobs:
5050
- runs-on: macos-14
5151
compiler: clang
5252
config: Debug
53-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-macos.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
53+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-macos.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
5454
with:
5555
runs-on: ${{ matrix.runs-on }}
5656
compiler: ${{ matrix.compiler }}
@@ -71,7 +71,7 @@ jobs:
7171
- runs-on: windows-2022
7272
compiler: msvc
7373
config: Debug
74-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-windows.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
74+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-windows.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
7575
with:
7676
runs-on: ${{ matrix.runs-on }}
7777
compiler: ${{ matrix.compiler }}
@@ -88,7 +88,7 @@ jobs:
8888
runs-on: [ubuntu-24.04, ubuntu-24.04-arm]
8989
compiler: [gcc, clang, clang-20, clang-21]
9090
config: [Release, Debug]
91-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-ubuntu.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
91+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-ubuntu.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
9292
with:
9393
runs-on: ${{ matrix.runs-on }}
9494
compiler: ${{ matrix.compiler }}
@@ -105,7 +105,7 @@ jobs:
105105
runs-on: [macos-14, macos-15, macos-15-intel]
106106
compiler: [clang, clang-20, clang-21, gcc-14, gcc-15]
107107
config: [Release, Debug]
108-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-macos.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
108+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-macos.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
109109
with:
110110
runs-on: ${{ matrix.runs-on }}
111111
compiler: ${{ matrix.compiler }}
@@ -123,7 +123,7 @@ jobs:
123123
runs-on: [windows-2022, windows-2025, windows-11-arm]
124124
compiler: [msvc, clang]
125125
config: [Release]
126-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-windows.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
126+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-tests-windows.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
127127
with:
128128
runs-on: ${{ matrix.runs-on }}
129129
compiler: ${{ matrix.compiler }}
@@ -133,7 +133,7 @@ jobs:
133133
name: 🇨‌ Coverage
134134
needs: change-detection
135135
if: fromJSON(needs.change-detection.outputs.run-cpp-tests)
136-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-coverage.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
136+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-coverage.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
137137
permissions:
138138
contents: read
139139
id-token: write
@@ -142,14 +142,14 @@ jobs:
142142
name: 🇨‌ Lint
143143
needs: change-detection
144144
if: fromJSON(needs.change-detection.outputs.run-cpp-linter)
145-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-linter.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
145+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-cpp-linter.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
146146
with:
147147
cmake-args: -DBUILD_MQT_CORE_BENCHMARKS=ON -DBUILD_MQT_CORE_MLIR=ON -DBUILD_MQT_CORE_BINDINGS=ON
148148
clang-version: 21
149149
build-project: true
150150
files-changed-only: true
151151
setup-python: true
152-
install-pkgs: "pybind11==3.0.1"
152+
install-pkgs: "nanobind==2.10.2"
153153
cpp-linter-extra-args: "-std=c++20"
154154
setup-mlir: true
155155

@@ -168,15 +168,15 @@ jobs:
168168
macos-14,
169169
windows-2022,
170170
]
171-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-tests.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
171+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-tests.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
172172
with:
173173
runs-on: ${{ matrix.runs-on }}
174174

175175
python-coverage:
176176
name: 🐍 Coverage
177177
needs: [change-detection, python-tests]
178178
if: fromJSON(needs.change-detection.outputs.run-python-tests)
179-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-coverage.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
179+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-coverage.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
180180
permissions:
181181
contents: read
182182
id-token: write
@@ -190,23 +190,24 @@ jobs:
190190
fail-fast: false
191191
matrix:
192192
runs-on: [macos-15, windows-2025]
193-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-tests.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
193+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-tests.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
194194
with:
195195
runs-on: ${{ matrix.runs-on }}
196196

197197
python-linter:
198198
name: 🐍 Lint
199199
needs: change-detection
200200
if: fromJSON(needs.change-detection.outputs.run-python-tests)
201-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-linter.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
201+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-linter.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
202202
with:
203+
check-stubs: true
203204
enable-ty: true
204205

205206
build-sdist:
206207
name: 🚀 CD
207208
needs: change-detection
208209
if: fromJSON(needs.change-detection.outputs.run-cd)
209-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging-sdist.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
210+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging-sdist.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
210211

211212
build-wheel:
212213
name: 🚀 CD
@@ -224,7 +225,7 @@ jobs:
224225
windows-2022,
225226
windows-11-arm,
226227
]
227-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging-wheel-cibuildwheel.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
228+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging-wheel-cibuildwheel.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
228229
with:
229230
runs-on: ${{ matrix.runs-on }}
230231

.github/workflows/upstream.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
runs-on: [ubuntu-24.04, macos-14, windows-2022]
22-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-qiskit-upstream-tests.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
22+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-qiskit-upstream-tests.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
2323
with:
2424
runs-on: ${{ matrix.runs-on }}
2525
setup-z3: true
@@ -28,7 +28,7 @@ jobs:
2828
name: Create issue on failure
2929
needs: qiskit-upstream-tests
3030
if: ${{ always() }}
31-
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-qiskit-upstream-issue.yml@654680ab77b3af8226a9f5cd9acfd157bd106f17 # v1.17.5
31+
uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-qiskit-upstream-issue.yml@2acb39781fa6ca7baa10c2a31a508cb0e2292d9e # v1.17.6
3232
with:
3333
tests-result: ${{ needs.qiskit-upstream-tests.result }}
3434
permissions:

.license-tools-config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
".*\\.tex",
3434
"uv\\.lock",
3535
"py\\.typed",
36-
".*build.*"
36+
".*build.*",
37+
"core_patterns.txt"
3738
]
3839
}

.pre-commit-config.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ repos:
5858
- id: rst-directive-colons
5959
- id: rst-inline-touching-normal
6060

61+
# Check for license headers
62+
- repo: https://github.com/emzeat/mz-lictools
63+
rev: v2.9.0
64+
hooks:
65+
- id: license-tools
66+
6167
# Ensure uv lock file is up-to-date
6268
- repo: https://github.com/astral-sh/uv-pre-commit
6369
rev: 0.9.18
@@ -101,12 +107,6 @@ repos:
101107
- id: blacken-docs
102108
additional_dependencies: [black==25.*]
103109

104-
# Check for license headers
105-
- repo: https://github.com/emzeat/mz-lictools
106-
rev: v2.9.0
107-
hooks:
108-
- id: license-tools
109-
110110
# Clang-format the C++ part of the code base automatically
111111
- repo: https://github.com/pre-commit/mirrors-clang-format
112112
rev: v21.1.8

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ This project adheres to [Semantic Versioning], with the exception that minor rel
2525

2626
### Changed
2727

28+
- ♻️ Migrate Python bindings from `pybind11` to `nanobind` ([#1383]) ([**@denialhaag**], [**@burgholzer**])
29+
- 📦️ Provide Stable ABI wheels for Python 3.12+ ([#1383]) ([**@burgholzer**], [**@denialhaag**])
30+
- 🚚 Create dedicated `mqt.core.na` submodule to closely follow the structure of other submodules ([#1383]) ([**@burgholzer**])
2831
- ✨ Add common definitions and utilities for QDMI ([#1355]) ([**@burgholzer**])
2932
- 🚚 Move `NA` QDMI device in its right place next to other QDMI devices ([#1355]) ([**@burgholzer**])
3033
- ♻️ Allow repeated loading of QDMI device library with potentially different session configurations ([#1355]) ([**@burgholzer**])
@@ -285,6 +288,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool
285288

286289
[#1385]: https://github.com/munich-quantum-toolkit/core/pull/1385
287290
[#1384]: https://github.com/munich-quantum-toolkit/core/pull/1384
291+
[#1383]: https://github.com/munich-quantum-toolkit/core/pull/1383
288292
[#1382]: https://github.com/munich-quantum-toolkit/core/pull/1382
289293
[#1381]: https://github.com/munich-quantum-toolkit/core/pull/1381
290294
[#1378]: https://github.com/munich-quantum-toolkit/core/pull/1378

CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# Licensed under the MIT License
88

99
# set required cmake version
10-
cmake_minimum_required(VERSION 3.24...4.0)
10+
cmake_minimum_required(VERSION 3.24...4.2)
1111

1212
project(
1313
mqt-core
@@ -47,7 +47,8 @@ if(BUILD_MQT_CORE_BINDINGS)
4747
endif()
4848

4949
# top-level call to find Python
50-
find_package(Python 3.10 REQUIRED COMPONENTS Interpreter Development.Module)
50+
find_package(Python 3.10 REQUIRED COMPONENTS Interpreter Development.Module
51+
${SKBUILD_SABI_COMPONENT})
5152
endif()
5253

5354
# check if this is the master project or used via add_subdirectory

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ The project relies on some external dependencies:
107107

108108
- [boost/multiprecision](https://github.com/boostorg/multiprecision): A library for multiprecision arithmetic (used in the ZX package).
109109
- [nlohmann/json](https://github.com/nlohmann/json): A JSON library for modern C++.
110-
- [pybind/pybind11_json](https://github.com/pybind/pybind11_json): A library for using `nlohmann::json` with `pybind11` (only used for creating the Python bindings).
111110
- [google/googletest](https://github.com/google/googletest): A testing framework for C++ (only used in tests).
112111

113112
CMake will automatically look for installed versions of these libraries. If it does not find them, they will be fetched automatically at configure time via the [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module (check out the documentation for more information on how to customize this behavior).

UPGRADING.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,24 @@ In the process, the `mqt-core-dd-compare` entry point as well as the `evaluation
5252
The `eval/dd_evaluation.py` script acts as a drop-in replacement for the previous CLI entry point.
5353
Since the `eval` directory is not part of the Python package, this functionality is only available via source installations or by cloning the repository.
5454

55-
### Removal of Python 3.13t wheels
55+
### Python wheels
5656

57+
This release contains two changes to the distributed wheels.
58+
59+
First, we have removed all wheels for Python 3.13t.
5760
Free-threading Python was introduced as an experimental feature in Python 3.13.
5861
It became stable in Python 3.14.
59-
To conserve space on PyPI and to reduce the CD build times, we have removed all wheels for Python 3.13t from our CI.
60-
We continue to provide wheels for the regular Python versions 3.10 to 3.14, as well as 3.14t.
62+
63+
Second, for Python 3.12+, we are now providing Stable ABI wheels instead of separate version-specific wheels.
64+
This was enabled by migrating our Python bindings from `pybind11` to `nanobind`.
65+
66+
Both of these changes were made in the interest of conserving PyPI space and reducing CI/CD build times.
67+
The full list of wheels now reads:
68+
69+
- 3.10
70+
- 3.11
71+
- 3.12+ Stable ABI
72+
- 3.14t
6173

6274
## [3.3.0]
6375

0 commit comments

Comments
 (0)