Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Simplify StackContext logic and behavior.

Previously, there was an optimization to avoid recreating contexts
that were already on the stack.  This optimization rarely mattered
(especially given the movement to run all callbacks through
IOLoop.add_callback), and sometimes caused surprising behavior as
other exception handlers could be inserted between stack contexts that
expected to be adjacent to each other or to the wrapped function.  Now
each wrapped function recreates its full stack of contexts, even if
some of those contexts were already on the stack.

This change allows a use of NullContext in testing.py to be
removed.
  • Loading branch information...
commit 2ded26610f9f3f7962129617bc2b60d1856708da 1 parent 69e4492
@bdarnell bdarnell authored
Showing with 9 additions and 31 deletions.
  1. +7 −25 tornado/stack_context.py
  2. +2 −6 tornado/testing.py
View
32 tornado/stack_context.py
@@ -70,7 +70,6 @@ def die_on_error():
import contextlib
import functools
-import itertools
import operator
import sys
import threading
@@ -198,31 +197,14 @@ def wrap(fn):
def wrapped(*args, **kwargs):
callback, contexts, args = args[0], args[1], args[2:]
- if contexts is _state.contexts:
- callback(*args, **kwargs)
- return
- if not _state.contexts:
- new_contexts = [cls(arg, active_cell)
- for (cls, arg, active_cell) in contexts
- if active_cell[0]]
- # If we're moving down the stack, _state.contexts is a prefix
- # of contexts. For each element of contexts not in that prefix,
- # create a new StackContext object.
- # If we're moving up the stack (or to an entirely different stack),
- # _state.contexts will have elements not in contexts. Use
- # NullContext to clear the state and then recreate from contexts.
- elif (len(_state.contexts) > len(contexts) or
- any(a[1] is not b[1]
- for a, b in itertools.izip(_state.contexts, contexts))):
- # contexts have been removed or changed, so start over
- new_contexts = ([NullContext()] +
- [cls(arg, active_cell)
- for (cls, arg, active_cell) in contexts
- if active_cell[0]])
+ if _state.contexts:
+ new_contexts = [NullContext()]
else:
- new_contexts = [cls(arg, active_cell)
- for (cls, arg, active_cell) in contexts[len(_state.contexts):]
- if active_cell[0]]
+ new_contexts = []
+ if contexts:
+ new_contexts.extend(cls(arg, active_cell)
+ for (cls, arg, active_cell) in contexts
+ if active_cell[0])
if len(new_contexts) > 1:
with _nested(*new_contexts):
callback(*args, **kwargs)
View
8 tornado/testing.py
@@ -36,7 +36,7 @@
netutil = None
SimpleAsyncHTTPClient = None
from tornado.log import gen_log
-from tornado.stack_context import StackContext, NullContext
+from tornado.stack_context import StackContext
from tornado.util import raise_exc_info
import contextlib
import logging
@@ -223,11 +223,7 @@ def timeout_func():
self.__timeout = self.io_loop.add_timeout(time.time() + timeout, timeout_func)
while True:
self.__running = True
- with NullContext():
- # Wipe out the StackContext that was established in
- # self.run() so that all callbacks executed inside the
- # IOLoop will re-run it.
- self.io_loop.start()
+ self.io_loop.start()
if (self.__failure is not None or
condition is None or condition()):
break
Please sign in to comment.
Something went wrong with that request. Please try again.