def _check_not_missing( repo: IConfigRepository, default: InputDefault, skip_missing: bool, ) -> bool: path = default.get_config_path() if path.endswith("???"): if skip_missing: return True if isinstance(default, GroupDefault): group_path = default.get_group_path() options = repo.get_group_options( group_path, results_filter=ObjectType.CONFIG, ) opt_list = "\n".join(["\t" + x for x in options]) msg = dedent(f"""\ You must specify '{group_path}', e.g, {group_path}=<OPTION> Available options: """) raise ConfigCompositionException(msg + opt_list) elif isinstance(default, ConfigDefault): raise ValueError( f"Missing ConfigDefault is not supported : {path}") else: assert False return False
def update_package_header(repo: IConfigRepository, node: InputDefault) -> None: if node.is_missing(): return # This loads the same config loaded in _create_defaults_tree # To avoid loading it twice, the repo implementation is expected to cache loaded configs loaded = repo.load_config(config_path=node.get_config_path()) if loaded is not None: node.set_package_header(loaded.header["package"])
def _update_overrides( defaults_list: List[InputDefault], overrides: Overrides, parent: InputDefault, interpolated_subtree: bool, ) -> None: seen_override = False last_override_seen = None for d in defaults_list: if d.is_self(): continue d.update_parent(parent.get_group_path(), parent.get_final_package()) if seen_override and not d.is_override(): assert isinstance(last_override_seen, GroupDefault) pcp = parent.get_config_path() okey = last_override_seen.get_override_key() oval = last_override_seen.get_name() raise ConfigCompositionException( dedent( f"""\ In {pcp}: Override '{okey} : {oval}' is defined before '{d.get_override_key()}: {d.get_name()}'. Overrides must be at the end of the defaults list""" ) ) if isinstance(d, GroupDefault): assert d.group is not None legacy_hydra_override = not d.is_override() and d.group.startswith("hydra/") if legacy_hydra_override: # DEPRECATED: remove in 1.2 d.override = True url = "https://hydra.cc/docs/next/upgrades/1.0_to_1.1/defaults_list_override" msg = dedent( f"""\ In {parent.get_config_path()}: Invalid overriding of {d.group}: Default list overrides requires 'override' keyword. See {url} for more information. """ ) warnings.warn(msg, UserWarning) if d.override: seen_override = True last_override_seen = d if interpolated_subtree: # Since interpolations are deferred for until all the config groups are already set, # Their subtree may not contain config group overrides raise ConfigCompositionException( dedent( f"""\ {parent.get_config_path()}: Default List Overrides are not allowed in the subtree of an in interpolated config group (override {d.get_override_key()}={d.get_name()}). """ ) ) overrides.add_override(parent.get_config_path(), d)
def __call__(self, tree_node: Optional[DefaultsTreeNode], node: InputDefault) -> None: if node.is_deleted(): return if node.is_missing(): return rd = _create_result_default(tree=tree_node, node=node) if rd is not None: self.output.append(rd)
def is_deleted(self, default: InputDefault) -> bool: if not isinstance(default, GroupDefault): return False key = default.get_override_key() if key in self.deletions: deletion = self.deletions[key] if deletion.name is None: return True else: return deletion.name == default.get_name() return False
def set_known_choice(self, default: InputDefault) -> None: if isinstance(default, GroupDefault): key = default.get_override_key() if key not in self.known_choices: self.known_choices[key] = default.get_name() else: prev = self.known_choices[key] if default.get_name() != prev: raise ConfigCompositionException( f"Multiple values for {key}." f" To override a value use 'override {key}: {prev}'") group = default.get_group_path() if group not in self.known_choices_per_group: self.known_choices_per_group[group] = set() self.known_choices_per_group[group].add(key)
def _create_result_default(tree: Optional[DefaultsTreeNode], node: InputDefault) -> Optional[ResultDefault]: if node.is_virtual(): return None if node.get_name() is None: return None res = ResultDefault() if node.is_self(): assert tree is not None res.config_path = tree.node.get_config_path() res.is_self = True pn = tree.parent_node() if pn is not None: res.parent = pn.get_config_path() else: res.parent = None res.package = tree.node.get_final_package() res.primary = tree.node.primary else: res.config_path = node.get_config_path() if tree is not None: res.parent = tree.node.get_config_path() res.package = node.get_final_package() if isinstance(node, GroupDefault): res.override_key = node.get_override_key() res.primary = node.primary if res.config_path == "_dummy_empty_config_": return None return res
def delete(self, default: InputDefault) -> None: assert isinstance(default, GroupDefault) default.deleted = True key = default.get_override_key() self.deletions[key].used = True
def is_overridden(self, default: InputDefault) -> bool: if isinstance(default, GroupDefault): return default.get_override_key() in self.override_choices return False