Merge branch 'master' into streaming

This commit is contained in:
L. Kärkkäinen 2020-03-02 14:05:15 +02:00
commit 9baa2419cd
8 changed files with 56 additions and 34 deletions

View File

@ -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

View File

@ -1177,6 +1177,12 @@ class Sanic:
try:
self.is_running = True
if workers > 1 and os.name != "posix":
logger.warn(
f"Multiprocessing is currently not supported on {os.name},"
" using workers=1 instead"
)
workers = 1
if workers == 1:
if auto_reload and os.name != "posix":
# This condition must be removed after implementing

View File

@ -1,11 +1,11 @@
import asyncio
import multiprocessing
import os
import sys
from asyncio import CancelledError
from functools import partial
from inspect import isawaitable
from multiprocessing import Process
from signal import SIG_IGN, SIGINT, SIGTERM, Signals
from signal import signal as signal_func
from socket import SO_REUSEADDR, SOL_SOCKET, socket
@ -613,9 +613,10 @@ def serve_multiple(server_settings, workers):
signal_func(SIGINT, lambda s, f: sig_handler(s, f))
signal_func(SIGTERM, lambda s, f: sig_handler(s, f))
mp = multiprocessing.get_context("fork")
for _ in range(workers):
process = Process(target=serve, kwargs=server_settings)
process = mp.Process(target=serve, kwargs=server_settings)
process.daemon = True
process.start()
processes.append(process)

View File

@ -23,7 +23,7 @@ class SanicTestClient:
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,7 +38,7 @@ class SanicTestClient:
try:
response = await getattr(session, method.lower())(
url, verify=False, *args, **kwargs
url, *args, **kwargs
)
except httpx.exceptions.ConnectionClosed:
logger.error(
@ -48,15 +48,17 @@ class SanicTestClient:
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 = {}
@ -189,11 +191,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,

View File

@ -85,7 +85,7 @@ requirements = [
"aiofiles>=0.3.0",
"websockets>=7.0,<9.0",
"multidict>=4.0,<5.0",
"httpx==0.9.3",
"httpx==0.11.1",
]
tests_require = [

View File

@ -18,6 +18,22 @@ old_conn = None
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 @@ class ReusableSanicConnectionPool(
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 @@ class ReusableSanicConnectionPool(
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 @@ class ReuseableSanicTestClient(SanicTestClient):
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 @@ class ReuseableSanicTestClient(SanicTestClient):
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 @@ class ReuseableSanicTestClient(SanicTestClient):
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")

View File

@ -14,18 +14,15 @@ class DelayableHTTPConnection(httpx.dispatch.connection.HTTPConnection):
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 @@ class DelayableSanicConnectionPool(
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 @@ class DelayableSanicConnectionPool(
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)

View File

@ -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