%global pypi_name surfa Name: python-%{pypi_name} Version: 0.6.3 Release: 4%{?dist} Summary: Utilities for medical image and surface processing License: MIT URL: https://github.com/freesurfer/surfa Source0: %{url}/archive/v%{version}/%{pypi_name}-%{version}.tar.gz # Upstream's NumPy 2 fixes after 0.6.3 (no release yet), cherry-picked onto v0.6.3: # 86c33ae 03d539f a94931c ea821ac eb13679 (its setup.py abi3 part left out) # 5e45fbd 8aa4a5f. Without them every .mgz read fails on numpy 2.4 (np.fromstring # binary mode removed) and crop_to_bbox fails (scipy find_objects on a bool mask). Patch0: python-surfa-numpy2.patch BuildRequires: gcc BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-wheel BuildRequires: python3-pip BuildRequires: python3-Cython >= 3.0 BuildRequires: python3-numpy BuildRequires: python3-scipy BuildRequires: python3-nibabel BuildRequires: python3-pillow BuildRequires: python3-xxhash %description Surfa is a collection of Python utilities for medical image analysis and mesh-based surface processing. It provides tools that operate on 3D image arrays and triangular meshes with consideration of their representation in a world (or scanner) coordinate system. %package -n python3-%{pypi_name} Summary: %{summary} Requires: python3-numpy Requires: python3-scipy Requires: python3-nibabel >= 2.1 Requires: python3-pillow Requires: python3-xxhash %description -n python3-%{pypi_name} Surfa is a collection of Python utilities for medical image analysis and mesh-based surface processing. %prep %autosetup -p1 -n %{pypi_name}-%{version} # Remove abi3 wheel tag override — build a normal platform wheel sed -i '/bdist_wheel_abi3/d' setup.py sed -i '/from wheel.bdist_wheel import bdist_wheel/d' setup.py sed -i '/class bdist_wheel_abi3/,/return python, abi, plat/d' setup.py sed -i 's/"cmdclass": {"bdist_wheel": bdist_wheel_abi3}//' setup.py sed -i '/Py_LIMITED_API/d' setup.py sed -i '/py_limited_api/d' setup.py %build %pyproject_wheel %install %pyproject_install %pyproject_save_files %{pypi_name} %check # Run from / to avoid source tree shadowing the installed package cd / PYTHONPATH=%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib} \ %{python3} -c "import surfa; print('surfa', surfa.__version__)" # An .mgz round trip, crop and resample: what FreeSurfer's Python tools do first. PYTHONPATH=%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib} \ %{python3} - << 'PYEOF' import os, tempfile import numpy as np import surfa as sf d = np.zeros((32, 32, 32), np.float32) d[8:20, 10:22, 5:25] = 1 v = sf.Volume(d) p = os.path.join(tempfile.mkdtemp(), 't.mgz') v.save(p) w = sf.load_volume(p) assert np.array_equal(w.data, d) assert w.crop_to_bbox().baseshape == (12, 12, 20) v.resample_like(sf.ImageGeometry((16, 16, 16), voxsize=2)) v.reorient('LIA') print('surfa mgz/crop/resample OK on numpy', np.__version__) PYEOF %files -n python3-%{pypi_name} -f %{pyproject_files} # License is MIT (declared in setup.py) but upstream has no standalone license file %changelog * Tue Oct 13 2026 Morgan Hough - 0.6.3-4 - Backport upstream's NumPy 2 fixes (seven commits after 0.6.3, unreleased). On F44's numpy 2.4.6 / scipy 1.16.2, 0.6.3 failed every .mgz read ("The binary mode of fromstring is removed") and crop_to_bbox ("'numpy.bool' object cannot be interpreted as an integer"), which broke FreeSurfer 8's Python tools. Found by neurospark's HBN recon-all on aarch64; reproduced on x86_64. - %%check now does an .mgz round trip, crop, resample and reorient. * Sun Sep 27 2026 Morgan Hough - 0.6.3-3 - Rebuild against f45's current numpy. The -2 build's compiled surfa.image.interp extension SEGFAULTS on import on f45. Nothing in the rpm dependencies can notice: a numpy ABI change moves no soname, so the package installs cleanly and dies at load -- the same shape as the VTK frozen-soname class this repo already tracks, in a different disguise. - Found via python3-samseg, which LOOKS like it crashes in PETSc. It does not. PETSc installs its own SIGSEGV handler, so when surfa faulted PETSc caught the signal and printed "Caught signal number 11 SEGV" with advice about debugging PETSc -- naming itself for someone else's fault. faulthandler gave the real chain: samseg -> surfa.transform.warp:6 -> surfa.image.framed:25 -> from surfa.image.interp import interpolate -> SIGSEGV Isolated one import per process: petsc4py rc=0, petsc4py.PETSc rc=0, numba rc=0, surfa rc=-11. On f44 (python 3.14) samseg imports fine and petsc4py is not installed at all. - The %%check here imports surfa and PASSED when -2 was built, which is the point rather than an oversight: a build-time import check cannot catch an ABI break that happens to the environment AFTER the build. * Fri Jun 12 2026 Morgan Hough - 0.6.3-2 - Rebuild for rawhide's Python 3.15 transition. The -1 build required python(abi)=3.14, blocking the rawhide SimNIBS chain (python-samseg BuildRequires python3-surfa and could not resolve on rawhide). * Tue Mar 10 2026 Morgan Hough - 0.6.3-1 - Initial package