def __init__(self):
     self.confs = dict()
     self.comps = dict()
     # Add the standard base config
     base = Configuration(None)
     base.set_name("_base")
     self.comps["_base"] = base
     self._load_config_requests = list()
def create_dummy_component(name="DUMMY"):
    config = Configuration(MACROS)
    config.add_block("COMPBLOCK1", "PV1", "GROUP1", True)
    config.add_block("COMPBLOCK2", "PV2", "COMPGROUP", True)
    config.add_ioc("COMPSIMPLE1")
    config.set_name(name)
    return config
    def test_valid_components_xml_matches_schema(self):
        conf = Configuration(MACROS)
        conf.components["COMP1"] = "COMP1"
        conf.components["COMP2"] = "COMP2"

        xml = ConfigurationXmlConverter.components_to_xml(conf.components)

        try:
            ConfigurationSchemaChecker.check_xml_data_matches_schema(os.path.join(self.schema_dir, "components.xsd"), xml)
        except:
            self.fail()
    def test_components_xml_does_not_match_schema_raises(self):
        conf = Configuration(MACROS)
        conf.components["COMP1"] = "COMP1"
        conf.components["COMP2"] = "COMP2"

        xml = ConfigurationXmlConverter.components_to_xml(conf.components)

        # Keep it valid XML but don't match schema
        xml = xml.replace("<component ", "<domponent ")

        self.assertRaises(ConfigurationInvalidUnderSchema, ConfigurationSchemaChecker.check_xml_data_matches_schema,
                          os.path.join(self.schema_dir, "meta.xsd"), xml)
class MockActiveConfigHolder(object):
    def __init__(self, macros):
        self.config_name = ""
        self.config = Configuration(macros)
        self.blocks = dict()

    def get_config_name(self):
        return self.config_name

    def set_config_name(self, name):
        # This does not exist in the real thing
        self.config_name = name

    def get_block_details(self):
        blks = copy.deepcopy(self.config.blocks)
        # for cn, cv in self.components.iteritems():
        #     for bn, bv in cv.blocks.iteritems():
        #         if bn not in blks:
        #             blks[bn] = bv
        return blks

    def add_block(self, blockargs):
        self.config.add_block(**blockargs)
    def __init__(self, macros, vc_manager, file_manager, is_component=False, test_config=None):
        """ Constructor.

        Args:
            macros (dict): The dictionary containing the macros
            is_component (bool): Defines whether the configuration held is a component or not
            file_manager (ConfigurationFileManager): The object used to save the configuration
            test_config (Configuration): A dummy configuration used for the unit tests :o(
        """
        if test_config is None:
            self._config = Configuration(macros)
        else:
            self._config = test_config
        self._components = OrderedDict()
        self._is_component = is_component
        self._macros = macros
        self._vc = vc_manager

        self._config_path = FILEPATH_MANAGER.config_dir
        self._component_path = FILEPATH_MANAGER.component_dir
        self._filemanager = file_manager

        self._cached_config = Configuration(macros)
        self._cached_components = OrderedDict()
 def clear_config(self):
     """ Clears the configuration.
     """
     self._config = Configuration(self._macros)
     self._components = OrderedDict()
     self._is_component = False
