a
    ReO                     @   s  d dl Z d dlZd dlZd dlZddlmZ d dlZd dlZd dlZddlm	Z	m
Z
mZmZmZ g dZe jde jd f Ze je je je jge je je jf f Zdd	 Zd
d Zdd Zdd Zdd Zee
e eeje eee eee dd Zejdd Zejdd Zdd Zd;eeee je j dddZ d<ddZ!d d! Z"d"d# Z#d=dd$d%d&Z$d'd( Z%d>d*d+Z&G d,d- d-Z'd.d/ Z(d0d1 Z)d2d3 Z*d4d5 Z+d)dd6d7d8Z,d)dd6d9d:Z-dS )?    N   )_uarray)BackendNotImplementedError	_Function_SkipBackendContext_SetBackendContext_BackendState)set_backendset_global_backendskip_backendregister_backenddetermine_backenddetermine_backend_multiclear_backendscreate_multimethodgenerate_multimethodr   r   Dispatchablewrap_single_convertorwrap_single_convertor_instanceall_of_typemark_as	set_state	get_statereset_stater   r   r   .)r   .c           	   
   C   s   dd l }zF|| }|d}|}|D ]}t||}q&|d urJt||}|W S  ttfy } zddlm	} ||W Y d }~n
d }~0 0 d S )Nr   .)UnpicklingError)
	importlibimport_modulesplitgetattrtypes
MethodTypeImportErrorAttributeErrorpickler   )	mod_nameqnameself_r   modulefuncqer    r,   O/var/www/sunrise/env/lib/python3.9/site-packages/scipy/_lib/_uarray/_backend.pyunpickle_function0   s    

r.   c                 C   sz   t | dd }t | dd }t | dd }zt|||}W n tjyL   d }Y n0 || urltd|  d| t|||ffS )N
__module____qualname____self__zCan't pickle z: it's not the same object as )r   r.   r$   r   PicklingError)r)   r%   r&   r'   testr,   r,   r-   pickle_functionD   s    
r4   c                 C   s   t jj|  fS N)r   r   	_unpickle_pickle)stater,   r,   r-   pickle_stateV   s    r9   c                 C   s   t |  fS r5   )r   r7   ctxr,   r,   r-   pickle_set_backend_contextZ   s    r<   c                 C   s   t |  fS r5   )r   r7   r:   r,   r,   r-   pickle_skip_backend_context^   s    r=   c                   C   s   t  S )z
    Returns an opaque object containing the current state of all the backends.

    Can be used for synchronization between threads/processes.

    See Also
    --------
    set_state
        Sets the state returned by this function.
    )r   r   r,   r,   r,   r-   r   h   s    r   c                   c   s4   t t  dV  W d   n1 s&0    Y  dS )z
    Returns a context manager that resets all state once exited.

    See Also
    --------
    set_state
        Context manager that sets the backend state.
    get_state
        Gets a state to be set by this context manager.
    N)r   r   r,   r,   r,   r-   r   v   s    r   c              
   c   s:   t  }t|  zdV  W t|d nt|d 0 dS )z
    A context manager that sets the state of the backends to one returned by :obj:`get_state`.

    See Also
    --------
    get_state
        Gets a state to be set by this context manager.
    NT)r   r   r   )r8   	old_stater,   r,   r-   r      s
    

