示例#1
0
    def _load_bench_conf(self):
        """
        Loads The Bench Configuration from its XML representation into a dict

        """
        self._bench_conf = AttributeDict()

        # New way of defining device parameters == as defined in the device catalog
        try:
            self._bench_tree_node = etree.parse(self.bench_conf_filename)
        except XMLParsingErrors:
            _error("Corrupted file {0}: {1}".format(
                self.bench_conf_filename,
                Utils.get_exception_info()[1]))

        node = self.bench_device_node
        if node is not None and len(node) > 0:
            # To load proper device config, need to get device model name
            device_conf = self.device_conf
            if device_conf:
                self._device_model_name = device_conf.get("DeviceModel")
            if self._device_model_name in ('', "", None, 'multi'):
                self._device_model_name = node[0].get("deviceModel")

            conf = self._parse_bench_node(node[0])
            if conf:
                self._bench_conf.update(conf)
示例#2
0
 def __init__(self):
     """
     DeviceModuleBase module
     """
     self.__device = None
     self.__logger = None
     self.__module_conf_file = None
     self.__module_config = None
     self.__global_conf = None
     self.__module_config = AttributeDict()
     self.__name = None
示例#3
0
    def _parse_bench_node(self, node):
        """
        Parses XML `Phone` node(s) from Bench Catalog file and maps it into a python structure (dict)

        :return: A dict mapping XML configuration
        :rtype: AttributeDict

        :raise AcsConfigException.INVALID_BENCH_CONFIG: If a (or more) deprecated parameter(s)
            is/are found in a Phone node

        """
        LOGGER_FWK.info(
            'Loading optional device model parameters from CLI and/or BenchConfig '
            'for {0} ({1})...'.format(self._device_name,
                                      self._device_model_name))
        buf_params = AttributeDict()
        # Storing value to avoid recomputing each call
        device_model_name = self.device_model_name

        if device_model_name:
            buf_params["Name"] = device_model_name

        if self.device_conf_filename:
            buf_params["DeviceConfigPath"] = self.device_conf_filename

        # Get phone properties
        for attrs in node.xpath(".//Parameter"):
            name, value, description = attrs.get("name"), attrs.get(
                "value"), attrs.get("description")

            if name in self.PROHIBITIVE_KEYS:
                # Do not allow to override internal keys
                # as it would lead to nasty & unexpected behavior !!
                continue

            # Not supported anymore, raise AcsConfigException.INVALID_BENCH_CONFIG !!
            if name and value:
                buf_params[name] = value
                self._bench_conf_deprecated[name] = (value, description)
            else:
                buf_params.update(attrs.attrib)

        # Report Errors if so
        if self.bench_contains_errors:
            LOGGER_FWK.error(self._report_errors())
            _error(
                'Invalid Bench Parameters format found! {0}'.format(', '.join(
                    self._bench_conf_deprecated.keys())),
                AcsConfigException.INVALID_BENCH_CONFIG)

        # Extracting device modules if so
        buf_params.device_modules = self.extract_device_modules(node)

        return buf_params
示例#4
0
        def extract_params(s_node):
            """
            Get Section properties

            :param s_node: The Section node
            :type s_node: etree.Element

            :return: A dict of Section's attributes
            :rtype: AttributeDict

            """
            params = AttributeDict()
            for attrs in s_node.xpath(".//Parameter"):
                params.update(attrs.attrib)
            return params
示例#5
0
    def device_only_params(self):
        """
        Get a map with only parameters, no sections !

        :return: A map with only parameters
        :rtype: AttributeDict()

        """
        if not self._device_only_params:
            # Store the Current Device's configuration
            self._device_only_params = AttributeDict()
            self._load_params_only(self.device_conf, self._device_only_params)

            # Updating all unchecked extra parameters
            self._device_only_params.update(self.device_extra_params)

        if 'description' in self.device_extra_params:
            del self.device_extra_params['description']

        return self._device_only_params
示例#6
0
    def load(config):
        """
        Load global device conf to the device conf objects

        :type config: dict
        :param config: device global conf dictionary
        """
        device_conf = AttributeDict()
        for key, value in config.items():
            device_conf[key] = value

        return device_conf
