mirror of https://github.com/tiangolo/fastapi.git
Fix UnboundLocalError in OpenAPI schema generation with custom response classes
When a route uses a custom response class whose __init__ does not expose
a status_code parameter with an int default, and the route decorator
does not specify an explicit status_code, the status_code local variable
in get_openapi_path() was never assigned. This caused an
UnboundLocalError at the point where status_code is used to populate
the operation responses dict.
The bug does not surface with standard Starlette response classes
(JSONResponse, HTMLResponse, PlainTextResponse, StreamingResponse, etc.)
because they all declare status_code: int = 200 (or 307 for redirects)
in their __init__ signatures. It triggers when users define custom
response classes that wrap or omit the status_code parameter, e.g.:
class CustomResponse(Response):
def __init__(self, content, **kwargs):
super().__init__(content=content, status_code=200, **kwargs)
@app.get("/items", response_class=CustomResponse)
async def get_items(): ...
Accessing /openapi.json or /docs would crash with:
UnboundLocalError: cannot access local variable 'status_code'
Fix: initialize status_code = "200" before the conditional block so it
always has a safe default. The existing branches that extract status_code
from the route or from the response class signature still override this
default when applicable.
This commit is contained in:
parent
ed12105cce
commit
05d1effc23
|
|
@ -339,6 +339,7 @@ def get_openapi_path(
|
|||
)
|
||||
callbacks[callback.name] = {callback.path: cb_path}
|
||||
operation["callbacks"] = callbacks
|
||||
status_code = "200"
|
||||
if route.status_code is not None:
|
||||
status_code = str(route.status_code)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
from starlette.responses import Response
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
||||
|
||||
class CustomResponse(Response):
|
||||
"""A custom response class whose __init__ does not expose status_code
|
||||
as a parameter with an int default. This previously caused an
|
||||
UnboundLocalError during OpenAPI schema generation when the route
|
||||
did not specify an explicit status_code."""
|
||||
|
||||
media_type = "text/plain"
|
||||
|
||||
def __init__(self, content: str, **kwargs: object) -> None:
|
||||
super().__init__(content=content, status_code=200, **kwargs)
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items", response_class=CustomResponse)
|
||||
async def get_items():
|
||||
return "ok"
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_get_response():
|
||||
response = client.get("/items")
|
||||
assert response.status_code == 200
|
||||
assert response.text == "ok"
|
||||
|
||||
|
||||
def test_openapi_schema():
|
||||
"""OpenAPI generation must not crash when the response class's __init__
|
||||
lacks a status_code parameter with an int default."""
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == snapshot(
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/items": {
|
||||
"get": {
|
||||
"summary": "Get Items",
|
||||
"operationId": "get_items_items_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"text/plain": {"schema": {"type": "string"}}},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
Loading…
Reference in New Issue