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
This commit is contained in:
Ben Darnell 2017-12-17 11:36:53 -05:00
parent ccd4930b2f
commit 5de0928e6e
5 changed files with 22 additions and 22 deletions

View File

@ -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

View File

@ -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`.

View File

@ -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):

View File

@ -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():

View File

@ -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