Repository navigation
Port the extension from pybind11 to nanobind - #40
Merged
Merged
Conversation
<details><summary>Claude's draft</summary> Rewrite ojph/ojph_bindings.cpp against nanobind, preserving the whole binding surface and semantics. Notable mapping decisions: - nb::ndarray replaces py::array/py::array_t; dlpack strides are in elements, so helpers convert to byte strides once at the boundary, and dtype codes replace buffer-format characters for the signed/unsigned dispatch - Codestream.pull/exchange return nb::rv_policy::reference, which takes over the job of the py::nodelete holder on LineBuf (the codestream owns those buffers) - errors inside nb::gil_scoped_release regions are carried out via an err pointer and raised after the GIL is reacquired, instead of throwing while unlocked - MemInfile.open keeps the backing array alive via nb::keep_alive; MemOutfile.get_data still returns a zero-copy memoryview - the base-class read/write bindings now take a 1-D uint8 array / bytes respectively (the old void* signatures were not callable from Python in any useful way) - free-threaded CPython: nanobind declares Py_MOD_GIL_NOT_USED when compiled with NB_FREE_THREADED, which setup.py defines when sysconfig reports Py_GIL_DISABLED (replaces py::mod_gil_not_used) Build changes: nanobind's support library is compiled into the extension via ojph/nanobind_support.cpp (setuptools has no nanobind CMake integration to lean on); include dirs gain nanobind's include/, its vendored robin_map, and src/ for the amalgamated nb_combined.cpp; NB_COMPACT_ASSERTIONS keeps the cheap internal checks; on Windows NOMINMAX is required because the amalgamated build includes <windows.h> (free-threading support in nb_internals.cpp) ahead of translation units that use std::max. pyproject/CI build requirements swap pybind11 for nanobind >= 2.2. Measured: binding call overhead 238 -> 97 ns (encode-style call), 254 -> 107 ns (decode-style); end-to-end encode/decode unchanged (codec-dominated). 186 tests pass, 3 skipped. Resume this Claude session: ``` cd /home/mark/git/jp2k claude --resume 487c1e20-36f3-416f-8be1-437c25ed67fe ``` </details>
<details><summary>Claude's draft</summary> Stamp the nanobind port section as 0.10.1 (2026-08-08). After this PR merges, tagging 0.10.1 on the merge commit publishes the release. Resume this Claude session: ``` cd /home/mark/git/jp2k claude --resume 487c1e20-36f3-416f-8be1-437c25ed67fe ``` </details>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prepared by Mark Harfouche's Claude bot; Mark Harfouche (@hmaarrfk) reviews via the GitHub interface.
Ports
ojph_bindings.cppfrom pybind11 to nanobind, anticipating a 0.10.1 release. The full binding surface and semantics are preserved.Measured effect: binding-layer call overhead drops ~2.5× (encode-style call 238 → 97 ns, decode-style 254 → 107 ns). End-to-end encode/decode is unchanged — the codec dominates by 3–4 orders of magnitude (rev12 4096²: 5.1 ms encode / 4.3 ms decode, level-2 reads 0.50 ms, all within noise of the pybind11 build). The practical win is staying on the actively developed binding framework; any future fine-grained (per-tile/per-block) APIs would benefit directly.
Key mapping decisions:
nb::ndarrayreplacespy::array; DLPack strides are in elements, so helpers convert to byte strides once at the boundary, and dtype codes replace buffer-format charsCodestream.pull/exchangeuserv_policy::reference, taking over the job of thepy::nodeleteholder (the codestream owns itsline_bufs)gil_scoped_releaseregions are carried out and raised after the GIL is reacquiredMemInfile.openkeeps the backing array alive viakeep_alive;MemOutfile.get_dataremains a zero-copy memoryviewPy_MOD_GIL_NOT_USEDwhen compiled withNB_FREE_THREADED, whichsetup.pydefines when building for a free-threaded interpreter (replacespy::mod_gil_not_used); the dedicated free-threading tests cover this in CIojph/nanobind_support.cpp) since there is no setuptools integration; build requirements swappybind11fornanobind >= 2.2Verified locally: 186 tests pass (3 skipped) on Linux/py3.12 against the statically linked fork.
https://claude.ai/code/session_015rdawfurPCmefzjoeFfuC4