o
    $ilA                     @  s   d dl mZ d dlZd dlZd dlmZmZ d dlmZ d dl	m
Z
mZmZ d dlmZmZmZ d dlmZmZ dgZG d	d dZdS )
    )annotationsN)IteratorSequence)Any)ConfigComponentConfigExpression
ConfigItem)DEPRECATED_ID_MAPPING
ID_REF_KEY
ID_SEP_KEY)allow_missing_referencelook_up_optionReferenceResolverc                   @  s   e Zd ZdZdZeZeZe	
e de dZeZdCdDdd	Zd
d ZdEddZdFddZdGdHddZ	dCdId!d"ZdJd#d$ZdKd&d'ZedLd)d*ZdMd,d-ZedGdNd0d1ZedOd3d4ZedPd7d8ZedQd;d<ZedCdRd>d?ZedCdSdAdBZdS )Tr   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*)*NitemsSequence[ConfigItem] | Nonec                 C  s&   |d u ri ndd |D | _ i | _d S )Nc                 S  s   i | ]}|  |qS  )get_id).0ir   r   a/home/dell461/cl/sdc2/last_ska_mid/HISourceFinder-master-l/src/monai/bundle/reference_resolver.py
<dictcomp>>   s    z.ReferenceResolver.__init__.<locals>.<dictcomp>r   resolved_content)selfr   r   r   r   __init__<   s   
zReferenceResolver.__init__c                 C  s   i | _ i | _dS )zQ
        Clear all the added `ConfigItem` and all the resolved content.

        Nr   r   r   r   r   resetA   s   
zReferenceResolver.resetreturnboolc                 C  s
   t | jS N)r   r   r   r   r   r   is_resolvedI   s   
zReferenceResolver.is_resolveditemr   Nonec                 C  s$   |  }|| jv rdS || j|< dS )zk
        Add a ``ConfigItem`` to the resolver.

        Args:
            item: a ``ConfigItem``.

        N)r   r   )r   r!   idr   r   r   add_itemL   s   
zReferenceResolver.add_itemFr#   strresolvekwargsr   ConfigItem | Nonec                 K  s8   |  |}|r|| jvr| jdd|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#   Nr   )normalize_idr   _resolve_one_itemr   get)r   r#   r&   r'   r   r   r   get_itemY   s   
zReferenceResolver.get_itemwaiting_listset[str] | None#ConfigExpression | str | Any | Nonec                 K  sF  |  |}|| jv r| j| S zt|| jd|ddd}W n ty3 } z	td| d|d}~ww t|ts;|S |	 }|du rFt
 }|| | j D ]$\}}|| jvrtt|trt||	 rt|dd	ro| n|| j|< qP| j||d
 D ]V}	|	|v rtd|	 d| d|	| jvrz
t|	| jdd W n% ty } zd|	 d}
| jst|
|t|
 W Y d}~q~d}~ww | jd|	|d| ||	 q~| j||| jd}|j|d t|tr|dd	r| n|| j|< n%t|tr|dd	}|r|j| j | jidn|| 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.

        Fdefault
