Exemplo n.º 1
0
    def _callable_executor_(self, callable, view_args, output_types,
                            provenance):
        output_views = callable(**view_args)
        output_views = tuplize(output_views)

        # TODO this won't work if the user has annotated their "view API" to
        # return a `typing.Tuple` with some number of components. Python will
        # return a tuple when there are multiple return values, and this length
        # check will fail because the tuple as a whole should be matched up to
        # a single output type instead of its components. This is an edgecase
        # due to how Python handles multiple returns, and can be worked around
        # by using something like `typing.List` instead.
        if len(output_views) != len(output_types):
            raise TypeError(
                "Number of output views must match number of output "
                "semantic types: %d != %d"
                % (len(output_views), len(output_types)))

        output_artifacts = []
        for output_view, (semantic_type, view_type) in \
                zip(output_views, output_types.values()):
            if type(output_view) is not view_type:
                raise TypeError(
                    "Expected output view type %r, received %r" %
                    (view_type.__name__, type(output_view).__name__))
            artifact = qiime.sdk.Artifact._from_view(
                semantic_type, output_view, view_type, provenance)
            output_artifacts.append(artifact)

        if len(output_artifacts) == 1:
            return output_artifacts[0]
        else:
            return tuple(output_artifacts)
Exemplo n.º 2
0
    def _callable_executor_(self, callable, view_args, output_types,
                            provenance):
        output_views = callable(**view_args)
        output_views = tuplize(output_views)

        # TODO this won't work if the user has annotated their "view API" to
        # return a `typing.Tuple` with some number of components. Python will
        # return a tuple when there are multiple return values, and this length
        # check will fail because the tuple as a whole should be matched up to
        # a single output type instead of its components. This is an edgecase
        # due to how Python handles multiple returns, and can be worked around
        # by using something like `typing.List` instead.
        if len(output_views) != len(output_types):
            raise TypeError(
                "Number of output views must match number of output "
                "semantic types: %d != %d"
                % (len(output_views), len(output_types)))

        output_artifacts = []
        for output_view, (semantic_type, view_type) in \
                zip(output_views, output_types.values()):
            if type(output_view) is not view_type:
                raise TypeError(
                    "Expected output view type %r, received %r" %
                    (view_type.__name__, type(output_view).__name__))
            artifact = qiime.sdk.Artifact._from_view(
                semantic_type, output_view, view_type, provenance.fork())
            output_artifacts.append(artifact)

        if len(output_artifacts) == 1:
            return output_artifacts[0]
        else:
            return tuple(output_artifacts)
Exemplo n.º 3
0
    def __getitem__(self, fields):
        fields = tuplize(fields)
        if len(fields) != len(self.field_names):
            raise TypeError("%r takes %d field(s), %d provided."
                            % (self, len(self.field_names), len(fields)))
        for args in zip(self.field_names, fields):
            self._validate_field_(*args)

        return self._apply_fields_(fields=fields)
Exemplo n.º 4
0
    def __getitem__(self, fields):
        fields = tuplize(fields)
        if len(fields) != len(self.field_names):
            raise TypeError("%r takes %d field(s), %d provided." %
                            (self, len(self.field_names), len(fields)))
        for args in zip(self.field_names, fields):
            self._validate_field_(*args)

        return self._apply_fields_(fields=fields)
Exemplo n.º 5
0
        def callable_wrapper(*args, **kwargs):
            provenance = archive.ActionProvenanceCapture(
                self.action_type, self.package, self.id)
            # This function's signature is rewritten below using
            # `decorator.decorator`. When the signature is rewritten, args[0]
            # is the function whose signature was used to rewrite this
            # function's signature.
            args = args[1:]

            # TODO this may be able to be simplified once Signature respects
            # order.
            wrapper_sig = self._callable_sig_converter_(self._callable)
            wrapper_sig = inspect.Signature.from_callable(wrapper_sig)
            wrapper_params = wrapper_sig.parameters

            user_input = {
                name: value
                for value, name in zip(args, wrapper_params)
            }
            user_input.update(kwargs)

            self.signature.check_types(**user_input)
            output_types = self.signature.solve_output(**user_input)

            artifacts = {}
            for name in self.signature.inputs:
                artifact = artifacts[name] = user_input[name]
                provenance.add_input(name, artifact)

            parameters = {}
            for name, (primitive_type, _) in self.signature.parameters.items():
                parameter = parameters[name] = user_input[name]
                provenance.add_parameter(name, primitive_type, parameter)

            view_args = parameters.copy()
            for name, (_, view_type) in self.signature.inputs.items():
                recorder = provenance.transformation_recorder(name)
                view_args[name] = artifacts[name]._view(view_type, recorder)

            outputs = self._callable_executor_(self._callable, view_args,
                                               output_types, provenance)
            # `outputs` matches a Python function's return: either a single
            # value is returned, or it is a tuple of return values. Treat both
            # cases uniformly.
            outputs_tuple = tuplize(outputs)
            for output in outputs_tuple:
                output._orphan(self._pid)

            if len(outputs_tuple) != len(self.signature.outputs):
                raise ValueError(
                    "Number of callable outputs must match number of outputs "
                    "defined in signature: %d != %d" %
                    (len(outputs_tuple), len(self.signature.outputs)))

            # Wrap in a Results object mapping output name to value so users
            # have access to outputs by name or position.
            return Results(self.signature.outputs.keys(), outputs_tuple)
Exemplo n.º 6
0
        def callable_wrapper(*args, **kwargs):
            provenance = archive.ActionProvenanceCapture(
                self.action_type, self.package, self.id)
            # This function's signature is rewritten below using
            # `decorator.decorator`. When the signature is rewritten, args[0]
            # is the function whose signature was used to rewrite this
            # function's signature.
            args = args[1:]

            # TODO this may be able to be simplified once Signature respects
            # order.
            wrapper_sig = self._callable_sig_converter_(self._callable)
            wrapper_sig = inspect.Signature.from_callable(wrapper_sig)
            wrapper_params = wrapper_sig.parameters

            user_input = {name: value for value, name in
                          zip(args, wrapper_params)}
            user_input.update(kwargs)

            self.signature.check_types(**user_input)
            output_types = self.signature.solve_output(**user_input)

            artifacts = {}
            for name in self.signature.inputs:
                artifact = artifacts[name] = user_input[name]
                provenance.add_input(name, artifact)

            parameters = {}
            for name, (primitive_type, _) in self.signature.parameters.items():
                parameter = parameters[name] = user_input[name]
                provenance.add_parameter(name, primitive_type, parameter)

            view_args = parameters.copy()
            for name, (_, view_type) in self.signature.inputs.items():
                recorder = provenance.transformation_recorder(name)
                view_args[name] = artifacts[name]._view(view_type, recorder)

            outputs = self._callable_executor_(self._callable, view_args,
                                               output_types, provenance)
            # `outputs` matches a Python function's return: either a single
            # value is returned, or it is a tuple of return values. Treat both
            # cases uniformly.
            outputs_tuple = tuplize(outputs)
            for output in outputs_tuple:
                output._orphan(self._pid)

            if len(outputs_tuple) != len(self.signature.outputs):
                raise ValueError(
                    "Number of callable outputs must match number of outputs "
                    "defined in signature: %d != %d" %
                    (len(outputs_tuple), len(self.signature.outputs)))

            # Wrap in a Results object mapping output name to value so users
            # have access to outputs by name or position.
            return Results(self.signature.outputs.keys(), outputs_tuple)
Exemplo n.º 7
0
        def callable_wrapper(*args, **kwargs):
            # This function's signature is rewritten below using
            # `decorator.decorator`. When the signature is rewritten, args[0]
            # is the function whose signature was used to rewrite this
            # function's signature.
            args = args[1:]

            # TODO this may be able to be simplified once Signature respects
            # order.
            wrapper_sig = self._callable_sig_converter_(self._callable)
            wrapper_sig = inspect.Signature.from_callable(wrapper_sig)
            wrapper_params = wrapper_sig.parameters

            user_input = {name: value for value, name in
                          zip(args, wrapper_params)}
            user_input.update(kwargs)

            self.signature.check_types(**user_input)
            output_types = self.signature.solve_output(**user_input)

            artifacts = {}
            for name in self.signature.inputs:
                artifacts[name] = user_input[name]

            parameters = {}
            for name in self.signature.parameters:
                parameters[name] = user_input[name]

            view_args = parameters.copy()
            for name, (_, view_type) in self.signature.inputs.items():
                view_args[name] = artifacts[name].view(view_type)

            execution_uuid = uuid.uuid4()
            action_reference = (
                "%s. Details on plugin, version, website, etc. will also be "
                "included, see https://github.com/qiime2/qiime2/issues/26"
                % self.id)
            artifact_uuids = {name: artifact.uuid for name, artifact in
                              artifacts.items()}
            parameter_references = {name: str(param) for name, param in
                                    parameters.items()}
            provenance = qiime.sdk.Provenance(
                execution_uuid, action_reference, artifact_uuids,
                parameter_references)

            outputs = self._callable_executor_(self._callable, view_args,
                                               output_types, provenance)
            # `outputs` matches a Python function's return: either a single
            # value is returned, or it is a tuple of return values. Treat both
            # cases uniformly.
            outputs_tuple = tuplize(outputs)
            for output in outputs_tuple:
                output._orphan(self._pid)

            if len(outputs_tuple) != len(self.signature.outputs):
                raise ValueError(
                    "Number of callable outputs must match number of outputs "
                    "defined in signature: %d != %d" %
                    (len(outputs_tuple), len(self.signature.outputs)))

            # If there is a single output, don't wrap in a Results object to
            # match how Python handles single return values. Otherwise, wrap in
            # a Results object mapping output name to value so users have
            # access to outputs by name or position.
            if len(outputs_tuple) == 1:
                return outputs_tuple[0]
            else:
                return Results(self.signature.outputs.keys(),
                               outputs_tuple)