-
-
Notifications
You must be signed in to change notification settings - Fork 3
♻️ Replace pybind11 with nanobind
#248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
📝 WalkthroughSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughMigrate Python bindings and build tooling from pybind11 to nanobind: update CMake and dependency discovery, convert binding sources and module init to nanobind, rename some exposed attributes (e.g., Changes
Sequence Diagram(s)(Skipped.) Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
bindings/InterfaceBindings.cpp (1)
841-878: Pre-existing memory management pattern - consider RAII wrapper.The manual
malloc/freepattern works but could leak if an exception occurs before the cleanup loop. This is pre-existing code, but for future improvement consider usingstd::unique_ptrwith a custom deleter orstd::vector<std::vector<char>>for exception safety.
🤖 Fix all issues with AI agents
In `@bindings/InterfaceBindings.cpp`:
- Around line 647-649: The docstring assigned to SimulationState in
InterfaceBindings.cpp contains an extra leading double-quote at the start of the
second line; edit the .doc() string for SimulationState to remove that stray `"`
so the multi-line C++ raw string becomes: a single coherent paragraph without
the errant quote, ensuring the opening/closing quotes and parentheses for R"(
... )" remain balanced and the text reads: Represenets the state... and then the
following sentence without the leading `"`.
In `@noxfile.py`:
- Around line 242-254: The code assumes pyi_files contains items; if
nanobind.stubgen produced none you will call session.run with no files which is
confusing—add an explicit check on pyi_files before running prek: if pyi_files
is empty, log a clear message and abort or skip the task (e.g., use
session.error(...) or session.skip(...)) and return early, otherwise proceed to
call session.run("prek", ...) for license-tools, ruff-check, ruff-format and the
final ruff-check; reference the pyi_files variable and the session.run("prek",
...) invocations when adding the guard.
In `@python/mqt/debugger/pydebugger.pyi`:
- Around line 302-306: The SimulationState class docstring in the generated stub
contains an extra leading quote; fix the source C++ binding where the
SimulationState docstring is set (the py::class_<SimulationState> / doc string
assignment in the binding that generates stubs) by removing the stray leading
double-quote so the string begins correctly, then regenerate the nanobind stubs
so the corrected docstring appears in python/mqt/debugger/pydebugger.pyi.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (17)
.github/workflows/ci.ymlCMakeLists.txtbindings/CMakeLists.txtbindings/InterfaceBindings.cppbindings/bindings.cppbindings/dd/DDSimDebugBindings.cppbindings/debugger_patterns.txtcmake/ExternalDependencies.cmakeinclude/python/InterfaceBindings.hppinclude/python/dd/DDSimDebugBindings.hppnoxfile.pypyproject.tomlpython/mqt/debugger/dap/dap_server.pypython/mqt/debugger/dap/messages/change_bit_dap_message.pypython/mqt/debugger/pydebugger.pyitest/python/test_diagnosis.pytest/python/test_python_bindings.py
💤 Files with no reviewable changes (2)
- include/python/InterfaceBindings.hpp
- include/python/dd/DDSimDebugBindings.hpp
🧰 Additional context used
🧠 Learnings (22)
📓 Common learnings
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/dd/register_matrix_dds.cpp:64-109
Timestamp: 2025-12-15T01:54:22.129Z
Learning: In the munich-quantum-toolkit/core repository, after migrating to nanobind, docstrings for Python bindings are now added directly in the C++ binding code (using R"pb(...)pb" syntax) and stub files (.pyi) are auto-generated using the `bindings/generate-stubs.sh` script. This replaces the previous pybind11 approach where docstrings were manually maintained in stub files.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qcec PR: 817
File: pyproject.toml:81-82
Timestamp: 2026-01-09T17:58:10.350Z
Learning: In the Munich Quantum Toolkit projects using nanobind, setting `wheel.py-api = "cp312"` in `[tool.scikit-build]` enables Stable ABI wheels only for Python 3.12+ (where nanobind supports it), while automatically building regular non-ABI3 wheels for earlier Python versions (3.10, 3.11) and free-threading builds (3.14t). This allows a single configuration to appropriately handle both old and new Python versions without forcing incompatible ABI requirements.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: bindings/fomac/fomac.cpp:227-264
Timestamp: 2025-12-07T01:21:27.544Z
Learning: In the munich-quantum-toolkit/core repository, docstrings for Python bindings are added to the corresponding stub files (.pyi) rather than directly in the pybind11 C++ bindings code. This practice may change if the project adopts nanobind with automatic stub generation.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/ir/register_permutation.cpp:153-171
Timestamp: 2025-12-22T01:25:21.609Z
Learning: In the munich-quantum-toolkit/core repository, when using nanobind iterator factory functions like `make_key_iterator` and `make_iterator`, the unqualified form (without explicit `nb::` prefix) is preferred. The clang-tidy configuration suggests removal of explicit namespace qualification, relying on ADL (Argument-Dependent Lookup) to resolve these functions correctly.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: python/mqt/core/ir/operations.pyi:9-16
Timestamp: 2025-12-15T01:59:17.023Z
Learning: In the munich-quantum-toolkit/core repository, stub files (.pyi) are auto-generated by nanobind's stubgen tool and should not be manually modified for style preferences, as changes would be overwritten during regeneration.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:111-116
Timestamp: 2025-12-19T00:05:54.428Z
Learning: In the munich-quantum-toolkit/core repository after migrating to nanobind, lifetime management differs from pybind11: `nb::keep_alive<nurse, patient>()` does not exist in nanobind. Instead, use `nb::rv_policy::reference_internal` when binding methods that return objects referencing internal state of the parent object (e.g., Session::getDevices returning Device objects that depend on the Session). This tells nanobind to keep the parent alive while children exist.
📚 Learning: 2025-12-15T01:54:22.129Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/dd/register_matrix_dds.cpp:64-109
Timestamp: 2025-12-15T01:54:22.129Z
Learning: In the munich-quantum-toolkit/core repository, after migrating to nanobind, docstrings for Python bindings are now added directly in the C++ binding code (using R"pb(...)pb" syntax) and stub files (.pyi) are auto-generated using the `bindings/generate-stubs.sh` script. This replaces the previous pybind11 approach where docstrings were manually maintained in stub files.
Applied to files:
cmake/ExternalDependencies.cmakebindings/CMakeLists.txttest/python/test_python_bindings.pyCMakeLists.txtnoxfile.py.github/workflows/ci.ymlbindings/dd/DDSimDebugBindings.cppbindings/bindings.cpppyproject.tomlbindings/InterfaceBindings.cpp
📚 Learning: 2026-01-14T14:38:00.745Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/syrec PR: 514
File: cmake/ExternalDependencies.cmake:28-32
Timestamp: 2026-01-14T14:38:00.745Z
Learning: In Munich Quantum Toolkit projects, the standard pattern for Python module CMake discovery (e.g., nanobind, pybind11) uses execute_process with Python -m <module> --cmake_dir without ERROR_QUIET or explicit nanobind_ROOT validation before find_package, as the error messages from find_package failures are considered sufficiently clear.
Applied to files:
cmake/ExternalDependencies.cmakeCMakeLists.txt.github/workflows/ci.yml
📚 Learning: 2025-10-10T08:09:54.528Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1246
File: bindings/CMakeLists.txt:0-0
Timestamp: 2025-10-10T08:09:54.528Z
Learning: In the Munich Quantum Toolkit (MQT) Core project, scikit-build-core is configured with `wheel.install-dir = "mqt/core"` in pyproject.toml, which automatically prefixes all CMake `DESTINATION` paths with `mqt/core/` during wheel installation. Therefore, CMake install destinations are relative to the `mqt/core` package namespace, not `site-packages`.
Applied to files:
cmake/ExternalDependencies.cmakebindings/CMakeLists.txtCMakeLists.txt.github/workflows/ci.ymlpyproject.toml
📚 Learning: 2025-12-05T17:45:37.602Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1360
File: .github/workflows/reusable-mlir-tests.yml:40-43
Timestamp: 2025-12-05T17:45:37.602Z
Learning: In the munich-quantum-toolkit/core repository, patch releases of LLVM dependencies don't require documentation updates, changelog entries, or additional tests beyond what's validated by passing CI checks.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-12-07T01:21:27.544Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: bindings/fomac/fomac.cpp:227-264
Timestamp: 2025-12-07T01:21:27.544Z
Learning: In the munich-quantum-toolkit/core repository, docstrings for Python bindings are added to the corresponding stub files (.pyi) rather than directly in the pybind11 C++ bindings code. This practice may change if the project adopts nanobind with automatic stub generation.
Applied to files:
cmake/ExternalDependencies.cmakebindings/CMakeLists.txtnoxfile.py.github/workflows/ci.ymlbindings/dd/DDSimDebugBindings.cppbindings/bindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2026-01-09T17:58:10.350Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qcec PR: 817
File: pyproject.toml:81-82
Timestamp: 2026-01-09T17:58:10.350Z
Learning: In the Munich Quantum Toolkit projects using nanobind, setting `wheel.py-api = "cp312"` in `[tool.scikit-build]` enables Stable ABI wheels only for Python 3.12+ (where nanobind supports it), while automatically building regular non-ABI3 wheels for earlier Python versions (3.10, 3.11) and free-threading builds (3.14t). This allows a single configuration to appropriately handle both old and new Python versions without forcing incompatible ABI requirements.
Applied to files:
cmake/ExternalDependencies.cmakeCMakeLists.txt.github/workflows/ci.ymlpyproject.toml
📚 Learning: 2025-10-10T08:10:16.394Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1246
File: test/python/na/test_na_fomac.py:35-0
Timestamp: 2025-10-10T08:10:16.394Z
Learning: In the munich-quantum-toolkit/core repository, scikit-build-core is configured with `wheel.install-dir = "mqt/core"` in pyproject.toml, which means CMake `install()` commands with `DESTINATION <path>` install files relative to `mqt/core/` in the wheel, making them accessible via `files("mqt.core").joinpath("<path>")`.
Applied to files:
cmake/ExternalDependencies.cmakebindings/CMakeLists.txtpyproject.toml
📚 Learning: 2025-12-28T17:14:53.890Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1403
File: src/qdmi/na/CMakeLists.txt:31-38
Timestamp: 2025-12-28T17:14:53.890Z
Learning: In the munich-quantum-toolkit/core repository, the NA device generator target (mqt-core-qdmi-na-device-gen) is intentionally propagated to MQT_CORE_TARGETS via list(APPEND) because it's publicly linked to the NA device library (the NA device uses a public function from the generator). The SC device generator is not propagated because it has no such dependency with the SC device library.
Applied to files:
cmake/ExternalDependencies.cmakebindings/CMakeLists.txt
📚 Learning: 2025-11-03T23:09:26.881Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1287
File: test/qdmi/dd/CMakeLists.txt:9-21
Timestamp: 2025-11-03T23:09:26.881Z
Learning: The CMake functions `generate_device_defs_executable` and `generate_prefixed_qdmi_headers` used in QDMI device test CMakeLists.txt files are provided by the external QDMI library (fetched via FetchContent from https://github.com/Munich-Quantum-Software-Stack/qdmi.git), specifically in the cmake/PrefixHandling.cmake module of the QDMI repository.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-12-22T01:25:21.609Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/ir/register_permutation.cpp:153-171
Timestamp: 2025-12-22T01:25:21.609Z
Learning: In the munich-quantum-toolkit/core repository, when using nanobind iterator factory functions like `make_key_iterator` and `make_iterator`, the unqualified form (without explicit `nb::` prefix) is preferred. The clang-tidy configuration suggests removal of explicit namespace qualification, relying on ADL (Argument-Dependent Lookup) to resolve these functions correctly.
Applied to files:
bindings/CMakeLists.txtbindings/dd/DDSimDebugBindings.cppbindings/bindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-21T22:35:08.572Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:348-364
Timestamp: 2025-12-21T22:35:08.572Z
Learning: In the munich-quantum-toolkit/core repository's nanobind bindings, use `.sig("...")` on parameter arguments that have vector or container defaults (e.g., `"sites"_a.sig("...") = std::vector<fomac::Session::Device::Site>{}`) to prevent exposing mutable defaults in the Python API, which would be flagged as a code smell by Python linters. This pattern is preferred over removing `.sig("...")` even though it shows `...` in the stub signature.
Applied to files:
bindings/CMakeLists.txtbindings/dd/DDSimDebugBindings.cppbindings/bindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-19T00:05:54.428Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:111-116
Timestamp: 2025-12-19T00:05:54.428Z
Learning: In the munich-quantum-toolkit/core repository after migrating to nanobind, lifetime management differs from pybind11: `nb::keep_alive<nurse, patient>()` does not exist in nanobind. Instead, use `nb::rv_policy::reference_internal` when binding methods that return objects referencing internal state of the parent object (e.g., Session::getDevices returning Device objects that depend on the Session). This tells nanobind to keep the parent alive while children exist.
Applied to files:
bindings/CMakeLists.txtbindings/dd/DDSimDebugBindings.cppbindings/bindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-15T01:59:17.023Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: python/mqt/core/ir/operations.pyi:9-16
Timestamp: 2025-12-15T01:59:17.023Z
Learning: In the munich-quantum-toolkit/core repository, stub files (.pyi) are auto-generated by nanobind's stubgen tool and should not be manually modified for style preferences, as changes would be overwritten during regeneration.
Applied to files:
noxfile.py.github/workflows/ci.ymlbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-14T16:51:52.504Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 23
File: .readthedocs.yaml:13-18
Timestamp: 2025-12-14T16:51:52.504Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, LLVM and MLIR toolchains are required for the documentation build because `uv run` includes a full build of the package, which compiles C++/MLIR extensions using scikit-build-core.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-10-09T13:14:10.178Z
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/ReplaceBasisStateControlsWithIfPattern.cpp:219-221
Timestamp: 2025-10-09T13:14:10.178Z
Learning: The MQT Core project (munich-quantum-toolkit/core repository) uses the C++20 standard, not C++17. C++20 features such as abbreviated function templates (e.g., `const auto&` parameters) are supported and valid in this codebase.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-10-11T13:21:15.212Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/ddsim PR: 674
File: .github/workflows/cd.yml:56-56
Timestamp: 2025-10-11T13:21:15.212Z
Learning: In the ddsim repository, modifying .github/workflows/cd.yml intentionally triggers CD workflow testing in CI through a change-detection mechanism in ci.yml. The change-detection job outputs a run-cd flag that controls whether build-sdist and build-wheel jobs execute in CI, allowing testing of the CD workflow (including wheel building and testing) before actual releases.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-12-02T10:08:36.022Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 1
File: .github/workflows/cd.yml:40-48
Timestamp: 2025-12-02T10:08:36.022Z
Learning: In munich-quantum-toolkit workflows, the reusable-python-packaging-sdist.yml workflow uploads the sdist artifact with the name `cibw-sdist` (or `dev-cibw-sdist` for pull requests), which means it is covered by the `cibw-*` glob pattern when downloading artifacts for deployment.
Applied to files:
.github/workflows/ci.ymlpyproject.toml
📚 Learning: 2025-12-13T20:08:45.549Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 862
File: pyproject.toml:65-66
Timestamp: 2025-12-13T20:08:45.549Z
Learning: In the qmap project (pyproject.toml), maintain broad compatibility with dependencies across supported Python versions. Avoid artificially raising minimum version requirements unless there's a specific need (e.g., to guarantee binary wheel availability for certain Python versions, or to access required features). The goal is to keep the software as broadly compatible as possible with the rest of the ecosystem.
Applied to files:
pyproject.toml
📚 Learning: 2025-12-28T17:13:36.900Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1403
File: pyproject.toml:98-102
Timestamp: 2025-12-28T17:13:36.900Z
Learning: In the munich-quantum-toolkit/core project, scikit-build-core is intelligent enough to skip build targets listed in pyproject.toml that don't exist for a given platform, so platform-specific targets (like `-dyn` targets conditioned on `NOT WIN32`) can be unconditionally listed in `build.targets` without causing Windows build failures.
Applied to files:
pyproject.toml
📚 Learning: 2025-10-11T19:39:32.050Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/debugger PR: 160
File: pyproject.toml:54-54
Timestamp: 2025-10-11T19:39:32.050Z
Learning: Qiskit packages use cp39-abi3 wheels (stable ABI) which are forward-compatible with Python 3.9+ including Python 3.14, even if the package classifiers don't explicitly list Python 3.14 support.
Applied to files:
pyproject.toml
📚 Learning: 2025-10-09T13:13:51.224Z
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/ReplaceBasisStateControlsWithIfPattern.cpp:171-180
Timestamp: 2025-10-09T13:13:51.224Z
Learning: In MQT Core MLIR, UnitaryInterface operations guarantee 1-1 correspondence between input and output qubits in the same order. When cloning or modifying unitary operations (e.g., removing controls), this correspondence is maintained by construction, so yielding getAllInQubits() in else-branches matches the result types from the operation's outputs.
Applied to files:
bindings/InterfaceBindings.cpp
🧬 Code graph analysis (7)
python/mqt/debugger/dap/messages/change_bit_dap_message.py (1)
python/mqt/debugger/pydebugger.pyi (1)
VariableType(157-167)
test/python/test_python_bindings.py (1)
python/mqt/debugger/pydebugger.pyi (6)
get_classical_variable(502-513)type_(40-41)type_(44-44)type_(208-209)type_(212-212)VariableType(157-167)
test/python/test_diagnosis.py (1)
python/mqt/debugger/pydebugger.pyi (7)
type_(40-41)type_(44-44)type_(208-209)type_(212-212)ErrorCauseType(13-27)get_diagnostics(617-622)potential_error_causes(127-135)
python/mqt/debugger/pydebugger.pyi (2)
test/utils/common_fixtures.hpp (4)
instruction(138-145)instruction(138-138)instruction(192-198)instruction(192-192)src/backend/dd/DDSimDebug.cpp (1)
amplitudes(685-685)
bindings/dd/DDSimDebugBindings.cpp (2)
include/backend/dd/DDSimDebug.hpp (1)
destroyDDSimulationState(666-666)src/backend/dd/DDSimDebug.cpp (2)
destroyDDSimulationState(1463-1467)destroyDDSimulationState(1463-1463)
python/mqt/debugger/dap/dap_server.py (1)
python/mqt/debugger/pydebugger.pyi (5)
type_(40-41)type_(44-44)type_(208-209)type_(212-212)ErrorCauseType(13-27)
bindings/InterfaceBindings.cpp (2)
python/mqt/debugger/pydebugger.pyi (6)
real(235-236)real(239-239)imaginary(241-242)imaginary(245-245)amplitudes(269-273)amplitudes(276-276)src/backend/dd/DDSimDebug.cpp (1)
amplitudes(685-685)
🪛 Cppcheck (2.19.0)
bindings/dd/DDSimDebugBindings.cpp
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingIncludeSystem)
[information] 22-22: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingIncludeSystem)
[information] 22-22: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingInclude)
[information] 24-24: Include file
(missingInclude)
[information] 25-25: Include file
(missingInclude)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingInclude)
[style] 27-27: The function 'bindBackend' is never used.
(unusedFunction)
bindings/bindings.cpp
[information] 18-18: Include file
(missingIncludeSystem)
bindings/InterfaceBindings.cpp
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 28-28: Include file
(missingIncludeSystem)
[information] 29-29: Include file
(missingIncludeSystem)
[information] 30-30: Include file
(missingIncludeSystem)
[information] 31-31: Include file
(missingIncludeSystem)
[style] 63-63: The function 'bindFramework' is never used.
(unusedFunction)
[style] 652-652: The function 'bindDiagnostics' is never used.
(unusedFunction)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🇨 Test 🏁 (windows-2022, msvc, Debug) / 🏁 windows-2022 msvc Debug
- GitHub Check: 🇨 Test 🏁 (windows-2022, msvc, Release) / 🏁 windows-2022 msvc Release
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🇨 Test 🍎 (macos-14, clang, Release) / 🍎 macos-14 clang Release
- GitHub Check: 🇨 Test 🏁 (windows-11-arm, msvc, Release) / 🏁 windows-11-arm msvc Release
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04-arm, gcc, Release) / 🐧 ubuntu-24.04-arm gcc Release
- GitHub Check: 🇨 Test 🍎 (macos-15-intel, clang, Release) / 🍎 macos-15-intel clang Release
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04, gcc, Release) / 🐧 ubuntu-24.04 gcc Release
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04, gcc, Debug) / 🐧 ubuntu-24.04 gcc Debug
- GitHub Check: 🇨 Lint / 🚨 Lint
- GitHub Check: 🐍 Lint / 🚨 Lint
🔇 Additional comments (27)
python/mqt/debugger/dap/messages/change_bit_dap_message.py (1)
136-136: LGTM!The attribute rename from
.typeto.type_correctly reflects the nanobind migration. This is a common pattern in nanobind bindings wheretype(a Python built-in) is suffixed with an underscore to avoid naming conflicts. The comparison logic againstVariableType.VarBoolremains correct.bindings/debugger_patterns.txt (1)
1-3: LGTM - Valid nanobind stubgen pattern file.This pattern file correctly defines the
_hashable_values_and_unhashable_values_map_directives used by nanobind's stubgen tool. The empty definitions are appropriate for the default stub generation behavior.python/mqt/debugger/dap/dap_server.py (1)
386-391: LGTM - Correct adaptation to nanobind naming convention.The attribute rename from
typetotype_aligns with nanobind's convention of appending an underscore to avoid shadowing Python builtins. Both branches are consistently updated.noxfile.py (1)
212-240: LGTM - Well-structured stub generation session.The session correctly follows the MQT pattern for nanobind stub generation: build the project, run
nanobind.stubgenwith appropriate flags, then apply license and formatting toolchains. Based on learnings, this aligns with the established approach in the munich-quantum-toolkit repositories..github/workflows/ci.yml (2)
128-129: LGTM - Enables stub verification in CI.Adding
check-stubs: trueensures that auto-generated stub files are verified during linting, catching any drift between the C++ bindings and their Python type stubs.
91-91: LGTM — Correct migration to nanobind in CI.The package installation correctly switches from
pybind11==3.0.1tonanobind==2.10.2for the C++ linter build. nanobind 2.10.2 is the latest stable version and aligns with the project'spyproject.tomlrequirement.cmake/ExternalDependencies.cmake (2)
12-18: LGTM - Standard nanobind discovery pattern.The nanobind CMake discovery correctly follows the established MQT pattern: use
execute_processwithPython -m nanobind --cmake_dirto locate nanobind's CMake configuration, then callfind_package. Based on learnings, the absence ofERROR_QUIETis intentional sincefind_packageerrors are considered sufficiently clear.
22-27: MQT Core 3.4.0 version confirmed. The version is released and the commit hash6bcc01e7d135058c6439c64fdd5f14b65ab88816correctly corresponds to the v3.4.0 tag.bindings/CMakeLists.txt (1)
8-19: LGTM!The migration from
add_mqt_python_bindingtoadd_mqt_python_binding_nanobindis correct for the nanobind transition. Removingpybind11_jsonfromLINK_LIBSis appropriate since nanobind has different JSON handling mechanisms.CMakeLists.txt (1)
45-46: LGTM!The integration of
${SKBUILD_SABI_COMPONENT}into thefind_packagecall correctly enables Stable ABI wheel building. Based on learnings from other MQT projects, this pattern withwheel.py-api = "cp312"in pyproject.toml will build ABI3 wheels for Python 3.12+ while automatically falling back to regular wheels for earlier Python versions.bindings/bindings.cpp (1)
18-32: LGTM!The nanobind migration is correctly implemented:
NB_MODULEmacro properly replacesPYBIND11_MODULE- Forward declarations correctly use
nb::module_&type- The
using namespace nb::literalsenables named argument syntax ("arg"_a)The static analysis hint about missing include is a false positive—nanobind headers are resolved via CMake's nanobind integration.
bindings/dd/DDSimDebugBindings.cpp (1)
27-52: LGTM!The nanobind migration is correctly implemented:
- Function signature properly uses
nb::module_&- The
"state"_anamed argument improves the Python API- Docstrings use the correct raw string literal format for nanobind's auto-generated stubs
The static analysis hint about
bindBackendbeing unused is a false positive—it's called frombindings.cppvia forward declaration.pyproject.toml (5)
9-14: LGTM!Build dependencies correctly updated from pybind11 to nanobind with appropriate minimum version constraint (>=2.10.2).
82-86: LGTM!The Stable ABI configuration is correct. Based on learnings from MQT projects,
wheel.py-api = "cp312"enables ABI3 wheels for Python 3.12+ (where nanobind supports Stable ABI) while automatically building regular wheels for earlier Python versions (3.10, 3.11) and free-threading builds.
240-240: LGTM!Adding
E501(line length) to the.pyifile ignores is appropriate since stub files are auto-generated by nanobind's stubgen tool and may contain long type signatures that shouldn't be manually reformatted. Based on learnings, these stubs should not be manually modified.
308-311: LGTM!The cibuildwheel override correctly integrates
abi3auditto verify Stable ABI compliance:
select = "cp312-*"targets the wheels where ABI3 is enabledinherit.repair-wheel-command = "append"ensures abi3audit runs after platform-specific repairs (e.g., delvewheel on Windows)--strict --reportflags will fail the build if ABI3 violations are detectedThis is a good practice to catch any accidental use of unstable ABI features.
314-319: LGTM!The dependency-groups build section correctly mirrors the build-system requirements with nanobind>=2.10.2.
python/mqt/debugger/pydebugger.pyi (1)
223-233: LGTM - Complex overloads are correctly structured.The two
__init__overloads correctly represent the nanobind binding: a default constructor and one with optionalreal/imaginaryparameters. The docstring appearing on the no-arg overload is a known stubgen artifact.bindings/InterfaceBindings.cpp (6)
63-69: LGTM - VariableType enum binding correctly migrated.The enum binding properly uses
nb::enum_<>withoutexport_values()(which is the nanobind convention), and includes appropriate docstrings.
84-90: LGTM - Variable binding withtype_rename.The
type→type_rename correctly avoids shadowing Python's built-intypefunction, and the pattern is consistently applied across bothVariableandErrorCauseclasses.
93-129: LGTM - Complex class binding is well-structured.The dual constructor pattern with default values and the
__str__/__repr__methods are correctly implemented for nanobind.
282-306: LGTM - Type checking order is correct.The check order (
nb::bool_→nb::int_→nb::float_) is correct. Since Python'sboolis a subclass ofint, checkingboolfirst ensures boolean values are handled correctly.
619-626: LGTM - Correct lifetime management withrv_policy::reference_internal.Using
reference_internalensures theSimulationStateparent stays alive while the returnedDiagnosticsobject exists. This is the correct nanobind pattern for objects referencing internal state. Based on learnings about nanobind lifetime management.
652-672: LGTM - ErrorCauseType and ErrorCause bindings.The enum and class bindings follow the established nanobind patterns, with consistent
type_naming to avoid Python keyword conflict.test/python/test_python_bindings.py (1)
325-327: LGTM - Test updated to use renamedtype_attribute.The test correctly accesses
Variable.type_instead ofVariable.type, consistent with the binding layer changes that rename the attribute to avoid shadowing Python's built-intype.test/python/test_diagnosis.py (2)
70-74: LGTM - Test assertions updated to usetype_attribute.The test correctly accesses
ErrorCause.type_for assertions, consistent with the binding layer changes.
81-84: LGTM - List comprehension filters updated to usetype_attribute.The filter expressions correctly use
x.type_to filterErrorCauseobjects by type, matching the updated binding API.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
python/mqt/debugger/pydebugger.pyi (1)
552-576: Misleading docstrings for state vector getter methods.The docstrings for
get_state_vector_full(lines 555-556) andget_state_vector_sub(lines 565-566) state: "The state vector is expected to be initialized with the correct number of qubits and allocated space for the amplitudes before calling this method."This language describes a pre-condition for an input parameter, but these methods return a
Statevector—they don't take one as input. This appears to be documentation carried over from a C-style API where the caller passes in a pre-allocated buffer.Since stub files are auto-generated, update the docstrings in the C++ bindings to reflect that these methods return a fully-constructed
Statevector.
🤖 Fix all issues with AI agents
In `@bindings/InterfaceBindings.cpp`:
- Around line 93-104: The default constructor declaration nb::init<>() for class
Complex currently includes a docstring that describes parameters that don't
exist; remove the docstring from the nb::init<>() call and ensure the long
parameter docstring remains only on the parameterized constructor
nb::init<double, double>() so that only the constructor that accepts "real" and
"imaginary" exposes those argument docs.
- Line 711: Replace the inconsistent nb::arg("instruction"),
nb::arg("include_callers") usage with the literal-argument syntax used
elsewhere: use "instruction"_a, "include_callers"_a = false so the binding
arguments match the rest of the file; ensure the pybind11 literals are available
(e.g., pybind11::literals namespace or equivalent using directive) where
InterfaceBindings.cpp defines the binding using these parameter names.
In `@python/mqt/debugger/pydebugger.pyi`:
- Around line 223-233: The docstring describing parameters is attached to the
parameterless __init__ overload instead of the (real: float, imaginary: float)
overload; update the C++ nanobind binding so the constructor docstring is bound
to the overload that takes real and imaginary (the __init__ overload with
signature matching real: float = 0.0, imaginary: float = 0.0) — e.g., move or
reassign the documentation call (nb::doc / set_documentation) from the
parameterless ctor binding to the ctor overload with parameters so stubgen emits
the docstring on the correct __init__ overload.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
bindings/InterfaceBindings.cppbindings/dd/DDSimDebugBindings.cpppython/mqt/debugger/pydebugger.pyi
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/dd/register_matrix_dds.cpp:64-109
Timestamp: 2025-12-15T01:54:22.129Z
Learning: In the munich-quantum-toolkit/core repository, after migrating to nanobind, docstrings for Python bindings are now added directly in the C++ binding code (using R"pb(...)pb" syntax) and stub files (.pyi) are auto-generated using the `bindings/generate-stubs.sh` script. This replaces the previous pybind11 approach where docstrings were manually maintained in stub files.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qcec PR: 817
File: pyproject.toml:81-82
Timestamp: 2026-01-09T17:58:10.350Z
Learning: In the Munich Quantum Toolkit projects using nanobind, setting `wheel.py-api = "cp312"` in `[tool.scikit-build]` enables Stable ABI wheels only for Python 3.12+ (where nanobind supports it), while automatically building regular non-ABI3 wheels for earlier Python versions (3.10, 3.11) and free-threading builds (3.14t). This allows a single configuration to appropriately handle both old and new Python versions without forcing incompatible ABI requirements.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/ir/register_permutation.cpp:153-171
Timestamp: 2025-12-22T01:25:21.609Z
Learning: In the munich-quantum-toolkit/core repository, when using nanobind iterator factory functions like `make_key_iterator` and `make_iterator`, the unqualified form (without explicit `nb::` prefix) is preferred. The clang-tidy configuration suggests removal of explicit namespace qualification, relying on ADL (Argument-Dependent Lookup) to resolve these functions correctly.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: bindings/fomac/fomac.cpp:227-264
Timestamp: 2025-12-07T01:21:27.544Z
Learning: In the munich-quantum-toolkit/core repository, docstrings for Python bindings are added to the corresponding stub files (.pyi) rather than directly in the pybind11 C++ bindings code. This practice may change if the project adopts nanobind with automatic stub generation.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:111-116
Timestamp: 2025-12-19T00:05:54.428Z
Learning: In the munich-quantum-toolkit/core repository after migrating to nanobind, lifetime management differs from pybind11: `nb::keep_alive<nurse, patient>()` does not exist in nanobind. Instead, use `nb::rv_policy::reference_internal` when binding methods that return objects referencing internal state of the parent object (e.g., Session::getDevices returning Device objects that depend on the Session). This tells nanobind to keep the parent alive while children exist.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: python/mqt/core/ir/operations.pyi:9-16
Timestamp: 2025-12-15T01:59:17.023Z
Learning: In the munich-quantum-toolkit/core repository, stub files (.pyi) are auto-generated by nanobind's stubgen tool and should not be manually modified for style preferences, as changes would be overwritten during regeneration.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/syrec PR: 514
File: cmake/ExternalDependencies.cmake:28-32
Timestamp: 2026-01-14T14:38:00.745Z
Learning: In Munich Quantum Toolkit projects, the standard pattern for Python module CMake discovery (e.g., nanobind, pybind11) uses execute_process with Python -m <module> --cmake_dir without ERROR_QUIET or explicit nanobind_ROOT validation before find_package, as the error messages from find_package failures are considered sufficiently clear.
📚 Learning: 2025-12-15T01:59:17.023Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: python/mqt/core/ir/operations.pyi:9-16
Timestamp: 2025-12-15T01:59:17.023Z
Learning: In the munich-quantum-toolkit/core repository, stub files (.pyi) are auto-generated by nanobind's stubgen tool and should not be manually modified for style preferences, as changes would be overwritten during regeneration.
Applied to files:
python/mqt/debugger/pydebugger.pyibindings/InterfaceBindings.cpp
📚 Learning: 2025-12-15T01:54:22.129Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/dd/register_matrix_dds.cpp:64-109
Timestamp: 2025-12-15T01:54:22.129Z
Learning: In the munich-quantum-toolkit/core repository, after migrating to nanobind, docstrings for Python bindings are now added directly in the C++ binding code (using R"pb(...)pb" syntax) and stub files (.pyi) are auto-generated using the `bindings/generate-stubs.sh` script. This replaces the previous pybind11 approach where docstrings were manually maintained in stub files.
Applied to files:
python/mqt/debugger/pydebugger.pyibindings/dd/DDSimDebugBindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-07T01:21:27.544Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: bindings/fomac/fomac.cpp:227-264
Timestamp: 2025-12-07T01:21:27.544Z
Learning: In the munich-quantum-toolkit/core repository, docstrings for Python bindings are added to the corresponding stub files (.pyi) rather than directly in the pybind11 C++ bindings code. This practice may change if the project adopts nanobind with automatic stub generation.
Applied to files:
python/mqt/debugger/pydebugger.pyibindings/dd/DDSimDebugBindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-21T22:35:08.572Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:348-364
Timestamp: 2025-12-21T22:35:08.572Z
Learning: In the munich-quantum-toolkit/core repository's nanobind bindings, use `.sig("...")` on parameter arguments that have vector or container defaults (e.g., `"sites"_a.sig("...") = std::vector<fomac::Session::Device::Site>{}`) to prevent exposing mutable defaults in the Python API, which would be flagged as a code smell by Python linters. This pattern is preferred over removing `.sig("...")` even though it shows `...` in the stub signature.
Applied to files:
python/mqt/debugger/pydebugger.pyibindings/dd/DDSimDebugBindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-19T00:05:54.428Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:111-116
Timestamp: 2025-12-19T00:05:54.428Z
Learning: In the munich-quantum-toolkit/core repository after migrating to nanobind, lifetime management differs from pybind11: `nb::keep_alive<nurse, patient>()` does not exist in nanobind. Instead, use `nb::rv_policy::reference_internal` when binding methods that return objects referencing internal state of the parent object (e.g., Session::getDevices returning Device objects that depend on the Session). This tells nanobind to keep the parent alive while children exist.
Applied to files:
bindings/dd/DDSimDebugBindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-22T01:25:21.609Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/ir/register_permutation.cpp:153-171
Timestamp: 2025-12-22T01:25:21.609Z
Learning: In the munich-quantum-toolkit/core repository, when using nanobind iterator factory functions like `make_key_iterator` and `make_iterator`, the unqualified form (without explicit `nb::` prefix) is preferred. The clang-tidy configuration suggests removal of explicit namespace qualification, relying on ADL (Argument-Dependent Lookup) to resolve these functions correctly.
Applied to files:
bindings/InterfaceBindings.cpp
📚 Learning: 2025-10-09T13:13:51.224Z
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/ReplaceBasisStateControlsWithIfPattern.cpp:171-180
Timestamp: 2025-10-09T13:13:51.224Z
Learning: In MQT Core MLIR, UnitaryInterface operations guarantee 1-1 correspondence between input and output qubits in the same order. When cloning or modifying unitary operations (e.g., removing controls), this correspondence is maintained by construction, so yielding getAllInQubits() in else-branches matches the result types from the operation's outputs.
Applied to files:
bindings/InterfaceBindings.cpp
🧬 Code graph analysis (2)
bindings/dd/DDSimDebugBindings.cpp (2)
include/backend/dd/DDSimDebug.hpp (1)
destroyDDSimulationState(666-666)src/backend/dd/DDSimDebug.cpp (2)
destroyDDSimulationState(1463-1467)destroyDDSimulationState(1463-1463)
bindings/InterfaceBindings.cpp (2)
python/mqt/debugger/pydebugger.pyi (12)
init(52-53)init(311-312)name(202-203)name(206-206)value(214-215)value(218-218)amplitudes(269-273)amplitudes(276-276)opt(290-291)opt(294-294)instruction(34-35)instruction(38-38)src/backend/dd/DDSimDebug.cpp (1)
amplitudes(685-685)
🪛 Cppcheck (2.19.0)
bindings/dd/DDSimDebugBindings.cpp
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingIncludeSystem)
[information] 22-22: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingIncludeSystem)
[information] 22-22: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 28-28: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingInclude)
[information] 24-24: Include file
(missingInclude)
[information] 25-25: Include file
(missingInclude)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 28-28: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingInclude)
[style] 28-28: The function 'bindBackend' is never used.
(unusedFunction)
bindings/InterfaceBindings.cpp
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 28-28: Include file
(missingIncludeSystem)
[information] 29-29: Include file
(missingIncludeSystem)
[information] 30-30: Include file
(missingIncludeSystem)
[information] 31-31: Include file
(missingIncludeSystem)
[style] 63-63: The function 'bindFramework' is never used.
(unusedFunction)
[style] 653-653: The function 'bindDiagnostics' is never used.
(unusedFunction)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
- GitHub Check: 🇨 Test 🏁 (windows-2022, msvc, Release) / 🏁 windows-2022 msvc Release
- GitHub Check: 🇨 Test 🏁 (windows-2022, msvc, Debug) / 🏁 windows-2022 msvc Debug
- GitHub Check: 🇨 Test 🍎 (macos-15-intel, clang, Release) / 🍎 macos-15-intel clang Release
- GitHub Check: 🇨 Test 🍎 (macos-14, clang, Debug) / 🍎 macos-14 clang Debug
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🇨 Test 🏁 (windows-11-arm, msvc, Release) / 🏁 windows-11-arm msvc Release
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04, gcc, Debug) / 🐧 ubuntu-24.04 gcc Debug
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04, gcc, Release) / 🐧 ubuntu-24.04 gcc Release
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04-arm, gcc, Release) / 🐧 ubuntu-24.04-arm gcc Release
- GitHub Check: 🐍 Lint / 🚨 Lint
- GitHub Check: 🇨 Lint / 🚨 Lint
🔇 Additional comments (18)
python/mqt/debugger/pydebugger.pyi (9)
9-11: LGTM!Imports are appropriate for the type annotations used throughout the stub file.
13-28: LGTM!The enum is well-documented with clear descriptions for each error cause type.
29-155: LGTM!The
ErrorCauseandDiagnosticsclasses are well-structured with comprehensive docstrings. Thetype_naming convention appropriately avoids collision with Python's built-intype.
157-218: LGTM!The variable representation classes are well-designed. The
VariableValuedocstring clearly explains that only one field is valid at a time based on theVariableType.
259-267: Verify intent:num_statessetter may conflict with documented invariant.The docstring states that
num_statesis "always equal to 2^num_qubits", implying a derived property. However, exposing a setter allows users to set an inconsistent value that violates this invariant.If
num_statesis truly always derived fromnum_qubits, consider making it read-only in the C++ bindings. If the setter is intentional for low-level control, the docstring should clarify this flexibility.
278-300: LGTM!The
CompilationSettingsclass is well-documented with clear parameter descriptions.
302-306: LGTM!The
SimulationStatedocstring is clean. The previously flagged errant quote issue appears to have been resolved.
578-632: LGTM!The breakpoint management, stack trace, diagnostics, and compilation methods are well-documented with clear signatures.
634-646: LGTM!Factory functions are well-documented. The explicit
destroy_ddsim_simulation_statefunction is appropriate for deterministic resource cleanup of the DD backend.bindings/dd/DDSimDebugBindings.cpp (2)
42-52: LGTM!The
destroy_ddsim_simulation_statebinding is correctly migrated to nanobind with proper named argument usage and appropriate lint suppression for the necessaryreinterpret_cast.
29-40: Memory management pattern is intentional—no issue here.The
create_ddsim_simulation_state/destroy_ddsim_simulation_statepairing is an explicit manual memory management API, not a hidden leak risk. All existing usage (tests, DAP handlers, utilities) properly callsdestroy()after use, and this contract is documented in the.pyistub. This pattern is carried over from pybind11 by design and poses no concern for the nanobind migration.bindings/InterfaceBindings.cpp (7)
24-34: LGTM!The nanobind includes and namespace setup follow the standard pattern. The
NOLINT(misc-include-cleaner)annotations are appropriate for the STL type caster headers which are used implicitly.
65-69: LGTM!The
VariableTypeenum binding correctly uses nanobind'snb::enum_withoutexport_values(), which is the preferred pattern for scoped enum access.
85-90: LGTM!The
Variablebinding correctly usestype_to avoid Python'stypebuiltin, anddef_rwis the proper nanobind equivalent of pybind11'sdef_readwrite.
132-160: LGTM!The
StatevectorCPPandCompilationSettingsbindings are correctly migrated with properdef_rwusage and named constructor arguments.
619-649: LGTM!The
get_diagnosticsmethod correctly usesnb::rv_policy::reference_internalfor lifetime management, ensuring theSimulationStatestays alive whileDiagnosticsobjects exist. This aligns with the nanobind migration pattern from the learnings. The docstring issue noted in previous reviews appears to have been resolved.
665-673: LGTM!The
ErrorCausebinding correctly usestype_to avoid Python'stypebuiltin, maintaining consistency with theVariableclass binding pattern.
675-890: LGTM!The
Diagnosticsclass binding is correctly migrated. Thereinterpret_castforbool*conversion is necessary for the C interface and properly suppressed with lint comments. The memory management insuggest_new_assertionscorrectly pairsmallocwithfree.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
burgholzer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks clean and once CI is green, can go in I suppose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
bindings/InterfaceBindings.cpp (1)
833-870: Consider RAII for buffer management.The
suggest_new_assertionsbinding uses manualmalloc/freefor buffer allocation. While functional, usingstd::vector<char>orstd::unique_ptr<char[]>would provide automatic cleanup and eliminate the need for NOLINT suppressions.This is not a nanobind migration issue but an optional improvement opportunity.
♻️ Suggested refactor using std::vector
[](Diagnostics* self) { const size_t stringSize = 2 << 17; const size_t count = self->suggestNewAssertions(self, nullptr, nullptr, 0); std::vector<size_t> positions(count); - std::vector<char*> buffers(count); - for (auto& b : buffers) { - // NOLINTBEGIN(cppcoreguidelines-owning-memory, - // cppcoreguidelines-pro-type-reinterpret-cast, - // cppcoreguidelines-pro-bounds-pointer-arithmetic) - char* buffer = reinterpret_cast<char*>( - malloc(sizeof(char) * stringSize)); // NOLINT - for (size_t i = 0; i < stringSize; i++) { - buffer[i] = '\0'; - } - // NOLINTEND(cppcoreguidelines-owning-memory, - // cppcoreguidelines-pro-type-reinterpret-cast, - // cppcoreguidelines-pro-bounds-pointer-arithmetic) - b = buffer; - } + std::vector<std::vector<char>> bufferStorage(count, std::vector<char>(stringSize, '\0')); + std::vector<char*> buffers(count); + for (size_t i = 0; i < count; ++i) { + buffers[i] = bufferStorage[i].data(); + } self->suggestNewAssertions(self, positions.data(), buffers.data(), count); std::vector<std::string> assertions; - for (auto* b : buffers) { - assertions.emplace_back(b); - free(b); // NOLINT + for (const auto& b : bufferStorage) { + assertions.emplace_back(b.data()); }
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
bindings/InterfaceBindings.cppbindings/dd/DDSimDebugBindings.cpppython/mqt/debugger/pydebugger.pyi
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/dd/register_matrix_dds.cpp:64-109
Timestamp: 2025-12-15T01:54:22.129Z
Learning: In the munich-quantum-toolkit/core repository, after migrating to nanobind, docstrings for Python bindings are now added directly in the C++ binding code (using R"pb(...)pb" syntax) and stub files (.pyi) are auto-generated using the `bindings/generate-stubs.sh` script. This replaces the previous pybind11 approach where docstrings were manually maintained in stub files.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/ir/register_permutation.cpp:153-171
Timestamp: 2025-12-22T01:25:21.609Z
Learning: In the munich-quantum-toolkit/core repository, when using nanobind iterator factory functions like `make_key_iterator` and `make_iterator`, the unqualified form (without explicit `nb::` prefix) is preferred. The clang-tidy configuration suggests removal of explicit namespace qualification, relying on ADL (Argument-Dependent Lookup) to resolve these functions correctly.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qcec PR: 817
File: pyproject.toml:81-82
Timestamp: 2026-01-09T17:58:10.350Z
Learning: In the Munich Quantum Toolkit projects using nanobind, setting `wheel.py-api = "cp312"` in `[tool.scikit-build]` enables Stable ABI wheels only for Python 3.12+ (where nanobind supports it), while automatically building regular non-ABI3 wheels for earlier Python versions (3.10, 3.11) and free-threading builds (3.14t). This allows a single configuration to appropriately handle both old and new Python versions without forcing incompatible ABI requirements.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: bindings/fomac/fomac.cpp:227-264
Timestamp: 2025-12-07T01:21:27.544Z
Learning: In the munich-quantum-toolkit/core repository, docstrings for Python bindings are added to the corresponding stub files (.pyi) rather than directly in the pybind11 C++ bindings code. This practice may change if the project adopts nanobind with automatic stub generation.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:111-116
Timestamp: 2025-12-19T00:05:54.428Z
Learning: In the munich-quantum-toolkit/core repository after migrating to nanobind, lifetime management differs from pybind11: `nb::keep_alive<nurse, patient>()` does not exist in nanobind. Instead, use `nb::rv_policy::reference_internal` when binding methods that return objects referencing internal state of the parent object (e.g., Session::getDevices returning Device objects that depend on the Session). This tells nanobind to keep the parent alive while children exist.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: python/mqt/core/ir/operations.pyi:9-16
Timestamp: 2025-12-15T01:59:17.023Z
Learning: In the munich-quantum-toolkit/core repository, stub files (.pyi) are auto-generated by nanobind's stubgen tool and should not be manually modified for style preferences, as changes would be overwritten during regeneration.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:348-364
Timestamp: 2025-12-21T22:35:08.572Z
Learning: In the munich-quantum-toolkit/core repository's nanobind bindings, use `.sig("...")` on parameter arguments that have vector or container defaults (e.g., `"sites"_a.sig("...") = std::vector<fomac::Session::Device::Site>{}`) to prevent exposing mutable defaults in the Python API, which would be flagged as a code smell by Python linters. This pattern is preferred over removing `.sig("...")` even though it shows `...` in the stub signature.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/syrec PR: 514
File: cmake/ExternalDependencies.cmake:28-32
Timestamp: 2026-01-14T14:38:00.745Z
Learning: In Munich Quantum Toolkit projects, the standard pattern for Python module CMake discovery (e.g., nanobind, pybind11) uses execute_process with Python -m <module> --cmake_dir without ERROR_QUIET or explicit nanobind_ROOT validation before find_package, as the error messages from find_package failures are considered sufficiently clear.
📚 Learning: 2025-12-15T01:54:22.129Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/dd/register_matrix_dds.cpp:64-109
Timestamp: 2025-12-15T01:54:22.129Z
Learning: In the munich-quantum-toolkit/core repository, after migrating to nanobind, docstrings for Python bindings are now added directly in the C++ binding code (using R"pb(...)pb" syntax) and stub files (.pyi) are auto-generated using the `bindings/generate-stubs.sh` script. This replaces the previous pybind11 approach where docstrings were manually maintained in stub files.
Applied to files:
bindings/dd/DDSimDebugBindings.cpppython/mqt/debugger/pydebugger.pyibindings/InterfaceBindings.cpp
📚 Learning: 2025-12-19T00:05:54.428Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:111-116
Timestamp: 2025-12-19T00:05:54.428Z
Learning: In the munich-quantum-toolkit/core repository after migrating to nanobind, lifetime management differs from pybind11: `nb::keep_alive<nurse, patient>()` does not exist in nanobind. Instead, use `nb::rv_policy::reference_internal` when binding methods that return objects referencing internal state of the parent object (e.g., Session::getDevices returning Device objects that depend on the Session). This tells nanobind to keep the parent alive while children exist.
Applied to files:
bindings/dd/DDSimDebugBindings.cppbindings/InterfaceBindings.cpp
📚 Learning: 2025-12-07T01:21:27.544Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: bindings/fomac/fomac.cpp:227-264
Timestamp: 2025-12-07T01:21:27.544Z
Learning: In the munich-quantum-toolkit/core repository, docstrings for Python bindings are added to the corresponding stub files (.pyi) rather than directly in the pybind11 C++ bindings code. This practice may change if the project adopts nanobind with automatic stub generation.
Applied to files:
bindings/dd/DDSimDebugBindings.cpppython/mqt/debugger/pydebugger.pyibindings/InterfaceBindings.cpp
📚 Learning: 2025-12-21T22:35:08.572Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:348-364
Timestamp: 2025-12-21T22:35:08.572Z
Learning: In the munich-quantum-toolkit/core repository's nanobind bindings, use `.sig("...")` on parameter arguments that have vector or container defaults (e.g., `"sites"_a.sig("...") = std::vector<fomac::Session::Device::Site>{}`) to prevent exposing mutable defaults in the Python API, which would be flagged as a code smell by Python linters. This pattern is preferred over removing `.sig("...")` even though it shows `...` in the stub signature.
Applied to files:
bindings/dd/DDSimDebugBindings.cpppython/mqt/debugger/pydebugger.pyibindings/InterfaceBindings.cpp
📚 Learning: 2025-12-15T01:59:17.023Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: python/mqt/core/ir/operations.pyi:9-16
Timestamp: 2025-12-15T01:59:17.023Z
Learning: In the munich-quantum-toolkit/core repository, stub files (.pyi) are auto-generated by nanobind's stubgen tool and should not be manually modified for style preferences, as changes would be overwritten during regeneration.
Applied to files:
python/mqt/debugger/pydebugger.pyibindings/InterfaceBindings.cpp
📚 Learning: 2025-12-22T01:25:21.609Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/ir/register_permutation.cpp:153-171
Timestamp: 2025-12-22T01:25:21.609Z
Learning: In the munich-quantum-toolkit/core repository, when using nanobind iterator factory functions like `make_key_iterator` and `make_iterator`, the unqualified form (without explicit `nb::` prefix) is preferred. The clang-tidy configuration suggests removal of explicit namespace qualification, relying on ADL (Argument-Dependent Lookup) to resolve these functions correctly.
Applied to files:
bindings/InterfaceBindings.cpp
📚 Learning: 2025-10-09T13:13:51.224Z
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/ReplaceBasisStateControlsWithIfPattern.cpp:171-180
Timestamp: 2025-10-09T13:13:51.224Z
Learning: In MQT Core MLIR, UnitaryInterface operations guarantee 1-1 correspondence between input and output qubits in the same order. When cloning or modifying unitary operations (e.g., removing controls), this correspondence is maintained by construction, so yielding getAllInQubits() in else-branches matches the result types from the operation's outputs.
Applied to files:
bindings/InterfaceBindings.cpp
🧬 Code graph analysis (2)
bindings/dd/DDSimDebugBindings.cpp (1)
src/backend/dd/DDSimDebug.cpp (2)
destroyDDSimulationState(1463-1467)destroyDDSimulationState(1463-1463)
bindings/InterfaceBindings.cpp (2)
python/mqt/debugger/pydebugger.pyi (14)
init(52-53)init(313-314)name(202-203)name(206-206)value(214-215)value(218-218)real(237-238)real(241-241)amplitudes(271-275)amplitudes(278-278)opt(292-293)opt(296-296)instruction(34-35)instruction(38-38)src/backend/dd/DDSimDebug.cpp (1)
amplitudes(685-685)
🪛 Cppcheck (2.19.0)
bindings/dd/DDSimDebugBindings.cpp
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingIncludeSystem)
[information] 22-22: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingIncludeSystem)
[information] 22-22: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 28-28: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 23-23: Include file
(missingInclude)
[information] 24-24: Include file
(missingInclude)
[information] 25-25: Include file
(missingInclude)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 28-28: Include file
(missingIncludeSystem)
[information] 21-21: Include file
(missingInclude)
[style] 28-28: The function 'bindBackend' is never used.
(unusedFunction)
bindings/InterfaceBindings.cpp
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 24-24: Include file
(missingIncludeSystem)
[information] 25-25: Include file
(missingIncludeSystem)
[information] 26-26: Include file
(missingIncludeSystem)
[information] 27-27: Include file
(missingIncludeSystem)
[information] 28-28: Include file
(missingIncludeSystem)
[information] 29-29: Include file
(missingIncludeSystem)
[information] 30-30: Include file
(missingIncludeSystem)
[information] 31-31: Include file
(missingIncludeSystem)
[style] 64-64: The function 'bindFramework' is never used.
(unusedFunction)
[style] 644-644: The function 'bindDiagnostics' is never used.
(unusedFunction)
[error] 702-702: Boolean value assigned to pointer.
(assignBoolToPointer)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04, gcc, Debug) / 🐧 ubuntu-24.04 gcc Debug
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04-arm, gcc, Release) / 🐧 ubuntu-24.04-arm gcc Release
- GitHub Check: 🇨 Test 🐧 (ubuntu-24.04, gcc, Release) / 🐧 ubuntu-24.04 gcc Release
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🇨 Lint / 🚨 Lint
- GitHub Check: 🐍 Lint / 🚨 Lint
🔇 Additional comments (15)
bindings/dd/DDSimDebugBindings.cpp (3)
19-28: LGTM! Clean migration to nanobind.The namespace alias, literals usage, and function signature update follow the standard nanobind migration pattern used in other MQT projects.
29-40: LGTM!The simulation state creation binding is correctly migrated. The manual memory management pattern with explicit create/destroy functions is appropriate for this C-style API.
42-52: LGTM!The addition of
"state"_anamed argument improves the Python API. Thereinterpret_castis correctly suppressed with NOLINTNEXTLINE given the C-style interface design.python/mqt/debugger/pydebugger.pyi (5)
1-12: LGTM!The stub file header and imports are correctly structured for the auto-generated nanobind stubs.
13-45: LGTM!The
ErrorCauseTypeenum andErrorCauseclass are correctly generated with proper docstrings and thetype_naming convention to avoid Python keyword conflict.
220-247: LGTM!The
Complexclass overloaded constructors are correctly documented after the previous fix. The parameterless constructor has a simple docstring, while the parameterized one includes theArgsdocumentation.
304-308: LGTM!The
SimulationStateclass docstring is now clean after the previous fix. The class exposes a comprehensive debugging API with proper type annotations.
630-641: LGTM!The factory functions are correctly typed and documented, matching the bindings in
DDSimDebugBindings.cpp.bindings/InterfaceBindings.cpp (7)
21-34: LGTM!The nanobind includes and namespace setup follow the standard pattern. The NOLINT comments on STL includes are appropriate as these are required for type conversions but may trigger include-cleaner warnings.
85-91: LGTM!The
Variablebinding correctly mapstype_to&Variable::type, following the convention to avoid Python keyword conflicts.
93-126: LGTM!The
Complexclass binding is correctly structured with two constructor overloads and proper docstrings after the previous fix.
128-141: LGTM!The
StatevectorCPPwrapper is correctly bound asStatevectorin Python, making the state vector accessible with proper properties.
610-617: LGTM!The
get_diagnosticsbinding correctly usesnb::rv_policy::reference_internalto ensure theSimulationStatestays alive while the returnedDiagnosticsobject exists. Based on learnings, this is the proper nanobind pattern for lifetime management.
700-702: LGTM - static analysis false positive.The Cppcheck warning "Boolean value assigned to pointer" at line 702 is a false positive. The code
"include_callers"_a = falseis valid nanobind syntax for setting a default parameter value, not a pointer assignment.
656-664: LGTM!The
ErrorCausebinding correctly usestype_to map to&ErrorCause::type, consistent with theVariablebinding pattern.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@noxfile.py`:
- Around line 212-240: The stubs session calls nanobind.stubgen which imports
mqt.debugger.pydebugger but never builds the extension module first; add a build
invocation before the stubgen run (e.g., call session.run("uv", "build",
"--no-build-isolation-package", "mqt-debugger", env=env) or equivalent) so the
compiled extension exists, then proceed with the existing session.run of "python
-m nanobind.stubgen" in the stubs() function.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
cmake/ExternalDependencies.cmakenoxfile.py
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/dd/register_matrix_dds.cpp:64-109
Timestamp: 2025-12-15T01:54:22.129Z
Learning: In the munich-quantum-toolkit/core repository, after migrating to nanobind, docstrings for Python bindings are now added directly in the C++ binding code (using R"pb(...)pb" syntax) and stub files (.pyi) are auto-generated using the `bindings/generate-stubs.sh` script. This replaces the previous pybind11 approach where docstrings were manually maintained in stub files.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/ir/register_permutation.cpp:153-171
Timestamp: 2025-12-22T01:25:21.609Z
Learning: In the munich-quantum-toolkit/core repository, when using nanobind iterator factory functions like `make_key_iterator` and `make_iterator`, the unqualified form (without explicit `nb::` prefix) is preferred. The clang-tidy configuration suggests removal of explicit namespace qualification, relying on ADL (Argument-Dependent Lookup) to resolve these functions correctly.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: bindings/fomac/fomac.cpp:227-264
Timestamp: 2025-12-07T01:21:27.544Z
Learning: In the munich-quantum-toolkit/core repository, docstrings for Python bindings are added to the corresponding stub files (.pyi) rather than directly in the pybind11 C++ bindings code. This practice may change if the project adopts nanobind with automatic stub generation.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qcec PR: 817
File: pyproject.toml:81-82
Timestamp: 2026-01-09T17:58:10.350Z
Learning: In the Munich Quantum Toolkit projects using nanobind, setting `wheel.py-api = "cp312"` in `[tool.scikit-build]` enables Stable ABI wheels only for Python 3.12+ (where nanobind supports it), while automatically building regular non-ABI3 wheels for earlier Python versions (3.10, 3.11) and free-threading builds (3.14t). This allows a single configuration to appropriately handle both old and new Python versions without forcing incompatible ABI requirements.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/fomac/fomac.cpp:111-116
Timestamp: 2025-12-19T00:05:54.428Z
Learning: In the munich-quantum-toolkit/core repository after migrating to nanobind, lifetime management differs from pybind11: `nb::keep_alive<nurse, patient>()` does not exist in nanobind. Instead, use `nb::rv_policy::reference_internal` when binding methods that return objects referencing internal state of the parent object (e.g., Session::getDevices returning Device objects that depend on the Session). This tells nanobind to keep the parent alive while children exist.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/syrec PR: 514
File: cmake/ExternalDependencies.cmake:28-32
Timestamp: 2026-01-14T14:38:00.745Z
Learning: In Munich Quantum Toolkit projects, the standard pattern for Python module CMake discovery (e.g., nanobind, pybind11) uses execute_process with Python -m <module> --cmake_dir without ERROR_QUIET or explicit nanobind_ROOT validation before find_package, as the error messages from find_package failures are considered sufficiently clear.
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: python/mqt/core/ir/operations.pyi:9-16
Timestamp: 2025-12-15T01:59:17.023Z
Learning: In the munich-quantum-toolkit/core repository, stub files (.pyi) are auto-generated by nanobind's stubgen tool and should not be manually modified for style preferences, as changes would be overwritten during regeneration.
📚 Learning: 2025-12-15T01:59:17.023Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: python/mqt/core/ir/operations.pyi:9-16
Timestamp: 2025-12-15T01:59:17.023Z
Learning: In the munich-quantum-toolkit/core repository, stub files (.pyi) are auto-generated by nanobind's stubgen tool and should not be manually modified for style preferences, as changes would be overwritten during regeneration.
Applied to files:
noxfile.py
📚 Learning: 2025-12-15T01:54:22.129Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1383
File: bindings/dd/register_matrix_dds.cpp:64-109
Timestamp: 2025-12-15T01:54:22.129Z
Learning: In the munich-quantum-toolkit/core repository, after migrating to nanobind, docstrings for Python bindings are now added directly in the C++ binding code (using R"pb(...)pb" syntax) and stub files (.pyi) are auto-generated using the `bindings/generate-stubs.sh` script. This replaces the previous pybind11 approach where docstrings were manually maintained in stub files.
Applied to files:
noxfile.pycmake/ExternalDependencies.cmake
📚 Learning: 2025-12-07T01:21:27.544Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: bindings/fomac/fomac.cpp:227-264
Timestamp: 2025-12-07T01:21:27.544Z
Learning: In the munich-quantum-toolkit/core repository, docstrings for Python bindings are added to the corresponding stub files (.pyi) rather than directly in the pybind11 C++ bindings code. This practice may change if the project adopts nanobind with automatic stub generation.
Applied to files:
noxfile.py
📚 Learning: 2026-01-14T14:38:00.745Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/syrec PR: 514
File: cmake/ExternalDependencies.cmake:28-32
Timestamp: 2026-01-14T14:38:00.745Z
Learning: In Munich Quantum Toolkit projects, the standard pattern for Python module CMake discovery (e.g., nanobind, pybind11) uses execute_process with Python -m <module> --cmake_dir without ERROR_QUIET or explicit nanobind_ROOT validation before find_package, as the error messages from find_package failures are considered sufficiently clear.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-11-03T23:09:26.881Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1287
File: test/qdmi/dd/CMakeLists.txt:9-21
Timestamp: 2025-11-03T23:09:26.881Z
Learning: The CMake functions `generate_device_defs_executable` and `generate_prefixed_qdmi_headers` used in QDMI device test CMakeLists.txt files are provided by the external QDMI library (fetched via FetchContent from https://github.com/Munich-Quantum-Software-Stack/qdmi.git), specifically in the cmake/PrefixHandling.cmake module of the QDMI repository.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-10-10T08:09:54.528Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1246
File: bindings/CMakeLists.txt:0-0
Timestamp: 2025-10-10T08:09:54.528Z
Learning: In the Munich Quantum Toolkit (MQT) Core project, scikit-build-core is configured with `wheel.install-dir = "mqt/core"` in pyproject.toml, which automatically prefixes all CMake `DESTINATION` paths with `mqt/core/` during wheel installation. Therefore, CMake install destinations are relative to the `mqt/core` package namespace, not `site-packages`.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-12-05T17:45:37.602Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1360
File: .github/workflows/reusable-mlir-tests.yml:40-43
Timestamp: 2025-12-05T17:45:37.602Z
Learning: In the munich-quantum-toolkit/core repository, patch releases of LLVM dependencies don't require documentation updates, changelog entries, or additional tests beyond what's validated by passing CI checks.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-12-05T15:57:39.701Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 3
File: lib/Conversion/CatalystQuantumToMQTOpt/CMakeLists.txt:22-25
Timestamp: 2025-12-05T15:57:39.701Z
Learning: The munich-quantum-toolkit projects (core and core-plugins-catalyst) use `file(GLOB_RECURSE ...)` patterns in CMakeLists.txt files to collect header files, following an established convention in the parent repository for consistency across the codebase.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2026-01-04T23:54:33.540Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1356
File: src/qdmi/na/CMakeLists.txt:179-184
Timestamp: 2026-01-04T23:54:33.540Z
Learning: In the munich-quantum-toolkit/core repository, MSVC link-time code generation (LTCG) must be disabled for the NA device dynamic library target (mqt-core-qdmi-na-device-dyn) on Windows to avoid link errors and missing symbols. This issue affects both release-only builds and debug/release mixed builds, not just debug/release mixing scenarios.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-12-28T17:14:53.890Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1403
File: src/qdmi/na/CMakeLists.txt:31-38
Timestamp: 2025-12-28T17:14:53.890Z
Learning: In the munich-quantum-toolkit/core repository, the NA device generator target (mqt-core-qdmi-na-device-gen) is intentionally propagated to MQT_CORE_TARGETS via list(APPEND) because it's publicly linked to the NA device library (the NA device uses a public function from the generator). The SC device generator is not propagated because it has no such dependency with the SC device library.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-10-10T08:10:16.394Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1246
File: test/python/na/test_na_fomac.py:35-0
Timestamp: 2025-10-10T08:10:16.394Z
Learning: In the munich-quantum-toolkit/core repository, scikit-build-core is configured with `wheel.install-dir = "mqt/core"` in pyproject.toml, which means CMake `install()` commands with `DESTINATION <path>` install files relative to `mqt/core/` in the wheel, making them accessible via `files("mqt.core").joinpath("<path>")`.
Applied to files:
cmake/ExternalDependencies.cmake
📚 Learning: 2025-10-09T13:14:10.178Z
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/ReplaceBasisStateControlsWithIfPattern.cpp:219-221
Timestamp: 2025-10-09T13:14:10.178Z
Learning: The MQT Core project (munich-quantum-toolkit/core repository) uses the C++20 standard, not C++17. C++20 features such as abbreviated function templates (e.g., `const auto&` parameters) are supported and valid in this codebase.
Applied to files:
cmake/ExternalDependencies.cmake
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: 🇨 Test 🏁 (windows-11-arm, msvc, Release) / 🏁 windows-11-arm msvc Release
🔇 Additional comments (6)
cmake/ExternalDependencies.cmake (4)
12-18: LGTM!The nanobind discovery pattern correctly follows the Munich Quantum Toolkit standard:
execute_processwithPython -m nanobind --cmake_dirwithout explicit validation, relying onfind_packageerror messages for diagnostics. Based on learnings, this is the established pattern.
42-56: LGTM!The Eigen3 fetch configuration is well-structured:
GIT_SHALLOW TRUEfor efficient cloning.- Build flags correctly disable unnecessary Eigen tests and documentation.
BUILD_TESTING=OFFappropriately prevents fetched dependencies from building their own tests, while the project's tests are controlled separately viaBUILD_MQT_DEBUGGER_TESTS.
58-68: LGTM!The Google Test fetch is well-configured:
FIND_PACKAGE_ARGSenables using system-installed GTest when available.gtest_force_shared_crt=ONensures proper Windows CRT linkage.- Clean URL-based fetch pattern.
22-35: LGTM!The version bump to 3.4.0 and simplified unconditional
FetchContent_Declareare clean. The removal ofFIND_PACKAGE_ARGSensures consistent builds by always fetching from source. The commit hash is correctly tagged to v3.4.0.noxfile.py (2)
244-246: LGTM!Good handling of the edge case where no stub files are generated.
248-258: LGTM!The workflow is well-structured: allowing exit code 1 during fix-up passes (license-tools, ruff-check, ruff-format) to accommodate file modifications, followed by a final strict ruff-check to verify everything is clean.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
* Update mqt-core * Replace pybind11 with nanobind * Enable Stable ABI wheels * Auto-generate stub file * Ignore linter errors * Clean up docstrings * Simplify ExternalDependencies.cmake * Improve stubs session
Description
This PR fully replaces
pybind11withnanobind. This change will allow us to ship Stable ABI wheels, saving us PyPI space.Checklist:
I have added appropriate tests that cover the new/changed functionality.