U Ph=@sddlmZddlZddlZddlmZddlmZmZddl m Z m Z m Z ddl mZmZddlmZmZdgZGd ddZdS) ) annotationsN)Sequence)AnyIterator)ConfigComponentConfigExpression ConfigItem) ID_REF_KEY ID_SEP_KEY)allow_missing_referencelook_up_optionReferenceResolverc@sJeZdZdZdZeZeZe ededZ e Z d?dddd Z d d Zd d ddZdddddZd@dd dddddZdAddddddd Zdddd!d"d#Zed$dd%d&d'ZedBd$d d(d)d*d+Zeddd,d-d.d/Zedd0d1d2d3Zedd4dd5d6d7ZedCddd8d0d9d:d;ZedDdddZdS)Er a Utility class to manage a set of ``ConfigItem`` and resolve the references between them. This class maintains a set of ``ConfigItem`` objects and their associated IDs. The IDs must be unique within this set. A string in ``ConfigItem`` starting with ``@`` will be treated as a reference to other ``ConfigItem`` objects by ID. Since ``ConfigItem`` may have a nested dictionary or list structure, the reference string may also contain the separator ``::`` to refer to a substructure by key indexing for a dictionary or integer indexing for a list. In this class, resolving references is essentially substitution of the reference strings with the corresponding python objects. A typical workflow of resolving references is as follows: - Add multiple ``ConfigItem`` objects to the ``ReferenceResolver`` by ``add_item()``. - Call ``get_resolved_content()`` to automatically resolve the references. This is done (recursively) by: - Convert the items to objects, for those do not have references to other items. - If it is instantiable, instantiate it and cache the class instance in ``resolved_content``. - If it is an expression, evaluate it and save the value in ``resolved_content``. - Substitute the reference strings with the corresponding objects. Args: items: ``ConfigItem``s to resolve, this could be added later with ``add_item()``. Z __local_refsz (?:\w*)(?:z\w*)*NzSequence[ConfigItem] | None)itemscCs&|dkr in dd|D|_i|_dS)NcSsi|]}||qS)get_id).0irrT/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/bundle/reference_resolver.py >sz.ReferenceResolver.__init__..rresolved_content)selfrrrr__init__<szReferenceResolver.__init__cCsi|_i|_dS)zQ Clear all the added `ConfigItem` and all the resolved content. NrrrrrresetAszReferenceResolver.resetbool)returncCs t|jS)N)rrrrrr is_resolvedIszReferenceResolver.is_resolvedrNone)itemrcCs$|}||jkrdS||j|<dS)zk Add a ``ConfigItem`` to the resolver. Args: item: a ``ConfigItem``. N)rr)rridrrradd_itemLs zReferenceResolver.add_itemFstrrzConfigItem | None)r resolvekwargsrcKs8||}|r,||jkr,|jfd|i||j|S)a Get the ``ConfigItem`` by id. If ``resolve=True``, the returned item will be resolved, that is, all the reference strings are substituted by the corresponding ``ConfigItem`` objects. Args: id: id of the expected config item. resolve: whether to resolve the item if it is not resolved, default to False. kwargs: keyword arguments to pass to ``_resolve_one_item()``. Currently support ``instantiate`` and ``eval_expr``. Both are defaulting to True. r ) normalize_idr_resolve_one_itemrget)rr r#r$rrrget_itemYs zReferenceResolver.get_itemzset[str] | Nonez#ConfigExpression | str | Any | None)r waiting_listr$rc Ksf||}||jkr|j|Szt||jd|ddd}Wn4tk rp}ztd|d|W5d}~XYnXt|ts|S| }|dkrt }| ||jD]H\}}||jkrt|t r| | r|dd r|n||j|<q|j||d D]} | |kr*td | d |d | |jkrzt| |jddWnVtk r}z6d| d} |js|t| |t| WYqW5d}~XYnX|jf| |d||| q|j|||jd} |j| dt|tr|dd r|n||j|<nJt|t rR|dd } | rF|j|j|jidn||j|<n | |j|<|j|S)aC Resolve and return one ``ConfigItem`` of ``id``, cache the resolved result in ``resolved_content``. If it has unresolved references, recursively resolve the referring items first. Args: id: id name of ``ConfigItem`` to be resolved. waiting_list: set of ids pending to be resolved. It's used to detect circular references such as: `{"name": "A", "dep": "@B"}` and `{"name": "B", "dep": "@A"}`. kwargs: keyword arguments to pass to ``_resolve_one_item()``. Currently support ``instantiate``, ``eval_expr`` and ``default``. `instantiate` and `eval_expr` are defaulting to True, `default` is the target config item if the `id` is not in the config content, must be a `ConfigItem` object. Fdefault no_default)print_all_optionsr*zid='z&' is not found in the config resolver.N eval_exprT)configr zdetected circular references 'z ' for id='z' in the config content.)r,zthe referring item `@z'` is not defined in the config content.)r r))r.r refs)r. instantiate)globals)r%rr rr' ValueErrorKeyError isinstancer get_configsetaddris_import_statementevaluatefind_refs_in_configkeysr warningswarnr&discardupdate_config_with_refs update_configrr0_vars) rr r)r$rerrZ item_configtvdmsgZ new_configrun_evalrrrr&ksZ   $           "    z#ReferenceResolver._resolve_one_item)r r$rcKs|jfd|i|S)a Get the resolved ``ConfigItem`` by id. Args: id: id name of the expected item. kwargs: keyword arguments to pass to ``_resolve_one_item()``. Currently support ``instantiate``, ``eval_expr`` and ``default``. `instantiate` and `eval_expr` are defaulting to True, `default` is the target config item if the `id` is not in the config content, must be a `ConfigItem` object. r )r&)rr r$rrrget_resolved_contents z&ReferenceResolver.get_resolved_contentz str | int)r rcCst|d|jS)z Normalize the id string to consistently use `cls.sep`. Args: id: id string to be normalized. #)r"replacesep)clsr rrrr%szReferenceResolver.normalize_idz list[str])r lastrcCsD|s|||jS|||jd}d|dd|dgS)z Split the id string into a list of strings by `cls.sep`. Args: id: id string to be split. last: whether to split the rightmost part of the id. default is False (split all parts). N)r%splitrKrsplitjoin)rLr rMresrrrsplit_ids zReferenceResolver.split_idzIterator[tuple[str, str, Any]])r r.rccsTt|tr|nt|D]4\}}|dkr<||j|n|}|||fVqdS)z Iterate over the sub-configs of the input config, the output `sub_id` uses `cls.sep` to denote substructure. Args: id: id string of the current input config. config: input config to be iterated. rON)r4dictr enumeraterK)rLr r.krDsub_idrrriter_subconfigss " z!ReferenceResolver.iter_subconfigszdict[str, int])valuercCsdi}||}|j|}t|}|D]6}|s8||kr(|t|jd}||dd||<q(|S)z 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. NrrN)r% id_matcherfindallr is_expressionlenrefr')rLr[r/result value_is_exprrr rrrmatch_refs_patterns     z$ReferenceResolver.match_refs_patternrV)r[r/rcCs||}|j|}|jtddt|}|D]}|sB||kr2|t|jd}||krd|d}|jsvt |t |q2|r| ||j d|d}q2||kr2||}q2|S)a 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`. T)keyreverseNzcan not find expected ID 'z' in the references.z['z'])r%r\r]sortr_rr^r`r r3r<r=rJrA)rLr[r/rarbrZref_idrFrrrupdate_refs_patterns$       z%ReferenceResolver.update_refs_patternzdict[str, int] | None)r.r r/rc Cs|pi}t|tr@|j|dD]\}}||d|||<q"t|ttfsR|S|||D]<\}}}t |st |r||krd||<| |||}q^|S)a7 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`. )r[rrN) r4r"rcrr'listrVrZris_instantiablerr^r:) rLr.r r/refs_count_rYrDrrrr:$s z%ReferenceResolver.find_refs_in_configz dict | Nonec Cs|pi}t|tr|||St|ttfs0|St|}|||D]l\}}}t|sdt |r||} t|r| dkrqFn| |||} t|tr| || in| | qF|S)aD 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`. N)r4r"rgrhrVtyperZrrirr^r?updateappend) rLr.r r/rjretidxrYrDupdatedrrrr?>s    $z)ReferenceResolver.update_config_with_refs)N)F)N)F)N)N)__name__ __module__ __qualname____doc__rAr rKr r`recompiler\r rrrr!r(r&rH classmethodr%rUrZrcrgr:r?rrrrr s8 J   %) __future__rrwr<collections.abcrtypingrrmonai.bundle.config_itemrrrmonai.bundle.utilsr r monai.utilsr r __all__r rrrr s