From 992d8733901490dbec17d588f3274f741725aa5b Mon Sep 17 00:00:00 2001 From: "Thomas G. Close" Date: Sat, 2 Aug 2025 13:16:27 +1000 Subject: [PATCH 1/2] added nipype.interfaces. prefix to nipype package generation spec --- example-specs/pkg-gen/nipype.yaml | 70 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/example-specs/pkg-gen/nipype.yaml b/example-specs/pkg-gen/nipype.yaml index fe1afe5..594db9c 100644 --- a/example-specs/pkg-gen/nipype.yaml +++ b/example-specs/pkg-gen/nipype.yaml @@ -1,4 +1,4 @@ -afni: +nipype.interfaces.afni: target_version: v25_2_06 interfaces: - nipype.interfaces.afni.model.Deconvolve @@ -81,7 +81,7 @@ afni: - nipype.interfaces.afni.utils.Axialize - nipype.interfaces.afni.utils.Zcat - nipype.interfaces.afni.utils.Zeropad -ants: +nipype.interfaces.ants: target_version: v2 interfaces: - nipype.interfaces.ants.legacy.antsIntroduction @@ -119,7 +119,7 @@ ants: - nipype.interfaces.ants.visualization.CreateTiledMosaic classes: - nipype.interfaces.ants.base.Info -brainsuite: +nipype.interfaces.brainsuite: target_version: v1_0 interfaces: - nipype.interfaces.brainsuite.brainsuite.Bse @@ -137,16 +137,16 @@ brainsuite: - nipype.interfaces.brainsuite.brainsuite.SVReg - nipype.interfaces.brainsuite.brainsuite.BDP - nipype.interfaces.brainsuite.brainsuite.ThicknessPVC -bru2nii: +nipype.interfaces.bru2nii: target_version: v1_0 interfaces: - nipype.interfaces.bru2nii.Bru2 -c3: +nipype.interfaces.c3: target_version: v1_0 interfaces: - nipype.interfaces.c3.C3dAffineTool - nipype.interfaces.c3.C3d -camino: +nipype.interfaces.camino: target_version: v1_0 interfaces: - nipype.interfaces.camino.calib.SFPICOCalibData @@ -183,19 +183,19 @@ camino: - nipype.interfaces.camino.odf.MESD - nipype.interfaces.camino.odf.SFPeaks - nipype.interfaces.camino.utils.ImageStats -camino2trackvis: +nipype.interfaces.camino2trackvis: target_version: v1_0 interfaces: - nipype.interfaces.camino2trackvis.convert.Camino2Trackvis - nipype.interfaces.camino2trackvis.convert.Trackvis2Camino -cat12: +nipype.interfaces.cat12: target_version: v1_0 interfaces: - nipype.interfaces.cat12.preprocess.CAT12Segment - nipype.interfaces.cat12.preprocess.CAT12SANLMDenoising - nipype.interfaces.cat12.surface.ExtractAdditionalSurfaceParameters - nipype.interfaces.cat12.surface.ExtractROIBasedSurfaceMeasures -cmtk: +nipype.interfaces.cmtk: target_version: v1_0 interfaces: - nipype.interfaces.cmtk.cmtk.CreateMatrix @@ -207,13 +207,13 @@ cmtk: - nipype.interfaces.cmtk.nx.NetworkXMetrics - nipype.interfaces.cmtk.nx.AverageNetworks - nipype.interfaces.cmtk.parcellation.Parcellate -dcm2nii: +nipype.interfaces.dcm2nii: target_version: v1_0 interfaces: - nipype.interfaces.dcm2nii.Info - nipype.interfaces.dcm2nii.Dcm2nii - nipype.interfaces.dcm2nii.Dcm2niix -dcmstack: +nipype.interfaces.dcmstack: target_version: v1_0 interfaces: - nipype.interfaces.dcmstack.NiftiGeneratorBase @@ -223,7 +223,7 @@ dcmstack: - nipype.interfaces.dcmstack.CopyMeta - nipype.interfaces.dcmstack.MergeNifti - nipype.interfaces.dcmstack.SplitNifti -diffusion_toolkit: +nipype.interfaces.diffusion_toolkit: target_version: v1_0 interfaces: - nipype.interfaces.diffusion_toolkit.dti.DTIRecon @@ -233,7 +233,7 @@ diffusion_toolkit: - nipype.interfaces.diffusion_toolkit.odf.ODFTracker - nipype.interfaces.diffusion_toolkit.postproc.SplineFilter - nipype.interfaces.diffusion_toolkit.postproc.TrackMerge -dipy: +nipype.interfaces.dipy: target_version: v1_0 interfaces: - nipype.interfaces.dipy.anisotropic_power.APMQball @@ -247,7 +247,7 @@ dipy: - nipype.interfaces.dipy.tensors.TensorMode - nipype.interfaces.dipy.tracks.TrackDensityMap - nipype.interfaces.dipy.tracks.StreamlineTractography -dtitk: +nipype.interfaces.dtitk: target_version: v1_0 interfaces: - nipype.interfaces.dtitk.registration.Rigid @@ -279,11 +279,11 @@ dtitk: - nipype.interfaces.dtitk.utils.TVAdjustVoxSpTask - nipype.interfaces.dtitk.utils.TVResampleTask - nipype.interfaces.dtitk.utils.TVtoolTask -dynamic_slicer: +nipype.interfaces.dynamic_slicer: target_version: v1_0 interfaces: - nipype.interfaces.dynamic_slicer.SlicerCommandLine -elastix: +nipype.interfaces.elastix: target_version: v1_0 interfaces: - nipype.interfaces.elastix.registration.Registration @@ -291,7 +291,7 @@ elastix: - nipype.interfaces.elastix.registration.AnalyzeWarp - nipype.interfaces.elastix.registration.PointsWarp - nipype.interfaces.elastix.utils.EditTransform -freesurfer: +nipype.interfaces.freesurfer: target_version: v8 interfaces: - nipype.interfaces.freesurfer.longitudinal.RobustTemplate @@ -383,7 +383,7 @@ freesurfer: - nipype.interfaces.freesurfer.utils.Apas2Aseg - nipype.interfaces.freesurfer.utils.MRIsExpand - nipype.interfaces.freesurfer.utils.LTAConvert -fsl: +nipype.interfaces.fsl: target_version: v6_0 interfaces: - nipype.interfaces.fsl.aroma.ICA_AROMA @@ -492,16 +492,16 @@ fsl: - nipype.interfaces.fsl.utils.MotionOutliers - nipype.interfaces.fsl.utils.Text2Vest - nipype.interfaces.fsl.utils.Vest2Text -image: +nipype.interfaces.image: target_version: v1_0 interfaces: - nipype.interfaces.image.Rescale - nipype.interfaces.image.Reorient -meshfix: +nipype.interfaces.meshfix: target_version: v1_0 interfaces: - nipype.interfaces.meshfix.MeshFix -minc: +nipype.interfaces.minc: target_version: v1_0 interfaces: - nipype.interfaces.minc.minc.Extract @@ -532,7 +532,7 @@ minc: - nipype.interfaces.minc.minc.BigAverage - nipype.interfaces.minc.minc.Reshape - nipype.interfaces.minc.minc.VolSymm -mipav: +nipype.interfaces.mipav: target_version: v1_0 interfaces: - nipype.interfaces.mipav.developer.JistLaminarVolumetricLayering @@ -553,14 +553,14 @@ mipav: - nipype.interfaces.mipav.developer.JistBrainPartialVolumeFilter - nipype.interfaces.mipav.developer.JistIntensityMp2rageMasking - nipype.interfaces.mipav.developer.MedicAlgorithmThresholdToBinaryMask -niftyfit: +nipype.interfaces.niftyfit: target_version: v1_0 interfaces: - nipype.interfaces.niftyfit.asl.FitAsl - nipype.interfaces.niftyfit.dwi.FitDwi - nipype.interfaces.niftyfit.dwi.DwiTool - nipype.interfaces.niftyfit.qt1.FitQt1 -niftyreg: +nipype.interfaces.niftyreg: target_version: v1_0 interfaces: - nipype.interfaces.niftyreg.reg.RegAladin @@ -571,7 +571,7 @@ niftyreg: - nipype.interfaces.niftyreg.regutils.RegAverage - nipype.interfaces.niftyreg.regutils.RegTransform - nipype.interfaces.niftyreg.regutils.RegMeasure -niftyseg: +nipype.interfaces.niftyseg: target_version: v1_0 interfaces: - nipype.interfaces.niftyseg.em.EM @@ -588,28 +588,28 @@ niftyseg: - nipype.interfaces.niftyseg.stats.StatsCommand - nipype.interfaces.niftyseg.stats.UnaryStats - nipype.interfaces.niftyseg.stats.BinaryStats -nilearn: +nipype.interfaces.nilearn: target_version: v1_0 interfaces: - nipype.interfaces.nilearn.NilearnBaseInterface - nipype.interfaces.nilearn.SignalExtraction -nitime: +nipype.interfaces.nitime: target_version: v1_0 interfaces: - nipype.interfaces.nitime.analysis.CoherenceAnalyzer -petpvc: +nipype.interfaces.petpvc: target_version: v1_0 interfaces: - nipype.interfaces.petpvc.PETPVC -quickshear: +nipype.interfaces.quickshear: target_version: v1_0 interfaces: - nipype.interfaces.quickshear.Quickshear -robex: +nipype.interfaces.robex: target_version: v1_0 interfaces: - nipype.interfaces.robex.preprocess.RobexSegment -semtools: +nipype.interfaces.semtools: target_version: v1_0 interfaces: - nipype.interfaces.semtools.brains.classify.BRAINSPosteriorToContinuousClass @@ -714,7 +714,7 @@ semtools: - nipype.interfaces.semtools.utilities.brains.ImageRegionPlotter - nipype.interfaces.semtools.utilities.brains.fcsv_to_hdf5 - nipype.interfaces.semtools.utilities.brains.FindCenterOfBrain -slicer: +nipype.interfaces.slicer: target_version: v1_0 interfaces: - nipype.interfaces.slicer.converters.DicomToNrrdConverter @@ -777,7 +777,7 @@ slicer: - nipype.interfaces.slicer.surface.LabelMapSmoothing - nipype.interfaces.slicer.surface.ModelMaker - nipype.interfaces.slicer.utilities.EMSegmentTransformToNewFormat -spm: +nipype.interfaces.spm: target_version: v1_0 interfaces: - nipype.interfaces.spm.model.Level1Design @@ -814,12 +814,12 @@ spm: - nipype.interfaces.spm.utils.ApplyInverseDeformation - nipype.interfaces.spm.utils.ResliceToReference - nipype.interfaces.spm.utils.DicomImport -vista: +nipype.interfaces.vista: target_version: v1_0 interfaces: - nipype.interfaces.vista.vista.Vnifti2Image - nipype.interfaces.vista.vista.VtoMat -workbench: +nipype.interfaces.workbench: target_version: v1_0 interfaces: - nipype.interfaces.workbench.cifti.CiftiSmooth From f2e6c3210e71c27f0feea9d88624267edb0b634f Mon Sep 17 00:00:00 2001 From: "Thomas G. Close" Date: Mon, 4 Aug 2025 11:12:08 +1000 Subject: [PATCH 2/2] fixed up sorting of inserted method args and xors for deterministic generation --- nipype2pydra/interface/base.py | 9 ++++----- nipype2pydra/interface/shell.py | 4 +++- nipype2pydra/package.py | 2 +- nipype2pydra/statements/imports.py | 5 ++++- nipype2pydra/workflow.py | 7 +++---- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/nipype2pydra/interface/base.py b/nipype2pydra/interface/base.py index 0284c6f..b239e58 100644 --- a/nipype2pydra/interface/base.py +++ b/nipype2pydra/interface/base.py @@ -1159,7 +1159,7 @@ def process_method( pass if "runtime" in args: args.remove("runtime") - args_to_add = list(self.used.method_args.get(method.__name__, [])) + list( + args_to_add = sorted(self.used.method_args.get(method.__name__, [])) + sorted( additional_args ) if args_to_add: @@ -1338,7 +1338,7 @@ def unwrap_nested_methods( ) # Insert additional arguments to the method call (which were previously # accessed via member attributes) - args_to_be_inserted = list(self.used.method_args[name]) + list( + args_to_be_inserted = sorted(self.used.method_args[name]) + sorted( additional_args ) try: @@ -1405,8 +1405,7 @@ def unwrap_nested_methods( "trait_modified", ] - CONFTEST = """ -# For debugging in IDE's don't catch raised exceptions and let the IDE + CONFTEST = """# For debugging in IDE's don't catch raised exceptions and let the IDE # break at it import os import pytest @@ -1423,7 +1422,7 @@ def pytest_internalerror(excinfo): raise excinfo.value # raise internal errors instead of capturing them def pytest_configure(config): - config.option.capture = 'no' # allow print statements to show up in the console + config.option.capture = "no" # allow print statements to show up in the console config.option.log_cli = True # show log messages in the console config.option.log_level = "INFO" # set the log level to INFO diff --git a/nipype2pydra/interface/shell.py b/nipype2pydra/interface/shell.py index d73524e..5a8dc7c 100644 --- a/nipype2pydra/interface/shell.py +++ b/nipype2pydra/interface/shell.py @@ -190,7 +190,9 @@ def generate_code(self, input_fields, nonstd_types, output_fields) -> str: spec_str += "@shell.define" if xor_sets: - spec_str += f"(xor={[list(x) for x in xor_sets]})" + spec_str += ( + f"(xor={[list(x) for x in sorted(tuple(sorted(s)) for s in xor_sets)]})" + ) spec_str += ( f"\nclass {self.task_name}(shell.Task['{self.task_name}.Outputs']):\n" ) diff --git a/nipype2pydra/package.py b/nipype2pydra/package.py index 7680cf1..7865855 100644 --- a/nipype2pydra/package.py +++ b/nipype2pydra/package.py @@ -708,7 +708,7 @@ def write_post_release_file(self, fspath: Path): src_pkg_version = "{src_pkg_version}" nipype2pydra_version = "{nipype2pydra_version}" post_release = "{post_release}" - """ +""" ) @classmethod diff --git a/nipype2pydra/statements/imports.py b/nipype2pydra/statements/imports.py index 208c5e7..92f682a 100644 --- a/nipype2pydra/statements/imports.py +++ b/nipype2pydra/statements/imports.py @@ -217,6 +217,9 @@ def __str__(self): if self.from_: imported_str = ", ".join(str(i) for i in sorted(self.imported.values())) module = self.translation if self.translation else self.from_ + # Drop trailing hidden module (e.g. '_local' from 'pathlib._local') + if module.split(".")[-1].startswith("_"): + module = ".".join(module.split(".")[:-1]) stmt_str = f"{self.indent}from {module} import {imported_str}" elif self.translation: stmt_str = f"{self.indent}import {self.translation}" @@ -614,7 +617,7 @@ def to_statement(self): def from_list_to_imports( - obj: ty.Union[ty.List[ExplicitImport], list] + obj: ty.Union[ty.List[ExplicitImport], list], ) -> ty.List[ExplicitImport]: if obj is None: return [] diff --git a/nipype2pydra/workflow.py b/nipype2pydra/workflow.py index fff775e..02791b3 100644 --- a/nipype2pydra/workflow.py +++ b/nipype2pydra/workflow.py @@ -44,7 +44,7 @@ def convert_node_prefixes( - nodes: ty.Union[ty.Dict[str, str], ty.Sequence[ty.Union[ty.Tuple[str, str], str]]] + nodes: ty.Union[ty.Dict[str, str], ty.Sequence[ty.Union[ty.Tuple[str, str], str]]], ) -> ty.Dict[str, str]: if isinstance(nodes, dict): nodes_it = nodes.items() @@ -1310,8 +1310,7 @@ def default_spec( ) return yaml_str - CONFTEST = """ -# For debugging in IDE's don't catch raised exceptions and let the IDE + CONFTEST = """# For debugging in IDE's don't catch raised exceptions and let the IDE # break at it import os import pytest @@ -1328,7 +1327,7 @@ def pytest_internalerror(excinfo): raise excinfo.value # raise internal errors instead of capturing them def pytest_configure(config): - config.option.capture = 'no' # allow print statements to show up in the console + config.option.capture = "no" # allow print statements to show up in the console config.option.log_cli = True # show log messages in the console config.option.log_level = "INFO" # set the log level to INFO