U
    Pha                     @  s  d dl mZ d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	m
Z
mZmZmZ d dlmZmZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZmZ d d
lmZmZmZ d dlZej dddkZ!ej dddkZ"ej dddkZ#dZ$dddddddddddddddd d!gZ%dSd$d%d&d'd&d(d)dZ&d*d*d+d,d-dZ'd.d Z(dTd0d'd*d1d2d3dZ)d*d*d&d&d4d5dZ*d6d Z+dUd&d*d&d'd8d9dZ,dVd&d*d&d'd:d;dZ-G d<d de.Z/G d=d de0Z1d7e,d7e$dd>d?fd*d*d@d*d*d&d'd*dAdB	dCdZ2d7e,d#fd*d*d@d'dDdEdFdZ3dWdHdZ4e5ddId Z6d*d*dJdKdLdMZ7d*d*d'dKdNdZ8d*d*d'dKdOd Z9e5ddXd+d+d+dPd'dQdRd!Z:dS )Y    )annotationsN)Callable
CollectionHashableMapping)partialwraps)import_module)walk_packages)locate)match)FunctionType
ModuleType)AnyIterablecastZMONAI_EVAL_EXPR10ZMONAI_DEBUG_CONFIGZMONAI_ALLOW_MISSING_REFERENCEz{}InvalidPyTorchVersionErrorOptionalImportErrorexact_versionexportdamerau_levenshtein_distancelook_up_optionmin_versionoptional_importrequire_pkgload_submodulesinstantiateget_full_type_nameget_package_versionget_torch_version_tupleversion_leqversion_geqpytorch_after
no_defaultTr   zCollection | enum.EnumMetar   bool)opt_str	supporteddefaultprint_all_optionsreturnc           
      C  s  t | ts$tdt|  d|  dt | tr6|  } t |tjrt | trf| dd |D krf|| S t | tjr| |kr| S n0t |t	r| |kr||  S t |t
r| |kr| S |dkr|S t |tjrdd |D }n|dk	rt|nt }|std	| di }|  } |D ]$}t| | }|d
kr|||< q|rJd| dnd}|rt||jd}	td|  d|	 dd|  d | td|  d| dS )a3  
    Look up the option in the supported collection and return the matched item.
    Raise a value error possibly with a guess of the closest match.

    Args:
        opt_str: The option string or Enum to look up.
        supported: The collection of supported options, it can be list, tuple, set, dict, or Enum.
        default: If it is given, this method will return `default` when `opt_str` is not found,
            instead of raising a `ValueError`. Otherwise, it defaults to `"no_default"`,
            so that the method may raise a `ValueError`.
        print_all_options: whether to print all available options when `opt_str` is not found. Defaults to True

    Examples:

    .. code-block:: python

        from enum import Enum
        from monai.utils import look_up_option
        class Color(Enum):
            RED = "red"
            BLUE = "blue"
        look_up_option("red", Color)  # <Color.RED: 'red'>
        look_up_option(Color.RED, Color)  # <Color.RED: 'red'>
        look_up_option("read", Color)
        # ValueError: By 'read', did you mean 'red'?
        # 'read' is not a valid option.
        # Available options are {'blue', 'red'}.
        look_up_option("red", {"red", "blue"})  # "red"

    Adapted from https://github.com/NifTK/NiftyNet/blob/v0.6.0/niftynet/utilities/util_common.py#L249
    zUnrecognized option type: :.c                 S  s   h | ]
}|j qS  value.0itemr.   r.   G/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/utils/module.py	<setcomp>i   s     z!look_up_option.<locals>.<setcomp>r%   c                 S  s   h | ]
}|j qS r.   r/   r1   r.   r.   r4   r5   {   s     NzNo options available:    zAvailable options are z.
 )keyzBy 'z', did you mean 'z'?
'z' is not a valid value.
zUnsupported option 'z', )
isinstancer   
ValueErrortypestrstripenumEnumMetaEnumr   r   setr   minget)
r'   r(   r)   r*   Zset_to_checkZ
edit_distsr8   Z	edit_distZsupported_msgZguess_at_spellingr.   r.   r4   r   ?   sJ    %