r   c                     s    fdd}|S )au  
    Creates a decorator for generating multimethods.

    This function creates a decorator that can be used with an argument
    extractor in order to generate a multimethod. Other than for the
    argument extractor, all arguments are passed on to
    :obj:`generate_multimethod`.

    See Also
    --------
    generate_multimethod
        Generates a multimethod.
    c                    s   t | g R i S r5   )r   )aargskwargsr,   r-   wrapper   s    z#create_multimethod.<locals>.wrapperr,   )rA   rB   rC   r,   r@   r-   r      s    r   )argument_extractorargument_replacerdomaindefaultc                 C   s,   t | \}}}t| |||||}t|| S )a  
    Generates a multimethod.

    Parameters
    ----------
    argument_extractor : ArgumentExtractorType
        A callable which extracts the dispatchable arguments. Extracted arguments
        should be marked by the :obj:`Dispatchable` class. It has the same signature
        as the desired multimethod.
    argument_replacer : ArgumentReplacerType
        A callable with the signature (args, kwargs, dispatchables), which should also
        return an (args, kwargs) pair with the dispatchables replaced inside the args/kwargs.
    domain : str
        A string value indicating the domain of this multimethod.
    default: Optional[Callable], optional
        The default implementation of this multimethod, where ``None`` (the default) specifies
        there is no default implementation.

    Examples
    --------
    In this example, ``a`` is to be dispatched over, so we return it, while marking it as an ``int``.
    The trailing comma is needed because the args have to be returned as an iterable.

    >>> def override_me(a, b):
    ...   return Dispatchable(a, int),

    Next, we define the argument replacer that replaces the dispatchables inside args/kwargs with the
    supplied ones.

    >>> def override_replacer(args, kwargs, dispatchables):
    ...     return (dispatchables[0], args[1]), {}

    Next, we define the multimethod.

    >>> overridden_me = generate_multimethod(
    ...     override_me, override_replacer, "ua_examples"
    ... )

    Notice that there's no default implementation, unless you supply one.

    >>> overridden_me(1, "a")
    Traceback (most recent call last):
        ...
    uarray.BackendNotImplementedError: ...

    >>> overridden_me2 = generate_multimethod(
    ...     override_me, override_replacer, "ua_examples", default=lambda x, y: (x, y)
    ... )
    >>> overridden_me2(1, "a")
    (1, 'a')

    See Also
    --------
    uarray
        See the module documentation for how to override the method by creating backends.
    )get_defaultsr   	functoolsupdate_wrapper)rD   rE   rF   rG   kw_defaultsarg_defaultsoptsZua_funcr,   r,   r-   r      s    >	r   Fc                 C   s\   z| j d||f W S  ty*   i | _ Y n ty:   Y n0 t| ||}|| j d||f< |S )a  
    A context manager that sets the preferred backend.

    Parameters
    ----------
    backend
        The backend to set.
    coerce
        Whether or not to coerce to a specific backend's types. Implies ``only``.
    only
        Whether or not this should be the last backend to try.

    See Also
    --------
    skip_backend: A context manager that allows skipping of backends.
    set_global_backend: Set a single, global backend for a domain.
    set)__ua_cache__r#   KeyErrorr   )backendcoerceonlyr;   r,   r,   r-   r	      s    
r	   c                 C   sL   z| j d W S  ty$   i | _ Y n ty4   Y n0 t| }|| j d< |S )a  
    A context manager that allows one to skip a given backend from processing
    entirely. This allows one to use another backend's code in a library that
    is also a consumer of the same backend.

    Parameters
    ----------
    backend
        The backend to skip.

    See Also
    --------
    set_backend: A context manager that allows setting of backends.
    set_global_backend: Set a single, global backend for a domain.
    skip)rO   r#   rP   r   )rQ   r;   r,   r,   r-   r     s    

r   c                 C   s~   t | }i }g }t }|j D ]L\}}|jt jjurB|j||< |jt jj	t jj
fv rd||j || q"|t||fS r5   )inspect	signaturerN   
parametersitemsrG   	ParameteremptykindPOSITIONAL_ONLYPOSITIONAL_OR_KEYWORDappendaddtuple)fsigrK   rL   rM   kvr,   r,   r-   rH   2  s    

rH   )try_lastc                C   s   t | ||| dS )ae  
    This utility method replaces the default backend for permanent use. It
    will be tried in the list of backends automatically, unless the
    ``only`` flag is set on a backend. This will be the first tried
    backend outside the :obj:`set_backend` context manager.

    Note that this method is not thread-safe.

    .. warning::
        We caution library authors against using this function in
        their code. We do *not* support this use-case. This function
        is meant to be used only by users themselves, or by a reference
        implementation, if one exists.

    Parameters
    ----------
    backend
        The backend to register.
    coerce : bool
        Whether to coerce input types when trying this backend.
    only : bool
        If ``True``, no more backends will be tried if this fails.
        Implied by ``coerce=True``.
    try_last : bool
        If ``True``, the global backend is tried after registered backends.

    See Also
    --------
    set_backend: A context manager that allows setting of backends.
    skip_backend: A context manager that allows skipping of backends.
    N)r   r
   )rQ   rR   rS   re   r,   r,   r-   r
   D  s     r
   c                 C   s   t |  dS )a0  
    This utility method sets registers backend for permanent use. It
    will be tried in the list of backends automatically, unless the
    ``only`` flag is set on a backend.

    Note that this method is not thread-safe.

    Parameters
    ----------
    backend
        The backend to register.
    N)r   r   )rQ   r,   r,   r-   r   g  s    r   Tc                 C   s   t | || dS )al  
    This utility method clears registered backends.

    .. warning::
        We caution library authors against using this function in
        their code. We do *not* support this use-case. This function
        is meant to be used only by users themselves.

    .. warning::
        Do NOT use this method inside a multimethod call, or the
        program is likely to crash.

    Parameters
    ----------
    domain : Optional[str]
        The domain for which to de-register backends. ``None`` means
        de-register for all domains.
    registered : bool
        Whether or not to clear registered backends. See :obj:`register_backend`.
    globals : bool
        Whether or not to clear global backends. See :obj:`set_global_backend`.

    See Also
    --------
    register_backend : Register a backend globally.
    set_global_backend : Set a global backend.
    N)r   r   )rF   Z
