From 83403b9889b181f0cd61a933666018101ef6b455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Je=CC=81re=CC=81mie=20Dumas?= Date: Tue, 18 Aug 2026 10:55:19 -0700 Subject: [PATCH 1/6] Try nanobind 3 split mode --- .github/workflows/wheel.yaml | 1 + cmake/recipes/external/nanobind.cmake | 2 +- .../core/python/include/lagrange/python/utils/StubType.h | 2 +- .../include/lagrange/python/utils/bind_safe_vector.h | 9 ++++++--- modules/core/python/src/logging.cpp | 4 ++-- modules/python/CMakeLists.txt | 3 +-- modules/scene/python/src/bind_value.h | 6 +++--- pyproject.toml | 5 ++++- 8 files changed, 19 insertions(+), 13 deletions(-) diff --git a/.github/workflows/wheel.yaml b/.github/workflows/wheel.yaml index abf00595..3aa2e26e 100644 --- a/.github/workflows/wheel.yaml +++ b/.github/workflows/wheel.yaml @@ -47,6 +47,7 @@ jobs: - name: Build wheels uses: pypa/cibuildwheel@v3.4.1 env: + CIBW_BUILD: "cp310-*" CIBW_BUILD_FRONTEND: "build[uv]" CIBW_ARCHS_LINUX: auto64 CIBW_ARCHS_WINDOWS: auto64 diff --git a/cmake/recipes/external/nanobind.cmake b/cmake/recipes/external/nanobind.cmake index fbb2207e..1a328bf8 100644 --- a/cmake/recipes/external/nanobind.cmake +++ b/cmake/recipes/external/nanobind.cmake @@ -19,7 +19,7 @@ include(CPM) CPMAddPackage( NAME nanobind GITHUB_REPOSITORY wjakob/nanobind - GIT_TAG v2.13.0 + GIT_TAG v3.0.0-dev1 DOWNLOAD_ONLY ON ) diff --git a/modules/core/python/include/lagrange/python/utils/StubType.h b/modules/core/python/include/lagrange/python/utils/StubType.h index a1a210e5..c9f70393 100644 --- a/modules/core/python/include/lagrange/python/utils/StubType.h +++ b/modules/core/python/include/lagrange/python/utils/StubType.h @@ -55,7 +55,7 @@ struct type_caster> NB_TYPE_CASTER(Wrapper, const_name(Hint::value)) - bool from_python(handle src, uint8_t flags, cleanup_list* cleanup) noexcept + bool from_python(handle src, uint32_t flags, cleanup_list* cleanup) noexcept { TCaster caster; if (!caster.from_python(src, flags, cleanup)) return false; diff --git a/modules/core/python/include/lagrange/python/utils/bind_safe_vector.h b/modules/core/python/include/lagrange/python/utils/bind_safe_vector.h index bd3ba5b7..6268ada3 100644 --- a/modules/core/python/include/lagrange/python/utils/bind_safe_vector.h +++ b/modules/core/python/include/lagrange/python/utils/bind_safe_vector.h @@ -29,7 +29,10 @@ NAMESPACE_BEGIN(NB_NAMESPACE) -template +template < + typename Vector, + rv_policy::value Policy = rv_policy::automatic_reference_v, + typename... Args> class_ bind_safe_vector(handle scope, const char* name, Args&&... args) { using ValueRef = typename detail::iterator_access::result_type; @@ -43,7 +46,7 @@ class_ bind_safe_vector(handle scope, const char* name, Args&&... args) static_assert( !detail::is_base_caster_v> || detail::is_copy_constructible_v || - (Policy != rv_policy::automatic_reference && Policy != rv_policy::copy), + (Policy != rv_policy::automatic_reference_v && Policy != rv_policy::copy_v), "bind_safe_vector(): the generated __getitem__ would copy elements, so the " "element type must be copy-constructible"); @@ -83,7 +86,7 @@ class_ bind_safe_vector(handle scope, const char* name, Args&&... args) [](Vector& v, Py_ssize_t i) -> ValueRef { return v.Vector::Super::operator[](detail::wrap(i, v.size())); }, - Policy) + rv_policy::policy_tag{}) .def("clear", [](Vector& v) { v.clear(); }, "Remove all items from list."); diff --git a/modules/core/python/src/logging.cpp b/modules/core/python/src/logging.cpp index 4de5cb50..5e3ee5fc 100644 --- a/modules/core/python/src/logging.cpp +++ b/modules/core/python/src/logging.cpp @@ -42,7 +42,7 @@ class PythonLoggingSink : public spdlog::sinks::base_sink void sink_it_(const spdlog::details::log_msg& msg) override { // Logging in python requires the current thread to hold the GIL. - if (!PyGILState_Check()) return; + if (!NB_CALL(gil_check)()) return; auto payload = msg.payload; auto res = nb::str(payload.data(), payload.size()); @@ -62,7 +62,7 @@ class PythonLoggingSink : public spdlog::sinks::base_sink void flush_() override { // Logging in python requires the current thread to hold the GIL. - if (!PyGILState_Check()) return; + if (!NB_CALL(gil_check)()) return; auto handlers = m_py_logger.attr("handlers"); for (auto handler : handlers) { diff --git a/modules/python/CMakeLists.txt b/modules/python/CMakeLists.txt index 501bb9dc..6861c4d9 100644 --- a/modules/python/CMakeLists.txt +++ b/modules/python/CMakeLists.txt @@ -22,8 +22,7 @@ endif() # 1. define module include(nanobind) lagrange_find_package(TBB CONFIG REQUIRED) -nanobind_add_module(lagrange_python NB_STATIC) -set_target_properties(nanobind-static PROPERTIES FOLDER third_party) +nanobind_add_module(lagrange_python BACKEND_MODULE nanobind_backend) add_library(lagrange::python ALIAS lagrange_python) set_target_properties(lagrange_python PROPERTIES FOLDER "${LAGRANGE_IDE_PREFIX}Lagrange/Modules" diff --git a/modules/scene/python/src/bind_value.h b/modules/scene/python/src/bind_value.h index 900d30ad..455d1364 100644 --- a/modules/scene/python/src/bind_value.h +++ b/modules/scene/python/src/bind_value.h @@ -24,7 +24,7 @@ struct type_caster NB_TYPE_CASTER(lagrange::scene::Value, const_name("int | float | str | list | dict | bool")); template - bool try_cast(const handle& src, uint8_t flags, cleanup_list* cleanup) + bool try_cast(const handle& src, uint32_t flags, cleanup_list* cleanup) { using CasterT = make_caster; @@ -34,7 +34,7 @@ struct type_caster return true; } - bool from_python(handle src, uint8_t flags, cleanup_list* cleanup) noexcept + bool from_python(handle src, uint32_t flags, cleanup_list* cleanup) noexcept { if (PyNumber_Check(src.ptr())) { lagrange::logger().debug("Number!"); @@ -48,7 +48,7 @@ struct type_caster size_t n; PyObject* temp; /* Will initialize 'temp' (NULL in the case of a failure.) */ - PyObject** o = seq_get(src.ptr(), &n, &temp); + PyObject** o = NB_CALL(seq_get)(src.ptr(), &n, &temp); bool success = o != nullptr; diff --git a/pyproject.toml b/pyproject.toml index 47e33f43..39f06365 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,8 @@ [build-system] build-backend = "scikit_build_core.build" requires = [ - "numpy>=1.25", # needed at build time for default dtype args + "nanobind-backend>=1.0.0.dev1", # needed at build time for stub generation + "numpy>=1.25", # needed at build time for default dtype args "scikit-build-core==0.11.6", "typing-extensions~=4.1", ] @@ -30,6 +31,7 @@ dynamic = [ "version" ] dependencies = [ "colorama>=0.4.4; platform_system!='Windows'", "colorama>=0.4.6; platform_system=='Windows'", + "nanobind-backend>=1.0.0.dev1", "numpy>=1.25", "scipy>=1.13.0", ] @@ -70,6 +72,7 @@ ninja.version = ">=1.11.1" ninja.make-fallback = false install.components = [ "Lagrange_Python_Runtime" ] wheel.packages = [ "modules/python/lagrange" ] +wheel.py-api = "cp310" build-dir = "build-python" editable.rebuild = false metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" From 6842ba199f753037a6d7eb1f129962d4b62e4ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Je=CC=81re=CC=81mie=20Dumas?= Date: Wed, 19 Aug 2026 09:17:14 -0700 Subject: [PATCH 2/6] Fix split-mode Python discovery on Windows --- CMakeLists.txt | 2 +- cmake/recipes/external/nanobind.cmake | 2 +- cmake/recipes/external/python.cmake | 8 ++++++-- pyproject.toml | 6 +++--- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a1faa68..56321d21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ else() endif() # Check required CMake version -cmake_minimum_required(VERSION 3.25.0) +cmake_minimum_required(VERSION 3.26.0) cmake_policy(SET CMP0054 NEW) # Only interpret if() arguments as variables or keywords when unquoted. cmake_policy(SET CMP0076 NEW) # target_sources() command converts relative paths to absolute. diff --git a/cmake/recipes/external/nanobind.cmake b/cmake/recipes/external/nanobind.cmake index 1a328bf8..1f907bf5 100644 --- a/cmake/recipes/external/nanobind.cmake +++ b/cmake/recipes/external/nanobind.cmake @@ -19,7 +19,7 @@ include(CPM) CPMAddPackage( NAME nanobind GITHUB_REPOSITORY wjakob/nanobind - GIT_TAG v3.0.0-dev1 + GIT_TAG v3.0.0-dev2 DOWNLOAD_ONLY ON ) diff --git a/cmake/recipes/external/python.cmake b/cmake/recipes/external/python.cmake index 919c4bc6..cd8b7b99 100644 --- a/cmake/recipes/external/python.cmake +++ b/cmake/recipes/external/python.cmake @@ -9,9 +9,13 @@ # OF ANY KIND, either express or implied. See the License for the specific language # governing permissions and limitations under the License. # -if(TARGET Python::Module) +if(TARGET Python::Module AND TARGET Python::SABIModule) return() endif() set(Python_FIND_VIRTUALENV FIRST) -find_package(Python 3.9 COMPONENTS Interpreter Development.Module REQUIRED) +find_package( + Python 3.10 + COMPONENTS Interpreter Development.Module Development.SABIModule + REQUIRED +) diff --git a/pyproject.toml b/pyproject.toml index 39f06365..8f5b7e5f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,8 @@ [build-system] build-backend = "scikit_build_core.build" requires = [ - "nanobind-backend>=1.0.0.dev1", # needed at build time for stub generation - "numpy>=1.25", # needed at build time for default dtype args + "nanobind-backend==1.0.0.dev2", # must match the nanobind development release + "numpy>=1.25", # needed at build time for default dtype args "scikit-build-core==0.11.6", "typing-extensions~=4.1", ] @@ -31,7 +31,7 @@ dynamic = [ "version" ] dependencies = [ "colorama>=0.4.4; platform_system!='Windows'", "colorama>=0.4.6; platform_system=='Windows'", - "nanobind-backend>=1.0.0.dev1", + "nanobind-backend>=1.0.0.dev2", "numpy>=1.25", "scipy>=1.13.0", ] From 115be63598028cb879f0d9ca36f74d17d0b9275c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Je=CC=81re=CC=81mie=20Dumas?= Date: Wed, 19 Aug 2026 12:04:43 -0700 Subject: [PATCH 3/6] Remove redundant PyPy wheel skip --- .github/workflows/wheel.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheel.yaml b/.github/workflows/wheel.yaml index 3aa2e26e..0d4351f9 100644 --- a/.github/workflows/wheel.yaml +++ b/.github/workflows/wheel.yaml @@ -52,7 +52,7 @@ jobs: CIBW_ARCHS_LINUX: auto64 CIBW_ARCHS_WINDOWS: auto64 CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 - CIBW_SKIP: "*-musllinux* pp*" + CIBW_SKIP: "*-musllinux*" CIBW_TEST_COMMAND: "pytest -s --pdb {project}/modules" CIBW_TEST_REQUIRES: pytest MACOSX_DEPLOYMENT_TARGET: 13.00 From 55f4e22b980da2cb4094a47860a6df299e10efdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Je=CC=81re=CC=81mie=20Dumas?= Date: Wed, 19 Aug 2026 12:41:24 -0700 Subject: [PATCH 4/6] Pin matching nanobind development backend --- cmake/recipes/external/nanobind.cmake | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/recipes/external/nanobind.cmake b/cmake/recipes/external/nanobind.cmake index 1f907bf5..88e8c207 100644 --- a/cmake/recipes/external/nanobind.cmake +++ b/cmake/recipes/external/nanobind.cmake @@ -19,7 +19,7 @@ include(CPM) CPMAddPackage( NAME nanobind GITHUB_REPOSITORY wjakob/nanobind - GIT_TAG v3.0.0-dev2 + GIT_TAG v3.0.0-dev3 DOWNLOAD_ONLY ON ) diff --git a/pyproject.toml b/pyproject.toml index 8f5b7e5f..bd734d4a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [build-system] build-backend = "scikit_build_core.build" requires = [ - "nanobind-backend==1.0.0.dev2", # must match the nanobind development release + "nanobind-backend==1.0.0.dev3", # must match the nanobind development release "numpy>=1.25", # needed at build time for default dtype args "scikit-build-core==0.11.6", "typing-extensions~=4.1", @@ -31,7 +31,7 @@ dynamic = [ "version" ] dependencies = [ "colorama>=0.4.4; platform_system!='Windows'", "colorama>=0.4.6; platform_system=='Windows'", - "nanobind-backend>=1.0.0.dev2", + "nanobind-backend==1.0.0.dev3", "numpy>=1.25", "scipy>=1.13.0", ] From 274503a003a78d7295c379eee83a246968fe810c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Je=CC=81re=CC=81mie=20Dumas?= Date: Thu, 20 Aug 2026 09:04:33 -0700 Subject: [PATCH 5/6] Test nanobind 3.0.0.dev4. --- cmake/recipes/external/nanobind.cmake | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/recipes/external/nanobind.cmake b/cmake/recipes/external/nanobind.cmake index 88e8c207..0ebb3ea0 100644 --- a/cmake/recipes/external/nanobind.cmake +++ b/cmake/recipes/external/nanobind.cmake @@ -19,7 +19,7 @@ include(CPM) CPMAddPackage( NAME nanobind GITHUB_REPOSITORY wjakob/nanobind - GIT_TAG v3.0.0-dev3 + GIT_TAG v3.0.0-dev4 DOWNLOAD_ONLY ON ) diff --git a/pyproject.toml b/pyproject.toml index bd734d4a..be7cb261 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [build-system] build-backend = "scikit_build_core.build" requires = [ - "nanobind-backend==1.0.0.dev3", # must match the nanobind development release + "nanobind-backend==1.0.0.dev4", # must match the nanobind development release "numpy>=1.25", # needed at build time for default dtype args "scikit-build-core==0.11.6", "typing-extensions~=4.1", @@ -31,7 +31,7 @@ dynamic = [ "version" ] dependencies = [ "colorama>=0.4.4; platform_system!='Windows'", "colorama>=0.4.6; platform_system=='Windows'", - "nanobind-backend==1.0.0.dev3", + "nanobind-backend==1.0.0.dev4", "numpy>=1.25", "scipy>=1.13.0", ] From 5747a1fe29e4e2fbb583e7d41655520f73b860b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Je=CC=81re=CC=81mie=20Dumas?= Date: Fri, 21 Aug 2026 08:14:23 -0700 Subject: [PATCH 6/6] Test nanobind 3.0.0.dev5 --- cmake/recipes/external/nanobind.cmake | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/recipes/external/nanobind.cmake b/cmake/recipes/external/nanobind.cmake index 0ebb3ea0..67d50c3b 100644 --- a/cmake/recipes/external/nanobind.cmake +++ b/cmake/recipes/external/nanobind.cmake @@ -19,7 +19,7 @@ include(CPM) CPMAddPackage( NAME nanobind GITHUB_REPOSITORY wjakob/nanobind - GIT_TAG v3.0.0-dev4 + GIT_TAG v3.0.0-dev5 DOWNLOAD_ONLY ON ) diff --git a/pyproject.toml b/pyproject.toml index be7cb261..37cf8460 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [build-system] build-backend = "scikit_build_core.build" requires = [ - "nanobind-backend==1.0.0.dev4", # must match the nanobind development release + "nanobind-backend==1.0.0.dev5", # must match the nanobind development release "numpy>=1.25", # needed at build time for default dtype args "scikit-build-core==0.11.6", "typing-extensions~=4.1", @@ -31,7 +31,7 @@ dynamic = [ "version" ] dependencies = [ "colorama>=0.4.4; platform_system!='Windows'", "colorama>=0.4.6; platform_system=='Windows'", - "nanobind-backend==1.0.0.dev4", + "nanobind-backend==1.0.0.dev5", "numpy>=1.25", "scipy>=1.13.0", ]