def test_xml_create_tag_tag_order_all_single(load_inpxml): from masci_tools.util.xml.common_functions import eval_xpath from masci_tools.util.xml.xml_setters_basic import xml_create_tag xmltree, schema_dict = load_inpxml(TEST_INPXML_PATH) root = xmltree.getroot() tags = [ 'cutoffs', 'scfLoop', 'coreElectrons', 'xcFunctional', 'magnetism', 'soc', 'prodBasis', 'expertModes', 'geometryOptimization', 'ldaU' ] node = eval_xpath(root, '/fleurInput/calculationSetup') assert [child.tag for child in node.iterchildren()] == tags order = [ 'cutoffs', 'scfLoop', 'coreElectrons', 'xcFunctional', 'magnetism', 'test_tag', 'soc', 'prodBasis', 'expertModes', 'geometryOptimization', 'ldaU' ] xmltree = xml_create_tag(xmltree, '/fleurInput/calculationSetup', 'test_tag', tag_order=order) node = eval_xpath(root, '/fleurInput/calculationSetup') assert [child.tag for child in node.iterchildren()] == order
def test_xml_create_tag_element_append(load_inpxml): from masci_tools.util.xml.common_functions import eval_xpath from masci_tools.util.xml.xml_setters_basic import xml_create_tag from lxml import etree new_element = etree.Element('test_tag') new_element.attrib['test_attrib'] = 'test' xmltree, schema_dict = load_inpxml(TEST_INPXML_PATH) root = xmltree.getroot() tags = [ 'cutoffs', 'scfLoop', 'coreElectrons', 'xcFunctional', 'magnetism', 'soc', 'prodBasis', 'expertModes', 'geometryOptimization', 'ldaU' ] node = eval_xpath(root, '/fleurInput/calculationSetup') assert [child.tag for child in node.iterchildren()] == tags xmltree = xml_create_tag(xmltree, '/fleurInput/calculationSetup', new_element) node = eval_xpath(root, '/fleurInput/calculationSetup') tags.append('test_tag') assert [child.tag for child in node.iterchildren()] == tags assert [child.attrib.items() for child in node.iterchildren()][-1] == [('test_attrib', 'test')]
def test_xml_create_tag_misaligned_order(load_inpxml): """ Test automatic correction of order """ from masci_tools.util.xml.xml_setters_basic import xml_create_tag from masci_tools.util.xml.common_functions import eval_xpath xmltree, schema_dict = load_inpxml(TEST_INPXML_PATH) root = xmltree.getroot() xml_create_tag(xmltree, '/fleurInput/atomSpecies/species', 'ldaU') #This creates an invalid order xml_create_tag(xmltree, '/fleurInput/atomSpecies/species', 'lo') order = [ 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'ldaU', 'lo' ] with pytest.raises( ValueError, match=r'Existing order does not correspond to tag_order list'): xml_create_tag(xmltree, '/fleurInput/atomSpecies/species', 'ldaU', tag_order=order, correct_order=False) with pytest.warns( UserWarning, match= r'Existing order does not correspond to tag_order list. Correcting it' ): xml_create_tag(xmltree, '/fleurInput/atomSpecies/species', 'ldaU', tag_order=order) tags = [[ 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'ldaU', 'ldaU', 'lo', 'lo', 'lo' ], [ 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'ldaU', 'ldaU', 'lo', 'lo' ]] nodes = eval_xpath(root, '/fleurInput/atomSpecies/species') assert [[child.tag for child in node.iterchildren()] for node in nodes] == tags
def test_xml_create_tag_errors(load_inpxml): from masci_tools.util.xml.xml_setters_basic import xml_create_tag xmltree, schema_dict = load_inpxml(TEST_INPXML_PATH) with pytest.raises( ValueError, match= r"Could not create tag 'test_tag' because atleast one subtag is missing." ): xml_create_tag(xmltree, '/fleurInput/calculationSetup/not_existent', 'test_tag') order = [ 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'lo' ] with pytest.raises( ValueError, match=r"The tag 'test_tag' was not found in the order list"): xml_create_tag(xmltree, '/fleurInput/atomSpecies/species', 'test_tag', tag_order=order) order = ['atomicCutoffs', 'electronConfig', 'energyParameters', 'lo'] with pytest.raises( ValueError, match= r"Did not find existing elements in the tag_order list: {'mtSphere'}" ): xml_create_tag(xmltree, '/fleurInput/atomSpecies/species', 'lo', tag_order=order)
def test_xml_create_tag_tag_order_multiple_occurrences_list(load_inpxml): from masci_tools.util.xml.common_functions import eval_xpath from masci_tools.util.xml.xml_setters_basic import xml_create_tag xmltree, schema_dict = load_inpxml(TEST_INPXML_PATH) root = xmltree.getroot() tags = [[ 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'lo', 'lo', ], [ 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'lo' ]] nodes = eval_xpath(root, '/fleurInput/atomSpecies/species') assert [[child.tag for child in node.iterchildren()] for node in nodes] == tags order = [ 'test_tag', 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'lo' ] xmltree = xml_create_tag(xmltree, '/fleurInput/atomSpecies/species', 'test_tag', tag_order=order, occurrences=[-1]) tags = [[ 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'lo', 'lo', ], [ 'test_tag', 'mtSphere', 'atomicCutoffs', 'electronConfig', 'energyParameters', 'lo' ]] nodes = eval_xpath(root, '/fleurInput/atomSpecies/species') assert [[child.tag for child in node.iterchildren()] for node in nodes] == tags
def xml_create_tag_schema_dict(xmltree, schema_dict, xpath, base_xpath, element, create_parents=False, occurrences=None): """ This method evaluates an xpath expression and creates a tag in a xmltree under the returned nodes. If there are no nodes evaluated the subtags can be created with `create_parents=True` The tag is always inserted in the correct place if a order is enforced by the schema :param xmltree: an xmltree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input :param xpath: a path where to place a new tag :param base_xpath: path where to place a new tag without complex syntax ([] conditions and so on) :param element: a tag name or etree Element to be created :param create_parents: bool optional (default False), if True and the given xpath has no results the the parent tags are created recursively :param occurrences: int or list of int. Which occurence of the parent nodes to create a tag. By default all nodes are used. :raises ValueError: If the nodes are missing and `create_parents=False` :returns: xmltree with created tags """ from masci_tools.util.xml.xml_setters_basic import xml_create_tag from masci_tools.util.xml.common_functions import check_complex_xpath, split_off_tag check_complex_xpath(xmltree, base_xpath, xpath) tag_info = schema_dict['tag_info'][base_xpath] if not etree.iselement(element): #Get original case of the tag element_name = (tag_info['simple'] | tag_info['complex']).original_case[element] try: element = etree.Element(element_name) except ValueError as exc: raise ValueError( f"Failed to construct etree Element from '{element_name}'" ) from exc else: element_name = element.tag if len(tag_info['order']) == 0: tag_order = None else: tag_order = tag_info['order'] several_tags = element_name in tag_info['several'] parent_nodes = eval_xpath(xmltree, xpath, list_return=True) if len(parent_nodes) == 0: if create_parents: parent_xpath, parent_name = split_off_tag(base_xpath) complex_parent_xpath, _ = split_off_tag(xpath) xmltree = xml_create_tag_schema_dict(xmltree, schema_dict, complex_parent_xpath, parent_xpath, parent_name, create_parents=create_parents) else: raise ValueError( f"Could not create tag '{element_name}' because atleast one subtag is missing. " 'Use create=True to create the subtags') return xml_create_tag(xmltree, xpath, element, tag_order=tag_order, occurrences=occurrences, several=several_tags)