Example #1
0
    def get_output_spec(self):
        """ Method to access the process output specifications.

        Returns
        -------
        outputs: str
            a string representation of all the output trait specifications.
        """
        output = "\nOUTPUT SPECIFICATIONS\n\n"
        for trait_name, trait in six.iteritems(self.traits(output=True)):
            output += "{0}: {1}\n".format(trait_name,
                                          trait_ids(self.trait(trait_name)))
        return output
Example #2
0
    def get_output_spec(self):
        """ Method to access the process output specifications.

        Returns
        -------
        outputs: str
            a string representation of all the output trait specifications.
        """
        output = "\nOUTPUT SPECIFICATIONS\n\n"
        for trait_name, trait in self.traits(output=True).iteritems():
            output += "{0}: {1}\n".format(
                trait_name, trait_ids(self.trait(trait_name)))
        return output
Example #3
0
    def get_input_spec(self):
        """ Method to access the process input specifications.

        Returns
        -------
        outputs: str
            a string representation of all the input trait specifications.
        """
        output = "\nINPUT SPECIFICATIONS\n\n"
        # self.traits(output=False) skips params with no output property
        for trait_name, trait in six.iteritems(self.user_traits()):
            if not trait.output:
                output += "{0}: {1}\n".format(
                    trait_name, trait_ids(self.trait(trait_name)))
        return output
Example #4
0
    def get_input_spec(self):
        """ Method to access the process input specifications.

        Returns
        -------
        outputs: str
            a string representation of all the input trait specifications.
        """
        output = "\nINPUT SPECIFICATIONS\n\n"
        # self.traits(output=False) skips params with no output property
        for trait_name, trait in self.user_traits().iteritems():
            if not trait.output:
                output += "{0}: {1}\n".format(
                    trait_name, trait_ids(self.trait(trait_name)))
        return output
Example #5
0
    def get_control_class(cls, trait):
        """ Find the control associated with the input trait.

        The mapping is defined in the global class parameter
        '_defined_controls'.

        Parameters
        ----------
        cls: ControllerWidget (mandatory)
            a ControllerWidget class
        trait: Trait (mandatory)
            a trait item

        Returns
        -------
        control_class: class
            the control class associated with the input trait.
            If no match has been found, return None
        """
        # Initilaize the output variable
        control_class = None

        # Go through the trait string description: can have multiple element
        # when either trait is used
        # Todo:: we actualy need to create all the controls and let the user
        # choose which one he wants to fill.
        for trait_id in trait_ids(trait):

            # Recursive construction: consider only the top level
            trait_id = trait_id.split("_")[0]

            # Try to get the control class
            control_class = cls._defined_controls.get(trait_id)

            # Stop when we have a match
            if control_class is not None:
                break

        return control_class