class ConfigHolder(object):
    """ The ConfigHolder class.

    Holds a configuration which can then be manipulated via this class.
    """
    def __init__(self, macros, vc_manager, file_manager, is_component=False, test_config=None):
        """ Constructor.

        Args:
            macros (dict): The dictionary containing the macros
            is_component (bool): Defines whether the configuration held is a component or not
            file_manager (ConfigurationFileManager): The object used to save the configuration
            test_config (Configuration): A dummy configuration used for the unit tests :o(
        """
        if test_config is None:
            self._config = Configuration(macros)
        else:
            self._config = test_config
        self._components = OrderedDict()
        self._is_component = is_component
        self._macros = macros
        self._vc = vc_manager

        self._config_path = FILEPATH_MANAGER.config_dir
        self._component_path = FILEPATH_MANAGER.component_dir
        self._filemanager = file_manager

        self._cached_config = Configuration(macros)
        self._cached_components = OrderedDict()

    def clear_config(self):
        """ Clears the configuration.
        """
        self._config = Configuration(self._macros)
        self._components = OrderedDict()
        self._is_component = False

    def add_component(self, name, component):
        """ Add a component to the configuration.

        Args:
            name (string): The name of the component being added
            component (Component): The component object to be added
        """
        # Add it to the holder
        if self._is_component:
            raise Exception("Can not add a component to a component")

        if name.lower() not in self._components:
            # Add it
            component.set_name(name)
            self._components[name.lower()] = component
            self._config.components[name.lower()] = name  # Only needs its case sensitive name name
        else:
            raise Exception("Requested component is already part of the configuration: " + str(name))

    def remove_comp(self, name):
        """ Removes a component from the configuration.

        This is not needed as part of the BlockServer as such, but it helps with unit testing.

        Args:
            name (string): The name of the component to remove
        """
        # Remove it from the holder
        if self._is_component:
            raise Exception("Can not remove a component from a component")
        del self._components[name.lower()]
        del self._config.components[name.lower()]

    def get_blocknames(self):
        """ Get all the blocknames including those in the components.

        Returns:
            list : The names of all the blocks
        """
        names = list()
        for bn, bv in self._config.blocks.iteritems():
            names.append(bv.name)
        for cn, cv in self._components.iteritems():
            for bn, bv in cv.blocks.iteritems():
                # Ignore duplicates
                if bv.name not in names:
                    names.append(bv.name)
        return names

    def get_block_details(self):
        """ Get the configuration details for all the blocks including any in components.

        Returns:
            dict : A dictionary of block objects
        """
        blks = copy.deepcopy(self._config.blocks)
        for cn, cv in self._components.iteritems():
            for bn, bv in cv.blocks.iteritems():
                if bn not in blks:
                    blks[bn] = bv
        return blks

    def get_group_details(self):
        """ Get the groups details for all the groups including any in components.

        Returns:
            dict : A dictionary of group objects
        """
        blocks = self.get_blocknames()
        used_blocks = list()
        groups = copy.deepcopy(self._config.groups)
        for n, v in groups.iteritems():
            used_blocks.extend(v.blocks)
        for cn, cv in self._components.iteritems():
            for gn, grp in cv.groups.iteritems():
                if gn not in groups.keys():
                    # Add the groups if they have not been used before and exist
                    blks = [x for x in grp.blocks if x not in used_blocks and x in blocks]
                    if len(blks) > 0:
                        # Only add if contains blocks
                        groups[gn] = grp
                        groups[gn].blocks = blks
                        used_blocks.extend(blks)
                else:
                    # If group exists then append with component group
                    # But don't add any duplicate blocks or blocks that don't exist
                    for bn in grp.blocks:
                        if bn not in groups[gn].blocks and bn not in used_blocks and bn in blocks:
                            groups[gn].blocks.append(bn)
                            used_blocks.append(bn)
        return groups

    def _set_group_details(self, redefinition):
        # Any redefinition only affects the main configuration
        homeless_blocks = self.get_blocknames()
        for grp in redefinition:
            # Skip the NONE group
            if grp["name"].lower() == GRP_NONE.lower():
                continue
            # If the group is in the config then it can be changed completely
            if grp["name"].lower() in self._config.groups:
                if len(grp["blocks"]) == 0:
                    # No blocks so delete the group
                    del self._config.groups[grp["name"].lower()]
                    continue
                self._config.groups[grp["name"].lower()].blocks = []
                for blk in grp["blocks"]:
                    if blk in homeless_blocks:
                        self._config.groups[grp["name"].lower()].blocks.append(blk)
                        homeless_blocks.remove(blk)
            else:
                # Not in config yet, so add it (it will override settings in any components)
                # Only add it if there are actually blocks
                if len(grp["blocks"]) > 0:
                    self._config.groups[grp["name"].lower()] = Group(grp["name"])
                    for blk in grp["blocks"]:
                        if blk in homeless_blocks:
                            self._config.groups[grp["name"].lower()].blocks.append(blk)
                            homeless_blocks.remove(blk)
        # Finally, anything in homeless gets put in NONE
        if GRP_NONE.lower() not in self._config.groups:
            self._config.groups[GRP_NONE.lower()] = Group(GRP_NONE)
        self._config.groups[GRP_NONE.lower()].blocks = homeless_blocks

    def get_config_name(self):
        """ Get the name of the configuration.

        Returns:
            string : The name
        """
        return self._config.get_name()

    def _set_config_name(self, name):
        self._config.set_name(name)

    def get_ioc_names(self, include_base=False):
        """ Get the names of the IOCs in the configuration and any components.

        Args:
            include_base (bool, optional): Whether to include the IOCs in base

        Returns:
            list : The names of the IOCs
        """
        iocs = self._config.iocs.keys()
        for cn, cv in self._components.iteritems():
            if include_base:
                iocs.extend(cv.iocs)
            elif cn.lower() != DEFAULT_COMPONENT.lower():
                iocs.extend(cv.iocs)
        return iocs

    def get_ioc_details(self):
        """ Get the details of the IOCs in the configuration.

        Returns:
            dict : A copy of all the configuration IOC details
        """
        iocs = copy.deepcopy(self._config.iocs)
        return iocs

    def get_component_ioc_details(self):
        """ Get the details of the IOCs in any components.

        Returns:
            dict : A copy of all the component IOC details
        """
        iocs = {}
        for cn, cv in self._components.iteritems():
            for n, v in cv.iocs.iteritems():
                if n not in iocs:
                     iocs[n] = v
        return iocs

    def get_all_ioc_details(self):
        """  Ge the details of the IOCs in the configuration and any components.

        Returns:
            dict : A copy of all the IOC details
        """
        iocs = self.get_ioc_details()
        iocs.update(self.get_component_ioc_details())
        return iocs

    def get_component_names(self, include_base=False):
        """ Get the names of the components in the configuration.

        Args:
            include_base (bool, optional): Whether to include the base in the list of names

        Returns:
            list : A list of components in the configuration
        """
        l = list()
        for cn, cv in self._components.iteritems():
            if (include_base) or (cn.lower() != DEFAULT_COMPONENT.lower()):
                l.append(cv.get_name())
        return l

    def add_block(self, blockargs):
        """ Add a block to the configuration.

        Args:
            blockargs (dict): A dictionary of settings for the new block
        """
        self._config.add_block(**blockargs)

    def _add_ioc(self, name, component=None, autostart=True, restart=True, macros=None, pvs=None, pvsets=None,
                 simlevel=None):
        # TODO: use IOC object instead?
        if component is None:
            self._config.add_ioc(name, None, autostart, restart, macros, pvs, pvsets, simlevel)
        else:
            if component.lower() in self._components:
                self._components[component.lower()].add_ioc(name, component, autostart, restart, macros, pvs, pvsets,
                                                            simlevel)
            else:
                raise Exception("No component called %s" % component)

    def get_config_details(self):
        """ Get the details of the configuration.

        Returns:
            dict : A dictionary containing all the details of the configuration
        """
        config = dict()

        # Blocks, groups and IOC include the component ones
        config['blocks'] = self._blocks_to_list(True)
        config['groups'] = self._groups_to_list()
        config['iocs'] = self._iocs_to_list()
        config['component_iocs'] = self._iocs_to_list_with_components()
        # Just return the names of the components
        config['components'] = self._comps_to_list()
        config['name'] = self._config.get_name()
        config['description'] = self._config.meta.description
        config['synoptic'] = self._config.meta.synoptic
        config['history'] = self._config.meta.history

        return config

    def _comps_to_list(self):
        comps = list()
        for cn, cv in self._components.iteritems():
            if cn.lower() != DEFAULT_COMPONENT.lower():
                comps.append({'name': cv.get_name()})
        return comps

    def _blocks_to_list(self, expand_macro=False):
        blocks = self.get_block_details()
        blks = list()
        if blocks is not None:
            for block in blocks.values():
                b = block.to_dict()
                if expand_macro or b['local']:
                    # Replace the prefix
                    b['pv'] = b['pv'].replace(PVPREFIX_MACRO, self._macros[PVPREFIX_MACRO])
                blks.append(b)
        return blks

    def _groups_to_list(self):
        groups = self.get_group_details()
        grps = list()
        if groups is not None:
            for group in groups.values():
                if group.name.lower() != GRP_NONE.lower():
                    grps.append(group.to_dict())

            # Add NONE group at end
            if GRP_NONE.lower() in groups.keys():
                grps.append(groups[GRP_NONE.lower()].to_dict())
        return grps

    def _iocs_to_list(self):
        ioc_list = list()
        for n, ioc in self._config.iocs.iteritems():
            ioc_list.append(ioc.to_dict())

        return ioc_list

    def _iocs_to_list_with_components(self):
        ioc_list = self._iocs_to_list()

        for cn, cv in self._components.iteritems():
            for n, ioc in cv.iocs.iteritems():
                ioc_list.append(ioc.to_dict())
        return ioc_list

    def set_config_details(self, details):
        """ Set the details of the configuration from a dictionary.

        Args:
            details (dict): A dictionary containing the new configuration settings
        """
        self._cache_config()

        try:
            self.clear_config()
            if "iocs" in details:
                # List of dicts
                for ioc in details["iocs"]:
                    macros = self._to_dict(ioc.get('macros'))
                    pvs = self._to_dict(ioc.get('pvs'))
                    pvsets = self._to_dict(ioc.get('pvsets'))

                    if ioc.get('component') is not None:
                        raise Exception('Cannot override iocs from components')

                    self._add_ioc(ioc['name'], autostart=ioc.get('autostart'), restart=ioc.get('restart'),
                                  macros=macros, pvs=pvs, pvsets=pvsets, simlevel=ioc.get('simlevel'))

            if "blocks" in details:
                # List of dicts
                for args in details["blocks"]:
                    if args.get('component') is not None:
                        raise Exception('Cannot override blocks from components')
                    self.add_block(args)
            if "groups" in details:
                # List of dicts
                for args in details["groups"]:
                    if args.get('component') is not None:
                        raise Exception('Cannot override groups from components')
                    self._set_group_details(details['groups'])
            if "name" in details:
                self._set_config_name(details["name"])
            if "description" in details:
                self._config.meta.description = details["description"]
            if "synoptic" in details:
                self._config.meta.synoptic = details["synoptic"]
            # blockserver ignores history returned by clients:
            if "history" in details:
                self._config.meta.history = details["history"]
            if "components" in details:
                # List of dicts
                for args in details["components"]:
                    comp = self.load_configuration(args['name'], True)
                    self.add_component(comp.get_name(), comp)
        except Exception as err:
            self._retrieve_cache()
            raise err

    def _to_dict(self, data_list):
        if data_list is None:
            return None
        out = dict()
        for item in data_list:
            out[item["name"]] = item
        return out

    def set_config(self, config, is_component=False):
        """ Replace the existing configuration with the supplied configuration.

        Args:
            config (Configuration): A configuration
            is_component (bool, optional): Whether it is a component
        """
        self.clear_config()
        self._config = config
        self._is_component = is_component
        self._components = OrderedDict()
        if not is_component:
            for n, v in config.components.iteritems():
                if n.lower() != DEFAULT_COMPONENT.lower():
                    comp = self.load_configuration(v, True)
                    self.add_component(v, comp)
            # add default component to list of components
            basecomp = self.load_configuration(DEFAULT_COMPONENT, True)
            self.add_component(DEFAULT_COMPONENT, basecomp)

    def _set_component_names(self, comp, name):
        # Set the component for blocks, groups and IOCs
        for n, v in comp.blocks.iteritems():
            v.component = name
        for n, v in comp.groups.iteritems():
            v.component = name
        for n, v in comp.iocs.iteritems():
            v.component = name

    def load_configuration(self, name, is_component=False, set_component_names=True):
        """ Load a configuration.

        Args:
            name (string): The name of the configuration to load
            is_component (bool, optional): Whether it is a component
            set_component_names (bool, optional): Whether to set the component names
        """
        if is_component:
            comp = self._filemanager.load_config(name, self._macros, True)
            if set_component_names:
                self._set_component_names(comp, name)
            return comp
        else:
            return self._filemanager.load_config(name, self._macros, False)

    def save_configuration(self, name, as_component):
        """ Save the configuration.

        Args:
            name (string): The name to save the configuration under
            as_component (bool): Whether to save as a component
        """
        self._check_name(name, as_component)
        if self._is_component != as_component:
            self._set_as_component(as_component)

        if self._is_component:
            self._set_config_name(name)
            self._filemanager.save_config(self._config, True)
            self._update_version_control(name)
        else:
            self._set_config_name(name)
            # TODO: CHECK WHAT COMPONENTS self._config contains and remove _base if it is in there
            self._filemanager.save_config(self._config, False)
            self._update_version_control(name)

    def _check_name(self, name, is_comp = False):
        # Not empty
        if name is None or name.strip() == "":
            raise Exception("Configuration name cannot be blank")
        #
        if is_comp and name.lower() == DEFAULT_COMPONENT.lower():
            raise Exception("Cannot save over default component")
        # Valid chars
        m = re.match("^[a-zA-Z][a-zA-Z0-9_]*$", name)
        if m is None:
            raise Exception("Configuration name contains invalid characters")

    def _update_version_control(self, name):
        if self._is_component:
            self._vc.add(FILEPATH_MANAGER.get_component_path(name))
        else:
            self._vc.add(FILEPATH_MANAGER.get_config_path(name))

        self._vc.commit("%s modified by client" % name)

    def _set_as_component(self, value):
        if value is True:
            if len(self._components) == 0:
                self._is_component = True
            else:
                raise Exception("Can not cast to a component as the configuration contains at least one component")
        else:
            self._is_component = False

    def update_runcontrol_settings_for_saving(self, rc_data):
        """ Updates the run-control settings stored in the configuration so they can be saved.

        Args:
            rc_data (dict): The current run-control settings
        """
        self._config.update_runcontrol_settings_for_saving(rc_data)

    def _cache_config(self):
        self._cached_config = copy.deepcopy(self._config)
        self._cached_components = copy.deepcopy(self._components)

    def _retrieve_cache(self):
        self._config = copy.deepcopy(self._cached_config)
        self._components = copy.deepcopy(self._cached_components)

    def get_config_meta(self):
        """ Fetch the configuration's metadata.

        Returns:
            MetaData : The metadata for the configuration
        """
        return self._config.meta

    def get_cached_name(self):
        """ Get the previous name which may be the same as the current.

        Returns:
            string : The previous name
        """
        return self._cached_config.get_name()

    def set_history(self, history):
        """ Set history for configuration.

        Args:
            history (list): The new history
        """
        self._config.meta.history = history

    def get_history(self):
        """ Get the history for configuration.

        Returns:
            list : The history
        """
        return self._config.meta.history
