← pod_r3_v1e

fastapi_14458

resolved RESOLVED PASS · 16 tool calls · 191 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 (17)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"is_coroutine_callable\" ."
}
{"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": "sed -n '150,180p' fastapi/dependencies/models.py"
}
{"status": "ok", "stdout": " return True\n return False\n\n @cached_property\n def is_coroutine_callable(self) -> bool:\n if self.call is None:\n return False #
full
{"status": "ok", "stdout": "            return True\n        return False\n\n    @cached_property\n    def is_coroutine_callable(self) -> bool:\n        if self.call is None:\n            return False  # pragma: no cover\n        if inspect.isroutine(_impartial(self.call)) and iscoroutinefunction(\n            _impartial(self.call)\n        ):\n            return True\n        if inspect.isroutine(_unwrapped_call(self.call)) and iscoroutinefunction(\n            _unwrapped_call(self.call)\n        ):\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 iscoroutinefunction(_impartial(dunder_call)) or iscoroutinefunction(\n            _unwrapped_call(dunder_call)\n        ):\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 iscoroutinefunction(\n            _impartial(dunder_unwrapped_call)\n        ) or iscoroutinefunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        # if inspect.isclass(self.call): False, covered by default return\n        return False\n", "stderr": "", "exit_code": 0}
3run_command
{
 "command": "grep -n \"is_async_gen_callable\" fastapi/dependencies/models.py"
}
{"status": "ok", "stdout": "130: def is_async_gen_callable(self) -> bool:\n186: if self.is_gen_callable or self.is_async_gen_callable:\n", "stderr": "", "exit_c
full
{"status": "ok", "stdout": "130:    def is_async_gen_callable(self) -> bool:\n186:        if self.is_gen_callable or self.is_async_gen_callable:\n", "stderr": "", "exit_code": 0}
4run_command
{
 "command": "grep -n \"is_gen_callable\" fastapi/dependencies/models.py"
}
{"status": "ok", "stdout": "106: def is_gen_callable(self) -> bool:\n186: if self.is_gen_callable or self.is_async_gen_callable:\n", "stderr": "", "exit_code":
full
{"status": "ok", "stdout": "106:    def is_gen_callable(self) -> bool:\n186:        if self.is_gen_callable or self.is_async_gen_callable:\n", "stderr": "", "exit_code": 0}
5run_command
{
 "command": "sed -n '100,150p' 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": "python3 - <<'PY'\nimport inspect\nfrom typing import AsyncGenerator, Generator\n\nclass AsyncCallClass:\n    async def __call__(self):\n        yield 1\n\nclass GenCallClass:\n    def __call__(self):\n        yield 1\n\nclass AsyncGenCallClass:\n    async def __call__(self):\n        yield 1\n\ndef is_coroutine_function(func):\n    return inspect.iscoroutinefunction(func)\n\ndef is_generator_function(func):\n    return inspect.isgeneratorfunction(func)\n\ndef is_async_gen_function(func):\n    return inspect.isasyncgenfunction(func)\n\ndef test_is_coroutine_callable(call):\n    # Simplified version of the logic in fastapi/dependencies/models.py\n    if call is None: return False\n    if inspect.isroutine(call) and is_coroutine_function(call):\n        return True\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_coroutine_function(dunder_call):\n        return True\n    return False\n\ndef test_is_gen_callable(call):\n    if call is None: return False\n    if is_generator_function(call):\n        return True\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_generator_function(dunder_call):\n        return True\n    return False\n\ndef test_is_async_gen_callable(call):\n    if call is None: return False\n    if is_async_gen_function(call):\n        return True\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_async_gen_function(dunder_call):\n        return True\n    return False\n\nprint(f\"AsyncCallClass is_coroutine_callable: {test_is_coroutine_callable(AsyncCallClass)}\")\nprint(f\"GenCallClass is_gen_callable: {test_is_gen_callable(GenCallClass)}\")\nprint(f\"AsyncGenCallClass is_async_gen_callable: {test_is_async_gen_callable(AsyncGenCallClass)}\")\nPY\n"
}
{"status": "ok", "stdout": "AsyncCallClass is_coroutine_callable: False\nGenCallClass is_gen_callable: True\nAsyncGenCallClass is_async_gen_callable: True\n", "
full
{"status": "ok", "stdout": "AsyncCallClass is_coroutine_callable: False\nGenCallClass is_gen_callable: True\nAsyncGenCallClass is_async_gen_callable: True\n", "stderr": "", "exit_code": 0}
7run_command
{
 "command": "python3 - <<'PY'\nimport inspect\nfrom typing import AsyncGenerator, Generator\n\nclass AsyncCallClass:\n    async def __call__(self):\n        return 1\n\nclass GenCallClass:\n    def __call__(self):\n        yield 1\n\nclass AsyncGenCallClass:\n    async def __call__(self):\n        yield 1\n\ndef is_coroutine_function(func):\n    return inspect.iscoroutinefunction(func)\n\ndef is_generator_function(func):\n    return inspect.isgeneratorfunction(func)\n\ndef is_async_gen_function(func):\n    return inspect.isasyncgenfunction(func)\n\ndef test_is_coroutine_callable(call):\n    if call is None: return False\n    if inspect.isroutine(call) and is_coroutine_function(call):\n        return True\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_coroutine_function(dunder_call):\n        return True\n    return False\n\ndef test_is_gen_callable(call):\n    if call is None: return False\n    if is_generator_function(call):\n        return True\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_generator_function(dunder_call):\n        return True\n    return False\n\ndef test_is_async_gen_callable(call):\n    if call is None: return False\n    if is_async_gen_function(call):\n        return True\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_async_gen_function(dunder_call):\n        return True\n    return False\n\nprint(f\"AsyncCallClass is_coroutine_callable: {test_is_coroutine_callable(AsyncCallClass)}\")\nprint(f\"GenCallClass is_gen_callable: {test_is_gen_callable(GenCallClass)}\")\nprint(f\"AsyncGenCallClass is_async_gen_callable: {test_is_async_gen_callable(AsyncGenCallClass)}\")\nPY\n"
}
{"status": "ok", "stdout": "AsyncCallClass is_coroutine_callable: True\nGenCallClass is_gen_callable: True\nAsyncGenCallClass is_async_gen_callable: True\n", "s
full
{"status": "ok", "stdout": "AsyncCallClass is_coroutine_callable: True\nGenCallClass is_gen_callable: True\nAsyncGenCallClass is_async_gen_callable: True\n", "stderr": "", "exit_code": 0}
8run_command
{
 "command": "python3 - <<'PY'\nimport inspect\nfrom typing import AsyncGenerator, Generator\n\nclass AsyncCallClass:\n    async def __call__(self):\n        return 1\n\nclass GenCallClass:\n    def __call__(self):\n        yield 1\n\nclass AsyncGenCallClass:\n    async def __call__(self):\n        yield 1\n\ndef is_coroutine_function(func):\n    return inspect.iscoroutinefunction(func)\n\ndef is_generator_function(func):\n    return inspect.isgeneratorfunction(func)\n\ndef is_async_gen_function(func):\n    return inspect.isasyncgenfunction(func)\n\ndef test_is_coroutine_callable(call):\n    if call is None: return False\n    if inspect.isroutine(call) and is_coroutine_function(call):\n        return True\n    # FIX: check if call is a class\n    if inspect.isclass(call):\n        return False\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_coroutine_function(dunder_call):\n        return True\n    return False\n\ndef test_is_gen_callable(call):\n    if call is None: return False\n    if is_generator_function(call):\n        return True\n    # FIX: check if call is a class\n    if inspect.isclass(call):\n        return False\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_generator_function(dunder_call):\n        return True\n    return False\n\ndef test_is_async_gen_callable(call):\n    if call is None: return False\n    if is_async_gen_function(call):\n        return True\n    # FIX: check if call is a class\n    if inspect.isclass(call):\n        return False\n    dunder_call = getattr(call, \"__call__\", None)\n    if dunder_call is None: return False\n    if is_async_gen_function(dunder_call):\n        return True\n    return False\n\nprint(f\"AsyncCallClass is_coroutine_callable: {test_is_coroutine_callable(AsyncCallClass)}\")\nprint(f\"GenCallClass is_gen_callable: {test_is_gen_callable(GenCallClass)}\")\nprint(f\"AsyncGenCallClass is_async_gen_callable: {test_is_async_gen_callable(AsyncGenCallClass)}\")\n\n# Test with instances\nprint(f\"AsyncCallClass() is_coroutine_callable: {test_is_coroutine_callable(AsyncCallClass())}\")\nprint(f\"GenCallClass() is_gen_callable: {test_is_gen_callable(GenCallClass())}\")\nprint(f\"AsyncGenCallClass() is_async_gen_callable: {test_is_async_gen_callable(AsyncGenCallClass())}\")\nPY\n"
}
{"status": "ok", "stdout": "AsyncCallClass is_coroutine_callable: False\nGenCallClass is_gen_callable: False\nAsyncGenCallClass is_async_gen_callable: False\nAs
full
{"status": "ok", "stdout": "AsyncCallClass is_coroutine_callable: False\nGenCallClass is_gen_callable: False\nAsyncGenCallClass is_async_gen_callable: False\nAsyncCallClass() is_coroutine_callable: True\nGenCallClass() is_gen_callable: True\nAsyncGenCallClass() is_async_gen_callable: True\n", "stderr": "", "exit_code": 0}
9run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"fastapi/dependencies/models.py\")\ns = p.read_text()\n\n# Fix is_gen_callable\nold_gen = \"\"\"        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\nnew_gen = \"\"\"        if inspect.isclass(_impartial(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\ns = s.replace(old_gen, new_gen)\n\n# Fix is_async_gen_callable\nold_async_gen = \"\"\"        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\n# Wait, is_async_gen_callable also has dunder_call. \n# I need to be careful about which one I replace if they are identical.\n# Let's use a more specific replacement or do it one by one.\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
10run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"fastapi/dependencies/models.py\")\ns = p.read_text()\n\n# Fix is_gen_callable\n# The block is around line 113\n# Let's find the exact block for is_gen_callable\n# and is_async_gen_callable and is_coroutine_callable.\n\ndef replace_block(content, search_str, replace_str):\n    return content.replace(search_str, replace_str)\n\n# For is_gen_callable\nold_gen = \"\"\"        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\nnew_gen = \"\"\"        if inspect.isclass(_impartial(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\n\n# For is_async_gen_callable\nold_async_gen = \"\"\"        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\nnew_async_gen = \"\"\"        if inspect.isclass(_impartial(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\n\n# For is_coroutine_callable\nold_coro = \"\"\"        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\nnew_coro = \"\"\"        if inspect.isclass(_impartial(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\"\"\"\n\n# Since the blocks are identical, I can't just use replace(). \n# I should use a more targeted approach.\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
11run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nfrom pathlib import Path\nimport re\n\np = Path(\"fastapi/dependencies/models.py\")\ns = p.read_text()\n\n# We want to insert \"        if inspect.isclass(_impartial(self.call)):\\n            return False\\n\" \n# before \"        dunder_call = getattr(_impartial(self.call), \\\"__call__\\\", None)  # noqa: B004\"\n# in three different methods: is_gen_callable, is_async_gen_callable, is_coroutine_callable.\n\n# Let's find all occurrences of the dunder_call line and insert before it.\n# But only if it's the first dunder_call in the method.\n# Actually, the methods have two dunder_call checks: one for _impartial(self.call) and one for _unwrapped_call(self.call).\n# The problem is that if self.call is a class, we should return False immediately before checking __call__.\n\n# Let's see the methods again.\n# is_gen_callable:\n# 1. check _impartial(self.call) and _unwrapped_call(self.call) with isgeneratorfunction\n# 2. check dunder_call of _impartial(self.call)\n# 3. check dunder_call of _unwrapped_call(self.call)\n\n# If self.call is a class, then _impartial(self.call) is also that class.\n# If we check isclass(_impartial(self.call)), we can return False.\n\n# Let's use a regex to find the first dunder_call in each of these methods.\n\npattern = r\"(def is_(?:gen|async_gen|coroutine)_callable\\(self\\) -> bool:.*?)(?=\\s+dunder_call = getattr\\(_impartial\\(self\\.call\\), \\\"__call__\\\", None)\"\n# This is too complex for a simple replace.\n\n# Let's just do it manually with line numbers or unique markers.\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
12run_command
{
 "command": "sed -n '100,190p' 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
13run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nfrom pathlib import Path\n\np = Path(\"fastapi/dependencies/models.py\")\ns = p.read_text()\n\n# We want to insert:\n#         if inspect.isclass(_impartial(self.call)):\n#             return False\n# before the first dunder_call = getattr(_impartial(self.call), \"__call__\", None) in each of the 3 methods.\n\n# Let's find the line numbers for the first dunder_call in each method.\n# is_gen_callable:\n# is_async_gen_callable:\n# is_coroutine_callable:\n\n# I'll use a simple replacement for each method by including enough context.\n\n# is_gen_callable\nold_gen = \"\"\"        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\"\"\"\nnew_gen = \"\"\"        if inspect.isgeneratorfunction(\n            _impartial(self.call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):\n            return True\n        if inspect.isclass(_impartial(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\"\"\"\n\n# is_async_gen_callable\nold_async_gen = \"\"\"        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\"\"\"\nnew_async_gen = \"\"\"        if inspect.isasyncgenfunction(\n            _impartial(self.call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)):\n            return True\n        if inspect.isclass(_impartial(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\"\"\"\n\n# is_coroutine_callable\nold_coro = \"\"\"        if inspect.isroutine(_unwrapped_call(self.call)) and iscoroutinefunction(\n            _unwrapped_call(self.call)\n        ):\n            return True\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\"\"\"\nnew_coro = \"\"\"        if inspect.isroutine(_unwrapped_call(self.call)) and iscoroutinefunction(\n            _unwrapped_call(self.call)\n        ):\n            return True\n        if inspect.isclass(_impartial(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\"\"\"\n\ns = s.replace(old_gen, new_gen)\ns = s.replace(old_async_gen, new_async_gen)\ns = s.replace(old_coro, new_coro)\n\np.write_text(s)\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
14run_command
{
 "command": "sed -n '100,190p' 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        if inspect.isclass(_impartial(self.call)):\n            return False\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        if inspect.isclass(_impartial(self.call)):\n            return False\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(du
15run_command
{
 "command": "git diff"
}
{"status": "ok", "stdout": "diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py\nindex af168a17..509b8f06 100644\n--- a/fastapi/depende
full
{"status": "ok", "stdout": "diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py\nindex af168a17..509b8f06 100644\n--- a/fastapi/dependencies/models.py\n+++ b/fastapi/dependencies/models.py\n@@ -110,6 +110,8 @@ class Dependant:\n             _impartial(self.call)\n         ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):\n             return True\n+        if inspect.isclass(_impartial(self.call)):\n+            return False\n         dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n         if dunder_call is None:\n             return False  # pragma: no cover\n@@ -134,6 +136,8 @@ class Dependant:\n             _impartial(self.call)\n         ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)):\n             return True\n+        if inspect.isclass(_impartial(self.call)):\n+            return False\n         dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n         if dunder_call is None:\n             return False  # pragma: no cover\n@@ -162,6 +166,8 @@ class Dependant:\n             _unwrapped_call(self.call)\n         ):\n             return True\n+        if inspect.isclass(_impartial(self.call)):\n+            return False\n         dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n         if dunder_call is None:\n             return False  # pragma: no cover\n", "stderr": "", "exit_code": 0}
16run_command
{
 "command": "submit_patch"
}
{"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: submit_patch: command not found\n", "details": {"stdout": "", "stderr": "/bin/bas
full
{"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: submit_patch: command not found\n", "details": {"stdout": "", "stderr": "/bin/bash: submit_patch: command not found\n", "exit_code": 127}}
17submit_patch
{}
{"status": "ok", "patch_size": 1361, "files_changed": 1}
full
{"status": "ok", "patch_size": 1361, "files_changed": 1}

Patch

diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py
index af168a17..509b8f06 100644
--- a/fastapi/dependencies/models.py
+++ b/fastapi/dependencies/models.py
@@ -110,6 +110,8 @@ class Dependant:
             _impartial(self.call)
         ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):
             return True
+        if inspect.isclass(_impartial(self.call)):
+            return False
         dunder_call = getattr(_impartial(self.call), "__call__", None)  # noqa: B004
         if dunder_call is None:
             return False  # pragma: no cover
@@ -134,6 +136,8 @@ class Dependant:
             _impartial(self.call)
         ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)):
             return True
+        if inspect.isclass(_impartial(self.call)):
+            return False
         dunder_call = getattr(_impartial(self.call), "__call__", None)  # noqa: B004
         if dunder_call is None:
             return False  # pragma: no cover
@@ -162,6 +166,8 @@ class Dependant:
             _unwrapped_call(self.call)
         ):
             return True
+        if inspect.isclass(_impartial(self.call)):
+            return False
         dunder_call = getattr(_impartial(self.call), "__call__", None)  # noqa: B004
         if dunder_call is None:
             return False  # pragma: no cover

Test output

show
............                                                             [100%]
=============================== 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
12 passed, 1 warning in 0.48s