def _create_root(config_name: Optional[str], with_hydra: bool) -> DefaultsTreeNode: primary: InputDefault if config_name is not None: primary = ConfigDefault(path=config_name, primary=True) else: primary = VirtualRoot() if with_hydra: root = DefaultsTreeNode( node=VirtualRoot(), children=[ConfigDefault(path="hydra/config"), primary], ) else: root = DefaultsTreeNode(node=primary) return root
def _validate_self( containing_node: InputDefault, defaults: List[InputDefault], has_config_content: bool, ) -> bool: # check that self is present only once has_self = False has_non_override = False for d in defaults: if not d.is_override(): has_non_override = True if d.is_self(): if has_self: raise ConfigCompositionException( f"Duplicate _self_ defined in {containing_node.get_config_path()}" ) has_self = True if not has_self and has_non_override or len(defaults) == 0: # This check is here to make the migration from Hydra 1.0 to Hydra 1.1 smoother and should be removed in 1.2 # The warning should be removed in 1.2 if containing_node.primary and has_config_content and has_non_override: msg = ( f"In '{containing_node.get_config_path()}': Defaults list is missing `_self_`. " f"See https://hydra.cc/docs/upgrades/1.0_to_1.1/default_composition_order for more information" ) if os.environ.get("SELF_WARNING_AS_ERROR") == "1": raise ConfigCompositionException(msg) warnings.warn(msg, UserWarning) defaults.append(ConfigDefault(path="_self_")) return not has_self
def _validate_self(containing_node: InputDefault, defaults: List[InputDefault]) -> bool: # check that self is present only once has_self = False has_non_override = False for d in defaults: if not d.is_override(): has_non_override = True if d.is_self(): if has_self: raise ConfigCompositionException( f"Duplicate _self_ defined in {containing_node.get_config_path()}" ) has_self = True if not has_self and has_non_override or len(defaults) == 0: defaults.append(ConfigDefault(path="_self_")) return not has_self
def _create_defaults_tree_impl( repo: IConfigRepository, root: DefaultsTreeNode, is_root_config: bool, skip_missing: bool, interpolated_subtree: bool, overrides: Overrides, ) -> DefaultsTreeNode: parent = root.node children: List[Union[InputDefault, DefaultsTreeNode]] = [] if parent.is_virtual(): if is_root_config: return _expand_virtual_root(repo, root, overrides, skip_missing) else: return root if is_root_config: root.node.update_parent("", "") if not repo.config_exists(root.node.get_config_path()): config_not_found_error(repo=repo, tree=root) update_package_header(repo=repo, node=parent) if overrides.is_deleted(parent): overrides.delete(parent) return root overrides.set_known_choice(parent) if parent.get_name() is None: return root if _check_not_missing(repo=repo, default=parent, skip_missing=skip_missing): return root path = parent.get_config_path() loaded = repo.load_config(config_path=path) if loaded is None: if parent.is_optional(): assert isinstance(parent, (GroupDefault, ConfigDefault)) parent.deleted = True return root config_not_found_error(repo=repo, tree=root) assert loaded is not None defaults_list = copy.deepcopy(loaded.defaults_list) if defaults_list is None: defaults_list = [] self_added = False if (len(defaults_list) > 0 or is_root_config and len(overrides.append_group_defaults) > 0): self_added = _validate_self(containing_node=parent, defaults=defaults_list) if is_root_config: # To ensure config overrides are last, insert the external overrides before the first config override. insert_idx = len(defaults_list) for idx, default in enumerate(defaults_list): if default.is_override(): insert_idx = idx break defaults_list[insert_idx:insert_idx] = overrides.append_group_defaults _update_overrides(defaults_list, overrides, parent, interpolated_subtree) def add_child( child_list: List[Union[InputDefault, DefaultsTreeNode]], new_root_: DefaultsTreeNode, ) -> None: subtree_ = _create_defaults_tree_impl( repo=repo, root=new_root_, is_root_config=False, interpolated_subtree=interpolated_subtree, skip_missing=skip_missing, overrides=overrides, ) if subtree_.children is None: child_list.append(new_root_.node) else: child_list.append(subtree_) for d in reversed(defaults_list): if d.is_self(): d.update_parent(root.node.parent_base_dir, root.node.get_package()) children.append(d) else: if d.is_override(): continue d.update_parent(parent.get_group_path(), parent.get_final_package()) if overrides.is_overridden(d): assert isinstance(d, GroupDefault) overrides.override_default_option(d) if isinstance(d, GroupDefault) and d.is_options(): # overriding may change from options to name if d.is_options(): for item in reversed(d.get_options()): if "${" in item: raise ConfigCompositionException( f"In '{path}': Defaults List interpolation is not supported in options list items" ) assert d.group is not None node = ConfigDefault( path=d.group + "/" + item, package=d.package, optional=d.is_optional(), ) node.update_parent(parent.get_group_path(), parent.get_final_package()) new_root = DefaultsTreeNode(node=node, parent=root) add_child(children, new_root) else: new_root = DefaultsTreeNode(node=d, parent=root) add_child(children, new_root) else: if d.is_interpolation(): children.append(d) continue new_root = DefaultsTreeNode(node=d, parent=root) add_child(children, new_root) # processed deferred interpolations known_choices = _create_interpolation_map(overrides, defaults_list, self_added) for idx, dd in enumerate(children): if isinstance(dd, InputDefault) and dd.is_interpolation(): dd.resolve_interpolation(known_choices) new_root = DefaultsTreeNode(node=dd, parent=root) dd.update_parent(parent.get_group_path(), parent.get_final_package()) subtree = _create_defaults_tree_impl( repo=repo, root=new_root, is_root_config=False, skip_missing=skip_missing, interpolated_subtree=True, overrides=overrides, ) if subtree.children is not None: children[idx] = subtree if len(children) > 0: root.children = list(reversed(children)) return root