From: Florimond Manca Date: Wed, 21 Aug 2019 21:11:12 +0000 (+0200) Subject: Remove usage of loop.create_task in ASGIDispatch (#261) X-Git-Tag: 0.7.2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80eafe89c2c3377e9f0702952c96044c69909155;p=thirdparty%2Fhttpx.git Remove usage of loop.create_task in ASGIDispatch (#261) * Remove usage of loop.create_task in ASGIDispatch * Add comment about usage of background manager * Update comment --- diff --git a/httpx/concurrency/asyncio.py b/httpx/concurrency/asyncio.py index 34d68c38..9b977832 100644 --- a/httpx/concurrency/asyncio.py +++ b/httpx/concurrency/asyncio.py @@ -223,7 +223,7 @@ class AsyncioBackend(ConcurrencyBackend): return typing.cast(BaseEvent, asyncio.Event()) def background_manager( - self, coroutine: typing.Callable, args: typing.Any + self, coroutine: typing.Callable, *args: typing.Any ) -> "BackgroundManager": return BackgroundManager(coroutine, args) diff --git a/httpx/concurrency/base.py b/httpx/concurrency/base.py index 45785df1..9bfd54d4 100644 --- a/httpx/concurrency/base.py +++ b/httpx/concurrency/base.py @@ -159,7 +159,7 @@ class ConcurrencyBackend: raise NotImplementedError() # pragma: no cover def background_manager( - self, coroutine: typing.Callable, args: typing.Any + self, coroutine: typing.Callable, *args: typing.Any ) -> "BaseBackgroundManager": raise NotImplementedError() # pragma: no cover diff --git a/httpx/dispatch/asgi.py b/httpx/dispatch/asgi.py index 589bf8c8..4e3f3dcd 100644 --- a/httpx/dispatch/asgi.py +++ b/httpx/dispatch/asgi.py @@ -1,4 +1,3 @@ -import asyncio import typing from .base import AsyncDispatcher @@ -121,13 +120,12 @@ class ASGIDispatch(AsyncDispatcher): await response_body.mark_as_done() response_started_or_failed.set() - # Really we'd like to push all `asyncio` logic into concurrency.py, - # with a standardized interface, so that we can support other event - # loop implementations, such as Trio and Curio. - # That's a bit fiddly here, so we're not yet supporting using a custom - # `ConcurrencyBackend` with the `Client(app=asgi_app)` case. - loop = asyncio.get_event_loop() - app_task = loop.create_task(run_app()) + # Using the background manager here *works*, but it is weak design because + # the background task isn't strictly context-managed. + # We could consider refactoring the other uses of this abstraction + # (mainly sending/receiving request/response data in h11 and h2 dispatchers), + # and see if that allows us to come back here and refactor things out. + background = await self.backend.background_manager(run_app).__aenter__() await response_started_or_failed.wait() @@ -138,9 +136,9 @@ class ASGIDispatch(AsyncDispatcher): assert headers is not None async def on_close() -> None: - nonlocal app_task, response_body + nonlocal response_body await response_body.drain() - await app_task + await background.__aexit__(None, None, None) if app_exc is not None and self.raise_app_exceptions: raise app_exc diff --git a/httpx/dispatch/http11.py b/httpx/dispatch/http11.py index 236c81e2..a54a8d4d 100644 --- a/httpx/dispatch/http11.py +++ b/httpx/dispatch/http11.py @@ -45,7 +45,7 @@ class HTTP11Connection: await self._send_request(request, timeout) task, args = self._send_request_data, [request.stream(), timeout] - async with self.backend.background_manager(task, args=args): + async with self.backend.background_manager(task, *args): http_version, status_code, headers = await self._receive_response(timeout) content = self._receive_response_data(timeout) diff --git a/httpx/dispatch/http2.py b/httpx/dispatch/http2.py index 0a698f35..f0ea1588 100644 --- a/httpx/dispatch/http2.py +++ b/httpx/dispatch/http2.py @@ -41,7 +41,7 @@ class HTTP2Connection: self.timeout_flags[stream_id] = TimeoutFlag() task, args = self.send_request_data, [stream_id, request.stream(), timeout] - async with self.backend.background_manager(task, args=args): + async with self.backend.background_manager(task, *args): status_code, headers = await self.receive_response(stream_id, timeout) content = self.body_iter(stream_id, timeout) on_close = functools.partial(self.response_closed, stream_id=stream_id)