
    Efo3                         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	  G d de
      Z G d d	ej                        Z e       Z G d
 de      Z G d de      Z G d de      Zd Zd Zd Zd Zy)a	  `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`.
    )absolute_importdivisionprint_functionwith_statementN   )raise_exc_infoc                       e Zd Zy)StackContextInconsistentErrorN)__name__
__module____qualname__     I/usr/lib/python3/dist-packages/zmq/eventloop/minitornado/stack_context.pyr
   r
   N   s    r   r
   c                       e Zd Zd Zy)_Statec                 &    t               d f| _        y N)tuplecontextsselfs    r   __init__z_State.__init__S   s    $r   N)r   r   r   r   r   r   r   r   r   R   s    (r   r   c                   4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	StackContexta  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                 .    || _         g | _        d| _        y NT)context_factoryr   active)r   r   s     r   r   zStackContext.__init__l   s    .r   c                     d| _         y NFr   r   s    r   _deactivatezStackContext._deactivateq   	    r   c                 z    | j                         }| j                  j                  |       |j                          y r   )r   r   append	__enter__)r   contexts     r   enterzStackContext.enteru   s.    &&(W%r   c                 ^    | j                   j                         }|j                  |||       y r   )r   pop__exit__)r   typevalue	tracebackr(   s        r   exitzStackContext.exitz   s&    --##%ui0r   c                     t         j                  | _        | j                  d   | fz   | f| _        | j                  t         _        	 | j	                          | j
                  S #  | j                  t         _         xY wNr   )_stater   old_contextsnew_contextsr)   r#   r   s    r   r'   zStackContext.__enter__   sm    "OO!..q1TG;TB++	JJL
 		"//FOs   A" "A:c                 J   	 | j                  |||       t        j                  }| j                  t        _        || j                  urt        d      d | _        y # t        j                  }| j                  t        _        || j                  urt        d      d | _        w xY wNzWstack_context inconsistency (may be caused by yield within a "with StackContext" block))r0   r3   r   r4   r5   r
   r   r-   r.   r/   final_contextss        r   r,   zStackContext.__exit__   s    	%IIdE9-#__N"//FO T%6%663:; ;
 !%D $__N"//FO T%6%663:; ;
 !%Ds   A AB"N)
r   r   r   __doc__r   r#   r)   r0   r'   r,   r   r   r   r   r   X   s%    &

1 %r   r   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)ExceptionStackContextaA  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                      || _         d| _        y r   )exception_handlerr   )r   r>   s     r   r   zExceptionStackContext.__init__   s    !2r   c                     d| _         y r!   r"   r   s    r   r#   z!ExceptionStackContext._deactivate   r$   r   c                 .    || j                  |||      S y r   )r>   r   r-   r.   r/   s       r   r0   zExceptionStackContext.exit   s"    ))$yAA r   c                     t         j                  | _        | j                  d   | f| _        | j                  t         _        | j                  S r2   )r3   r   r4   r5   r#   r   s    r   r'   zExceptionStackContext.__enter__   s?    "OO!..q148++r   c                    	 |X| j                  |||      t        j                  }| j                  t        _        || j                  urt        d      d | _        S 	 t        j                  }| j                  t        _        || j                  urt        d      d | _        y # t        j                  }| j                  t        _        || j                  urt        d      d | _        w xY wr7   )r>   r3   r   r4   r5   r
   r8   s        r   r,   zExceptionStackContext.__exit__   s    	%--dE9E#__N"//FOT%6%663:; ;
 !%D   $__N"//FOT%6%663:; ;
 !%D $__N"//FOT%6%663:; ;
 !%Ds   B# #AC*N)	r   r   r   r:   r   r#   r0   r'   r,   r   r   r   r<   r<      s!    B %r   r<   c                       e Zd ZdZd Zd Zy)NullContextzResets 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                 X    t         j                  | _        t               d ft         _        y r   )r3   r   r4   r   r   s    r   r'   zNullContext.__enter__   s    "OO 7D/r   c                 .    | j                   t        _        y r   )r4   r3   r   rA   s       r   r,   zNullContext.__exit__   s    ++r   N)r   r   r   r:   r'   r,   r   r   r   rE   rE      s    *,r   rE   c                 \   t        | d   D cg c]  }|j                  s| c}      }| d   }|*|j                  s|j                  d   }||j                  s|}|F|j                  d   }|0|j                  rn#|j                  |_        |j                  d   }|0|}|F||fS c c}w )z*Remove deactivated handlers from the chainr   r   )r   r   r4   )r   hstack_contextsheadctxparents         r   _remove_deactivatedrN      s     x{?!ahhA?@N A;D

4;;  # 
4;; C
/!!!$ }}%22C((+F	    / D!!) @s
   B)B)c                       t         d      r S t        j                  gd   d   sd   d   s fd}d|_        |S  fd}d|_        |S )a
  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).
    _wrappedr   r   c                      	 t         j                  }d   t         _         | i ||t         _        S # t         _        w xY wr2   )r3   r   )argskwargscurrent_statecap_contextsfns      r   null_wrapperzwrap.<locals>.null_wrapper  s8    0 &".q/4*6*"/-s	   %4 ATc                     d }	 t         j                  }t        d         xd<   }|t         _        d}d }d}|d   }|D ]  }		 |	j                          |dz  } |		  | i |}|t        ||      }n5|dkD  r |dz  }||   }
	  |
j                  |  |dkD  r d }|t        ||      }|dk7  rt        |       |t         _        |S #  t	        j
                         }|	j                  d   }Y xY w#  t	        j
                         }|d   }Y xY w#  t	        j
                         }|
j                  d   }Y xY w# t         _        w xY w)Nr   NNNr   )
r3   r   rN   r)   sysexc_infor4   _handle_exceptionr0   r   )rR   rS   retrT   r   exctoplast_ctxstackncrU   rV   s              r   wrappedzwrap.<locals>.wrapped  s   >	,"OOM *=\!_)MMLOh 'FO %CC HQKE  ,,GGIMH, {&d-f-C 'S1 lMHhA l C ?+C5C ((s#+FO
Q,,,.C..+C&,,.C"1+C!llnnnQ/ ,FOsY   >D; CD; C1 &D; D D;  D; %C.,D; 1DD; %D86D; ;E)hasattrr3   r   rP   )rV   rW   rd   rU   s   `  @r   wraprf      sh     
zWR,	 OO$L?1l1oa&8	0 !%AF GNr   c                     | $	  | j                   | rd}| j                  d   } | $|S #  t        j                         }Y ,xY w)NrY   r   )r0   rZ   r[   r4   )tailr^   s     r   r\   r\   `  sR    

	!tyy#(   # 
 J	!,,.Cs	   ) Ac                 @    | 5   |       cddd       S # 1 sw Y   yxY w)a  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
    Nr   )r(   funcs     r   run_with_stack_contextrk   m  s!    , 
 v  s   )r:   
__future__r   r   r   r   rZ   	threadingutilr   	Exceptionr
   localr   r3   objectr   r<   rE   rN   rf   r\   rk   r   r   r   <module>rr      s   "3j Q P 
   	I 	(Y__ ( 
I%6 I%X-%F -%`,& ,"4`F
r   