Example #1
0
    def read_type(pipeline):
        """Read the type of a Variable from its pipeline.

        The type is obtained from the 'spec' input port of the 'OutputPort'
        module.
        """
        reg = get_module_registry()
        OutputPort = reg.get_module_by_name(
            'org.vistrails.vistrails.basic', 'OutputPort')
        outputs = find_modules_by_type(pipeline, [OutputPort])
        if len(outputs) == 1:
            output = outputs[0]
            if get_function(output, 'name') == 'value':
                spec = get_function(output, 'spec')
                return resolve_descriptor(spec)
        return None
Example #2
0
def get_pipeline_location(controller, pipelineInfo):
    pipeline = get_upgraded_pipeline(controller.vistrail, pipelineInfo.version)

    location_modules = find_modules_by_type(pipeline, [CellLocation])
    if len(location_modules) != 1:
        raise ValueError
    loc = location_modules[0]
    row = int(get_function(loc, 'Row')) - 1
    col = int(get_function(loc, 'Column')) - 1

    sheetref_modules = find_modules_by_type(pipeline, [SheetReference])
    if len(sheetref_modules) != 1:
        raise ValueError
    ref = sheetref_modules[0]
    for connection in pipeline.connection_list:
        src = pipeline.modules[connection.source.moduleId]
        if connection.destination.moduleId == ref.id and src.is_vistrail_var():
            var_uuid = src.get_vistrail_var()
            sheetname_var = controller.get_vistrail_variable_by_uuid(var_uuid)
            return row, col, sheetname_var
    raise ValueError
Example #3
0
File: __init__.py Project: rbax/DAT
def get_pipeline_location(controller, pipelineInfo):
    pipeline = get_upgraded_pipeline(controller.vistrail, pipelineInfo.version)

    location_modules = find_modules_by_type(pipeline, [CellLocation])
    if len(location_modules) != 1:
        raise ValueError
    loc = location_modules[0]
    row = int(get_function(loc, 'Row')) - 1
    col = int(get_function(loc, 'Column')) - 1

    sheetref_modules = find_modules_by_type(pipeline, [SheetReference])
    if len(sheetref_modules) != 1:
        raise ValueError
    ref = sheetref_modules[0]
    for connection in pipeline.connection_list:
        src = pipeline.modules[connection.source.moduleId]
        if connection.destination.moduleId == ref.id and src.is_vistrail_var():
            var_uuid = src.get_vistrail_var()
            sheetname_var = controller.get_vistrail_variable_by_uuid(var_uuid)
            return row, col, sheetname_var
    raise ValueError
Example #4
0
def add_variable_subworkflow(generator, variable, plot_ports=None):
    """Add a variable subworkflow to the pipeline.

    Copy the variable subworkflow from its own pipeline to the given one.

    If plot_ports is given, connects the pipeline to the ports in plot_ports,
    and returns the ids of the connections tying this variable to the plot,
    which are used to build the pipeline's conn_map.

    If plot_ports is None, just returns the (module, port_name) of the output
    port.
    """
    if isinstance(variable, Pipeline):
        var_pipeline = variable
    else:
        var_pipeline = get_upgraded_pipeline(
            generator.controller.vistrail,
            'dat-var-%s' % variable)

    reg = get_module_registry()
    outputport_desc = reg.get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'OutputPort')

    # Copy every module but the OutputPort
    output_id = None
    var_modules_map = dict()  # old_mod_id -> new_module
    for module in var_pipeline.modules.itervalues():
        if (module.module_descriptor is outputport_desc and
                get_function(module, 'name') == 'value'):
            output_id = module.id
        else:
            # We can't just add this module to the new pipeline!
            # We need to create a new one to avoid id collisions
            var_modules_map[module.id] = generator.copy_module(module)

    if output_id is None:
        raise ValueError("add_variable_subworkflow: variable pipeline has no "
                         "'OutputPort' module")

    # Copy every connection except the one to the OutputPort module
    for connection in var_pipeline.connection_list:
        if connection.destination.moduleId != output_id:
            generator.connect_modules(
                var_modules_map[connection.source.moduleId],
                connection.source.name,
                var_modules_map[connection.destination.moduleId],
                connection.destination.name)

    if plot_ports:
        connection_ids = []
        # Connects the port previously connected to the OutputPort to the ports
        # in plot_ports
        for connection in var_pipeline.connection_list:
            if connection.destination.moduleId == output_id:
                for var_output_mod, var_output_port in plot_ports:
                    connection_ids.append(generator.connect_modules(
                        var_modules_map[connection.source.moduleId],
                        connection.source.name,
                        var_output_mod,
                        var_output_port))
        return connection_ids
    else:
        # Just find the output port and return it
        for connection in var_pipeline.connection_list:
            if connection.destination.moduleId == output_id:
                return (var_modules_map[connection.source.moduleId],
                        connection.source.name)
        assert False
