Source code for aiida.orm.calculation.job.simpleplugins.templatereplacer

# -*- coding: utf-8 -*-
"""
This is a simple plugin that takes two node inputs, both of type ParameterData,
with the following labels: template and parameters.
You can also add other SinglefileData nodes as input, that will be copied according to
what is written in 'template' (see below).

* parameters: a set of parameters that will be used for substitution.

* template: can contain the following parameters:

    * input_file_template: a string with substitutions to be managed with the format()\
      function of python, i.e. if you want to substitute a variable called 'varname', you write\
      {varname} in the text. See http://www.python.org/dev/peps/pep-3101/ for more\
      details. The replaced file will be the input file.

    * input_file_name: a string with the file name for the input. If it is not provided, no\
      file will be created.

    * output_file_name: a string with the file name for the output. If it is not provided, no\
      redirection will be done and the output will go in the scheduler output file.

    * cmdline_params: a list of strings, to be passed as command line parameters.\
      Each one is substituted with the same rule of input_file_template. Optional

    * input_through_stdin: if True, the input file name is passed via stdin. Default is\
      False if missing.

    * files_to_copy: if defined, a list of tuple pairs, with format ('link_name', 'dest_rel_path');\
         for each tuple, an input link to this calculation is looked for, with link labeled 'link_label',\
         and with file type 'Singlefile', and the content is copied to a remote file named 'dest_rel_path'\
         Errors are raised in the input links are non-existent, or of the wrong type, or if there are \
         unused input files.

TODO: probably use Python's Template strings instead??
TODO: catch exceptions
"""
from aiida.orm.calculation.job import JobCalculation
from aiida.common.exceptions import InputValidationError
from aiida.common.datastructures import CalcInfo, CodeInfo

# TODO: write a 'input_type_checker' routine to automatically check the existence
# and type of inputs + default values etc.

__copyright__ = u"Copyright (c), This file is part of the AiiDA platform. For further information please visit http://www.aiida.net/. All rights reserved."
__license__ = "MIT license, see LICENSE.txt file."
__version__ = "0.7.0"
__authors__ = "The AiiDA team."


[docs]class TemplatereplacerCalculation(JobCalculation): """ Simple stub of a plugin that can be used to replace some text in a given template. Can be used for many different codes, or as a starting point to develop a new plugin. """ def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: a aiida.common.folders.Folder subclass where the plugin should put all its files. :param inputdict: a dictionary with the input nodes, as they would be returned by get_inputs_dict (with the Code!) """ import StringIO from aiida.orm.data.parameter import ParameterData from aiida.orm.data.singlefile import SinglefileData from aiida.orm.data.remote import RemoteData from aiida.common.utils import validate_list_of_string_tuples from aiida.common.exceptions import ValidationError parameters_node = inputdict.pop('parameters', None) if parameters_node is None: parameters = {} else: if not isinstance(parameters_node, ParameterData): raise InputValidationError("'parameters' data is not of type ParameterData") parameters = dict(parameters_node.iterattrs()) template_node = inputdict.pop('template', None) if template_node is None: raise InputValidationError("No 'template' input data") if not isinstance(template_node, ParameterData): raise InputValidationError("'template' data is not of type ParameterData") template = dict(template_node.iterattrs()) input_file_template = template.pop('input_file_template', "") input_file_name = template.pop('input_file_name', None) output_file_name = template.pop('output_file_name', None) cmdline_params_tmpl = template.pop('cmdline_params', []) input_through_stdin = template.pop('input_through_stdin', False) files_to_copy = template.pop('files_to_copy', []) if template: raise InputValidationError("The following keys could not be " "used in the template node: {}".format( template.keys())) try: validate_list_of_string_tuples(files_to_copy, tuple_length=2) except ValidationError as e: raise InputValidationError("invalid file_to_copy format: {}".format(e.message)) local_copy_list = [] remote_copy_list = [] for link_name, dest_rel_path in files_to_copy: try: fileobj = inputdict.pop(link_name) except KeyError: raise InputValidationError("You are asking to copy a file link {}, " "but there is no input link with such a name".format(link_name)) if isinstance(fileobj, SinglefileData): local_copy_list.append((fileobj.get_file_abs_path(), dest_rel_path)) elif isinstance(fileobj, RemoteData): # can be a folder remote_copy_list.append( (fileobj.get_computer().uuid, fileobj.get_remote_path(), dest_rel_path) ) else: raise InputValidationError("If you ask to copy a file link {}, " "it must be either a SinglefileData or a RemoteData; it is instead of type {}".format( link_name, fileobj.__class__.__name__)) code = inputdict.pop('code', None) if code is None: raise InputValidationError("No code in input") if len(inputdict) > 0: raise InputValidationError("The input nodes with the following labels could not be " "used by the templatereplacer plugin: {}".format( inputdict.keys())) if input_file_name is not None and not input_file_template: raise InputValidationError("If you give an input_file_name, you " "must also specify a input_file_template") if input_through_stdin and input_file_name is None: raise InputValidationError("If you ask for input_through_stdin you have to " "specify a input_file_name") input_file = StringIO.StringIO(input_file_template.format(**parameters)) if input_file_name: tempfolder.create_file_from_filelike(input_file, input_file_name) else: if input_file_template: self.logger.warning("No input file name passed, but a input file template is present") cmdline_params = [i.format(**parameters) for i in cmdline_params_tmpl] calcinfo = CalcInfo() calcinfo.retrieve_list = [] calcinfo.uuid = self.uuid calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list codeinfo = CodeInfo() codeinfo.cmdline_params = cmdline_params if input_through_stdin is not None: codeinfo.stdin_name = input_file_name if output_file_name: codeinfo.stdout_name = output_file_name calcinfo.retrieve_list.append(output_file_name) codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] return calcinfo