def test_10_update_with_replace(self): dic = copy.deepcopy(self.dic) exp = copy.deepcopy(self.upd) exp["name"] = dic["name"] TT.merge(dic, self.upd, ac_merge=TT.MS_REPLACE) self.assertTrue(dicts_equal(dic, exp))
def test_20_update_wo_replace(self): dic = copy.deepcopy(self.dic) exp = copy.deepcopy(self.dic) exp["e"] = self.upd["e"] TT.merge(dic, self.upd, ac_merge=TT.MS_NO_REPLACE) self.assertTrue(dicts_equal(dic, exp))
def test_30_update_with_merge(self): dic = copy.deepcopy(self.dic) exp = copy.deepcopy(self.upd) exp["b"]["c"] = dic["b"]["c"] exp["name"] = dic["name"] TT.merge(dic, self.upd, ac_merge=TT.MS_DICTS) self.assertTrue(dicts_equal(dic, exp))
def test_30_update_with_invalid(self): try: raised = False TT.merge(self.dic, 1) except (ValueError, TypeError): raised = True self.assertTrue(raised)
def test_40_update_with_merge_lists(self): dic = copy.deepcopy(self.dic) exp = copy.deepcopy(self.upd) exp["b"]["b"] = [0] + exp["b"]["b"] exp["b"]["c"] = dic["b"]["c"] exp["name"] = dic["name"] TT.merge(dic, self.upd, ac_merge=TT.MS_DICTS_AND_LISTS) self.assertEqual(dic, exp)
def test_50_update_with_custom_merge(self): def set_none_merge_strat(self, other, key, *args, **kwargs): for k in self: self[k] = None dic = copy.deepcopy(self.dic) exp = dict(zip(dic.keys(), [None for _ in dic])) TT.merge(dic, self.upd, ac_merge=set_none_merge_strat) self.assertTrue(dicts_equal(dic, exp))
def multi_load(inputs, ac_parser=None, ac_template=False, ac_context=None, **options): r""" Load multiple config files. .. note:: :func:`load` is a preferable alternative and this API should be used only if there is a need to emphasize given inputs are multiple ones. The first argument `inputs` may be a list of a file paths or a glob pattern specifying them or a pathlib.Path object represents file[s] or a namedtuple `~anyconfig.globals.IOInfo` object represents some inputs to load some data from. About glob patterns, for example, is, if a.yml, b.yml and c.yml are in the dir /etc/foo/conf.d/, the followings give same results:: multi_load(["/etc/foo/conf.d/a.yml", "/etc/foo/conf.d/b.yml", "/etc/foo/conf.d/c.yml", ]) multi_load("/etc/foo/conf.d/*.yml") :param inputs: A list of file path or a glob pattern such as r'/a/b/\*.json'to list of files, file or file-like object or pathlib.Path object represents the file or a namedtuple `~anyconfig.globals.IOInfo` object represents some inputs to load some data from :param ac_parser: Forced parser type or parser object :param ac_template: Assume configuration file may be a template file and try to compile it AAR if True :param ac_context: Mapping object presents context to instantiate template :param options: Optional keyword arguments: - ac_dict, ac_ordered, ac_schema and ac_query are the options common in :func:`single_load`, :func:`multi_load`, :func:`load`: and :func:`loads`. See the descriptions of them in :func:`single_load`. - Options specific to this function and :func:`load`: - ac_merge (merge): Specify strategy of how to merge results loaded from multiple configuration files. See the doc of :mod:`anyconfig.dicts` for more details of strategies. The default is anyconfig.dicts.MS_DICTS. - ac_marker (marker): Globbing marker to detect paths patterns. - Common backend options: - ignore_missing: Ignore and just return empty result if given file ``path`` does not exist. - Backend specific options such as {"indent": 2} for JSON backend :return: Mapping object or any query result might be primitive objects :raises: ValueError, UnknownParserTypeError, UnknownFileTypeError """ marker = options.setdefault("ac_marker", options.get("marker", '*')) schema = _maybe_schema(ac_template=ac_template, ac_context=ac_context, **options) options["ac_schema"] = None # Avoid to load schema more than twice. paths = anyconfig.utils.expand_paths(inputs, marker=marker) if anyconfig.utils.are_same_file_types(paths): ac_parser = anyconfig.backends.find_parser(paths[0], ac_parser) cnf = ac_context for path in paths: opts = options.copy() cups = _single_load(path, ac_parser=ac_parser, ac_template=ac_template, ac_context=cnf, **opts) if cups: if cnf is None: cnf = cups else: merge(cnf, cups, **options) if cnf is None: return anyconfig.dicts.convert_to({}, **options) cnf = _try_validate(cnf, schema, **options) return anyconfig.query.query(cnf, **options)
def assert_updated(self, other): dic = copy.deepcopy(self.dic) TT.merge(dic, other, ac_merge=self.ac_merge) self.assert_dicts_equal(dic, other, self.dic)
def multi_load(paths, ac_parser=None, ac_template=False, ac_context=None, **options): """ Load multiple config files. .. note:: :func:`load` is a preferable alternative and this API should be used only if there is a need to emphasize given file paths are multiple ones. The first argument `paths` may be a list of config file paths or a glob pattern specifying that. That is, if a.yml, b.yml and c.yml are in the dir /etc/foo/conf.d/, the followings give same results:: multi_load(["/etc/foo/conf.d/a.yml", "/etc/foo/conf.d/b.yml", "/etc/foo/conf.d/c.yml", ]) multi_load("/etc/foo/conf.d/*.yml") :param paths: List of configuration file paths or a glob pattern to list of these paths, or a list of file or file-like objects :param ac_parser: Forced parser type or parser object :param ac_template: Assume configuration file may be a template file and try to compile it AAR if True :param ac_context: Mapping object presents context to instantiate template :param options: Optional keyword arguments: - Options common with :func:`multi_load` and :func:`load`: - ac_dict: callable (function or class) to make mapping object will be returned as a result or None. If not given or ac_dict is None, default mapping object used to store resutls is dict or :class:`~collections.OrderedDict` if ac_ordered is True and selected backend can keep the order of items in mapping objects. - ac_ordered: True if you want to keep resuls ordered. Please note that order of items may be lost depends on backend used. - ac_schema: JSON schema file path to validate given config file - ac_query: JMESPath expression to query data - ac_dict: callable (function or class) to make a dict or dict-like object, dict and OrderedDict for example - Options specific to this function and :func:`load`: - ac_merge (merge): Specify strategy of how to merge results loaded from multiple configuration files. See the doc of :mod:`anyconfig.dicts` for more details of strategies. The default is anyconfig.dicts.MS_DICTS. - ac_marker (marker): Globbing marker to detect paths patterns. - Common backend options: - ignore_missing: Ignore and just return empty result if given file (``path_or_stream``) does not exist. - Backend specific options such as {"indent": 2} for JSON backend :return: Mapping object or any query result might be primitive objects """ marker = options.setdefault("ac_marker", options.get("marker", '*')) schema = _maybe_schema(ac_template=ac_template, ac_context=ac_context, **options) options["ac_schema"] = None # Avoid to load schema more than twice. paths = anyconfig.utils.norm_paths(paths, marker=marker) if anyconfig.utils.are_same_file_types(paths): ac_parser = find_loader(paths[0], ac_parser, is_path(paths[0])) cnf = ac_context for path in paths: opts = options.copy() cups = single_load(path, ac_parser=ac_parser, ac_template=ac_template, ac_context=cnf, **opts) if cups: if cnf is None: cnf = cups else: merge(cnf, cups, **options) if cnf is None: return anyconfig.dicts.convert_to({}, **options) cnf = _maybe_validated(cnf, schema, **options) return anyconfig.query.query(cnf, **options)
def multi_load(inputs, ac_parser=None, ac_template=False, ac_context=None, **options): r""" Load multiple config files. .. note:: :func:`load` is a preferable alternative and this API should be used only if there is a need to emphasize given inputs are multiple ones. The first argument 'inputs' may be a list of a file paths or a glob pattern specifying them or a pathlib.Path object represents file[s] or a namedtuple 'anyconfig.globals.IOInfo' object represents some inputs to load some data from. About glob patterns, for example, is, if a.yml, b.yml and c.yml are in the dir /etc/foo/conf.d/, the followings give same results:: multi_load(["/etc/foo/conf.d/a.yml", "/etc/foo/conf.d/b.yml", "/etc/foo/conf.d/c.yml", ]) multi_load("/etc/foo/conf.d/*.yml") :param inputs: A list of file path or a glob pattern such as r'/a/b/\*.json'to list of files, file or file-like object or pathlib.Path object represents the file or a namedtuple 'anyconfig.globals.IOInfo' object represents some inputs to load some data from :param ac_parser: Forced parser type or parser object :param ac_template: Assume configuration file may be a template file and try to compile it AAR if True :param ac_context: Mapping object presents context to instantiate template :param options: Optional keyword arguments: - ac_dict, ac_ordered, ac_schema and ac_query are the options common in :func:`single_load`, :func:`multi_load`, :func:`load`: and :func:`loads`. See the descriptions of them in :func:`single_load`. - Options specific to this function and :func:`load`: - ac_merge (merge): Specify strategy of how to merge results loaded from multiple configuration files. See the doc of :mod:`anyconfig.dicts` for more details of strategies. The default is anyconfig.dicts.MS_DICTS. - ac_marker (marker): Globbing marker to detect paths patterns. - Common backend options: - ignore_missing: Ignore and just return empty result if given file 'path' does not exist. - Backend specific options such as {"indent": 2} for JSON backend :return: Mapping object or any query result might be primitive objects :raises: ValueError, UnknownProcessorTypeError, UnknownFileTypeError """ marker = options.setdefault("ac_marker", options.get("marker", '*')) schema = _maybe_schema(ac_template=ac_template, ac_context=ac_context, **options) options["ac_schema"] = None # Avoid to load schema more than twice. paths = anyconfig.utils.expand_paths(inputs, marker=marker) if anyconfig.utils.are_same_file_types(paths): ac_parser = find(paths[0], forced_type=ac_parser) cnf = ac_context for path in paths: opts = options.copy() cups = _single_load(path, ac_parser=ac_parser, ac_template=ac_template, ac_context=cnf, **opts) if cups: if cnf is None: cnf = cups else: merge(cnf, cups, **options) if cnf is None: return anyconfig.dicts.convert_to({}, **options) cnf = _try_validate(cnf, schema, **options) return anyconfig.query.query(cnf, **options)