Skip to content

Commit 68cfa5d

Browse files
authored
Merge pull request #595 from ablachair/master
Handling input fields checking for Mandatory and Mutually exclusive fields
2 parents 66919ab + 5e0c249 commit 68cfa5d

File tree

2 files changed

+117
-3
lines changed

2 files changed

+117
-3
lines changed

pydra/engine/specs.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,21 @@ def check_fields_input_spec(self):
163163
# checking if the mandatory field is provided
164164
if getattr(self, fld.name) is attr.NOTHING:
165165
if mdata.get("mandatory"):
166-
raise AttributeError(
167-
f"{fld.name} is mandatory, but no value provided"
168-
)
166+
# checking if the mandatory field is provided elsewhere in the xor list
167+
in_exclusion_list = mdata.get("xor") is not None
168+
alreday_populated = in_exclusion_list and [
169+
getattr(self, el)
170+
for el in mdata["xor"]
171+
if (getattr(self, el) is not attr.NOTHING)
172+
]
173+
if (
174+
alreday_populated
175+
): # another input satisfies mandatory attribute via xor condition
176+
continue
177+
else:
178+
raise AttributeError(
179+
f"{fld.name} is mandatory, but no value provided"
180+
)
169181
else:
170182
continue
171183
names.append(fld.name)

pydra/engine/tests/test_specs.py

+102
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
DockerSpec,
1515
SingularitySpec,
1616
LazyField,
17+
ShellOutSpec,
1718
)
19+
from ..task import TaskBase, ShellCommandTask
1820
from ..helpers import make_klass
1921
import pytest
22+
import attr
2023

2124

2225
def test_basespec():
@@ -366,3 +369,102 @@ def test_input_file_hash_5(tmpdir):
366369
f.write("hi")
367370
hash3 = inputs(in_file=[{"file": file_diffcontent, "int": 3}]).hash
368371
assert hash1 != hash3
372+
373+
374+
class SimpleTask(ShellCommandTask):
375+
input_fields = [
376+
(
377+
"input_1",
378+
str,
379+
{
380+
"help_string": "help",
381+
"mandatory": True,
382+
"xor": ("input_1", "input_2", "input_3"),
383+
},
384+
),
385+
(
386+
"input_2",
387+
bool,
388+
{
389+
"help_string": "help",
390+
"mandatory": True,
391+
"argstr": "--i2",
392+
"xor": ("input_1", "input_2", "input_3"),
393+
},
394+
),
395+
(
396+
"input_3",
397+
bool,
398+
{
399+
"help_string": "help",
400+
"mandatory": True,
401+
"xor": ("input_1", "input_2", "input_3"),
402+
},
403+
),
404+
]
405+
task_input_spec = SpecInfo(name="Input", fields=input_fields, bases=(ShellSpec,))
406+
task_output_fields = []
407+
task_output_spec = SpecInfo(
408+
name="Output", fields=task_output_fields, bases=(ShellOutSpec,)
409+
)
410+
411+
input_spec = task_input_spec
412+
output_spec = task_output_spec
413+
executable = "cmd"
414+
415+
416+
def test_task_inputs_mandatory_with_xOR_one_mandatory_is_OK():
417+
"""input spec with mandatory inputs"""
418+
task = SimpleTask()
419+
task.inputs.input_1 = "Input1"
420+
task.inputs.input_2 = attr.NOTHING
421+
task.inputs.check_fields_input_spec()
422+
423+
424+
def test_task_inputs_mandatory_with_xOR_one_mandatory_out_3_is_OK():
425+
"""input spec with mandatory inputs"""
426+
task = SimpleTask()
427+
task.inputs.input_1 = attr.NOTHING
428+
task.inputs.input_2 = attr.NOTHING
429+
task.inputs.input_3 = True
430+
task.inputs.check_fields_input_spec()
431+
432+
433+
def test_task_inputs_mandatory_with_xOR_zero_mandatory_raises_error():
434+
"""input spec with mandatory inputs"""
435+
task = SimpleTask()
436+
task.inputs.input_1 = attr.NOTHING
437+
task.inputs.input_2 = attr.NOTHING
438+
with pytest.raises(Exception) as excinfo:
439+
task.inputs.check_fields_input_spec()
440+
assert "input_1 is mandatory, but no value provided" in str(excinfo.value)
441+
assert excinfo.type is AttributeError
442+
443+
444+
def test_task_inputs_mandatory_with_xOR_two_mandatories_raises_error():
445+
"""input spec with mandatory inputs"""
446+
task = SimpleTask()
447+
task.inputs.input_1 = "Input1"
448+
task.inputs.input_2 = True
449+
450+
with pytest.raises(Exception) as excinfo:
451+
task.inputs.check_fields_input_spec()
452+
assert "input_2 is mutually exclusive with ('input_1', 'input_2'" in str(
453+
excinfo.value
454+
)
455+
assert excinfo.type is AttributeError
456+
457+
458+
def test_task_inputs_mandatory_with_xOR_3_mandatories_raises_error():
459+
"""input spec with mandatory inputs"""
460+
task = SimpleTask()
461+
task.inputs.input_1 = "Input1"
462+
task.inputs.input_2 = True
463+
task.inputs.input_3 = False
464+
465+
with pytest.raises(Exception) as excinfo:
466+
task.inputs.check_fields_input_spec()
467+
assert "input_2 is mutually exclusive with ('input_1', 'input_2', 'input_3'" in str(
468+
excinfo.value
469+
)
470+
assert excinfo.type is AttributeError

0 commit comments

Comments
 (0)