U
    Jc16                     @   s   d dl mZ d dlZddlmZmZmZmZ ddlm	Z	 ddl
mZmZ d dlZddd	d
dddddddgZG dd deZdd Zdd	 Zefdd
Zdd Zdd ZG dd deZdd ZG dd deZdd Zdd ZdS )    )warnN   )orderingambiguitiessuper_signatureAmbiguityWarning)expand_tuples)Variadic
isvariadicMDNotImplementedErrorambiguity_warnhalt_orderingrestart_orderingvariadic_signature_matches_itervariadic_signature_matches
DispatchersourceMethodDispatcherstr_signaturewarning_textc                   @   s   e Zd ZdZdS )r   z- A NotImplementedError for multiple dispatch N)__name__
__module____qualname____doc__ r   r   a/tmp/pip-unpacked-wheel-gikjz4vx/torch/fx/experimental/unification/multipledispatch/dispatcher.pyr      s   c                 C   s   t t| j|t dS )aA   Raise warning when ambiguity is detected
    Parameters
    ----------
    dispatcher : Dispatcher
        The dispatcher on which the ambiguity was detected
    ambiguities : set
        Set of type signature pairs that are ambiguous within this dispatcher
    See Also:
        Dispatcher.add
        warning_text
    N)r   r   namer   )
dispatcherr   r   r   r   r      s    c                   C   s   t dt dS )z:Deprecated interface to temporarily disable ordering.
    z=halt_ordering is deprecated, you can safely remove this call.Nr   DeprecationWarningr   r   r   r   r      s    c                 C   s   t dt dS )z9Deprecated interface to temporarily resume ordering.
    zrestart_ordering is deprecated, if you would like to eagerly orderthe dispatchers, you should call the ``reorder()`` method on each dispatcher.Nr   )on_ambiguityr   r   r   r   '   s    c                 c   sx   t |}t|}| D ]$}t||}|V  t|st|}qzt|}W n& tk
rl   t|sbtdV  Y nX dV  dS )ag  Check if a set of input types matches a variadic signature.
    Notes
    -----
    The algorithm is as follows:
    Initialize the current signature to the first in the sequence
    For each type in `types`:
        If the current signature is variadic
            If the type matches the signature
                yield True
            Else
                Try to get the next signature
                If no signatures are left we can't possibly have a match
                    so yield False
        Else
            yield True if the type matches the current signature
            Get the next signature
    TFN)iternext
issubclassr
   StopIterationAssertionError)typesfull_signatureZsigitersigtypmatchesr   r   r   r   2   s    

c                 C   s   |st tt| |S N)r%   allr   )r&   r'   r   r   r   r   Y   s    c                   @   s   e Zd ZdZdZd*ddZdd Zedd	 Zed
d Z	dd Z
edd ZefddZdd Zdd ZeZdd Zdd Zdd Zdd Zdd Zed d! Zd"d# Zd$d% Zd&d' Zd(d) ZdS )+r   a   Dispatch methods based on type signature
    Use ``dispatch`` to add implementations
    Examples
    --------
    >>> # xdoctest: +SKIP("bad import name")
    >>> from multipledispatch import dispatch
    >>> @dispatch(int)
    ... def f(x):
    ...     return x + 1
    >>> @dispatch(float)
    ... def f(x):
    ...     return x - 1
    >>> f(3)
    4
    >>> f(3.0)
    2.0
    )r   r   funcs	_ordering_cachedocNc                 C   s"   | | _ | _i | _|| _i | _d S r+   )r   r   r-   r0   r/   )selfr   r0   r   r   r   __init__s   s    zDispatcher.__init__c                    s    fdd}|S )a   register dispatcher with new implementation
        >>> f = Dispatcher('f')
        >>> @f.register(int)
        ... def inc(x):
        ...     return x + 1
        >>> @f.register(float)
        ... def dec(x):
        ...     return x - 1
        >>> @f.register(list)
        ... @f.register(tuple)
        ... def reverse(x):
        ...     return x[::-1]
        >>> f(1)
        2
        >>> f(1.0)
        0.0
        >>> f([1, 2, 3])
        [3, 2, 1]
        c                    s   j | f  | S r+   )add)funckwargsr1   r&   r   r   _df   s    z Dispatcher.register.<locals>._dfr   )r1   r&   r6   r7   r   r5   r   registerz   s    zDispatcher.registerc                 C   s"   t tdrt|}|j S d S )N	signature)hasattrinspectr9   