Example #5
0
    def _read_metadata(self, package_identifier):
        """Reads a plot's ports from the subworkflow file

        Finds each InputPort module and gets the parameter name, optional flag
        and type from its 'name', 'optional' and 'spec' input functions.

        If input ports were declared in this Plot, we check that they are
        indeed present and were all listed (either list all of them or none).

        If the module type is a subclass of Constant, we will assume the port
        is to be set via direct input (ConstantPort), else by dragging a
        variable (DataPort).

        We also automatically add aliased input ports of compatible constant
        types as optional ConstantPort's.
        """
        pipeline = self.get_pipeline()

        inputports = find_modules_by_type(pipeline, [InputPort])
        if not inputports:
            raise ValueError("No InputPort module")

        currentports = {port.name: port for port in self.ports}
        seenports = set()
        for port in inputports:
            name = get_function(port, 'name')
            if not name:
                raise ValueError(
                    "Subworkflow of plot '%s' in package '%s' has an "
                    "InputPort with no name" % (
                        self.name, package_identifier))
            if name in seenports:
                raise ValueError(
                    "Subworkflow of plot '%s' in package '%s' has several "
                    "InputPort modules with name '%s'" % (
                        self.name, package_identifier, name))
            spec = get_function(port, 'spec')
            optional = get_function(port, 'optional')
            if optional == 'True':
                optional = True
            elif optional == 'False':
                optional = False
            else:
                optional = None

            try:
                currentport = currentports[name]
            except KeyError:
                # If the package didn't provide any port, it's ok, we can
                # discover them. But if some were present and some were
                # forgotten, emit a warning
                if currentports:
                    warnings.warn(
                        "Declaration of plot '%s' in package '%s' omitted "
                        "port '%s'" % (
                            self.name, package_identifier, name))
                if not spec:
                    warnings.warn(
                        "Subworkflow of plot '%s' in package '%s' has an "
                        "InputPort '%s' with no type; assuming Module" % (
                            self.name, package_identifier, name))
                    spec = 'org.vistrails.vistrails.basic:Module'
                if not optional:
                    optional = False
                type = resolve_descriptor(spec, package_identifier)
                if issubclass(type.module, Constant):
                    currentport = ConstantPort(
                        name=name,
                        type=type,
                        optional=optional)
                else:
                    currentport = DataPort(
                        name=name,
                        type=type,
                        optional=optional)

                self.ports.append(currentport)
            else:
                currentspec = (currentport.type.identifier +
                               ':' +
                               currentport.type.name)
                # Canonicalize spec
                spec = create_descriptor_string(*parse_descriptor_string(
                    spec, package_identifier))
                if ((spec and spec != currentspec) or
                        (optional is not None and
                         optional != currentport.optional)):
                    warnings.warn(
                        "Declaration of port '%s' from plot '%s' in "
                        "package '%s' differs from subworkflow "
                        "contents" % (
                            name, self.name, package_identifier))
                spec = currentspec
                type = resolve_descriptor(currentspec, package_identifier)

            # Get info from the PortSpec
            try:
                (default_type, default_value,
                 entry_type, enum_values) = read_port_specs(
                     pipeline,
                     port)
                if default_value is not None:
                    if not issubclass(default_type, type.module):
                        raise ValueError("incompatible type %r" % ((
                                         default_type,
                                         type.module),))
                    elif default_type is type.module:
                        currentport.default_value = default_value
                currentport.entry_type = entry_type
                currentport.enum_values = enum_values
            except ValueError, e:
                raise ValueError(
                    "Error reading specs for port '%s' from plot '%s' of "
                    "package '%s': %s" % (
                        name, self.name, package_identifier, e.args[0]))

            seenports.add(name)
