def apply_config(raw, validators): raw = _normalize(raw, validators) # find invalid options invalid = deepcopy(raw) for k, config in validators.items(): options = [opt for opt in config.options() if opt.alias is None] for option in options: if dict_has_path(invalid, option.name): dict_del_path(invalid, option.name) if k in invalid or (not k and invalid): first = dict_paths(invalid, k)[0] candidates = [opt.name for opt in options] suggestion = did_you_mean(candidates, first) raise _invalid_option(first, help_topic=config.name, suggestion=suggestion, kind='key') # validate and cast options for option in options: if dict_has_path(raw, option.name): value = dict_get_path(raw, option.name) dict_del_path(raw, option.name) config.configure(option, value) return raw
def _validate_source(self, config, source_name): name = config['type'] if not name: return plugin = self.plugins.get("vergeml.io", name) if not plugin: raise _invalid_option(f"data.{source_name}.type", help_topic='data', suggestion=did_you_mean(self.plugins.keys('vergeml.io'), name)) source = Source.discover(plugin) options = list(filter(lambda o: o.name != 'type', source.options)) validator = ValidateOptions(options, source_name, self.plugins) config = {source_name: deepcopy(config)} dict_del_path(config, source_name + ".type") rest = apply_config(config, {name: validator}) if rest: k = dict_paths(rest)[0] candidates = [opt.name for opt in source.options] raise _invalid_option(f"data.{source_name}.{k}", help_topic=name, suggestion=did_you_mean(candidates, k), kind='key') else: values = dict(data=validator.values) if source_name not in values['data']: values['data'][source_name] = {} values['data'][source_name]['type'] = name dict_merge(self.values, values)
def _normalize(raw, validators): raw = deepcopy(raw) res = {} for _, conf in validators.items(): options = Option.discover(conf) aliases = [opt for opt in options if opt.alias] for alias in aliases: if dict_has_path(raw, alias.name): v = dict_get_path(raw, alias.name) if not alias.type or isinstance(v, alias.type): dict_set_path(res, alias.alias, v) dict_del_path(raw, alias.name) for k, v in deepcopy(raw).items(): if "." in k: dict_set_path(res, k, v) del raw[k] return dict_merge(res, raw)
def test_del_path_non_empty(): dic = {'x': {'y': {'z': 1}, 'y1': 1}} dict_del_path(dic, "x.y.z") assert dic == {'x': {'y1': 1}}
def test_del_path(): dic = {'x': {'y': {'z': 1}}} dict_del_path(dic, "x.y.z") assert dic == {}