Streaming migration for 20.3 release (#1800)
* Compatibility and deprecations for Sanic 20.3 in preparation of the streaming branch. * Add test for new API. * isort tests * More coverage * json takes str, not bytes Co-authored-by: L. Kärkkäinen <tronic@users.noreply.github.com>
This commit is contained in:
parent
60b4efad67
commit
4db075ffc1
|
@ -56,6 +56,14 @@ class StreamBuffer:
|
|||
self._queue.task_done()
|
||||
return payload
|
||||
|
||||
async def __aiter__(self):
|
||||
"""Support `async for data in request.stream`"""
|
||||
while True:
|
||||
data = await self.read()
|
||||
if not data:
|
||||
break
|
||||
yield data
|
||||
|
||||
async def put(self, payload):
|
||||
await self._queue.put(payload)
|
||||
|
||||
|
@ -128,14 +136,33 @@ class Request:
|
|||
)
|
||||
|
||||
def body_init(self):
|
||||
""".. deprecated:: 20.3"""
|
||||
self.body = []
|
||||
|
||||
def body_push(self, data):
|
||||
""".. deprecated:: 20.3"""
|
||||
self.body.append(data)
|
||||
|
||||
def body_finish(self):
|
||||
""".. deprecated:: 20.3"""
|
||||
self.body = b"".join(self.body)
|
||||
|
||||
async def receive_body(self):
|
||||
"""Receive request.body, if not already received.
|
||||
|
||||
Streaming handlers may call this to receive the full body.
|
||||
|
||||
This is added as a compatibility shim in Sanic 20.3 because future
|
||||
versions of Sanic will make all requests streaming and will use this
|
||||
function instead of the non-async body_init/push/finish functions.
|
||||
|
||||
Please make an issue if your code depends on the old functionality and
|
||||
cannot be upgraded to the new API.
|
||||
"""
|
||||
if not self.stream:
|
||||
return
|
||||
self.body = b"".join([data async for data in self.stream])
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
if self.parsed_json is None:
|
||||
|
|
|
@ -3,7 +3,7 @@ import pytest
|
|||
from sanic.blueprints import Blueprint
|
||||
from sanic.exceptions import HeaderExpectationFailed
|
||||
from sanic.request import StreamBuffer
|
||||
from sanic.response import stream, text
|
||||
from sanic.response import json, stream, text
|
||||
from sanic.views import CompositionView, HTTPMethodView
|
||||
from sanic.views import stream as stream_decorator
|
||||
|
||||
|
@ -613,3 +613,43 @@ def test_request_stream(app):
|
|||
request, response = app.test_client.post("/bp_stream", data=data)
|
||||
assert response.status == 200
|
||||
assert response.text == data
|
||||
|
||||
def test_streaming_new_api(app):
|
||||
@app.post("/non-stream")
|
||||
async def handler(request):
|
||||
assert request.body == b"x"
|
||||
await request.receive_body() # This should do nothing
|
||||
assert request.body == b"x"
|
||||
return text("OK")
|
||||
|
||||
@app.post("/1", stream=True)
|
||||
async def handler(request):
|
||||
assert request.stream
|
||||
assert not request.body
|
||||
await request.receive_body()
|
||||
return text(request.body.decode().upper())
|
||||
|
||||
@app.post("/2", stream=True)
|
||||
async def handler(request):
|
||||
ret = []
|
||||
async for data in request.stream:
|
||||
# We should have no b"" or None, just proper chunks
|
||||
assert data
|
||||
assert isinstance(data, bytes)
|
||||
ret.append(data.decode("ASCII"))
|
||||
return json(ret)
|
||||
|
||||
request, response = app.test_client.post("/non-stream", data="x")
|
||||
assert response.status == 200
|
||||
|
||||
request, response = app.test_client.post("/1", data="TEST data")
|
||||
assert request.body == b"TEST data"
|
||||
assert response.status == 200
|
||||
assert response.text == "TEST DATA"
|
||||
|
||||
request, response = app.test_client.post("/2", data=data)
|
||||
assert response.status == 200
|
||||
res = response.json
|
||||
assert isinstance(res, list)
|
||||
assert len(res) > 1
|
||||
assert "".join(res) == data
|
||||
|
|
|
@ -15,6 +15,7 @@ from aiofiles import os as async_os
|
|||
from sanic.response import (
|
||||
HTTPResponse,
|
||||
StreamingHTTPResponse,
|
||||
empty,
|
||||
file,
|
||||
file_stream,
|
||||
json,
|
||||
|
@ -22,7 +23,6 @@ from sanic.response import (
|
|||
stream,
|
||||
text,
|
||||
)
|
||||
from sanic.response import empty
|
||||
from sanic.server import HttpProtocol
|
||||
from sanic.testing import HOST, PORT
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user