B
    k[4                 @   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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
isvariadicc               @   s   e Zd ZdZdS )MDNotImplementedErrorz- A NotImplementedError for multiple dispatch N)__name__
__module____qualname____doc__ r   r   :lib/python3.7/site-packages/multipledispatch/dispatcher.pyr   	   s   r   c             C   s   t t| j|t dS )aC   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   warning_textnamer   )Z
dispatcherr   r   r   r   ambiguity_warn   s    r   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   halt_ordering   s    r   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.N)r   r   )on_ambiguityr   r   r   restart_ordering'   s    r   c             c   s|   t |}t|}xf| D ]$}t||}|V  t|st|}qW yt|}W n& tk
rp   t|sftdV  Y nX dV  dS )aj  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typZmatchesr   r   r   variadic_signature_matches_iter2   s    

r"   c             C   s   |st tt| |S )N)r   allr"   )r   r   r   r   r   variadic_signature_matches\   s    r$   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 )+
DispatcheraW   Dispatch methods based on type signature

    Use ``dispatch`` to add implementations

    Examples
    --------

    >>> 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 )N)r   r   r&   r)   r(   )selfr   r)   r   r   r   __init__z   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 )N)add)func)kwargsr*   r   r   r   _   s    zDispatcher.register.<locals>._r   )r*   r   r.   r/   r   )r.   r*   r   r   register   s    zDispatcher.registerc             C   s"   t tdrt|}|j S d S )N	signature)hasattrinspectr1   
parametersvalues)clsr-   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 )N)ZkindZPOSITIONAL_ONLYZPOSITIONAL_OR_KEYWORD).0param)	Parameterr   r   	<genexpr>   s    z2Dispatcher.get_func_annotations.<locals>.<genexpr>c             s   s   | ]}|j V  qd S )N)Z
annotation)r8   r9   r   r   r   r;      s   c             3   s   | ]}| j k	V  qd S )N)empty)r8   ann)r:   r   r   r;      s    N)r7   r3   r:   tupler#   )r6   r-   Zparamsannotationsr   )r:   r   get_func_annotations   s    

zDispatcher.get_func_annotationsc       	      C   s*  |s|  |}|r|}tdd |D rJxt|D ]}| || q2W dS g }xt|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   q\|| q\W || jt|< | j  y| `W n tk
r$   Y nX dS )aL   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 )N)
isinstancer>   )r8   r!   r   r   r   r;      s    z!Dispatcher.add.<locals>.<genexpr>Nr   )startz, c             s   s&   | ]}t |tr|jnt|V  qd S )N)rA   typer   str)r8   cr   r   r   r;      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   )r@   anyr   r,   	enumeraterA   rC   listjoin	TypeErrorr   lenappendr	   r&   r>   r(   clearr'   AttributeError)	r*   r1   r-   r?   ZtypsZnew_signatureindexr!   Zstr_sigr   r   r   r,      s<    




zDispatcher.addc             C   s$   y| j S  tk
r   |  S X d S )N)r'   rN   reorder)r*   r   r   r   r      s    zDispatcher.orderingc             C   s,   t | j | _}t| j}|r(|| | |S )N)r   r&   r'   r   )r*   r   Zodambr   r   r   rP     s
    

zDispatcher.reorderc             O   s   t dd |D }y| j| }W nB tk
rb   | j| }|sTtd| jt|f || j|< Y nX y
|||S  tk
r   | j| }t	| x,|D ]$}y
|||S  tk
r   Y qX qW td| jt|f Y nX d S )Nc             S   s   g | ]}t |qS r   )rC   )r8   argr   r   r   
<listcomp>  s    z'Dispatcher.__call__.<locals>.<listcomp>z%Could not find signature for %s: <%s>zFMatching functions for %s: <%s> found, but none completed successfully)
r>   r(   KeyErrordispatchNotImplementedErrorr   str_signaturer   dispatch_iterr   )r*   argsr.   r   r-   r&   r   r   r   __call__
  s.    





zDispatcher.__call__c             C   s
   d| j  S )Nz<dispatched %s>)r   )r*   r   r   r   __str__(  s    zDispatcher.__str__c             G   s<   || j kr| j | S yt| j| S  tk
r6   dS X dS )aQ  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.

        >>> 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   rX   r   )r*   r   r   r   r   rU   ,  s    

zDispatcher.dispatchc             g   sx   t |}xj| jD ]`}t ||krBttt||rB| j| }|V  qt |rt|d rt||r| j| }|V  qW d S )N)rK   r   r#   mapr   r&   r
   r$   )r*   r   nr1   resultr   r   r   rX   J  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   rU   )r*   r   r   r   r   resolveV  s    zDispatcher.resolvec             C   s   | j | jdS )N)r   r&   )r   r&   )r*   r   r   r   __getstate__a  s    zDispatcher.__getstate__c             C   s,   |d | _ |d | _t| j| _t | _d S )Nr   r&   )r   r&   r   r'   dictr(   )r*   dr   r   r   __setstate__e  s    