Example #6
0
    def create_control(self, trait_name, trait):
        """ Create a control associated to a trait.

        Parameters
        ----------
        trait_name: str (mandatory)
            the name of the trait from which we want to create a control. The
            control widget will share the same name
        trait: Trait (mandatory)
            a trait item
        """
        # Search if the current trait has already been processed
        control_groups = self._controls.get(trait_name)
        control_instances = []
        control_labels = []

        # If no control has been found in the class intern parameters
        if control_groups is None:

            # Call the search function that will map the trait type to the
            # corresponding control type
            control_class = self.get_control_class(trait)

            # If no control has been found, skip this trait and print
            # an error message. Note that the parameter will not be
            # accessible in the user interface.
            if control_class is None:
                logger.error("No control defined for trait '{0}': {1}. This "
                             "parameter will not be accessible in the "
                             "user interface.".format(trait_name,
                                                      trait_ids(trait)))
                return

            # handle groups
            layouts = []
            groups = trait.groups
            if groups:
                for group in groups:
                    group_widget = self._groups.get(group)
                    if group_widget is None:
                        group_widget = self._create_group_widget(group)
                        self._groups[group] = group_widget
                    layouts.append(group_widget.hideable_widget.layout())
            else:
                layouts.append(self._grid_layout)

            group = None
            for i, layout in enumerate(layouts):
                if groups:
                    group = groups[i]
                control_instance, control_label \
                      = self._create_control_in_layout(trait_name, trait,
                                                       layout, group)
                control_instances.append(control_instance)
                if control_label:
                    if not isinstance(control_label, tuple):
                        control_label = [control_label]
                    control_labels += list(control_label)
                    if isinstance(control_label[0], QtGui.QLabel):
                        control_label[0].setTextInteractionFlags(
                            QtCore.Qt.TextSelectableByKeyboard
                            | QtCore.Qt.TextSelectableByMouse)

        # Otherwise, the control associated with the current trait name is
        # already inserted in the grid layout, just unpack the values
        # contained in the private '_controls' class parameter
        else:
            for group, control in six.iteritems(control_groups):
                trait, control_class, control_instance, control_label = control
                control_instances.append(control_instance)
                if control_label:
                    if isinstance(control_label, tuple):
                        control_labels += list(control_label)
                    else:
                        control_labels.append(control_label)

        # Each trait has a hidden property. Take care of this information
        hide = (getattr(trait, 'hidden', False)
                or getattr(trait, 'unused', False))

        # Show/Hide the control and associated labels
        for control_instance in control_instances:
            control_instance.setVisible(not hide)
        for label in control_labels:
            label.setVisible(not hide)
    def display_parameters(self, node_name, process, pipeline):
        """
        Display the parameters of the selected node

        The node parameters are read and line labels/line edits/push buttons
        are created for each of them. This methods consists mainly in widget
        and layout organization.

        :param node_name: name of the node
        :param process: process of the node
        :param pipeline: current pipeline
        """

        self.node_name = node_name
        self.current_process = process

        self.line_edit_input = []
        self.line_edit_output = []
        self.labels_input = []
        self.labels_output = []

        # Refreshing the layouts
        if len(self.children()) > 0:
            self.clearLayout(self)

        self.v_box_final = QVBoxLayout()

        # Node name
        label_node_name = QLabel()
        label_node_name.setText('Node name:')

        self.line_edit_node_name = QLineEdit()

        # The pipeline global inputs and outputs node name cannot be modified
        if self.node_name not in ('inputs', 'outputs'):
            self.line_edit_node_name.setText(self.node_name)
            self.line_edit_node_name.returnPressed.connect(
                partial(self.update_node_name, pipeline))
        else:
            self.line_edit_node_name.setText('Pipeline inputs/outputs')
            self.line_edit_node_name.setReadOnly(True)

        self.h_box_node_name = QHBoxLayout()
        self.h_box_node_name.addWidget(label_node_name)
        self.h_box_node_name.addWidget(self.line_edit_node_name)

        # Inputs
        self.button_group_inputs = QGroupBox('Inputs')
        self.v_box_inputs = QVBoxLayout()
        idx = 0

        for name, trait in process.user_traits().items():
            if name == 'nodes_activation':
                continue
            if not trait.output:
                label_input = QLabel()
                label_input.setText(str(name))
                self.labels_input.insert(idx, label_input)
                try:
                    value = getattr(process, name)
                except TraitError:
                    value = Undefined
                trait_type = trait_ids(process.trait(name))

                self.line_edit_input.insert(idx, QLineEdit())
                self.line_edit_input[idx].setText(str(value))
                self.line_edit_input[idx].returnPressed.connect(
                    partial(self.update_plug_value, 'in', name, pipeline,
                            type(value)))

                h_box = QHBoxLayout()
                h_box.addWidget(label_input)
                h_box.addWidget(self.line_edit_input[idx])

                # Adding the possibility to filter pipeline global
                # inputs except if the input is "database_scans"
                # which means that the scans will be filtered with InputFilter
                if self.node_name == "inputs" and name != "database_scans":
                    parameters = (idx, pipeline, type(value))
                    push_button = QPushButton('Filter')
                    push_button.clicked.connect(
                        partial(self.display_filter, self.node_name, name,
                                parameters, process))
                    h_box.addWidget(push_button)

                self.v_box_inputs.addLayout(h_box)

                idx += 1

        self.button_group_inputs.setLayout(self.v_box_inputs)

        # Outputs
        self.button_group_outputs = QGroupBox('Outputs')
        self.v_box_outputs = QVBoxLayout()
        idx = 0
        for name, trait in process.traits(output=True).items():
            label_output = QLabel()
            label_output.setText(str(name))
            self.labels_output.insert(idx, label_output)

            value = getattr(process, name)
            trait_type = trait_ids(process.trait(name))

            self.line_edit_output.insert(idx, QLineEdit())
            self.line_edit_output[idx].setText(str(value))
            self.line_edit_output[idx].returnPressed.connect(
                partial(self.update_plug_value, 'out', name, pipeline,
                        type(value)))

            h_box = QHBoxLayout()
            h_box.addWidget(label_output)
            h_box.addWidget(self.line_edit_output[idx])

            self.v_box_outputs.addLayout(h_box)

            idx += 1

        self.button_group_outputs.setLayout(self.v_box_outputs)

        self.v_box_final.addLayout(self.h_box_node_name)
        self.v_box_final.addWidget(self.button_group_inputs)
        self.v_box_final.addWidget(self.button_group_outputs)

        self.setLayout(self.v_box_final)
