resolved RESOLVED PASS · 17 tool calls · 106 s · fastapi/fastapi
🐛 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 | Arguments | Result |
|---|---|---|---|
| 1 | run_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_defull{"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} |
| 2 | run_command | {
"command": "sed -n '150,170p' 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", "stderr": "", "exit_code": 0} |
| 3 | run_command | {
"command": "sed -n '150,200p' 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\n @cached_property\n def computed_scope(self) -> Union[str, None]:\n if self.scope:\n return self.scope\n if self.is_gen_callable or self.is_async_gen_callable:\n return \"request\"\n return None\n", "stderr": "", "exit_code": 0} |
| 4 | run_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} |
| 5 | run_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_cfull{"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} |
| 6 | run_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} |
| 7 | run_command | {
"command": "sed -n '130,150p' fastapi/dependencies/models.py"
} | {"status": "ok", "stdout": " def is_async_gen_callable(self) -> bool:\n if self.call is None:\n return False # pragma: no cover\n if inspect.isasyncgenfunction(full{"status": "ok", "stdout": " 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(_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", "stderr": "", "exit_code": 0} |
| 8 | run_command | {
"command": "sed -n '130,150p' fastapi/dependencies/models.py | tail -n 1"
} | {"status": "ok", "stdout": " return True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": " return True\n", "stderr": "", "exit_code": 0} |
| 9 | run_command | {
"command": "python3 - <<'PY'\nimport inspect\nfrom fastapi.dependencies.models import Dependant\n\nclass MyCallable:\n def __call__(self):\n yield 1\n\ndef test_is_gen_callable():\n # Case 1: Instance of MyCallable\n dep_inst = Dependant(call=MyCallable())\n print(f\"Instance is_gen_callable: {dep_inst.is_gen_callable}\")\n \n # Case 2: Class MyCallable\n dep_cls = Dependant(call=MyCallable)\n print(f\"Class is_gen_callable: {dep_cls.is_gen_callable}\")\n\ntest_is_gen_callable()\nPY\n"
} | {"status": "ok", "stdout": "Instance is_gen_callable: True\nClass is_gen_callable: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Instance is_gen_callable: True\nClass is_gen_callable: True\n", "stderr": "", "exit_code": 0} |
| 10 | run_command | {
"command": "python3 - <<'PY'\nimport inspect\nfrom fastapi.dependencies.models import Dependant\n\nclass MyAsyncCallable:\n async def __call__(self):\n return 1\n\ndef test_is_coroutine_callable():\n # Case 1: Instance of MyAsyncCallable\n dep_inst = Dependant(call=MyAsyncCallable())\n print(f\"Instance is_coroutine_callable: {dep_inst.is_coroutine_callable}\")\n \n # Case 2: Class MyAsyncCallable\n dep_cls = Dependant(call=MyAsyncCallable)\n print(f\"Class is_coroutine_callable: {dep_cls.is_coroutine_callable}\")\n\ntest_is_coroutine_callable()\nPY\n"
} | {"status": "ok", "stdout": "Instance is_coroutine_callable: True\nClass is_coroutine_callable: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Instance is_coroutine_callable: True\nClass is_coroutine_callable: True\n", "stderr": "", "exit_code": 0} |
| 11 | run_command | {
"command": "python3 - <<'PY'\nimport inspect\nfrom fastapi.dependencies.models import Dependant\n\nclass MyAsyncGenCallable:\n async def __call__(self):\n yield 1\n\ndef test_is_async_gen_callable():\n # Case 1: Instance of MyAsyncGenCallable\n dep_inst = Dependant(call=MyAsyncGenCallable())\n print(f\"Instance is_async_gen_callable: {dep_inst.is_async_gen_callable}\")\n \n # Case 2: Class MyAsyncGenCallable\n dep_cls = Dependant(call=MyAsyncGenCallable)\n print(f\"Class is_async_gen_callable: {dep_cls.is_async_gen_callable}\")\n\ntest_is_async_gen_callable()\nPY\n"
} | {"status": "ok", "stdout": "Instance is_async_gen_callable: True\nClass is_async_gen_callable: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Instance is_async_gen_callable: True\nClass is_async_gen_callable: True\n", "stderr": "", "exit_code": 0} |
| 12 | run_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\n if inspect.isgeneratorfunction(\n _impartial(dunder_call)\n ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n return True\"\"\"\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 if inspect.isgeneratorfunction(\n _impartial(dunder_call)\n ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n return True\"\"\"\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 if inspect.isasyncgenfunction(\n _impartial(dunder_call)\n ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):\n return True\"\"\"\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 if inspect.isasyncgenfunction(\n _impartial(dunder_call)\n ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):\n return True\"\"\"\n\n# Fix 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\n if iscoroutinefunction(_impartial(dunder_call)) or iscoroutinefunction(\n _unwrapped_call(dunder_call)\n ):\n return True\"\"\"\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 if iscoroutinefunction(_impartial(dunder_call)) or iscoroutinefunction(\n _unwrapped_call(dunder_call)\n ):\n return True\"\"\"\n\ns = s.replace(old_gen, new_gen)\ns = s.replace(old_async_gen, new_async_gen)\ns = s.replace(old_coro, new_coro)\np.write_text(s)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 13 | run_command | {
"command": "python3 - <<'PY'\nimport inspect\nfrom fastapi.dependencies.models import Dependant\n\nclass MyCallable:\n def __call__(self):\n yield 1\n\ndef test_is_gen_callable():\n # Case 1: Instance of MyCallable\n dep_inst = Dependant(call=MyCallable())\n print(f\"Instance is_gen_callable: {dep_inst.is_gen_callable}\")\n \n # Case 2: Class MyCallable\n dep_cls = Dependant(call=MyCallable)\n print(f\"Class is_gen_callable: {dep_cls.is_gen_callable}\")\n\ntest_is_gen_callable()\nPY\n"
} | {"status": "ok", "stdout": "Instance is_gen_callable: True\nClass is_gen_callable: False\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Instance is_gen_callable: True\nClass is_gen_callable: False\n", "stderr": "", "exit_code": 0} |
| 14 | run_command | {
"command": "python3 - <<'PY'\nimport inspect\nfrom fastapi.dependencies.models import Dependant\n\nclass MyAsyncCallable:\n async def __call__(self):\n return 1\n\ndef test_is_coroutine_callable():\n # Case 1: Instance of MyAsyncCallable\n dep_inst = Dependant(call=MyAsyncCallable())\n print(f\"Instance is_coroutine_callable: {dep_inst.is_coroutine_callable}\")\n \n # Case 2: Class MyAsyncCallable\n dep_cls = Dependant(call=MyAsyncCallable)\n print(f\"Class is_coroutine_callable: {dep_cls.is_coroutine_callable}\")\n\ntest_is_coroutine_callable()\nPY\n"
} | {"status": "ok", "stdout": "Instance is_coroutine_callable: True\nClass is_coroutine_callable: False\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Instance is_coroutine_callable: True\nClass is_coroutine_callable: False\n", "stderr": "", "exit_code": 0} |
| 15 | run_command | {
"command": "python3 - <<'PY'\nimport inspect\nfrom fastapi.dependencies.models import Dependant\n\nclass MyAsyncGenCallable:\n async def __call__(self):\n yield 1\n\ndef test_is_async_gen_callable():\n # Case 1: Instance of MyAsyncGenCallable\n dep_inst = Dependant(call=MyAsyncGenCallable())\n print(f\"Instance is_async_gen_callable: {dep_inst.is_async_gen_callable}\")\n \n # Case 2: Class MyAsyncGenCallable\n dep_cls = Dependant(call=MyAsyncGenCallable)\n print(f\"Class is_async_gen_callable: {dep_cls.is_async_gen_callable}\")\n\ntest_is_async_gen_callable()\nPY\n"
} | {"status": "ok", "stdout": "Instance is_async_gen_callable: True\nClass is_async_gen_callable: False\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Instance is_async_gen_callable: True\nClass is_async_gen_callable: False\n", "stderr": "", "exit_code": 0} |
| 16 | run_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/dependefull{"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} |
| 17 | run_command | {
"command": "submit_patch"
} | {"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: submit_patch: command not found\n", "details": {"stdout": "", "stderr": "/bin/basfull{"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}} |
| 18 | submit_patch | {} | {"status": "ok", "patch_size": 1361, "files_changed": 1}full{"status": "ok", "patch_size": 1361, "files_changed": 1} |
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
............ [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.49s