def create_dummy_config():
    config = Configuration(MACROS)
    config.add_block("TESTBLOCK1", "PV1", "GROUP1", True)
    config.add_block("TESTBLOCK2", "PV2", "GROUP2", True)
    config.add_block("TESTBLOCK3", "PV3", "GROUP2", True)
    config.add_block("TESTBLOCK4", "PV4", "NONE", False)
    config.add_ioc("SIMPLE1")
    config.add_ioc("SIMPLE2")
    config.set_name("DUMMY")
    return config
 def setUp(self):
     # Create a new configuration
     self.file_manager = MockConfigurationFileManager()
     self.json_converter = MockConfigurationJsonConverter()
     self.config = Configuration(MACROS)
class TestConfigurationSequence(unittest.TestCase):
    def setUp(self):
        # Create a new configuration
        self.file_manager = MockConfigurationFileManager()
        self.json_converter = MockConfigurationJsonConverter()
        self.config = Configuration(MACROS)

    def tearDown(self):
        pass

    def test_new_config_has_blank_name(self):
        # assert
        self.assertEqual(self.config.get_name(), "")

    def test_adding_a_block_and_getting_block_names_returns_the_name_of_the_block(self):
        # arrange
        cf = self.config
        block_args = NEW_BLOCK_ARGS
        block_name = block_args['name']
        # act
        cf.add_block(**block_args)
        blocks = cf.blocks.keys()
        # assert
        self.assertEqual(len(blocks), 1)
        self.assertEqual(blocks[0], block_name.lower())

    def test_adding_a_block_also_adds_its_associated_group(self):
        # arrange
        cf = self.config
        block_args = NEW_BLOCK_ARGS
        group_name = block_args['group']
        # act
        cf.add_block(**block_args)
        groups = cf.groups.keys()
        # assert
        self.assertEqual(len(groups), 1)
        self.assertTrue(group_name.lower() in groups)

    def test_adding_the_same_block_twice_raises_exception(self):
        # arrange
        cf = self.config
        block_args = NEW_BLOCK_ARGS
        # act
        cf.add_block(**block_args)
        # assert
        self.assertRaises(Exception, cf.add_block, *block_args)

    def test_adding_ioc_correctly_adds_to_ioc_list(self):
        # arrange
        cf = self.config
        ioc_name = "TESTIOC"
        # act
        cf.add_ioc(ioc_name)
        iocs = cf.iocs
        # assert
        self.assertEqual(len(iocs), 1)
        self.assertEqual(iocs["TESTIOC"].name, ioc_name)

    def test_adding_the_same_ioc_twice_does_not_raise_exception(self):
        # arrange
        cf = self.config
        ioc_name = "TESTIOC"
        # act
        cf.add_ioc(ioc_name)
        # assert
        try:
            cf.add_ioc(ioc_name)
        except:
            self.fail("Adding the same ioc twice raised Exception unexpectedly!")

    def test_get_blocks_names_returns_empty_list_when_no_blocks(self):
        # arrange
        cf = self.config
        # act
        block_names = cf.blocks.keys()
        # assert
        self.assertEqual(len(block_names), 0)
