From: Ben Darnell Date: Mon, 19 Mar 2018 02:36:38 +0000 (-0400) Subject: gen: Deprecate Task X-Git-Tag: v5.1.0b1~36^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=647aed6fc812e4f9fdc5a82a0675a4402ff9035b;p=thirdparty%2Ftornado.git gen: Deprecate Task --- diff --git a/tornado/gen.py b/tornado/gen.py index 989174264..579939a19 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -646,7 +646,12 @@ def Task(func, *args, **kwargs): ``gen.Task`` is now a function that returns a `.Future`, instead of a subclass of `YieldPoint`. It still behaves the same way when yielded. + + .. deprecated:: 5.1 + This function is deprecated and will be removed in 6.0. """ + warnings.warn("gen.Task is deprecated, use Futures instead", + DeprecationWarning) future = _create_future() def handle_exception(typ, value, tb): diff --git a/tornado/platform/twisted.py b/tornado/platform/twisted.py index d1ab2c795..4ae98be97 100644 --- a/tornado/platform/twisted.py +++ b/tornado/platform/twisted.py @@ -554,7 +554,9 @@ class TwistedResolver(Resolver): resolved_family = socket.AF_INET6 else: deferred = self.resolver.getHostByName(utf8(host)) - resolved = yield gen.Task(deferred.addBoth) + fut = Future() + deferred.addBoth(fut.set_result) + resolved = yield fut if isinstance(resolved, failure.Failure): try: resolved.raiseException() diff --git a/tornado/test/asyncio_test.py b/tornado/test/asyncio_test.py index 41fda20d4..37f2f6e1b 100644 --- a/tornado/test/asyncio_test.py +++ b/tornado/test/asyncio_test.py @@ -77,7 +77,7 @@ class AsyncIOLoopTest(AsyncTestCase): # as demonstrated by other tests in the package. @gen.coroutine def tornado_coroutine(): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment raise gen.Return(42) native_coroutine_without_adapter = exec_test(globals(), locals(), """ async def native_coroutine_without_adapter(): diff --git a/tornado/test/concurrent_test.py b/tornado/test/concurrent_test.py index 5199033a3..ea1479103 100644 --- a/tornado/test/concurrent_test.py +++ b/tornado/test/concurrent_test.py @@ -201,7 +201,7 @@ class ReturnFutureTest(AsyncTestCase): def test_future_traceback(self): @gen.coroutine def f(): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment try: 1 / 0 except ZeroDivisionError: @@ -335,10 +335,10 @@ class GeneratorCapClient(BaseCapClient): logging.debug('capitalize') stream = IOStream(socket.socket()) logging.debug('connecting') - yield gen.Task(stream.connect, ('127.0.0.1', self.port)) + yield stream.connect(('127.0.0.1', self.port)) stream.write(utf8(request_data + '\n')) logging.debug('reading') - data = yield gen.Task(stream.read_until, b'\n') + data = yield stream.read_until(b'\n') logging.debug('returning') stream.close() raise gen.Return(self.process_response(data)) diff --git a/tornado/test/gen_test.py b/tornado/test/gen_test.py index c831f3bd0..373fae79a 100644 --- a/tornado/test/gen_test.py +++ b/tornado/test/gen_test.py @@ -714,7 +714,7 @@ class GenCoroutineTest(AsyncTestCase): def test_async_gen_return(self): @gen.coroutine def f(): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment raise gen.Return(42) result = yield f() self.assertEqual(result, 42) @@ -735,7 +735,7 @@ class GenCoroutineTest(AsyncTestCase): namespace = exec_test(globals(), locals(), """ @gen.coroutine def f(): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment return 42 """) result = yield namespace['f']() @@ -762,15 +762,20 @@ class GenCoroutineTest(AsyncTestCase): @skipBefore35 @gen_test def test_async_await(self): + @gen.coroutine + def f1(): + yield gen.moment + raise gen.Return(42) + # 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 + async def f2(): + result = await f1() + return result """) - result = yield namespace['f']() + result = yield namespace['f2']() self.assertEqual(result, 42) self.finished = True @@ -792,18 +797,22 @@ class GenCoroutineTest(AsyncTestCase): @skipBefore35 @gen_test def test_async_await_mixed_multi_native_future(self): + @gen.coroutine + def f1(): + yield gen.moment + namespace = exec_test(globals(), locals(), """ - async def f1(): - await gen.Task(self.io_loop.add_callback) + async def f2(): + await f1() return 42 """) @gen.coroutine - def f2(): - yield gen.Task(self.io_loop.add_callback) + def f3(): + yield gen.moment raise gen.Return(43) - results = yield [namespace['f1'](), f2()] + results = yield [namespace['f2'](), f3()] self.assertEqual(results, [42, 43]) self.finished = True @@ -854,7 +863,7 @@ class GenCoroutineTest(AsyncTestCase): # Without a return value we don't need python 3.3. @gen.coroutine def f(): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment return result = yield f() self.assertEqual(result, None) @@ -877,7 +886,7 @@ class GenCoroutineTest(AsyncTestCase): def test_async_raise(self): @gen.coroutine def f(): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment 1 / 0 future = f() with self.assertRaises(ZeroDivisionError): @@ -1145,7 +1154,8 @@ class GenTaskHandler(RequestHandler): @gen.coroutine def get(self): client = AsyncHTTPClient() - response = yield gen.Task(client.fetch, self.get_argument('url')) + with ignore_deprecation(): + response = yield gen.Task(client.fetch, self.get_argument('url')) response.rethrow() self.finish(b"got response: " + response.body) @@ -1175,14 +1185,14 @@ class GenYieldExceptionHandler(RequestHandler): def get(self): io_loop = self.request.connection.stream.io_loop # Test the interaction of the two stack_contexts. - - def fail_task(callback): - io_loop.add_callback(lambda: 1 / 0) - try: - yield gen.Task(fail_task) - raise Exception("did not get expected exception") - except ZeroDivisionError: - self.finish('ok') + with ignore_deprecation(): + def fail_task(callback): + io_loop.add_callback(lambda: 1 / 0) + try: + yield gen.Task(fail_task) + raise Exception("did not get expected exception") + except ZeroDivisionError: + self.finish('ok') # "Undecorated" here refers to the absence of @asynchronous. @@ -1190,22 +1200,22 @@ class UndecoratedCoroutinesHandler(RequestHandler): @gen.coroutine def prepare(self): self.chunks = [] - yield gen.Task(IOLoop.current().add_callback) + yield gen.moment self.chunks.append('1') @gen.coroutine def get(self): self.chunks.append('2') - yield gen.Task(IOLoop.current().add_callback) + yield gen.moment self.chunks.append('3') - yield gen.Task(IOLoop.current().add_callback) + yield gen.moment self.write(''.join(self.chunks)) class AsyncPrepareErrorHandler(RequestHandler): @gen.coroutine def prepare(self): - yield gen.Task(IOLoop.current().add_callback) + yield gen.moment raise HTTPError(403) def get(self): @@ -1216,7 +1226,8 @@ class NativeCoroutineHandler(RequestHandler): if sys.version_info > (3, 5): exec(textwrap.dedent(""" async def get(self): - await gen.Task(IOLoop.current().add_callback) + import asyncio + await asyncio.sleep(0) self.write("ok") """)) diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index 30696a04a..bfac9ab52 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -1,8 +1,8 @@ from __future__ import absolute_import, division, print_function from tornado import netutil +from tornado.concurrent import Future from tornado.escape import json_decode, json_encode, utf8, _unicode, recursive_unicode, native_str -from tornado import gen from tornado.http1connection import HTTP1Connection from tornado.httpserver import HTTPServer from tornado.httputil import HTTPHeaders, HTTPMessageDelegate, HTTPServerConnectionDelegate, ResponseStartLine # noqa: E501 @@ -1120,7 +1120,9 @@ class BodyLimitsTest(AsyncHTTPTestCase): stream.write(b'PUT /streaming?expected_size=10240 HTTP/1.1\r\n' b'Content-Length: 10240\r\n\r\n') stream.write(b'a' * 10240) - start_line, headers, response = yield gen.Task(read_stream_body, stream) + fut = Future() + read_stream_body(stream, callback=fut.set_result) + start_line, headers, response = yield fut self.assertEqual(response, b'10240') # Without the ?expected_size parameter, we get the old default value stream.write(b'PUT /streaming HTTP/1.1\r\n' diff --git a/tornado/test/ioloop_test.py b/tornado/test/ioloop_test.py index 1aa3f1e54..09f71c5d6 100644 --- a/tornado/test/ioloop_test.py +++ b/tornado/test/ioloop_test.py @@ -693,14 +693,14 @@ class TestIOLoopRunSync(unittest.TestCase): def test_async_result(self): @gen.coroutine def f(): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment raise gen.Return(42) self.assertEqual(self.io_loop.run_sync(f), 42) def test_async_exception(self): @gen.coroutine def f(): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment 1 / 0 with self.assertRaises(ZeroDivisionError): self.io_loop.run_sync(f) @@ -713,16 +713,20 @@ class TestIOLoopRunSync(unittest.TestCase): def test_timeout(self): @gen.coroutine def f(): - yield gen.Task(self.io_loop.add_timeout, self.io_loop.time() + 1) + yield gen.sleep(1) self.assertRaises(TimeoutError, self.io_loop.run_sync, f, timeout=0.01) @skipBefore35 def test_native_coroutine(self): + @gen.coroutine + def f1(): + yield gen.moment + namespace = exec_test(globals(), locals(), """ - async def f(): - await gen.Task(self.io_loop.add_callback) + async def f2(): + await f1() """) - self.io_loop.run_sync(namespace['f']) + self.io_loop.run_sync(namespace['f2']) @unittest.skipIf(asyncio is not None, diff --git a/tornado/test/simple_httpclient_test.py b/tornado/test/simple_httpclient_test.py index f32319e59..973353e03 100644 --- a/tornado/test/simple_httpclient_test.py +++ b/tornado/test/simple_httpclient_test.py @@ -378,7 +378,7 @@ class SimpleHTTPClientTestMixin(object): @gen.coroutine def async_body_producer(self, write): yield write(b'1234') - yield gen.Task(IOLoop.current().add_callback) + yield gen.moment yield write(b'5678') def test_sync_body_producer_chunked(self): @@ -412,7 +412,8 @@ class SimpleHTTPClientTestMixin(object): namespace = exec_test(globals(), locals(), """ async def body_producer(write): await write(b'1234') - await gen.Task(IOLoop.current().add_callback) + import asyncio + await asyncio.sleep(0) await write(b'5678') """) response = self.fetch("/echo_post", method="POST", @@ -425,7 +426,8 @@ class SimpleHTTPClientTestMixin(object): namespace = exec_test(globals(), locals(), """ async def body_producer(write): await write(b'1234') - await gen.Task(IOLoop.current().add_callback) + import asyncio + await asyncio.sleep(0) await write(b'5678') """) response = self.fetch("/echo_post", method="POST", diff --git a/tornado/test/testing_test.py b/tornado/test/testing_test.py index 796530ff8..9905c9272 100644 --- a/tornado/test/testing_test.py +++ b/tornado/test/testing_test.py @@ -208,14 +208,14 @@ class GenTest(AsyncTestCase): @gen_test def test_async(self): - yield gen.Task(self.io_loop.add_callback) + yield gen.moment self.finished = True def test_timeout(self): # Set a short timeout and exceed it. @gen_test(timeout=0.1) def test(self): - yield gen.Task(self.io_loop.add_timeout, self.io_loop.time() + 1) + yield gen.sleep(1) # This can't use assertRaises because we need to inspect the # exc_info triple (and not just the exception object) @@ -226,7 +226,7 @@ class GenTest(AsyncTestCase): # The stack trace should blame the add_timeout line, not just # unrelated IOLoop/testing internals. self.assertIn( - "gen.Task(self.io_loop.add_timeout, self.io_loop.time() + 1)", + "gen.sleep(1)", traceback.format_exc()) self.finished = True @@ -235,8 +235,7 @@ class GenTest(AsyncTestCase): # A test that does not exceed its timeout should succeed. @gen_test(timeout=1) def test(self): - time = self.io_loop.time - yield gen.Task(self.io_loop.add_timeout, time() + 0.1) + yield gen.sleep(0.1) test(self) self.finished = True @@ -244,8 +243,7 @@ class GenTest(AsyncTestCase): def test_timeout_environment_variable(self): @gen_test(timeout=0.5) def test_long_timeout(self): - time = self.io_loop.time - yield gen.Task(self.io_loop.add_timeout, time() + 0.25) + yield gen.sleep(0.25) # Uses provided timeout of 0.5 seconds, doesn't time out. with set_environ('ASYNC_TEST_TIMEOUT', '0.1'): @@ -256,8 +254,7 @@ class GenTest(AsyncTestCase): def test_no_timeout_environment_variable(self): @gen_test(timeout=0.01) def test_short_timeout(self): - time = self.io_loop.time - yield gen.Task(self.io_loop.add_timeout, time() + 1) + yield gen.sleep(1) # Uses environment-variable timeout of 0.1, times out. with set_environ('ASYNC_TEST_TIMEOUT', '0.1'): @@ -270,7 +267,7 @@ class GenTest(AsyncTestCase): @gen_test def test_with_args(self, *args): self.assertEqual(args, ('test',)) - yield gen.Task(self.io_loop.add_callback) + yield gen.moment test_with_args(self, 'test') self.finished = True @@ -279,7 +276,7 @@ class GenTest(AsyncTestCase): @gen_test def test_with_kwargs(self, **kwargs): self.assertDictEqual(kwargs, {'test': 'test'}) - yield gen.Task(self.io_loop.add_callback) + yield gen.moment test_with_kwargs(self, test='test') self.finished = True diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index 6aa06266e..6673a4f26 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -11,7 +11,7 @@ from tornado.log import app_log, gen_log from tornado.simple_httpclient import SimpleAsyncHTTPClient from tornado.template import DictLoader from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test -from tornado.test.util import unittest, skipBefore35, exec_test +from tornado.test.util import unittest, skipBefore35, exec_test, ignore_deprecation from tornado.util import ObjectDict, unicode_type, timedelta_to_seconds, PY3 from tornado.web import ( Application, RequestHandler, StaticFileHandler, RedirectHandler as WebRedirectHandler, @@ -587,8 +587,9 @@ class EmptyFlushCallbackHandler(RequestHandler): # Ensure that the flush callback is run whether or not there # was any output. The gen.Task and direct yield forms are # equivalent. - yield gen.Task(self.flush) # "empty" flush, but writes headers - yield gen.Task(self.flush) # empty flush + with ignore_deprecation(): + yield gen.Task(self.flush) # "empty" flush, but writes headers + yield gen.Task(self.flush) # empty flush self.write("o") yield self.flush() # flushes the "o" yield self.flush() # empty flush @@ -1807,7 +1808,6 @@ class MultipleExceptionTest(SimpleHandlerTestCase): @asynchronous def get(self): - from tornado.ioloop import IOLoop IOLoop.current().add_callback(lambda: 1 / 0) IOLoop.current().add_callback(lambda: 1 / 0) @@ -2159,7 +2159,7 @@ class StreamingRequestBodyTest(WebTestCase): self.assertEquals(data, b"qwer") stream.write(b"0\r\n\r\n") yield self.finished - data = yield gen.Task(stream.read_until_close) + data = yield stream.read_until_close() # This would ideally use an HTTP1Connection to read the response. self.assertTrue(data.endswith(b"{}")) stream.close() @@ -2167,14 +2167,14 @@ class StreamingRequestBodyTest(WebTestCase): @gen_test def test_early_return(self): stream = self.connect(b"/early_return", connection_close=False) - data = yield gen.Task(stream.read_until_close) + data = yield stream.read_until_close() self.assertTrue(data.startswith(b"HTTP/1.1 401")) @gen_test def test_early_return_with_data(self): stream = self.connect(b"/early_return", connection_close=False) stream.write(b"4\r\nasdf\r\n") - data = yield gen.Task(stream.read_until_close) + data = yield stream.read_until_close() self.assertTrue(data.startswith(b"HTTP/1.1 401")) @gen_test @@ -2213,12 +2213,12 @@ class BaseFlowControlHandler(RequestHandler): # Note that asynchronous prepare() does not block data_received, # so we don't use in_method here. self.methods.append('prepare') - yield gen.Task(IOLoop.current().add_callback) + yield gen.moment @gen.coroutine def post(self): with self.in_method('post'): - yield gen.Task(IOLoop.current().add_callback) + yield gen.moment self.write(dict(methods=self.methods)) @@ -2279,7 +2279,7 @@ class DecoratedStreamingRequestFlowControlTest( @gen.coroutine def data_received(self, data): with self.in_method('data_received'): - yield gen.Task(IOLoop.current().add_callback) + yield gen.moment return [('/', DecoratedFlowControlHandler, dict(test=self))] @@ -2292,7 +2292,8 @@ class NativeStreamingRequestFlowControlTest( data_received = exec_test(globals(), locals(), """ async def data_received(self, data): with self.in_method('data_received'): - await gen.Task(IOLoop.current().add_callback) + import asyncio + await asyncio.sleep(0) """)["data_received"] return [('/', NativeFlowControlHandler, dict(test=self))]