def test_asyncio_adapter(self): # This test demonstrates that when using the asyncio coroutine # runner (i.e. run_until_complete), the to_asyncio_future # adapter is needed. No adapter is needed in the other direction, # as demonstrated by other tests in the package. @gen.coroutine def tornado_coroutine(): yield gen.Task(self.io_loop.add_callback) raise gen.Return(42) native_coroutine_without_adapter = exec_test(globals(), locals(), """ async def native_coroutine_without_adapter(): return await tornado_coroutine() """)["native_coroutine_without_adapter"] native_coroutine_with_adapter = exec_test(globals(), locals(), """ async def native_coroutine_with_adapter(): return await to_asyncio_future(tornado_coroutine()) """)["native_coroutine_with_adapter"] # Use the adapter, but two degrees from the tornado coroutine. native_coroutine_with_adapter2 = exec_test(globals(), locals(), """ async def native_coroutine_with_adapter2(): return await to_asyncio_future(native_coroutine_without_adapter()) """)["native_coroutine_with_adapter2"] # Tornado supports native coroutines both with and without adapters self.assertEqual( self.io_loop.run_sync(native_coroutine_without_adapter), 42) self.assertEqual( self.io_loop.run_sync(native_coroutine_with_adapter), 42) self.assertEqual( self.io_loop.run_sync(native_coroutine_with_adapter2), 42) # Asyncio only supports coroutines that yield asyncio-compatible # Futures (which our Future is since 5.0). self.assertEqual( asyncio.get_event_loop().run_until_complete( native_coroutine_without_adapter()), 42) self.assertEqual( asyncio.get_event_loop().run_until_complete( native_coroutine_with_adapter()), 42) self.assertEqual( asyncio.get_event_loop().run_until_complete( native_coroutine_with_adapter2()), 42)
def test_asyncio_adapter(self): # This test demonstrates that when using the asyncio coroutine # runner (i.e. run_until_complete), the to_asyncio_future # adapter is needed. No adapter is needed in the other direction, # as demonstrated by other tests in the package. @gen.coroutine def tornado_coroutine(): yield gen.Task(self.io_loop.add_callback) raise gen.Return(42) native_coroutine_without_adapter = exec_test(globals(), locals(), """ async def native_coroutine_without_adapter(): return await tornado_coroutine() """)["native_coroutine_without_adapter"] native_coroutine_with_adapter = exec_test(globals(), locals(), """ async def native_coroutine_with_adapter(): return await to_asyncio_future(tornado_coroutine()) """)["native_coroutine_with_adapter"] # Use the adapter, but two degrees from the tornado coroutine. native_coroutine_with_adapter2 = exec_test(globals(), locals(), """ async def native_coroutine_with_adapter2(): return await to_asyncio_future(native_coroutine_without_adapter()) """)["native_coroutine_with_adapter2"] # Tornado supports native coroutines both with and without adapters self.assertEqual( self.io_loop.run_sync(native_coroutine_without_adapter), 42) self.assertEqual( self.io_loop.run_sync(native_coroutine_with_adapter), 42) self.assertEqual( self.io_loop.run_sync(native_coroutine_with_adapter2), 42) # Asyncio only supports coroutines that yield asyncio-compatible # Futures. with self.assertRaises(RuntimeError): asyncio.get_event_loop().run_until_complete( native_coroutine_without_adapter()) self.assertEqual( asyncio.get_event_loop().run_until_complete( native_coroutine_with_adapter()), 42) self.assertEqual( asyncio.get_event_loop().run_until_complete( native_coroutine_with_adapter2()), 42)
def test_run_in_executor_native(self): event1 = threading.Event() event2 = threading.Event() def sync_func(self_event, other_event): self_event.set() other_event.wait() return self_event # Go through an async wrapper to ensure that the result of # run_in_executor works with await and not just gen.coroutine # (simply passing the underlying concurrrent future would do that). namespace = exec_test( globals(), locals(), """ async def async_wrapper(self_event, other_event): return await IOLoop.current().run_in_executor( None, sync_func, self_event, other_event) """) res = yield [ namespace["async_wrapper"](event1, event2), namespace["async_wrapper"](event2, event1) ] self.assertEqual([event1, event2], res)
def test_native_coroutine(self): namespace = exec_test( globals(), locals(), """ async def f(): await gen.Task(self.io_loop.add_callback) """) self.io_loop.run_sync(namespace['f'])
def test_native_coroutine(self): namespace = exec_test(globals(), locals(), """ @gen_test async def test(self): self.finished = True """) namespace['test'](self)
def test_native_coroutine(self): @gen.coroutine def f1(): yield gen.moment namespace = exec_test(globals(), locals(), """ async def f2(): await f1() """) self.io_loop.run_sync(namespace['f2'])
def test_async_return(self): namespace = exec_test(globals(), locals(), """ @gen.coroutine def f(): yield gen.Task(self.io_loop.add_callback) return 42 """) result = yield namespace['f']() self.assertEqual(result, 42) self.finished = True
def test_async_with_timeout(self): namespace = exec_test(globals(), locals(), """ async def f1(): return 42 """) result = yield gen.with_timeout(datetime.timedelta(hours=1), namespace['f1']()) self.assertEqual(result, 42) self.finished = True
def test_native_body_producer_chunked(self): namespace = exec_test(globals(), locals(), """ async def body_producer(write): await write(b'1234') await gen.Task(IOLoop.current().add_callback) await write(b'5678') """) response = self.fetch("/echo_post", method="POST", body_producer=namespace["body_producer"]) response.rethrow() self.assertEqual(response.body, b"12345678")
def test_exception_logging_native_coro(self): """The IOLoop examines exceptions from awaitables and logs them.""" namespace = exec_test(globals(), locals(), """ async def callback(): self.io_loop.add_callback(self.stop) 1 / 0 """) with NullContext(): self.io_loop.add_callback(namespace["callback"]) with ExpectLog(app_log, "Exception in callback"): self.wait()
def test_async_await(self): # This test verifies that an async function can await a # yield-based gen.coroutine, and that a gen.coroutine # (the test method itself) can yield an async function. namespace = exec_test(globals(), locals(), """ async def f(): await gen.Task(self.io_loop.add_callback) return 42 """) result = yield namespace['f']() self.assertEqual(result, 42) self.finished = True
def test_asyncio_sleep_zero(self): # asyncio.sleep(0) turns into a special case (equivalent to # `yield None`) namespace = exec_test(globals(), locals(), """ async def f(): import asyncio await asyncio.sleep(0) return 42 """) result = yield namespace['f']() self.assertEqual(result, 42) self.finished = True
def test_asyncio_yield_from(self): # Test that we can use asyncio coroutines with 'yield from' # instead of asyncio.async(). This requires python 3.3 syntax. namespace = exec_test(globals(), locals(), """ @gen.coroutine def f(): event_loop = asyncio.get_event_loop() x = yield from event_loop.run_in_executor(None, lambda: 42) return x """) result = yield namespace['f']() self.assertEqual(result, 42)
def test_native_body_producer_chunked(self): namespace = exec_test(globals(), locals(), """ async def body_producer(write): await write(b'1234') import asyncio await asyncio.sleep(0) await write(b'5678') """) response = self.fetch("/echo_post", method="POST", body_producer=namespace["body_producer"]) response.rethrow() self.assertEqual(response.body, b"12345678")
def test_native_coroutine_timeout(self): # Set a short timeout and exceed it. namespace = exec_test(globals(), locals(), """ @gen_test(timeout=0.1) async def test(self): await gen.sleep(1) """) try: namespace['test'](self) self.fail("did not get expected exception") except ioloop.TimeoutError: self.finished = True
def test_context_manager_async_await(self): # Repeat the above test using 'async with'. sem = locks.Semaphore() namespace = exec_test(globals(), locals(), """ async def f(): async with sem as yielded: self.assertTrue(yielded is None) """) yield namespace['f']() # Semaphore was released and can be acquired again. self.assertTrue(sem.acquire().done())
def test_async_early_return(self): # A yield statement exists but is not executed, which means # this function "returns" via an exception. This exception # doesn't happen before the exception handling is set up. namespace = exec_test(globals(), locals(), """ @gen.coroutine def f(): if True: return 42 yield gen.Task(self.io_loop.add_callback) """) result = yield namespace['f']() self.assertEqual(result, 42) self.finished = True
def test_native_body_producer_chunked(self): namespace = exec_test( globals(), locals(), """ async def body_producer(write): await write(b'1234') import asyncio await asyncio.sleep(0) await write(b'5678') """) response = self.fetch("/echo_post", method="POST", body_producer=namespace["body_producer"]) response.rethrow() self.assertEqual(response.body, b"12345678")
def test_async_for(self): q = queues.Queue() for i in range(5): q.put(i) namespace = exec_test(globals(), locals(), """ async def f(): results = [] async for i in q: results.append(i) if i == 4: return results """) results = yield namespace['f']() self.assertEqual(results, list(range(5)))
def test_async_await_mixed_multi(self): namespace = exec_test(globals(), locals(), """ async def f1(): await gen.Task(self.io_loop.add_callback) return 42 """) @gen.coroutine def f2(): yield gen.Task(self.io_loop.add_callback) raise gen.Return(43) results = yield [namespace['f1'](), f2()] self.assertEqual(results, [42, 43]) self.finished = True
def test_async_await_mixed_multi_native_future(self): namespace = exec_test(globals(), locals(), """ async def f1(): await gen.Task(self.io_loop.add_callback) return 42 """) @gen.coroutine def f2(): yield gen.Task(self.io_loop.add_callback) raise gen.Return(43) results = yield [namespace['f1'](), f2()] self.assertEqual(results, [42, 43]) self.finished = True
def test_async_await(self): class Object(object): def __init__(self): self.executor = futures.thread.ThreadPoolExecutor(1) @run_on_executor() def f(self): return 42 o = Object() namespace = exec_test(globals(), locals(), """ async def f(): answer = await o.f() return answer """) result = yield namespace['f']() self.assertEqual(result, 42)
def test_acquire_fifo_async_with(self): # Repeat the above test using `async with lock:` # instead of `with (yield lock.acquire()):`. lock = locks.Lock() self.assertTrue(lock.acquire().done()) N = 5 history = [] namespace = exec_test(globals(), locals(), """ async def f(idx): async with lock: history.append(idx) """) futures = [namespace['f'](i) for i in range(N)] lock.release() yield futures self.assertEqual(list(range(N)), history)
def test_undecorated_coroutine(self): namespace = exec_test(globals(), locals(), """ class Test(AsyncTestCase): async def test_coro(self): pass """) test_class = namespace['Test'] test = test_class('test_coro') result = unittest.TestResult() # Silence "RuntimeWarning: coroutine 'test_coro' was never awaited". with warnings.catch_warnings(): warnings.simplefilter('ignore') test.run(result) self.assertEqual(len(result.errors), 1) self.assertIn("should be decorated", result.errors[0][1])
def test_handle_stream_native_coroutine(self): # handle_stream may be a native coroutine. namespace = exec_test(globals(), locals(), """ class TestServer(TCPServer): async def handle_stream(self, stream, address): stream.write(b'data') stream.close() """) sock, port = bind_unused_port() server = namespace['TestServer']() server.add_socket(sock) client = IOStream(socket.socket()) yield client.connect(('localhost', port)) result = yield client.read_until_close() self.assertEqual(result, b'data') server.stop() client.close()
def test_async_await_mixed_multi_native_yieldpoint(self): namespace = exec_test( globals(), locals(), """ async def f1(): await gen.Task(self.io_loop.add_callback) return 42 """, ) @gen.coroutine def f2(): yield gen.Task(self.io_loop.add_callback) raise gen.Return(43) f2(callback=(yield gen.Callback("cb"))) results = yield [namespace["f1"](), gen.Wait("cb")] self.assertEqual(results, [42, 43]) self.finished = True
def test_iterator_async_await(self): # Recreate the previous test with py35 syntax. It's a little clunky # because of the way the previous test handles an exception on # a single iteration. futures = [Future(), Future(), Future(), Future()] self.finish_coroutines(0, futures) self.finished = False namespace = exec_test( globals(), locals(), """ async def f(): i = 0 g = gen.WaitIterator(*futures) try: async for r in g: if i == 0: self.assertEqual(r, 24, 'iterator value incorrect') self.assertEqual(g.current_index, 2, 'wrong index') else: raise Exception("expected exception on iteration 1") i += 1 except ZeroDivisionError: i += 1 async for r in g: if i == 2: self.assertEqual(r, 42, 'iterator value incorrect') self.assertEqual(g.current_index, 1, 'wrong index') elif i == 3: self.assertEqual(r, 84, 'iterator value incorrect') self.assertEqual(g.current_index, 3, 'wrong index') else: raise Exception("didn't expect iteration %d" % i) i += 1 self.finished = True """, ) yield namespace["f"]() self.assertTrue(self.finished)
def test_iterator_async_await(self): # Recreate the previous test with py35 syntax. It's a little clunky # because of the way the previous test handles an exception on # a single iteration. futures = [Future(), Future(), Future(), Future()] self.finish_coroutines(0, futures) self.finished = False namespace = exec_test( globals(), locals(), """ async def f(): i = 0 g = gen.WaitIterator(*futures) try: async for r in g: if i == 0: self.assertEqual(r, 24, 'iterator value incorrect') self.assertEqual(g.current_index, 2, 'wrong index') else: raise Exception("expected exception on iteration 1") i += 1 except ZeroDivisionError: i += 1 async for r in g: if i == 2: self.assertEqual(r, 42, 'iterator value incorrect') self.assertEqual(g.current_index, 1, 'wrong index') elif i == 3: self.assertEqual(r, 84, 'iterator value incorrect') self.assertEqual(g.current_index, 3, 'wrong index') else: raise Exception("didn't expect iteration %d" % i) i += 1 self.finished = True """) yield namespace['f']() self.assertTrue(self.finished)
def test_run_in_executor_native(self): event1 = threading.Event() event2 = threading.Event() def sync_func(self_event, other_event): self_event.set() other_event.wait() return self_event # Go through an async wrapper to ensure that the result of # run_in_executor works with await and not just gen.coroutine # (simply passing the underlying concurrrent future would do that). namespace = exec_test(globals(), locals(), """ async def async_wrapper(self_event, other_event): return await IOLoop.current().run_in_executor( None, sync_func, self_event, other_event) """) res = yield [ namespace["async_wrapper"](event1, event2), namespace["async_wrapper"](event2, event1) ] self.assertEqual([event1, event2], res)
with self.assertRaises(HTTPError) as cm: yield websocket_connect(HTTPRequest(url, headers=headers), io_loop=self.io_loop) self.assertEqual(cm.exception.code, 403) if sys.version_info >= (3, 5): NativeCoroutineOnMessageHandler = exec_test( globals(), locals(), """ class NativeCoroutineOnMessageHandler(TestWebSocketHandler): def initialize(self, close_future, compression_options=None): super().initialize(close_future, compression_options) self.sleeping = 0 async def on_message(self, message): if self.sleeping > 0: self.write_message('another coroutine is already sleeping') self.sleeping += 1 await gen.sleep(0.01) self.sleeping -= 1 self.write_message(message)""")['NativeCoroutineOnMessageHandler'] class WebSocketNativeCoroutineTest(WebSocketBaseTestCase): def get_app(self): self.close_future = Future() return Application([('/native', NativeCoroutineOnMessageHandler, dict(close_future=self.close_future))]) @skipBefore35
def test_native_coroutine(self): namespace = exec_test(globals(), locals(), """ async def f(): await gen.Task(self.io_loop.add_callback) """) self.io_loop.run_sync(namespace['f'])
headers = {'Origin': 'http://subtenant.localhost'} with self.assertRaises(HTTPError) as cm: yield websocket_connect(HTTPRequest(url, headers=headers)) self.assertEqual(cm.exception.code, 403) if sys.version_info >= (3, 5): NativeCoroutineOnMessageHandler = exec_test(globals(), locals(), """ class NativeCoroutineOnMessageHandler(TestWebSocketHandler): def initialize(self, close_future, compression_options=None): super().initialize(close_future, compression_options) self.sleeping = 0 async def on_message(self, message): if self.sleeping > 0: self.write_message('another coroutine is already sleeping') self.sleeping += 1 await gen.sleep(0.01) self.sleeping -= 1 self.write_message(message)""")['NativeCoroutineOnMessageHandler'] class WebSocketNativeCoroutineTest(WebSocketBaseTestCase): def get_app(self): self.close_future = Future() return Application([ ('/native', NativeCoroutineOnMessageHandler, dict(close_future=self.close_future))])