示例#7
0
    def extract_device_modules(cls, node):
        """
        Get DeviceModule Node(s) properties

        :param node: The root node
        :type node: etree.Element

        :return: A dict of DeviceModule's attributes
        :rtype: AttributeDict

        """
        # Extract device modules
        module_params = AttributeDict()
        for device_module in node.xpath(".//DeviceModule/*"):
            if device_module.tag not in module_params:
                # init module config as list
                module_params[device_module.tag] = []
            module_config = AttributeDict()
            module_config.class_name = device_module.get("className")
            module_config.config = device_module.get("config")

            # Handle parameter overload
            module_config.parameter_overloaded = {}
            for module_param in device_module.xpath("Parameter"):
                module_config.parameter_overloaded.update(module_param.attrib)

            # store config of the module
            module_params[device_module.tag].append(module_config)
            # Removing the node for post processing
            device_module.getparent().remove(device_module)
        return module_params
示例#8
0
    def _parse_device_node(self):
        """
        Parses XML Device Catalog file and maps it into a python structure (dict)

        :return: A dict mapping XML configuration
        :rtype: AttributeDict

        """
        def extract_params(s_node):
            """
            Get Section properties

            :param s_node: The Section node
            :type s_node: etree.Element

            :return: A dict of Section's attributes
            :rtype: AttributeDict

            """
            params = AttributeDict()
            for attrs in s_node.xpath(".//Parameter"):
                params.update(attrs.attrib)
            return params

        buf_params = AttributeDict()
        # Storing value to avoid recomputing each call
        device_model_name = self.device_model_name

        if device_model_name:
            buf_params["Name"] = device_model_name

        if self.device_conf_filename:
            buf_params["DeviceConfigPath"] = self.device_conf_filename

        node = self.device_root_node
        buf_params['device_modules'] = self.extract_device_modules(node)
        for section_node in list(node):
            buf_params[section_node.tag] = extract_params(section_node)

        self._device_conf = buf_params
示例#9
0
    def __init__(self, config, logger):
        """
        Constructor

        :type  config: dict
        :param config: Device configuration to use

        :type  logger: logger
        :param logger: Logger to use
        """
        device_man = DeviceManager.DeviceManager()
        self._global_config = device_man.get_global_config()
        self._device_config = config
        self._uecmd_path = self._device_config.UECmd
        self._device_model_name = self._device_config.Name
        self._wait_btwn_cmd = self.get_config("waitBetweenCmd", 5, float)
        self._min_file_install_timeout = self.get_config(
            "minFileInstallTimeout", 30, int)
        self._device_name = config.device_name
        self._acs_agent = None
        self._userdata_path = None
        self.uecommands = {}
        self._device_capabilities = []
        self._logger = logger
        self.__uecmd_instances = {}
        self.retrieve_tc_debug_log = None

        self._module_instances = AttributeDict()
        self._device_properties = DeviceProperties()
        self._flash_device_properties = FlashDeviceProperties()
        self._device_capabilities = DCManager.load_device_capabilities(
            self._device_config.deviceCapabilities, self._logger)
        campaign_report_tree = self._global_config.campaignConfig[
            "campaignReportTree"]
        campaign_report_tree.set_hw_variant_name(self.hw_variant_name)
        campaign_report_tree.create_report_folder()
示例#10
0
class DeviceModuleBase(object):
    """
    Device module interface
    """
    def __init__(self):
        """
        DeviceModuleBase module
        """
        self.__device = None
        self.__logger = None
        self.__module_conf_file = None
        self.__module_config = None
        self.__global_conf = None
        self.__module_config = AttributeDict()
        self.__name = None

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, new_name):
        self.__name = new_name

    @property
    def configuration_file(self):
        return self.__module_conf_file

    @configuration_file.setter
    def configuration_file(self, new_conf):
        self.__module_conf_file = new_conf

    @property
    def configuration(self):
        return self.__module_config

    @property
    def path(self):
        return path.dirname(path.abspath(inspect.getfile(self.__class__)))

    @property
    def device(self):
        """
        Retrieve the device instance associated to that module
        """
        return self.__device

    @device.setter
    def device(self, new_device):
        """
        Set the device instance associated to that module
        """
        self.__device = new_device

    @property
    def logger(self):
        """
        Retrieve the logger associated to that module
        """
        return self.__logger

    @logger.setter
    def logger(self, new_logger):
        """
        Set the logger associated to that module
        """
        self.__logger = new_logger

    @property
    def global_conf(self):
        return self.__global_conf

    @global_conf.setter
    def global_conf(self, conf):
        self.__global_conf = conf

    def load_conf(self):
        """
        Load the configuration of the module.
        Need to be overloaded is you expect to use a specific configuration file.
        """
        if self.configuration_file and path.isfile(self.configuration_file):
            parser = Parser.get_parser(self.configuration_file)
            for module_conf in parser.get("/ModuleConfiguration/*"):
                if self.device.config.get(module_conf.tag):
                    # Parameter is available in the device config
                    # it may be an old override, take it for back compatibility
                    self.__module_config[module_conf.tag] = self.device.config[
                        module_conf.tag]
                else:
                    self.__module_config[module_conf.tag] = module_conf.text
                    # If the XML parameter has some attributes - parse them
                    if len(module_conf.attrib) != 0:
                        self.__module_config.update(module_conf.attrib)
        else:
            self.logger.error("No module configuration to load!")
