From 5de0928e6e3111e27fffb02c1de4c42e63b08555 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 17 Dec 2017 11:36:53 -0500 Subject: [PATCH] ioloop: Setting AsyncIOLoop as current also sets asyncio event loop This should eliminate the need for explicit asyncio manipulations from applications migrating to Tornado 5.0 --- tornado/ioloop.py | 10 ++++++++++ tornado/platform/asyncio.py | 20 ++++++++++++-------- tornado/test/asyncio_test.py | 1 - tornado/test/twisted_test.py | 8 -------- tornado/testing.py | 5 ----- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/tornado/ioloop.py b/tornado/ioloop.py index 5d359d06..0a1056fb 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -300,8 +300,18 @@ class IOLoop(Configurable): Intended primarily for use by test frameworks in between tests. """ + old = IOLoop._current.instance + if old is not None: + old._clear_current_hook() IOLoop._current.instance = None + def _clear_current_hook(self): + """Instance method called when an IOLoop ceases to be current. + + May be overridden by subclasses as a counterpart to make_current. + """ + pass + @classmethod def configurable_base(cls): return IOLoop diff --git a/tornado/platform/asyncio.py b/tornado/platform/asyncio.py index 5066fe4b..2a90099e 100644 --- a/tornado/platform/asyncio.py +++ b/tornado/platform/asyncio.py @@ -31,7 +31,6 @@ import asyncio class BaseAsyncIOLoop(IOLoop): def initialize(self, asyncio_loop, close_loop=False, **kwargs): - super(BaseAsyncIOLoop, self).initialize(**kwargs) self.asyncio_loop = asyncio_loop self.close_loop = close_loop # Maps fd to (fileobj, handler function) pair (as in IOLoop.add_handler) @@ -40,6 +39,7 @@ class BaseAsyncIOLoop(IOLoop): self.readers = set() self.writers = set() self.closing = False + super(BaseAsyncIOLoop, self).initialize(**kwargs) def close(self, all_fds=False): self.closing = True @@ -104,22 +104,15 @@ class BaseAsyncIOLoop(IOLoop): def start(self): old_current = IOLoop.current(instance=False) - try: - old_asyncio = asyncio.get_event_loop() - except RuntimeError: - old_asyncio = None try: self._setup_logging() self.make_current() - # This is automatic in 3.5, but must be done manually in 3.4. - asyncio.set_event_loop(self.asyncio_loop) self.asyncio_loop.run_forever() finally: if old_current is None: IOLoop.clear_current() else: old_current.make_current() - asyncio.set_event_loop(old_asyncio) def stop(self): self.asyncio_loop.stop() @@ -188,6 +181,17 @@ class AsyncIOLoop(BaseAsyncIOLoop): loop.close() raise + def make_current(self): + super(AsyncIOLoop, self).make_current() + try: + self.old_asyncio = asyncio.get_event_loop() + except RuntimeError: + self.old_asyncio = None + asyncio.set_event_loop(self.asyncio_loop) + + def _clear_current_hook(self): + asyncio.set_event_loop(self.old_asyncio) + def to_tornado_future(asyncio_future): """Convert an `asyncio.Future` to a `tornado.concurrent.Future`. diff --git a/tornado/test/asyncio_test.py b/tornado/test/asyncio_test.py index 1bfbe76c..54d9fa03 100644 --- a/tornado/test/asyncio_test.py +++ b/tornado/test/asyncio_test.py @@ -30,7 +30,6 @@ else: class AsyncIOLoopTest(AsyncTestCase): def get_new_ioloop(self): io_loop = AsyncIOLoop() - asyncio.set_event_loop(io_loop.asyncio_loop) return io_loop def test_asyncio_callback(self): diff --git a/tornado/test/twisted_test.py b/tornado/test/twisted_test.py index 5c9884df..84a9f44d 100644 --- a/tornado/test/twisted_test.py +++ b/tornado/test/twisted_test.py @@ -505,14 +505,6 @@ class CompatibilityTests(unittest.TestCase): @skipIfNoTwisted class ConvertDeferredTest(unittest.TestCase): - def setUp(self): - if asyncio is not None: - asyncio.set_event_loop(asyncio.new_event_loop()) - - def tearDown(self): - if asyncio is not None: - asyncio.set_event_loop(None) - def test_success(self): @inlineCallbacks def fn(): diff --git a/tornado/testing.py b/tornado/testing.py index 975df86c..95f0ec53 100644 --- a/tornado/testing.py +++ b/tornado/testing.py @@ -217,9 +217,6 @@ class AsyncTestCase(unittest.TestCase): super(AsyncTestCase, self).setUp() self.io_loop = self.get_new_ioloop() self.io_loop.make_current() - if hasattr(self.io_loop, 'asyncio_loop'): - # Ensure that asyncio's current event loop matches ours. - asyncio.set_event_loop(self.io_loop.asyncio_loop) def tearDown(self): # Clean up Subprocess, so it can be used again with a new ioloop. @@ -231,8 +228,6 @@ class AsyncTestCase(unittest.TestCase): # set FD_CLOEXEC on its file descriptors) self.io_loop.close(all_fds=True) super(AsyncTestCase, self).tearDown() - if hasattr(self.io_loop, 'asyncio_loop'): - asyncio.set_event_loop(None) # In case an exception escaped or the StackContext caught an exception # when there wasn't a wait() to re-raise it, do so here. # This is our last chance to raise an exception in a way that the