コード例 #1
0
    def _do_parse(self, config, id: str = ""):
        """
        Recursively parse the nested data in config source, add every item as `ConfigItem` to the resolver.

        Args:
            config: config source to parse.
            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``.

        """
        if isinstance(config, (dict, list)):
            for k, v in enumerate(config) if isinstance(config, list) else config.items():
                sub_id = f"{id}{ID_SEP_KEY}{k}" if id != "" else k
                self._do_parse(config=v, id=sub_id)

        # copy every config item to make them independent and add them to the resolver
        item_conf = deepcopy(config)
        if ConfigComponent.is_instantiable(item_conf):
            self.ref_resolver.add_item(ConfigComponent(config=item_conf, id=id, locator=self.locator))
        elif ConfigExpression.is_expression(item_conf):
            self.ref_resolver.add_item(ConfigExpression(config=item_conf, id=id, globals=self.globals))
        else:
            self.ref_resolver.add_item(ConfigItem(config=item_conf, id=id))
コード例 #2
0
    def test_resolve(self, configs, expected_id, output_type):
        locator = ComponentLocator()
        resolver = ReferenceResolver()
        # add items to resolver
        for k, v in configs.items():
            if ConfigComponent.is_instantiable(v):
                resolver.add_item(
                    ConfigComponent(config=v, id=k, locator=locator))
            elif ConfigExpression.is_expression(v):
                resolver.add_item(
                    ConfigExpression(config=v,
                                     id=k,
                                     globals={
                                         "monai": monai,
                                         "torch": torch
                                     }))
            else:
                resolver.add_item(ConfigItem(config=v, id=k))

        result = resolver.get_resolved_content(
            expected_id)  # the root id is `expected_id` here
        self.assertTrue(isinstance(result, output_type))

        # test lazy instantiation
        item = resolver.get_item(expected_id, resolve=True)
        config = item.get_config()
        config["_disabled_"] = False
        item.update_config(config=config)
        if isinstance(item, ConfigComponent):
            result = item.instantiate()
        else:
            result = item.get_config()
        self.assertTrue(isinstance(result, output_type))
コード例 #3
0
    def update_config_with_refs(cls, config, id: str, refs: Optional[Dict] = None):
        """
        With all the references in ``refs``, update the input config content with references
        and return the new config.

        Args:
            config: input config content to update.
            id: ID name for the input config.
            refs: all the referring content with ids, default to `None`.

        """
        refs_: Dict = refs or {}
        if isinstance(config, str):
            return cls.update_refs_pattern(config, refs_)
        if not isinstance(config, (list, dict)):
            return config
        ret = type(config)()
        for idx, v in config.items() if isinstance(config, dict) else enumerate(config):
            sub_id = f"{id}{cls.sep}{idx}" if id != "" else f"{idx}"
            if ConfigComponent.is_instantiable(v) or ConfigExpression.is_expression(v):
                updated = refs_[sub_id]
                if ConfigComponent.is_instantiable(v) and updated is None:
                    # the component is disabled
                    continue
            else:
                updated = cls.update_config_with_refs(v, sub_id, refs_)
            ret.update({idx: updated}) if isinstance(ret, dict) else ret.append(updated)
        return ret
コード例 #4
0
    def update_refs_pattern(cls, value: str, refs: Dict) -> str:
        """
        Match regular expression for the input string to update content with the references.
        The reference part starts with ``"@"``, like: ``"@XXX#YYY#ZZZ"``.
        References dictionary must contain the referring IDs as keys.

        Args:
            value: input value to match regular expression.
            refs: all the referring components with ids as keys, default to `None`.

        """
        # regular expression pattern to match "@XXX" or "@XXX#YYY"
        result = cls.id_matcher.findall(value)
        value_is_expr = ConfigExpression.is_expression(value)
        for item in result:
            ref_id = item[len(cls.ref) :]  # remove the ref prefix "@"
            if ref_id not in refs:
                msg = f"can not find expected ID '{ref_id}' in the references."
                if cls.allow_missing_reference:
                    warnings.warn(msg)
                    continue
                else:
                    raise KeyError(msg)
            if value_is_expr:
                # replace with local code, will be used in the `evaluate` logic with `locals={"refs": ...}`
                value = value.replace(item, f"{cls._vars}['{ref_id}']")
            elif value == item:
                # the whole content is "@XXX", it will avoid the case that regular string contains "@"
                value = refs[ref_id]
        return value
コード例 #5
0
    def find_refs_in_config(
            cls,
            config,
            id: str,
            refs: Optional[Dict[str, int]] = None) -> Dict[str, int]:
        """
        Recursively search all the content of input config item to get the ids of references.
        References mean: the IDs of other config items (``"@XXX"`` in this config item), or the
        sub-item in the config is `instantiable`, or the sub-item in the config is `expression`.
        For `dict` and `list`, recursively check the sub-items.

        Args:
            config: input config content to search.
            id: ID name for the input config item.
            refs: dict of the ID name and count of found references, default to `None`.

        """
        refs_: Dict[str, int] = refs or {}
        if isinstance(config, str):
            for id, count in cls.match_refs_pattern(value=config).items():
                refs_[id] = refs_.get(id, 0) + count
        if not isinstance(config, (list, dict)):
            return refs_
        for k, v in config.items() if isinstance(config,
                                                 dict) else enumerate(config):
            sub_id = f"{id}{cls.sep}{k}" if id != "" else f"{k}"
            if ConfigComponent.is_instantiable(
                    v
            ) or ConfigExpression.is_expression(v) and sub_id not in refs_:
                refs_[sub_id] = 1
            refs_ = cls.find_refs_in_config(v, sub_id, refs_)
        return refs_
コード例 #6
0
    def match_refs_pattern(cls, value: str) -> Set[str]:
        """
        Match regular expression for the input string to find the references.
        The reference string starts with ``"@"``, like: ``"@XXX#YYY#ZZZ"``.

        Args:
            value: input value to match regular expression.

        """
        refs: Set[str] = set()
        # regular expression pattern to match "@XXX" or "@XXX#YYY"
        result = cls.id_matcher.findall(value)
        value_is_expr = ConfigExpression.is_expression(value)
        for item in result:
            if value_is_expr or value == item:
                # only check when string starts with "$" or the whole content is "@XXX"
                refs.add(item[len(cls.ref) :])
        return refs