def make_comps():
    config = Configuration(None)
    config.components["comp1"] = "comp1"
    config.components["comp2"] = "comp2"
    return config.components
    def load_config(self, name, macros, is_component):
        """Loads the configuration from the specified folder.

        Args:
            name (string): The name of the configuration
            macros (dict): The BlockServer macros
            is_component (bool): Is it a component?
        """
        configuration = Configuration(macros)

        if is_component:
            path = os.path.abspath(FILEPATH_MANAGER.get_component_path(name))
        else:
            path = os.path.abspath(FILEPATH_MANAGER.get_config_path(name))

        if not os.path.isdir(path):
            raise IOError("Configuration could not be found: " + name)

        # Create empty containers
        blocks = OrderedDict()
        groups = OrderedDict()
        components = OrderedDict()
        iocs = OrderedDict()

        # Make sure NONE group exists
        groups[GRP_NONE.lower()] = Group(GRP_NONE)

        config_files_missing = list()

        # Open the block file first
        blocks_path = os.path.join(path, FILENAME_BLOCKS)
        if os.path.isfile(blocks_path):
            root = ElementTree.parse(blocks_path).getroot()

            # Check against the schema - raises if incorrect
            self._check_againgst_schema(ElementTree.tostring(root, encoding="utf8"), FILENAME_BLOCKS)

            ConfigurationXmlConverter.blocks_from_xml(root, blocks, groups)
        else:
            config_files_missing.append(FILENAME_BLOCKS)

        # Import the groups
        groups_path = os.path.join(path, FILENAME_GROUPS)
        if os.path.isfile(groups_path):
            root = ElementTree.parse(groups_path).getroot()

            # Check against the schema - raises if incorrect
            self._check_againgst_schema(ElementTree.tostring(root, encoding="utf8"), FILENAME_GROUPS)

            ConfigurationXmlConverter.groups_from_xml(root, groups, blocks)
        else:
            config_files_missing.append(FILENAME_GROUPS)

        # Import the IOCs
        iocs_path = os.path.join(path, FILENAME_IOCS)
        if os.path.isfile(iocs_path):
            root = ElementTree.parse(iocs_path).getroot()

            # There was a historic bug where the simlevel was saved as 'None' rather than "none".
            # Correct that here
            correct_xml = ElementTree.tostring(root, encoding="utf8").replace('simlevel="None"', 'simlevel="none"')

            # Check against the schema - raises if incorrect
            self._check_againgst_schema(correct_xml, FILENAME_IOCS)

            ConfigurationXmlConverter.ioc_from_xml(root, iocs)
        else:
            config_files_missing.append(FILENAME_IOCS)

        # Import the components
        component_path = os.path.join(path, FILENAME_COMPONENTS)
        if os.path.isfile(component_path):
            root = ElementTree.parse(component_path).getroot()

            # Check against the schema - raises if incorrect
            self._check_againgst_schema(ElementTree.tostring(root, encoding="utf8"), FILENAME_COMPONENTS)

            ConfigurationXmlConverter.components_from_xml(root, components)
        elif not is_component:
            # It should be missing for a component
            config_files_missing.append(FILENAME_COMPONENTS)

        # Import the metadata
        meta = MetaData(name)
        meta_path = os.path.join(path, FILENAME_META)
        if os.path.isfile(meta_path):
            root = ElementTree.parse(meta_path).getroot()

            # Check against the schema - raises if incorrect
            self._check_againgst_schema(ElementTree.tostring(root, encoding="utf8"), FILENAME_META)

            ConfigurationXmlConverter.meta_from_xml(root, meta)
        else:
            config_files_missing.append(FILENAME_META)

        if len(config_files_missing) > 0:
            raise ConfigurationIncompleteException(
                "Files missing in " + name + " (%s)" % ",".join(list(config_files_missing))
            )

        # Set properties in the config
        configuration.blocks = blocks
        configuration.groups = groups
        configuration.iocs = iocs
        configuration.components = components
        configuration.meta = meta
        return configuration
 def __init__(self, macros):
     self.config_name = ""
     self.config = Configuration(macros)
     self.blocks = dict()