# SlicerPipelines ("Pipelines") — build simple 3D Slicer modules by chaining # existing ones through a GUI, with no coding. Provides the PipelineCreator # Python API (`slicerPipeline`, `PipelineProgressCallback`) that other # extensions' generated modules import: SlicerSkeletalRepresentation's # SRepCreateAndRefine is a PipelineCreator-generated module and does not load # without it. # # Pure Python: three scripted modules, no compiled code anywhere in the tree. # EXTENSION_DEPENDS is "NA" — no other Slicer extension is required. # # Upstream has no tags; pin the commit. %global commit 5fbd4a26e36d2c6f49da9af986593a62e053c2a6 %global shortcommit %(c=%{commit}; echo ${c:0:8}) %global snapdate 20240423 # Scripted-only extension: nothing is compiled, so the debuginfo machinery finds # no sources and dies on an empty debugsourcefiles.list. %global debug_package %{nil} %global slicer_inst %{_prefix}/lib/slicer %global slicer_subdir Slicer-5.12 Name: 3dslicer-pipelines Version: 1.0 Release: 0.5.%{snapdate}git%{shortcommit}%{?dist} Summary: GUI-built processing pipelines for 3D Slicer (PipelineCreator) License: Apache-2.0 URL: https://github.com/KitwareMedical/SlicerPipelines Source0: %{url}/archive/%{commit}/SlicerPipelines-%{shortcommit}.tar.gz # Two regex literals written as non-raw strings, so \s, \W and \d are unrecognised # escapes. Correct today -- re interprets the surviving backslash -- but Python has # announced these become SyntaxError rather than SyntaxWarning, at which point both # modules stop importing. They are also the first thing printed by every headless # Slicer startup. Reported by fedora-framework from a gui-smoke log. Patch20: 3dslicer-pipelines-raw-regex-strings.patch # Scripted-only extension, but the Slicer module-install machinery is CMake and # the install layout is arch-specific (%%{_lib}), so this is not noarch. BuildRequires: cmake >= 3.13.4 BuildRequires: ninja-build BuildRequires: gcc-c++ BuildRequires: python3-devel BuildRequires: 3dslicer-devel >= 5.12.1 # find_package(Slicer) demands the full Qt6 set even for a scripted-only # extension. BuildRequires: cmake(Qt6Core) BuildRequires: cmake(Qt6Gui) BuildRequires: cmake(Qt6Widgets) BuildRequires: cmake(Qt6Network) BuildRequires: cmake(Qt6Sql) BuildRequires: cmake(Qt6Svg) BuildRequires: cmake(Qt6Xml) BuildRequires: cmake(Qt6OpenGL) BuildRequires: cmake(Qt6OpenGLWidgets) BuildRequires: cmake(Qt6PrintSupport) BuildRequires: cmake(Qt6Multimedia) BuildRequires: cmake(Qt6MultimediaWidgets) BuildRequires: cmake(Qt6Core5Compat) BuildRequires: cmake(Qt6StateMachine) BuildRequires: cmake(Qt6WebEngineCore) BuildRequires: cmake(Qt6WebEngineWidgets) BuildRequires: cmake(Qt6WebChannel) BuildRequires: cmake(Qt6Qml) BuildRequires: cmake(Qt6Quick) BuildRequires: cmake(Qt6QuickWidgets) BuildRequires: cmake(Qt6Test) BuildRequires: cmake(Qt6UiTools) BuildRequires: qt6-qttools-devel BuildRequires: InsightToolkit5-devel >= 5.4.6-7 BuildRequires: vtk-devel >= 9.6 BuildRequires: ctk-devel BuildRequires: qttesting-devel BuildRequires: vtkAddon-devel BuildRequires: qRestAPI-devel BuildRequires: python-pythonqt-devel BuildRequires: commontk-applauncher-devel BuildRequires: dcmtk-devel BuildRequires: SlicerExecutionModel-devel BuildRequires: rapidjson-devel BuildRequires: libcurl-devel BuildRequires: jsoncpp-devel # Loading the foundation SlicerConfig.cmake triggers find_package(Teem). BuildRequires: teem-devel Requires: 3dslicer # Its only third-party Python import. Upstream self-installs it with # slicer.util.pip_install on ImportError; we satisfy it from the distro instead # (see %%prep). Requires: python3-networkx # Pin the exact VTK ABI this package was built against. VTK freezes its soname at # libvtk*.so.1 across all of 9.x, so rpm cannot tell 9.5 from 9.6 from 9.7: a consumer # built against one installs cleanly against another and fails at LOAD with undefined # symbols. A >= floor does not help -- 9.7.0 satisfies >= 9.6.2 -- so this is an exact # match. %%vtk_abi comes from vtk-devel's macros.vtk, so it re-pins on every rebuild. # # The missing-macro check lives in %%build, deliberately, NOT at parse time. A # parse-time %%error cannot distinguish "COPR is generating the SRPM" from "this is a # real buildroot": rpkg srpm parses the spec with no buildroot and therefore no # vtk-devel, so a parse-time guard killed every SCM build of every guarded package # before any chroot existed (python-simpleitk 10980296 failed in 0 minutes with # "can't parse specfile"). Expanding to UNSET keeps the SRPM parse alive, and the # %%build test still fails loudly in a buildroot lacking vtk-devel, so no RPM carrying # the placeholder can ever be produced. Requires: vtk(abi) = %{?vtk_abi}%{!?vtk_abi:UNSET} %description SlicerPipelines lets you assemble a new 3D Slicer module by chaining existing modules together in a GUI, with no code: pick a sequence of steps, wire their inputs and outputs, and the extension generates a working scripted module from it. It also ships PipelineCaseIterator for running a pipeline in batch over a directory of cases. Beyond the GUI it provides the PipelineCreator Python API (the slicerPipeline decorator and PipelineProgressCallback) that pipeline-generated modules import at load time, so it is a runtime prerequisite for other extensions that ship such modules — notably SlicerSkeletalRepresentation's SRepCreateAndRefine. %prep %autosetup -p1 -n SlicerPipelines-%{commit} # Post-condition for Patch20. autosetup shipped without -p1 once, at which point # patch could not find the file at all; the only reason that was caught is that it # also failed the build. Assert the EFFECT rather than the application: the whole # point of this patch is that the file compiles clean, so compile it here and # require zero SyntaxWarnings. python3 - <<'PYEOF' import pathlib, warnings files = ["PipelineCaseIterator/PipelineCaseIterator.py", "PipelineCreator/_PipelineCreator/PipelineCreation/CodeGeneration/logic.py"] bad = [] for f in files: src = pathlib.Path(f).read_text(encoding="utf-8") with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") compile(src, f, "exec") msgs = [str(x.message) for x in w if issubclass(x.category, SyntaxWarning)] if msgs: bad.append((f, sorted(set(msgs)))) assert not bad, "SyntaxWarnings remain after the patch: " + str(bad) print("compile-clean, zero SyntaxWarnings:", ", ".join(files)) PYEOF # Distro build: install modules directly rather than as an Extension-Manager # bundle, so skip SlicerExtensionCPack (it wants an s4ext template the install # tree does not ship). sed -i '/include(${Slicer_EXTENSION_CPACK})/d' CMakeLists.txt # PipelineCreator.py self-heals a missing networkx by calling # slicer.util.pip_install("networkx") at import. In an RPM that is wrong twice # over: it needs network at first import, and it would try to write into a # read-only /usr (it fails outright headless, where PythonSlicer is not on the # path). networkx is a proper Requires, so let the import speak for itself. python3 - <<'PYEOF' p = "PipelineCreator/PipelineCreator.py" s = open(p, encoding="utf-8").read() old = ( "try:\n" " import networkx as nx\n" "except ImportError:\n" " import slicer\n" " slicer.util.pip_install(\"networkx\")\n" " import networkx as nx\n" ) new = "import networkx as nx\n" assert old in s, "networkx pip_install bootstrap not found (upstream changed?)" open(p, "w", encoding="utf-8").write(s.replace(old, new, 1)) print("replaced the networkx pip_install bootstrap with a plain import") PYEOF # PipelineModules imports four wrapping modules at module scope, one of which # does `from SurfaceToolbox import SurfaceToolboxLogic`. SurfaceToolbox was a # CORE Slicer scripted module when this commit was made (2024-04-23), but it left # core in Slicer 5.12 -- the 5.12.1 tarball keeps only its documentation page, # and the code now lives in the separate SlicerSurfaceToolbox extension. The # module-scope import therefore takes the whole of PipelineModules down with it. # The four wrappings are independent (each merely registers @slicerPipeline # steps), so make this one optional: Segmentations, SegmentEditor and vtk # wrappings keep working, and only the SurfaceToolbox pipeline steps go missing. # Packaging SlicerSurfaceToolbox would bring them back. python3 - <<'PYEOF' p = "PipelineModules/PipelineModules.py" s = open(p, encoding="utf-8").read() old = ( "from _PipelineModules import (\n" " SegmentationsWrapping,\n" " SegmentEditorWrapping,\n" " SurfaceToolboxWrapping,\n" " vtkWrapping,\n" ")\n" ) new = ( "from _PipelineModules import (\n" " SegmentationsWrapping,\n" " SegmentEditorWrapping,\n" " vtkWrapping,\n" ")\n" "\n" "# SurfaceToolbox left Slicer core in 5.12 and is now its own extension; its\n" "# wrapping is optional so the other three still register.\n" "try:\n" " from _PipelineModules import SurfaceToolboxWrapping # noqa: F401\n" "except ImportError:\n" " import logging\n" " logging.info(\n" " 'PipelineModules: SurfaceToolbox not available, skipping its pipeline'\n" " ' steps (install the SurfaceToolbox extension to enable them).')\n" ) assert old in s, "PipelineModules wrapping import block not found (upstream changed?)" open(p, "w", encoding="utf-8").write(s.replace(old, new, 1)) print("made the SurfaceToolbox wrapping import optional") PYEOF %build # vtk_abi comes from vtk-devel's macros.vtk. Absent means BuildRequires: vtk-devel is # missing, and the Requires above would ship as the vacuous "vtk(abi) = UNSET". test -n "%{?vtk_abi}" || { echo "ERROR: vtk_abi undefined - add 'BuildRequires: vtk-devel'" >&2; exit 1; } %cmake -G Ninja \ -DSlicer_DIR:PATH=%{slicer_inst}/lib/%{slicer_subdir} \ -DTeem_DIR:PATH=%{_libdir}/cmake \ -DBUILD_TESTING:BOOL=OFF \ -DSlicer_SKIP_SlicerBlockAdditionalLauncherSettings:BOOL=TRUE \ -DCMAKE_INSTALL_PREFIX:PATH=%{slicer_inst} %cmake_build %install %cmake_install # Catch-all file list (files + symlinks only, so the shared module dirs that # 3dslicer owns are never claimed). ( cd %{buildroot} && find . \( -type f -o -type l \) | sed 's|^\.||' ) \ > %{_builddir}/pipelines.files %files -f %{_builddir}/pipelines.files %license LICENSE %doc README.md %changelog * Tue Sep 29 2026 Morgan Hough - 1.0-0.5.20240423git5fbd4a26 - Apply Patch20 with -p1. autosetup was declared without it, so patch defaulted to -p0 and skipped both files ("No file to patch", twice) -- the build failed in %prep on both chroots (11047458). The patch and its paths were always correct. - Assert the post-condition too: compile both patched files in %prep and require zero SyntaxWarnings, so a patch that applies but changes nothing cannot pass. * Mon Sep 28 2026 Morgan Hough - 1.0-0.4.20240423git5fbd4a26 - Patch20 makes two regex literals raw strings. PipelineCaseIterator.py:611 and CodeGeneration/logic.py:61 write regexes as ordinary strings containing \s, \W and \d, so Python warns on every compile -- they are literally the first thing printed by `Slicer --no-main-window --exit-after-startup`. Behaviour is correct today because re interprets the surviving backslash, but Python has announced these become SyntaxError rather than SyntaxWarning, at which point both modules stop importing. The patterns are byte identical after the change. - Reported by the fedora-framework session from a headless startup log while they were validating unrelated harness changes. * Sun Aug 23 2026 Morgan Hough - 1.0-0.3.20240423git5fbd4a26 - Rebuild against VTK 9.7.0. VTK here installs unversioned sonames (libvtk*.so.1), so 9.7 replaces 9.6 in place and every consumer must be rebuilt or it fails at runtime with undefined symbols. * Thu Jul 30 2026 Morgan Hough - 1.0-0.2.20240423git5fbd4a26 - Make PipelineModules load on Slicer 5.12. It imports four wrapping modules at module scope, one of which does 'from SurfaceToolbox import SurfaceToolboxLogic'. SurfaceToolbox was a CORE scripted module when this commit was cut (2024-04-23) but left core in Slicer 5.12 -- the 5.12.1 tarball retains only its documentation page and the code now lives in the separate SlicerSurfaceToolbox extension. The module-scope import took all of PipelineModules down with it. The four wrappings are independent, so make this one optional: Segmentations, SegmentEditor and vtk wrappings still register and only the SurfaceToolbox pipeline steps go missing. Packaging SlicerSurfaceToolbox would restore them. Caught by the CDash modules-all-instantiated check immediately after -0.1 was installed. * Mon Jul 27 2026 Morgan Hough - 1.0-0.1.20240423git5fbd4a26 - Initial package, pinned to commit 5fbd4a26 (upstream has no tags). - Packaged to fix SlicerSkeletalRepresentation's SRepCreateAndRefine, a PipelineCreator-generated module that fails to instantiate without the PipelineCreator Python API. - Replace the slicer.util.pip_install("networkx") bootstrap with a plain import backed by Requires: python3-networkx.