r=   int)s1s2r+   c           
   	   C  sN  | |krdS t | }t |}| s$|S |s,|S dd td|d D }td|d D ]}|d |d|f< qRt| D ]\}}t|D ]\}}||krdnd}	t||d |f d |||d f d ||d |d f |	 |||f< |r|r|||d  kr| |d  |krt|||f ||d |d f |	 |||f< qqp||d |d f S )u   
    Calculates the Damerau–Levenshtein distance between two strings for spelling correction.
    https://en.wikipedia.org/wiki/Damerau–Levenshtein_distance
    r   c                 S  s   i | ]}|d f|d qS )   r.   )r2   ir.   r.   r4   
<dictcomp>   s      z0damerau_levenshtein_distance.<locals>.<dictcomp>rH   rI      )lenrange	enumeraterC   )
rF   rG   Zstring_1_lengthZstring_2_lengthdjrJ   s1iZs2jcostr.   r.   r4   r      s,      (2c                   s    fdd}|S )aA  
    Make the decorated object a member of the named module. This will also add the object under its aliases if it has
    a `__aliases__` member, thus this decorator should be before the `alias` decorator to pick up those names. Alias
    names which conflict with package names or existing members will be ignored.
    c                   sN   t  }t|| jsJt|| j|  t| ddD ]}t||s.t|||  q.| S )N__aliases__r.   )r	   hasattr__name__setattrgetattr)objmodaliasmodnamer.   r4   _inner   s    
zexport.<locals>._innerr.   )r]   r^   r.   r\   r4   r      s    (.*[tT]est.*)|(_.*)r   z"tuple[list[ModuleType], list[str]])basemodload_allexclude_patternr+   c                 C  s   g }g }t | j| jd |jdD ]\}}}|s2|r |tjkr t||dkr z(t|}||j	
| || W q  tk
r   Y q  tk
r }	 z(d}
t|	|	 d|
 |	j|	W 5 d}	~	X Y q X q ||fS )z
    Traverse the source of the module structure starting with module `basemod`, loading all packages plus all files if
    `load_all` is True, excluding anything whose name matches `exclude_pattern`.
    r-   )prefixonerrorNz