Example #6
0
File: __init__.py Project: rbax/DAT
def create_pipeline(controller,
                    recipe,
                    row,
                    column,
                    var_sheetname,
                    typecast=None):
    """Create a pipeline from a recipe and return its information.
    """
    # Build from the root version
    controller.change_selected_version(0)

    reg = get_module_registry()

    generator = PipelineGenerator(controller)

    inputport_desc = reg.get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'InputPort')

    # Add the plot subworkflow
    plot_pipeline = recipe.plot.get_pipeline()

    connected_to_inputport = set(
        c.source.moduleId for c in plot_pipeline.connection_list
        if (plot_pipeline.modules[c.destination.moduleId].module_descriptor is
            inputport_desc))

    # Copy every module but the InputPorts and up
    plot_modules_map = dict()  # old module id -> new module
    for module in plot_pipeline.modules.itervalues():
        if (module.module_descriptor is not inputport_desc
                and module.id not in connected_to_inputport):
            plot_modules_map[module.id] = generator.copy_module(module)

    del connected_to_inputport

    def _get_or_create_module(moduleType):
        """Returns or creates a new module of the given type.

        Warns if multiple modules of that type were found.
        """
        modules = find_modules_by_type(plot_pipeline, [moduleType])
        if not modules:
            desc = reg.get_descriptor_from_module(moduleType)
            module = controller.create_module_from_descriptor(desc)
            generator.add_module(module)
            return module, True
        else:
            # Currently we do not support multiple cell locations in one
            # pipeline but this may be a feature in the future, to have
            # linked visualizations in multiple cells
            if len(modules) > 1:
                warnings.warn("Found multiple %s modules in plot "
                              "subworkflow, only using one." % moduleType)
            return plot_modules_map[modules[0].id], False

    # Connect the CellLocation to the SpreadsheetCell
    cell_modules = find_modules_by_type(plot_pipeline, [SpreadsheetCell])
    if cell_modules:
        cell_module = plot_modules_map[cell_modules[0].id]

        # Add a CellLocation module if the plot subworkflow didn't contain one
        location_module, new_location = _get_or_create_module(CellLocation)

        if new_location:
            # Connect the CellLocation to the SpreadsheetCell
            generator.connect_modules(location_module, 'value', cell_module,
                                      'Location')

        generator.update_function(location_module, 'Row', [str(row + 1)])
        generator.update_function(location_module, 'Column', [str(column + 1)])

        if len(cell_modules) > 1:
            warnings.warn("Plot subworkflow '%s' contains more than "
                          "one spreadsheet cell module. Only one "
                          "was connected to a location module." %
                          recipe.plot.name)

        # Add a SheetReference module
        sheetref_module, new_sheetref = _get_or_create_module(SheetReference)

        if new_sheetref or new_location:
            # Connection the SheetReference to the CellLocation
            generator.connect_modules(sheetref_module, 'value',
                                      location_module, 'SheetReference')

        generator.connect_var(var_sheetname, sheetref_module, 'SheetName')
    else:
        warnings.warn("Plot subworkflow '%s' does not contain a "
                      "spreadsheet cell module" % recipe.plot.name)

    # TODO : use walk_modules() to find all modules above an InputPort's
    # 'Default' port and ignore them in the following loop

    # Copy the connections and locate the input ports
    plot_params = dict()  # param name -> [(module, input port name)]
    for connection in plot_pipeline.connection_list:
        src = plot_pipeline.modules[connection.source.moduleId]
        dest = plot_pipeline.modules[connection.destination.moduleId]
        if dest.module_descriptor is inputport_desc:
            continue
        elif src.module_descriptor is inputport_desc:
            param = get_function(src, 'name')
            ports = plot_params.setdefault(param, [])
            ports.append((plot_modules_map[connection.destination.moduleId],
                          connection.destination.name))
        else:
            generator.connect_modules(
                plot_modules_map[connection.source.moduleId],
                connection.source.name,
                plot_modules_map[connection.destination.moduleId],
                connection.destination.name)

    # Find the constant ports declared with aliases
    aliases = {port.name: port for port in recipe.plot.ports if port.is_alias}
    for module in plot_pipeline.module_list:
        for function in module.functions:
            remove = False
            for param in function.parameters:
                if param.alias in aliases:
                    plot_params[param.alias] = [(plot_modules_map[module.id],
                                                 function.name)]
                    remove = True

            if remove:
                # Remove the function from the generated pipeline
                generator.update_function(plot_modules_map[module.id],
                                          function.name, None)
    del aliases

    # Adds default values for unset constants
    parameters_incl_defaults = dict(recipe.parameters)
    for port in recipe.plot.ports:
        if (isinstance(port, ConstantPort) and port.default_value is not None
                and port.name not in recipe.parameters):
            parameters_incl_defaults[port.name] = [
                RecipeParameterValue(constant=port.default_value)
            ]

    # Maps a port name to the list of parameters
    # for each parameter, we have a list of connections tying it to modules of
    # the plot
    conn_map = dict()  # param: str -> [[conn_id: int]]

    name_to_port = {port.name: port for port in recipe.plot.ports}
    actual_parameters = {}
    for port_name, parameters in parameters_incl_defaults.iteritems():
        plot_ports = plot_params.get(port_name, [])
        p_conns = conn_map[port_name] = []
        actual_values = []
        for parameter in parameters:
            if parameter.type == RecipeParameterValue.VARIABLE:
                conns, actual_param = add_variable_subworkflow_typecast(
                    generator,
                    parameter.variable,
                    plot_ports,
                    name_to_port[port_name].type,
                    typecast=typecast)
                p_conns.append(conns)
                actual_values.append(actual_param)
            else:  # parameter.type == RecipeParameterValue.CONSTANT
                desc = name_to_port[port_name].type
                p_conns.append(
                    add_constant_module(generator, desc, parameter.constant,
                                        plot_ports))
                actual_values.append(parameter)
        actual_parameters[port_name] = actual_values
    del name_to_port

    pipeline_version = generator.perform_action()
    controller.vistrail.change_description(
        "Created DAT plot %s" % recipe.plot.name, pipeline_version)
    # FIXME : from_root seems to be necessary here, I don't know why
    controller.change_selected_version(pipeline_version, from_root=True)

    # Convert the modules to module ids in the port_map
    port_map = dict()
    for param, portlist in plot_params.iteritems():
        port_map[param] = [(module.id, port) for module, port in portlist]

    return PipelineInformation(pipeline_version,
                               DATRecipe(recipe.plot, actual_parameters),
                               conn_map, port_map)