示例#11
0
    def __init__(self, name, device_model_name, global_config, cli_params):
        """
        Constructor

        :param global_config: The Global configuration
        :type global_config: AttributeDict or dict

        """
        # ################ Global #################

        # Global Configuration instance (grouping all needed parameters)
        self._global_config = global_config

        # ################ CmdLine #################

        # Command line parameters
        self._cli_params = cli_params

        # Unknown Parameter(s) found in the Command line arguments (``-o``)
        self._cli_unknown_parameters = {}

        # ################ Device #################

        # The current Device's name
        self._device_name = name

        # The Device parameters only (no sections)
        self._device_only_params = {}

        # The Device extra unchecked parameters reference
        self._device_extra_params = {}

        # The Device Model's map with its sections (dict)
        self._device_conf_sections = None

        # The Device Model name
        self._device_model_name = device_model_name

        # The Device Model final XML node
        self._device_model_final = None

        # Device Configuration etree.ElementTree
        self._device_tree_node = None

        # Device Configuration root node (etree.Element)
        self._device_root_node = None

        # Device Configuration filename (abspath)
        self._device_conf_filename = None

        # Device configuration instance (AttributeDict)
        self._device_conf = None

        # Device's XML Schema reference
        self._device_schema = None

        # ################ Bench #################

        # Unknown Parameter(s) found in the BenchConfig file
        self._bench_unknown_parameters = {}

        # Global Bench Configuration instance
        self._bench_conf_global = None

        # Bench Configuration etree.ElementTree
        self._bench_tree_node = None

        # Bench Configuration root node (etree.Element)
        self._bench_root_node = None

        # Bench Configuration `Phone` node (etree.Element)
        # for the given Device Model name
        self._bench_device_node = None

        # Bench Configuration filename (abspath)
        self._bench_conf_filename = None

        # Bench configuration instance (AttributeDict)
        self._bench_conf = None

        # Bench configuration instance (AttributeDict)
        self._bench_conf_deprecated = AttributeDict()
