未验证 提交 fb74e481 编写于 作者: B Ben Darnell 提交者: GitHub

Merge pull request #2319 from bdarnell/gen-deprecation

gen: Deprecate legacy interfaces
......@@ -34,17 +34,6 @@
.. autofunction:: multi_future
.. autofunction:: Task
.. class:: Arguments
The result of a `Task` or `Wait` whose callback had more than one
argument (or keyword arguments).
The `Arguments` object is a `collections.namedtuple` and can be
used either as a tuple ``(args, kwargs)`` or an object with attributes
``args`` and ``kwargs``.
.. autofunction:: convert_yielded
.. autofunction:: maybe_future
......@@ -70,3 +59,18 @@
.. autoclass:: WaitAll
.. autoclass:: MultiYieldPoint
.. autofunction:: Task
.. class:: Arguments
The result of a `Task` or `Wait` whose callback had more than one
argument (or keyword arguments).
The `Arguments` object is a `collections.namedtuple` and can be
used either as a tuple ``(args, kwargs)`` or an object with attributes
``args`` and ``kwargs``.
.. deprecated:: 5.1
This class will be removed in 6.0.
......@@ -96,6 +96,7 @@ import itertools
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)
......@@ -213,7 +214,14 @@ def engine(func):
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)
......@@ -232,7 +240,7 @@ def engine(func):
return wrapper
def coroutine(func, replace_callback=True):
def coroutine(func):
"""Decorator for asynchronous generators.
Any generator that yields objects from this module must be wrapped
......@@ -253,9 +261,6 @@ def coroutine(func, replace_callback=True):
``callback`` argument is not visible inside the decorated
function; it is handled by the decorator itself.
From the caller's perspective, ``@gen.coroutine`` is similar to
the combination of ``@return_future`` and ``@gen.engine``.
.. warning::
When exceptions occur inside a coroutine, the exception
......@@ -266,6 +271,10 @@ def coroutine(func, replace_callback=True):
`.IOLoop.run_sync` for top-level calls, or passing the `.Future`
to `.IOLoop.add_future`.
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
return _make_coroutine_wrapper(func, replace_callback=True)
......@@ -288,6 +297,8 @@ def _make_coroutine_wrapper(func, replace_callback):
future = _create_future()
if replace_callback and 'callback' in kwargs:
warnings.warn("callback arguments are deprecated, use the returned Future instead",
DeprecationWarning, stacklevel=2)
callback = kwargs.pop('callback')
IOLoop.current().add_future(
future, lambda future: callback(future.result()))
......@@ -513,8 +524,13 @@ class YieldPoint(object):
"""Base class for objects that may be yielded from the generator.
.. deprecated:: 4.0
Use `Futures <.Future>` instead.
Use `Futures <.Future>` instead. This class and all its subclasses
will be removed in 6.0
"""
def __init__(self):
warnings.warn("YieldPoint is deprecated, use Futures instead",
DeprecationWarning)
def start(self, runner):
"""Called by the runner after the generator has yielded.
......@@ -551,9 +567,11 @@ class Callback(YieldPoint):
is given it will be returned by `Wait`.
.. deprecated:: 4.0
Use `Futures <.Future>` instead.
Use `Futures <.Future>` instead. This class will be removed in 6.0.
"""
def __init__(self, key):
warnings.warn("gen.Callback is deprecated, use Futures instead",
DeprecationWarning)
self.key = key
def start(self, runner):
......@@ -571,9 +589,11 @@ class Wait(YieldPoint):
"""Returns the argument passed to the result of a previous `Callback`.
.. deprecated:: 4.0
Use `Futures <.Future>` instead.
Use `Futures <.Future>` instead. This class will be removed in 6.0.
"""
def __init__(self, key):
warnings.warn("gen.Wait is deprecated, use Futures instead",
DeprecationWarning)
self.key = key
def start(self, runner):
......@@ -595,9 +615,11 @@ class WaitAll(YieldPoint):
`WaitAll` is equivalent to yielding a list of `Wait` objects.
.. deprecated:: 4.0
Use `Futures <.Future>` instead.
Use `Futures <.Future>` instead. This class will be removed in 6.0.
"""
def __init__(self, keys):
warnings.warn("gen.WaitAll is deprecated, use gen.multi instead",
DeprecationWarning)
self.keys = keys
def start(self, runner):
......@@ -621,7 +643,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):
......@@ -645,7 +672,12 @@ class YieldFuture(YieldPoint):
.. versionchanged:: 5.0
The ``io_loop`` argument (deprecated since version 4.1) has been removed.
.. deprecated:: 5.1
This class will be removed in 6.0.
"""
warnings.warn("YieldFuture is deprecated, use Futures instead",
DeprecationWarning)
self.future = future
self.io_loop = IOLoop.current()
......@@ -761,9 +793,11 @@ class MultiYieldPoint(YieldPoint):
remains as an alias for the equivalent `multi` function.
.. deprecated:: 4.3
Use `multi` instead.
Use `multi` instead. This class will be removed in 6.0.
"""
def __init__(self, children, quiet_exceptions=()):
warnings.warn("MultiYieldPoint is deprecated, use Futures instead",
DeprecationWarning)
self.keys = None
if isinstance(children, dict):
self.keys = list(children.keys())
......
......@@ -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()
......
......@@ -227,10 +227,10 @@ class _HTTPConnection(httputil.HTTPMessageDelegate):
self._timeout = self.io_loop.add_timeout(
self.start_time + timeout,
stack_context.wrap(functools.partial(self._on_timeout, "while connecting")))
self.tcp_client.connect(host, port, af=af,
ssl_options=ssl_options,
max_buffer_size=self.max_buffer_size,
callback=self._on_connect)
fut = self.tcp_client.connect(host, port, af=af,
ssl_options=ssl_options,
max_buffer_size=self.max_buffer_size)
fut.add_done_callback(stack_context.wrap(self._on_connect))
def _get_ssl_options(self, scheme):
if scheme == "https":
......@@ -275,7 +275,8 @@ class _HTTPConnection(httputil.HTTPMessageDelegate):
self.io_loop.remove_timeout(self._timeout)
self._timeout = None
def _on_connect(self, stream):
def _on_connect(self, stream_fut):
stream = stream_fut.result()
if self.final_callback is None:
# final_callback is cleared if we've hit our timeout.
stream.close()
......
......@@ -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():
......
......@@ -252,16 +252,17 @@ class TwitterClientLoginHandler(TwitterClientHandler):
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):
......@@ -277,21 +278,22 @@ 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):
......@@ -310,22 +312,6 @@ 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')
......@@ -395,8 +381,6 @@ class AuthTest(AsyncHTTPTestCase):
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),
......@@ -623,17 +607,6 @@ class AuthTest(AsyncHTTPTestCase):
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):
......
......@@ -177,12 +177,31 @@ class ReturnFutureTest(AsyncTestCase):
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):
yield gen.Task(self.io_loop.add_callback)
@gen.coroutine
def f():
yield gen.moment
try:
1 / 0
except ZeroDivisionError:
......@@ -311,19 +330,18 @@ class DecoratorCapClient(BaseCapClient):
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')
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()
callback(self.process_response(data))
raise gen.Return(self.process_response(data))
class ClientTestMixin(object):
......@@ -362,22 +380,18 @@ 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):
......
此差异已折叠。
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'
......
......@@ -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,
......
......@@ -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",
......
......@@ -11,6 +11,7 @@ from tornado.web import asynchronous, Application, RequestHandler
import contextlib
import functools
import logging
import warnings
class TestRequestHandler(RequestHandler):
......@@ -61,6 +62,13 @@ class StackContextTest(AsyncTestCase):
def setUp(self):
super(StackContextTest, self).setUp()
self.active_contexts = []
self.warning_catcher = warnings.catch_warnings()
self.warning_catcher.__enter__()
warnings.simplefilter('ignore', DeprecationWarning)
def tearDown(self):
self.warning_catcher.__exit__(None, None, None)
super(StackContextTest, self).tearDown()
@contextlib.contextmanager
def context(self, name):
......
......@@ -77,8 +77,7 @@ class TCPClientTest(AsyncTestCase):
def skipIfLocalhostV4(self):
# The port used here doesn't matter, but some systems require it
# to be non-zero if we do not also pass AI_PASSIVE.
Resolver().resolve('localhost', 80, callback=self.stop)
addrinfo = self.wait()
addrinfo = yield Resolver().resolve('localhost', 80)
families = set(addr[0] for addr in addrinfo)
if socket.AF_INET6 not in families:
self.skipTest("localhost does not resolve to ipv6")
......
......@@ -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
......
......@@ -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,
......@@ -582,14 +582,14 @@ class RedirectHandler(RequestHandler):
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
# 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
......@@ -1808,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)
......@@ -2160,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()
......@@ -2168,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
......@@ -2214,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))
......@@ -2280,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))]
......@@ -2293,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))]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册