Example #7
0
File: __init__.py Project: rbax/DAT
def get_variable_value(variable):
    """Get the value of a variable, i.e. the result of its pipeline.

    The 'variable' can either be a Variable, from which a temporary pipeline
    will be built, or a VariableInformation, representing an existing pipeline.
    """
    def pipeline_from_info(variableinfo):
        controller = variableinfo._controller
        version = controller.vistrail.get_version_number('dat-var-%s' %
                                                         variable.name)
        return controller.vistrail.getPipeline(version), version

    def pipeline_from_generator(variable_gen):
        # Get the original OutputPort module
        orig_controller = variable_gen._generator.controller
        base_pipeline = orig_controller.vistrail.getPipeline('dat-vars')
        if len(base_pipeline.module_list) != 1:
            raise ValueError("dat-vars version is invalid")
        output_port = base_pipeline.module_list[0]

        controller = VistrailController(Vistrail())
        # OutputPort
        operations = [('add', output_port)]
        # Rest of the pipeline
        operations += variable_gen._generator.operations
        # Connection
        connection = controller.create_connection(
            variable_gen._output_module, variable_gen._outputport_name,
            output_port, 'InternalPipe')
        operations.append(('add', connection))
        # Materialize this
        action = create_action(operations)
        controller.add_new_action(action)
        version = controller.perform_action(action)
        controller.change_selected_version(version)
        assert version == controller.current_version == 1
        return controller.current_pipeline, 1

    # Obtain 'pipeline' and 'version' from 'variable'
    if isinstance(variable, Variable.VariableInformation):
        # Pipeline already exists
        pipeline, version = pipeline_from_info(variable)
    elif isinstance(variable, Variable):
        if variable._materialized is not None:
            # Pipeline already exists
            pipeline, version = pipeline_from_info(variable._materialized)
        else:
            # Pipeline doesn't exist
            # We need to make one from the operations
            pipeline, version = pipeline_from_generator(variable)
    else:
        raise TypeError

    # Setup the interpreter for execution
    interpreter = get_default_interpreter()
    interpreter.clean_non_cacheable_modules()
    interpreter.parent_execs = [None]
    res = interpreter.setup_pipeline(pipeline)
    if len(res[5]) > 0:
        raise ValueError("Variable pipeline has errors:\n%s" %
                         '\n'.join(me.msg for me in res[5].itervalues()))
    tmp_id_to_module_map = res[0]

    # Execute
    res = interpreter.execute_pipeline(
        pipeline,
        res[0],  # tmp_id_to_module_map
        res[1],  # persistent_to_tmp_id_map
        current_version=version,
        reason="getting variable value")
    if len(res[2]) > 0:
        raise ValueError("Error while executing variable pipeline:\n%s" %
                         '\n'.join('%s: %s' %
                                   (me.module.__class__.__name__, me.msg)
                                   for me in res[2].itervalues()))
    if len(res[4]) > 0:
        # extract messages and previous ModuleSuspended exceptions
        raise ValueError("Module got suspended while executing variable "
                         "pipeline:\n%s" %
                         '\n'.join(msg for msg in res[4].itervalues()))

    # Get the result
    outputport_desc = get_module_registry().get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'OutputPort')
    for module in pipeline.module_list:
        if module.module_descriptor is outputport_desc:
            if get_function(module, 'name') == 'value':
                module_obj = tmp_id_to_module_map[module.id]
                result = module_obj.get_output('ExternalPipe')
                break
    else:
        result = None

    interpreter.finalize_pipeline(pipeline, *res[:-1])
    interpreter.parent_execs = [None]
    return result
