U
    luf                     @   s^   d Z dZddlmZ ddlZG dd dZG dd deZG d	d
 d
eZdd Zdd Z	dS )ai  Decorators for running functions with context/sockets.

.. versionadded:: 15.3

Like using Contexts and Sockets as context managers, but with decorator syntax.
Context and sockets are closed at the end of the function.

For example::

    from zmq.decorators import context, socket
    
    @context()
    @socket(zmq.PUSH)
    def work(ctx, push):
        ...
)contextsocket    wrapsNc                   @   s2   e Zd ZdZdddZdd Zdd Zd	d
 ZdS )
_DecoratorzThe mini decorator factoryNc                 C   s
   || _ d S N_target)selftarget r   2/tmp/pip-unpacked-wheel-h6ekxre8/zmq/decorators.py__init__"   s    z_Decorator.__init__c                    s(   j  \  fdd}|S )a  
        The main logic of decorator

        Here is how those arguments works::

            @out_decorator(*dec_args, *dec_kwargs)
            def func(*wrap_args, **wrap_kwargs):
                ...

        And in the ``wrapper``, we simply create ``self.target`` instance via
        ``with``::

            target = self.get_target(*args, **kwargs)
            with target(*dec_args, **dec_kwargs) as obj:
                ...

        c                    s    t   fdd}|S )Nc               
      sx   j | |}| X}r.|kr.||< n*rN|krNtdjn
| |f } | |W  5 Q R  S Q R X d S )Nz*{}() got multiple values for argument '{}')
get_target	TypeErrorformat__name__)argskwargsr   obj)dec_args
dec_kwargsfunckw_namer
   r   r   wrapper<   s    
 
z7_Decorator.__call__.<locals>.decorator.<locals>.wrapperr   )r   r   r   r   r   r
   )r   r   	decorator;   s    z&_Decorator.__call__.<locals>.decorator)process_decorator_args)r
   r   r   r   r   r   r   __call__%   s     
z_Decorator.__call__c                 O   s   | j S )zWReturn the target function

        Allows modifying args/kwargs to be passed.
        r   )r
   r   r   r   r   r   r   R   s    z_Decorator.get_targetc                 O   sX   d}t |dtr |d}n.t|dkrNt |d trN|d }|dd }|||fS )zProcess args passed to the decorator.

        args not consumed by the decorator will be passed to the target factory
        (Context/Socket constructor).
        Nname   r   )
isinstancegetstrpoplenr
   r   r   r   r   r   r   r   Y   s    z!_Decorator.process_decorator_args)N)r   
__module____qualname____doc__r   r   r   r   r   r   r   r   r      s
   
-r   c                       s    e Zd ZdZ fddZ  ZS )_ContextDecoratorzDecorator subclass for Contextsc                    s   t  tj d S r   )superr   zmqContext)r
   	__class__r   r   r   m   s    z_ContextDecorator.__init__)r   r'   r(   r)   r   __classcell__r   r   r.   r   r*   j   s   r*   c                       s0   e Zd ZdZ fddZdd Zdd Z  ZS )_SocketDecoratorzJDecorator subclass for sockets

    Gets the context from other args.
    c                    s,   t  j||\}}}|dd| _|||fS )z$Also grab context_name out of kwargscontext_namer   )r+   r   r$   r2   r&   r.   r   r   r   w   s    z'_SocketDecorator.process_decorator_argsc                 O   s   | j ||}|jS )z$Get context, based on call-time args)_get_contextr   )r
   r   r   r   r   r   r   r   }   s    z_SocketDecorator.get_targetc                 O   sL   | j |kr$|| j  }t|tjr$|S |D ]}t|tjr(|  S q(tj S )a  
        Find the ``zmq.Context`` from ``args`` and ``kwargs`` at call time.

        First, if there is an keyword argument named ``context`` and it is a
        ``zmq.Context`` instance , we will take it.

        Second, we check all the ``args``, take the first ``zmq.Context``
        instance.

        Finally, we will provide default Context -- ``zmq.Context.instance``

        :return: a ``zmq.Context`` instance
        )r2   r!   r,   r-   instance)r
   r   r   ctxargr   r   r   r3      s    


z_SocketDecorator._get_context)r   r'   r(   r)   r   r   r3   r0   r   r   r.   r   r1   q   s   r1   c                  O   s   t  | |S )zDecorator for adding a Context to a function.

    Usage::

        @context()
        def foo(ctx):
            ...

    .. versionadded:: 15.3

    :param str name: the keyword argument passed to decorated function
    )r*   r   r   r   r   r   r      s    r   c                  O   s   t  | |S )aS  Decorator for adding a socket to a function.

    Usage::

        @socket(zmq.PUSH)
        def foo(push):
            ...

    .. versionadded:: 15.3

    :param str name: the keyword argument passed to decorated function
    :param str context_name: the keyword only argument to identify context
                             object
    )r1   r7   r   r   r   r      s    r   )
r)   __all__	functoolsr   r,   r   r*   r1   r   r   r   r   r   r   <module>   s   K,