registeredglobalsr,   r,   r-   r   w  s    r   c                   @   s.   e Zd ZdZd
ddZdd Zdd ZeZd	S )r   a  
    A utility class which marks an argument with a specific dispatch type.


    Attributes
    ----------
    value
        The value of the Dispatchable.

    type
        The type of the Dispatchable.

    Examples
    --------
    >>> x = Dispatchable(1, str)
    >>> x
    <Dispatchable: type=<class 'str'>, value=1>

    See Also
    --------
    all_of_type
        Marks all unmarked parameters of a function.

    mark_as
        Allows one to create a utility function to mark as a given type.
    Tc                 C   s   || _ || _|| _d S r5   )valuetype	coercible)selfrg   dispatch_typeri   r,   r,   r-   __init__  s    zDispatchable.__init__c                 C   s   | j | jf| S r5   )rh   rg   )rj   indexr,   r,   r-   __getitem__  s    zDispatchable.__getitem__c                 C   s   d t| j| j| jS )Nz<{}: type={!r}, value={!r}>)formatrh   __name__rg   )rj   r,   r,   r-   __str__  s    zDispatchable.__str__N)T)rp   r/   r0   __doc__rl   rn   rq   __repr__r,   r,   r,   r-   r     s
   
r   c                 C   s   t jt| dS )z
    Creates a utility function to mark something as a specific type.

    Examples
    --------
    >>> mark_int = mark_as(int)
    >>> mark_int(1)
    <Dispatchable: type=<class 'int'>, value=1>
    rk   )rI   partialr   rt   r,   r,   r-   r     s    
r   c                    s    fdd}|S )a  
    Marks all unmarked arguments as a given type.

    Examples
    --------
    >>> @all_of_type(str)
    ... def f(a, b):
    ...     return a, Dispatchable(b, int)
    >>> f('a', 1)
    (<Dispatchable: type=<class 'str'>, value='a'>, <Dispatchable: type=<class 'int'>, value=1>)
    c                    s   t   fdd}|S )Nc                     s$   | i |}t  fdd|D S )Nc                 3   s&   | ]}t |tst| n|V  qd S r5   
