resolved RESOLVED PASS · 34 tool calls · 597 s · fastapi/fastapi
✨ Allow `None` as return type for bodiless responses Fixes #9424 If the return annotation of the route function is exactly `"None"`, return `None` for the typed annotation. This allows the status code `204 No Content` to be used.
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "ls /workspace && ls /workspace/fastapi"
} | {"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "ls: /tmp/swe_work/or2full{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "ls: /tmp/swe_work/or20_qwen27b_v2/fastapi_9425/a/workspace: No such file or directory\n", "exit_code": 1}} |
| 2 | run_command | {
"command": "grep -rn \"9424\" /workspace --include=*.py | head -20"
} | {"status": "ok", "stdout": "", "exit_code": 0}full{"status": "ok", "stdout": "", "exit_code": 0} |
| 3 | run_command | {
"command": "pwd; ls; ls fastapi 2>/dev/null | head"
} | {"status": "ok", "stdout": "/private/workspace\nCITATION.cff\nCONTRIBUTING.md\ndocs\ndocs_src\nfastapi\nLICENSE\npdm_build.py\npyproject.toml\npytest.ini\nREADMfull{"status": "ok", "stdout": "/private/workspace\nCITATION.cff\nCONTRIBUTING.md\ndocs\ndocs_src\nfastapi\nLICENSE\npdm_build.py\npyproject.toml\npytest.ini\nREADME.md\nrequirements-docs-insiders.txt\nrequirements-docs-tests.txt\nrequirements-docs.txt\nrequirements-github-actions.txt\nrequirements-tests.txt\nrequirements-translations.txt\nrequirements.txt\nscripts\nSECURITY.md\ntests\n__init__.py\n__main__.py\n_compat.py\napplications.py\nbackground.py\ncli.py\nconcurrency.py\ndatastructures.py\ndependencies\nencoders.py\n", "exit_code": 0} |
| 4 | run_command | {
"command": "grep -rn \"get_typed_return_annotation\\|return_annotation\" fastapi/routing.py | head -30"
} | {"status": "ok", "stdout": "fastapi/routing.py:42: get_typed_return_annotation,\nfastapi/routing.py:473: return_annotation = get_typed_return_annotation(endpoinfull{"status": "ok", "stdout": "fastapi/routing.py:42: get_typed_return_annotation,\nfastapi/routing.py:473: return_annotation = get_typed_return_annotation(endpoint)\nfastapi/routing.py:474: if lenient_issubclass(return_annotation, Response):\nfastapi/routing.py:477: response_model = return_annotation\n", "exit_code": 0} |
| 5 | run_command | {
"command": "grep -n \"get_typed_return_annotation\" fastapi/utils.py"
} | {"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 6 | run_command | {
"command": "sed -n 440,520p fastapi/routing.py"
} | {"status": "ok", "stdout": " *,\n response_model: Any = Default(None),\n status_code: Optional[int] = None,\n tags: Optional[List[Union[str, Enum]]] = None,\n dfull{"status": "ok", "stdout": " *,\n response_model: Any = Default(None),\n status_code: Optional[int] = None,\n tags: Optional[List[Union[str, Enum]]] = None,\n dependencies: Optional[Sequence[params.Depends]] = None,\n summary: Optional[str] = None,\n description: Optional[str] = None,\n response_description: str = \"Successful Response\",\n responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,\n deprecated: Optional[bool] = None,\n name: Optional[str] = None,\n methods: Optional[Union[Set[str], List[str]]] = None,\n operation_id: Optional[str] = None,\n response_model_include: Optional[IncEx] = None,\n response_model_exclude: Optional[IncEx] = None,\n response_model_by_alias: bool = True,\n response_model_exclude_unset: bool = False,\n response_model_exclude_defaults: bool = False,\n response_model_exclude_none: bool = False,\n include_in_schema: bool = True,\n response_class: Union[Type[Response], DefaultPlaceholder] = Default(\n JSONResponse\n ),\n dependency_overrides_provider: Optional[Any] = None,\n callbacks: Optional[List[BaseRoute]] = None,\n openapi_extra: Optional[Dict[str, Any]] = None,\n generate_unique_id_function: Union[\n Callable[[\"APIRoute\"], str], DefaultPlaceholder\n ] = Default(generate_unique_id),\n ) -> None:\n self.path = path\n self.endpoint = endpoint\n if isinstance(response_model, DefaultPlaceholder):\n return_annotation = get_typed_return_annotation(endpoint)\n if lenient_issubclass(return_annotation, Response):\n response_model = None\n else:\n response_model = return_annotation\n self.response_model = response_model\n self.summary = summary\n self.response_description = response_description\n self.depr |
| 7 | run_command | {
"command": "grep -n \"def get_typed_return_annotation\" -A 15 fastapi/utils.py"
} | {"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 8 | run_command | {
"command": "grep -rn \"def get_typed_return_annotation\" fastapi/"
} | {"status": "ok", "stdout": "fastapi/dependencies/utils.py:260:def get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n", "exit_code": 0}full{"status": "ok", "stdout": "fastapi/dependencies/utils.py:260:def get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n", "exit_code": 0} |
| 9 | run_command | {
"command": "sed -n 250,280p fastapi/dependencies/utils.py"
} | {"status": "ok", "stdout": " return typed_signature\n\n\ndef get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n if isinstance(annotation,full{"status": "ok", "stdout": " return typed_signature\n\n\ndef get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n if isinstance(annotation, str):\n annotation = ForwardRef(annotation)\n annotation = evaluate_forwardref(annotation, globalns, globalns)\n return annotation\n\n\ndef get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n signature = inspect.signature(call)\n annotation = signature.return_annotation\n\n if annotation is inspect.Signature.empty:\n return None\n\n globalns = getattr(call, \"__globals__\", {})\n return get_typed_annotation(annotation, globalns)\n\n\ndef get_dependant(\n *,\n path: str,\n call: Callable[..., Any],\n name: Optional[str] = None,\n security_scopes: Optional[List[str]] = None,\n use_cache: bool = True,\n) -> Dependant:\n path_param_names = get_path_param_names(path)\n endpoint_signature = get_typed_signature(call)\n", "exit_code": 0} |
| 10 | run_command | {
"command": "cat tests/test_response_code_no_body.py"
} | {"status": "ok", "stdout": "import typing\n\nfrom fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\full{"status": "ok", "stdout": "import typing\n\nfrom fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass JsonApiResponse(JSONResponse):\n media_type = \"application/vnd.api+json\"\n\n\nclass Error(BaseModel):\n status: str\n title: str\n\n\nclass JsonApiError(BaseModel):\n errors: typing.List[Error]\n\n\n@app.get(\n \"/a\",\n status_code=204,\n response_class=JsonApiResponse,\n responses={500: {\"description\": \"Error\", \"model\": JsonApiError}},\n)\nasync def a():\n pass\n\n\n@app.get(\"/b\", responses={204: {\"description\": \"No Content\"}})\nasync def b():\n pass # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_get_response():\n response = client.get(\"/a\")\n assert response.status_code == 204, response.text\n assert \"content-length\" not in response.headers\n assert response.content == b\"\"\n\n\ndef test_openapi_schema():\n response = client.get(\"/openapi.json\")\n assert response.status_code == 200, response.text\n assert response.json() == {\n \"openapi\": \"3.1.0\",\n \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n \"paths\": {\n \"/a\": {\n \"get\": {\n \"responses\": {\n \"500\": {\n \"description\": \"Error\",\n \"content\": {\n \"application/vnd.api+json\": {\n \"schema\": {\n \"$ref\": \"#/components/schemas/JsonApiError\"\n }\n }\n },\n },\n \"204\": {\"description\": \"Successful Response\"},\n },\n \"summary\": \"A\",\n |
| 11 | run_command | {
"command": "grep -rn \"get_openapi_operation_path_response\" fastapi/openapi/utils.py | head; grep -n \"def get_openapi_operation_path_response\" -A 40 fastapi/openapi/utils.py"
} | {"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 12 | run_command | {
"command": "git log --oneline -5 && git status"
} | {"status": "ok", "stdout": "2a215a23 baseline\n8704f855 \ud83d\udcdd Update release notes\n3d404f10 \ud83d\udc1b Fix inconsistent processing of model docstring full{"status": "ok", "stdout": "2a215a23 baseline\n8704f855 \ud83d\udcdd Update release notes\n3d404f10 \ud83d\udc1b Fix inconsistent processing of model docstring formfeed char with Pydantic V1 (#6039)\nfc3254fc \ud83d\udcdd Update release notes\ne170329a \ud83d\udc1b Fix `jsonable_encoder` alters `json_encoders` of Pydantic v1 objects (#4972)\nOn branch main\nnothing to commit, working tree clean\n", "exit_code": 0} |
| 13 | run_command | {
"command": "cat > /tmp/repro.py <<'EOF'\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n@app.get(\"/a\", status_code=204)\nasync def a() -> None:\n pass\n\nclient = TestClient(app)\nresponse = client.get(\"/a\")\nprint(response.status_code, response.content)\nEOF\npython3 /tmp/repro.py"
} | {"status": "ok", "stdout": "204 b''\n", "exit_code": 0}full{"status": "ok", "stdout": "204 b''\n", "exit_code": 0} |
| 14 | run_command | {
"command": "cat > /tmp/repro2.py <<'EOF'\nimport json\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n@app.get(\"/a\", status_code=204)\nasync def a() -> None:\n pass\n\nclient = TestClient(app)\nprint(json.dumps(client.get(\"/openapi.json\").json(), indent=1))\nEOF\npython3 /tmp/repro2.py"
} | {"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"FastAPI\",\n \"version\": \"0.1.0\"\n },\n \"paths\": {\n \"/a\": {\n \"getfull{"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"FastAPI\",\n \"version\": \"0.1.0\"\n },\n \"paths\": {\n \"/a\": {\n \"get\": {\n \"summary\": \"A\",\n \"operationId\": \"a_a_get\",\n \"responses\": {\n \"204\": {\n \"description\": \"Successful Response\"\n }\n }\n }\n }\n }\n}\n", "exit_code": 0} |
| 15 | run_command | {
"command": "cat fastapi/__init__.py | head -20; python3 -c \"import fastapi; print(fastapi.__version__)\""
} | {"status": "ok", "stdout": "\"\"\"FastAPI framework, high performance, easy to learn, fast to code, ready for production\"\"\"\n\n__version__ = \"0.116.2\"\n\nffull{"status": "ok", "stdout": "\"\"\"FastAPI framework, high performance, easy to learn, fast to code, ready for production\"\"\"\n\n__version__ = \"0.116.2\"\n\nfrom starlette import status as status\n\nfrom .applications import FastAPI as FastAPI\nfrom .background import BackgroundTasks as BackgroundTasks\nfrom .datastructures import UploadFile as UploadFile\nfrom .exceptions import HTTPException as HTTPException\nfrom .exceptions import WebSocketException as WebSocketException\nfrom .param_functions import Body as Body\nfrom .param_functions import Cookie as Cookie\nfrom .param_functions import Depends as Depends\nfrom .param_functions import File as File\nfrom .param_functions import Form as Form\nfrom .param_functions import Header as Header\nfrom .param_functions import Path as Path\nfrom .param_functions import Query as Query\nfrom .param_functions import Security as Security\n0.116.2\n", "exit_code": 0} |
| 16 | run_command | {
"command": "grep -rn \"lenient_issubclass\" fastapi/utils.py | head -5; grep -n \"def lenient_issubclass\" -A 10 fastapi/utils.py"
} | {"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "fastapi/utils.py:26: lenient_issubcfull{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "fastapi/utils.py:26: lenient_issubclass,\nfastapi/utils.py:125: if lenient_issubclass(original_type, BaseModel):\n", "stderr": "", "exit_code": 1}} |
| 17 | run_command | {
"command": "grep -n \"def get_openapi_operation_path_response\" -A 60 fastapi/openapi/utils.py"
} | {"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 18 | run_command | {
"command": "grep -n \"def \" fastapi/openapi/utils.py | head -40"
} | {"status": "ok", "stdout": "77:def get_openapi_security_definitions(\n94:def _get_openapi_operation_parameters(\n169:def get_openapi_operation_request_body(\n20full{"status": "ok", "stdout": "77:def get_openapi_security_definitions(\n94:def _get_openapi_operation_parameters(\n169:def get_openapi_operation_request_body(\n206:def generate_operation_id(\n221:def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:\n227:def get_openapi_operation_metadata(\n253:def get_openapi_path(\n445:def get_fields_from_routes(\n476:def get_openapi(\n", "exit_code": 0} |
| 19 | run_command | {
"command": "sed -n 253,445p fastapi/openapi/utils.py"
} | {"status": "ok", "stdout": "def get_openapi_path(\n *,\n route: routing.APIRoute,\n operation_ids: Set[str],\n schema_generator: GenerateJsonSchema,\n model_namfull{"status": "ok", "stdout": "def get_openapi_path(\n *,\n route: routing.APIRoute,\n operation_ids: Set[str],\n schema_generator: GenerateJsonSchema,\n model_name_map: ModelNameMap,\n field_mapping: Dict[\n Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n ],\n separate_input_output_schemas: bool = True,\n) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:\n path = {}\n security_schemes: Dict[str, Any] = {}\n definitions: Dict[str, Any] = {}\n assert route.methods is not None, \"Methods must be a list\"\n if isinstance(route.response_class, DefaultPlaceholder):\n current_response_class: Type[Response] = route.response_class.value\n else:\n current_response_class = route.response_class\n assert current_response_class, \"A response class is needed to generate OpenAPI\"\n route_response_media_type: Optional[str] = current_response_class.media_type\n if route.include_in_schema:\n for method in route.methods:\n operation = get_openapi_operation_metadata(\n route=route, method=method, operation_ids=operation_ids\n )\n parameters: List[Dict[str, Any]] = []\n flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)\n security_definitions, operation_security = get_openapi_security_definitions(\n flat_dependant=flat_dependant\n )\n if operation_security:\n operation.setdefault(\"security\", []).extend(operation_security)\n if security_definitions:\n security_schemes.update(security_definitions)\n operation_parameters = _get_openapi_operation_parameters(\n dependant=route.dependant,\n schema_generator=schema_generator,\n model_name_map=model_name_map,\n field_mapping=field_mapping,\n separate_input_output_schemas=sepa |
| 20 | run_command | {
"command": "sed -n 400,445p fastapi/openapi/utils.py"
} | {"status": "ok", "stdout": " media_type = route_response_media_type or \"application/json\"\n additional_schema = (\n process_response.setdefault(\"content\", {full{"status": "ok", "stdout": " media_type = route_response_media_type or \"application/json\"\n additional_schema = (\n process_response.setdefault(\"content\", {})\n .setdefault(media_type, {})\n .setdefault(\"schema\", {})\n )\n deep_dict_update(additional_schema, additional_field_schema)\n status_text: Optional[str] = status_code_ranges.get(\n str(additional_status_code).upper()\n ) 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 = \"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 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 },\n }\n if \"ValidationError\" not in definitions:\n definitions.update(\n {\n \"ValidationError\": validation_error_definition,\n \"HTTP |
| 21 | run_command | {
"command": "sed -n 355,400p fastapi/openapi/utils.py"
} | {"status": "ok", "stdout": " ):\n response_schema = {\"type\": \"string\"}\n if lenient_issubclass(current_response_class, JSONResponse):\n if route.response_fifull{"status": "ok", "stdout": " ):\n response_schema = {\"type\": \"string\"}\n if lenient_issubclass(current_response_class, JSONResponse):\n if route.response_field:\n response_schema = get_schema_from_model_field(\n field=route.response_field,\n schema_generator=schema_generator,\n model_name_map=model_name_map,\n field_mapping=field_mapping,\n separate_input_output_schemas=separate_input_output_schemas,\n )\n else:\n response_schema = {}\n operation.setdefault(\"responses\", {}).setdefault(\n status_code, {}\n ).setdefault(\"content\", {}).setdefault(route_response_media_type, {})[\n \"schema\"\n ] = response_schema\n if route.responses:\n operation_responses = operation.setdefault(\"responses\", {})\n for (\n additional_status_code,\n additional_response,\n ) in route.responses.items():\n process_response = additional_response.copy()\n process_response.pop(\"model\", None)\n status_code_key = str(additional_status_code).upper()\n if status_code_key == \"DEFAULT\":\n status_code_key = \"default\"\n openapi_response = operation_responses.setdefault(\n status_code_key, {}\n )\n assert isinstance(process_response, dict), (\n \"An additional response must be a dict\"\n )\n field = route.response_fields.get(additional_status_code)\n additional_field_schema: Optiona |
| 22 | run_command | {
"command": "sed -n 330,356p fastapi/openapi/utils.py"
} | {"status": "ok", "stdout": " schema_generator=schema_generator,\n model_name_map=model_name_map,\n field_mapping=field_mapping,\n separate_input_output_schemas=full{"status": "ok", "stdout": " schema_generator=schema_generator,\n model_name_map=model_name_map,\n field_mapping=field_mapping,\n separate_input_output_schemas=separate_input_output_schemas,\n )\n callbacks[callback.name] = {callback.path: cb_path}\n operation[\"callbacks\"] = callbacks\n if route.status_code is not None:\n status_code = str(route.status_code)\n else:\n # It would probably make more sense for all response classes to have an\n # explicit default status_code, and to extract it from them, instead of\n # doing this inspection tricks, that would probably be in the future\n # TODO: probably make status_code a default class attribute for all\n # responses in Starlette\n response_signature = inspect.signature(current_response_class.__init__)\n status_code_param = response_signature.parameters.get(\"status_code\")\n if status_code_param is not None:\n if isinstance(status_code_param.default, int):\n status_code = str(status_code_param.default)\n operation.setdefault(\"responses\", {}).setdefault(status_code, {})[\n \"description\"\n ] = route.response_description\n if route_response_media_type and is_body_allowed_for_status_code(\n route.status_code\n ):\n response_schema = {\"type\": \"string\"}\n", "exit_code": 0} |
| 23 | run_command | {
"command": "cd /private/workspace && PYTHONPATH=/private/workspace python3 /tmp/repro.py; echo \"exit: $?\""
} | {"status": "ok", "stdout": "exit: 1\n", "exit_code": 0}full{"status": "ok", "stdout": "exit: 1\n", "exit_code": 0} |
| 24 | run_command | {
"command": "cd /private/workspace && PYTHONPATH=/private/workspace python3 /tmp/repro.py 2>&1 | tail -20"
} | {"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "/bin/bash: line 0: cdfull{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "/bin/bash: line 0: cd: /private/workspace: No such file or directory\n", "exit_code": 1}} |
| 25 | run_command | {
"command": "pwd; ls fastapi/routing.py"
} | {"status": "ok", "stdout": "/private/workspace\nfastapi/routing.py\n", "exit_code": 0}full{"status": "ok", "stdout": "/private/workspace\nfastapi/routing.py\n", "exit_code": 0} |
| 26 | run_command | {
"command": "python3 /tmp/repro.py 2>&1 | tail -25"
} | {"status": "ok", "stdout": "204 b''\n", "exit_code": 0}full{"status": "ok", "stdout": "204 b''\n", "exit_code": 0} |
| 27 | run_command | {
"command": "cat > /tmp/repro3.py <<'EOF'\nfrom __future__ import annotations\nimport json\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n@app.get(\"/a\", status_code=204)\nasync def a() -> None:\n pass\n\nclient = TestClient(app)\nprint(\"status:\", client.get(\"/a\").status_code)\nprint(json.dumps(client.get(\"/openapi.json\").json(), indent=1))\nEOF\npython3 /tmp/repro3.py 2>&1 | tail -30"
} | {"status": "ok", "stdout": "Traceback (most recent call last):\n File \"/tmp/swe_work/or20_qwen27b_v2/fastapi_9425/a/tmp/repro3.py\", line 8, in <module>\n @appfull{"status": "ok", "stdout": "Traceback (most recent call last):\n File \"/tmp/swe_work/or20_qwen27b_v2/fastapi_9425/a/tmp/repro3.py\", line 8, in <module>\n @app.get(\"/a\", status_code=204)\n ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^\n File \"/workspace/fastapi/routing.py\", line 1001, in decorator\n self.add_api_route(\n ~~~~~~~~~~~~~~~~~~^\n path,\n ^^^^^\n ...<23 lines>...\n generate_unique_id_function=generate_unique_id_function,\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n )\n ^\n File \"/workspace/fastapi/routing.py\", line 940, in add_api_route\n route = route_class(\n self.prefix + path,\n ...<24 lines>...\n generate_unique_id_function=current_generate_unique_id,\n )\n File \"/workspace/fastapi/routing.py\", line 514, in __init__\n assert is_body_allowed_for_status_code(status_code), (\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^\nAssertionError: Status code 204 must not have a response body\n", "exit_code": 0} |
| 28 | run_command | {
"command": "cat > /tmp/dbg.py <<'EOF'\nfrom __future__ import annotations\nfrom fastapi.dependencies.utils import get_typed_return_annotation\n\nasync def a() -> None:\n pass\n\nann = get_typed_return_annotation(a)\nprint(repr(ann), type(ann))\nEOF\npython3 /tmp/dbg.py"
} | {"status": "ok", "stdout": "<class 'NoneType'> <class 'type'>\n", "exit_code": 0}full{"status": "ok", "stdout": "<class 'NoneType'> <class 'type'>\n", "exit_code": 0} |
| 29 | edit_file | {
"filepath": "fastapi/dependencies/utils.py",
"old_string": " globalns = getattr(call, \"__globals__\", {})\n return get_typed_annotation(annotation, globalns)",
"new_string": " globalns = getattr(call, \"__globals__\", {})\n annotation = get_typed_annotation(annotation, globalns)\n if annotation is type(None):\n return None\n return annotation"
} | {"status": "ok", "filepath": "fastapi/dependencies/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/dependencies/utils.py\n+++ b/fastapifull{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/dependencies/utils.py\n+++ b/fastapi/dependencies/utils.py\n@@ -265,7 +265,10 @@\n return None\n \n globalns = getattr(call, \"__globals__\", {})\n- return get_typed_annotation(annotation, globalns)\n+ annotation = get_typed_annotation(annotation, globalns)\n+ if annotation is type(None):\n+ return None\n+ return annotation\n \n \n def get_dependant(\n", "is_truncated": false} |
| 30 | run_command | {
"command": "python3 /tmp/repro3.py 2>&1 | tail -30 && python3 /tmp/repro.py && python3 /tmp/repro2.py"
} | {"status": "ok", "stdout": "status: 204\n{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"FastAPI\",\n \"version\": \"0.1.0\"\n },\n \"paths\": {\n \"/afull{"status": "ok", "stdout": "status: 204\n{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"FastAPI\",\n \"version\": \"0.1.0\"\n },\n \"paths\": {\n \"/a\": {\n \"get\": {\n \"summary\": \"A\",\n \"operationId\": \"a_a_get\",\n \"responses\": {\n \"204\": {\n \"description\": \"Successful Response\"\n }\n }\n }\n }\n }\n}\n204 b''\n{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"FastAPI\",\n \"version\": \"0.1.0\"\n },\n \"paths\": {\n \"/a\": {\n \"get\": {\n \"summary\": \"A\",\n \"operationId\": \"a_a_get\",\n \"responses\": {\n \"204\": {\n \"description\": \"Successful Response\"\n }\n }\n }\n }\n }\n}\n", "exit_code": 0} |
| 31 | run_command | {
"command": "sed -n 260,275p fastapi/dependencies/utils.py"
} | {"status": "ok", "stdout": "def get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n signature = inspect.signature(call)\n annotation = signature.retfull{"status": "ok", "stdout": "def get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n signature = inspect.signature(call)\n annotation = signature.return_annotation\n\n if annotation is inspect.Signature.empty:\n return None\n\n globalns = getattr(call, \"__globals__\", {})\n annotation = get_typed_annotation(annotation, globalns)\n if annotation is type(None):\n return None\n return annotation\n\n\ndef get_dependant(\n *,\n", "exit_code": 0} |
| 32 | run_command | {
"command": "python3 -m pytest tests/test_response_code_no_body.py tests/test_response_model_as_return_annotation.py tests/test_response_change_status_code.py -q 2>&1 | tail -20"
} | {"status": "ok", "stdout": "......................................... [100%]\n=============================== warnings summary ===============================\nfull{"status": "ok", "stdout": "......................................... [100%]\n=============================== warnings summary ===============================\n../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.48.0-py3-none-any/starlette/testclient.py:51\n /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.48.0-py3-none-any/starlette/testclient.py:51: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.\n _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n41 passed, 1 warning in 0.42s\n", "exit_code": 0} |
| 33 | run_command | {
"command": "python3 -m pytest tests/test_typing_python39.py tests/test_annotated.py tests/test_openapi_schema_type.py tests/test_response_model_sub_types.py -q 2>&1 | tail -5"
} | {"status": "ok", "stdout": " /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.48.0-py3-none-any/starlette/testclient.py:51: Dfull{"status": "ok", "stdout": " /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.48.0-py3-none-any/starlette/testclient.py:51: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.\n _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n20 passed, 1 warning in 0.39s\n", "exit_code": 0} |
| 34 | run_command | {
"command": "git diff && git status --short"
} | {"status": "ok", "stdout": "diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py\nindex 8dd0a14c..565ce21f 100644\n--- a/fastapi/dependencfull{"status": "ok", "stdout": "diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py\nindex 8dd0a14c..565ce21f 100644\n--- a/fastapi/dependencies/utils.py\n+++ b/fastapi/dependencies/utils.py\n@@ -265,7 +265,10 @@ def get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n return None\n \n globalns = getattr(call, \"__globals__\", {})\n- return get_typed_annotation(annotation, globalns)\n+ annotation = get_typed_annotation(annotation, globalns)\n+ if annotation is type(None):\n+ return None\n+ return annotation\n \n \n def get_dependant(\n M fastapi/dependencies/utils.py\n", "exit_code": 0} |
| 35 | submit_patch | [] | {"status": "ok", "patch_size": 556, "files_changed": 1}full{"status": "ok", "patch_size": 556, "files_changed": 1} |
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index 8dd0a14c..565ce21f 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -265,7 +265,10 @@ def get_typed_return_annotation(call: Callable[..., Any]) -> Any:
return None
globalns = getattr(call, "__globals__", {})
- return get_typed_annotation(annotation, globalns)
+ annotation = get_typed_annotation(annotation, globalns)
+ if annotation is type(None):
+ return None
+ return annotation
def get_dependant(
. [100%]
=============================== warnings summary ===============================
../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.48.0-py3-none-any/starlette/testclient.py:51
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.48.0-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
1 passed, 1 warning in 0.40s