Example #8
0
    def sync_process_output_traits(process_instance, name, value):
        """ Event handler function to update the process instance outputs

        This callback is only called when an input process instance trait is
        modified.

        Parameters
        ----------
        process_instance: process instance (mandatory)
            the process instance that contain the nipype interface we want
            to update.
        name: str (mandatory)
            the name of the trait we want to update.
        value: type (mandatory)
            the old trait value
        """
        # Get all the input traits
        input_traits = process_instance.traits(output=False)
        output_directory \
            = getattr(process_instance, 'output_directory', Undefined)

        # get the interface name from the process trait name
        trait_map = getattr(process_instance, '_nipype_trait_mapping', {})

        # Try to update all the output process instance traits values when
        # a process instance input trait is modified or when the dedicated
        # 'synchronize' trait value is modified
        if name in input_traits or name in ("synchronize", 'output_directory'):

            # Try to set all the process instance output traits values from
            # the nipype autocompleted traits values
            try:
                nipype_outputs = (
                    process_instance._nipype_interface._list_outputs())
            except Exception as e:
                # don't make it all crash because of a nipype trait assign
                # error
                print('EXCEPTION:', e, file=sys.stderr)
                print('while syncing nipype parameter',
                      name,
                      'on',
                      process_instance.name,
                      file=sys.stderr)
                # when called during exit, the traceback module might have
                # already disappeared
                import traceback
                traceback.print_exc()
                ex_type, ex, tb = sys.exc_info()
                logger.debug("Something wrong in the nipype output trait "
                             "synchronization:\n\n\tError: {0} - {1}\n"
                             "\tTraceback:\n{2}".format(
                                 ex_type, ex,
                                 "".join(traceback.format_tb(tb))))
                nipype_outputs = {}

            # Synchronize traits: check file existence
            for out_name, out_value in six.iteritems(nipype_outputs):

                pname = trait_map.get(out_name, '_' + out_name)

                try:
                    # if we have an output directory, replace it
                    if output_directory not in (Undefined, None) \
                            and any([x
                                     for x in trait_ids(process_instance.trait(
                                        pname))
                                     if 'File' in x or 'Directory' in x]):
                        out_value = _replace_dir(out_value, output_directory)
                    # Set the output process trait value
                    process_instance.set_parameter(pname, out_value)

                # If we can't update the output process instance traits values,
                # print a logging debug message.
                except Exception as e:
                    print('EXCEPTION:', e, file=sys.stderr)
                    print('while setting nipype output parameter',
                          pname,
                          'on',
                          process_instance.name,
                          'with value:',
                          out_value,
                          file=sys.stderr)
                    import traceback
                    traceback.print_exc()
                    ex_type, ex, tb = sys.exc_info()
                    logger.debug("Something wrong in the nipype output trait "
                                 "synchronization:\n\n\tError: {0} - {1}\n"
                                 "\tTraceback:\n{2}".format(
                                     ex_type, ex,
                                     "".join(traceback.format_tb(tb))))

        if name in list(
                input_traits.keys()) + ['synchronize', 'output_directory']:
            names = [name]
            if name == 'output_directory':
                names = list(input_traits.keys())
            for name in names:
                # check if the input trait is duplicated as an output
                trait = process_instance.trait(name)
                if trait.copyfile:
                    out_trait = process_instance.trait('_modified_%s' % name)
                    if out_trait:
                        new_value = getattr(process_instance, name)
                        if output_directory not in (Undefined, None):
                            new_value = _replace_dir(new_value,
                                                     output_directory)
                        try:
                            process_instance.set_parameter(
                                "_modified_%s" % name, new_value)
                        # If we can't update the output process instance
                        # traits values, print a logging debug message.
                        except Exception as e:
                            print('EXCEPTION:', e)
                            import traceback
                            traceback.print_exc()
                            ex_type, ex, tb = sys.exc_info()
                            logger.debug(
                                "Something wrong in the nipype output trait "
                                "synchronization:\n\n\tError: {0} - {1}\n"
                                "\tTraceback:\n{2}".format(
                                    ex_type, ex,
                                    "".join(traceback.format_tb(tb))))
