Skip to content

Commit c1136a3

Browse files
committed
debugging interface conversions
1 parent fb38d6c commit c1136a3

File tree

39 files changed

+416
-214
lines changed

39 files changed

+416
-214
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ __pycache__
2222
/outputs
2323
/test-data
2424
/nipype2pydra/_version.py
25-
25+
/required-fileformats/**/_version.py

nipype2pydra/interface/base.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -683,23 +683,23 @@ def pydra_fld_output(self, field, name):
683683
pydra_metadata["callable"] = self.outputs.callables[name]
684684
return (pydra_type, pydra_metadata)
685685

686-
def function_callables(self):
687-
if not self.outputs.callables:
688-
return ""
689-
if not self.callables_module:
690-
raise Exception(
691-
"callables module must be provided if output_callables are set in the spec file"
692-
)
693-
fun_str = ""
694-
if list(set(self.outputs.callables.values())):
695-
fun_str = inspect.getsource(self.callables_module)
696-
# fun_names.sort()
697-
# for fun_nm in fun_names:
698-
# fun = getattr(self.callables_module, fun_nm)
699-
# fun_str += inspect.getsource(fun) + "\n"
700-
# list_outputs = getattr(self.callables_module, "_list_outputs")
701-
# fun_str += inspect.getsource(list_outputs) + "\n"
702-
return fun_str
686+
# def function_callables(self):
687+
# if not self.outputs.callables:
688+
# return ""
689+
# if not self.callables_module:
690+
# raise Exception(
691+
# "callables module must be provided if output_callables are set in the spec file"
692+
# )
693+
# fun_str = ""
694+
# if list(set(self.outputs.callables.values())):
695+
# fun_str = inspect.getsource(self.callables_module)
696+
# # fun_names.sort()
697+
# # for fun_nm in fun_names:
698+
# # fun = getattr(self.callables_module, fun_nm)
699+
# # fun_str += inspect.getsource(fun) + "\n"
700+
# # list_outputs = getattr(self.callables_module, "_list_outputs")
701+
# # fun_str += inspect.getsource(list_outputs) + "\n"
702+
# return fun_str
703703

704704
def pydra_type_converter(self, field, spec_type, name):
705705
"""converting types to types used in pydra"""

nipype2pydra/interface/python.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ def type2str(type_):
1818
return type_
1919
if type_ is ty.Any:
2020
return "ty.Any"
21-
elif hasattr(type_, "__name__"):
22-
return type_.__name__
21+
if origin := ty.get_origin(type_):
22+
return f"{type2str(origin)}[{', '.join(type2str(arg) for arg in ty.get_args(type_))}]"
23+
module_name = "ty." if type_.__module__ == "typing" else ""
24+
if hasattr(type_, "__name__"):
25+
return module_name + type_.__name__
2326
elif hasattr(type_, "__qualname__"):
24-
return type_.__qualname__
27+
return module_name + type_.__qualname__
2528
else:
2629
return str(type_).replace("typing.", "ty.")
2730

