def _folder_with_code_validator(self, folder_with_code): """ Validates the folder_with_code. """ import os.path from aiida.common.exceptions import ValidationError if not os.path.isdir(folder_with_code): raise ValidationError("'{}' is not a valid directory".format( folder_with_code))
def setup(cls, **kwargs): # raise NotImplementedError from aiida.cmdline.commands.code import CodeInputValidationClass code = CodeInputValidationClass().set_and_validate_from_code(kwargs) try: code.store() except ValidationError as exc: raise ValidationError( 'Unable to store the computer: {}.'.format(exc)) return code
def validate_key(key): """ Validate the key string to check if it is valid (e.g., if it does not contain the separator symbol.). :return: None if the key is valid :raise aiida.common.ValidationError: if the key is not valid """ from aiida.backends.utils import AIIDA_ATTRIBUTE_SEP from aiida.common.exceptions import ValidationError if not isinstance(key, str): raise ValidationError('The key must be a string.') if not key: raise ValidationError('The key cannot be an empty string.') if AIIDA_ATTRIBUTE_SEP in key: raise ValidationError( "The separator symbol '{}' cannot be present " 'in the key of attributes, extras, etc.'.format( AIIDA_ATTRIBUTE_SEP))
def _local_rel_path_validator(self, local_rel_path): """ Validates the local_rel_path. """ import os.path from aiida.common.exceptions import ValidationError if not os.path.isfile(os.path.join(self.folder_with_code, local_rel_path)): raise ValidationError("'{}' is not a valid file within '{}'".format( local_rel_path, self.folder_with_code))
def set_exclude(self, exclude): """ Return the list of classes to exclude from autogrouping. """ the_exclude_classes = self._validate(exclude) if self.get_include() is not None: if 'all.' in self.get_include(): if 'all.' in the_exclude_classes: raise ValidationError( "Cannot exclude and include all classes") self.exclude = the_exclude_classes
def validate_m(value): """ Validate the value of the magnetic number """ if not isinstance(value, int): raise ValidationError('magnetic number (m) must be integer') # without knowing l we cannot validate the value of m. We will call an additional function # in the validate function return value
def validate_len3_list(value): """ Validate that the value is a list of three floats """ try: conv_value = list(float(i) for i in value) if len(conv_value) != 3: raise ValueError except (ValueError, TypeError): raise ValidationError('must be a list of three float number') return conv_value
def set_include(self, include): """ Set the list of classes to include in the autogrouping. """ the_include_classes = self._validate(include) if self.get_exclude() is not None: if 'all.' in self.get_exclude(): if 'all.' in the_include_classes: raise ValidationError("Cannot exclude and include all classes") self.include = the_include_classes
def _validate(self): from aiida.common.exceptions import ValidationError, ParsingError from aiida.common.files import md5_from_filelike import aiida.common.utils super(PsmlData, self)._validate() # Yet another parsing ??? with self.open(mode='r') as handle: parsed_data = parse_psml(handle.name) # Open in binary mode which is required for generating the md5 checksum with self.open(mode='rb') as handle: md5 = md5_from_filelike(handle) # TODO: This is erroneous exception, # as it is in the `upf` module oin `aiida_core` try: element = parsed_data['element'] except KeyError: raise ValidationError("No 'element' could be parsed in the PSML " "file {}".format(psml_abspath)) try: attr_element = self.get_attribute('element') except AttributeError: raise ValidationError("attribute 'element' not set.") try: attr_md5 = self.get_attribute('md5') except AttributeError: raise ValidationError("attribute 'md5' not set.") if attr_element != element: raise ValidationError("Attribute 'element' says '{}' but '{}' was " "parsed instead.".format( attr_element, element)) if attr_md5 != md5: raise ValidationError("Attribute 'md5' says '{}' but '{}' was " "parsed instead.".format(attr_md5, md5))
def par_validate(params): the_params = {} for k, v in params.iteritems(): if any([isinstance(v, int), isinstance(v, bool), isinstance(v, float), isinstance(v, str)]): the_params[k] = v else: raise ValidationError("Cannot store in the DB a parameter " "which is not of type int, bool, float or str.") return the_params
def generate_md5(self): """ Computes and returns MD5 hash of the CIF file. """ import aiida.common.utils from aiida.common.exceptions import ValidationError abspath = self.get_file_abs_path() if not abspath: raise ValidationError("No valid CIF was passed!") return aiida.common.utils.md5_file(abspath)
def set_query(self, filters=None, orders=None, projections=None, query_type=None, pk=None, alist=None, nalist=None, elist=None, nelist=None): """ Adds filters, default projections, order specs to the query_help, and initializes the qb object :param filters: dictionary with the filters :param orders: dictionary with the order for each tag :param projections: dictionary with the projection. It is discarded if query_type=='attributes'/'extras' :param query_type: (string) specify the result or the content ( "attr") :param pk: (integer) pk of a specific node """ ## Check the compatibility of query_type and pk if query_type is not "default" and pk is None: raise ValidationError("non default result/content can only be " "applied to a specific pk") ## Set the type of query self.set_query_type(query_type, alist=alist, nalist=nalist, elist=elist, nelist=nelist) ## Define projections if self._content_type is not None: # Use '*' so that the object itself will be returned. # In get_results() we access attributes/extras by # calling the get_attrs()/get_extras(). projections = ['*'] else: pass #i.e. use the input parameter projection ## TODO this actually works, but the logic is a little bit obscure. # Make it clearer if self._result_type is not self.__label__: projections = self._default_projections super(NodeTranslator, self).set_query(filters=filters, orders=orders, projections=projections, pk=pk)
def generate_md5(self): """ Generate MD5 hash of the file's contents on-the-fly. """ import aiida.common.utils from aiida.common.exceptions import ValidationError abspath = self.get_file_abs_path() if not abspath: raise ValidationError("No valid CIF was passed!") return aiida.common.utils.md5_file(abspath)
def _get_orbital_class_from_orbital_dict(self, orbital_dict): """ Gets the orbital class from the orbital dictionary stored in DB :param orbital_dict: orbital dictionary associated with the orbital :return: an Orbital produced using the module_name """ try: module_name = orbital_dict['module_name'] except KeyError: raise ValidationError("No valid module name found in orbital") return OrbitalFactory(module_name)
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!) """ try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError("No parameters specified for this " "calculation") if not isinstance(parameters, ParameterData): raise InputValidationError("parameters is not of type " "ParameterData") try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError("No code specified for this " "calculation") if inputdict: raise ValidationError("Cannot add other nodes beside parameters") ############################## # END OF INITIAL INPUT CHECK # ############################## input_json = parameters.get_dict() # write all the input to a file input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: json.dump(input_json, infile) # ============================ calcinfo ================================ calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [self._OUTPUT_FILE_NAME] codeinfo = CodeInfo() codeinfo.cmdline_params = [ self._INPUT_FILE_NAME, self._OUTPUT_FILE_NAME ] codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] return calcinfo
def _validate(self): super(AbstractCode, self)._validate() if self.is_local() is None: raise ValidationError("You did not set whether the code is local " "or remote") if self.is_local(): if not self.get_local_executable(): raise ValidationError( "You have to set which file is the local executable " "using the set_exec_filename() method") # c[1] is True if the element is a file if self.get_local_executable() not in self.get_folder_list(): raise ValidationError( "The local executable '{}' is not in the list of " "files of this code".format(self.get_local_executable())) else: if self.get_folder_list(): raise ValidationError( "The code is remote but it has files inside") if not self.get_remote_computer(): raise ValidationError("You did not specify a remote computer") if not self.get_remote_exec_path(): raise ValidationError( "You did not specify a remote executable")
def _validate(self): super()._validate() if self.is_local() is None: raise ValidationError( 'You did not set whether the code is local or remote') if self.is_local(): if not self.get_local_executable(): raise ValidationError( 'You have to set which file is the local executable ' 'using the set_exec_filename() method') if self.get_local_executable() not in self.list_object_names(): raise ValidationError( "The local executable '{}' is not in the list of " 'files of this code'.format(self.get_local_executable())) else: if self.list_object_names(): raise ValidationError( 'The code is remote but it has files inside') if not self.get_remote_computer(): raise ValidationError('You did not specify a remote computer') if not self.get_remote_exec_path(): raise ValidationError( 'You did not specify a remote executable')
def _validate(self): """Validate the UPF potential file stored for this node.""" from aiida.common.exceptions import ValidationError from aiida.common.files import md5_from_filelike super(UpfData, self)._validate() with self.open(mode='r') as handle: parsed_data = parse_upf(handle) # Open in binary mode which is required for generating the md5 checksum with self.open(mode='rb') as handle: md5 = md5_from_filelike(handle) try: element = parsed_data['element'] except KeyError: raise ValidationError( "No 'element' could be parsed in the UPF {}".format( self.filename)) try: attr_element = self.get_attribute('element') except AttributeError: raise ValidationError("attribute 'element' not set.") try: attr_md5 = self.get_attribute('md5') except AttributeError: raise ValidationError("attribute 'md5' not set.") if attr_element != element: raise ValidationError( "Attribute 'element' says '{}' but '{}' was parsed instead.". format(attr_element, element)) if attr_md5 != md5: raise ValidationError( "Attribute 'md5' says '{}' but '{}' was parsed instead.". format(attr_md5, md5))
def _default_mpiprocs_per_machine_validator(self, def_cpus_per_machine): """ Validates the default number of CPUs per machine (node) """ if def_cpus_per_machine is None: return if not isinstance(def_cpus_per_machine, ( int, long)) or def_cpus_per_machine <= 0: raise ValidationError("Invalid value for default_mpiprocs_per_machine, " "must be a positive integer, or an empty " "string if you do not want to provide a " "default value.")
def _validate_inputs(self, inputdict): """ Validate input links. """ # Check inputdict try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError("No parameters specified for this " "calculation") if not isinstance(parameters, RipsDistanceMatrixParameters): raise InputValidationError("parameters not of type " "RipsDistanceMatrixParameters") # Check code try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError("No code specified for this " "calculation") # Check input files try: distance_matrix = inputdict.pop( self.get_linkname('distance_matrix')) if not isinstance(distance_matrix, SinglefileData): raise InputValidationError( "distance_matrix not of type SinglefileData") symlink = None except KeyError: distance_matrix = None try: remote_folder = inputdict.pop( self.get_linkname('remote_folder')) if not isinstance(remote_folder, RemoteData): raise InputValidationError( "remote_folder is not of type RemoteData") comp_uuid = remote_folder.get_computer().uuid remote_path = remote_folder.get_remote_path() symlink = (comp_uuid, remote_path, self._REMOTE_FOLDER_LINK) except KeyError: raise InputValidationError( "Need to provide either distance_matrix or remote_folder") # Check that nothing is left unparsed if inputdict: raise ValidationError("Unrecognized inputs: {}".format(inputdict)) return parameters, code, distance_matrix, symlink
def _prepare_for_submission(self, tempfolder, inputdict): """ Create input files. :param tempfolder: aiida.common.folders.Folder subclass where the plugin should put all its files. :param inputdict: dictionary of the input nodes as they would be returned by get_inputs_dict """ # Check inputdict try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError("No parameters specified for this " "calculation") if not isinstance(parameters, MultiplyParameters): raise InputValidationError("parameters not of type " "MultiplyParameters") try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError("No code specified for this " "calculation") if inputdict: raise ValidationError("Unknown inputs besides MultiplyParameters") # In this example, the input file is simply a json dict. # Adapt for your particular code! input_dict = parameters.get_dict() # Write input to file input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: json.dump(input_dict, infile) # Prepare CalcInfo to be returned to aiida calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [self._OUTPUT_FILE_NAME] codeinfo = CodeInfo() # will call ./code.py in.json out.json codeinfo.cmdline_params = [ self._INPUT_FILE_NAME, self._OUTPUT_FILE_NAME ] codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] return calcinfo
def set_data(self, data): """ Replace the current data with another one. :param data: The dictionary to set. """ from aiida.common.exceptions import ModificationNotAllowed # first validate the inputs try: jsonschema.validate(data, self.data_schema) except SchemeError as err: raise ValidationError(err) kinds = data["kind_names"] for key, value in data.items(): if len(value) != len(kinds): raise ValidationError( "'{}' array not the same length as 'kind_names'" "".format(key)) # store all but the symmetry operations as attributes old_dict = copy.deepcopy(dict(self.iterattrs())) attributes_set = False try: # Delete existing attributes self._del_all_attrs() # I set the keys self._update_attrs(data) attributes_set = True finally: if not attributes_set: try: # Try to restore the old data self._del_all_attrs() self._update_attrs(old_dict) except ModificationNotAllowed: pass
def __init__(self, time, loggername="", levelname="", objname="", objpk=None, message=None, metadata=None): if not loggername or not levelname: raise ValidationError( "The loggername and levelname can't be empty") self.time = time self.loggername = loggername self.levelname = levelname self.objname = objname self.objpk = objpk self.message = message self._metadata = metadata or {}
def _set_parent_remotedata(self,remotedata): """ Used to set a parent remotefolder in the restart of ph. """ if not isinstance(remotedata,RemoteData): raise ValueError('remotedata must be a RemoteData') # complain if another remotedata is already found input_remote = self.get_inputs(node_type=RemoteData) if input_remote: raise ValidationError("Cannot set several parent calculation to a " "ph calculation") self.use_parent_folder(remotedata)
def _validate_keys(self, input_dict): """ Validates the keys otherwise raise ValidationError. Does basic validation from the parent followed by validations for the quantum numbers. Raises exceptions should the input_dict fail the valiation or if it contains any unsupported keywords. :param input_dict: the dictionary of keys to be validated :return validated_dict: a validated dictionary """ validated_dict = super()._validate_keys(input_dict) # Validate m knowing the value of l angular_momentum = validated_dict[ 'angular_momentum'] # l quantum number, must be there magnetic_number = validated_dict[ 'magnetic_number'] # m quantum number, must be there if angular_momentum >= 0: accepted_range = [0, 2 * angular_momentum] else: accepted_range = [0, -angular_momentum] if magnetic_number < min(accepted_range) or magnetic_number > max( accepted_range): raise ValidationError( f'the magnetic number must be in the range [{min(accepted_range)}, {max(accepted_range)}]' ) # Check if it is a known combination try: self.get_name_from_quantum_numbers( validated_dict['angular_momentum'], magnetic_number=validated_dict['magnetic_number']) except ValidationError: raise ValidationError( 'Invalid angular momentum magnetic number combination') return validated_dict
def _validate(self, param, is_exact=True): """ Used internally to verify the sanity of exclude, include lists """ from aiida.orm import DataFactory, CalculationFactory for i in param: if not any([ i.startswith('calculation'), i.startswith('code'), i.startswith('data'), i == 'all', ]): raise ValidationError("Module not recognized, allow prefixes " " are: calculation, code or data") the_param = [i + '.' for i in param] factorydict = { 'calculation': locals()['CalculationFactory'], 'data': locals()['DataFactory'] } for i in the_param: base, module = i.split('.', 1) if base == 'code': if module: raise ValidationError("Cannot have subclasses for codes") elif base == 'all': continue else: if is_exact: try: factorydict[base](module.rstrip('.')) except MissingPluginError: raise ValidationError( "Cannot find the class to be excluded") return the_param
def _validate(self): """ A validation method. Checks if an ``inp.xml`` file is in the FleurinpData. """ #from aiida.common.exceptions import ValidationError # check if schema file path exists. super()._validate() if 'inp.xml' in self.files: # has_inpxml = True # does nothing so far pass else: raise ValidationError( 'inp.xml file not in attribute "files". ' 'FleurinpData needs to have and inp.xml file!')
def _set_computer_string(self, string): """ Set the computer starting from a string. """ from aiida.common.exceptions import ValidationError, NotExistent from aiida.orm import Computer as AiidaOrmComputer try: computer = AiidaOrmComputer.get(string) except NotExistent: raise ValidationError("Computer with name '{}' not found in " "DB".format(string)) self._computer_validator(computer) self.computer = computer
def strip_api_prefix(self, path): """ Removes the PREFIX from an URL path. PREFIX must be defined in the config.py file:: PREFIX = "/api/v2" path = "/api/v2/calculations/page/2" strip_api_prefix(path) ==> "/calculations/page/2" :param path: the URL path string :return: the same URL without the prefix """ if path.startswith(self.prefix): return path[len(self.prefix):] raise ValidationError(f'path has to start with {self.prefix}')
def strip_prefix(path): """ Removes the PREFIX from an URL path. PREFIX must be defined in the config.py file. Ex. PREFIX = "/api/v2" path = "/api/v2/calculations/page/2" strip_prefix(path) ==> "/calculations/page/2" :param path: the URL path string :return: the same URL without the prefix """ if path.startswith(PREFIX): return path[len(PREFIX):] else: raise ValidationError('path has to start with {}'.format(PREFIX))