σ
¨[c           @` sψ   d  Z  d d l m Z m Z m Z d d l 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(   sm	  `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`.

.. deprecated:: 5.1

   The ``stack_context`` package is deprecated and will be removed in
   Tornado 6.0.
i    (   t   absolute_importt   divisiont   print_functionN(   t   raise_exc_infot   StackContextInconsistentErrorc           B` s   e  Z RS(    (   t   __name__t
   __module__(    (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   S   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(    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyt   __init__X   s    (   R   R   R   (    (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   W   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/   t  j d t  | |  _ g  |  _ t |  _ d  S(   Ns=   StackContext is deprecated and will be removed in Tornado 6.0(   t   warningst   warnt   DeprecationWarningt   context_factoryR
   t   Truet   active(   R   R   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   s   s
    			c         C` s   t  |  _ d  S(   N(   t   FalseR   (   R   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyt   _deactivatez   s    c         C` s*   |  j    } |  j j |  | j   d  S(   N(   R   R
   t   appendt	   __enter__(   R   t   context(    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyt   enter~   s    c         C` s&   |  j  j   } | j | | |  d  S(   N(   R
   t   popt   __exit__(   R   t   typet   valuet	   tracebackR   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyt   exit   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   (    (    s4   lib/python2.7/site-packages/tornado/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(    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR      s    	(	   R   R   t   __doc__R   R   R   R   R   R   (    (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   _   s   					t   ExceptionStackContextc           B` s>   e  Z d  Z e d  Z d   Z d   Z d   Z d   Z RS(   sB  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.

    .. versionadded:: 5.1

       The ``delay_warning`` argument can be used to delay the emission
       of DeprecationWarnings until an exception is caught by the
       ``ExceptionStackContext``, which facilitates certain transitional
       use cases.
    c         C` s;   | |  _  |  j  s% t j d t  n  | |  _ t |  _ d  S(   Ns=   StackContext is deprecated and will be removed in Tornado 6.0(   t   delay_warningR   R   R   t   exception_handlerR   R   (   R   R'   R&   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   Α   s    		
	c         C` s   t  |  _ d  S(   N(   R   R   (   R   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   Κ   s    c         C` s?   | d  k	 r; |  j r( t j d t  n  |  j | | |  Sd  S(   Ns=   StackContext is deprecated and will be removed in Tornado 6.0(   R	   R&   R   R   R   R'   (   R   R   R   R   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   Ν   s    	
c         C` s5   t  j |  _ |  j d |  f |  _ |  j t  _ |  j S(   Ni    (   R    R
   R!   R"   R   (   R   (    (    s4   lib/python2.7/site-packages/tornado/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#   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   ά   s    	(	   R   R   R$   R   R   R   R   R   R   (    (    (    s4   lib/python2.7/site-packages/tornado/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   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   τ   s    c         C` s   |  j  t _ d  S(   N(   R!   R    R
   (   R   R   R   R   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR   ψ   s    (   R   R   R$   R   R   (    (    (    s4   lib/python2.7/site-packages/tornado/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(    (    s4   lib/python2.7/site-packages/tornado/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(    s4   lib/python2.7/site-packages/tornado/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   (   R0   R1   t   retR2   R
   t   exct   topt   last_ctxt   stackt   nt   c(   R3   R4   (    s4   lib/python2.7/site-packages/tornado/stack_context.pyt   wrapped2  sP    		



	
N(   R	   t   hasattrR    R
   R   R/   (   R4   R5   R@   (    (   R3   R4   s4   lib/python2.7/site-packages/tornado/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   R6   R7   R!   (   t   tailR:   (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyR8   y  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(    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyt   run_with_stack_context  s    (   R$   t
   __future__R    R   R   R6   t	   threadingR   t   tornado.utilR   t	   ExceptionR   t   localR   R    t   objectR   R%   R(   R.   RB   R8   RE   (    (    (    s4   lib/python2.7/site-packages/tornado/stack_context.pyt   <module>H   s   	N@		c	