isinstancer   ).0argarg_typer,   r-   	<genexpr>  s   z<all_of_type.<locals>.outer.<locals>.inner.<locals>.<genexpr>)r`   )rA   rB   Zextracted_args)r{   r)   r,   r-   inner  s    z)all_of_type.<locals>.outer.<locals>.innerrI   wraps)r)   r}   rz   )r)   r-   outer  s    	zall_of_type.<locals>.outerr,   )r{   r   r,   rz   r-   r     s    r   c                    s   t   fdd}|S )
    Wraps a ``__ua_convert__`` defined for a single element to all elements.
    If any of them return ``NotImplemented``, the operation is assumed to be
    undefined.

    Accepts a signature of (value, type, coerce).
    c                    sB   g }| D ]4} |j |j|o|j}|tu r2t  S || q|S r5   rg   rh   ri   NotImplementedr^   )dispatchablesrR   	converteddcconvert_singler,   r-   __ua_convert__  s    z-wrap_single_convertor.<locals>.__ua_convert__r~   r   r   r,   r   r-   r     s    	r   c                    s   t   fdd}|S )r   c                    sD   g }|D ]6} | |j |j|o |j}|tu r4t  S || q|S r5   r   )rj   r   rR   r   r   r   r   r,   r-   r     s    z6wrap_single_convertor_instance.<locals>.__ua_convert__r~   r   r,   r   r-   r     s    	r   )rS   rR   c                C   s*   t | ||f}t|||}t|||dS )a	  Set the backend to the first active backend that supports ``value``

    This is useful for functions that call multimethods without any dispatchable
    arguments. You can use :func:`determine_backend` to ensure the same backend
    is used everywhere in a block of multimethod calls.

    Parameters
    ----------
    value
        The value being tested
    dispatch_type
        The dispatch type associated with ``value``, aka
        ":ref:`marking <MarkingGlossary>`".
    domain: string
        The domain to query for backends and set.
    coerce: bool
        Whether or not to allow coercion to the backend's types. Implies ``only``.
    only: bool
        Whether or not this should be the last backend to try.

    See Also
    --------
    set_backend: For when you know which backend to set

    Notes
    -----

    Support is determined by the ``__ua_convert__`` protocol. Backends not
    supporting the type must return ``NotImplemented`` from their
    ``__ua_convert__`` if they don't support input of that type.

    Examples
    --------

    Suppose we have two backends ``BackendA`` and ``BackendB`` each supporting
    different types, ``TypeA`` and ``TypeB``. Neither supporting the other type:

    >>> with ua.set_backend(ex.BackendA):
    ...     ex.call_multimethod(ex.TypeB(), ex.TypeB())
    Traceback (most recent call last):
        ...
    uarray.BackendNotImplementedError: ...

    Now consider a multimethod that creates a new object of ``TypeA``, or
    ``TypeB`` depending on the active backend.

    >>> with ua.set_backend(ex.BackendA), ua.set_backend(ex.BackendB):
    ...         res = ex.creation_multimethod()
    ...         ex.call_multimethod(res, ex.TypeA())
    Traceback (most recent call last):
        ...
    uarray.BackendNotImplementedError: ...

    ``res`` is an object of ``TypeB`` because ``BackendB`` is set in the
    innermost with statement. So, ``call_multimethod`` fails since the types
    don't match.

    Instead, we need to first find a backend suitable for all of our objects.

    >>> with ua.set_backend(ex.BackendA), ua.set_backend(ex.BackendB):
    ...     x = ex.TypeA()
    ...     with ua.determine_backend(x, "mark", domain="ua_examples"):
    ...         res = ex.creation_multimethod()
    ...         ex.call_multimethod(res, x)
    TypeA

    rR   rS   )r   r   r   r	   )rg   rk   rF   rS   rR   r   rQ   r,   r,   r-   r     s    Dr   c                   s   d|v r*| d t fdd| D } n"t| } tdd | D sLtdt|dkrftd| t|| |}t|||dS )	a	  Set a backend supporting all ``dispatchables``

    This is useful for functions that call multimethods without any dispatchable
    arguments. You can use :func:`determine_backend_multi` to ensure the same
    backend is used everywhere in a block of multimethod calls involving
    multiple arrays.

    Parameters
    ----------
    dispatchables: Sequence[Union[uarray.Dispatchable, Any]]
        The dispatchables that must be supported
    domain: string
        The domain to query for backends and set.
    coerce: bool
        Whether or not to allow coercion to the backend's types. Implies ``only``.
    only: bool
        Whether or not this should be the last backend to try.
    dispatch_type: Optional[Any]
        The default dispatch type associated with ``dispatchables``, aka
        ":ref:`marking <MarkingGlossary>`".

    See Also
    --------
    determine_backend: For a single dispatch value
    set_backend: For when you know which backend to set

    Notes
    -----

    Support is determined by the ``__ua_convert__`` protocol. Backends not
    supporting the type must return ``NotImplemented`` from their
    ``__ua_convert__`` if they don't support input of that type.

    Examples
    --------

    :func:`determine_backend` allows the backend to be set from a single
    object. :func:`determine_backend_multi` allows multiple objects to be
    checked simultaneously for support in the backend. Suppose we have a
    ``BackendAB`` which supports ``TypeA`` and ``TypeB`` in the same call,
    and a ``BackendBC`` that doesn't support ``TypeA``.

    >>> with ua.set_backend(ex.BackendAB), ua.set_backend(ex.BackendBC):
    ...     a, b = ex.TypeA(), ex.TypeB()
    ...     with ua.determine_backend_multi(
    ...         [ua.Dispatchable(a, "mark"), ua.Dispatchable(b, "mark")],
    ...         domain="ua_examples"
    ...     ):
    ...         res = ex.creation_multimethod()
    ...         ex.call_multimethod(res, a, b)
    TypeA

    This won't call ``BackendBC`` because it doesn't support ``TypeA``.

    We can also use leave out the ``ua.Dispatchable`` if we specify the
    default ``dispatch_type`` for the ``dispatchables`` argument.

    >>> with ua.set_backend(ex.BackendAB), ua.set_backend(ex.BackendBC):
    ...     a, b = ex.TypeA(), ex.TypeB()
    ...     with ua.determine_backend_multi(
    ...         [a, b], dispatch_type="mark", domain="ua_examples"
    ...     ):
    ...         res = ex.creation_multimethod()
    ...         ex.call_multimethod(res, a, b)
    TypeA

    rk   c                 3   s&   | ]}t |tr|nt| V  qd S r5   rv   rx   r   Z	disp_typer,   r-   r|     s   z*determine_backend_multi.<locals>.<genexpr>c                 s   s   | ]}t |tV  qd S r5   rv   r   r,   r,   r-   r|         z6dispatchables must be instances of uarray.Dispatchabler   z'Received unexpected keyword arguments: r   )popr`   all	TypeErrorlenr   r   r	   )r   rF   rS   rR   rB   rQ   r,   r   r-   r   h  s    F

r   )N)FF)FF)TF).typingr    rU   rI    r   copyregr$   
contextlibr   r   r   r   r   __all__CallableTupleZArgumentExtractorTypeDictZArgumentReplacerTyper.   r4   r9   r<   r=   r   contextmanagerr   r   r   strOptionalr   r	   r   rH   r
   r   r   r   r   r   r   r   r   r   r,   r,   r,   r-   <module>   sb    

 
K
#
,K