parametersvaluesclsr4   r(   r   r   r   get_func_params   s    

zDispatcher.get_func_paramsc                    sV   |  |}|rRtj  fdd|D }tdd |D }t fdd|D rR|S dS )z; get annotations of function positional parameters
        c                 3   s$   | ]}|j  j jfkr|V  qd S r+   )kindPOSITIONAL_ONLYPOSITIONAL_OR_KEYWORD.0param	Parameterr   r   	<genexpr>   s    z2Dispatcher.get_func_annotations.<locals>.<genexpr>c                 s   s   | ]}|j V  qd S r+   )
annotationrD   r   r   r   rI      s   c                 3   s   | ]}| j k	V  qd S r+   )empty)rE   annrG   r   r   rI      s     N)r@   r;   rH   tupler,   )r?   r4   paramsannotationsr   rG   r   get_func_annotations   s    
zDispatcher.get_func_annotationsc           	      C   s"  |s|  |}|r|}tdd |D rFt|D ]}| || q0dS g }t|ddD ]\}}t|ttfsddd |D }t	d||| j
f t|tr|t|krt	d	t|dkrt	d
|t|d   qV|| qV|| jt|< | j  z| `W n tk
r   Y nX dS )a[   Add new types/method pair to dispatcher
        >>> D = Dispatcher('add')
        >>> D.add((int, int), lambda x, y: x + y)
        >>> D.add((float, float), lambda x, y: x + y)
        >>> D(1, 2)
        3
        >>> D(1, 2.0)
        Traceback (most recent call last):
        ...
        NotImplementedError: Could not find signature for add: <int, float>
        >>> # When ``add`` detects a warning it calls the ``on_ambiguity`` callback
        >>> # with a dispatcher/itself, and a set of ambiguous type signature pairs
        >>> # as inputs.  See ``ambiguity_warn`` for an example.
        c                 s   s   | ]}t |tV  qd S r+   )
isinstancerM   )rE   r)   r   r   r   rI      s     z!Dispatcher.add.<locals>.<genexpr>Nr   )start, c                 s   s&   | ]}t |tr|jnt|V  qd S r+   )rQ   typer   str)rE   cr   r   r   rI      s   zDTried to dispatch on non-type: %s
In signature: <%s>
In function: %sz+Variadic signature must be the last elementzVariadic signature must contain exactly one element. To use a variadic union type place the desired types inside of a tuple, e.g., [(int, str)]r   )rP   anyr   r3   	enumeraterQ   rT   listjoin	TypeErrorr   lenappendr	   r-   rM   r/   clearr.   AttributeError)	r1   r9   r4   rO   ZtypsZnew_signatureindexr)   Zstr_sigr   r   r   r3      sD    




zDispatcher.addc                 C   s*   z| j W S  tk
r$   |   Y S X d S r+   )r.   r_   reorderr1   r   r   r   r      s    zDispatcher.orderingc                 C   s,   t | j | _}t| j}|r(|| | |S r+   )r   r-   r.   r   )r1   r    Zodambr   r   r   ra      s
    

zDispatcher.reorderc                 O   s   t dd |D }z| j| }W nB tk
rb   | j| }|sTtd| jt|f || j|< Y nX z|||W S  tk
r   | j| }t	| |D ].}z|||W    Y S  tk
r   Y qX qtd| jt|f Y nX d S )Nc                 S   s   g | ]}t |qS r   rT   rE   argr   r   r   
<listcomp>   s     z'Dispatcher.__call__.<locals>.<listcomp>%Could not find signature for %s: <%s>zFMatching functions for %s: <%s> found, but none completed successfully)
rM   r/   KeyErrordispatchNotImplementedErrorr   r   r   dispatch_iterr"   )r1   argsr6   r&   r4   r-   r   r   r   __call__   s:    

 zDispatcher.__call__c                 C   s
   d| j  S )Nz<dispatched %s>r   rb   r   r   r   __str__  s    zDispatcher.__str__c                 G   s@   || j kr| j | S zt| j| W S  tk
r:   Y dS X dS )aj  Deterimine appropriate implementation for this type signature
        This method is internal.  Users should call this object as a function.
        Implementation resolution occurs within the ``__call__`` method.
        >>> # xdoctest: +SKIP
        >>> from multipledispatch import dispatch
        >>> @dispatch(int)
        ... def inc(x):
        ...     return x + 1
        >>> implementation = inc.dispatch(int)
        >>> implementation(3)
        4
        >>> print(inc.dispatch(float))
        None
        See Also:
          ``multipledispatch.conflict`` - module to determine resolution order
        N)r-   r"   rl   r$   r1   r&   r   r   r   rj     s    

zDispatcher.dispatchc                 g   st   t |}| jD ]`}t ||kr@ttt||r@| j| }|V  qt |rt|d rt||r| j| }|V  qd S )N)r\   r   r,   mapr#   r-   r
   r   )r1   r&   nr9   resultr   r   r   rl   4  s    