no_default)print_all_optionsr0   zid='z&' is not found in the config resolver.N	eval_exprT)configr#   zdetected circular references 'z
' for id='z' in the config content.)r2   zthe referring item `@z'` is not defined in the config content.)r#   r-   )r4   r#   refs)r4   instantiate)globalsr   )r)   r   r   r   r+   
ValueErrorKeyError
isinstancer   
get_configsetaddr   is_import_statementevaluatefind_refs_in_configkeysr   warningswarnr*   discardupdate_config_with_refsupdate_configr   r6   _vars)r   r#   r-   r'   r!   errZitem_configtvdmsg
new_configrun_evalr   r   r   r*   k   sd   










 


z#ReferenceResolver._resolve_one_itemc                 K  s   | j dd|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#   Nr   )r*   )r   r#   r'   r   r   r   get_resolved_content   s   z&ReferenceResolver.get_resolved_content
Any | Nonec                 C  s   || j v r| j |S dS )zy
        Remove the resolved ``ConfigItem`` by id.

        Args:
            id: id name of the expected item.

        N)r   pop)r   r#   r   r   r   remove_resolved_content   s   z)ReferenceResolver.remove_resolved_content	str | intc                 C  s   t |d| jS )z
        Normalize the id string to consistently use `cls.sep`.

        Args:
            id: id string to be normalized.
        #)r%   replacesep)clsr#   r   r   r   r)      s   zReferenceResolver.normalize_idr4   c                 C  sR   t |tr't D ]\}}|| v r&td| d| d ||||< q	|S )z
        Update deprecated identifiers in `config` using `DEPRECATED_ID_MAPPING`.
        This will replace names that are marked as deprecated with their replacement.

        Args:
            config: input config to be updated.
        zDetected deprecated name 'z)' in configuration file, replacing with 'z'.)r:   dictr	   r   rA   rB   rC   rQ   )r   r4   _idZ_new_idr   r   r   normalize_meta_id   s   
z#ReferenceResolver.normalize_meta_idlast	list[str]c                 C  sD   |s|  || jS |  || jd}d|dd |d gS )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)   splitrV   rsplitjoin)rW   r#   r[   resr   r   r   split_id   s   	zReferenceResolver.split_idIterator[tuple[str, str, Any]]c                 c  sV    t |tr
| nt|D ]\}}|dkr| | j | n| }|||fV  qdS )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.
        r^   N)r:   rX   r   	enumeraterV   )rW   r#   r4   krJ   sub_idr   r   r   iter_subconfigs   s
   "	 z!ReferenceResolver.iter_subconfigsvaluedict[str, int]c                 C  sd   i }|  |}| j|}t|}|D ]}|s||kr/|t| jd }||dd ||< 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.

        Nr   r]   )r)   
id_matcherfindallr   is_expressionlenrefr+   )rW   rj   r5   resultvalue_is_exprr!   r#   r   r   r   match_refs_pattern  s   


z$ReferenceResolver.match_refs_patternr5   rX   c                 C  s   |  |}| j|}|jtdd t|}|D ]@}|s!||krY|t| jd }||vrAd| d}| js;t	|t
| q|rQ||| j d| d}q||krY|| }q|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)keyreverseNzcan not find expected ID 'z' in the references.z['z'])r)   rl   rm   sortro   r   rn   rp   r   r9   rB   rC   rU   rG   )rW   rj   r5   rq   rr   r!   Zref_idrL   r   r   r   update_refs_pattern  s&   


z%ReferenceResolver.update_refs_patterndict[str, int] | Nonec           	      C  s   |pi }t |tr | j|d D ]\}}||d| ||< qt |ttfs)|S | ||D ]\}}}t	|sBt
|rF||vrFd||< | |||}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`.

        )rj   r   r]   )r:   r%   rs   r   r+   listrX   ri   r   is_instantiabler   rn   r@   )	rW   r4   r#   r5   refs_count_rh   rJ   r   r   r   r@   ?  s   
z%ReferenceResolver.find_refs_in_configdict | Nonec           
      C  s   |pi }t |tr| ||S t |ttfs|S t| }| ||D ]6\}}}t|s2t	
|rA|| }	t|r@|	du r@q#n| |||}	t |trT|||	in||	 q#|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)r:   r%   rw   ry   rX   typeri   r   rz   r   rn   rE   updateappend)
rW   r4   r#   r5   r{   retidxrh   rJ   updatedr   r   r   rE   Y  s    

 z)ReferenceResolver.update_config_with_refsr   )r   r   )r   r   )r!   r   r   r"   )F)r#   r%   r&   r   r'   r   r   r(   )r#   r%   r-   r.   r'   r   r   r/   )r#   r%   r'   r   r   r/   )r#   r%   r   rP   )r#   rS   r   r%   )r4   r   r   r   )r#   rS   r[   r   r   r\   )r#   r%   r4   r   r   re   )rj   r%   r   rk   )rj   r%   r5   rX   r   r%   )r4   r   r#   r%   r5   rx   r   rk   )r4   r   r#   r%   r5   r~   r   r   )__name__
__module____qualname____doc__rG   r   rV   r
   rp   recompilerl   r   r   r   r    r$   r,   r*   rO   rR   classmethodr)   rZ   rd   ri   rs   rw   r@   rE   r   r   r   r   r      s>    


J


	%)
__future__r   r   rB   collections.abcr   r   typingr   monai.bundle.config_itemr   r   r   monai.bundle.utilsr	   r
   r   monai.utilsr   r   __all__r   r   r   r   r   <module>   s   