U
    Ph"                     @  sx   d Z ddlmZ ddlmZ ddlmZ ddddgZed	dddZ	ed	dd Z
ed	dd ZG dd dZd
S )a  
How to use the adaptor function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The key to using 'adaptor' lies in understanding the function that want to
adapt. The 'inputs' and 'outputs' parameters take either strings, lists/tuples
of strings or a dictionary mapping strings, depending on call signature of the
function being called.

The adaptor function is written to minimise the cognitive load on the caller.
There should be a minimal number of cases where the caller has to set anything
on the input parameter, and for functions that return a single value, it is
only necessary to name the dictionary keyword to which that value is assigned.

Use of `outputs`
----------------

`outputs` can take either a string, a list/tuple of string or a dict of string
to string, depending on what the transform being adapted returns:

    - If the transform returns a single argument, then outputs can be supplied a
      string that indicates what key to assign the return value to in the
      dictionary
    - If the transform returns a list/tuple of values, then outputs can be supplied
      a list/tuple of the same length. The strings in outputs map the return value
      at the corresponding position to a key in the dictionary
    - If the transform returns a dictionary of values, then outputs must be supplied
      a dictionary that maps keys in the function's return dictionary to the
      dictionary being passed between functions

Note, the caller is free to use a more complex way of specifying the outputs
parameter than is required. The following are synonymous and will be treated
identically:

.. code-block:: python

   # single argument
   adaptor(MyTransform(), 'image')
   adaptor(MyTransform(), ['image'])
   adaptor(MyTransform(), {'image': 'image'})

   # multiple arguments
   adaptor(MyTransform(), ['image', 'label'])
   adaptor(MyTransform(), {'image': 'image', 'label': 'label'})

Use of `inputs`
---------------

`inputs` can usually be omitted when using `adaptor`. It is only required when a
the function's parameter names do not match the names in the dictionary that is
used to chain transform calls.

.. code-block:: python

    class MyTransform1:
        def __call__(self, image):
            # do stuff to image
            return image + 1


    class MyTransform2:
        def __call__(self, img_dict):
            # do stuff to image
            img_dict["image"] += 1
            return img_dict


    xform = Compose([adaptor(MyTransform1(), "image"), MyTransform2()])
    d = {"image": 1}
    print(xform(d))

    >>> {'image': 3}

.. code-block:: python

    class MyTransform3:
        def __call__(self, img_dict):
            # do stuff to image
            img_dict["image"] -= 1
            img_dict["segment"] = img_dict["image"]
            return img_dict


    class MyTransform4:
        def __call__(self, img, seg):
            # do stuff to image
            img -= 1
            seg -= 1
            return img, seg


    xform = Compose([MyTransform3(), adaptor(MyTransform4(), ["img", "seg"], {"image": "img", "segment": "seg"})])
    d = {"image": 1}
    print(xform(d))

    >>> {'image': 0, 'segment': 0, 'img': -1, 'seg': -1}

Inputs:

- dictionary in: None | Name maps
- params in (match): None | Name list | Name maps
- params in (mismatch): Name maps
- params & `**kwargs` (match) : None | Name maps
- params & `**kwargs` (mismatch) : Name maps

Outputs:

- dictionary out: None | Name maps
- list/tuple out: list/tuple
- variable out: string

    )annotations)Callable)exportadaptorapply_alias	to_kwargsFunctionSignaturezmonai.transformsNc                   s<   dd dd dd dd  fd	d
}|S )Nc                 S  s4   |d k	r0t ||s0td|  d| dt| d S )N'z' must be None or one of  but is 
isinstance	TypeErrortypevariable_namevariabletypes r   N/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/transforms/adaptors.pymust_be_types_or_none   s    
z&adaptor.<locals>.must_be_types_or_nonec                 S  s,   t ||s(td|  d| dt| d S )Nr	   z' must be one of r
   r   r   r   r   r   must_be_types   s    
zadaptor.<locals>.must_be_typesc                   s    fdd|   D S )Nc                   s   i | ]\}} |||qS r   r   .0kv	input_mapr   r   
<dictcomp>   s      z.adaptor.<locals>.map_names.<locals>.<dictcomp>itemsditemsr   r   r   r   	map_names   s    zadaptor.<locals>.map_namesc                   s    fdd|  D S )Nc                   s   i | ]\}}| | qS r   r   r   r!   r   r   r      s      z3adaptor.<locals>.map_only_names.<locals>.<dictcomp>r   r    r   r#   r   map_only_names   s    zadaptor.<locals>.map_only_namesc                   s   t jr:dtf d kr.t|  qȈ|  nfdd|  D  dttttf d krnnZttrtj	dkrt
d|  i n,tttfr fddD  n
|  f  	}ttrd|tf |d k	r؇fdd| D ntttfrtdkrDd|tttf nd|ttf t|trf|g}tt	krt
d	tt|nHd|tttf t|ttfrt|dkrt
d
|d }|it| }  D ]\}}|| |< q| S )Ninputsc                   s    i | ]\}}| j kr||qS r   )non_var_parametersr   )sigr   r   r      s     
  z+adaptor.<locals>._inner.<locals>.<dictcomp>   zOif 'inputs' is a string, function may only have a single non-variadic parameterc                   s   i | ]}| | qS r   r   )r   r   )dinputsr   r   r      s      outputsc                   s   i | ]\}}| | qS r   r   r   )retr   r   r      s      zP'outputs' must have the same length as the number of elements that were returnedz8'outputs' must be of length one if it is a list or tupler   )r   found_kwargsdictr   strlisttupler   lenr&   
ValueErrorzip)r!   opr   r   functionr%   r"   r$   r   r   r*   )r)   r+   r'   r   _inner   sT    




zadaptor.<locals>._innerr   )r6   r*   r%   r7   r   r5   r   r      s    @c                   s    fdd}|S )Nc                   sT   t | } D ]\}}||||< q |} D ]\}}||||< q8|S N)r-   r   pop)dataZpre_callZ_from_toZ	post_callfnname_mapr   r   r7      s    zapply_alias.<locals>._innerr   )r=   r>   r7   r   r<   r   r      s    c                   s    fdd}|S )Nc                   s
    f | S r8   r   )r:   r=   r   r   r7      s    zto_kwargs.<locals>._innerr   )r=   r7   r   r?   r   r      s    c                   @  s8   e Zd ZdddddZdddd	Zddd
dZdS )r   r   None)r6   returnc                 C  s   dd l }||}d| _d| _i | _t | _|j D ]P}|j	|j
jkrNd| _|j	|j
jkrdd| _q6| j|j |j|jk	| j|j< q6d S )Nr   FT)inspect	signature
found_argsr,   defaultssetr&   
parametersvalueskind	ParameterVAR_POSITIONALVAR_KEYWORDaddnamedefaultempty)selfr6   rB   Zsfnpr   r   r   __init__   s    
zFunctionSignature.__init__r.   )rA   c                 C  s   d}| | j| j| jS )NzG<class 'FunctionSignature': found_args={}, found_kwargs={}, defaults={})formatrD   r,   rE   )rQ   sr   r   r   __repr__  s    zFunctionSignature.__repr__c                 C  s   |   S r8   )rV   )rQ   r   r   r   __str__  s    zFunctionSignature.__str__N)__name__
__module____qualname__rS   rV   rW   r   r   r   r   r      s   )N)__doc__
__future__r   typingr   monai.utilsr   Z_monai_export__all__r   r   r   r   r   r   r   r   <module>   s   qT

