← eval7_submission_v1n

fastapi_14458

failed WRONG_FIX UNSUBMITTED wrong_fix_unsubmitted(budget) · 13 tool calls · 303 s · fastapi/fastapi

Task input

🐛 Fix using class (not instance) dependency that has `__call__` method

As reported in https://github.com/fastapi/fastapi/discussions/14452, FastAPI 0.123.6 introduced a regression - if we use class (not instance) as dependency and this class has `__call__` method that is coroutine or generator, it is mistakenly treated as coroutine\generator (actually class is not coroutine\generator, instance of this class is).


So, to fix this we need to check if the callable is class before inspecting its `dunder_call` in `is_coroutine_callable`, `is_async_gen_callable`, and `is_gen_callable`.

Tool calls (13)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"is_coroutine_callable\" . | head -20"
}
{"status": "ok", "stdout": "./fastapi/dependencies/models.py:154: def is_coroutine_callable(self) -> bool:\n./fastapi/dependencies/utils.py:666: elif use_sub_de
full
{"status": "ok", "stdout": "./fastapi/dependencies/models.py:154:    def is_coroutine_callable(self) -> bool:\n./fastapi/dependencies/utils.py:666:        elif use_sub_dependant.is_coroutine_callable:\n./fastapi/routing.py:305:    is_coroutine = dependant.is_coroutine_callable\n", "stderr": "", "exit_code": 0}
2run_command
{
 "command": "grep -rn \"is_async_gen_callable\" . | head -20"
}
{"status": "ok", "stdout": "./fastapi/dependencies/models.py:130: def is_async_gen_callable(self) -> bool:\n./fastapi/dependencies/models.py:186: if self.is_gen
full
{"status": "ok", "stdout": "./fastapi/dependencies/models.py:130:    def is_async_gen_callable(self) -> bool:\n./fastapi/dependencies/models.py:186:        if self.is_gen_callable or self.is_async_gen_callable:\n./fastapi/dependencies/utils.py:290:                (dependant.is_gen_callable or dependant.is_async_gen_callable)\n./fastapi/dependencies/utils.py:571:    if dependant.is_async_gen_callable:\n./fastapi/dependencies/utils.py:656:            use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable\n", "stderr": "", "exit_code": 0}
3run_command
{
 "command": "grep -rn \"is_gen_callable\" . | head -20"
}
{"status": "ok", "stdout": "./fastapi/dependencies/models.py:106: def is_gen_callable(self) -> bool:\n./fastapi/dependencies/models.py:186: if self.is_gen_calla
full
{"status": "ok", "stdout": "./fastapi/dependencies/models.py:106:    def is_gen_callable(self) -> bool:\n./fastapi/dependencies/models.py:186:        if self.is_gen_callable or self.is_async_gen_callable:\n./fastapi/dependencies/utils.py:290:                (dependant.is_gen_callable or dependant.is_async_gen_callable)\n./fastapi/dependencies/utils.py:573:    elif dependant.is_gen_callable:\n./fastapi/dependencies/utils.py:656:            use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable\n", "stderr": "", "exit_code": 0}
4run_command
{
 "command": "cat fastapi/dependencies/models.py"
}
{"status": "ok", "stdout": "import inspect\nimport sys\nfrom dataclasses import dataclass, field\nfrom functools import cached_property, partial\nfrom typing im
full
{"status": "ok", "stdout": "import inspect\nimport sys\nfrom dataclasses import dataclass, field\nfrom functools import cached_property, partial\nfrom typing import Any, Callable, List, Optional, Union\n\nfrom fastapi._compat import ModelField\nfrom fastapi.security.base import SecurityBase\nfrom fastapi.types import DependencyCacheKey\nfrom typing_extensions import Literal\n\nif sys.version_info >= (3, 13):  # pragma: no cover\n    from inspect import iscoroutinefunction\nelse:  # pragma: no cover\n    from asyncio import iscoroutinefunction\n\n\ndef _unwrapped_call(call: Optional[Callable[..., Any]]) -> Any:\n    if call is None:\n        return call  # pragma: no cover\n    unwrapped = inspect.unwrap(_impartial(call))\n    return unwrapped\n\n\ndef _impartial(func: Callable[..., Any]) -> Callable[..., Any]:\n    while isinstance(func, partial):\n        func = func.func\n    return func\n\n\n@dataclass\nclass Dependant:\n    path_params: List[ModelField] = field(default_factory=list)\n    query_params: List[ModelField] = field(default_factory=list)\n    header_params: List[ModelField] = field(default_factory=list)\n    cookie_params: List[ModelField] = field(default_factory=list)\n    body_params: List[ModelField] = field(default_factory=list)\n    dependencies: List[\"Dependant\"] = field(default_factory=list)\n    name: Optional[str] = None\n    call: Optional[Callable[..., Any]] = None\n    request_param_name: Optional[str] = None\n    websocket_param_name: Optional[str] = None\n    http_connection_param_name: Optional[str] = None\n    response_param_name: Optional[str] = None\n    background_tasks_param_name: Optional[str] = None\n    security_scopes_param_name: Optional[str] = None\n    own_oauth_scopes: Optional[List[str]] = None\n    parent_oauth_scopes: Optional[List[str]] = None\n    use_cache: bool = True\n    path: Optional[str] = None\n    scope: Union[Literal[\"function\", \"request\"], None] = None\n\n    @cached_property\n    def oauth_scopes(self)
5run_command
{
 "command": "sed -n '100,200p' fastapi/dependencies/models.py"
}
{"status": "ok", "stdout": " @cached_property\n def _security_dependencies(self) -> List[\"Dependant\"]:\n security_deps = [dep for dep in self.dependencies if
full
{"status": "ok", "stdout": "    @cached_property\n    def _security_dependencies(self) -> List[\"Dependant\"]:\n        security_deps = [dep for dep in self.dependencies if dep._is_security_scheme]\n        return security_deps\n\n    @cached_property\n    def is_gen_callable(self) -> bool:\n        if self.call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(self.call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):\n            return True\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False\n\n    @cached_property\n    def is_async_gen_callable(self) -> bool:\n        if self.call is None:\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(self.call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)):\n            return True\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(dunder_call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrap
6run_command
{
 "command": "cat <<EOF > /tmp/repro.py\nimport inspect\nimport asyncio\nfrom fastapi.dependencies.models import Dependant\n\nclass MyDependency:\n    async def __call__(self):\n        yield \"hello\"\n\ndef test_is_coroutine_callable():\n    # Case 1: Instance of class with __call__ (should be True)\n    dep_instance = Dependant(call=MyDependency())\n    print(f\"Instance is_coroutine_callable: {dep_instance.is_coroutine_callable}\")\n    \n    # Case 2: Class itself with __call__ (should be False, because the class is not a coroutine, its instance is)\n    dep_class = Dependant(call=MyDependency)\n    print(f\"Class is_coroutine_callable: {dep_class.is_coroutine_callable}\")\n\nclass MyGenDependency:\n    def __call__(self):\n        yield \"hello\"\n\ndef test_is_gen_callable():\n    # Case 1: Instance of class with __call__ (should be True)\n    dep_instance = Dependant(call=MyGenDependency())\n    print(f\"Instance is_gen_callable: {dep_instance.is_gen_callable}\")\n    \n    # Case 2: Class itself with __call__ (should be False)\n    dep_class = Dependant(call=MyGenDependency)\n    print(f\"Class is_gen_callable: {dep_class.is_gen_callable}\")\n\nclass MyAsyncGenDependency:\n    async def __call__(self):\n        yield \"hello\"\n\ndef test_is_async_gen_callable():\n    # Case 1: Instance of class with __call__ (should be True)\n    dep_instance = Dependant(call=MyAsyncGenDependency())\n    print(f\"Instance is_async_gen_callable: {dep_instance.is_async_gen_callable}\")\n    \n    # Case 2: Class itself with __call__ (should be False)\n    dep_class = Dependant(call=MyAsyncGenDependency)\n    print(f\"Class is_async_gen_callable: {dep_class.is_async_gen_callable}\")\n\nif __name__ == \"__main__\":\n    print(\"Testing is_coroutine_callable:\")\n    test_is_coroutine_callable()\n    print(\"\\nTesting is_gen_callable:\")\n    test_is_gen_callable()\n    print(\"\\nTesting is_async_gen_callable:\")\n    test_is_async_gen_callable()\nEOF\npython3 /tmp/repro.py\n"
}
{"status": "ok", "stdout": "Testing is_coroutine_callable:\nInstance is_coroutine_callable: False\nClass is_coroutine_callable: False\n\nTesting is_gen_callable
full
{"status": "ok", "stdout": "Testing is_coroutine_callable:\nInstance is_coroutine_callable: False\nClass is_coroutine_callable: False\n\nTesting is_gen_callable:\nInstance is_gen_callable: True\nClass is_gen_callable: True\n\nTesting is_async_gen_callable:\nInstance is_async_gen_callable: True\nClass is_async_gen_callable: True\n", "stderr": "", "exit_code": 0}
7run_command
{
 "command": "cat <<EOF > /tmp/repro.py\nimport inspect\nimport asyncio\nfrom fastapi.dependencies.models import Dependant\n\nclass MyCoroutineDependency:\n    async def __call__(self):\n        return \"hello\"\n\ndef test_is_coroutine_callable():\n    # Case 1: Instance of class with __call__ (should be True)\n    dep_instance = Dependant(call=MyCoroutineDependency())\n    print(f\"Instance is_coroutine_callable: {dep_instance.is_coroutine_callable}\")\n    \n    # Case 2: Class itself with __call__ (should be False)\n    dep_class = Dependant(call=MyCoroutineDependency)\n    print(f\"Class is_coroutine_callable: {dep_class.is_coroutine_callable}\")\n\nclass MyGenDependency:\n    def __call__(self):\n        yield \"hello\"\n\ndef test_is_gen_callable():\n    # Case 1: Instance of class with __call__ (should be True)\n    dep_instance = Dependant(call=MyGenDependency())\n    print(f\"Instance is_gen_callable: {dep_instance.is_gen_callable}\")\n    \n    # Case 2: Class itself with __call__ (should be False)\n    dep_class = Dependant(call=MyGenDependency)\n    print(f\"Class is_gen_callable: {dep_class.is_gen_callable}\")\n\nclass MyAsyncGenDependency:\n    async def __call__(self):\n        yield \"hello\"\n\ndef test_is_async_gen_callable():\n    # Case 1: Instance of class with __call__ (should be True)\n    dep_instance = Dependant(call=MyAsyncGenDependency())\n    print(f\"Instance is_async_gen_callable: {dep_instance.is_async_gen_callable}\")\n    \n    # Case 2: Class itself with __call__ (should be False)\n    dep_class = Dependant(call=MyAsyncGenDependency)\n    print(f\"Class is_async_gen_callable: {dep_class.is_async_gen_callable}\")\n\nif __name__ == \"__main__\":\n    print(\"Testing is_coroutine_callable:\")\n    test_is_coroutine_callable()\n    print(\"\\nTesting is_gen_callable:\")\n    test_is_gen_callable()\n    print(\"\\nTesting is_async_gen_callable:\")\n    test_is_async_gen_callable()\nEOF\npython3 /tmp/repro.py\n"
}
{"status": "ok", "stdout": "Testing is_coroutine_callable:\nInstance is_coroutine_callable: True\nClass is_coroutine_callable: True\n\nTesting is_gen_callable:\
full
{"status": "ok", "stdout": "Testing is_coroutine_callable:\nInstance is_coroutine_callable: True\nClass is_coroutine_callable: True\n\nTesting is_gen_callable:\nInstance is_gen_callable: True\nClass is_gen_callable: True\n\nTesting is_async_gen_callable:\nInstance is_async_gen_callable: True\nClass is_async_gen_callable: True\n", "stderr": "", "exit_code": 0}
8edit_file
{
 "filepath": "fastapi/dependencies/models.py",
 "new_string": "        dunder_call = getattr(_impartial(self.call), \\\"__call__\\\", None)  # noqa: B004\n        if dunder_call is None or inspect.isclass(_impartial(self.call)):\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \\\"__call__\\\", None)  # noqa: B004\n        if dunder_unwrapped_call is None or inspect.isclass(_unwrapped_call(self.call)):\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False",
 "old_string": "        dunder_call = getattr(_impartial(self.call), \\\"__call__\\\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \\\"__call__\\\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False"
}
{"status": "error", "error_type": "FileEditError", "error_message": "Failed to replace: old_string not found. Ensure you're not escaping content incorrectly and
full
{"status": "error", "error_type": "FileEditError", "error_message": "Failed to replace: old_string not found. Ensure you're not escaping content incorrectly and check whitespace, indentation, and context."}
9run_command
{
 "command": "sed -n '100,130p' fastapi/dependencies/models.py"
}
{"status": "ok", "stdout": " @cached_property\n def _security_dependencies(self) -> List[\"Dependant\"]:\n security_deps = [dep for dep in self.dependencies if
full
{"status": "ok", "stdout": "    @cached_property\n    def _security_dependencies(self) -> List[\"Dependant\"]:\n        security_deps = [dep for dep in self.dependencies if dep._is_security_scheme]\n        return security_deps\n\n    @cached_property\n    def is_gen_callable(self) -> bool:\n        if self.call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(self.call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):\n            return True\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False\n\n    @cached_property\n    def is_async_gen_callable(self) -> bool:\n", "stderr": "", "exit_code": 0}
10edit_file
{
 "filepath": "fastapi/dependencies/models.py",
 "new_string": "        dunder_call = getattr(_impartial(self.call), \\\"__call__\\\", None)  # noqa: B004\n        if dunder_call is None or inspect.isclass(_impartial(self.call)):\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \\\"__call__\\\", None)  # noqa: B004\n        if dunder_unwrapped_call is None or inspect.isclass(_unwrapped_call(self.call)):\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False",
 "old_string": "        dunder_call = getattr(_impartial(self.call), \\\"__call__\\\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \\\"__call__\\\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False"
}
{"status": "error", "error_type": "FileEditError", "error_message": "Failed to replace: old_string not found. Ensure you're not escaping content incorrectly and
full
{"status": "error", "error_type": "FileEditError", "error_message": "Failed to replace: old_string not found. Ensure you're not escaping content incorrectly and check whitespace, indentation, and context."}
11run_command
{
 "command": "cat -A fastapi/dependencies/models.py | sed -n '110,130p'"
}
{"status": "ok", "stdout": " _impartial(self.call)$\n ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):$\n return True$\n dunder_call = getattr(_imp
full
{"status": "ok", "stdout": "            _impartial(self.call)$\n        ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):$\n            return True$\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004$\n        if dunder_call is None:$\n            return False  # pragma: no cover$\n        if inspect.isgeneratorfunction($\n            _impartial(dunder_call)$\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):$\n            return True$\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004$\n        if dunder_unwrapped_call is None:$\n            return False  # pragma: no cover$\n        if inspect.isgeneratorfunction($\n            _impartial(dunder_unwrapped_call)$\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):$\n            return True$\n        return False$\n$\n    @cached_property$\n    def is_async_gen_callable(self) -> bool:$\n", "stderr": "", "exit_code": 0}
12edit_file
{
 "filepath": "fastapi/dependencies/models.py",
 "new_string": "        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None or inspect.isclass(_impartial(self.call)):\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None or inspect.isclass(_unwrapped_call(self.call)):\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False",
 "old_string": "        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False"
}
{"status": "ok", "filepath": "fastapi/dependencies/models.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/dependencies/models.py\n+++ b/fasta
full
{"status": "ok", "filepath": "fastapi/dependencies/models.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/dependencies/models.py\n+++ b/fastapi/dependencies/models.py\n@@ -111,14 +111,14 @@\n         ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):\n             return True\n         dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n-        if dunder_call is None:\n+        if dunder_call is None or inspect.isclass(_impartial(self.call)):\n             return False  # pragma: no cover\n         if inspect.isgeneratorfunction(\n             _impartial(dunder_call)\n         ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n             return True\n         dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n-        if dunder_unwrapped_call is None:\n+        if dunder_unwrapped_call is None or inspect.isclass(_unwrapped_call(self.call)):\n             return False  # pragma: no cover\n         if inspect.isgeneratorfunction(\n             _impartial(dunder_unwrapped_call)\n", "is_truncated": false}
13edit_file
{
 "filepath": "fastapi/dependencies/models.py",
 "new_string": "        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None or inspect.isclass(_impartial(self.call)):\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(dunder_call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None or inspect.isclass(_unwrapped_call(self.call)):\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False",
 "old_string": "        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(dunder_call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False"
}
{"status": "ok", "filepath": "fastapi/dependencies/models.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/dependencies/models.py\n+++ b/fasta
full
{"status": "ok", "filepath": "fastapi/dependencies/models.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/dependencies/models.py\n+++ b/fastapi/dependencies/models.py\n@@ -135,14 +135,14 @@\n         ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)):\n             return True\n         dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n-        if dunder_call is None:\n+        if dunder_call is None or inspect.isclass(_impartial(self.call)):\n             return False  # pragma: no cover\n         if inspect.isasyncgenfunction(\n             _impartial(dunder_call)\n         ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):\n             return True\n         dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n-        if dunder_unwrapped_call is None:\n+        if dunder_unwrapped_call is None or inspect.isclass(_unwrapped_call(self.call)):\n             return False  # pragma: no cover\n         if inspect.isasyncgenfunction(\n             _impartial(dunder_unwrapped_call)\n", "is_truncated": false}

Patch

diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py
index af168a17..dd7c9bb7 100644
--- a/fastapi/dependencies/models.py
+++ b/fastapi/dependencies/models.py
@@ -111,14 +111,14 @@ class Dependant:
         ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):
             return True
         dunder_call = getattr(_impartial(self.call), "__call__", None)  # noqa: B004
-        if dunder_call is None:
+        if dunder_call is None or inspect.isclass(_impartial(self.call)):
             return False  # pragma: no cover
         if inspect.isgeneratorfunction(
             _impartial(dunder_call)
         ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):
             return True
         dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None)  # noqa: B004
-        if dunder_unwrapped_call is None:
+        if dunder_unwrapped_call is None or inspect.isclass(_unwrapped_call(self.call)):
             return False  # pragma: no cover
         if inspect.isgeneratorfunction(
             _impartial(dunder_unwrapped_call)
@@ -135,14 +135,14 @@ class Dependant:
         ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)):
             return True
         dunder_call = getattr(_impartial(self.call), "__call__", None)  # noqa: B004
-        if dunder_call is None:
+        if dunder_call is None or inspect.isclass(_impartial(self.call)):
             return False  # pragma: no cover
         if inspect.isasyncgenfunction(
             _impartial(dunder_call)
         ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):
             return True
         dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None)  # noqa: B004
-        if dunder_unwrapped_call is None:
+        if dunder_unwrapped_call is None or inspect.isclass(_unwrapped_call(self.call)):
             return False  # pragma: no cover
         if inspect.isasyncgenfunction(
             _impartial(dunder_unwrapped_call)

Test output

show
-none-any/starlette/routing.py:290: in handle
    await self.app(scope, receive, send)
fastapi/routing.py:119: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
/kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
fastapi/routing.py:105: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
fastapi/routing.py:375: in app
    solved_result = await solve_dependencies(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.requests.Request object at 0x7b3a724b77f0>
dependant = Dependant(path_params=[], query_params=[ModelField(field_info=Query(PydanticUndefined), name='value', mode='validation...oauth_scopes=None, parent_oauth_scopes=None, use_cache=True, path='/async-callable-dependency-class', scope='function')
body = None, background_tasks = None
response = <starlette.responses.Response object at 0x7b3a724a8f50>
dependency_overrides_provider = <fastapi.applications.FastAPI object at 0x7b3a72556120>
dependency_cache = {}
async_exit_stack = <contextlib.AsyncExitStack object at 0x7b3a7248cb90>
embed_body_fields = False

    async def solve_dependencies(
        *,
        request: Union[Request, WebSocket],
        dependant: Dependant,
        body: Optional[Union[Dict[str, Any], FormData]] = None,
        background_tasks: Optional[StarletteBackgroundTasks] = None,
        response: Optional[Response] = None,
        dependency_overrides_provider: Optional[Any] = None,
        dependency_cache: Optional[Dict[DependencyCacheKey, Any]] = None,
        # TODO: remove this parameter later, no longer used, not removing it yet as some
        # people might be monkey patching this function (although that's not supported)
        async_exit_stack: AsyncExitStack,
        embed_body_fields: bool,
    ) -> SolvedDependency:
        request_astack = request.scope.get("fastapi_inner_astack")
        assert isinstance(request_astack, AsyncExitStack), (
            "fastapi_inner_astack not found in request scope"
        )
        function_astack = request.scope.get("fastapi_function_astack")
        assert isinstance(function_astack, AsyncExitStack), (
            "fastapi_function_astack not found in request scope"
        )
        values: Dict[str, Any] = {}
        errors: List[Any] = []
        if response is None:
            response = Response()
            del response.headers["content-length"]
            response.status_code = None  # type: ignore
        if dependency_cache is None:
            dependency_cache = {}
        for sub_dependant in dependant.dependencies:
            sub_dependant.call = cast(Callable[..., Any], sub_dependant.call)
            call = sub_dependant.call
            use_sub_dependant = sub_dependant
            if (
                dependency_overrides_provider
                and dependency_overrides_provider.dependency_overrides
            ):
                original_call = sub_dependant.call
                call = getattr(
                    dependency_overrides_provider, "dependency_overrides", {}
                ).get(original_call, original_call)
                use_path: str = sub_dependant.path  # type: ignore
                use_sub_dependant = get_dependant(
                    path=use_path,
                    call=call,
                    name=sub_dependant.name,
                    parent_oauth_scopes=sub_dependant.oauth_scopes,
                    scope=sub_dependant.scope,
                )
    
            solved_result = await solve_dependencies(
                request=request,
                dependant=use_sub_dependant,
                body=body,
                background_tasks=background_tasks,
                response=response,
                dependency_overrides_provider=dependency_overrides_provider,
                dependency_cache=dependency_cache,
                async_exit_stack=async_exit_stack,
                embed_body_fields=embed_body_fields,
            )
            background_tasks = solved_result.background_tasks
            if solved_result.errors:
                errors.extend(solved_result.errors)
                continue
            if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
                solved = dependency_cache[sub_dependant.cache_key]
            elif (
                use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable
            ):
                use_astack = request_astack
                if sub_dependant.scope == "function":
                    use_astack = function_astack
                solved = await _solve_generator(
                    dependant=use_sub_dependant,
                    stack=use_astack,
                    sub_values=solved_result.values,
                )
            elif use_sub_dependant.is_coroutine_callable:
>               solved = await call(**solved_result.values)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: object AsyncCallableDependency can't be used in 'await' expression

fastapi/dependencies/utils.py:667: TypeError
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45
  /kaggle/tmp/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, 10 passed, 1 warning in 0.93s