From: Ben Darnell Date: Mon, 3 Sep 2012 19:10:57 +0000 (-0700) Subject: Add magic for yielding futures. X-Git-Tag: v3.0.0~263^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0cc0df770b72177a6df289f065dd4cec260779b5;p=thirdparty%2Ftornado.git Add magic for yielding futures. Introduce IOLoop.current() as a thread-local counterpart to IOLoop.instance(). gen.engine now recognizes Futures directly. --- diff --git a/tornado/gen.py b/tornado/gen.py index bc0f935dc..51d64a3aa 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -69,6 +69,7 @@ import operator import sys import types +from tornado.concurrent import Future from tornado.ioloop import IOLoop from tornado.stack_context import ExceptionStackContext @@ -251,7 +252,7 @@ class Task(YieldPoint): class YieldFuture(YieldPoint): def __init__(self, future, io_loop=None): self.future = future - self.io_loop = io_loop or IOLoop.instance() + self.io_loop = io_loop or IOLoop.current() def start(self, runner): self.runner = runner @@ -379,6 +380,9 @@ class Runner(object): raise if isinstance(yielded, list): yielded = Multi(yielded) + if isinstance(yielded, Future): + # TODO: lists of futures + yielded = YieldFuture(yielded) if isinstance(yielded, YieldPoint): self.yield_point = yielded try: diff --git a/tornado/ioloop.py b/tornado/ioloop.py index 745bdf898..724472092 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -114,6 +114,8 @@ class IOLoop(object): # Global lock for creating global IOLoop instance _instance_lock = threading.Lock() + _current = threading.local() + def __init__(self, impl=None): self._impl = impl or _poll() if hasattr(self._impl, 'fileno'): @@ -173,6 +175,20 @@ class IOLoop(object): assert not IOLoop.initialized() IOLoop._instance = self + @staticmethod + def current(): + current = getattr(IOLoop._current, "instance", None) + if current is None: + raise ValueError("no current IOLoop") + return current + + def make_current(self): + IOLoop._current.instance = self + + def clear_current(self): + assert IOLoop._current.instance is self + IOLoop._current.instance = None + def close(self, all_fds=False): """Closes the IOLoop, freeing any resources used. @@ -264,6 +280,8 @@ class IOLoop(object): if self._stopped: self._stopped = False return + old_current = getattr(IOLoop._current, "instance", None) + IOLoop._current.instance = self self._thread_ident = thread.get_ident() self._running = True while True: @@ -346,6 +364,7 @@ class IOLoop(object): self._stopped = False if self._blocking_signal_threshold is not None: signal.setitimer(signal.ITIMER_REAL, 0, 0) + IOLoop._current.instance = old_current def stop(self): """Stop the loop after the current event loop iteration is complete. diff --git a/tornado/test/concurrent_test.py b/tornado/test/concurrent_test.py index 2cf371894..5267358ad 100644 --- a/tornado/test/concurrent_test.py +++ b/tornado/test/concurrent_test.py @@ -161,8 +161,7 @@ class ClientTestMixin(object): def test_generator(self): @gen.engine def f(): - result = yield gen.YieldFuture(self.client.capitalize("hello"), - io_loop=self.io_loop) + result = yield self.client.capitalize("hello") self.assertEqual(result, "HELLO") self.stop() f() @@ -172,8 +171,7 @@ class ClientTestMixin(object): @gen.engine def f(): with self.assertRaisesRegexp(CapError, "already capitalized"): - yield gen.YieldFuture(self.client.capitalize("HELLO"), - io_loop=self.io_loop) + yield self.client.capitalize("HELLO") self.stop() f() self.wait() diff --git a/tornado/testing.py b/tornado/testing.py index c597e3a77..4e2bc2efb 100644 --- a/tornado/testing.py +++ b/tornado/testing.py @@ -124,8 +124,10 @@ class AsyncTestCase(unittest.TestCase): def setUp(self): super(AsyncTestCase, self).setUp() self.io_loop = self.get_new_ioloop() + self.io_loop.make_current() def tearDown(self): + self.io_loop.clear_current() if (not IOLoop.initialized() or self.io_loop is not IOLoop.instance()): # Try to clean up any file descriptors left open in the ioloop.