示例#12
0
class Device(object):
    """
    A Device Class, representing a D.U.T with its :

    * Parameters
    * Overrides mechanisms
    * Parameters checker

    """

    ROOT_TAG = 'DeviceModel'
    SCHEMA_LOCATION_KEY = '{http://www.w3.org/2001/XMLSchema-instance}noNamespaceSchemaLocation'
    DEPRECATED_OVERRIDE_MSG = 'Unsupported format detected in {0}'
    DEPRECATED_ELEMENT_MSG = '\n\t<Parameter name="{0}" value="{1}" {2} />'
    RECOMMENDED_ELEMENT_MSG = '\n\t<Parameter {0}="{1}" {2} />'
    PROHIBITIVE_KEYS = ('Name', 'DeviceConfigPath', 'device_modules',
                        'parameter_overloaded')

    @classmethod
    def dict2xml(cls, xml_map, parent, parameter_tag='Parameter'):
        """
        This class method maps into the given XML root node,
        all what is contained into inner configuration dict.

        It produces an XML node which can either pass or not validations

        :param xml_map: The XML map
        :type xml_map: dict or AttributeDict

        :param parent: The root/parent node
        :type parent: etree.Element

        :param parameter_tag: The Parameter `tag` name
        :type parameter_tag: str

        """
        def generic_processing():
            """
            This method's purpose is to structure inner actions only

            .. important:: For parameters details see parent definition (:meth:`DeviceConfigLoader.dict2xml`)

            """
            for key, value in xml_map.iteritems():
                if isinstance(value, (dict, AttributeDict)):
                    section = etree.Element(_tag=key)
                    parent.append(section)
                    cls.dict2xml(value, section, parameter_tag=parameter_tag)
                else:
                    parent.append(
                        etree.Element(_tag=parameter_tag, attrib={key: value}))

        if not isinstance(parent, EtreeElementType):
            _error('Need A XML node as `parent` attribute ! Got => {0}'.format(
                type(parent)))

        # Hack for non-generic Implementation tag.
        if parent.tag == 'Implementation':
            parent.append(etree.Element(_tag=parameter_tag, attrib=xml_map))
        else:
            generic_processing()

    @classmethod
    def extract_schema(cls, node, schema_folder, file_only=True):
        """
        Class Method which extracts the XML Schema file reference if so.

        :param node: The XML Node or the XML file to be parsed into a node
        :type node: etree.Element

        :param schema_folder: If provided the value is concatenated to the schema basename if available
        :type schema_folder: str

        :param file_only: If set to True the schema is not loaded
        :type file_only: bool

        :return: Either the schema filename or its corresponding XML instance (
        :rtype: str or etree.XMLSchema

        """
        schema_files = []
        if isinstance(node, basestring) and path.isfile(node):
            node = etree.parse(node).getroot()

        schema_file = node.attrib.get(cls.SCHEMA_LOCATION_KEY)
        if schema_file and schema_folder and path.isdir(schema_folder):
            schema_file = PathMgr.absjoin(schema_folder,
                                          path.basename(schema_file))
            schema_files = os.listdir(schema_folder)

        try:
            self_name = node.base
        except AttributeError:
            self_name = "Unknown"

        if not schema_file or not path.isfile(schema_file):
            _error(("Your Configuration file : {0} does not define an"
                    " 'xsi:noNamespaceSchemaLocation' in root element!"
                    ).format(self_name))

        if path.basename(schema_file) not in schema_files:
            _error(
                "Your Device Model file : {0} does not define a Valid Schema"
                " 'xsi:noNamespaceSchemaLocation' in root element!").format(
                    self_name)

        if file_only:
            return schema_file
        try:
            return etree.XMLSchema(etree.parse(schema_file))
        except etree.Error as schema_error:
            _error(schema_error.message)

    @classmethod
    def extract_device_modules(cls, node):
        """
        Get DeviceModule Node(s) properties

        :param node: The root node
        :type node: etree.Element

        :return: A dict of DeviceModule's attributes
        :rtype: AttributeDict

        """
        # Extract device modules
        module_params = AttributeDict()
        for device_module in node.xpath(".//DeviceModule/*"):
            if device_module.tag not in module_params:
                # init module config as list
                module_params[device_module.tag] = []
            module_config = AttributeDict()
            module_config.class_name = device_module.get("className")
            module_config.config = device_module.get("config")

            # Handle parameter overload
            module_config.parameter_overloaded = {}
            for module_param in device_module.xpath("Parameter"):
                module_config.parameter_overloaded.update(module_param.attrib)

            # store config of the module
            module_params[device_module.tag].append(module_config)
            # Removing the node for post processing
            device_module.getparent().remove(device_module)
        return module_params

    @property
    def cli_parameters(self):
        """
        Property/Generator yielding the CLI parameter(s) from list to dict-style

        For example, -o bootTimeout="300" in CLI produces a list like this :

            .. code-block:: python

                [bootTimeout="300"]

        It becomes :

            .. code-block:: python

                {bootTimeout: "300"}

        """
        if isinstance(self._cli_params, list):
            for device_parameter in self._cli_params:
                split_device_param = device_parameter.split("=")
                # Set parameters which are correctly set in ACS command line
                # as follow : -o bootTimeout="300" or --op=bootTimeout="300" or
                # --override_device_parameter=bootTimeout="300"
                if len(split_device_param) == 2:
                    # Store device parameter name and value
                    yield split_device_param

    @property
    def device_extra_params(self):
        """
        Property holding All extra parameters found either in Bench Config file
        or CLI that are not referenced in the corresponding Device Model Schema.

        Since those parameters cannot be validated, we just update device configuration with it !

        :return: The Current Device's configuration
        :rtype: AttributeDict

        """
        if not self._device_extra_params:
            self._device_extra_params = {}
            self._device_extra_params.update(self._bench_unknown_parameters)
            self._device_extra_params.update(self._cli_unknown_parameters)
        return self._device_extra_params

    @property
    def device_only_params(self):
        """
        Get a map with only parameters, no sections !

        :return: A map with only parameters
        :rtype: AttributeDict()

        """
        if not self._device_only_params:
            # Store the Current Device's configuration
            self._device_only_params = AttributeDict()
            self._load_params_only(self.device_conf, self._device_only_params)

            # Updating all unchecked extra parameters
            self._device_only_params.update(self.device_extra_params)

        if 'description' in self.device_extra_params:
            del self.device_extra_params['description']

        return self._device_only_params

    @property
    def device_model_final(self):
        """
        Property computing/holding the final Device Model XML node,
        rebuild from its mapped AttributeDict

        :return: The final Device Model XML node
        :rtype: etree.Element

        """
        if self._device_model_final is None:
            self._device_model_final = etree.Element(_tag=self.ROOT_TAG)
            # Hack to match XSD, ACS input is not compliant!
            xml_map = self.device_conf.copy()

            dm_key = 'device_modules'

            if dm_key in xml_map:
                _override_filter(xml_map,
                                 conf_key=dm_key,
                                 klass=(list, ),
                                 callback=lambda v: v[0] if v else None)
                xml_map['DeviceModule'] = xml_map[dm_key]

            for unexpected_key in self.PROHIBITIVE_KEYS:
                if unexpected_key in xml_map:
                    del xml_map[unexpected_key]

            self.dict2xml(xml_map, self._device_model_final)
        return self._device_model_final

    @property
    def device_model_name(self):
        """
        Computes the Current Device Model name

        :return: Current Device Model name
        :rtype: str

        """
        if not self._device_model_name:
            if self._device_name == AcsConstants.DEFAULT_DEVICE_NAME:
                # For PHONE1 we need to retrieve the device model name
                if self._device_model_name and "multi" not in self._device_model_name:
                    pass
                elif ((not self._device_model_name
                       or "multi" in self._device_model_name)
                      and self.bench_conf  # noqa
                      and "Name" in self.bench_conf):  # noqa
                    # Device model name is not specified or in "multi" mode
                    # Get it from bench config
                    self._device_model_name = self.bench_conf.Name
                else:
                    _error(
                        "No device model specified/configured. Cannot instantiate the device."
                    )
            else:
                # For any other phone than phone1, the information comes from the bench config.
                self._device_model_name = self.bench_conf.Name
        return self._device_model_name

    @property
    def device_root_node(self):
        """
        Property holding the Device root's node

        :return: The device root's node
        :rtype: etree.Element

        .. note:: Consider etree.Element as an `etree._Element` instance factory

            The real Class is **etree._Element**

        """
        if self._device_root_node is None and self._device_tree_node is not None:
            self._device_root_node = self._device_tree_node.getroot()

        if self._device_root_node is None:
            _error("Device catalog is corrupted! Unable to parse {0}".format(
                self.device_conf_filename))

        return self._device_root_node

    @property
    def device_schema(self):
        """
        Property holding the Device associated XML Schema instance

        :return: The device XML Schema instance
        :rtype: etree.XMLSchema

        """
        return self._device_schema

    @property
    def device_conf_filename(self):
        """
        Property holding the Device configuration filename (full path)

        :return: The Device configuration filename
        :rtype: str

        """
        if not self._device_conf_filename:
            device_model, catalog_path = self.device_model_name, Paths.DEVICE_MODELS_CATALOG
            device_config_filename = "{0}.xml".format(device_model)

            files = FileUtilities.find_file(catalog_path,
                                            device_config_filename)
            files_count = len(files)
            error = None
            if files_count == 0:
                error = ("Device {0} not found in the catalog {1} !".format(
                    device_model,
                    catalog_path), AcsConfigException.FILE_NOT_FOUND)
            elif files_count > 1:
                error = ("Device {0} found multiple times in the catalog {1}. "
                         "{2}".format(device_model, catalog_path,
                                      "\n at ".join(files)),
                         AcsConfigException.PROHIBITIVE_BEHAVIOR)
            else:
                self._device_conf_filename = files[0]
            if error:
                _error(*error)
        return self._device_conf_filename

    @property
    def device_conf(self):
        """
        Property holding the Current Device's configuration

        :return: The Current Device's configuration
        :rtype: AttributeDict

        """
        return self._device_conf

    @property
    def bench_contains_errors(self):
        """
        Property holding whether or not
        the Bench Configuration file is properly filled in.

        :return: Whether or not the Bench Configuration file is properly filled in
        :rtype: bool

        """
        return len(self._bench_conf_deprecated) > 0

    @property
    def bench_root_node(self):
        """
        Property holding the Bench root's node

        :return: The Bench root's node
        :rtype: etree.Element

        .. note:: Consider etree.Element as an `etree._Element` instance factory

            The real Class is **etree._Element**

        """
        if self._bench_root_node is None and self._bench_tree_node is not None:
            self._bench_root_node = self._bench_tree_node.getroot()
        return self._bench_root_node

    @property
    def bench_device_node(self):
        """
        Property holding the Current Device Bench Phone's node

        :return: The Current Device Bench Phone's node
        :rtype: etree.Element

        .. note:: Consider etree.Element as an `etree._Element` instance factory

            The real Class is **etree._Element**

        """
        if self._bench_tree_node is not None:
            xpath = "//Phone[@name='{0}']".format(self._device_name)
            self._bench_device_node = self._bench_tree_node.xpath(xpath)
        return self._bench_device_node

    # noinspection PyUnresolvedReferences
    @property
    def bench_conf_global(self):
        """
        Property holding the Global Bench Configuration instance

        .. seealso:: Constructor parameters.

        :return: The Global Bench configuration instance
        :rtype: AttributeDict

        """
        if not self._bench_conf_global:
            self._bench_conf_global = self._global_config.benchConfig
        return self._bench_conf_global

    @property
    def bench_conf_filename(self):
        """
        Property holding the Bench Configuration filename (abspath)

        :return: The Bench configuration filename
        :rtype: str

        """
        if not self._bench_conf_filename:
            self._bench_conf_filename = self.bench_conf_global.file
        return self._bench_conf_filename

    @property
    def bench_conf(self):
        """
        Property holding the Current Device's Bench configuration

        :return: The Current Device's Bench configuration
        :rtype: AttributeDict

        """
        return self._bench_conf

    def __init__(self, name, device_model_name, global_config, cli_params):
        """
        Constructor

        :param global_config: The Global configuration
        :type global_config: AttributeDict or dict

        """
        # ################ Global #################

        # Global Configuration instance (grouping all needed parameters)
        self._global_config = global_config

        # ################ CmdLine #################

        # Command line parameters
        self._cli_params = cli_params

        # Unknown Parameter(s) found in the Command line arguments (``-o``)
        self._cli_unknown_parameters = {}

        # ################ Device #################

        # The current Device's name
        self._device_name = name

        # The Device parameters only (no sections)
        self._device_only_params = {}

        # The Device extra unchecked parameters reference
        self._device_extra_params = {}

        # The Device Model's map with its sections (dict)
        self._device_conf_sections = None

        # The Device Model name
        self._device_model_name = device_model_name

        # The Device Model final XML node
        self._device_model_final = None

        # Device Configuration etree.ElementTree
        self._device_tree_node = None

        # Device Configuration root node (etree.Element)
        self._device_root_node = None

        # Device Configuration filename (abspath)
        self._device_conf_filename = None

        # Device configuration instance (AttributeDict)
        self._device_conf = None

        # Device's XML Schema reference
        self._device_schema = None

        # ################ Bench #################

        # Unknown Parameter(s) found in the BenchConfig file
        self._bench_unknown_parameters = {}

        # Global Bench Configuration instance
        self._bench_conf_global = None

        # Bench Configuration etree.ElementTree
        self._bench_tree_node = None

        # Bench Configuration root node (etree.Element)
        self._bench_root_node = None

        # Bench Configuration `Phone` node (etree.Element)
        # for the given Device Model name
        self._bench_device_node = None

        # Bench Configuration filename (abspath)
        self._bench_conf_filename = None

        # Bench configuration instance (AttributeDict)
        self._bench_conf = None

        # Bench configuration instance (AttributeDict)
        self._bench_conf_deprecated = AttributeDict()

    def _load_params_only(self, conf, data):
        """
        Loads in memory into `data` parameter
        only the DUT parameters (without sections)

        :param conf: The Device Model Configuration
        :type conf: dict or AttributeDict

        """
        dm_key = 'device_modules'
        for key, value in conf.iteritems():
            is_device_modules = key == dm_key
            if is_device_modules:
                _override_filter(conf,
                                 conf_key=dm_key,
                                 klass=(AttributeDict, dict),
                                 callback=lambda v: [v])
            if isinstance(value,
                          (dict, AttributeDict)) and not is_device_modules:
                self._load_params_only(value, data)
            else:
                data[key] = value

    def _load_cli_conf(self):
        """
        Loads Overridden Device Configuration parameters from CLI into a dict

        Some keys are not allowed in CLI overridden parameters::

            1. "Name" => Used for the whole process, `DeviceModel alias` (**INTERNAL USE ONLY**)
            2. "DeviceConfigPath" => The associated Bench configuration file path (**INTERNAL USE ONLY**)
            3. "DeviceModel" => There's no point in overriding this property

        """
        _remove_prohibited_keys(self._cli_params,
                                self.PROHIBITIVE_KEYS + ("DeviceModel", ))

    def _load_device_conf(self):
        """
        Loads The Device Configuration from its XML representation into a dict

        """
        try:
            self._device_tree_node = etree.parse(self.device_conf_filename)
        except XMLParsingErrors:
            _error("Corrupted file {0}: {1}".format(
                self.device_conf_filename,
                Utils.get_exception_info()[1]))

        self._parse_device_node()
        self._device_schema = self.extract_schema(
            self.device_root_node,
            schema_folder=Paths.FWK_DEVICE_MODELS_CATALOG,
            file_only=False)

    def _load_bench_conf(self):
        """
        Loads The Bench Configuration from its XML representation into a dict

        """
        self._bench_conf = AttributeDict()

        # New way of defining device parameters == as defined in the device catalog
        try:
            self._bench_tree_node = etree.parse(self.bench_conf_filename)
        except XMLParsingErrors:
            _error("Corrupted file {0}: {1}".format(
                self.bench_conf_filename,
                Utils.get_exception_info()[1]))

        node = self.bench_device_node
        if node is not None and len(node) > 0:
            # To load proper device config, need to get device model name
            device_conf = self.device_conf
            if device_conf:
                self._device_model_name = device_conf.get("DeviceModel")
            if self._device_model_name in ('', "", None, 'multi'):
                self._device_model_name = node[0].get("deviceModel")

            conf = self._parse_bench_node(node[0])
            if conf:
                self._bench_conf.update(conf)

    def _parse_device_node(self):
        """
        Parses XML Device Catalog file and maps it into a python structure (dict)

        :return: A dict mapping XML configuration
        :rtype: AttributeDict

        """
        def extract_params(s_node):
            """
            Get Section properties

            :param s_node: The Section node
            :type s_node: etree.Element

            :return: A dict of Section's attributes
            :rtype: AttributeDict

            """
            params = AttributeDict()
            for attrs in s_node.xpath(".//Parameter"):
                params.update(attrs.attrib)
            return params

        buf_params = AttributeDict()
        # Storing value to avoid recomputing each call
        device_model_name = self.device_model_name

        if device_model_name:
            buf_params["Name"] = device_model_name

        if self.device_conf_filename:
            buf_params["DeviceConfigPath"] = self.device_conf_filename

        node = self.device_root_node
        buf_params['device_modules'] = self.extract_device_modules(node)
        for section_node in list(node):
            buf_params[section_node.tag] = extract_params(section_node)

        self._device_conf = buf_params

    def _parse_bench_node(self, node):
        """
        Parses XML `Phone` node(s) from Bench Catalog file and maps it into a python structure (dict)

        :return: A dict mapping XML configuration
        :rtype: AttributeDict

        :raise AcsConfigException.INVALID_BENCH_CONFIG: If a (or more) deprecated parameter(s)
            is/are found in a Phone node

        """
        LOGGER_FWK.info(
            'Loading optional device model parameters from CLI and/or BenchConfig '
            'for {0} ({1})...'.format(self._device_name,
                                      self._device_model_name))
        buf_params = AttributeDict()
        # Storing value to avoid recomputing each call
        device_model_name = self.device_model_name

        if device_model_name:
            buf_params["Name"] = device_model_name

        if self.device_conf_filename:
            buf_params["DeviceConfigPath"] = self.device_conf_filename

        # Get phone properties
        for attrs in node.xpath(".//Parameter"):
            name, value, description = attrs.get("name"), attrs.get(
                "value"), attrs.get("description")

            if name in self.PROHIBITIVE_KEYS:
                # Do not allow to override internal keys
                # as it would lead to nasty & unexpected behavior !!
                continue

            # Not supported anymore, raise AcsConfigException.INVALID_BENCH_CONFIG !!
            if name and value:
                buf_params[name] = value
                self._bench_conf_deprecated[name] = (value, description)
            else:
                buf_params.update(attrs.attrib)

        # Report Errors if so
        if self.bench_contains_errors:
            LOGGER_FWK.error(self._report_errors())
            _error(
                'Invalid Bench Parameters format found! {0}'.format(', '.join(
                    self._bench_conf_deprecated.keys())),
                AcsConfigException.INVALID_BENCH_CONFIG)

        # Extracting device modules if so
        buf_params.device_modules = self.extract_device_modules(node)

        return buf_params

    def _override_through_sections(self, conf, key_lookup, value_lookup,
                                   unknown):
        """
        Implement Section Lookup through a dict.

        :param conf: The configuration dict
        :type conf: dict or AttributeDict

        .. important:: As the method returns nothing (None), you must pass a reference you hold as `conf` parameter.

            **This reference is modified inside the method only**

        :param key_lookup: The key to look up
        :type key_lookup: str

        :param value_lookup: The value to set
        :type value_lookup: object

        :param unknown: A dict designed to store unknown Key(s)/Value(s)
        :type unknown: dict or AttributeDict

        """
        for existing_key, v in conf.copy().iteritems():
            if isinstance(v, dict):
                self._override_through_sections(v, key_lookup, value_lookup,
                                                unknown)
                continue
            if existing_key != key_lookup:
                unknown[key_lookup] = value_lookup
            else:
                conf[key_lookup] = value_lookup

    def _override_parameters_cli(self):
        """
        Override device config with device parameters available in CLI parameters (**-o**) if applicable.

        """
        if self._device_name == AcsConstants.DEFAULT_DEVICE_NAME:
            for param, value in self.cli_parameters:
                self._override_through_sections(self.device_conf, param, value,
                                                self._cli_unknown_parameters)

    def _override_parameters_bench(self):
        """
        Override device config with device parameters available in bench config if applicable.

        """
        device_model_name = self.device_model_name
        device_name = self._device_name

        if self.bench_conf:
            do_the_override = False
            if device_name == AcsConstants.DEFAULT_DEVICE_NAME:
                if "Name" not in self.bench_conf:
                    # No device specified in the bench config for PHONE1
                    # Do the override then
                    do_the_override = True
                elif self.bench_conf.Name == device_model_name:
                    # Same device specified on the command line then in the bench config
                    # Do the override
                    do_the_override = True
                else:
                    warning_msg = (
                        "Different device model specified on the command line ({0}) "
                        "then in the bench config ({1}) for {2}! Related parameters specified "
                        "in bench config will be ignored !").format(
                            device_model_name, self.bench_conf.Name,
                            AcsConstants.DEFAULT_DEVICE_NAME)
                    LOGGER_FWK.warning(warning_msg)
            else:
                # For other phones (PHONE2, ...) we do the override every time
                do_the_override = True

            if do_the_override:
                for key, value in self.bench_conf.iteritems():
                    if key == "device_modules":
                        for module, module_conf in value.iteritems():
                            self.device_conf.device_modules[
                                module] = module_conf
                    else:
                        self._override_through_sections(
                            self.device_conf, key, value,
                            self._bench_unknown_parameters)

    def _validate(self):
        """
        Asserts that the given Device Model Configuration match its associated Contract

        :raise: AcsConfigException

        """
        try:
            self.device_schema.assertValid(self.device_model_final)
        except (etree.XMLSchemaParseError,
                etree.DocumentInvalid) as assert_error:
            flag = AcsConfigException.XML_PARSING_ERROR
            if isinstance(assert_error, etree.DocumentInvalid):
                flag = AcsConfigException.INVALID_PARAMETER
            _error(assert_error.message, flag)

    def _report_errors(self):
        """
        Reports all warnings found in BenchConfig, CLI, ...

        """
        report = None
        if self.bench_contains_errors:
            report = self.DEPRECATED_OVERRIDE_MSG.format(
                self.bench_conf_filename)
            report += '\n\nUnsupported format\n'
            report += '******************\n'
            for k, data in self._bench_conf_deprecated.iteritems():
                value, description = data
                report += self.DEPRECATED_ELEMENT_MSG.format(
                    k, value, 'description="{0}"'.format(description)
                    if description else "")

            report += '\n\nExpected format (to copy in BenchConfig)\n'
            report += '****************************************\n'
            for k, data in self._bench_conf_deprecated.iteritems():
                value, description = data
                report += self.RECOMMENDED_ELEMENT_MSG.format(
                    k, _check_and_format_value(value),
                    'description="{0}"'.format(description)
                    if description else "")

            report += '\n'

        return report

    def load(self):
        """
        Public method which acts as device configuration loader.

        :rtype: dict
        :return: A dict containing all device parameters

        """
        self._load_cli_conf()
        self._load_bench_conf()
        self._load_device_conf()

        # Load the device config from the device catalog
        if not self.device_conf:
            _error(
                "ACS single mode : No device config found for device {0} !".
                format(self._device_model_name),
                AcsConfigException.INVALID_PARAMETER)

        # Override Current DUT parameters from Bench ...
        self._override_parameters_bench()
        # ... and CLI
        self._override_parameters_cli()

        LOGGER_FWK.info('Checking device model integrity...')

        # Asserts All Device Model is valid (Parameters)
        self._validate()

        return self.device_only_params