Multiple versions of MONAI may have been installed?
Please see the installation guide: https://docs.monai.io/en/stable/installation.html

)r
   __path__rV   appendsysmodulesr   r	   	find_specloaderload_moduler   ImportErrorr<   with_traceback__traceback__)r`   ra   rb   
submodulesZerr_modimporternameZis_pkgrZ   emsgr.   r.   r4   r      s&       4)__path__modekwargsr+   c                 K  sl  ddl m} t| trt| n| }|dkr:td|  dt||}z|ddsVtrtt	
d| d	| d
 t  t|st	
d| d| d |W S ||jkr|f |W S ||jkr|rt|f|n|W S ||jkrt	
d| d	| d
 tj|f|W S W nN tk
rT } z.td|  dd|  d|j d|W 5 d}~X Y nX t	
d|  d |S )a  
    Create an object instance or call a callable object from a class or function represented by ``_path``.
    `kwargs` will be part of the input arguments to the class constructor or function.
    The target component must be a class or a function, if not, return the component directly.

    Args:
        __path: if a string is provided, it's interpreted as the full path of the target class or function component.
            If a callable is provided, ``__path(**kwargs)`` will be invoked and returned for ``__mode="default"``.
            For ``__mode="callable"``, the callable will be returned as ``__path`` or, if ``kwargs`` are provided,
            as ``functools.partial(__path, **kwargs)`` for future invoking.

        __mode: the operating mode for invoking the (callable) ``component`` represented by ``__path``:

            - ``"default"``: returns ``component(**kwargs)``
            - ``"callable"``: returns ``component`` or, if ``kwargs`` are provided, ``functools.partial(component, **kwargs)``
            - ``"debug"``: returns ``pdb.runcall(component, **kwargs)``

        kwargs: keyword arguments to the callable represented by ``__path``.

    r   )CompInitModeNz'Cannot locate class or function path: 'z'.Z_debug_Fz

pdb: instantiating component=z, mode=zV
See also Debugger commands documentation: https://docs.python.org/3/library/pdb.html
z
Component z is not callable when mode=r-   z!Failed to instantiate component 'z' with keywords: ,z
 set '_mode_=z' to enter the debugging mode.zKComponent to instantiate must represent a valid class or function, but got )monai.utils.enumsrx   r:   r=   r   ModuleNotFoundErrorr   pop	run_debugwarningswarn
breakpointcallableDEFAULTZCALLABLEr   DEBUGpdbZruncall	ExceptionRuntimeErrorjoinkeys)ru   rv   rw   rx   	componentmrs   r.   r.   r4   r      s>    


"c                 C  s.   | j }|dks|tjj kr | jS |d | j S )zG
    Utility to get the full path name of a class or object type.

    Nr-   )
__module__r=   	__class__rV   )typeobjmoduler.   r.   r4   r     s    r7   )
the_modulemin_version_str_argsr+   c                 G  s\   |rt | dsdS tdd | jddd D }tdd |ddd D }||kS )	z
    Convert version strings into tuples of int and compare them.

    Returns True if the module's version is greater or equal to the 'min_version'.
    When min_version_str is not provided, it always returns True.
    __version__Tc                 s  s   | ]}t |V  qd S NrE   r2   xr.   r.   r4   	<genexpr>0  s     zmin_version.<locals>.<genexpr>r-   NrL   c                 s  s   | ]}t |V  qd S r   r   r   r.   r.   r4   r   1  s     )rU   tupler   split)r   r   r   Zmod_versionrequiredr.   r.   r4   r   &  s
    " )r   version_strr   r+   c                 G  s,   t | dst|  d dS t| j|kS )zF
    Returns True if the module's __version__ matches version_str
    r   z5 has no attribute __version__ in exact_version check.F)rU   r~   r   r&   r   )r   r   r   r.   r.   r4   r   5  s    
c                      s    e Zd ZdZ fddZ  ZS )r   zo
    Raised when called function or method requires a more recent
    PyTorch version than that installed.
    c                   s    | d| d}t  | d S )Nz requires PyTorch version z	 or later)super__init__)selfZrequired_versionrr   messager   r.   r4   r   E  s    z#InvalidPyTorchVersionError.__init__)rV   r   __qualname____doc__r   __classcell__r.   r.   r   r4   r   ?  s   c                   @  s   e Zd ZdZdS )r   z<
    Could not import APIs from an optional dependency.
    N)rV   r   r   r   r.   r.   r.   r4   r   J  s   Fr)   zCallable[..., bool]ztuple[Any, bool])	r   versionversion_checkerrr   
descriptorversion_argsallow_namespace_pkgas_typer+   c              
     sd  dd}|rd|  d| }	n
d|  }	zHt | }
t| }|s`t|dddkoVt|d}|r`t|rnt||}W n. tk
r } z|j| }W 5 d}~X Y n4X |r||
| |r|dfS |s||
| r|dfS ||	|r
dkr
d	|  d
| d|j d7 |r d| d7 G fddd} dkrH| dfS G  fddd|}|dfS )a	  
    Imports an optional module specified by `module` string.
    Any importing related exceptions will be stored, and exceptions raise lazily
    when attempting to use the failed-to-import module.

    Args:
        module: name of the module to be imported.
        version: version string used by the version_checker.
        version_checker: a callable to check the module version, Defaults to monai.utils.min_version.
        name: a non-module attribute (such as method/class) to import from the imported module.
        descriptor: a format string for the final error message when using a not imported module.
        version_args: additional parameters to the version checker.
        allow_namespace_pkg: whether importing a namespace package is allowed. Defaults to False.
        as_type: there are cases where the optionally imported object is used as
            a base class, or a decorator, the exceptions should raise accordingly. The current supported values
            are "default" (call once to raise), "decorator" (call the constructor and the second call to raise),
            and anything else will return a lazy class that can be used as a base class (call the constructor to raise).

    Returns:
        The imported module and a boolean flag indicating whether the import is successful.

    Examples::

        >>> torch, flag = optional_import('torch', '1.1')
        >>> print(torch, flag)
        <module 'torch' from 'python/lib/python3.6/site-packages/torch/__init__.py'> True

        >>> the_module, flag = optional_import('unknown_module')
        >>> print(flag)
        False
        >>> the_module.method  # trying to access a module which is not imported
        OptionalImportError: import unknown_module (No module named 'unknown_module').

        >>> torch, flag = optional_import('torch', '42', exact_version)
        >>> torch.nn  # trying to access a module for which there isn't a proper version imported
        OptionalImportError: import torch (requires version '42' by 'exact_version').

        >>> conv, flag = optional_import('torch.nn.functional', '1.0', name='conv1d')
        >>> print(conv)
        <built-in method conv1d of type object at 0x11a49eac0>

        >>> conv, flag = optional_import('torch.nn.functional', '42', name='conv1d')
        >>> conv()  # trying to use a function from the not successfully imported module (due to unmatched version)
        OptionalImportError: from torch.nn.functional import conv1d (requires version '42' by 'min_version').
    Nr7   zfrom z import zimport __file__rf   Tz (requires ' z' by 'z')z ()c                      s:   e Zd Z fddZdd Zdd Zdd Zd	d
 ZdS )z#optional_import.<locals>._LazyRaisec                   s:     dd d }d kr&t || _nt || _d S )Nr-   zG

For details about installing the optional dependencies, please visit:z^
    https://docs.monai.io/en/latest/installation.html#installing-the-recommended-dependencies)r   
_exceptionrn   )r   r   _kwargsZ_default_msgrt   tbr.   r4   r     s    z,optional_import.<locals>._LazyRaise.__init__c                 S  s
   | j dS za
            Raises:
                OptionalImportError: When you call this method.
            Nr   )r   rr   r.   r.   r4   __getattr__  s    z/optional_import.<locals>._LazyRaise.__getattr__c                 _  s
   | j dS r   r   )r   r   r   r.   r.   r4   __call__  s    z,optional_import.<locals>._LazyRaise.__call__c                 S  s
   | j d S r   r   )r   r3   r.   r.   r4   __getitem__  s    z/optional_import.<locals>._LazyRaise.__getitem__c                 S  s
   | j d S r   r   )r   r.   r.   r4   __iter__  s    z,optional_import.<locals>._LazyRaise.__iter__N)rV   r   r   r   r   r   r   r   r.   r   r.   r4   
_LazyRaise  s
   r   r)   Fc                      s   e Zd Z fddZ  ZS )z!optional_import.<locals>._LazyClsc                   s   t    ds| jd S )N	decorator)r   r   
startswithr   )r   r   rw   )r   r   r.   r4   r     s    

z*optional_import.<locals>._LazyCls.__init__)rV   r   r   r   r   r.   )r   r   r4   _LazyCls  s   r   )	
__import__r	   rX   rU   AssertionErrorr   ro   formatrV   )r   r   r   rr   r   r   r   r   Zexception_strZ
actual_cmdpkgr   is_namespaceZimport_exceptionr   r   r.   )r   rt   r   r4   r   P  s>    8

!

r   )pkg_namer   r   raise_errorr+   c                   s    fdd}|S )a  
    Decorator function to check the required package installation.

    Args:
        pkg_name: required package name, like: "itk", "nibabel", etc.
        version: required version string used by the version_checker.
        version_checker: a callable to check the module version, defaults to `monai.utils.min_version`.
        raise_error: if True, raise `OptionalImportError` error if the required package is not installed
            or the version doesn't match requirement, if False, print the error in a warning.

    c                   sF   t | t}|r| n| j t  fdd}|r<|S || _| S )Nc                    sD   t d\}}|s:d d}r0t|n
t|  | |S )N)r   r   r   zrequired package `z<` is not installed or the version doesn't match requirement.)r   r   r~   r   )argsrw   _haserr_msg)call_objr   r   r   r   r.   r4   _wrapper  s    

z1require_pkg.<locals>._decorator.<locals>._wrapper)r:   r   r   r   )rY   is_funcr   r   r   r   r   )r   r4   
_decorator  s    
zrequire_pkg.<locals>._decoratorr.   )r   r   r   r   r   r.   r   r4   r     s    !NOT INSTALLED or UNKNOWN VERSION.c                 C  s$   t | \}}|r t|dr |jS |S )zN
    Try to load package and get version. If not found, return `default`.
    r   )r   rU   r   )Zdep_namer)   depZhas_depr.   r.   r4   r      s    c                   C  s"   t dd tjddd D S )zT
    Returns:
        tuple of ints represents the pytorch major/minor version.
    c                 s  s   | ]}t |V  qd S r   r   r   r.   r.   r4   r     s     z*get_torch_version_tuple.<locals>.<genexpr>r-   NrL   )r   torchr   r   r.   r.   r.   r4   r!     s    z/tuple[Iterable[int | str], Iterable[int | str]])lhsrhsr+   c                 C  sX   ddddd}|  ddd } | ddd }t||  d	}t|| d	}||fS )
z$
    Parse the version strings.
    r=   z	int | str)valr+   c                 S  sT   |   } z.td| }|d k	r2| d } t| W S | W S  tk
rN   |  Y S X d S )Nz	(\d+)(.*)r   )r>   r   groupsrE   r;   )r   r   r.   r.   r4   	_try_cast  s    

z%parse_version_strs.<locals>._try_cast+rI   r   r-   )r   map)r   r   r   lhs_rhs_r.   r.   r4   parse_version_strs  s    r   c                 C  s   t | t | } }tddd\}}|rbz tt|j| |j|kW S  |jjk
r`   Y dS X t| |\}}t||D ]@\}}||krzt	|t
rt	|t
r||k   S | | k   S qzdS )a  
    Returns True if version `lhs` is earlier or equal to `rhs`.

    Args:
        lhs: version name to compare with `rhs`, return True if earlier or equal to `rhs`.
        rhs: version name to compare with `lhs`, return True if later or equal to `lhs`.

    pkg_resources	packagingrr   Tr=   r   r   r&   r   VersionInvalidVersionr   zipr:   rE   r   r   Zpkginghas_verr   r   lrr.   r.   r4   r"   )  s    
 c                 C  s   t | t | } }tddd\}}|rbz tt|j| |j|kW S  |jjk
