def set_inpchanges(xmltree, schema_dict, change_dict, path_spec=None): """ This method sets all the attribute and texts provided in the change_dict. The first occurrence of the attribute/tag is set :param xmltree: xml tree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input :params change_dict: dictionary {attrib_name : value} with all the wanted changes. :param path_spec: dict, with ggf. necessary further specifications for the path of the attribute An example of change_dict:: change_dict = {'itmax' : 1, 'l_noco': True, 'ctail': False, 'l_ss': True} :returns: an xmltree of the inp.xml file with changes. """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_first_attrib_value, xml_set_first_text from masci_tools.util.xml.common_functions import split_off_attrib from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict if path_spec is None: path_spec = {} path_spec = CaseInsensitiveDict(path_spec) for key, change_value in change_dict.items(): #Special alias for xcFunctional since name is not a very telling attribute name if key == 'xcFunctional': key = 'name' if key not in schema_dict['attrib_types'] and key not in schema_dict['simple_elements']: raise ValueError(f"You try to set the key:'{key}' to : '{change_value}', but the key is unknown" ' to the fleur plug-in') text_attrib = key not in schema_dict['attrib_types'] key_spec = path_spec.get(key, {}) #This method only support unique and unique_path attributes if 'exclude' not in key_spec: key_spec['exclude'] = ['other'] elif 'other' not in key_spec['exclude']: key_spec['exclude'].append('other') key_xpath = get_attrib_xpath(schema_dict, key, **key_spec) if not text_attrib: #Split up path into tag path and attribute name (original name of key could have different cases) key_xpath, key = split_off_attrib(key_xpath) if text_attrib: xml_set_first_text(xmltree, schema_dict, key_xpath, key_xpath, change_value) else: xml_set_first_attrib_value(xmltree, schema_dict, key_xpath, key_xpath, key, change_value) return xmltree
def test_case_insensitive_dict_pop_upper(key, result): """ Test case insensitive pop in CaseInsensitiveDict with upper() as normalizing function """ from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict d = CaseInsensitiveDict(TEST_DICT, upper=True) assert key in d assert d.pop(key) == result assert key not in d
def test_case_insensitive_dict_pop(key, result): """ Test case insensitive pop in CaseInsensitiveDict """ from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict d = CaseInsensitiveDict(TEST_DICT) assert key in d assert d.pop(key) == result assert key not in d
def create_outschema_dict(path, inpschema_dict): """ Creates dictionary with information about the FleurOutputSchema.xsd. The functions, whose results are added to the schema_dict and the corresponding keys are defined in schema_actions :param path: str path to the folder containing the FleurOutputSchema.xsd file :param inp_path: str path to the FleurInputSchema.xsd file (defaults to the same folder as path) """ #Add new functionality to this dictionary here schema_actions = { 'input_tag': get_input_tag, 'root_tag': get_root_tag, '_basic_types': get_basic_types, 'attrib_types': extract_attribute_types, 'simple_elements': get_basic_elements, 'tag_paths': get_tag_paths, 'iteration_tag_paths': get_tag_paths, 'unique_attribs': get_unique_attribs, 'unique_path_attribs': get_unique_path_attribs, 'other_attribs': get_other_attribs, 'iteration_unique_attribs': get_unique_attribs, 'iteration_unique_path_attribs': get_unique_path_attribs, 'iteration_other_attribs': get_other_attribs, 'tag_info': get_tag_info, 'iteration_tag_info': get_tag_info, 'omitt_contained_tags': get_omittable_tags, } #print(f'processing: {path}/FleurOutputSchema.xsd') xmlschema = etree.parse(path) xmlschema, _ = clear_xml(xmlschema) namespaces = {'xsd': 'http://www.w3.org/2001/XMLSchema'} out_version = str(xmlschema.xpath('/xsd:schema/@version', namespaces=namespaces)[0]) input_basic_types = inpschema_dict.get('_basic_types').get_unlocked() schema_dict = {} schema_dict['out_version'] = out_version for key, action in schema_actions.items(): addargs = {'input_basic_types': input_basic_types} if key in ['unique_attribs', 'unique_path_attribs', 'other_attribs', 'tag_paths', 'tag_info']: addargs['stop_iteration'] = True elif key in [ 'iteration_unique_attribs', 'iteration_unique_path_attribs', 'iteration_other_attribs', 'iteration_tag_paths', 'iteration_tag_info' ]: addargs['iteration_root'] = True addargs['iteration'] = True schema_dict[key] = action(xmlschema, namespaces, **schema_dict, **addargs) schema_dict['_input_basic_types'] = input_basic_types #We cannot do the conversion to CaseInsensitiveDict before since we need the correct case #For these attributes in the attrib_path functions schema_dict['simple_elements'] = CaseInsensitiveDict(schema_dict['simple_elements']) return schema_dict
def test_case_insensitive_dict_upper_get_not_existent(key): """ Test case insensitive lookup (non existent keys) in CaseInsensitiveDict with upper() as normalizing function """ from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict d = CaseInsensitiveDict(TEST_DICT, upper=True) assert key not in d with pytest.raises(KeyError): val = d[key]
def test_case_insensitive_dict_get_not_existent(key): """ Test case insensitive lookup (non existent keys) in CaseInsensitiveDict """ from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict d = CaseInsensitiveDict(TEST_DICT) assert key not in d with pytest.raises(KeyError): val = d[key]
def test_case_insensitive_dict_upper_get(key, result): """ Test case insensitive lookup in CaseInsensitiveDict with upper() as normalizing function """ from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict d = CaseInsensitiveDict(TEST_DICT, upper=True) assert key in d assert d[key] == result assert repr(d) == EXPECTED_REPR_UPPER
def test_case_insensitive_dict_get(key, result): """ Test case insensitive lookup in CaseInsensitiveDict """ from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict d = CaseInsensitiveDict(TEST_DICT) assert key in d assert d[key] == result assert repr(d) == EXPECTED_REPR
def create_inpschema_dict(path, apply_patches=True): """ Creates dictionary with information about the FleurInputSchema.xsd. The functions, whose results are added to the schema_dict and the corresponding keys are defined in schema_actions :param path: str path to the folder containing the FleurInputSchema.xsd file :param apply_patches: bool if True (default) the registered patching functions are applied after creation """ #Add new functionality to this dictionary here schema_actions = { 'root_tag': get_root_tag, 'tag_paths': get_tag_paths, '_basic_types': get_basic_types, 'attrib_types': extract_attribute_types, 'simple_elements': get_basic_elements, 'unique_attribs': get_unique_attribs, 'unique_path_attribs': get_unique_path_attribs, 'other_attribs': get_other_attribs, 'omitt_contained_tags': get_omittable_tags, 'tag_info': get_tag_info, } schema_patches = [convert_string_to_float_expr, patch_simple_elements] #print(f'processing: {path}/FleurInputSchema.xsd') xmlschema = etree.parse(path) xmlschema, _ = clear_xml(xmlschema) namespaces = {'xsd': 'http://www.w3.org/2001/XMLSchema'} inp_version = str( xmlschema.xpath('/xsd:schema/@version', namespaces=namespaces)[0]) inp_version_tuple = convert_str_version_number(inp_version) schema_dict = {} schema_dict['inp_version'] = inp_version for key, action in schema_actions.items(): schema_dict[key] = action(xmlschema, namespaces, **schema_dict) if key == '_basic_types' and apply_patches: schema_dict[key] = patch_basic_types(schema_dict[key], inp_version_tuple) #We cannot do the conversion to CaseInsensitiveDict before since we need the correct case #For these attributes in the attrib_path functions schema_dict['simple_elements'] = CaseInsensitiveDict( schema_dict['simple_elements']) if apply_patches: for patch_func in schema_patches: patch_func(schema_dict, inp_version_tuple) return schema_dict
def shift_value(xmltree, schema_dict, change_dict, mode='abs', path_spec=None): """ Shifts numerical values of attributes directly in the inp.xml file. The first occurrence of the attribute is shifted :param xmltree: xml tree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input :param change_dict: a python dictionary with the keys to shift and the shift values. :param mode: 'abs' if change given is absolute, 'rel' if relative :param path_spec: dict, with ggf. necessary further specifications for the path of the attribute :returns: a xml tree with shifted values An example of change_dict:: change_dict = {'itmax' : 1, 'dVac': -0.123} """ from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict if path_spec is None: path_spec = {} path_spec = CaseInsensitiveDict(path_spec) for key, value_given in change_dict.items(): key_spec = path_spec.get(key, {}) #This method only support unique and unique_path attributes if 'exclude' not in key_spec: key_spec['exclude'] = ['other'] elif 'other' not in key_spec['exclude']: key_spec['exclude'].append('other') xmltree = add_number_to_first_attrib(xmltree, schema_dict, key, value_given, mode=mode, **key_spec) return xmltree