Skip to content

Commit f171828

Browse files
committed
using input/output_spec_names instead of input/output_spec for BoshTask: this allows for providing subset of names that should be used, but type, help_string, etc. is taken from the zenodo spec file
1 parent 46ad553 commit f171828

File tree

2 files changed

+82
-31
lines changed

2 files changed

+82
-31
lines changed

pydra/engine/boutiques.py

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,13 @@
22
import json
33
import attr
44
from urllib.request import urlretrieve
5-
import subprocess as sp
6-
import os
75
from pathlib import Path
86
from functools import reduce
97

108
from ..utils.messenger import AuditFlag
119
from ..engine import ShellCommandTask
12-
from ..engine.specs import (
13-
SpecInfo,
14-
ShellSpec,
15-
ShellOutSpec,
16-
File,
17-
Directory,
18-
attr_fields,
19-
)
20-
from .helpers import ensure_list, execute
21-
from .helpers_file import template_update, is_local_file
10+
from ..engine.specs import SpecInfo, ShellSpec, ShellOutSpec, File, attr_fields
11+
from .helpers_file import is_local_file
2212

2313

2414
class BoshTask(ShellCommandTask):
@@ -30,11 +20,11 @@ def __init__(
3020
bosh_file=None,
3121
audit_flags: AuditFlag = AuditFlag.NONE,
3222
cache_dir=None,
33-
input_spec: ty.Optional[SpecInfo] = None,
23+
input_spec_names: ty.Optional[ty.List] = None,
3424
messenger_args=None,
3525
messengers=None,
3626
name=None,
37-
output_spec: ty.Optional[SpecInfo] = None,
27+
output_spec_names: ty.Optional[ty.List] = None,
3828
rerun=False,
3929
strip=False,
4030
**kwargs,
@@ -52,16 +42,16 @@ def __init__(
5242
Auditing configuration
5343
cache_dir : :obj:`os.pathlike`
5444
Cache directory
55-
input_spec : :obj:`pydra.engine.specs.SpecInfo`
56-
Specification of inputs.
45+
input_spec_names : :obj: list
46+
Input names for input_spec.
5747
messenger_args :
5848
TODO
5949
messengers :
6050
TODO
6151
name : :obj:`str`
6252
Name of this task.
63-
output_spec : :obj:`pydra.engine.specs.BaseSpec`
64-
Specification of inputs.
53+
output_spec_names : :obj: list
54+
Output names for output_spec.
6555
strip : :obj:`bool`
6656
TODO
6757
@@ -86,18 +76,14 @@ def __init__(
8676
if tries == tries_max:
8777
raise
8878

89-
if input_spec is None:
90-
input_spec = self._prepare_input_spec()
91-
self.input_spec = input_spec
92-
if output_spec is None:
93-
output_spec = self._prepare_output_spec()
94-
self.output_spec = output_spec
79+
self.input_spec = self._prepare_input_spec(names_subset=input_spec_names)
80+
self.output_spec = self._prepare_output_spec(names_subset=output_spec_names)
9581
self.bindings = ["-v", f"{self.bosh_file.parent}:{self.bosh_file.parent}:ro"]
9682

9783
super(BoshTask, self).__init__(
9884
name=name,
99-
input_spec=input_spec,
100-
output_spec=output_spec,
85+
input_spec=self.input_spec,
86+
output_spec=self.output_spec,
10187
executable=["bosh", "exec", "launch"],
10288
args=["-s"],
10389
audit_flags=audit_flags,
@@ -129,13 +115,21 @@ def _download_spec(self, zenodo_id):
129115
urlretrieve(zenodo_url, zenodo_file)
130116
return zenodo_file
131117

132-
def _prepare_input_spec(self):
133-
""" creating input spec from the zenodo file"""
118+
def _prepare_input_spec(self, names_subset=None):
119+
""" creating input spec from the zenodo file
120+
if name_subset provided, only names from the subset will be used in the spec
121+
"""
134122
binputs = self.bosh_spec["inputs"]
135123
self._input_spec_keys = {}
136124
fields = []
137125
for input in binputs:
138126
name = input["id"]
127+
if names_subset is None:
128+
pass
129+
elif name not in names_subset:
130+
continue
131+
else:
132+
names_subset.remove(name)
139133
if input["type"] == "File":
140134
tp = File
141135
elif input["type"] == "String":
@@ -157,16 +151,25 @@ def _prepare_input_spec(self):
157151
}
158152
fields.append((name, tp, mdata))
159153
self._input_spec_keys[input["value-key"]] = "{" + f"{name}" + "}"
160-
154+
if names_subset:
155+
raise RuntimeError(f"{names_subset} are not in the zenodo input spec")
161156
spec = SpecInfo(name="Inputs", fields=fields, bases=(ShellSpec,))
162157
return spec
163158

164-
def _prepare_output_spec(self):
165-
""" creating output spec from the zenodo file"""
159+
def _prepare_output_spec(self, names_subset=None):
160+
""" creating output spec from the zenodo file
161+
if name_subset provided, only names from the subset will be used in the spec
162+
"""
166163
boutputs = self.bosh_spec["output-files"]
167164
fields = []
168165
for output in boutputs:
169166
name = output["id"]
167+
if names_subset is None:
168+
pass
169+
elif name not in names_subset:
170+
continue
171+
else:
172+
names_subset.remove(name)
170173
path_template = reduce(
171174
lambda s, r: s.replace(*r),
172175
self._input_spec_keys.items(),
@@ -179,6 +182,8 @@ def _prepare_output_spec(self):
179182
}
180183
fields.append((name, attr.ib(type=File, metadata=mdata)))
181184

185+
if names_subset:
186+
raise RuntimeError(f"{names_subset} are not in the zenodo output spec")
182187
spec = SpecInfo(name="Outputs", fields=fields, bases=(ShellOutSpec,))
183188
return spec
184189

pydra/engine/tests/test_boutiques.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,52 @@ def test_boutiques_1(maskfile, plugin, results_function):
4747
assert not res.output.out_outskin_off.exists()
4848

4949

50+
@no_win
51+
@need_bosh_docker
52+
def test_boutiques_spec_1():
53+
""" testing spec: providing input/output fields names"""
54+
btask = BoshTask(
55+
name="NA",
56+
zenodo_id="1482743",
57+
infile=Infile,
58+
maskfile="test_brain.nii.gz",
59+
input_spec_names=["infile", "maskfile"],
60+
output_spec_names=["outfile", "out_outskin_off"],
61+
)
62+
63+
assert len(btask.input_spec.fields) == 2
64+
assert btask.input_spec.fields[0][0] == "infile"
65+
assert btask.input_spec.fields[1][0] == "maskfile"
66+
assert hasattr(btask.inputs, "infile")
67+
assert hasattr(btask.inputs, "maskfile")
68+
69+
assert len(btask.output_spec.fields) == 2
70+
assert btask.output_spec.fields[0][0] == "outfile"
71+
assert btask.output_spec.fields[1][0] == "out_outskin_off"
72+
73+
74+
@no_win
75+
@need_bosh_docker
76+
def test_boutiques_spec_2():
77+
""" testing spec: providing partial input/output fields names"""
78+
btask = BoshTask(
79+
name="NA",
80+
zenodo_id="1482743",
81+
infile=Infile,
82+
maskfile="test_brain.nii.gz",
83+
input_spec_names=["infile"],
84+
output_spec_names=[],
85+
)
86+
87+
assert len(btask.input_spec.fields) == 1
88+
assert btask.input_spec.fields[0][0] == "infile"
89+
assert hasattr(btask.inputs, "infile")
90+
# input doesn't see maskfile
91+
assert not hasattr(btask.inputs, "maskfile")
92+
93+
assert len(btask.output_spec.fields) == 0
94+
95+
5096
@no_win
5197
@need_bosh_docker
5298
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)