zDispatcher.__setstate__c             C   s   d| j  g}| jr|| j g }xp| jd d d D ]\}| j| }|jrdt| }|dt| d 7 }||j 7 }|| q4|t| q4W |r|dd	|  d	|S )	NzMultiply dispatched method: %sr\   zInputs: <%s>
-
zOther signatures:
    z
    z

)
r   r)   rL   r   r&   r   rW   rK   striprI   )r*   Zdocsotherr    r-   sr   r   r   r   k  s    
zDispatcher.__doc__c             G   s   | j tt| jS )N)rU   r]   rC   r   )r*   rY   r   r   r   _help  s    zDispatcher._helpc             O   s   t | j|  dS )z: Print docstring for the function corresponding to inputs N)printrj   )r*   rY   r.   r   r   r   help  s    zDispatcher.helpc             G   s$   | j tt| }|stdt|S )NzNo function found)rU   r]   rC   rJ   source)r*   rY   r-   r   r   r   _source  s    zDispatcher._sourcec             O   s   t | j|  dS )z< Print source code for the function corresponding to inputs N)rk   rn   )r*   rY   r.   r   r   r   rm     s    zDispatcher.source)N)r   r   r   r   	__slots__r+   r0   classmethodr7   r@   r,   propertyr   r   rP   rZ   r[   __repr__rU   rX   r`   ra   rd   rj   rl   rn   rm   r   r   r   r   r%   b   s,   
Br%   c             C   s    dt |  }|t |  }|S )Nz
File: %s

)r3   ZgetsourcefileZ	getsource)r-   ri   r   r   r   rm     s    rm   c               @   s0   e Zd ZdZdZedd Zdd Zdd Zd	S )
MethodDispatcherzP Dispatch methods based on type signature

    See Also:
        Dispatcher
    )objr6   c             C   s,   t tdr(t|}t|j dd S d S )Nr1   r   )r2   r3   r1   itlislicer4   r5   )r6   r-   r    r   r   r   r7     s    

z MethodDispatcher.get_func_paramsc             C   s   || _ || _| S )N)rt   r6   )r*   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   )rC   )r8   rR   r   r   r   rS     s    z-MethodDispatcher.__call__.<locals>.<listcomp>z%Could not find signature for %s: <%s>)r>   rU   rV   r   rW   rt   )r*   rY   r.   r   r-   r   r   r   rZ     s    
zMethodDispatcher.__call__N)	r   r   r   r   ro   rp   r7   ry   rZ   r   r   r   r   rs     s
   rs   c             C   s   d dd | D S )zc String representation of type signature

    >>> str_signature((int, float))
    'int, float'
    z, c             s   s   | ]}|j V  qd S )N)r   )r8   r6   r   r   r   r;     s    z str_signature.<locals>.<genexpr>)rI   )r    r   r   r   rW     s    rW   c                sf   d  }|d7 }x,|D ]$}|dd dd |D  d 7 }qW |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:
	z, c             s   s   | ]}d t | d V  qdS )[]N)rW   )r8   ri   r   r   r   r;     s    zwarning_text.<locals>.<genexpr>rf   z,

Consider making the following additions:

z

c                s$   g | ]}d t t| d   qS )z
@dispatch(z)
def %s(...))rW   r   )r8   ri   )r   r   r   rS     s   z warning_text.<locals>.<listcomp>)rI   )r   rQ   textZpairr   )r   r   r     s    
"r   )warningsr   r3   Zconflictr   r   r   r   Zutilsr   Zvariadicr	   r
   	itertoolsru   rV   r   r   r   r   r"   r$   objectr%   rm   rs   rW   r   r   r   r   r   <module>   s$   	*  4	