zDispatcher.dispatch_iterc                 C   s   t dt | j| S )z Deterimine appropriate implementation for this type signature
        .. deprecated:: 0.4.4
            Use ``dispatch(*types)`` instead
        z-resolve() is deprecated, use dispatch(*types))r   r   rj   rq   r   r   r   resolve@  s    zDispatcher.resolvec                 C   s   | j | jdS )Nr   r-   rw   rb   r   r   r   __getstate__J  s    zDispatcher.__getstate__c                 C   s*   |d | _ |d | _t| j| _i | _d S )Nr   r-   )r   r-   r   r.   r/   )r1   dr   r   r   __setstate__N  s    

zDispatcher.__setstate__c                 C   s   d| j  g}| jr|| j g }| jd d d D ]\}| j| }|jrdt| }|dt| d 7 }||j 7 }|| q2|t| q2|r|dd	|  d	|S )	NzMultiply dispatched method: %srr   zInputs: <%s>
-
zOther signatures:
    z
    

)
r   r0   r]   r   r-   r   r   r\   striprZ   )r1   Zdocsotherr(   r4   sr   r   r   r   T  s    
zDispatcher.__doc__c                 G   s   | j tt| jS r+   )rj   rs   rT   r   )r1   rm   r   r   r   _helpk  s    zDispatcher._helpc                 O   s   t | j|  dS )z: Print docstring for the function corresponding to inputs N)printr   r1   rm   r6   r   r   r   helpn  s    zDispatcher.helpc                 G   s$   | j tt| }|stdt|S )NzNo function found)rj   rs   rT   r[   r   )r1   rm   r4   r   r   r   _sourcer  s    zDispatcher._sourcec                 O   s   t | j|  dS )z< Print source code for the function corresponding to inputs N)r   r   r   r   r   r   r   x  s    zDispatcher.source)N)r   r   r   r   	__slots__r2   r8   classmethodr@   rP   r3   propertyr   r   ra   rn   rp   __repr__rj   rl   rv   rx   rz   r   r   r   r   r   r   r   r   r   _   s4   


?


c                 C   s    dt |  }|t |  }|S )Nz
File: %s

)r;   getsourcefile	getsource)r4   r   r   r   r   r   }  s    c                   @   s0   e Zd ZdZdZedd Zdd Zdd Zd	S )
r   zO Dispatch methods based on type signature
    See Also:
        Dispatcher
    objr?   c                 C   s,   t tdr(t|}t|j dd S d S )Nr9   r   )r:   r;   r9   itlislicer<   r=   r>   r   r   r   r@     s    

z MethodDispatcher.get_func_paramsc                 C   s   || _ || _| S r+   r   )r1   instanceownerr   r   r   __get__  s    zMethodDispatcher.__get__c                 O   sH   t dd |D }| j| }|s6td| jt|f || jf||S )Nc                 S   s   g | ]}t |qS r   rd   re   r   r   r   rg     s     z-MethodDispatcher.__call__.<locals>.<listcomp>rh   )rM   rj   rk   r   r   r   )r1   rm   r6   r&   r4   r   r   r   rn     s    
zMethodDispatcher.__call__N)	r   r   r   r   r   r   r@   r   rn   r   r   r   r   r     s   
c                 C   s   d dd | D S )zb String representation of type signature
    >>> str_signature((int, float))
    'int, float'
    rS   c                 s   s   | ]}|j V  qd S r+   )r   )rE   r?   r   r   r   rI     s     z str_signature.<locals>.<genexpr>rZ   )r(   r   r   r   r     s    c                    sb   d  }|d7 }|D ]$}|dd dd |D  d 7 }q|d7 }|d	  fd
d|D 7 }|S )z! The text for ambiguity warnings z.
Ambiguities exist in dispatched function %s

z;The following signatures may result in ambiguous behavior:
	rS   c                 s   s   | ]}d t | d V  qdS )[]N)r   rE   r   r   r   r   rI     s     zwarning_text.<locals>.<genexpr>r|   z,

Consider making the following additions:

r}   c                    s$   g | ]}d t t| d   qS )z
@dispatch(z)
def %s(...))r   r   r   ro   r   r   rg     s   z warning_text.<locals>.<listcomp>r   )r   rc   textpairr   ro   r   r     s    
)warningsr   r;   conflictr   r   r   r   utilsr   Zvariadicr	   r
   	itertoolsr   __all__rk   r   r   r   r   r   r   objectr   r   r   r   r   r   r   r   r   <module>   s4   
     	'   