diff --git a/environment.yml b/environment.yml index dc88e64687..a689bdeff0 100644 --- a/environment.yml +++ b/environment.yml @@ -13,7 +13,7 @@ dependencies: - sphinx==1.8.3 - sphinx_rtd_theme==0.4.2 - recommonmark==0.5.0 - - httpx==0.9.3 + - httpx==0.11.1 - sphinxcontrib-asyncio>=0.2.0 - docutils==0.14 - pygments==2.3.1 diff --git a/sanic/testing.py b/sanic/testing.py index c836a943c2..98ff29e683 100644 --- a/sanic/testing.py +++ b/sanic/testing.py @@ -23,7 +23,7 @@ def __init__(self, app, port=PORT, host=HOST): self.host = host def get_new_session(self): - return httpx.Client() + return httpx.AsyncClient(verify=False) async def _local_request(self, method, url, *args, **kwargs): logger.info(url) @@ -38,20 +38,22 @@ async def _local_request(self, method, url, *args, **kwargs): try: response = await getattr(session, method.lower())( - url, verify=False, *args, **kwargs + url, *args, **kwargs ) except NameError: raise Exception(response.status_code) + response.body = await response.aread() + response.status = response.status_code + response.content_type = response.headers.get("content-type") + + # response can be decoded as json after response._content + # is set by response.aread() try: response.json = response.json() except (JSONDecodeError, UnicodeDecodeError): response.json = None - response.body = await response.read() - response.status = response.status_code - response.content_type = response.headers.get("content-type") - if raw_cookies: response.raw_cookies = {} @@ -185,11 +187,11 @@ async def app_call_with_return(self, scope, receive, send): return await asgi_app() -class SanicASGIDispatch(httpx.dispatch.ASGIDispatch): +class SanicASGIDispatch(httpx.dispatch.asgi.ASGIDispatch): pass -class SanicASGITestClient(httpx.Client): +class SanicASGITestClient(httpx.AsyncClient): def __init__( self, app, diff --git a/setup.py b/setup.py index 263c0db13b..332229ff10 100644 --- a/setup.py +++ b/setup.py @@ -85,7 +85,7 @@ def open_local(paths, mode="r", encoding="utf8"): "aiofiles>=0.3.0", "websockets>=7.0,<9.0", "multidict>=4.0,<5.0", - "httpx==0.9.3", + "httpx==0.11.1", ] tests_require = [ diff --git a/tests/test_keep_alive_timeout.py b/tests/test_keep_alive_timeout.py index ec9d997552..78f956559a 100644 --- a/tests/test_keep_alive_timeout.py +++ b/tests/test_keep_alive_timeout.py @@ -18,6 +18,22 @@ class ReusableSanicConnectionPool( httpx.dispatch.connection_pool.ConnectionPool ): + @property + def cert(self): + return self.ssl.cert + + @property + def verify(self): + return self.ssl.verify + + @property + def trust_env(self): + return self.ssl.trust_env + + @property + def http2(self): + return self.ssl.http2 + async def acquire_connection(self, origin, timeout): global old_conn connection = self.pop_connection(origin) @@ -26,14 +42,17 @@ async def acquire_connection(self, origin, timeout): pool_timeout = None if timeout is None else timeout.pool_timeout await self.max_connections.acquire(timeout=pool_timeout) + ssl_config = httpx.config.SSLConfig( + cert=self.cert, + verify=self.verify, + trust_env=self.trust_env, + http2=self.http2 + ) connection = httpx.dispatch.connection.HTTPConnection( origin, - verify=self.verify, - cert=self.cert, - http2=self.http2, + ssl=ssl_config, backend=self.backend, release_func=self.release_connection, - trust_env=self.trust_env, uds=self.uds, ) @@ -49,7 +68,7 @@ async def acquire_connection(self, origin, timeout): return connection -class ResusableSanicSession(httpx.Client): +class ResusableSanicSession(httpx.AsyncClient): def __init__(self, *args, **kwargs) -> None: dispatch = ReusableSanicConnectionPool() super().__init__(dispatch=dispatch, *args, **kwargs) @@ -159,7 +178,7 @@ def kill_server(self): self._server = None if self._session: - self._loop.run_until_complete(self._session.close()) + self._loop.run_until_complete(self._session.aclose()) self._session = None except Exception as e3: @@ -178,7 +197,7 @@ async def _local_request(self, method, url, *args, **kwargs): self._session = self.get_new_session() try: response = await getattr(self._session, method.lower())( - url, verify=False, timeout=request_keepalive, *args, **kwargs + url, timeout=request_keepalive, *args, **kwargs ) except NameError: raise Exception(response.status_code) @@ -188,7 +207,7 @@ async def _local_request(self, method, url, *args, **kwargs): except (JSONDecodeError, UnicodeDecodeError): response.json = None - response.body = await response.read() + response.body = await response.aread() response.status = response.status_code response.content_type = response.headers.get("content-type") diff --git a/tests/test_request_timeout.py b/tests/test_request_timeout.py index c518f087a8..f698ae12d0 100644 --- a/tests/test_request_timeout.py +++ b/tests/test_request_timeout.py @@ -14,18 +14,15 @@ def __init__(self, *args, **kwargs): self._request_delay = kwargs.pop("request_delay") super().__init__(*args, **kwargs) - async def send(self, request, verify=None, cert=None, timeout=None): - if self.h11_connection is None and self.h2_connection is None: - await self.connect(verify=verify, cert=cert, timeout=timeout) + async def send(self, request, timeout=None): + + if self.connection is None: + self.connection = (await self.connect(timeout=timeout)) if self._request_delay: await asyncio.sleep(self._request_delay) - if self.h2_connection is not None: - response = await self.h2_connection.send(request, timeout=timeout) - else: - assert self.h11_connection is not None - response = await self.h11_connection.send(request, timeout=timeout) + response = await self.connection.send(request, timeout=timeout) return response @@ -46,12 +43,9 @@ async def acquire_connection(self, origin, timeout=None): await self.max_connections.acquire(timeout=pool_timeout) connection = DelayableHTTPConnection( origin, - verify=self.verify, - cert=self.cert, - http2=self.http2, + ssl=self.ssl, backend=self.backend, release_func=self.release_connection, - trust_env=self.trust_env, uds=self.uds, request_delay=self._request_delay, ) @@ -61,7 +55,7 @@ async def acquire_connection(self, origin, timeout=None): return connection -class DelayableSanicSession(httpx.Client): +class DelayableSanicSession(httpx.AsyncClient): def __init__(self, request_delay=None, *args, **kwargs) -> None: dispatch = DelayableSanicConnectionPool(request_delay=request_delay) super().__init__(dispatch=dispatch, *args, **kwargs) diff --git a/tox.ini b/tox.ini index bb7e5f1e12..321e3a5566 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ deps = pytest-sanic pytest-sugar httpcore==0.3.0 - httpx==0.9.3 + httpx==0.11.1 chardet<=2.3.0 beautifulsoup4 gunicorn