From 2c217db4ad145e25b5f1a9ad4f73f669e8541399 Mon Sep 17 00:00:00 2001 From: qbisicwate Date: Mon, 23 Feb 2026 20:09:52 +0800 Subject: [PATCH 01/15] add cpp stub files (#4096) * add cpp stub files * fix nanobind OUTPUT path Note that these OUTPUT are not actually passed to the stub generator and purely used for dependency management within CMake. --- python/CMakeLists.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index a3d9b63904..7d262299e7 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -186,3 +186,28 @@ endif() set_target_properties(cpp PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) install(TARGETS cpp DESTINATION dolfinx) + +nanobind_add_stub( + cpp_stub + MODULE dolfinx.cpp + DEPENDS cpp + VERBOSE + RECURSIVE + INSTALL_TIME + OUTPUT_PATH dolfinx + OUTPUT + dolfinx/cpp/fem/__init__.pyi + dolfinx/cpp/fem/petsc.pyi + dolfinx/cpp/la/__init__.pyi + dolfinx/cpp/la/petsc.pyi + dolfinx/cpp/nls/__init__.pyi + dolfinx/cpp/nls/petsc.pyi + dolfinx/cpp/__init__.pyi + dolfinx/cpp/common.pyi + dolfinx/cpp/geometry.pyi + dolfinx/cpp/graph.pyi + dolfinx/cpp/io.pyi + dolfinx/cpp/log.pyi + dolfinx/cpp/mesh.pyi + dolfinx/cpp/refinement.pyi +) From 297c774da5284b34c41521005a6ec18ec380f415 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:30:50 +0100 Subject: [PATCH 02/15] Fix: reserved python global keyword --- python/dolfinx/wrappers/common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/dolfinx/wrappers/common.cpp b/python/dolfinx/wrappers/common.cpp index 8ca47ccaf2..e3dfde0aea 100644 --- a/python/dolfinx/wrappers/common.cpp +++ b/python/dolfinx/wrappers/common.cpp @@ -167,7 +167,7 @@ void common(nb::module_& m) local); return dolfinx_wrappers::as_nbarray(std::move(local)); }, - nb::arg("global")); + nb::arg("global_index")); // dolfinx::common::Timer nb::class_>( From 905a654b6230cedc83a66706c39e314d1b152b72 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Tue, 24 Feb 2026 19:09:18 +0100 Subject: [PATCH 03/15] Fix: non-install time for UNIX platforms + CI adaptation --- .github/workflows/ccpp.yml | 12 ++++++-- python/CMakeLists.txt | 62 +++++++++++++++++++++++--------------- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index dba743d57e..4546c7fdd5 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -128,9 +128,15 @@ jobs: run: cmake --build . --target test - name: Build Python interface - run: | - pip install --check-build-dependencies --no-build-isolation --config-settings=cmake.build-type="Developer" 'python/[test]' - python -c "from mpi4py import MPI; import dolfinx; assert not dolfinx.has_petsc; assert not dolfinx.has_petsc4py; assert dolfinx.has_superlu_dist" + run: > + pip install 'python/[test]' + --check-build-dependencies + --no-build-isolation + --config-settings=cmake.build-type="Developer" + --verbose + + - name: Check Python install + run: python -c "from mpi4py import MPI; import dolfinx; assert not dolfinx.has_petsc; assert not dolfinx.has_petsc4py; assert dolfinx.has_superlu_dist" - name: Run mypy working-directory: python diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 7d262299e7..cc0f87dc8d 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -187,27 +187,41 @@ set_target_properties(cpp PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) install(TARGETS cpp DESTINATION dolfinx) -nanobind_add_stub( - cpp_stub - MODULE dolfinx.cpp - DEPENDS cpp - VERBOSE - RECURSIVE - INSTALL_TIME - OUTPUT_PATH dolfinx - OUTPUT - dolfinx/cpp/fem/__init__.pyi - dolfinx/cpp/fem/petsc.pyi - dolfinx/cpp/la/__init__.pyi - dolfinx/cpp/la/petsc.pyi - dolfinx/cpp/nls/__init__.pyi - dolfinx/cpp/nls/petsc.pyi - dolfinx/cpp/__init__.pyi - dolfinx/cpp/common.pyi - dolfinx/cpp/geometry.pyi - dolfinx/cpp/graph.pyi - dolfinx/cpp/io.pyi - dolfinx/cpp/log.pyi - dolfinx/cpp/mesh.pyi - dolfinx/cpp/refinement.pyi -) + +if (WIN32) + message("Windows..." STATUS FATAL_ERROR) +else() + nanobind_add_stub( + cpp_stub + MODULE cpp + PYTHON_PATH $ + DEPENDS cpp + MARKER_FILE cpp/py.typed + VERBOSE + RECURSIVE + # INSTALL_TIME + # OUTPUT_PATH dolfinx + OUTPUT + cpp/fem/__init__.pyi + cpp/fem/petsc.pyi + cpp/la/__init__.pyi + cpp/la/petsc.pyi + cpp/nls/__init__.pyi + cpp/nls/petsc.pyi + cpp/__init__.pyi + cpp/common.pyi + cpp/geometry.pyi + cpp/graph.pyi + cpp/io.pyi + cpp/log.pyi + cpp/mesh.pyi + cpp/refinement.pyi + ) + + install(TARGETS cpp LIBRARY DESTINATION dolfinx) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cpp + DESTINATION dolfinx + FILES_MATCHING + PATTERN "*.pyi" + PATTERN "*.typed") +endif() From 55974d6eae8794a2db60c397f11e53b96e64b90d Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:06:14 +0100 Subject: [PATCH 04/15] Fix: scoped log import --- python/dolfinx/fem/petsc.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index 0ec761b992..b9da60d8a1 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -35,6 +35,7 @@ # ruff: noqa: E402 import dolfinx +from dolfinx.log import LogLevel, log assert dolfinx.has_petsc4py @@ -1669,7 +1670,7 @@ def get_petsc_lib() -> pathlib.Path: import petsc4py as _petsc4py petsc_dir = _petsc4py.get_config()["PETSC_DIR"] - petsc_arch = _petsc4py.lib.getPathArchPETSc()[1] + petsc_arch = _petsc4py.lib.getPathArchPETSc()[1] # type: ignore candidate_paths = [ os.path.join(petsc_dir, petsc_arch, "lib", "libpetsc.so"), os.path.join(petsc_dir, petsc_arch, "lib", "libpetsc.dylib"), @@ -1854,8 +1855,6 @@ def set_vals(A: int, except KeyError: pass except ImportError: - from dolfinx.log import LogLevel, log - log( LogLevel.DEBUG, "Could not import numba, so cffi/numba complex types were not registered.", @@ -1901,8 +1900,6 @@ def set_vals(A: int, except KeyError: pass except ImportError: - from dolfinx.log import LogLevel, log - log( LogLevel.DEBUG, "Could not import petsc4py, so cffi/PETSc ABI mode interface was not created.", From f4d0bc0ecbad711d84a742c1d5cdd624ece6b5f7 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:35:18 +0100 Subject: [PATCH 05/15] fix: petsc... --- python/dolfinx/fem/petsc.py | 98 ++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index b9da60d8a1..bfde982dea 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -194,7 +194,7 @@ def create_matrix( else: # Array of 'kind' types return _cpp.fem.petsc.create_matrix_nest(_a, kind) else: # Single form - return _cpp.fem.petsc.create_matrix(a._cpp_object, kind) + return _cpp.fem.petsc.create_matrix(a._cpp_object, kind) # type: ignore # -- Vector assembly ------------------------------------------------------ @@ -264,7 +264,7 @@ def assemble_vector( @assemble_vector.register -def _( +def _( # type: ignore b: PETSc.Vec, # type: ignore[name-defined] L: Form | Sequence[Form], constants: npt.NDArray | Sequence[npt.NDArray] | None = None, @@ -315,10 +315,16 @@ def _( elif isinstance(L, Sequence): constants = pack_constants(L) if constants is None else constants coeffs = pack_coefficients(L) if coeffs is None else coeffs - offset0, offset1 = b.getAttr("_blocks") + offset0, offset1 = b.getAttr("_blocks") # type: ignore with b.localForm() as b_l: for L_, const, coeff, off0, off1, offg0, offg1 in zip( - L, constants, coeffs, offset0, offset0[1:], offset1, offset1[1:] + L, + constants, + coeffs, + offset0, # type: ignore + offset0[1:], # type: ignore + offset1, # type: ignore + offset1[1:], # type: ignore ): bx_ = np.zeros((off1 - off0) + (offg1 - offg0), dtype=PETSc.ScalarType) # type: ignore[attr-defined] _assemble_vector_array(bx_, L_, const, coeff) # type: ignore[arg-type] @@ -402,8 +408,8 @@ def assemble_matrix( @assemble_matrix.register -def _( - A: PETSc.Mat, # type: ignore[name-defined] +def _( # type: ignore + A: PETSc.Mat, a: Form | Sequence[Sequence[Form]], bcs: Sequence[DirichletBC] | None = None, diag: float = 1, @@ -467,7 +473,7 @@ def _( for i, a_row in enumerate(a): for j, a_sub in enumerate(a_row): if a_sub is not None: - Asub = A.getLocalSubMatrix(is0[i], is1[j]) + Asub = A.getLocalSubMatrix(is0[i], is1[j]) # type: ignore _cpp.fem.petsc.assemble_matrix( Asub, a_sub._cpp_object, @@ -476,7 +482,7 @@ def _( _bcs, True, ) - A.restoreLocalSubMatrix(is0[i], is1[j], Asub) + A.restoreLocalSubMatrix(is0[i], is1[j], Asub) # type: ignore elif i == j: for bc in _bcs: row_forms = [row_form for row_form in a_row if row_form is not None] @@ -495,15 +501,15 @@ def _( for i, a_row in enumerate(a): for j, a_sub in enumerate(a_row): if a_sub is not None: - Asub = A.getLocalSubMatrix(is0[i], is1[j]) + Asub = A.getLocalSubMatrix(is0[i], is1[j]) # type: ignore if a_sub.function_spaces[0] is a_sub.function_spaces[1]: _cpp.fem.petsc.insert_diagonal(Asub, a_sub.function_spaces[0], _bcs, diag) - A.restoreLocalSubMatrix(is0[i], is1[j], Asub) + A.restoreLocalSubMatrix(is0[i], is1[j], Asub) # type: ignore else: # Non-blocked constants = pack_constants(a) if constants is None else constants # type: ignore[assignment] coeffs = pack_coefficients(a) if coeffs is None else coeffs # type: ignore[assignment] _bcs = [bc._cpp_object for bc in bcs] if bcs is not None else [] - _cpp.fem.petsc.assemble_matrix(A, a._cpp_object, constants, coeffs, _bcs) + _cpp.fem.petsc.assemble_matrix(A, a._cpp_object, constants, coeffs, _bcs) # type: ignore if a.function_spaces[0] is a.function_spaces[1]: A.assemblyBegin(PETSc.Mat.AssemblyType.FLUSH) # type: ignore[attr-defined] A.assemblyEnd(PETSc.Mat.AssemblyType.FLUSH) # type: ignore[attr-defined] @@ -605,7 +611,7 @@ def apply_lifting( else: xlocal = None - offset0, offset1 = b.getAttr("_blocks") + offset0, offset1 = b.getAttr("_blocks") # type: ignore with b.localForm() as b_l: for i, (a_, off0, off1, offg0, offg1) in enumerate( zip(a, offset0, offset0[1:], offset1, offset1[1:]) @@ -628,8 +634,6 @@ def apply_lifting( b_local = stack.enter_context(b.localForm()) _apply_lifting(b_local.array_w, a, bcs, x0_r, alpha, constants, coeffs) # type: ignore[arg-type] - return b - def set_bc( b: PETSc.Vec, # type: ignore[name-defined] @@ -663,19 +667,19 @@ def set_bc( return if not isinstance(bcs[0], Sequence): - x0 = x0.array_r if x0 is not None else None + x0 = x0.array_r if x0 is not None else None # type: ignore for bc in bcs: - bc.set(b.array_w, x0, alpha) # type: ignore[union-attr] + bc.set(b.array_w, x0, alpha) # type: ignore elif b.getType() == PETSc.Vec.Type.NEST: # type: ignore[attr-defined] _b = b.getNestSubVecs() - x0 = len(_b) * [None] if x0 is None else x0.getNestSubVecs() - for b_sub, bc, x_sub in zip(_b, bcs, x0): # type: ignore[assignment, arg-type] + x0 = len(_b) * [None] if x0 is None else x0.getNestSubVecs() # type: ignore + for b_sub, bc, x_sub in zip(_b, bcs, x0): # type: ignore set_bc(b_sub, bc, x_sub, alpha) # type: ignore[arg-type] else: # block vector - offset0, _ = b.getAttr("_blocks") + offset0, _ = b.getAttr("_blocks") # type: ignore b_array = b.getArray(readonly=False) x_array = x0.getArray(readonly=True) if x0 is not None else None - for bcs, off0, off1 in zip(bcs, offset0, offset0[1:]): # type: ignore[assignment] + for bcs, off0, off1 in zip(bcs, offset0, offset0[1:]): # type: ignore x0_sub = x_array[off0:off1] if x0 is not None else None # type: ignore[index] for bc in bcs: bc.set(b_array[off0:off1], x0_sub, alpha) # type: ignore[arg-type, union-attr] @@ -855,13 +859,13 @@ def __init__( opts.prefixPush(self.solver.getOptionsPrefix()) for k, v in petsc_options.items(): - opts[k] = v + opts[k] = v # type: ignore self.solver.setFromOptions() # Tidy up global options for k in petsc_options.keys(): - del opts[k] + del opts[k] # type: ignore opts.prefixPop() @@ -921,8 +925,8 @@ def solve(self) -> _Function | Sequence[_Function]: apply_lifting(self.b, self.a, bcs=bcs1) # type: ignore[arg-type] dolfinx.la.petsc._ghost_update( self.b, - PETSc.InsertMode.ADD, # type: ignore[attr-defined] - PETSc.ScatterMode.REVERSE, # type: ignore[attr-defined] + PETSc.InsertMode.ADD, # type: ignore + PETSc.ScatterMode.REVERSE, # type: ignore ) bcs0 = _bcs_by_block(_extract_function_spaces(self.L), self.bcs) # type: ignore[arg-type] dolfinx.fem.petsc.set_bc(self.b, bcs0) @@ -930,8 +934,8 @@ def solve(self) -> _Function | Sequence[_Function]: apply_lifting(self.b, [self.a], bcs=[self.bcs]) # type: ignore[arg-type] dolfinx.la.petsc._ghost_update( self.b, - PETSc.InsertMode.ADD, # type: ignore[attr-defined] - PETSc.ScatterMode.REVERSE, # type: ignore[attr-defined] + PETSc.InsertMode.ADD, # type: ignore + PETSc.ScatterMode.REVERSE, # type: ignore ) for bc in self.bcs: bc.set(self.b.array_w) @@ -940,8 +944,8 @@ def solve(self) -> _Function | Sequence[_Function]: # Solve linear system and update ghost values in the solution self.solver.solve(self.b, self.x) - dolfinx.la.petsc._ghost_update(self.x, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore[attr-defined] - dolfinx.fem.petsc.assign(self.x, self.u) + dolfinx.la.petsc._ghost_update(self.x, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore + dolfinx.fem.petsc.assign(self.x, self.u) # type: ignore return self.u @property @@ -965,7 +969,7 @@ def A(self) -> PETSc.Mat: # type: ignore[name-defined] return self._A @property - def P_mat(self) -> PETSc.Mat: # type: ignore[name-defined] + def P_mat(self) -> PETSc.Mat | None: # type: ignore[name-defined] """Preconditioner matrix.""" return self._P_mat @@ -1043,10 +1047,10 @@ def assemble_residual( format of this argument. """ # Update input vector before assigning - dolfinx.la.petsc._ghost_update(x, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore[attr-defined] + dolfinx.la.petsc._ghost_update(x, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore # Assign the input vector to the unknowns - assign(x, u) + assign(x, u) # type: ignore # Assign block data if block assembly is requested if isinstance(residual, Sequence) and b.getType() != PETSc.Vec.Type.NEST: # type: ignore[attr-defined] @@ -1062,16 +1066,16 @@ def assemble_residual( if isinstance(jacobian, Sequence): # Nest and blocked lifting bcs1 = _bcs_by_block(_extract_function_spaces(jacobian, 1), bcs) # type: ignore[arg-type] - apply_lifting(b, jacobian, bcs=bcs1, x0=x, alpha=-1.0) - dolfinx.la.petsc._ghost_update(b, PETSc.InsertMode.ADD, PETSc.ScatterMode.REVERSE) # type: ignore[attr-defined] + apply_lifting(b, jacobian, bcs=bcs1, x0=x, alpha=-1.0) # type: ignore + dolfinx.la.petsc._ghost_update(b, PETSc.InsertMode.ADD, PETSc.ScatterMode.REVERSE) # type: ignore bcs0 = _bcs_by_block(_extract_function_spaces(residual), bcs) # type: ignore[arg-type] set_bc(b, bcs0, x0=x, alpha=-1.0) else: # Single form lifting apply_lifting(b, [jacobian], bcs=[bcs], x0=[x], alpha=-1.0) - dolfinx.la.petsc._ghost_update(b, PETSc.InsertMode.ADD, PETSc.ScatterMode.REVERSE) # type: ignore[attr-defined] + dolfinx.la.petsc._ghost_update(b, PETSc.InsertMode.ADD, PETSc.ScatterMode.REVERSE) # type: ignore set_bc(b, bcs, x0=x, alpha=-1.0) - dolfinx.la.petsc._ghost_update(b, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore[attr-defined] + dolfinx.la.petsc._ghost_update(b, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore def assemble_jacobian( @@ -1114,8 +1118,8 @@ def assemble_jacobian( """ # Copy existing soultion into the function used in the residual and # Jacobian - dolfinx.la.petsc._ghost_update(x, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore[attr-defined] - assign(x, u) + dolfinx.la.petsc._ghost_update(x, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore + assign(x, u) # type: ignore # Assemble Jacobian J.zeroEntries() @@ -1146,6 +1150,8 @@ class NonlinearProblem: ``.destroy()`` on returned PETSc objects. """ # noqa: D301 + _P_mat: PETSc.Mat | None + def __init__( self, F: ufl.form.Form | Sequence[ufl.form.Form], @@ -1303,13 +1309,13 @@ def __init__( opts.prefixPush(self.solver.getOptionsPrefix()) for k, v in petsc_options.items(): - opts[k] = v + opts[k] = v # type: ignore self.solver.setFromOptions() # Tidy up global options for k in petsc_options.keys(): - del opts[k] + del opts[k] # type: ignore opts.prefixPop() @@ -1346,10 +1352,10 @@ def solve(self) -> _Function | Sequence[_Function]: # Solve problem self.solver.solve(None, self.x) - dolfinx.la.petsc._ghost_update(self.x, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore[attr-defined] + dolfinx.la.petsc._ghost_update(self.x, PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD) # type: ignore # Copy solution back to function - assign(self.x, self.u) + assign(self.x, self.u) # type: ignore return self.u @@ -1518,7 +1524,7 @@ def F(self, x: PETSc.Vec, b: PETSc.Vec) -> None: # type: ignore[name-defined] """ # Reset the residual vector dolfinx.la.petsc._zero_vector(b) - assemble_vector(b, self._L) + assemble_vector(b, self._L) # type: ignore # Apply boundary condition if self.bcs is not None: @@ -1629,7 +1635,7 @@ def assign(u: _Function | Sequence[_Function], x: PETSc.Vec): # type: ignore[na @assign.register -def _(x: PETSc.Vec, u: _Function | Sequence[_Function]): # type: ignore[name-defined] +def _(x: PETSc.Vec, u: _Function | Sequence[_Function]): # type: ignore[name-defined, misc] """Assign vector entries to :class:`Function` degrees-of-freedom. Assigns values in ``x`` to the degrees-of-freedom of ``u``, which is @@ -1643,7 +1649,7 @@ def _(x: PETSc.Vec, u: _Function | Sequence[_Function]): # type: ignore[name-de u: ``Function`` (s) to assign degree-of-freedom values to. """ if x.getType() == PETSc.Vec.Type().NEST: # type: ignore[attr-defined] - dolfinx.la.petsc.assign(x, [v.x.array for v in u]) + dolfinx.la.petsc.assign(x, [v.x.array for v in u]) # type: ignore else: if isinstance(u, Sequence): data0, data1 = [], [] @@ -1652,9 +1658,9 @@ def _(x: PETSc.Vec, u: _Function | Sequence[_Function]): # type: ignore[name-de n = v.function_space.dofmap.index_map.size_local data0.append(v.x.array[: bs * n]) data1.append(v.x.array[bs * n :]) - dolfinx.la.petsc.assign(x, data0 + data1) + dolfinx.la.petsc.assign(x, data0 + data1) # type: ignore else: - dolfinx.la.petsc.assign(x, u.x.array) + dolfinx.la.petsc.assign(x, u.x.array) # type: ignore def get_petsc_lib() -> pathlib.Path: From fa45edbfef8652d5229c71d991e33c92ba74704e Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 26 May 2026 14:55:56 +0200 Subject: [PATCH 06/15] Work in progress on autogenerating nanobind stubs --- python/CMakeLists.txt | 71 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index a3d9b63904..b3298caebd 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -185,4 +185,73 @@ endif() set_target_properties(cpp PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) -install(TARGETS cpp DESTINATION dolfinx) + +# and the nanobind typing stubs. +if (WIN32) + # On Windows we cannot import dolfinx.cpp without installing the package + # alongside its external dlls. + + # This *must* be called prior to nanobind_add_stub + install(TARGETS cpp DESTINATION dolfinx) + # nanobind automatically installs into ${CMAKE_INSTALL_PREFIX} in + # INSTALL_TIME mode. + # DEPENDS is redundant in INSTALL_TIME mode - cpp must be installed. + nanobind_add_stub( + cpp_stub + INSTALL_TIME + + MODULE dolfinx.cpp + DEPENDS cpp + + RECURSIVE + VERBOSE + OUTPUT + dolfinx/_cpp.pyi + ) +else() + # On UNIX-like systems we can import the cpp compiled module before + # installing and rely on dynamic linking at import time. + nanobind_add_stub( + cpp_stub + MODULE cpp + + PYTHON_PATH $ + DEPENDS cpp + + OUTPUT + _cpp.pyi + assemble/__init__.pyi + common/__init__.pyi + fem/__init__.pyi + fem/petsc/__init__.pyi + geometry/__init__.pyi + graph/__init__.pyi + io/__init__.pyi + la/__init__.pyi + la/petsc/__init__.pyi + log/__init__.pyi + mesh/__init__.pyi + refinement/__init__.pyi + + RECURSIVE + VERBOSE + ) + + install(TARGETS cpp DESTINATION dolfinx) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/_cpp.pyi + ${CMAKE_CURRENT_BINARY_DIR}/assemble/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/common/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/fem/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/fem/petsc/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/geometry/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/graph/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/io/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/la/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/la/petsc/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/log/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/mesh/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/refinement/__init__.pyi + DESTINATION dolfinx + ) +endif() From 2c6eb515ba92456b0a7c0e30bb0307610a75a1de Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 26 May 2026 15:25:20 +0200 Subject: [PATCH 07/15] Generate dolfinx.cpp stubs automatically --- python/CMakeLists.txt | 79 ++++++++++++++++++++++++------------------- python/pyproject.toml | 4 ++- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index b3298caebd..4d94569c9e 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -199,14 +199,24 @@ if (WIN32) nanobind_add_stub( cpp_stub INSTALL_TIME - - MODULE dolfinx.cpp - DEPENDS cpp - + MODULE cpp RECURSIVE VERBOSE OUTPUT - dolfinx/_cpp.pyi + dolfinx/cpp/__init__.pyi + dolfinx/cpp/common.pyi + dolfinx/cpp/fem/__init__.pyi + dolfinx/cpp/fem/petsc.pyi + dolfinx/cpp/geometry.pyi + dolfinx/cpp/graph.pyi + dolfinx/cpp/io.pyi + dolfinx/cpp/la/__init__.pyi + dolfinx/cpp/la/petsc.pyi + dolfinx/cpp/log.pyi + dolfinx/cpp/mesh.pyi + dolfinx/cpp/nls/__init__.pyi + dolfinx/cpp/nls/petsc.pyi + dolfinx/cpp/refinement.pyi ) else() # On UNIX-like systems we can import the cpp compiled module before @@ -214,44 +224,43 @@ else() nanobind_add_stub( cpp_stub MODULE cpp - PYTHON_PATH $ DEPENDS cpp - - OUTPUT - _cpp.pyi - assemble/__init__.pyi - common/__init__.pyi - fem/__init__.pyi - fem/petsc/__init__.pyi - geometry/__init__.pyi - graph/__init__.pyi - io/__init__.pyi - la/__init__.pyi - la/petsc/__init__.pyi - log/__init__.pyi - mesh/__init__.pyi - refinement/__init__.pyi - RECURSIVE VERBOSE + OUTPUT + cpp/__init__.pyi + cpp/common.pyi + cpp/fem/__init__.pyi + cpp/fem/petsc.pyi + cpp/geometry.pyi + cpp/graph.pyi + cpp/io.pyi + cpp/la/__init__.pyi + cpp/la/petsc.pyi + cpp/log.pyi + cpp/mesh.pyi + cpp/nls/__init__.pyi + cpp/nls/petsc.pyi + cpp/refinement.pyi ) install(TARGETS cpp DESTINATION dolfinx) install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/_cpp.pyi - ${CMAKE_CURRENT_BINARY_DIR}/assemble/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/common/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/fem/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/fem/petsc/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/geometry/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/graph/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/io/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/la/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/la/petsc/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/log/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/mesh/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/refinement/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/common.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/petsc.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/geometry.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/graph.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/io.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/petsc.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/log.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/mesh.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/petsc.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/refinement.pyi DESTINATION dolfinx ) endif() diff --git a/python/pyproject.toml b/python/pyproject.toml index 304fff9448..fc9255c153 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -4,7 +4,9 @@ # NOTE: petsc4py is an optional build dependency, therefore we don't # list it here. [build-system] -requires = ["scikit-build-core[pyproject]>=0.10", "nanobind>=2.5.0", "mpi4py"] +# scikit-build-core>=0.11 has SPDX license support PEP 639 +# nanobind>=2.9.2 has working recursive stubgen +requires = ["scikit-build-core[pyproject]>=0.11", "nanobind>=2.9.2", "mpi4py"] build-backend = "scikit_build_core.build" [project] From 902c54aea6c5fd2c81182497ab0158e7e803a0e5 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 26 May 2026 15:30:35 +0200 Subject: [PATCH 08/15] Add a way to disable nanobind stubgen (e.g. HPC builds) --- python/CMakeLists.txt | 158 ++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 77 deletions(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 4d94569c9e..f6168f1858 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -21,6 +21,9 @@ include(FeatureSummary) option(ENABLE_CLANG_TIDY "Run clang-tidy while building" OFF) add_feature_info(ENABLE_CLANG_TIDY ENABLE_CLANG_TIDY "Run clang-tidy while building") +option(ENABLE_NANOBIND_STUBGEN "Run nanobind stub generation" ON) +add_feature_info(ENABLE_NANOBIND_STUBGEN ENABLE_NANOBIND_STUBGEN "Run nanobind stub generation") + feature_summary(WHAT ALL) # Detect the installed nanobind package and import it into CMake @@ -185,82 +188,83 @@ endif() set_target_properties(cpp PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) - # and the nanobind typing stubs. -if (WIN32) - # On Windows we cannot import dolfinx.cpp without installing the package - # alongside its external dlls. - - # This *must* be called prior to nanobind_add_stub - install(TARGETS cpp DESTINATION dolfinx) - # nanobind automatically installs into ${CMAKE_INSTALL_PREFIX} in - # INSTALL_TIME mode. - # DEPENDS is redundant in INSTALL_TIME mode - cpp must be installed. - nanobind_add_stub( - cpp_stub - INSTALL_TIME - MODULE cpp - RECURSIVE - VERBOSE - OUTPUT - dolfinx/cpp/__init__.pyi - dolfinx/cpp/common.pyi - dolfinx/cpp/fem/__init__.pyi - dolfinx/cpp/fem/petsc.pyi - dolfinx/cpp/geometry.pyi - dolfinx/cpp/graph.pyi - dolfinx/cpp/io.pyi - dolfinx/cpp/la/__init__.pyi - dolfinx/cpp/la/petsc.pyi - dolfinx/cpp/log.pyi - dolfinx/cpp/mesh.pyi - dolfinx/cpp/nls/__init__.pyi - dolfinx/cpp/nls/petsc.pyi - dolfinx/cpp/refinement.pyi - ) -else() - # On UNIX-like systems we can import the cpp compiled module before - # installing and rely on dynamic linking at import time. - nanobind_add_stub( - cpp_stub - MODULE cpp - PYTHON_PATH $ - DEPENDS cpp - RECURSIVE - VERBOSE - OUTPUT - cpp/__init__.pyi - cpp/common.pyi - cpp/fem/__init__.pyi - cpp/fem/petsc.pyi - cpp/geometry.pyi - cpp/graph.pyi - cpp/io.pyi - cpp/la/__init__.pyi - cpp/la/petsc.pyi - cpp/log.pyi - cpp/mesh.pyi - cpp/nls/__init__.pyi - cpp/nls/petsc.pyi - cpp/refinement.pyi - ) - - install(TARGETS cpp DESTINATION dolfinx) - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/cpp/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/common.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/petsc.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/geometry.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/graph.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/io.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/petsc.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/log.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/mesh.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/petsc.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/refinement.pyi - DESTINATION dolfinx - ) +if (ENABLE_NANOBIND_STUBGEN) + if (WIN32) + # On Windows we cannot import dolfinx.cpp without installing the package + # alongside its external dlls. + + # This *must* be called prior to nanobind_add_stub + install(TARGETS cpp DESTINATION dolfinx) + # nanobind automatically installs into ${CMAKE_INSTALL_PREFIX} in + # INSTALL_TIME mode. + # DEPENDS is redundant in INSTALL_TIME mode - cpp must be installed. + nanobind_add_stub( + cpp_stub + INSTALL_TIME + MODULE cpp + RECURSIVE + VERBOSE + OUTPUT + dolfinx/cpp/__init__.pyi + dolfinx/cpp/common.pyi + dolfinx/cpp/fem/__init__.pyi + dolfinx/cpp/fem/petsc.pyi + dolfinx/cpp/geometry.pyi + dolfinx/cpp/graph.pyi + dolfinx/cpp/io.pyi + dolfinx/cpp/la/__init__.pyi + dolfinx/cpp/la/petsc.pyi + dolfinx/cpp/log.pyi + dolfinx/cpp/mesh.pyi + dolfinx/cpp/nls/__init__.pyi + dolfinx/cpp/nls/petsc.pyi + dolfinx/cpp/refinement.pyi + ) + else() + # On UNIX-like systems we can import the cpp compiled module before + # installing and rely on dynamic linking at import time. + nanobind_add_stub( + cpp_stub + MODULE cpp + PYTHON_PATH $ + DEPENDS cpp + RECURSIVE + VERBOSE + OUTPUT + cpp/__init__.pyi + cpp/common.pyi + cpp/fem/__init__.pyi + cpp/fem/petsc.pyi + cpp/geometry.pyi + cpp/graph.pyi + cpp/io.pyi + cpp/la/__init__.pyi + cpp/la/petsc.pyi + cpp/log.pyi + cpp/mesh.pyi + cpp/nls/__init__.pyi + cpp/nls/petsc.pyi + cpp/refinement.pyi + ) + + install(TARGETS cpp DESTINATION dolfinx) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/cpp/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/common.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/petsc.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/geometry.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/graph.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/io.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/petsc.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/log.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/mesh.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/petsc.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/refinement.pyi + DESTINATION dolfinx + ) + endif() endif() From f21118efb2e250153264cfa2dad55543c488e416 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 26 May 2026 15:47:42 +0200 Subject: [PATCH 09/15] Fix formatting --- python/CMakeLists.txt | 56 +++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index f6168f1858..547c4720ed 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -206,20 +206,20 @@ if (ENABLE_NANOBIND_STUBGEN) RECURSIVE VERBOSE OUTPUT - dolfinx/cpp/__init__.pyi - dolfinx/cpp/common.pyi - dolfinx/cpp/fem/__init__.pyi - dolfinx/cpp/fem/petsc.pyi - dolfinx/cpp/geometry.pyi - dolfinx/cpp/graph.pyi - dolfinx/cpp/io.pyi - dolfinx/cpp/la/__init__.pyi - dolfinx/cpp/la/petsc.pyi - dolfinx/cpp/log.pyi - dolfinx/cpp/mesh.pyi - dolfinx/cpp/nls/__init__.pyi - dolfinx/cpp/nls/petsc.pyi - dolfinx/cpp/refinement.pyi + dolfinx/cpp/__init__.pyi + dolfinx/cpp/common.pyi + dolfinx/cpp/fem/__init__.pyi + dolfinx/cpp/fem/petsc.pyi + dolfinx/cpp/geometry.pyi + dolfinx/cpp/graph.pyi + dolfinx/cpp/io.pyi + dolfinx/cpp/la/__init__.pyi + dolfinx/cpp/la/petsc.pyi + dolfinx/cpp/log.pyi + dolfinx/cpp/mesh.pyi + dolfinx/cpp/nls/__init__.pyi + dolfinx/cpp/nls/petsc.pyi + dolfinx/cpp/refinement.pyi ) else() # On UNIX-like systems we can import the cpp compiled module before @@ -232,20 +232,20 @@ if (ENABLE_NANOBIND_STUBGEN) RECURSIVE VERBOSE OUTPUT - cpp/__init__.pyi - cpp/common.pyi - cpp/fem/__init__.pyi - cpp/fem/petsc.pyi - cpp/geometry.pyi - cpp/graph.pyi - cpp/io.pyi - cpp/la/__init__.pyi - cpp/la/petsc.pyi - cpp/log.pyi - cpp/mesh.pyi - cpp/nls/__init__.pyi - cpp/nls/petsc.pyi - cpp/refinement.pyi + cpp/__init__.pyi + cpp/common.pyi + cpp/fem/__init__.pyi + cpp/fem/petsc.pyi + cpp/geometry.pyi + cpp/graph.pyi + cpp/io.pyi + cpp/la/__init__.pyi + cpp/la/petsc.pyi + cpp/log.pyi + cpp/mesh.pyi + cpp/nls/__init__.pyi + cpp/nls/petsc.pyi + cpp/refinement.pyi ) install(TARGETS cpp DESTINATION dolfinx) From d7de563188bc3ca09d12ad77b0d509f1e2bf18c0 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 26 May 2026 16:16:18 +0200 Subject: [PATCH 10/15] Fix on platforms without petsc4py --- python/CMakeLists.txt | 71 ++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 547c4720ed..a759cb0bb4 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -189,8 +189,8 @@ endif() set_target_properties(cpp PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) # and the nanobind typing stubs. -if (ENABLE_NANOBIND_STUBGEN) - if (WIN32) +if(ENABLE_NANOBIND_STUBGEN) + if(WIN32) # On Windows we cannot import dolfinx.cpp without installing the package # alongside its external dlls. @@ -206,20 +206,23 @@ if (ENABLE_NANOBIND_STUBGEN) RECURSIVE VERBOSE OUTPUT - dolfinx/cpp/__init__.pyi - dolfinx/cpp/common.pyi - dolfinx/cpp/fem/__init__.pyi - dolfinx/cpp/fem/petsc.pyi - dolfinx/cpp/geometry.pyi - dolfinx/cpp/graph.pyi - dolfinx/cpp/io.pyi - dolfinx/cpp/la/__init__.pyi - dolfinx/cpp/la/petsc.pyi - dolfinx/cpp/log.pyi - dolfinx/cpp/mesh.pyi - dolfinx/cpp/nls/__init__.pyi - dolfinx/cpp/nls/petsc.pyi - dolfinx/cpp/refinement.pyi + dolfinx/cpp/__init__.pyi + dolfinx/cpp/common.pyi + dolfinx/cpp/fem.pyi + dolfinx/cpp/fem/__init__.pyi + dolfinx/cpp/fem/petsc.pyi + dolfinx/cpp/geometry.pyi + dolfinx/cpp/graph.pyi + dolfinx/cpp/io.pyi + dolfinx/cpp/la.pyi + dolfinx/cpp/la/__init__.pyi + dolfinx/cpp/la/petsc.pyi + dolfinx/cpp/log.pyi + dolfinx/cpp/mesh.pyi + dolfinx/cpp/nls.pyi + dolfinx/cpp/nls/__init__.pyi + dolfinx/cpp/nls/petsc.pyi + dolfinx/cpp/refinement.pyi ) else() # On UNIX-like systems we can import the cpp compiled module before @@ -232,39 +235,59 @@ if (ENABLE_NANOBIND_STUBGEN) RECURSIVE VERBOSE OUTPUT - cpp/__init__.pyi - cpp/common.pyi + cpp/__init__.pyi + cpp/common.pyi + cpp/fem.pyi cpp/fem/__init__.pyi cpp/fem/petsc.pyi cpp/geometry.pyi cpp/graph.pyi cpp/io.pyi + cpp/la.pyi cpp/la/__init__.pyi cpp/la/petsc.pyi cpp/log.pyi cpp/mesh.pyi + cpp/nls.pyi cpp/nls/__init__.pyi cpp/nls/petsc.pyi cpp/refinement.pyi ) install(TARGETS cpp DESTINATION dolfinx) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cpp/__init__.pyi ${CMAKE_CURRENT_BINARY_DIR}/cpp/common.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/petsc.pyi ${CMAKE_CURRENT_BINARY_DIR}/cpp/geometry.pyi ${CMAKE_CURRENT_BINARY_DIR}/cpp/graph.pyi ${CMAKE_CURRENT_BINARY_DIR}/cpp/io.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/petsc.pyi ${CMAKE_CURRENT_BINARY_DIR}/cpp/log.pyi ${CMAKE_CURRENT_BINARY_DIR}/cpp/mesh.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/__init__.pyi - ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/petsc.pyi ${CMAKE_CURRENT_BINARY_DIR}/cpp/refinement.pyi DESTINATION dolfinx ) + + # Structure and number of typing files varies based on if petsc4py was + # found + get_target_property(compile_definitions cpp COMPILE_DEFINITIONS) + if("HAS_PETSC4PY" IN_LIST compile_definitions) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem/petsc.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/la/petsc.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/__init__.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls/petsc.pyi + DESTINATION dolfinx + ) + else() + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/cpp/fem.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/la.pyi + ${CMAKE_CURRENT_BINARY_DIR}/cpp/nls.pyi + DESTINATION dolfinx + ) + endif() endif() endif() From a1cadb636a0e7b6a674b9ca86baa3e7fabeb6be0 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 26 May 2026 16:37:13 +0200 Subject: [PATCH 11/15] Use spack-fenics due to updated base deps --- .github/workflows/ci-spack.yml | 8 ++++++++ .github/workflows/ci.yml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-spack.yml b/.github/workflows/ci-spack.yml index 7a7ba9626f..20cd07bcc5 100644 --- a/.github/workflows/ci-spack.yml +++ b/.github/workflows/ci-spack.yml @@ -49,11 +49,19 @@ jobs: repository: spack/spack-packages ref: develop path: spack-packages + - name: Get FEniCS Spack packages + uses: actions/checkout@v6 + with: + repository: fenics/spack-fenics + ref: jhale/nanobind-scikit-main-updates + path: spack-fenics + # Use upstream Spack packages and overlay FEniCS Spack packages - name: Add Spack packages repo run: | . $GITHUB_WORKSPACE/spack-src/share/spack/setup-env.sh spack repo add --name builtin $GITHUB_WORKSPACE/spack-packages/repos/spack_repo/builtin + spack repo add --name fenics $GITHUB_WORKSPACE/spack-fenics/spack_repo/fenics spack config get repos spack repo list diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1afab4b32d..79a76dfeff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,7 @@ jobs: uses: actions/checkout@v6 with: repository: fenics/spack-fenics - ref: main + ref: jhale/nanobind-scikit-main-updates path: spack-fenics # Use upstream Spack packages and overlay FEniCS Spack packages From 61675d5899119cd1f4eddfeb4af3403cfb7a400d Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 27 May 2026 08:19:51 +0200 Subject: [PATCH 12/15] Back to main --- .github/workflows/ci-spack.yml | 2 +- .github/workflows/ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-spack.yml b/.github/workflows/ci-spack.yml index 20cd07bcc5..4f97408fe1 100644 --- a/.github/workflows/ci-spack.yml +++ b/.github/workflows/ci-spack.yml @@ -53,7 +53,7 @@ jobs: uses: actions/checkout@v6 with: repository: fenics/spack-fenics - ref: jhale/nanobind-scikit-main-updates + ref: main path: spack-fenics # Use upstream Spack packages and overlay FEniCS Spack packages diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79a76dfeff..1afab4b32d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,7 @@ jobs: uses: actions/checkout@v6 with: repository: fenics/spack-fenics - ref: jhale/nanobind-scikit-main-updates + ref: main path: spack-fenics # Use upstream Spack packages and overlay FEniCS Spack packages From 584a9117aa795b16c53e979b6792e23cb2646166 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 27 May 2026 11:31:25 +0200 Subject: [PATCH 13/15] Fix. --- python/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index d39b6705c2..7d5d8c9d68 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -195,7 +195,7 @@ if(ENABLE_NANOBIND_STUBGEN) # alongside its external dlls. # This *must* be called prior to nanobind_add_stub - install(TARGETS cpp DESTINATION dolfinx) + install(TARGETS cpp LIBRARY DESTINATION dolfinx) # nanobind automatically installs into ${CMAKE_INSTALL_PREFIX} in # INSTALL_TIME mode. # DEPENDS is redundant in INSTALL_TIME mode - cpp must be installed. @@ -205,6 +205,7 @@ if(ENABLE_NANOBIND_STUBGEN) MODULE cpp RECURSIVE VERBOSE + MARKER_FILE dolfinx/cpp/py.typed OUTPUT dolfinx/cpp/__init__.pyi dolfinx/cpp/common.pyi @@ -234,6 +235,7 @@ if(ENABLE_NANOBIND_STUBGEN) DEPENDS cpp RECURSIVE VERBOSE + MARKER_FILE cpp/py.typed OUTPUT cpp/__init__.pyi cpp/common.pyi From 532c893e1a4503b06d8f8589a69c9366e7adc87e Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 27 May 2026 11:31:43 +0200 Subject: [PATCH 14/15] Revert --- .github/workflows/ccpp.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 4546c7fdd5..dba743d57e 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -128,15 +128,9 @@ jobs: run: cmake --build . --target test - name: Build Python interface - run: > - pip install 'python/[test]' - --check-build-dependencies - --no-build-isolation - --config-settings=cmake.build-type="Developer" - --verbose - - - name: Check Python install - run: python -c "from mpi4py import MPI; import dolfinx; assert not dolfinx.has_petsc; assert not dolfinx.has_petsc4py; assert dolfinx.has_superlu_dist" + run: | + pip install --check-build-dependencies --no-build-isolation --config-settings=cmake.build-type="Developer" 'python/[test]' + python -c "from mpi4py import MPI; import dolfinx; assert not dolfinx.has_petsc; assert not dolfinx.has_petsc4py; assert dolfinx.has_superlu_dist" - name: Run mypy working-directory: python From 2dd79cab43aa68129539d1870394e61f044f4010 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 27 May 2026 12:46:10 +0200 Subject: [PATCH 15/15] Fix Windows module name --- python/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 7d5d8c9d68..63fd8b4505 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -202,7 +202,7 @@ if(ENABLE_NANOBIND_STUBGEN) nanobind_add_stub( cpp_stub INSTALL_TIME - MODULE cpp + MODULE dolfinx.cpp RECURSIVE VERBOSE MARKER_FILE dolfinx/cpp/py.typed