Example #8
0
File: __init__.py Project: rbax/DAT
def apply_operation_subworkflow(controller, op, subworkflow, args):
    """Load an operation subworkflow from a file to build a new Variable.

    op is the requested operation.
    subworkflow is the filename of an XML file.
    args is a list of Variable that are the arguments of the operation; they
    will be connected in place of the operation subworkflow's InputPort
    modules.
    """
    reg = get_module_registry()
    inputport_desc = reg.get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'InputPort')
    outputport_desc = reg.get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'OutputPort')

    generator = PipelineGenerator(controller)

    # Add the operation subworkflow
    locator = XMLFileLocator(subworkflow)
    vistrail = locator.load()
    operation_pipeline = get_upgraded_pipeline(vistrail)

    # Copy every module but the InputPorts and the OutputPort
    operation_modules_map = dict()  # old module id -> new module
    for module in operation_pipeline.modules.itervalues():
        if module.module_descriptor not in (inputport_desc, outputport_desc):
            operation_modules_map[module.id] = generator.copy_module(module)

    # Copy the connections and locate the input ports and the output port
    operation_params = dict()  # param name -> [(module, input port name)]
    output = None  # (module, port name)
    for connection in operation_pipeline.connection_list:
        src = operation_pipeline.modules[connection.source.moduleId]
        dest = operation_pipeline.modules[connection.destination.moduleId]
        if src.module_descriptor is inputport_desc:
            param = get_function(src, 'name')
            ports = operation_params.setdefault(param, [])
            ports.append(
                (operation_modules_map[connection.destination.moduleId],
                 connection.destination.name))
        elif dest.module_descriptor is outputport_desc:
            output = (operation_modules_map[connection.source.moduleId],
                      connection.source.name)
        else:
            generator.connect_modules(
                operation_modules_map[connection.source.moduleId],
                connection.source.name,
                operation_modules_map[connection.destination.moduleId],
                connection.destination.name)

    # Add the parameter subworkflows
    for i in xrange(len(args)):
        generator.append_operations(args[i]._generator.operations)
        o_mod = args[i]._output_module
        o_port = args[i]._outputport_name
        for i_mod, i_port in operation_params.get(op.parameters[i].name, []):
            generator.connect_modules(o_mod, o_port, i_mod, i_port)

    return Variable(type=op.return_type,
                    controller=controller,
                    generator=generator,
                    output=output)
