def __setitem__(self, id: Union[str, int], config: Any): """ Set config by ``id``. Note that this method should be used before ``parse()`` or ``get_parsed_content()`` to ensure the updates are included in the parsed content. Args: id: id of the ``ConfigItem``, ``"#"`` in id are interpreted as special characters to go one level further into the nested structures. Use digits indexing from "0" for list or other strings for dict. For example: ``"xform#5"``, ``"net#channels"``. ``""`` indicates the entire ``self.config``. config: config to set at location ``id``. """ if id == "": self.config = config self.ref_resolver.reset() return keys = str(id).split(ID_SEP_KEY) # get the last parent level config item and replace it last_id = ID_SEP_KEY.join(keys[:-1]) conf_ = self[last_id] indexing = keys[-1] if isinstance(conf_, dict) else int(keys[-1]) conf_[indexing] = config self.ref_resolver.reset() return
def resolve_relative_ids(cls, id: str, value: str) -> str: """ To simplify the reference or macro tokens ID in the nested config content, it's available to use relative ID name which starts with the `ID_SEP_KEY`, for example, "@#A" means `A` in the same level, `@##A` means `A` in the upper level. It resolves the relative ids to absolute ids. For example, if the input data is: .. code-block:: python { "A": 1, "B": {"key": "@##A", "value1": 2, "value2": "%#value1", "value3": [3, 4, "@#1"]}, } It will resolve `B` to `{"key": "@A", "value1": 2, "value2": "%B#value1", "value3": [3, 4, "@B#value3#1"]}`. Args: id: id name for current config item to compute relative id. value: input value to resolve relative ids. """ # get the prefixes like: "@####", "%###", "@#" prefixes = sorted(set().union(cls.relative_id_prefix.findall(value)), reverse=True) current_id = id.split(ID_SEP_KEY) for p in prefixes: sym = ID_REF_KEY if ID_REF_KEY in p else MACRO_KEY length = p[len(sym):].count(ID_SEP_KEY) if length > len(current_id): raise ValueError( f"the relative id in `{value}` is out of the range of config content." ) if length == len(current_id): new = "" # root id is `""` else: new = ID_SEP_KEY.join(current_id[:-length]) + ID_SEP_KEY value = value.replace(p, sym + new) return value