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 _groups_to_list(groups):
        grps = list()
        if groups is not None:
            for group in groups.values():
                if group.name.lower() != GRP_NONE.lower():
                    grps.append({"name": group.name, "component": group.component, "blocks": group.blocks})

            # Add NONE group at end
            if GRP_NONE.lower() in groups.keys():
                grps.append({"name": GRP_NONE, "component": None, "blocks": groups[GRP_NONE.lower()].blocks})
        return grps
    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 test_groups_to_json_converts_correctly(self):
        # Arrange
        jc = self.json_converter
        groups = OrderedDict()
        groups["TESTGROUP1".lower()] = Group("TESTGROUP1")
        groups["TESTGROUP1".lower()].blocks = ["TESTGROUP1BLOCK1", "TESTGROUP1BLOCK2"]
        groups["TESTGROUP2".lower()] = Group("TESTGROUP2")
        groups["TESTGROUP2".lower()].blocks = ["TESTGROUP2BLOCK1", "TESTGROUP2BLOCK2"]
        groups["TESTGROUP3".lower()] = Group("TESTGROUP3", "TESTCOMPONENT1")
        groups["TESTGROUP3".lower()].blocks = ["TESTGROUP3BLOCK1", "TESTGROUP3BLOCK2"]
        groups[GRP_NONE.lower()] = Group(GRP_NONE)
        groups[GRP_NONE.lower()].blocks = ["TESTGROUPNONEBLOCK1", "TESTGROUPNONEBLOCK2"]

        # act
        groups_json = jc.groups_to_json(groups)
        returned = json.loads(groups_json)
        # Returned should be a list of dictionaries

        # Assert
        self.assertEqual(len(returned), 4)
        self.assertEqual(returned[0]['name'], "TESTGROUP1")
        self.assertEqual(returned[1]['name'], "TESTGROUP2")
        self.assertEqual(returned[2]['name'], "TESTGROUP3")
        self.assertEqual(returned[3]['name'], GRP_NONE)
        self.assertTrue("TESTGROUP1BLOCK1" in returned[0]['blocks'])
        self.assertTrue("TESTGROUP1BLOCK2" in returned[0]['blocks'])
        self.assertTrue("TESTGROUP2BLOCK1" in returned[1]['blocks'])
        self.assertTrue("TESTGROUP2BLOCK2" in returned[1]['blocks'])
        self.assertTrue("TESTGROUP3BLOCK1" in returned[2]['blocks'])
        self.assertTrue("TESTGROUP3BLOCK2" in returned[2]['blocks'])
        self.assertTrue("TESTGROUPNONEBLOCK1" in returned[3]['blocks'])
        self.assertTrue("TESTGROUPNONEBLOCK2" in returned[3]['blocks'])
        self.assertIsNone(returned[0]["component"])
        self.assertIsNone(returned[1]["component"])
        self.assertEqual(returned[2]["component"], "TESTCOMPONENT1")
        self.assertIsNone(returned[3]["component"])
    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