← baseline_full_v2

fastapi_14794

failed NO_PATCH NO_PATCH UNSUBMITTED empty_patch(None) · None tool calls · 0 s · fastapi/fastapi

Task input

✨ 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 calls (0)

#ToolArgumentsResult
No trace captured.

Test output

show
dify_response(response: Response) -> Response:
            response.headers["X-Custom"] = "modified"
            return response
    
>       @app.get("/")
         ^^^^^^^^^^^^

tests/test_response_dependency.py:22: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
fastapi/routing.py:1063: in decorator
    self.add_api_route(
fastapi/routing.py:1002: in add_api_route
    route = route_class(
fastapi/routing.py:621: in __init__
    self.dependant = get_dependant(
fastapi/dependencies/utils.py:281: in get_dependant
    param_details = analyze_param(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

param_name = 'response'
annotation = typing.Annotated[starlette.responses.Response, Depends(dependency=<function test_response_with_depends_annotated.<locals>.modify_response at 0x10771bf60>, use_cache=True, scope=None)]
value = <class 'inspect._empty'>, is_path_param = False

    def analyze_param(
        *,
        param_name: str,
        annotation: Any,
        value: Any,
        is_path_param: bool,
    ) -> ParamDetails:
        field_info = None
        depends = None
        type_annotation: Any = Any
        use_annotation: Any = Any
        if annotation is not inspect.Signature.empty:
            use_annotation = annotation
            type_annotation = annotation
        # Extract Annotated info
        if get_origin(use_annotation) is Annotated:
            annotated_args = get_args(annotation)
            type_annotation = annotated_args[0]
            fastapi_annotations = [
                arg
                for arg in annotated_args[1:]
                if isinstance(arg, (FieldInfo, params.Depends))
            ]
            fastapi_specific_annotations = [
                arg
                for arg in fastapi_annotations
                if isinstance(
                    arg,
                    (
                        params.Param,
                        params.Body,
                        params.Depends,
                    ),
                )
            ]
            if fastapi_specific_annotations:
                fastapi_annotation: Union[FieldInfo, params.Depends, None] = (
                    fastapi_specific_annotations[-1]
                )
            else:
                fastapi_annotation = None
            # Set default for Annotated FieldInfo
            if isinstance(fastapi_annotation, FieldInfo):
                # Copy `field_info` because we mutate `field_info.default` below.
                field_info = copy_field_info(
                    field_info=fastapi_annotation,
                    annotation=use_annotation,
                )
                assert (
                    field_info.default == Undefined or field_info.default == RequiredParam
                ), (
                    f"`{field_info.__class__.__name__}` default value cannot be set in"
                    f" `Annotated` for {param_name!r}. Set the default value with `=` instead."
                )
                if value is not inspect.Signature.empty:
                    assert not is_path_param, "Path parameters cannot have default values"
                    field_info.default = value
                else:
                    field_info.default = RequiredParam
            # Get Annotated Depends
            elif isinstance(fastapi_annotation, params.Depends):
                depends = fastapi_annotation
        # Get Depends from default value
        if isinstance(value, params.Depends):
            assert depends is None, (
                "Cannot specify `Depends` in `Annotated` and default value"
                f" together for {param_name!r}"
            )
            assert field_info is None, (
                "Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a"
                f" default value together for {param_name!r}"
            )
            depends = value
        # Get FieldInfo from default value
        elif isinstance(value, FieldInfo):
            assert field_info is None, (
                "Cannot specify FastAPI annotations in `Annotated` and default value"
                f" together for {param_name!r}"
            )
            field_info = value
            if isinstance(field_info, FieldInfo):
                field_info.annotation = type_annotation
    
        # Get Depends from type annotation
        if depends is not None and depends.dependency is None:
            # Copy `depends` before mutating it
            depends = copy(depends)
            depends = dataclasses.replace(depends, dependency=type_annotation)
    
        # Handle non-param type annotations like Request
        if lenient_issubclass(
            type_annotation,
            (
                Request,
                WebSocket,
                HTTPConnection,
                Response,
                StarletteBackgroundTasks,
                SecurityScopes,
            ),
        ):
>           assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}"
                   ^^^^^^^^^^^^^^^
E           AssertionError: Cannot specify `Depends` for type <class 'starlette.responses.Response'>

fastapi/dependencies/utils.py:463: AssertionError
=============================== warnings summary ===============================
../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45
  /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45: 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
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 1 warning in 0.58s