From: Ben Darnell Date: Sun, 14 Oct 2018 17:30:54 +0000 (-0400) Subject: web: Convert RequestHandler._execute to a native coroutine X-Git-Tag: v6.0.0b1~23^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f15102bfa3517529ce83f6ab324fb5ce67fa1817;p=thirdparty%2Ftornado.git web: Convert RequestHandler._execute to a native coroutine --- diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index b46a0a396..2a8b6a5b1 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -751,11 +751,13 @@ class KeepAliveTest(AsyncHTTPTestCase): self.write("".join(chr(i % 256) * 1024 for i in range(512))) class FinishOnCloseHandler(RequestHandler): + def initialize(self, cleanup_event): + self.cleanup_event = cleanup_event + @gen.coroutine def get(self): self.flush() - never_finish = Event() - yield never_finish.wait() + yield self.cleanup_event.wait() def on_connection_close(self): # This is not very realistic, but finishing the request @@ -763,11 +765,16 @@ class KeepAliveTest(AsyncHTTPTestCase): # some errors seen in the wild. self.finish("closed") + self.cleanup_event = Event() return Application( [ ("/", HelloHandler), ("/large", LargeHandler), - ("/finish_on_close", FinishOnCloseHandler), + ( + "/finish_on_close", + FinishOnCloseHandler, + dict(cleanup_event=self.cleanup_event), + ), ] ) @@ -894,6 +901,8 @@ class KeepAliveTest(AsyncHTTPTestCase): self.stream.write(b"GET /finish_on_close HTTP/1.1\r\n\r\n") yield self.read_headers() self.close() + # Let the hanging coroutine clean up after itself + self.cleanup_event.set() @gen_test def test_keepalive_chunked(self): diff --git a/tornado/test/simple_httpclient_test.py b/tornado/test/simple_httpclient_test.py index ed399ae05..11539a2f7 100644 --- a/tornado/test/simple_httpclient_test.py +++ b/tornado/test/simple_httpclient_test.py @@ -58,18 +58,11 @@ class TriggerHandler(RequestHandler): @gen.coroutine def get(self): logging.debug("queuing trigger") - self.queue.append(self.finish) + event = Event() + self.queue.append(event.set) if self.get_argument("wake", "true") == "true": self.wake_callback() - never_finish = Event() - yield never_finish.wait() - - -class HangHandler(RequestHandler): - @gen.coroutine - def get(self): - never_finish = Event() - yield never_finish.wait() + yield event.wait() class ContentLengthHandler(RequestHandler): @@ -163,7 +156,6 @@ class SimpleHTTPClientTestMixin(object): ), url("/chunk", ChunkHandler), url("/countdown/([0-9]+)", CountdownHandler, name="countdown"), - url("/hang", HangHandler), url("/hello", HelloWorldHandler), url("/content_length", ContentLengthHandler), url("/head", HeadHandler), @@ -304,6 +296,7 @@ class SimpleHTTPClientTestMixin(object): self.fetch("/trigger?wake=false", request_timeout=timeout, raise_error=True) # trigger the hanging request to let it clean up after itself self.triggers.popleft()() + self.io_loop.run_sync(lambda: gen.sleep(0)) @skipIfNoIPv6 def test_ipv6(self): diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index 87738ba3c..96a787bb3 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -441,8 +441,7 @@ class ConnectionCloseHandler(RequestHandler): @gen.coroutine def get(self): self.test.on_handler_waiting() - never_finish = Event() - yield never_finish.wait() + yield self.test.cleanup_event.wait() def on_connection_close(self): self.test.on_connection_close() @@ -450,6 +449,7 @@ class ConnectionCloseHandler(RequestHandler): class ConnectionCloseTest(WebTestCase): def get_handlers(self): + self.cleanup_event = Event() return [("/", ConnectionCloseHandler, dict(test=self))] def test_connection_close(self): @@ -458,6 +458,9 @@ class ConnectionCloseTest(WebTestCase): self.stream = IOStream(s) self.stream.write(b"GET / HTTP/1.0\r\n\r\n") self.wait() + # Let the hanging coroutine clean up after itself + self.cleanup_event.set() + self.io_loop.run_sync(lambda: gen.sleep(0)) def on_handler_waiting(self): logging.debug("handler waiting") diff --git a/tornado/web.py b/tornado/web.py index a9d28a600..c6dca17ff 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -1659,10 +1659,9 @@ class RequestHandler(object): break return match - @gen.coroutine - def _execute( + async def _execute( self, transforms: List["OutputTransform"], *args: bytes, **kwargs: bytes - ) -> Generator[Any, Any, None]: + ) -> None: """Executes this request with the given output transforms.""" self._transforms = transforms try: @@ -1683,7 +1682,7 @@ class RequestHandler(object): result = self.prepare() if result is not None: - result = yield result + result = await result if self._prepared_future is not None: # Tell the Application we've finished with prepare() # and are ready for the body to arrive. @@ -1697,14 +1696,14 @@ class RequestHandler(object): # result; the data has been passed to self.data_received # instead. try: - yield self.request._body_future + await self.request._body_future except iostream.StreamClosedError: return method = getattr(self, self.request.method.lower()) result = method(*self.path_args, **self.path_kwargs) if result is not None: - result = yield result + result = await result if self._auto_finish and not self._finished: self.finish() except Exception as e: @@ -2329,7 +2328,10 @@ class _HandlerDelegate(httputil.HTTPMessageDelegate): # except handler, and we cannot easily access the IOLoop here to # call add_future (because of the requirement to remain compatible # with WSGI) - self.handler._execute(transforms, *self.path_args, **self.path_kwargs) + fut = gen.convert_yielded( + self.handler._execute(transforms, *self.path_args, **self.path_kwargs) + ) + fut.add_done_callback(lambda f: f.result()) # If we are streaming the request body, then execute() is finished # when the handler has prepared to receive the body. If not, # it doesn't matter when execute() finishes (so we return None)