Variation of StreamingResponse that can dynamically decide the HTTP status code, based on the returns from the content iterator (parameter 'content'). Expects the content to yield tuples of (content: str, status_code: int), instead of just content as it was in the original StreamingResponse
| 10 | |
| 11 | |
| 12 | class StreamingResponseWithStatusCode(StreamingResponse): |
| 13 | ''' |
| 14 | Variation of StreamingResponse that can dynamically decide the HTTP status code, based on the returns from the content iterator (parameter 'content'). |
| 15 | Expects the content to yield tuples of (content: str, status_code: int), instead of just content as it was in the original StreamingResponse. |
| 16 | The parameter status_code in the constructor is ignored, but kept for compatibility with StreamingResponse. |
| 17 | ''' |
| 18 | |
| 19 | async def stream_response(self, send: Send) -> None: |
| 20 | try: |
| 21 | first_chunk_content, headers, self.status_code = ( |
| 22 | await self.body_iterator.__anext__() |
| 23 | ) |
| 24 | |
| 25 | if not isinstance(first_chunk_content, bytes): |
| 26 | first_chunk_content = first_chunk_content.encode(self.charset) |
| 27 | |
| 28 | asgi_headers: List[Tuple[bytes, bytes]] = [ |
| 29 | (key.encode("latin-1"), value.encode("latin-1")) |
| 30 | for key, value in headers.items() |
| 31 | ] |
| 32 | await send( |
| 33 | { |
| 34 | "type": "http.response.start", |
| 35 | "status": self.status_code, |
| 36 | "headers": asgi_headers, |
| 37 | } |
| 38 | ) |
| 39 | await send( |
| 40 | { |
| 41 | "type": "http.response.body", |
| 42 | "body": first_chunk_content, |
| 43 | "more_body": True, |
| 44 | } |
| 45 | ) |
| 46 | |
| 47 | async for chunk_content, _, _ in self.body_iterator: |
| 48 | if not isinstance(chunk_content, bytes): |
| 49 | chunk_content = chunk_content.encode(self.charset) |
| 50 | await send( |
| 51 | { |
| 52 | "type": "http.response.body", |
| 53 | "body": chunk_content, |
| 54 | "more_body": True, |
| 55 | } |
| 56 | ) |
| 57 | |
| 58 | await send({"type": "http.response.body", "body": b"", "more_body": False}) |
| 59 | |
| 60 | except StopAsyncIteration: |
| 61 | self.status_code = status.HTTP_503_SERVICE_UNAVAILABLE |
| 62 | await send( |
| 63 | { |
| 64 | "type": "http.response.start", |
| 65 | "status": self.status_code, |
| 66 | "headers": self.raw_headers, |
| 67 | } |
| 68 | ) |
| 69 |
no outgoing calls
no test coverage detected