populse / capsul

Collaborative Analysis Platform : Simple, Unifying, Lean
Other
7 stars 14 forks source link

Nipype traits in capsul #316

Closed Hboni closed 7 months ago

Hboni commented 8 months ago

I wanted to use nipype fonctions to run spm commands as NewSegment. One of the input parameters of this function is "channel_info (a tuple of the form: (a float, a float, a tuple of the form: (a boolean, a boolean)))".

However, when I tried to use it inside a capsul v3 pipeline, I get a TraitError on channel_info :

traits.trait_errors.TraitError: The 'channel_info' trait of a NewSegmentInputSpec instance must be a tuple of the form: (a float, a float, a tuple of the form: (a boolean, a boolean)), but a value of (0.0001, 60, [True, True])  was specified.

This happened even if I set channel_info value as .channel_info = (0.0001, 60., (True, True)). The Tuple inside the Tuple is not considered as Tuple.

After looking more precisely on NewSegment input traits type for channel_info, we saw that it is only a Tuple (and not a tuple[float, float, tuple[bool, bool]] as it is asked by the documentation). That explains why capsul cannot recast list inside tuple as a tuple, as it does have no idea that a tuple is required.

I am going to make a workaround by creating my own process that can broadcast this parameter types to the good one, but it may be needed for several nipype functions..

denisri commented 8 months ago

Crap. That defeats the automatic wrapping principle :( mia_processes also provides nipype/spm customized wrappings, but using the populse_mia Process overloads.

sapetnioc commented 8 months ago

I had a look at the definition of the channel_info trait in the NewSegment Nypipe interface. It is not a simple tuple but contains inner types:

    channel_info = traits.Tuple(
        traits.Float(),
        traits.Float(),
        traits.Tuple(traits.Bool, traits.Bool),
        desc="""A tuple with the following fields:
            - bias reguralisation (0-10)
            - FWHM of Gaussian smoothness of bias
            - which maps to save (Field, Corrected) - a tuple of two boolean values""",
        field="channel",
    )

But, if I remember well, Capsul's trait_to_field() simply returns tuple for this trait type. I should be possible to fix that.

Hboni commented 8 months ago

Yeah, we looked at traits of NewSegment parameters, and we found tuple for the trait, but nothin in inner_traits, maybe the info is elsewhere.

sapetnioc commented 8 months ago

The info is directly in the types attribute. I made a small change and the following code is now printing tuple[float, float, tuple]. The second level of subtypes is not taken into account but it may already solve the problem:

from nipype.interfaces.base import traits
from capsul.process.nipype_process import trait_to_field

channel_info = traits.Tuple(
   traits.Float(),
   traits.Float(),
   traits.Tuple(traits.Bool, traits.Bool),
   desc="""A tuple with the following fields:
       - bias reguralisation (0-10)
       - FWHM of Gaussian smoothness of bias
       - which maps to save (Field, Corrected) - a tuple of two boolean values""",
   field="channel",
)

field = trait_to_field(channel_info)
print(field.type)
Hboni commented 8 months ago

I pull your last modifications locally and tried NewSegment, but I get the same error as before :

traits.trait_errors.TraitError: The 'channel_info' trait of a NewSegmentInputSpec instance must be a tuple of the form: (a float, a float, a tuple of the form: (a boolean, a boolean)), but a value of (0.0001, 60, [True, True]) <class 'tuple'> was specified.
sapetnioc commented 7 months ago

This issue should be fixed now. I did some basic tests, we'll re-open it if it appears to still be broken.