Example #9
0
    def delete_list_item(controller_widget, control_name, control_instance):
        """ Delete the last control element

        Parameters
        ----------
        controller_widget: ControllerWidget (mandatory)
            a controller widget that contains the controller we want to update
        control_name: str(mandatory)
            the name of the controller widget control we want to synchronize
            with the controller
        control_instance: QFrame (mandatory)
            the instance of the controller widget control we want to
            synchronize with the controller
        """
        # Delete the last inserted control
        last_row = (control_instance.controller_widget._grid_layout.rowCount())
        nb_of_items = control_instance.controller_widget._grid_layout.count()
        item_found = False
        index_to_remove = last_row - 1

        # If the list contain at least one widget
        if nb_of_items > 0:

            # While the last inserted widget has not been found
            while index_to_remove >= 0 and not item_found:

                # Try to remove the 'index_to_remove' control row
                item_found, widget = ListControlWidget.delete_one_row(
                    control_instance, index_to_remove)

                # If a list control has been deleted, remove the associated
                # tools
                if hasattr(widget, "controller"):

                    # Remove the list control extra tools row
                    ListControlWidget.delete_one_row(control_instance,
                                                     index_to_remove - 1)

                # Get the trait name that has just been deleted from the
                # controller widget
                if item_found:
                    trait_name = str(index_to_remove - 1)

                # Increment
                index_to_remove -= 1

        # No more control to delete
        else:
            logger.debug(
                "No more control to delete in '{0}'.".format(control_instance))

        # If one list control item has been deleted
        if item_found:

            # If the inner control is a list, convert the control index
            # Indeed, two elements are inserted for a list item
            # (tools + widget)
            if trait_ids(control_instance.inner_trait)[0].startswith("List_"):
                trait_name = str((int(trait_name) + 1) / 2 - 1)

            # Remove the trait from the controller
            control_instance.controller.remove_trait(trait_name)

            # Get, unpack and delete the control item
            control_groups \
                = control_instance.controller_widget._controls[trait_name]
            for group, control in six.iteritems(control_groups):
                (inner_trait, inner_control_class, inner_control_instance,
                 inner_control_label) = control
                del (control_instance.controller_widget._controls[trait_name])

                # Disconnect the removed control
                inner_control_class.disconnect(controller_widget, trait_name,
                                               inner_control_instance)

            # Update the list controller
            if hasattr(control_instance, '_controller_connections'):
                control_instance._controller_connections[0]()
            logger.debug("Remove 'ListControlWidget' '{0}' controller and "
                         "trait item.".format(trait_name))

        control_instance.controller_widget._grid_layout.update()
Example #10
0
    def get_control_class(self, trait):
        """ Find the control associated with the input trait.

        The mapping is defined in the global class parameter
        '_defined_controls'.

        Parameters
        ----------
        trait: Trait (mandatory)
            a trait item

        Returns
        -------
        control_class: class
            the control class associated with the input trait.
            If no match has been found, return None
        """
        # Initilaize the output variable
        control_class = None

        todo = [trait]
        done = set()
        while todo:
            trait = todo.pop(0)
            done.add(trait)

            trait_id = None
            ids = trait_ids(trait)
            if len(ids) >= 2:
                trait_id = 'Compound'
            elif len(ids) == 1:
                trait_id = ids[0]

            if trait_id is not None:
                control_class = self._defined_controls.get(trait_id)
                # Recursive construction: consider only the top level
                while control_class is None:
                    split_id = trait_id.rsplit("_", 1)
                    if len(split_id) == 1:
                        break
                    trait_id = split_id[0]
                    # Try to get the control class
                    control_class = self._defined_controls.get(trait_id)

                if control_class is not None:
                    break

            # not found: look in superclasses
            bases = trait.trait_type.__class__.__bases__ \
                + trait.__class__.__bases__
            for base in bases:
                if issubclass(base, traits.TraitType):
                    trait = self._instantiate_trait(base)
                    todo.append(trait)

        if control_class is None:
            # fallback to a label displaying "this value cannot be seen/edited"
            control_class = self._defined_controls.get('unknown')

        if inspect.isfunction(control_class):
            # the function may instantiate a specialized type dynamically
            control_class = control_class(trait)

        return control_class