Skip to content

Meta-interface to wrap optionally executing interface #2416

Open
@effigies

Description

@effigies

Any interest in adding a meta-interface like the following?

class OptionalInterface(SimpleInterface):
    def __init__(self, real_interface):
        class input_spec(real_interface.__class__.input_spec):
            pass
        class output_spec(real_interface.__class__.output_spec):
            pass

        self._interface = real_interface
        self.input_spec = input_spec
        self.output_spec = output_spec
        self._mandatory = [name for name, trait in input_spec.__class_traits__.items()
                           if trait.mandatory]

        for name in self._mandatory:
            trait = deepcopy(input_spec.__class_traits__[name])
            trait.mandatory = False
            self.input_spec.__base_traits__[name] = trait
            self.input_spec.__class_traits__[name] = trait

        super(OptionalInterface, self).__init__()
        self.inputs.trait_set(**self._interface.inputs.get_traitsfree())

    def _run_interface(self, runtime):
        do_run = all(isdefined(getattr(self.inputs, trait)) for trait in self._mandatory)

        if do_run:
            self._interface.inputs.set(**self.inputs.get_traitsfree())
            runtime = self._interface._run_interface(runtime)
            self._results.update(self._interface.aggregate_outputs(runtime).get_traitsfree())

        return runtime

This wraps an interface such that, if the mandatory inputs are not set, the outputs are left undefined.

I'm currently thinking of it for the purposes of inserting a validation step for an optional input to another node that always run, but it could also be chained to set up a part of a pipeline that will only execute if an input is present, but will silently pass Undefineds otherwise.

This is an initial hack, and some of the above might not be necessary. Currently testing with the following code:

class A(SimpleInterface):                              
     class input_spec(BaseInterfaceInputSpec):
         a = traits.Int(mandatory=True)
         b = traits.Int()
     class output_spec(TraitedSpec):
         c = traits.Int()
     def _run_interface(self, runtime):
         self._results['c'] = self.inputs.a + (self.inputs.b if isdefined(self.inputs.b) else 0)
         return runtime
In [1]: a = A(b=2)

In [2]: a.run().outputs
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
...

In [3]: b = OptionalInterface(A(b=2))

In [4]: b.run().outputs
Out[4]: 

c = <undefined>

In [5]: b.inputs.a = 5

In [6]: b.run().outputs
Out[6]: 

c = 7

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions