Esempio n. 1
0
 def change_self_to_inputs(cls, v):
     refs = parse_double_quotes_vars(v)
     for ref in refs:
         v = v.replace(
             ref, ref.replace('self.', 'inputs.').replace('_', '-')
         )
     return v
 def _clean_command(command: str) -> str:
     """A helper function to reformat python command to Queenbee function commands."""
     refs = parse_double_quotes_vars(command)
     for ref in refs:
         command = command.replace(
             ref,
             ref.replace('self.', 'inputs.').replace('_', '-'))
     return command
    def _try(self, inputs: Dict[str, Any], folder: str = None) -> str:
        """Try running a function locally for testing.

        This method does not return the output values. See the folder to validate the
        outputs.

        Args:
            inputs: A dictionary that maps input names to values
                (e.g. {'input_one': 5, ...}).
            folder: An optional folder to run the function. A temporary folder
                will be created if this folder is not provided.

        Returns:
            str -- path to run_folder.
        """
        func = self.queenbee
        # check all the required inputs are provided
        for inp in func.inputs:
            name = inp.name.replace('-', '_')
            if inp.required:
                assert name in inputs, f'Required input "{name}" is missing from inputs.'
                continue
            # see if default value should be used
            if name not in inputs:
                inputs[name] = inp.default

        dst = folder or tempfile.TemporaryDirectory().name

        command = ' '.join(func.command.split())

        refs = parse_double_quotes_vars(command)
        command = command.replace('{{', '{').replace('}}', '}')
        for ref in refs:
            assert ref.startswith('inputs.'), \
                'All referenced values must start with {{inputs followed with' \
                f' variable name. Invalid referenced value: {ref}'
            var = ref.replace('inputs.', '').replace('-', '_')
            command = command.replace('{%s}' % ref, str(inputs[var]))

        for art in func.artifact_inputs:
            print(f"copying input artifact: {art.name}...")
            name = art.name.replace('-', '_')
            _copy_artifacts(inputs[name], os.path.join(dst, art.path))

        cur_dir = os.getcwd()
        os.chdir(dst)

        print(f'command: {command}')

        p = subprocess.Popen(command,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             shell=True,
                             env=os.environ)

        stdout, stderr = p.communicate()

        if p.returncode != 0 and stderr != b'':
            raise RuntimeError(stderr.decode('utf-8'))

        if stderr.decode('utf-8'):
            print(stderr.decode('utf-8'))

        if stdout.decode('utf-8'):
            print(stdout.decode('utf-8'))

        # change back to initial directory
        os.chdir(cur_dir)

        return dst
Esempio n. 4
0
        def to_queenbee(method, returns: List[Dict],
                        dag_inputs: Dict[int, str], dag_package: str):
            """Convert a task method to a Queenbee DAGTask."""
            name = method.__name__.replace('_', '-')
            tt = method.__task_template__
            if tt.__decorator__ == 'dag' and tt._package == dag_package:
                # template is another dag in the same plugin (AKA package)
                template = f'{camel_to_snake(tt.__class__.__name__)}'
            elif tt.__decorator__ == 'dag':
                # template is a recipe entry point - use recipe name as the package name
                template = tt._package["name"]
            else:
                # it is a function from a plugin
                template = \
                    f'{tt._package["name"]}/{camel_to_snake(tt.__class__.__name__)}'

            task_needs = [
                need.__name__.replace('_', '-')
                for need in method.__task_needs__
            ]
            # TODO: validate arguments against needs to ensure all the task names are
            # included in needs.
            task_arguments = _get_task_arguments(method, dag_inputs, sub_paths)
            task_loop = _get_task_loop(method.__task_loop__, dag_inputs)
            task_returns = []
            for out in returns or []:
                from_ = out.get('from', None)
                from_ = from_['value'] if from_ else from_
                to_ = out.get('to', None)
                description = out.get('description', None)
                if from_.is_artifact:
                    assert to_ is not None, 'Missing \'to\' key for {from_.name}. ' \
                        'All file and folder returns must provide a target path using ' \
                        'the `to` key.'
                    if to_:
                        # find and replace referenced values
                        refs = parse_double_quotes_vars(to_)
                        for ref in refs:
                            to_ = to_.replace(
                                ref,
                                ref.replace('self.',
                                            'inputs.').replace('_', '-'))
                    return_ = TaskPathReturn(name=from_.name,
                                             description=description,
                                             path=to_)
                else:
                    # returning a parameter
                    return_ = TaskReturn(name=from_.name,
                                         description=description)
                task_returns.append(return_)

            annotations = method.__task_annotations__
            sub_folder = method.__task_subfolder__
            return DAGTask(name=name,
                           template=template,
                           needs=task_needs,
                           arguments=task_arguments,
                           returns=task_returns,
                           loop=task_loop,
                           sub_folder=sub_folder,
                           annotations=annotations)