Example #1
0
    def add_src(self, src, conf, filter_none=False, fallback=False):
        """
        Add a source of configuration.

        :param src: Name of the soruce to add
        :type src: str

        :param conf: Nested mapping of key/values to overlay
        :type conf: collections.abc.Mapping

        :param filter_none: Ignores the keys that have a ``None`` value. That
            simplifies the creation of the mapping, by having keys always
            present. That should not be used if ``None`` value for a key is
            expected, as opposit to not having that key set at all.
        :type filter_none: bool

        :param fallback: If True, the source will be added as a fallback, which
            means at the end of the priority list. By default, the source will
            have the highest priority and will be used unless a key-specific
            priority override is setup.
        :type fallback: bool

        This method provides a way to update the configuration, by importing a
        mapping as a new source.
        """

        logger = self.get_logger()
        if logger.isEnabledFor(logging.DEBUG):
            caller, filename, lineno = get_call_site(
                1, exclude_caller_module=True)
            logger.debug(
                '{caller} ({filename}:{lineno}) has set source "{src}":\n{conf}'
                .format(
                    src=src,
                    conf=conf,
                    caller=caller if caller else '<unknown>',
                    filename=filename if filename else '<unknown>',
                    lineno=lineno if lineno else '<unknown>',
                ))
        return self._add_src(src,
                             conf,
                             filter_none=filter_none,
                             fallback=fallback)
Example #2
0
    def get_key(self, key, src=None, eval_deferred=True, quiet=False):
        """
        Get the value of the given key. It returns a deepcopy of the value.

        :param key: name of the key to lookup
        :type key: str

        :param src: If not None, look up the value of the key in that source
        :type src: str or None

        :param eval_deferred: If True, evaluate instances of
            :class:`DeferredValue` if needed
        :type eval_deferred: bool

        :param quiet: Avoid logging the access
        :type quiet: bool

        .. note:: Using the indexing operator ``self[key]`` is preferable in
            most cases , but this method provides more parameters.
        """
        key_desc = self._structure[key]

        if isinstance(key_desc, LevelKeyDesc):
            return self._sublevel_map[key]
        elif isinstance(key_desc, DerivedKeyDesc):
            # Specifying a source is an error for a derived key
            if src is not None:
                key = key_desc.qualname
                raise ValueError(
                    'Cannot specify the source when getting "{key}" since it is a derived key'
                    .format(
                        key=key,
                        src=src,
                    ), key)

            val = key_desc.compute_val(self)
            src = self.resolve_src(key)
        else:
            # Compute the source to use for that key
            if src is None:
                src = self.resolve_src(key)

            try:
                val = self._key_map[key][src]
            except KeyError:
                key = key_desc.qualname
                raise KeyError(
                    'Key "{key}" is not available from source "{src}"'.format(
                        key=key,
                        src=src,
                    ), key)

            if eval_deferred:
                val = self._eval_deferred_val(src, key)

        logger = self.get_logger()
        if not quiet and logger.isEnabledFor(logging.DEBUG):
            caller, filename, lineno = get_call_site(
                2, exclude_caller_module=True)
            logger.debug(
                '{caller} ({filename}:{lineno}) has used key {key} from source "{src}": {val}'
                .format(
                    key=key_desc.qualname,
                    src=src,
                    val=key_desc.pretty_format(val),
                    caller=caller if caller else '<unknown>',
                    filename=filename if filename else '<unknown>',
                    lineno=lineno if lineno else '<unknown>',
                ))

        if isinstance(val, DeferredValue):
            return val
        else:
            return copy.deepcopy(val)