Example #9
0
def create_pipeline(controller, recipe, row, column, var_sheetname,
                    typecast=None):
    """Create a pipeline from a recipe and return its information.
    """
    # Build from the root version
    controller.change_selected_version(0)

    reg = get_module_registry()

    generator = PipelineGenerator(controller)

    inputport_desc = reg.get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'InputPort')

    # Add the plot subworkflow
    if recipe.plot.subworkflow is not None:
        locator = XMLFileLocator(recipe.plot.subworkflow)
        vistrail = locator.load()
        plot_pipeline = get_upgraded_pipeline(vistrail)
    elif recipe.plot.callback is not None:
        callback_ret = recipe.plot.callback()
        if isinstance(callback_ret, Pipeline):
            plot_pipeline = callback_ret
        elif callback_ret[0] == 'pipeline':
            plot_pipeline, = callback_ret[1:]
        elif callback_ret[0] == 'python_lists':
            plot_pipeline = build_pipeline(*callback_ret[1:])
        else:
            raise ValueError("Plot callback returned invalid value %r" %
                             callback_ret[0])
    else:
        assert False

    connected_to_inputport = set(
        c.source.moduleId
        for c in plot_pipeline.connection_list
        if (plot_pipeline.modules[c.destination.moduleId]
                .module_descriptor is inputport_desc))

    # Copy every module but the InputPorts and up
    plot_modules_map = dict()  # old module id -> new module
    for module in plot_pipeline.modules.itervalues():
        if (module.module_descriptor is not inputport_desc and
                module.id not in connected_to_inputport):
            plot_modules_map[module.id] = generator.copy_module(module)

    del connected_to_inputport

    def _get_or_create_module(moduleType):
        """Returns or creates a new module of the given type.

        Warns if multiple modules of that type were found.
        """
        modules = find_modules_by_type(plot_pipeline, [moduleType])
        if not modules:
            desc = reg.get_descriptor_from_module(moduleType)
            module = controller.create_module_from_descriptor(desc)
            generator.add_module(module)
            return module, True
        else:
            # Currently we do not support multiple cell locations in one
            # pipeline but this may be a feature in the future, to have
            # linked visualizations in multiple cells
            if len(modules) > 1:
                warnings.warn("Found multiple %s modules in plot "
                              "subworkflow, only using one." % moduleType)
            return plot_modules_map[modules[0].id], False

    # Connect the CellLocation to the SpreadsheetCell
    cell_modules = find_modules_by_type(plot_pipeline,
                                        [SpreadsheetCell])
    if cell_modules:
        cell_module = plot_modules_map[cell_modules[0].id]

        # Add a CellLocation module if the plot subworkflow didn't contain one
        location_module, new_location = _get_or_create_module(CellLocation)

        if new_location:
            # Connect the CellLocation to the SpreadsheetCell
            generator.connect_modules(
                location_module, 'value',
                cell_module, 'Location')

        generator.update_function(
            location_module, 'Row', [str(row + 1)])
        generator.update_function(
            location_module, 'Column', [str(column + 1)])

        if len(cell_modules) > 1:
            warnings.warn("Plot subworkflow '%s' contains more than "
                          "one spreadsheet cell module. Only one "
                          "was connected to a location module." %
                          recipe.plot.name)

        # Add a SheetReference module
        sheetref_module, new_sheetref = _get_or_create_module(SheetReference)

        if new_sheetref or new_location:
            # Connection the SheetReference to the CellLocation
            generator.connect_modules(
                sheetref_module, 'value',
                location_module, 'SheetReference')

        generator.connect_var(
            var_sheetname,
            sheetref_module,
            'SheetName')
    else:
        warnings.warn("Plot subworkflow '%s' does not contain a "
                      "spreadsheet cell module" % recipe.plot.name)

    # TODO : use walk_modules() to find all modules above an InputPort's
    # 'Default' port and ignore them in the following loop

    # Copy the connections and locate the input ports
    plot_params = dict()  # param name -> [(module, input port name)]
    for connection in plot_pipeline.connection_list:
        src = plot_pipeline.modules[connection.source.moduleId]
        dest = plot_pipeline.modules[connection.destination.moduleId]
        if dest.module_descriptor is inputport_desc:
            continue
        elif src.module_descriptor is inputport_desc:
            param = get_function(src, 'name')
            ports = plot_params.setdefault(param, [])
            ports.append((
                plot_modules_map[connection.destination.moduleId],
                connection.destination.name))
        else:
            generator.connect_modules(
                plot_modules_map[connection.source.moduleId],
                connection.source.name,
                plot_modules_map[connection.destination.moduleId],
                connection.destination.name)

    # Find the constant ports declared with aliases
    aliases = {port.name: port for port in recipe.plot.ports if port.is_alias}
    for module in plot_pipeline.module_list:
        for function in module.functions:
            remove = False
            for param in function.parameters:
                if param.alias in aliases:
                    plot_params[param.alias] = [(
                        plot_modules_map[module.id],
                        function.name)]
                    remove = True

            if remove:
                # Remove the function from the generated pipeline
                generator.update_function(
                    plot_modules_map[module.id],
                    function.name,
                    None)
    del aliases

    # Adds default values for unset constants
    parameters_incl_defaults = dict(recipe.parameters)
    for port in recipe.plot.ports:
        if (isinstance(port, ConstantPort) and
                port.default_value is not None and
                port.name not in recipe.parameters):
            parameters_incl_defaults[port.name] = [RecipeParameterValue(
                constant=port.default_value)]

    # Maps a port name to the list of parameters
    # for each parameter, we have a list of connections tying it to modules of
    # the plot
    conn_map = dict()  # param: str -> [[conn_id: int]]

    name_to_port = {port.name: port for port in recipe.plot.ports}
    actual_parameters = {}
    for port_name, parameters in parameters_incl_defaults.iteritems():
        plot_ports = plot_params.get(port_name, [])
        p_conns = conn_map[port_name] = []
        actual_values = []
        for parameter in parameters:
            if parameter.type == RecipeParameterValue.VARIABLE:
                conns, actual_param = add_variable_subworkflow_typecast(
                    generator,
                    parameter.variable,
                    plot_ports,
                    name_to_port[port_name].type,
                    typecast=typecast)
                p_conns.append(conns)
                actual_values.append(actual_param)
            else:  # parameter.type == RecipeParameterValue.CONSTANT
                desc = name_to_port[port_name].type
                p_conns.append(add_constant_module(
                    generator,
                    desc,
                    parameter.constant,
                    plot_ports))
                actual_values.append(parameter)
        actual_parameters[port_name] = actual_values
    del name_to_port

    pipeline_version = generator.perform_action()
    controller.vistrail.change_description(
        "Created DAT plot %s" % recipe.plot.name,
        pipeline_version)
    # FIXME : from_root seems to be necessary here, I don't know why
    controller.change_selected_version(pipeline_version, from_root=True)

    # Convert the modules to module ids in the port_map
    port_map = dict()
    for param, portlist in plot_params.iteritems():
        port_map[param] = [(module.id, port) for module, port in portlist]

    return PipelineInformation(
        pipeline_version,
        DATRecipe(recipe.plot, actual_parameters),
        conn_map, port_map)
Example #10
0
def get_variable_value(variable):
    """Get the value of a variable, i.e. the result of its pipeline.

    The 'variable' can either be a Variable, from which a temporary pipeline
    will be built, or a VariableInformation, representing an existing pipeline.
    """
    def pipeline_from_info(variableinfo):
        controller = variableinfo._controller
        version = controller.vistrail.get_version_number(
            'dat-var-%s' % variable.name)
        return controller.vistrail.getPipeline(version), version

    def pipeline_from_generator(variable_gen):
        # Get the original OutputPort module
        orig_controller = variable_gen._generator.controller
        base_pipeline = orig_controller.vistrail.getPipeline('dat-vars')
        if len(base_pipeline.module_list) != 1:
            raise ValueError("dat-vars version is invalid")
        output_port = base_pipeline.module_list[0]

        controller = VistrailController(Vistrail())
        # OutputPort
        operations = [('add', output_port)]
        # Rest of the pipeline
        operations += variable_gen._generator.operations
        # Connection
        connection = controller.create_connection(
            variable_gen._output_module,
            variable_gen._outputport_name,
            output_port,
            'InternalPipe')
        operations.append(('add', connection))
        # Materialize this
        action = create_action(operations)
        controller.add_new_action(action)
        version = controller.perform_action(action)
        controller.change_selected_version(version)
        assert version == controller.current_version == 1
        return controller.current_pipeline, 1

    # Obtain 'pipeline' and 'version' from 'variable'
    if isinstance(variable, Variable.VariableInformation):
        # Pipeline already exists
        pipeline, version = pipeline_from_info(variable)
    elif isinstance(variable, Variable):
        if variable._materialized is not None:
            # Pipeline already exists
            pipeline, version = pipeline_from_info(variable._materialized)
        else:
            # Pipeline doesn't exist
            # We need to make one from the operations
            pipeline, version = pipeline_from_generator(variable)
    else:
        raise TypeError

    # Setup the interpreter for execution
    interpreter = get_default_interpreter()
    interpreter.clean_non_cacheable_modules()
    interpreter.parent_execs = [None]
    res = interpreter.setup_pipeline(pipeline)
    if len(res[5]) > 0:
        raise ValueError("Variable pipeline has errors:\n%s" %
                         '\n'.join(me.msg for me in res[5].itervalues()))
    tmp_id_to_module_map = res[0]

    # Execute
    res = interpreter.execute_pipeline(
        pipeline,
        res[0],  # tmp_id_to_module_map
        res[1],  # persistent_to_tmp_id_map
        current_version=version,
        reason="getting variable value")
    if len(res[2]) > 0:
        raise ValueError("Error while executing variable pipeline:\n%s" %
                         '\n'.join('%s: %s' % (me.module.__class__.__name__,
                                               me.msg)
                                   for me in res[2].itervalues()))
    if len(res[4]) > 0:
        # extract messages and previous ModuleSuspended exceptions
        raise ValueError("Module got suspended while executing variable "
                         "pipeline:\n%s" %
                         '\n'.join(msg for msg in res[4].itervalues()))

    # Get the result
    outputport_desc = get_module_registry().get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'OutputPort')
    for module in pipeline.module_list:
        if module.module_descriptor is outputport_desc:
            if get_function(module, 'name') == 'value':
                module_obj = tmp_id_to_module_map[module.id]
                result = module_obj.get_output('ExternalPipe')
                break
    else:
        result = None

    interpreter.finalize_pipeline(pipeline, *res[:-1])
    interpreter.parent_execs = [None]
    return result
Example #11
0
def apply_operation_subworkflow(controller, op, subworkflow, args):
    """Load an operation subworkflow from a file to build a new Variable.

    op is the requested operation.
    subworkflow is the filename of an XML file.
    args is a list of Variable that are the arguments of the operation; they
    will be connected in place of the operation subworkflow's InputPort
    modules.
    """
    reg = get_module_registry()
    inputport_desc = reg.get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'InputPort')
    outputport_desc = reg.get_descriptor_by_name(
        'org.vistrails.vistrails.basic', 'OutputPort')

    generator = PipelineGenerator(controller)

    # Add the operation subworkflow
    locator = XMLFileLocator(subworkflow)
    vistrail = locator.load()
    operation_pipeline = get_upgraded_pipeline(vistrail)

    # Copy every module but the InputPorts and the OutputPort
    operation_modules_map = dict()  # old module id -> new module
    for module in operation_pipeline.modules.itervalues():
        if module.module_descriptor not in (inputport_desc, outputport_desc):
            operation_modules_map[module.id] = generator.copy_module(module)

    # Copy the connections and locate the input ports and the output port
    operation_params = dict()  # param name -> [(module, input port name)]
    output = None  # (module, port name)
    for connection in operation_pipeline.connection_list:
        src = operation_pipeline.modules[connection.source.moduleId]
        dest = operation_pipeline.modules[connection.destination.moduleId]
        if src.module_descriptor is inputport_desc:
            param = get_function(src, 'name')
            ports = operation_params.setdefault(param, [])
            ports.append((
                operation_modules_map[connection.destination.moduleId],
                connection.destination.name))
        elif dest.module_descriptor is outputport_desc:
            output = (operation_modules_map[connection.source.moduleId],
                      connection.source.name)
        else:
            generator.connect_modules(
                operation_modules_map[connection.source.moduleId],
                connection.source.name,
                operation_modules_map[connection.destination.moduleId],
                connection.destination.name)

    # Add the parameter subworkflows
    for i in xrange(len(args)):
        generator.append_operations(args[i]._generator.operations)
        o_mod = args[i]._output_module
        o_port = args[i]._outputport_name
        for i_mod, i_port in operation_params.get(op.parameters[i].name, []):
            generator.connect_modules(
                o_mod, o_port,
                i_mod, i_port)

    return Variable(
        type=op.return_type,
        controller=controller,
        generator=generator,
        output=output)