From f82f6677d7352644d198e256b636bf621a1a9c39 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:39:01 +0100 Subject: [PATCH 1/8] Add reproducible mypy make recipe --- .github/workflows/ccpp.yml | 10 ++-------- python/Makefile | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 python/Makefile diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index c009dfd4f0..21fe82f6f9 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -132,15 +132,9 @@ jobs: 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 # Use a venv to avoid NumPy upgrades that are incompatible with numba + - name: Run mypy working-directory: python - run: | - python -m venv mypy-env - . ./mypy-env/bin/activate - pip install mypy types-cffi scipy-stubs - mypy -p dolfinx - # mypy test - # mypy demo + run: make lint-mypy - name: Install gmsh and pyvista (and dependencies) run: | diff --git a/python/Makefile b/python/Makefile new file mode 100644 index 0000000000..4f59ecff41 --- /dev/null +++ b/python/Makefile @@ -0,0 +1,14 @@ +# Note: mypy is currenlty on CI tested without petsc4py! +lint-mypy: + python -m venv dolfinx-venv-mypy + . dolfinx-venv-mypy/bin/activate && pip install mypy types-cffi scipy-stubs + . dolfinx-venv-mypy/bin/activate && mypy -p dolfinx +# . dolfinx-venv-mypy/bin/activate && mypy test +# . dolfinx-venv-mypy/bin/activate && mypy demo + +lint-mypy-clean: + rm -rf dolfinx-venv-mypy + +lint: lint-mypy + +clean: lint-mypy-clean From 452f4ae05d43a74122da83870d06341c8f5c891f Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:46:31 +0100 Subject: [PATCH 2/8] Mypy check test/ --- python/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/Makefile b/python/Makefile index 4f59ecff41..a8a0c8213f 100644 --- a/python/Makefile +++ b/python/Makefile @@ -3,7 +3,7 @@ lint-mypy: python -m venv dolfinx-venv-mypy . dolfinx-venv-mypy/bin/activate && pip install mypy types-cffi scipy-stubs . dolfinx-venv-mypy/bin/activate && mypy -p dolfinx -# . dolfinx-venv-mypy/bin/activate && mypy test + . dolfinx-venv-mypy/bin/activate && mypy test # . dolfinx-venv-mypy/bin/activate && mypy demo lint-mypy-clean: From 4cb783a790f19a2aa17729d7b531a900ac585564 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Fri, 20 Mar 2026 16:10:27 +0100 Subject: [PATCH 3/8] Fix: dbc value type --- python/dolfinx/fem/bcs.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 10dce42ba3..d4abcaa8a7 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -12,7 +12,6 @@ from __future__ import annotations -import numbers from collections.abc import Callable, Iterable import numpy as np @@ -172,7 +171,7 @@ def dof_indices(self) -> tuple[npt.NDArray[np.int32], int]: def dirichletbc( - value: Function | Constant | np.ndarray, + value: Function | Constant | np.ndarray | float | complex, dofs: npt.NDArray[np.int32], V: dolfinx.fem.FunctionSpace | None = None, ) -> DirichletBC: @@ -193,7 +192,7 @@ def dirichletbc( A representation of the boundary condition for modifying linear systems. """ - if isinstance(value, numbers.Number): + if isinstance(value, float | complex): value = np.asarray(value) try: From a75f18d34bee6f37da15f1c10e4ee6bd44d7d15b Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:51:55 +0100 Subject: [PATCH 4/8] Mypy check (and fix) demo/ --- python/Makefile | 2 +- python/demo/demo_pml.py | 4 ++-- python/demo/demo_pyamg.py | 10 +++++----- python/demo/demo_scattering_boundary_conditions.py | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/python/Makefile b/python/Makefile index a8a0c8213f..88332551f5 100644 --- a/python/Makefile +++ b/python/Makefile @@ -4,7 +4,7 @@ lint-mypy: . dolfinx-venv-mypy/bin/activate && pip install mypy types-cffi scipy-stubs . dolfinx-venv-mypy/bin/activate && mypy -p dolfinx . dolfinx-venv-mypy/bin/activate && mypy test -# . dolfinx-venv-mypy/bin/activate && mypy demo + . dolfinx-venv-mypy/bin/activate && mypy demo lint-mypy-clean: rm -rf dolfinx-venv-mypy diff --git a/python/demo/demo_pml.py b/python/demo/demo_pml.py index 27d4fb9464..c5634bf72d 100644 --- a/python/demo/demo_pml.py +++ b/python/demo/demo_pml.py @@ -214,8 +214,8 @@ def generate_mesh_wire( def compute_a(nu: int, m: complex, alpha: float) -> float: """Compute the Mie coefficient a_nu for a cylinder.""" - J_nu_alpha = jv(nu, alpha) - J_nu_malpha = jv(nu, m * alpha) + J_nu_alpha = jv(nu, alpha) # type: ignore + J_nu_malpha = jv(nu, m * alpha) # type: ignore J_nu_alpha_p = jvp(nu, alpha, 1) J_nu_malpha_p = jvp(nu, m * alpha, 1) diff --git a/python/demo/demo_pyamg.py b/python/demo/demo_pyamg.py index bf6e4e68c8..6027e028ce 100644 --- a/python/demo/demo_pyamg.py +++ b/python/demo/demo_pyamg.py @@ -63,7 +63,7 @@ def poisson_problem(dtype: npt.DTypeLike, solver_type: str) -> None: solver_type: pyamg solver type, either "ruge_stuben" or "smoothed_aggregation" """ - real_type = np.real(dtype(0)).dtype + real_type = np.real(dtype(0)).dtype # type: ignore mesh = create_box( comm=MPI.COMM_WORLD, points=[(0.0, 0.0, 0.0), (3.0, 2.0, 1.0)], @@ -84,7 +84,7 @@ def poisson_problem(dtype: npt.DTypeLike, solver_type: str) -> None: dofs = locate_dofs_topological(V=V, entity_dim=fdim, entities=facets) - bc = dirichletbc(value=dtype(0), dofs=dofs, V=V) + bc = dirichletbc(value=0.0, dofs=dofs, V=V) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) @@ -110,14 +110,14 @@ def poisson_problem(dtype: npt.DTypeLike, solver_type: str) -> None: print(ml) # Solve linear systems - print(f"\nSolve Poisson equation: {dtype.__name__}") + print(f"\nSolve Poisson equation: {dtype!s}") res: list[float] = [] tol = 1e-10 if real_type == np.float64 else 1e-6 uh.x.array[:] = ml.solve(b.array, tol=tol, residuals=res, accel="cg") for i, q in enumerate(res): print(f"Convergence history: iteration {i}, residual= {q}") - with io.XDMFFile(mesh.comm, f"out_pyamg/poisson_{dtype.__name__}.xdmf", "w") as file: + with io.XDMFFile(mesh.comm, f"out_pyamg/poisson_{dtype!s}.xdmf", "w") as file: file.write_mesh(mesh) file.write_function(uh) @@ -126,7 +126,7 @@ def poisson_problem(dtype: npt.DTypeLike, solver_type: str) -> None: # + -def nullspace_elasticty(Q: fem.FunctionSpace) -> list[np.ndarray]: +def nullspace_elasticty(Q: fem.FunctionSpace) -> npt.NDArray: """Create the elasticity (near)nulspace. Args: diff --git a/python/demo/demo_scattering_boundary_conditions.py b/python/demo/demo_scattering_boundary_conditions.py index f3bd735f6d..3c40b83574 100644 --- a/python/demo/demo_scattering_boundary_conditions.py +++ b/python/demo/demo_scattering_boundary_conditions.py @@ -220,8 +220,8 @@ def generate_mesh_wire( # + def compute_a(nu: int, m: complex, alpha: float) -> float: """Compute the a_nu coefficient.""" - J_nu_alpha = jv(nu, alpha) - J_nu_malpha = jv(nu, m * alpha) + J_nu_alpha = jv(nu, alpha) # type: ignore + J_nu_malpha = jv(nu, m * alpha) # type: ignore J_nu_alpha_p = jvp(nu, alpha, 1) J_nu_malpha_p = jvp(nu, m * alpha, 1) From ce1b91135aa93b5115dc653cfbd65250b072adbb Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:26:28 +0100 Subject: [PATCH 5/8] Fix --- python/demo/demo_pyamg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/demo/demo_pyamg.py b/python/demo/demo_pyamg.py index 6027e028ce..0da47e25ed 100644 --- a/python/demo/demo_pyamg.py +++ b/python/demo/demo_pyamg.py @@ -63,7 +63,7 @@ def poisson_problem(dtype: npt.DTypeLike, solver_type: str) -> None: solver_type: pyamg solver type, either "ruge_stuben" or "smoothed_aggregation" """ - real_type = np.real(dtype(0)).dtype # type: ignore + real_type = np.real(np.zeros(0, dtype=dtype)).dtype mesh = create_box( comm=MPI.COMM_WORLD, points=[(0.0, 0.0, 0.0), (3.0, 2.0, 1.0)], @@ -84,7 +84,7 @@ def poisson_problem(dtype: npt.DTypeLike, solver_type: str) -> None: dofs = locate_dofs_topological(V=V, entity_dim=fdim, entities=facets) - bc = dirichletbc(value=0.0, dofs=dofs, V=V) + bc = dirichletbc(value=dtype(0.0), dofs=dofs, V=V) # type: ignore u, v = ufl.TrialFunction(V), ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) From 7cf770bd5a39bebcbbbd9057fac171f4de5eb0a7 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 2 Apr 2026 12:39:34 +0200 Subject: [PATCH 6/8] Allow for 2/3 Python suffix --- python/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/Makefile b/python/Makefile index 88332551f5..b4ec8cb73e 100644 --- a/python/Makefile +++ b/python/Makefile @@ -1,6 +1,9 @@ # Note: mypy is currenlty on CI tested without petsc4py! + +PYTHON = python$(py) + lint-mypy: - python -m venv dolfinx-venv-mypy + $(PYTHON) -m venv dolfinx-venv-mypy . dolfinx-venv-mypy/bin/activate && pip install mypy types-cffi scipy-stubs . dolfinx-venv-mypy/bin/activate && mypy -p dolfinx . dolfinx-venv-mypy/bin/activate && mypy test From a5f47da9dcc85cfc228400c56a5f48aa99b4b7b9 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:42:42 +0200 Subject: [PATCH 7/8] remove --- .github/workflows/ccpp.yml | 10 ++++++++-- python/Makefile | 17 ----------------- 2 files changed, 8 insertions(+), 19 deletions(-) delete mode 100644 python/Makefile diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 21fe82f6f9..b24affa806 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -132,9 +132,15 @@ jobs: 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 + - name: Run mypy # Use a venv to avoid NumPy upgrades that are incompatible with numba working-directory: python - run: make lint-mypy + run: | + python -m venv mypy-env + . ./mypy-env/bin/activate + pip install mypy types-cffi scipy-stubs + mypy -p dolfinx + mypy test + mypy demo - name: Install gmsh and pyvista (and dependencies) run: | diff --git a/python/Makefile b/python/Makefile deleted file mode 100644 index b4ec8cb73e..0000000000 --- a/python/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# Note: mypy is currenlty on CI tested without petsc4py! - -PYTHON = python$(py) - -lint-mypy: - $(PYTHON) -m venv dolfinx-venv-mypy - . dolfinx-venv-mypy/bin/activate && pip install mypy types-cffi scipy-stubs - . dolfinx-venv-mypy/bin/activate && mypy -p dolfinx - . dolfinx-venv-mypy/bin/activate && mypy test - . dolfinx-venv-mypy/bin/activate && mypy demo - -lint-mypy-clean: - rm -rf dolfinx-venv-mypy - -lint: lint-mypy - -clean: lint-mypy-clean From 304a6b211b26be2938b630a6eb6b21e7daf41436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20T=2E=20K=C3=BChner?= <56360279+schnellerhase@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:48:31 +0200 Subject: [PATCH 8/8] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paul T. Kühner <56360279+schnellerhase@users.noreply.github.com> --- python/demo/demo_pyamg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/demo/demo_pyamg.py b/python/demo/demo_pyamg.py index 0da47e25ed..6708a1ff6e 100644 --- a/python/demo/demo_pyamg.py +++ b/python/demo/demo_pyamg.py @@ -63,7 +63,7 @@ def poisson_problem(dtype: npt.DTypeLike, solver_type: str) -> None: solver_type: pyamg solver type, either "ruge_stuben" or "smoothed_aggregation" """ - real_type = np.real(np.zeros(0, dtype=dtype)).dtype + real_type = np.real(dtype(0)).dtype # type: ignore mesh = create_box( comm=MPI.COMM_WORLD, points=[(0.0, 0.0, 0.0), (3.0, 2.0, 1.0)], @@ -84,7 +84,7 @@ def poisson_problem(dtype: npt.DTypeLike, solver_type: str) -> None: dofs = locate_dofs_topological(V=V, entity_dim=fdim, entities=facets) - bc = dirichletbc(value=dtype(0.0), dofs=dofs, V=V) # type: ignore + bc = dirichletbc(value=dtype(0), dofs=dofs, V=V) # type: ignore u, v = ufl.TrialFunction(V), ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh)