docs: def add(self, config, strip_app_name=False, filter_by_app_name=False,
              key_normalisation_func=default_key_normalisation_func):
          """
          Add a dict of config data. Values from later dicts will take precedence
          over those added earlier, so the order data is added matters.
  
          Note: Double underscores can be used to indicate dict key name
          boundaries. i.e. if we have a dict like:
  
          {
              'logging': {
                  'level': INFO
                  ...
              }
          }
  
          we could pass an environment variable LOGGING__LEVEL=DEBUG to override
          the log level.
  
          Note: Key names will be normalised by recursively applying the
          key_normalisation_func function. By default this will:
  
              1) Convert keys to lowercase
              2) Replace hyphens with underscores
              3) Strip leading underscores
  
          This allows key names from different sources (e.g. CLI args, env vars,
          etc.) to be able to override each other.
  
          :param config dict: config data
          :param strip_app_name boolean: If True, the configured app_name will
          stripped from the start of top-level input keys if present.
          :param filter_by_app_name boolean: If True, keys that don't begin with
          the app name will be discarded.
          :return:
          """
          config = walk_recursive(key_normalisation_func, OrderedDict(config))
  
          if filter_by_app_name:
              config = funcy.compact(funcy.select_keys(
                  lambda k: k.startswith(self._app_name), config))
  
          if strip_app_name:
              strip_app_name_regex = re.compile("^%s" % self._app_name)
              config = funcy.walk_keys(
                  lambda k: re.sub(strip_app_name_regex, '', k), config)
  
          self._sources.append(config)
  
          return self