resolved RESOLVED PASS · 11 tool calls · 46 s · fastapi/fastapi
⬆️ Upgrade Starlette supported version range to >=0.40.0,<0.49.0 Starlette 0.48.0 introduced `HTTP_422_UNPROCESSABLE_CONTENT` as a new name for `HTTP_422_UNPROCESSABLE_ENTITY` and deprecated the old name due to RFC 9110; see https://github.com/Kludex/starlette/pull/2939. I updated all instances ~to the new name and increased the lower bound on the Starlette version~ to use the literal integer or string value `422`/`"422"` instead of either `HTTP_422_UNPROCESSABLE_CONTENT` or `HTTP_422_UNPROCESSABLE_ENTITY`, which makes FastAPI compatible with Starlette >=0.48 without deprecation warnings while preserving backwards compatibility with Starlette<0.48. @Kludex, FYI.
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"HTTP_422_UNPROCESSABLE\" ."
} | {"status": "ok", "stdout": "./fastapi/exception_handlers.py:8:from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION\n./fastapi/exfull{"status": "ok", "stdout": "./fastapi/exception_handlers.py:8:from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION\n./fastapi/exception_handlers.py:24: status_code=HTTP_422_UNPROCESSABLE_ENTITY,\n./fastapi/openapi/utils.py:38:from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY\n./fastapi/openapi/utils.py:419: http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)\n./tests/test_enforce_once_required_parameter.py:105: assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY\n./docs_src/handling_errors/tutorial005.py:13: status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,\n", "exit_code": 0} |
| 2 | read_file | {
"filepath": "fastapi/exception_handlers.py",
"start_line": 1,
"end_line": 30
} | {"status": "ok", "filepath": "fastapi/exception_handlers.py", "content": "from fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import RequestVfull{"status": "ok", "filepath": "fastapi/exception_handlers.py", "content": "from fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError\nfrom fastapi.utils import is_body_allowed_for_status_code\nfrom fastapi.websockets import WebSocket\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.responses import JSONResponse, Response\nfrom starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION\n\n\nasync def http_exception_handler(request: Request, exc: HTTPException) -> Response:\n headers = getattr(exc, \"headers\", None)\n if not is_body_allowed_for_status_code(exc.status_code):\n return Response(status_code=exc.status_code, headers=headers)\n return JSONResponse(\n {\"detail\": exc.detail}, status_code=exc.status_code, headers=headers\n )\n\n\nasync def request_validation_exception_handler(\n request: Request, exc: RequestValidationError\n) -> JSONResponse:\n return JSONResponse(\n status_code=HTTP_422_UNPROCESSABLE_ENTITY,\n content={\"detail\": jsonable_encoder(exc.errors())},\n )\n\n\nasync def websocket_request_validation_exception_handler(\n websocket: WebSocket, exc: WebSocketRequestValidationError\n", "start_line": 1, "end_line": 30, "total_lines": 34, "is_truncated": false} |
| 3 | read_file | {
"end_line": 45,
"filepath": "fastapi/openapi/utils.py",
"start_line": 30
} | {"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": "from fastapi.utils import (\n deep_dict_update,\n generate_operation_id_for_path,\n is_bodyfull{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": "from fastapi.utils import (\n deep_dict_update,\n generate_operation_id_for_path,\n is_body_allowed_for_status_code,\n)\nfrom pydantic import BaseModel\nfrom starlette.responses import JSONResponse\nfrom starlette.routing import BaseRoute\nfrom starlette.status import HTTP_422_UNPROCESSABLE_ENTITY\nfrom typing_extensions import Literal\n\nvalidation_error_definition = {\n \"title\": \"ValidationError\",\n \"type\": \"object\",\n \"properties\": {\n \"loc\": {\n", "start_line": 30, "end_line": 45, "total_lines": 569, "is_truncated": false} |
| 4 | read_file | {
"end_line": 430,
"filepath": "fastapi/openapi/utils.py",
"start_line": 410
} | {"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": " ) or http.client.responses.get(int(additional_status_code))\n description = (\n process_refull{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": " ) or http.client.responses.get(int(additional_status_code))\n description = (\n process_response.get(\"description\")\n or openapi_response.get(\"description\")\n or status_text\n or \"Additional Response\"\n )\n deep_dict_update(openapi_response, process_response)\n openapi_response[\"description\"] = description\n http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)\n all_route_params = get_flat_params(route.dependant)\n if (all_route_params or route.body_field) and not any(\n status in operation[\"responses\"]\n for status in [http422, \"4XX\", \"default\"]\n ):\n operation[\"responses\"][http422] = {\n \"description\": \"Validation Error\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\"$ref\": REF_PREFIX + \"HTTPValidationError\"}\n }\n", "start_line": 410, "end_line": 430, "total_lines": 569, "is_truncated": false} |
| 5 | run_command | {
"command": "grep -rn \"starlette\" . | grep \">=0.\" | head -20"
} | {"status": "ok", "stdout": "./docs/en/docs/release-notes.md:2729:* \u2b06\ufe0f Upgrade Starlette version to `>=0.27.0` for a security release. PR [#9541](httpsfull{"status": "ok", "stdout": "./docs/en/docs/release-notes.md:2729:* \u2b06\ufe0f Upgrade Starlette version to `>=0.27.0` for a security release. PR [#9541](https://github.com/tiangolo/fastapi/pull/9541) by [@tiangolo](https://github.com/tiangolo). Details on [Starlette's security advisory](https://github.com/encode/starlette/security/advisories/GHSA-v5gw-mw7f-84px).\n./pyproject.toml:46: \"starlette>=0.40.0,<0.48.0\",\n", "exit_code": 0} |
| 6 | read_file | {
"end_line": 50,
"filepath": "pyproject.toml",
"start_line": 40
} | {"status": "ok", "filepath": "pyproject.toml", "content": " \"Programming Language :: Python :: 3.12\",\n \"Programming Language :: Python :: 3.13\",\n \"Topic full{"status": "ok", "filepath": "pyproject.toml", "content": " \"Programming Language :: Python :: 3.12\",\n \"Programming Language :: Python :: 3.13\",\n \"Topic :: Internet :: WWW/HTTP :: HTTP Servers\",\n \"Topic :: Internet :: WWW/HTTP\",\n]\ndependencies = [\n \"starlette>=0.40.0,<0.48.0\",\n \"pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0\",\n \"typing-extensions>=4.8.0\",\n]\n\n", "start_line": 40, "end_line": 50, "total_lines": 270, "is_truncated": false} |
| 7 | edit_file | {
"filepath": "pyproject.toml",
"new_string": " \"starlette>=0.40.0,<0.49.0\",",
"old_string": " \"starlette>=0.40.0,<0.48.0\","
} | {"status": "ok", "filepath": "pyproject.toml", "occurrences": 1, "strategy": "exact", "diff": "--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -43,7 +43,7 @@\n \full{"status": "ok", "filepath": "pyproject.toml", "occurrences": 1, "strategy": "exact", "diff": "--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -43,7 +43,7 @@\n \"Topic :: Internet :: WWW/HTTP\",\n ]\n dependencies = [\n- \"starlette>=0.40.0,<0.48.0\",\n+ \"starlette>=0.40.0,<0.49.0\",\n \"pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0\",\n \"typing-extensions>=4.8.0\",\n ]\n", "is_truncated": false} |
| 8 | edit_file | {
"filepath": "fastapi/exception_handlers.py",
"new_string": "from starlette.status import WS_1008_POLICY_VIOLATION",
"old_string": "from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION"
} | {"status": "ok", "filepath": "fastapi/exception_handlers.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/exception_handlers.py\n+++ b/fastapifull{"status": "ok", "filepath": "fastapi/exception_handlers.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/exception_handlers.py\n+++ b/fastapi/exception_handlers.py\n@@ -5,7 +5,7 @@\n from starlette.exceptions import HTTPException\n from starlette.requests import Request\n from starlette.responses import JSONResponse, Response\n-from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION\n+from starlette.status import WS_1008_POLICY_VIOLATION\n \n \n async def http_exception_handler(request: Request, exc: HTTPException) -> Response:\n", "is_truncated": false} |
| 9 | edit_file | {
"filepath": "fastapi/exception_handlers.py",
"new_string": " return JSONResponse(\n status_code=422,\n content={\"detail\": jsonable_encoder(exc.errors())},\n )",
"old_string": " return JSONResponse(\n status_code=HTTP_422_UNPROCESSABLE_ENTITY,\n content={\"detail\": jsonable_encoder(exc.errors())},\n )"
} | {"status": "ok", "filepath": "fastapi/exception_handlers.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/exception_handlers.py\n+++ b/fastapifull{"status": "ok", "filepath": "fastapi/exception_handlers.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/exception_handlers.py\n+++ b/fastapi/exception_handlers.py\n@@ -21,7 +21,7 @@\n request: Request, exc: RequestValidationError\n ) -> JSONResponse:\n return JSONResponse(\n- status_code=HTTP_422_UNPROCESSABLE_ENTITY,\n+ status_code=422,\n content={\"detail\": jsonable_encoder(exc.errors())},\n )\n \n", "is_truncated": false} |
| 10 | edit_file | {
"filepath": "fastapi/openapi/utils.py",
"new_string": "from starlette.responses import JSONResponse\nfrom starlette.routing import BaseRoute\nfrom typing_extensions import Literal",
"old_string": "from starlette.responses import JSONResponse\nfrom starlette.routing import BaseRoute\nfrom starlette.status import HTTP_422_UNPROCESSABLE_ENTITY\nfrom typing_extensions import Literal"
} | {"status": "ok", "filepath": "fastapi/openapi/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/openapi/utils.py\n+++ b/fastapi/openapi/ufull{"status": "ok", "filepath": "fastapi/openapi/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/openapi/utils.py\n+++ b/fastapi/openapi/utils.py\n@@ -35,7 +35,6 @@\n from pydantic import BaseModel\n from starlette.responses import JSONResponse\n from starlette.routing import BaseRoute\n-from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY\n from typing_extensions import Literal\n \n validation_error_definition = {\n", "is_truncated": false} |
| 11 | edit_file | {
"filepath": "fastapi/openapi/utils.py",
"new_string": " http422 = \"422\"\n all_route_params = get_flat_params(route.dependant)",
"old_string": " http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)\n all_route_params = get_flat_params(route.dependant)"
} | {"status": "ok", "filepath": "fastapi/openapi/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/openapi/utils.py\n+++ b/fastapi/openapi/ufull{"status": "ok", "filepath": "fastapi/openapi/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/openapi/utils.py\n+++ b/fastapi/openapi/utils.py\n@@ -415,7 +415,7 @@\n )\n deep_dict_update(openapi_response, process_response)\n openapi_response[\"description\"] = description\n- http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)\n+ http422 = \"422\"\n all_route_params = get_flat_params(route.dependant)\n if (all_route_params or route.body_field) and not any(\n status in operation[\"responses\"]\n", "is_truncated": false} |
| 12 | submit_patch | [] | {"status": "ok", "patch_size": 2240, "files_changed": 3}full{"status": "ok", "patch_size": 2240, "files_changed": 3} |
diff --git a/fastapi/exception_handlers.py b/fastapi/exception_handlers.py
index 6c2ba7fe..475dd7bd 100644
--- a/fastapi/exception_handlers.py
+++ b/fastapi/exception_handlers.py
@@ -5,7 +5,7 @@ from fastapi.websockets import WebSocket
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
-from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION
+from starlette.status import WS_1008_POLICY_VIOLATION
async def http_exception_handler(request: Request, exc: HTTPException) -> Response:
@@ -21,7 +21,7 @@ async def request_validation_exception_handler(
request: Request, exc: RequestValidationError
) -> JSONResponse:
return JSONResponse(
- status_code=HTTP_422_UNPROCESSABLE_ENTITY,
+ status_code=422,
content={"detail": jsonable_encoder(exc.errors())},
)
diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py
index 808646cc..eda64a99 100644
--- a/fastapi/openapi/utils.py
+++ b/fastapi/openapi/utils.py
@@ -35,7 +35,6 @@ from fastapi.utils import (
from pydantic import BaseModel
from starlette.responses import JSONResponse
from starlette.routing import BaseRoute
-from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
from typing_extensions import Literal
validation_error_definition = {
@@ -416,7 +415,7 @@ def get_openapi_path(
)
deep_dict_update(openapi_response, process_response)
openapi_response["description"] = description
- http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)
+ http422 = "422"
all_route_params = get_flat_params(route.dependant)
if (all_route_params or route.body_field) and not any(
status in operation["responses"]
diff --git a/pyproject.toml b/pyproject.toml
index 7709451f..4d86b21f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -43,7 +43,7 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
]
dependencies = [
- "starlette>=0.40.0,<0.48.0",
+ "starlette>=0.40.0,<0.49.0",
"pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0",
"typing-extensions>=4.8.0",
]
... [100%]
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/overlays/starlette-0.47.3-py3-none-any/starlette/testclient.py:51
/kaggle/tmp/envs/overlays/starlette-0.47.3-py3-none-any/starlette/testclient.py:51: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
_PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
3 passed, 1 warning in 0.63s