@@ -151,7 +154,9 @@ def generate_code(self, input_fields, nonstd_types, output_fields) -> ty.Tuple[
151154
assert method_body, "Neither `run_interface` and `list_outputs` are defined"
152155

153156
spec_str = "@python.define\n"
154-
spec_str += f"class {self.task_name}(python.Task['{self.task_name}.Outputs']):\n"
157+
spec_str += (
158+
f"class {self.task_name}(python.Task['{self.task_name}.Outputs']):\n"
159+
)
155160
spec_str += ' """\n'
156161
spec_str += self.create_doctests(
157162
input_fields=input_fields, nonstd_types=nonstd_types
@@ -181,14 +186,13 @@ def generate_code(self, input_fields, nonstd_types, output_fields) -> ty.Tuple[
181186
if any(t is not ty.Any for t in output_types):
182187
spec_str += " -> "
183188
if len(output_types) > 1:
184-
spec_str += "tuples[" + ", ".join(output_types) + "]"
189+
spec_str += "tuple[" + ", ".join(output_types) + "]"
185190
else:
186191
spec_str += output_types[0]
187192
spec_str += ":\n"
188193
spec_str += " " + method_body.replace("\n", "\n ") + "\n"
189194
spec_str += "\n return {}".format(", ".join(output_names))
190195

191-
192196
for m in sorted(self.used.methods, key=attrgetter("__name__")):
193197
if m.__name__ not in self.included_methods:
194198
spec_str += "\n\n" + self.process_method(

nipype2pydra/interface/shell.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ def generate_code(self, input_fields, nonstd_types, output_fields) -> str:
107107
name, _, __, mdata = inpt
108108
if "xor" in mdata:
109109
xor_sets.add(frozenset(list(mdata["xor"]) + [name]))
110-
if mdata.get("position", None) == 0:
110+
pos = mdata.get("position", None)
111+
if isinstance(pos, str):
112+
# convert string reprs (I think a mistake) to ints
113+
pos = mdata["position"] = int(pos)
114+
if pos == 0:
111115
has_zero_pos = True
112116

113117
# Increment positions if there is a zero position
@@ -164,6 +168,8 @@ def generate_code(self, input_fields, nonstd_types, output_fields) -> str:
164168
output_fields_str += (
165169
f" {name}: {type_to_str(type_)} = shell.out({', '.join(args)})\n"
166170
)
171+
if not output_fields_str:
172+
output_fields_str = " pass\n"
167173

168174
spec_str = (
169175
self.init_code

nipype2pydra/interface/tests/test_interface.py

Lines changed: 83 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,35 @@
2424
"ants-interfaces-ai",
2525
"ants-interfaces-measure_image_similarity",
2626
"ants-interfaces-threshold_image",
27-
"fsl-interfaces-prob_track_x2",
28-
"fsl-interfaces-flameo",
29-
"fsl-interfaces-make_dyadic_vectors",
27+
"fsl-interfaces-copy_geom",
28+
"fsl-interfaces-flirt",
29+
"fsl-interfaces-mcflirt",
30+
"fsl-interfaces-filmgls",
31+
"fsl-interfaces-topup",
32+
"fsl-interfaces-slice",
33+
"fsl-interfaces-apply_topup",
34+
"fsl-interfaces-tract_skeleton",
35+
"fsl-interfaces-smooth_estimate",
36+
"fsl-interfaces-apply_xfm",
3037
"fsl-interfaces-dual_regression",
31-
"fsl-interfaces-epi_de_warp",
38+
"fsl-interfaces-eddy",
39+
"fsl-interfaces-split",
40+
"freesurfer-interfaces-logan",
41+
"freesurfer-interfaces-mrtm1",
42+
"freesurfer-interfaces-mrtm2",
43+
"freesurfer-interfaces-concatenate_lta",
44+
"freesurfer-interfaces-one_sample_t_test",
45+
"freesurfer-interfaces-concatenate",
46+
"freesurfer-interfaces-mris_preproc_recon_all",
47+
"freesurfer-interfaces-recon_all",
48+
"freesurfer-interfaces-glm_fit",
49+
"freesurfer-interfaces-mri_convert",
50+
"freesurfer-interfaces-parcellation_stats",
51+
"freesurfer-interfaces-mp_rto_mni305",
52+
"afni-interfaces-qwarp_plus_minus",
53+
"afni-interfaces-qwarp",
54+
"afni-interfaces-align_epi_anat_py",
55+
"afni-interfaces-fwh_mx",
3256
]
3357

3458
XFAIL_INTERFACES_IN_COMBINED = [
@@ -48,10 +72,10 @@
4872
params=[
4973
str(p.relative_to(EXAMPLE_INTERFACES_DIR)).replace("/", "-")[:-5]
5074
for p in (EXAMPLE_INTERFACES_DIR).glob("**/interfaces/*.yaml")
51-
if (
52-
str(p.relative_to(EXAMPLE_INTERFACES_DIR)).replace("/", "-")[:-5]
53-
not in XFAIL_INTERFACES
54-
)
75+
# if (
76+
# str(p.relative_to(EXAMPLE_INTERFACES_DIR)).replace("/", "-")[:-5]
77+
# not in XFAIL_INTERFACES
78+
# )
5579
]
5680
)
5781
def interface_spec_file(request):
@@ -63,57 +87,56 @@ def interface_spec_file(request):
6387
def test_interface_convert(
6488
interface_spec_file, cli_runner, work_dir, gen_test_conftest
6589
):
66-
# Clear UsedSymbol caches
90+
# Clear UsedSymbol caches from previous tests
6791
clear_caches()
6892

69-
try:
70-
with open(interface_spec_file) as f:
71-
interface_spec = yaml.safe_load(f)
72-
pkg_root = work_dir / "src"
73-
pkg_root.mkdir()
74-
# shutil.copyfile(gen_test_conftest, pkg_root / "conftest.py")
75-
76-
pkg_converter = PackageConverter(
77-
name="nipype2pydratest."
78-
+ "_".join(
79-
interface_spec["nipype_module"].split(".")
80-
+ [interface_spec["task_name"]]
81-
),
82-
nipype_name=interface_spec["nipype_module"],
83-
interface_only=True,
84-
)
93+
with open(interface_spec_file) as f:
94+
interface_spec = yaml.safe_load(f)
95+
pkg_root = work_dir / "src"
96+
pkg_root.mkdir()
97+
# shutil.copyfile(gen_test_conftest, pkg_root / "conftest.py")
98+
99+
pkg_converter = PackageConverter(
100+
name="nipype2pydratest."
101+
+ "_".join(
102+
interface_spec["nipype_module"].split(".") + [interface_spec["task_name"]]
103+
),
104+
nipype_name=interface_spec["nipype_module"],
105+
interface_only=True,
106+
)
85107

86-
converter = pkg_converter.add_interface_from_spec(
87-
spec=interface_spec,
88-
# callables_file=interface_spec_file.parent
89-
# / (interface_spec_file.stem + "_callables.py"),
90-
)
108+
converter = pkg_converter.add_interface_from_spec(
109+
spec=interface_spec,
110+
# callables_file=interface_spec_file.parent
111+
# / (interface_spec_file.stem + "_callables.py"),
112+
)
91113

92-
converter.write(pkg_root)
93-
94-
nipype_ports = []
95-
intra_pkg_modules = defaultdict(set)
96-
97-
for _, klass in converter.used.imported_classes:
98-
address = full_address(klass)
99-
if address in pkg_converter.nipype_port_converters:
100-
nipype_ports.append(pkg_converter.nipype_port_converters[address])
101-
for _, func in converter.used.imported_funcs:
102-
if full_address(func) not in list(pkg_converter.workflows):
103-
intra_pkg_modules[func.__module__].add(func)
104-
105-
already_converted = set()
106-
for converter in tqdm(
107-
nipype_ports, "Porting interfaces from the core nipype package"
108-
):
109-
converter.write(
110-
pkg_root,
111-
already_converted=already_converted,
112-
)
114+
converter.write(pkg_root)
115+
116+
nipype_ports = []
117+
intra_pkg_modules = defaultdict(set)
118+
119+
for _, klass in converter.used.imported_classes:
120+
address = full_address(klass)
121+
if address in pkg_converter.nipype_port_converters:
122+
nipype_ports.append(pkg_converter.nipype_port_converters[address])
123+
for _, func in converter.used.imported_funcs:
124+
if full_address(func) not in list(pkg_converter.workflows):
125+
intra_pkg_modules[func.__module__].add(func)
126+
127+
already_converted = set()
128+
for converter in tqdm(
129+
nipype_ports, "Porting interfaces from the core nipype package"
130+
):
131+
converter.write(
132+
pkg_root,
133+
already_converted=already_converted,
134+
)
113135

114-
# Write any additional functions in other modules in the package
115-
pkg_converter.write_intra_pkg_modules(pkg_root, intra_pkg_modules)
136+
# Write any additional functions in other modules in the package
137+
pkg_converter.write_intra_pkg_modules(pkg_root, intra_pkg_modules)
116138

139+
try:
117140
with add_to_sys_path(pkg_root):
118141
try:
119142
pydra_module = import_module(converter.output_module)
@@ -202,7 +225,13 @@ def test_interface_convert(
202225

203226
# assert result.value == 0
204227
except Exception:
205-
task_name = interface_spec_file.parent.name + "-" + interface_spec_file.stem
228+
task_name = "-".join(
229+
[
230+
interface_spec_file.parent.parent.name,
231+
interface_spec_file.parent.name,
232+
interface_spec_file.stem,
233+
]
234+
)
206235
if task_name in XFAIL_INTERFACES or task_name in XFAIL_INTERFACES_IN_COMBINED:
207236
msg = f"Test for '{task_name}' is expected to fail:\n{format_exc()}"
208237
if task_name in XFAIL_INTERFACES_IN_COMBINED:

nipype2pydra/package.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -732,9 +732,7 @@ def nipype_port_converters(self) -> ty.Dict[str, interface.BaseInterfaceConverte
732732
+ "."
733733
+ to_snake_case(task_name)
734734
)
735-
converter = interface.get_converter(
736-
output_module=output_module, callables_module=callables_file, **spec
737-
)
735+
converter = interface.get_converter(output_module=output_module, **spec)
738736
converter.package = self
739737
converters[converter.full_address] = converter
740738

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
# file generated by setuptools_scm
1+
# file generated by setuptools-scm
22
# don't change, don't track in version control
3+
4+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5+
36
TYPE_CHECKING = False
47
if TYPE_CHECKING:
5-
from typing import Tuple, Union
8+
from typing import Tuple
9+
from typing import Union
10+
611
VERSION_TUPLE = Tuple[Union[int, str], ...]
712
else:
813
VERSION_TUPLE = object
@@ -12,5 +17,5 @@
1217
__version_tuple__: VERSION_TUPLE
1318
version_tuple: VERSION_TUPLE
1419

15-
__version__ = version = '0.2.3.dev42+gb9e3ee9.d20240226'
16-
__version_tuple__ = version_tuple = (0, 2, 3, 'dev42', 'gb9e3ee9.d20240226')
20+
__version__ = version = '0.4.5.dev37+gfb38d6c.d20250731'
21+
__version_tuple__ = version_tuple = (0, 4, 5, 'dev37', 'gfb38d6c.d20250731')
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
# file generated by setuptools_scm
1+
# file generated by setuptools-scm
22
# don't change, don't track in version control
3+
4+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5+
36
TYPE_CHECKING = False
47
if TYPE_CHECKING:
5-
from typing import Tuple, Union
8+
from typing import Tuple
9+
from typing import Union
10+
611
VERSION_TUPLE = Tuple[Union[int, str], ...]
712
else:
813
VERSION_TUPLE = object
@@ -12,5 +17,5 @@
1217
__version_tuple__: VERSION_TUPLE
1318
version_tuple: VERSION_TUPLE
1419

15-
__version__ = version = '0.2.3.dev42+gb9e3ee9.d20240226'
16-
__version_tuple__ = version_tuple = (0, 2, 3, 'dev42', 'gb9e3ee9.d20240226')
20+
__version__ = version = '0.4.5.dev37+gfb38d6c.d20250731'
21+
__version_tuple__ = version_tuple = (0, 4, 5, 'dev37', 'gfb38d6c.d20250731')
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
# file generated by setuptools_scm
1+
# file generated by setuptools-scm
22
# don't change, don't track in version control
3+
4+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5+
36
TYPE_CHECKING = False
47
if TYPE_CHECKING:
5-
from typing import Tuple, Union
8+
from typing import Tuple
9+
from typing import Union
10+
611
VERSION_TUPLE = Tuple[Union[int, str], ...]
712
else:
813
VERSION_TUPLE = object
@@ -12,5 +17,5 @@
1217
__version_tuple__: VERSION_TUPLE
1318
version_tuple: VERSION_TUPLE
1419

15-
__version__ = version = '0.2.3.dev42+gb9e3ee9.d20240226'
16-
__version_tuple__ = version_tuple = (0, 2, 3, 'dev42', 'gb9e3ee9.d20240226')
20+
__version__ = version = '0.4.5.dev37+gfb38d6c.d20250731'
21+
__version_tuple__ = version_tuple = (0, 4, 5, 'dev37', 'gfb38d6c.d20250731')
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
# file generated by setuptools_scm
1+
# file generated by setuptools-scm
22
# don't change, don't track in version control
3+
4+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5+
36
TYPE_CHECKING = False
47
if TYPE_CHECKING:
5-
from typing import Tuple, Union
8+
from typing import Tuple
9+
from typing import Union
10+
611
VERSION_TUPLE = Tuple[Union[int, str], ...]
712
else:
813
VERSION_TUPLE = object
@@ -12,5 +17,5 @@
1217
__version_tuple__: VERSION_TUPLE
1318
version_tuple: VERSION_TUPLE
1419

15-
__version__ = version = '0.2.3.dev42+gb9e3ee9.d20240226'
16-
__version_tuple__ = version_tuple = (0, 2, 3, 'dev42', 'gb9e3ee9.d20240226')
20+
__version__ = version = '0.4.5.dev37+gfb38d6c.d20250731'
21+
__version_tuple__ = version_tuple = (0, 4, 5, 'dev37', 'gfb38d6c.d20250731')

0 commit comments

Comments
 (0)