r`   Y dS X t| |\}}t||D ]@\}}||krzt	|t
rt	|t
r||k  S | | k  S qzdS )a  
    Returns True if version `lhs` is later or equal to `rhs`.

    Args:
        lhs: version name to compare with `rhs`, return True if later or equal to `rhs`.
        rhs: version name to compare with `lhs`, return True if earlier or equal to `lhs`.

    r   r   r   Tr   r   r.   r.   r4   r#   E  s    	 z
str | None)majorminorpatchcurrent_ver_stringr+   c              
   C  s  z|dkr&t jdd}|r |ntj}tddd\}}|r`|d|  | | f|| kW S | dd	d
 dd}t|dk r|dg7 }qz|dd \}}	}
W n( t	t
tfk
r   t \}}	d}
Y nX t|t|	f}t| t|f}||kr||kS d|
  kpd|
  k}d
}z$td|
 }|rFt| }W n  t	tt
fk
rh   d}Y nX t|}||kr||kS |rdS dS )aJ  
    Compute whether the current pytorch version is after or equal to the specified version.
    The current system pytorch version is determined by `torch.__version__` or
    via system environment variable `PYTORCH_VER`.

    Args:
        major: major version number to be compared with
        minor: minor version number to be compared with
        patch: patch version number to be compared with
        current_ver_string: if None, `torch.__version__` will be used.

    Returns:
        True if the current pytorch version is greater than or equal to the specified version.
    NZPYTORCH_VERr7   r   Zparse_versionr   r-   r   rI   r   r6   r   arcz\d+TF)osenvironrD   r   r   r   r   r   rM   AttributeErrorr;   	TypeErrorr!   rE   lowerresearchgroup)r   r   r   r   Z_env_varverr   partsZc_majorZc_minorZc_patchZc_mnmnis_prereleaseZc_pZp_regr.   r.   r4   r$   `  s@    &




)r%   T)Tr_   )r7   )r7   )r   )r   N);
__future__r   r?   	functoolsr   r   r   rh   r~   collections.abcr   r   r   r   r   r   	importlibr	   pkgutilr
   pydocr   r   typesr   r   typingr   r   r   r   r   rD   run_evalr}   allow_missing_referenceZOPTIONAL_IMPORT_MSG_FMT__all__r   r   r   r   r   r   r   r   r   r   rm   r   r   r   r    	lru_cacher!   r   r"   r#   r$   r.   r.   r.   r4   <module>   s     S   9
    '


