import os
import sys
import types
+import warnings
from tornado.concurrent import (Future, is_future, chain_future, future_set_exc_info,
future_add_done_callback, future_set_result_unless_cancelled)
they are finished. One notable exception is the
`~tornado.web.RequestHandler` :ref:`HTTP verb methods <verbs>`,
which use ``self.finish()`` in place of a callback argument.
+
+ .. deprecated:: 5.1
+
+ This decorator will be removed in 6.0. Use `coroutine` or
+ ``async def`` instead.
"""
+ warnings.warn("gen.engine is deprecated, use gen.coroutine or async def instead",
+ DeprecationWarning)
func = _make_coroutine_wrapper(func, replace_callback=False)
@functools.wraps(func)
class TwitterClientLoginGenEngineHandler(TwitterClientHandler):
- @asynchronous
- @gen.engine
- def get(self):
- if self.get_argument("oauth_token", None):
- user = yield self.get_authenticated_user()
- self.finish(user)
- else:
- # Old style: with @gen.engine we can ignore the Future from
- # authorize_redirect.
- self.authorize_redirect()
+ with ignore_deprecation():
+ @asynchronous
+ @gen.engine
+ def get(self):
+ if self.get_argument("oauth_token", None):
+ user = yield self.get_authenticated_user()
+ self.finish(user)
+ else:
+ # Old style: with @gen.engine we can ignore the Future from
+ # authorize_redirect.
+ self.authorize_redirect()
class TwitterClientLoginGenCoroutineHandler(TwitterClientHandler):
class TwitterClientShowUserHandlerLegacy(TwitterClientHandler):
- @asynchronous
- @gen.engine
- def get(self):
- # TODO: would be nice to go through the login flow instead of
- # cheating with a hard-coded access token.
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- response = yield gen.Task(self.twitter_request,
- '/users/show/%s' % self.get_argument('name'),
- access_token=dict(key='hjkl', secret='vbnm'))
- if response is None:
- self.set_status(500)
- self.finish('error from twitter request')
- else:
- self.finish(response)
+ with ignore_deprecation():
+ @asynchronous
+ @gen.engine
+ def get(self):
+ # TODO: would be nice to go through the login flow instead of
+ # cheating with a hard-coded access token.
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', DeprecationWarning)
+ response = yield gen.Task(self.twitter_request,
+ '/users/show/%s' % self.get_argument('name'),
+ access_token=dict(key='hjkl', secret='vbnm'))
+ if response is None:
+ self.set_status(500)
+ self.finish('error from twitter request')
+ else:
+ self.finish(response)
class TwitterClientShowUserHandler(TwitterClientHandler):
self.finish(response)
-class TwitterClientShowUserFutureHandler(TwitterClientHandler):
- @asynchronous
- @gen.engine
- def get(self):
- try:
- response = yield self.twitter_request(
- '/users/show/%s' % self.get_argument('name'),
- access_token=dict(key='hjkl', secret='vbnm'))
- except AuthError as e:
- self.set_status(500)
- self.finish(str(e))
- return
- assert response is not None
- self.finish(response)
-
-
class TwitterServerAccessTokenHandler(RequestHandler):
def get(self):
self.write('oauth_token=hjkl&oauth_token_secret=vbnm&screen_name=foo')
TwitterClientShowUserHandlerLegacy, dict(test=self)),
('/twitter/client/show_user',
TwitterClientShowUserHandler, dict(test=self)),
- ('/twitter/client/show_user_future',
- TwitterClientShowUserFutureHandler, dict(test=self)),
# simulated servers
('/openid/server/authenticate', OpenIdServerAuthenticateHandler),
self.assertEqual(response.code, 500)
self.assertEqual(response.body, b'error from twitter request')
- def test_twitter_show_user_future(self):
- response = self.fetch('/twitter/client/show_user_future?name=somebody')
- response.rethrow()
- self.assertEqual(json_decode(response.body),
- {'name': 'Somebody', 'screen_name': 'somebody'})
-
- def test_twitter_show_user_future_error(self):
- response = self.fetch('/twitter/client/show_user_future?name=error')
- self.assertEqual(response.code, 500)
- self.assertIn(b'Error response HTTP 500', response.body)
-
class GoogleLoginHandler(RequestHandler, GoogleOAuth2Mixin):
def initialize(self, test):
self.assertIs(result, None)
future.result()
+ @gen_test
+ def test_future_traceback_legacy(self):
+ with ignore_deprecation():
+ @return_future
+ @gen.engine
+ def f(callback):
+ yield gen.Task(self.io_loop.add_callback)
+ try:
+ 1 / 0
+ except ZeroDivisionError:
+ self.expected_frame = traceback.extract_tb(
+ sys.exc_info()[2], limit=1)[0]
+ raise
+ try:
+ yield f()
+ self.fail("didn't get expected exception")
+ except ZeroDivisionError:
+ tb = traceback.extract_tb(sys.exc_info()[2])
+ self.assertIn(self.expected_frame, tb)
+
@gen_test
def test_future_traceback(self):
- @return_future
- @gen.engine
- def f(callback):
+ @gen.coroutine
+ def f():
yield gen.Task(self.io_loop.add_callback)
try:
1 / 0
class GeneratorCapClient(BaseCapClient):
- @return_future
- @gen.engine
- def capitalize(self, request_data, callback):
+ @gen.coroutine
+ def capitalize(self, request_data):
logging.debug('capitalize')
stream = IOStream(socket.socket())
logging.debug('connecting')
data = yield gen.Task(stream.read_until, b'\n')
logging.debug('returning')
stream.close()
- callback(self.process_response(data))
+ raise gen.Return(self.process_response(data))
class ClientTestMixin(object):
self.assertRaisesRegexp(CapError, "already capitalized", future.result)
def test_generator(self):
- @gen.engine
+ @gen.coroutine
def f():
result = yield self.client.capitalize("hello")
self.assertEqual(result, "HELLO")
- self.stop()
- f()
- self.wait()
+ self.io_loop.run_sync(f)
def test_generator_error(self):
- @gen.engine
+ @gen.coroutine
def f():
with self.assertRaisesRegexp(CapError, "already capitalized"):
yield self.client.capitalize("HELLO")
- self.stop()
- f()
- self.wait()
+ self.io_loop.run_sync(f)
class ManualClientTest(ClientTestMixin, AsyncTestCase):
import textwrap
import time
import weakref
+import warnings
from tornado.concurrent import return_future, Future
from tornado.escape import url_escape
from tornado.log import app_log
from tornado import stack_context
from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test
-from tornado.test.util import unittest, skipOnTravis, skipBefore33, skipBefore35, skipNotCPython, exec_test # noqa: E501
+from tornado.test.util import unittest, skipOnTravis, skipBefore33, skipBefore35, skipNotCPython, exec_test, ignore_deprecation # noqa: E501
from tornado.web import Application, RequestHandler, asynchronous, HTTPError
from tornado import gen
class GenEngineTest(AsyncTestCase):
def setUp(self):
+ self.warning_catcher = warnings.catch_warnings()
+ self.warning_catcher.__enter__()
+ warnings.simplefilter('ignore', DeprecationWarning)
super(GenEngineTest, self).setUp()
self.named_contexts = []
+ def tearDown(self):
+ super(GenEngineTest, self).tearDown()
+ self.warning_catcher.__exit__(None, None, None)
+
def named_context(self, name):
@contextlib.contextmanager
def context():
class GenSequenceHandler(RequestHandler):
- @asynchronous
- @gen.engine
- def get(self):
- self.io_loop = self.request.connection.stream.io_loop
- self.io_loop.add_callback((yield gen.Callback("k1")))
- yield gen.Wait("k1")
- self.write("1")
- self.io_loop.add_callback((yield gen.Callback("k2")))
- yield gen.Wait("k2")
- self.write("2")
- # reuse an old key
- self.io_loop.add_callback((yield gen.Callback("k1")))
- yield gen.Wait("k1")
- self.finish("3")
+ with ignore_deprecation():
+ @asynchronous
+ @gen.engine
+ def get(self):
+ self.io_loop = self.request.connection.stream.io_loop
+ self.io_loop.add_callback((yield gen.Callback("k1")))
+ yield gen.Wait("k1")
+ self.write("1")
+ self.io_loop.add_callback((yield gen.Callback("k2")))
+ yield gen.Wait("k2")
+ self.write("2")
+ # reuse an old key
+ self.io_loop.add_callback((yield gen.Callback("k1")))
+ yield gen.Wait("k1")
+ self.finish("3")
class GenCoroutineSequenceHandler(RequestHandler):
class GenTaskHandler(RequestHandler):
- @asynchronous
- @gen.engine
+ @gen.coroutine
def get(self):
client = AsyncHTTPClient()
response = yield gen.Task(client.fetch, self.get_argument('url'))
class GenExceptionHandler(RequestHandler):
- @asynchronous
- @gen.engine
- def get(self):
- # This test depends on the order of the two decorators.
- io_loop = self.request.connection.stream.io_loop
- yield gen.Task(io_loop.add_callback)
- raise Exception("oops")
+ with ignore_deprecation():
+ @asynchronous
+ @gen.engine
+ def get(self):
+ # This test depends on the order of the two decorators.
+ io_loop = self.request.connection.stream.io_loop
+ yield gen.Task(io_loop.add_callback)
+ raise Exception("oops")
class GenCoroutineExceptionHandler(RequestHandler):
class GenYieldExceptionHandler(RequestHandler):
- @asynchronous
- @gen.engine
+ @gen.coroutine
def get(self):
io_loop = self.request.connection.stream.io_loop
# Test the interaction of the two stack_contexts.
from tornado.stack_context import (StackContext, wrap, NullContext, StackContextInconsistentError,
ExceptionStackContext, run_with_stack_context, _state)
from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test
-from tornado.test.util import unittest
+from tornado.test.util import unittest, ignore_deprecation
from tornado.web import asynchronous, Application, RequestHandler
import contextlib
import functools
self.wait()
def test_yield_in_with(self):
- @gen.engine
- def f():
- self.callback = yield gen.Callback('a')
- with StackContext(functools.partial(self.context, 'c1')):
- # This yield is a problem: the generator will be suspended
- # and the StackContext's __exit__ is not called yet, so
- # the context will be left on _state.contexts for anything
- # that runs before the yield resolves.
- yield gen.Wait('a')
+ with ignore_deprecation():
+ @gen.engine
+ def f():
+ self.callback = yield gen.Callback('a')
+ with StackContext(functools.partial(self.context, 'c1')):
+ # This yield is a problem: the generator will be suspended
+ # and the StackContext's __exit__ is not called yet, so
+ # the context will be left on _state.contexts for anything
+ # that runs before the yield resolves.
+ yield gen.Wait('a')
with self.assertRaises(StackContextInconsistentError):
f()
def test_yield_in_with_exception_stack_context(self):
# As above, but with ExceptionStackContext instead of StackContext.
- @gen.engine
- def f():
- with ExceptionStackContext(lambda t, v, tb: False):
- yield gen.Task(self.io_loop.add_callback)
-
- with self.assertRaises(StackContextInconsistentError):
- f()
- self.wait()
+ with ignore_deprecation():
+ @gen.engine
+ def f():
+ with ExceptionStackContext(lambda t, v, tb: False):
+ yield gen.Task(self.io_loop.add_callback)
+
+ with self.assertRaises(StackContextInconsistentError):
+ f()
+ self.wait()
@gen_test
def test_yield_outside_with_exception_stack_context(self):
class EmptyFlushCallbackHandler(RequestHandler):
- @asynchronous
- @gen.engine
+ @gen.coroutine
def get(self):
# Ensure that the flush callback is run whether or not there
# was any output. The gen.Task and direct yield forms are