failed NO_PATCH NO_PATCH UNSUBMITTED agent_error · 9 tool calls · 263 s · fastapi/fastapi
✨ Allow `Response` type hint as dependency annotation
## Summary
Fixes #10127
Using `Response` as a type hint with `Depends` would fail with an assertion error:
```python
def endpoint(response: Annotated[Response, Depends(modify_response)]):
# AssertionError: Cannot specify \`Depends\` for type Response
```
## Changes
Modified the type annotation handling in `analyze_param()` to check for `Depends` before applying special type handling. When a `Depends` is specified, the dependency is called normally and its return value used.
## Usage
Now supports:
- `response: Annotated[Response, Depends(modify_response)]`
- `response: Response = Depends(modify_response)`
While still supporting regular injection:
- `response: Response`
## Testing
Added comprehensive tests in `tests/test_response_dependency.py`| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"Cannot specify\" /workspace/fastapi --include=*.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}} |
| 2 | run_command | {
"command": "grep -rn \"analyze_param\" /workspace/fastapi --include=*.py | head -20"
} | {"status": "ok", "stdout": "", "exit_code": 0}full{"status": "ok", "stdout": "", "exit_code": 0} |
| 3 | run_command | {
"command": "grep -rn \"Cannot specify\" /workspace --include=*.py | head; ls /workspace"
} | {"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_14794/a/workspace: No such file or directory\n", "exit_code": 1}} |
| 4 | run_command | {
"command": "pwd; ls"
} | {"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\nscripts\nSECURITY.md\ntests\nuv.lock\n", "exit_code": 0} |
| 5 | run_command | {
"command": "grep -rn \"Cannot specify\" fastapi --include=*.py | head"
} | {"status": "ok", "stdout": "fastapi/dependencies/utils.py:320: f\"Cannot specify multiple FastAPI annotations for {param_name!r}\"\nfastapi/dependencies/utils.pfull{"status": "ok", "stdout": "fastapi/dependencies/utils.py:320: f\"Cannot specify multiple FastAPI annotations for {param_name!r}\"\nfastapi/dependencies/utils.py:427: \"Cannot specify `Depends` in `Annotated` and default value\"\nfastapi/dependencies/utils.py:431: \"Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a\"\nfastapi/dependencies/utils.py:438: \"Cannot specify FastAPI annotations in `Annotated` and default value\"\nfastapi/dependencies/utils.py:463: assert depends is None, f\"Cannot specify `Depends` for type {type_annotation!r}\"\nfastapi/dependencies/utils.py:465: f\"Cannot specify FastAPI annotation for type {type_annotation!r}\"\n", "exit_code": 0} |
| 6 | read_file | {
"filepath": "fastapi/dependencies/utils.py",
"start_line": 380,
"end_line": 520
} | {"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " fastapi_annotations = [\n arg\n for arg in annotated_args[1:]\n if isinstance(arg, (Ffull{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " fastapi_annotations = [\n arg\n for arg in annotated_args[1:]\n if isinstance(arg, (FieldInfo, params.Depends))\n ]\n fastapi_specific_annotations = [\n arg\n for arg in fastapi_annotations\n if isinstance(\n arg,\n (\n params.Param,\n params.Body,\n params.Depends,\n ),\n )\n ]\n if fastapi_specific_annotations:\n fastapi_annotation: Union[FieldInfo, params.Depends, None] = (\n fastapi_specific_annotations[-1]\n )\n else:\n fastapi_annotation = None\n # Set default for Annotated FieldInfo\n if isinstance(fastapi_annotation, FieldInfo):\n # Copy `field_info` because we mutate `field_info.default` below.\n field_info = copy_field_info(\n field_info=fastapi_annotation,\n annotation=use_annotation,\n )\n assert (\n field_info.default == Undefined or field_info.default == RequiredParam\n ), (\n f\"`{field_info.__class__.__name__}` default value cannot be set in\"\n f\" `Annotated` for {param_name!r}. Set the default value with `=` instead.\"\n )\n if value is not inspect.Signature.empty:\n assert not is_path_param, \"Path parameters cannot have default values\"\n field_info.default = value\n else:\n field_info.default = RequiredParam\n # Get Annotated Depends\n elif isinstance(fastapi_annotation, params.Depends):\n depends = fastapi_annotation\n # Get Depends from default value\n if isinstance(value, params.Depends):\n assert depends is None, (\n \"Cannot specify `De |
| 7 | read_file | {
"filepath": "fastapi/dependencies/utils.py",
"start_line": 520,
"end_line": 640
} | {"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " is_scalar_field(field)\n or is_scalar_sequence_field(field)\n or (\n lenient_issubclafull{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " is_scalar_field(field)\n or is_scalar_sequence_field(field)\n or (\n lenient_issubclass(field.type_, BaseModel)\n # For Pydantic v1\n and getattr(field, \"shape\", 1) == 1\n )\n ), f\"Query parameter {param_name!r} must be one of the supported types\"\n\n return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)\n\n\ndef add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:\n field_info = field.field_info\n field_info_in = getattr(field_info, \"in_\", None)\n if field_info_in == params.ParamTypes.path:\n dependant.path_params.append(field)\n elif field_info_in == params.ParamTypes.query:\n dependant.query_params.append(field)\n elif field_info_in == params.ParamTypes.header:\n dependant.header_params.append(field)\n else:\n assert field_info_in == params.ParamTypes.cookie, (\n f\"non-body parameters must be in path, query, header or cookie: {field.name}\"\n )\n dependant.cookie_params.append(field)\n\n\nasync def _solve_generator(\n *, dependant: Dependant, stack: AsyncExitStack, sub_values: dict[str, Any]\n) -> Any:\n assert dependant.call\n if dependant.is_async_gen_callable:\n cm = asynccontextmanager(dependant.call)(**sub_values)\n elif dependant.is_gen_callable:\n cm = contextmanager_in_threadpool(contextmanager(dependant.call)(**sub_values))\n return await stack.enter_async_context(cm)\n\n\n@dataclass\nclass SolvedDependency:\n values: dict[str, Any]\n errors: list[Any]\n background_tasks: Optional[StarletteBackgroundTasks]\n response: Response\n dependency_cache: dict[DependencyCacheKey, Any]\n\n\nasync def solve_dependencies(\n *,\n request: Union[Request, WebSocket],\n dependant: Dependant, |
| 8 | read_file | {
"filepath": "fastapi/dependencies/utils.py",
"start_line": 640,
"end_line": 760
} | {"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " if sub_dependant.scope == \"function\":\n use_astack = function_astack\n solved = awafull{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " if sub_dependant.scope == \"function\":\n use_astack = function_astack\n solved = await _solve_generator(\n dependant=use_sub_dependant,\n stack=use_astack,\n sub_values=solved_result.values,\n )\n elif use_sub_dependant.is_coroutine_callable:\n solved = await call(**solved_result.values)\n else:\n solved = await run_in_threadpool(call, **solved_result.values)\n if sub_dependant.name is not None:\n values[sub_dependant.name] = solved\n if sub_dependant.cache_key not in dependency_cache:\n dependency_cache[sub_dependant.cache_key] = solved\n path_values, path_errors = request_params_to_args(\n dependant.path_params, request.path_params\n )\n query_values, query_errors = request_params_to_args(\n dependant.query_params, request.query_params\n )\n header_values, header_errors = request_params_to_args(\n dependant.header_params, request.headers\n )\n cookie_values, cookie_errors = request_params_to_args(\n dependant.cookie_params, request.cookies\n )\n values.update(path_values)\n values.update(query_values)\n values.update(header_values)\n values.update(cookie_values)\n errors += path_errors + query_errors + header_errors + cookie_errors\n if dependant.body_params:\n (\n body_values,\n body_errors,\n ) = await request_body_to_args( # body_params checked above\n body_fields=dependant.body_params,\n received_body=body,\n embed_body_fields=embed_body_fields,\n )\n values.update(body_values)\n errors.extend(body_errors)\n if dependant.http_connection_param_name:\n values[dependant.http_connection_param_name] = request\n if dependant.request_param_name and isinstance( |
| 9 | read_file | {
"filepath": "fastapi/dependencies/utils.py",
"start_line": 280,
"end_line": 380
} | {"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " is_path_param = param_name in path_param_names\n param_details = analyze_param(\n parfull{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " is_path_param = param_name in path_param_names\n param_details = analyze_param(\n param_name=param_name,\n annotation=param.annotation,\n value=param.default,\n is_path_param=is_path_param,\n )\n if param_details.depends is not None:\n assert param_details.depends.dependency\n if (\n (dependant.is_gen_callable or dependant.is_async_gen_callable)\n and dependant.computed_scope == \"request\"\n and param_details.depends.scope == \"function\"\n ):\n assert dependant.call\n raise DependencyScopeError(\n f'The dependency \"{dependant.call.__name__}\" has a scope of '\n '\"request\", it cannot depend on dependencies with scope \"function\".'\n )\n sub_own_oauth_scopes: list[str] = []\n if isinstance(param_details.depends, params.Security):\n if param_details.depends.scopes:\n sub_own_oauth_scopes = list(param_details.depends.scopes)\n sub_dependant = get_dependant(\n path=path,\n call=param_details.depends.dependency,\n name=param_name,\n own_oauth_scopes=sub_own_oauth_scopes,\n parent_oauth_scopes=current_scopes,\n use_cache=param_details.depends.use_cache,\n scope=param_details.depends.scope,\n )\n dependant.dependencies.append(sub_dependant)\n continue\n if add_non_field_param_to_dependency(\n param_name=param_name,\n type_annotation=param_details.type_annotation,\n dependant=dependant,\n ):\n assert param_details.field is None, (\n f\"Cannot specify multiple FastAPI annotations for {param_name |