
L]c           @ s   d  Z  d d l m Z m Z m Z m Z d d l Z d d l Z d d l m	 Z	 d e
 f d     YZ d e j f d	     YZ e   Z d
 e f d     YZ d e f d     YZ d e f d     YZ d   Z d   Z d   Z d   Z d S(   s	  `StackContext` allows applications to maintain threadlocal-like state
that follows execution as it moves to other execution contexts.

The motivating examples are to eliminate the need for explicit
``async_callback`` wrappers (as in `tornado.web.RequestHandler`), and to
allow some additional context to be kept for logging.

This is slightly magic, but it's an extension of the idea that an
exception handler is a kind of stack-local state and when that stack
is suspended and resumed in a new context that state needs to be
preserved.  `StackContext` shifts the burden of restoring that state
from each call site (e.g.  wrapping each `.AsyncHTTPClient` callback
in ``async_callback``) to the mechanisms that transfer control from
one context to another (e.g. `.AsyncHTTPClient` itself, `.IOLoop`,
thread pools, etc).

Example usage::

    @contextlib.contextmanager
    def die_on_error():
        try:
            yield
        except Exception:
            logging.error("exception in asynchronous operation",exc_info=True)
            sys.exit(1)

    with StackContext(die_on_error):
        # Any exception thrown here *or in callback and its descendants*
        # will cause the process to exit instead of spinning endlessly
        # in the ioloop.
        http_client.fetch(url, callback)
    ioloop.start()

Most applications shouldn't have to work with `StackContext` directly.
Here are a few rules of thumb for when it's necessary:

* If you're writing an asynchronous library that doesn't rely on a
  stack_context-aware library like `tornado.ioloop` or `tornado.iostream`
  (for example, if you're writing a thread pool), use
  `.stack_context.wrap()` before any asynchronous operations to capture the
  stack context from where the operation was started.

* If you're writing an asynchronous library that has some shared
  resources (such as a connection pool), create those shared resources
  within a ``with stack_context.NullContext():`` block.  This will prevent
  ``StackContexts`` from leaking from one request to another.

* If you want to write something like an exception handler that will
  persist across asynchronous calls, create a new `StackContext` (or
  `ExceptionStackContext`), and make your asynchronous calls in a ``with``
  block that references your `StackContext`.
i    (   t   absolute_importt   divisiont   print_functiont   with_statementNi   (   t   raise_exc_infot   StackContextInconsistentErrorc           B s   e  Z RS(    (   t   __name__t
   __module__(    (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR   N   s   t   _Statec           B s   e  Z d    Z RS(   c         C s   t    d  f |  _ d  S(   N(   t   tuplet   Nonet   contexts(   t   self(    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   __init__S   s    (   R   R   R   (    (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR   R   s   t   StackContextc           B sD   e  Z d  Z d   Z d   Z d   Z d   Z d   Z d   Z RS(   s  Establishes the given context as a StackContext that will be transferred.

    Note that the parameter is a callable that returns a context
    manager, not the context itself.  That is, where for a
    non-transferable context manager you would say::

      with my_context():

    StackContext takes the function itself rather than its result::

      with StackContext(my_context):

    The result of ``with StackContext() as cb:`` is a deactivation
    callback.  Run this callback when the StackContext is no longer
    needed to ensure that it is not propagated any further (note that
    deactivating a context does not affect any instances of that
    context that are currently pending).  This is an advanced feature
    and not necessary in most applications.
    c         C s   | |  _  g  |  _ t |  _ d  S(   N(   t   context_factoryR   t   Truet   active(   R   R   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR   l   s    		c         C s   t  |  _ d  S(   N(   t   FalseR   (   R   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   _deactivateq   s    c         C s*   |  j    } |  j j |  | j   d  S(   N(   R   R   t   appendt	   __enter__(   R   t   context(    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   enteru   s    c         C s&   |  j  j   } | j | | |  d  S(   N(   R   t   popt   __exit__(   R   t   typet   valuet	   tracebackR   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   exitz   s    c         C sc   t  j |  _ |  j d |  f |  f |  _ |  j t  _ y |  j   Wn |  j t  _   n X|  j S(   Ni    (   t   _stateR   t   old_contextst   new_contextsR   R   (   R   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    c         C s[   z |  j  | | |  Wd  t j } |  j t _ | |  j k	 rM t d   n  d  |  _ Xd  S(   NsW   stack_context inconsistency (may be caused by yield within a "with StackContext" block)(   R   R   R   R   R    R   R
   (   R   R   R   R   t   final_contexts(    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    	(	   R   R   t   __doc__R   R   R   R   R   R   (    (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR   X   s   					t   ExceptionStackContextc           B s;   e  Z d  Z d   Z d   Z d   Z d   Z d   Z RS(   sA  Specialization of StackContext for exception handling.

    The supplied ``exception_handler`` function will be called in the
    event of an uncaught exception in this context.  The semantics are
    similar to a try/finally clause, and intended use cases are to log
    an error, close a socket, or similar cleanup actions.  The
    ``exc_info`` triple ``(type, value, traceback)`` will be passed to the
    exception_handler function.

    If the exception handler returns true, the exception will be
    consumed and will not be propagated to other exception handlers.
    c         C s   | |  _  t |  _ d  S(   N(   t   exception_handlerR   R   (   R   R$   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    	c         C s   t  |  _ d  S(   N(   R   R   (   R   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    c         C s#   | d  k	 r |  j | | |  Sd  S(   N(   R
   R$   (   R   R   R   R   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    c         C s5   t  j |  _ |  j d |  f |  _ |  j t  _ |  j S(   Ni    (   R   R   R   R    R   (   R   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    c         C sg   z# | d  k	 r" |  j | | |  SWd  t j } |  j t _ | |  j k	 rY t d   n  d  |  _ Xd  S(   NsW   stack_context inconsistency (may be caused by yield within a "with StackContext" block)(   R
   R$   R   R   R   R    R   (   R   R   R   R   R!   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    	(   R   R   R"   R   R   R   R   R   (    (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR#      s   				t   NullContextc           B s    e  Z d  Z d   Z d   Z RS(   s   Resets the `StackContext`.

    Useful when creating a shared resource on demand (e.g. an
    `.AsyncHTTPClient`) where the stack that caused the creating is
    not relevant to future operations.
    c         C s"   t  j |  _ t   d  f t  _ d  S(   N(   R   R   R   R	   R
   (   R   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    c         C s   |  j  t _ d  S(   N(   R   R   R   (   R   R   R   R   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR      s    (   R   R   R"   R   R   (    (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR%      s   	c         C s   t  g  |  d D] } | j r | ^ q  } |  d } x' | d k	 r_ | j r_ | j d } q9 W| } x\ | d k	 r | j d } x6 | d k	 r | j r Pn  | j | _ | j d } q W| } qi W| | f S(   s*   Remove deactivated handlers from the chaini    i   N(   R	   R   R
   R   (   R   t   ht   stack_contextst   headt   ctxt   parent(    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   _remove_deactivated   s    ,
	
c          s    d k s t  d  r  St j g     d d rh   d d rh    f d   } t | _ | S   f d   } t | _ | S(   s
  Returns a callable object that will restore the current `StackContext`
    when executed.

    Use this whenever saving a callback to be executed later in a
    different execution context (either in a different thread or
    asynchronously in the same thread).
    t   _wrappedi    i   c           s8   z' t  j }   d t  _  |  |   SWd  | t  _ Xd  S(   Ni    (   R   R   (   t   argst   kwargst   current_state(   t   cap_contextst   fn(    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   null_wrapper  s
    	c           s  d  } zt j } t   d    d <} | t _ d } d  } d } | d } xI | D]A }	 y |	 j   | d 7} WqV t j   } |	 j d } qV XqV W| d  k r y  |  |   } Wq t j   } | d } q Xn  | d  k	 r t | |  } n x_ | d k rV| d 8} | | }
 y |
 j	 |   Wq t j   } |
 j d } Pq Xq Wd  } | d  k	 r{t | |  } n  | d k rt
 |  n  Wd  | t _ X| S(   Ni    i   (   NNN(   NNN(   R
   R   R   R+   R   t   syst   exc_infoR   t   _handle_exceptionR   R   (   R-   R.   t   retR/   R   t   exct   topt   last_ctxt   stackt   nt   c(   R0   R1   (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   wrapped  sP    		



	
N(   R
   t   hasattrR   R   R   R,   (   R1   R2   R=   (    (   R0   R1   sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   wrap   s    		C	c         C sV   xO |  d  k	 rQ y |  j |   r* d } n  Wn t j   } n X|  j d }  q W| S(   Ni   (   NNN(   R
   R   R3   R4   R   (   t   tailR7   (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyR5   `  s    c         C s   |   |   SWd QXd S(   s  Run a coroutine ``func`` in the given `StackContext`.

    It is not safe to have a ``yield`` statement within a ``with StackContext``
    block, so it is difficult to use stack context with `.gen.coroutine`.
    This helper function runs the function in the correct context while
    keeping the ``yield`` and ``with`` statements syntactically separate.

    Example::

        @gen.coroutine
        def incorrect():
            with StackContext(ctx):
                # ERROR: this will raise StackContextInconsistentError
                yield other_coroutine()

        @gen.coroutine
        def correct():
            yield run_with_stack_context(StackContext(ctx), other_coroutine)

    .. versionadded:: 3.1
    N(    (   R   t   func(    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   run_with_stack_contextm  s    (   R"   t
   __future__R    R   R   R   R3   t	   threadingt   utilR   t	   ExceptionR   t   localR   R   t   objectR   R#   R%   R+   R?   R5   RB   (    (    (    sF   lib/python2.7/site-packages/zmq/eventloop/minitornado/stack_context.pyt   <module>D   s   "	L0		c	