|
7 | 7 | import numpy as np
|
8 | 8 | from ... import logging
|
9 | 9 | from ..base import (traits, File, isdefined, LibraryBaseInterface,
|
10 |
| - BaseInterfaceInputSpec) |
| 10 | + BaseInterfaceInputSpec, TraitedSpec) |
11 | 11 |
|
12 | 12 | HAVE_DIPY = True
|
13 | 13 | try:
|
14 | 14 | import dipy
|
| 15 | + from dipy.workflows.base import IntrospectiveArgumentParser |
15 | 16 | except ImportError:
|
16 | 17 | HAVE_DIPY = False
|
17 | 18 |
|
@@ -75,3 +76,123 @@ def _gen_filename(self, name, ext=None):
|
75 | 76 | ext = fext
|
76 | 77 |
|
77 | 78 | return out_prefix + '_' + name + ext
|
| 79 | + |
| 80 | + |
| 81 | +def convert_to_traits_type(dipy_type, is_file=False): |
| 82 | + """Convert DIPY type to Traits type.""" |
| 83 | + dipy_type = dipy_type.lower() |
| 84 | + is_mandatory = bool("optional" not in dipy_type) |
| 85 | + if "variable" in dipy_type and "string" in dipy_type: |
| 86 | + return traits.ListStr, is_mandatory |
| 87 | + elif "variable" in dipy_type and "int" in dipy_type: |
| 88 | + return traits.ListInt, is_mandatory |
| 89 | + elif "variable" in dipy_type and "float" in dipy_type: |
| 90 | + return traits.ListFloat, is_mandatory |
| 91 | + elif "variable" in dipy_type and "bool" in dipy_type: |
| 92 | + return traits.ListBool, is_mandatory |
| 93 | + elif "variable" in dipy_type and "complex" in dipy_type: |
| 94 | + return traits.ListComplex, is_mandatory |
| 95 | + elif "string" in dipy_type and not is_file: |
| 96 | + return traits.Str, is_mandatory |
| 97 | + elif "string" in dipy_type and is_file: |
| 98 | + return traits.File, is_mandatory |
| 99 | + elif "int" in dipy_type: |
| 100 | + return traits.Int, is_mandatory |
| 101 | + elif "float" in dipy_type: |
| 102 | + return traits.Float, is_mandatory |
| 103 | + elif "bool" in dipy_type: |
| 104 | + return traits.Bool, is_mandatory |
| 105 | + elif "complex" in dipy_type: |
| 106 | + return traits.Complex, is_mandatory |
| 107 | + else: |
| 108 | + msg = "Error during convert_to_traits_type({0}).".format(dipy_type) + \ |
| 109 | + "Unknown DIPY type." |
| 110 | + raise IOError(msg) |
| 111 | + |
| 112 | + |
| 113 | +def create_interface_specs(class_name, params=None, BaseClass=TraitedSpec): |
| 114 | + """Create IN/Out interface specifications dynamically. |
| 115 | +
|
| 116 | + Parameters |
| 117 | + ---------- |
| 118 | + class_name: str |
| 119 | + The future class name(e.g, (MyClassInSpec)) |
| 120 | + params: list of tuple |
| 121 | + dipy argument list |
| 122 | + BaseClass: TraitedSpec object |
| 123 | + parent class |
| 124 | +
|
| 125 | + Returns |
| 126 | + ------- |
| 127 | + newclass: object |
| 128 | + new nipype interface specification class |
| 129 | +
|
| 130 | + """ |
| 131 | + attr = {} |
| 132 | + if params is not None: |
| 133 | + for name, dipy_type, desc in params: |
| 134 | + is_file = bool("files" in name or "out_" in name) |
| 135 | + traits_type, is_mandatory = convert_to_traits_type(dipy_type, |
| 136 | + is_file) |
| 137 | + # print(name, dipy_type, desc, is_file, traits_type, is_mandatory) |
| 138 | + if isinstance(BaseClass, BaseInterfaceInputSpec): |
| 139 | + attr[name] = traits_type(desc=desc[-1], mandatory=is_mandatory) |
| 140 | + else: |
| 141 | + attr[name] = traits_type(desc=desc[-1], exists=True) |
| 142 | + |
| 143 | + newclass = type(class_name, (BaseClass, ), attr) |
| 144 | + return newclass |
| 145 | + |
| 146 | + |
| 147 | +def dipy_to_nipype_interface(cls_name, dipy_flow, BaseClass=DipyBaseInterface): |
| 148 | + """Construct a class in order to respect nipype interface specifications. |
| 149 | +
|
| 150 | + This convenient class factory convert a DIPY Workflow to a nipype |
| 151 | + interface. |
| 152 | +
|
| 153 | + Parameters |
| 154 | + ---------- |
| 155 | + cls_name: string |
| 156 | + new class name |
| 157 | + dipy_flow: Workflow class type. |
| 158 | + It should be any children class of `dipy.workflows.workflow.Worflow` |
| 159 | + BaseClass: object |
| 160 | + nipype instance object |
| 161 | +
|
| 162 | + Returns |
| 163 | + ------- |
| 164 | + newclass: object |
| 165 | + new nipype interface specification class |
| 166 | +
|
| 167 | + """ |
| 168 | + parser = IntrospectiveArgumentParser() |
| 169 | + parser.add_workflow(dipy_flow()) |
| 170 | + input_parameters = parser.positional_parameters + parser.optional_parameters |
| 171 | + |
| 172 | + input_spec = create_interface_specs("{}InputSpec".format(cls_name), |
| 173 | + input_parameters, |
| 174 | + BaseClass=BaseInterfaceInputSpec) |
| 175 | + |
| 176 | + output_spec = create_interface_specs("{}OutputSpec".format(cls_name), |
| 177 | + parser.output_parameters, |
| 178 | + BaseClass=TraitedSpec) |
| 179 | + |
| 180 | + def _run_interface(self, runtime): |
| 181 | + flow = dipy_flow() |
| 182 | + args = self.inputs.get() |
| 183 | + flow.run(**args) |
| 184 | + |
| 185 | + def _list_outputs(self): |
| 186 | + outputs = self._outputs().get() |
| 187 | + out_dir = outputs.get("out_dir", ".") |
| 188 | + for key, values in outputs.items(): |
| 189 | + outputs[key] = op.join(out_dir, values) |
| 190 | + |
| 191 | + return outputs |
| 192 | + |
| 193 | + newclass = type(cls_name, (BaseClass, ), |
| 194 | + {"input_spec": input_spec, |
| 195 | + "output_spec": output_spec, |
| 196 | + "_run_interface": _run_interface, |
| 197 | + "_list_outputs:": _list_outputs}) |
| 198 | + return newclass |
0 commit comments