failed WRONG_FIX UNSUBMITTED wrong_fix_unsubmitted(budget) ยท 37 tool calls ยท 303 s ยท fastapi/fastapi
๐ Fix support for functools wraps and partial combined, for async and regular functions and classes in path operations and dependencies ๐ Fix support for functools wraps and partial combined, for async and regular functions and classes in path operations and dependencies This also uses and extends the tests created by @YuriiMotov :raised_hands: Should fix / related to: https://github.com/fastapi/fastapi/issues/14444 The new tests simulate the multiple combinations of how decorators could affect dependencies and path operation functions (endpoints). The logic to analyze if a function is an async, generator, async generator, callable instance, etc. now also checks and unwraps and extracts partials in all those levels. The main case is when the callable is an _async_ something (function, generator, etc) because then it needs to be awaited. But the original function could be async or not, the wrapper could be async or not. if either is async, then it has to be awaited, no matter if the other is not async. So, analyzing only the last point in the chain is not enough, it's necessary to analyze the function but also the wrapper. This PR implements and tests all that, all those combinations.
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"is_async_gen\" fastapi | head -20"
} | {"status": "ok", "stdout": "fastapi/dependencies/models.py:95: def is_async_gen_callable(self) -> bool:\nfastapi/dependencies/models.py:114: if self.is_gen_callfull{"status": "ok", "stdout": "fastapi/dependencies/models.py:95: def is_async_gen_callable(self) -> bool:\nfastapi/dependencies/models.py:114: if self.is_gen_callable or self.is_async_gen_callable:\nfastapi/dependencies/utils.py:270: (dependant.is_gen_callable or dependant.is_async_gen_callable)\nfastapi/dependencies/utils.py:553: elif dependant.is_async_gen_callable:\nfastapi/dependencies/utils.py:636: use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable\n", "stderr": "", "exit_code": 0} |
| 2 | run_command | {
"command": "grep -rn \"is_async_callable\" fastapi | head -20"
} | {"status": "ok", "stdout": "fastapi/routing.py:65:from starlette._utils import is_async_callable\nfastapi/routing.py:92: func if is_async_callable(func) else fufull{"status": "ok", "stdout": "fastapi/routing.py:65:from starlette._utils import is_async_callable\nfastapi/routing.py:92: func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore\n", "stderr": "", "exit_code": 0} |
| 3 | run_command | {
"command": "grep -rn \"is_async\" fastapi | head -20"
} | {"status": "ok", "stdout": "fastapi/dependencies/models.py:95: def is_async_gen_callable(self) -> bool:\nfastapi/dependencies/models.py:114: if self.is_gen_callfull{"status": "ok", "stdout": "fastapi/dependencies/models.py:95: def is_async_gen_callable(self) -> bool:\nfastapi/dependencies/models.py:114: if self.is_gen_callable or self.is_async_gen_callable:\nfastapi/dependencies/utils.py:270: (dependant.is_gen_callable or dependant.is_async_gen_callable)\nfastapi/dependencies/utils.py:553: elif dependant.is_async_gen_callable:\nfastapi/dependencies/utils.py:636: use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable\nfastapi/routing.py:65:from starlette._utils import is_async_callable\nfastapi/routing.py:92: func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore\n", "stderr": "", "exit_code": 0} |
| 4 | run_command | {
"command": "sed -n '80,130p' fastapi/dependencies/models.py"
} | {"status": "ok", "stdout": " if self.call is None:\n return self.call # pragma: no cover\n unwrapped = inspect.unwrap(self.call)\n if isinstance(unwrapped, partfull{"status": "ok", "stdout": " if self.call is None:\n return self.call # pragma: no cover\n unwrapped = inspect.unwrap(self.call)\n if isinstance(unwrapped, partial):\n unwrapped = unwrapped.func\n return unwrapped\n\n @cached_property\n def is_gen_callable(self) -> bool:\n if inspect.isgeneratorfunction(self._unwrapped_call):\n return True\n dunder_call = getattr(self._unwrapped_call, \"__call__\", None) # noqa: B004\n return inspect.isgeneratorfunction(dunder_call)\n\n @cached_property\n def is_async_gen_callable(self) -> bool:\n if inspect.isasyncgenfunction(self._unwrapped_call):\n return True\n dunder_call = getattr(self._unwrapped_call, \"__call__\", None) # noqa: B004\n return inspect.isasyncgenfunction(dunder_call)\n\n @cached_property\n def is_coroutine_callable(self) -> bool:\n if inspect.isroutine(self._unwrapped_call):\n return iscoroutinefunction(self._unwrapped_call)\n if inspect.isclass(self._unwrapped_call):\n return False\n dunder_call = getattr(self._unwrapped_call, \"__call__\", None) # noqa: B004\n return iscoroutinefunction(dunder_call)\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} |
| 5 | run_command | {
"command": "sed -n '60,100p' fastapi/dependencies/models.py"
} | {"status": "ok", "stdout": " )\n return (\n self.call,\n scopes_for_cache,\n self.computed_scope or \"\",\n )\n\n @cached_property\n def _uses_scopes(self) -> bfull{"status": "ok", "stdout": " )\n return (\n self.call,\n scopes_for_cache,\n self.computed_scope or \"\",\n )\n\n @cached_property\n def _uses_scopes(self) -> bool:\n if self.own_oauth_scopes:\n return True\n if self.security_scopes_param_name is not None:\n return True\n for sub_dep in self.dependencies:\n if sub_dep._uses_scopes:\n return True\n return False\n\n @cached_property\n def _unwrapped_call(self) -> Any:\n if self.call is None:\n return self.call # pragma: no cover\n unwrapped = inspect.unwrap(self.call)\n if isinstance(unwrapped, partial):\n unwrapped = unwrapped.func\n return unwrapped\n\n @cached_property\n def is_gen_callable(self) -> bool:\n if inspect.isgeneratorfunction(self._unwrapped_call):\n return True\n dunder_call = getattr(self._unwrapped_call, \"__call__\", None) # noqa: B004\n return inspect.isgeneratorfunction(dunder_call)\n\n @cached_property\n def is_async_gen_callable(self) -> bool:\n if inspect.isasyncgenfunction(self._unwrapped_call):\n return True\n dunder_call = getattr(self._unwrapped_call, \"__call__\", None) # noqa: B004\n return inspect.isasyncgenfunction(dunder_call)\n\n", "stderr": "", "exit_code": 0} |
| 6 | run_command | {
"command": "grep -n \"is_async_callable\" fastapi/routing.py"
} | {"status": "ok", "stdout": "65:from starlette._utils import is_async_callable\n92: func if is_async_callable(func) else functools.partial(run_in_threadpool, funfull{"status": "ok", "stdout": "65:from starlette._utils import is_async_callable\n92: func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore\n", "stderr": "", "exit_code": 0} |
| 7 | run_command | {
"command": "sed -n '80,100p' fastapi/routing.py"
} | {"status": "ok", "stdout": "\n\n# Copy of starlette.routing.request_response modified to include the\n# dependencies' AsyncExitStack\ndef request_response(\n fufull{"status": "ok", "stdout": "\n\n# Copy of starlette.routing.request_response modified to include the\n# dependencies' AsyncExitStack\ndef request_response(\n func: Callable[[Request], Union[Awaitable[Response], Response]],\n) -> ASGIApp:\n \"\"\"\n Takes a function or coroutine `func(request) -> response`,\n and returns an ASGI application.\n \"\"\"\n f: Callable[[Request], Awaitable[Response]] = (\n func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore\n )\n\n async def app(scope: Scope, receive: Receive, send: Send) -> None:\n request = Request(scope, receive, send)\n\n async def app(scope: Scope, receive: Receive, send: Send) -> None:\n # Starts customization\n response_awaited = False\n", "stderr": "", "exit_code": 0} |
| 8 | run_command | {
"command": "cat /workspace/fastapi/dependencies/models.py"
} | {"status": "ok", "stdout": "import inspect\nimport sys\nfrom dataclasses import dataclass, field\nfrom functools import cached_property, partial\nfrom typing imfull{"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, Sequence, 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\n@dataclass\nclass SecurityRequirement:\n security_scheme: SecurityBase\n scopes: Optional[Sequence[str]] = None\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 security_requirements: List[SecurityRequirement] = 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) -> List[str]:\n scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else []\n # This doesn't use a set to |
| 9 | run_command | {
"command": "grep -rn \"is_async_callable\" ."
} | {"status": "ok", "stdout": "./fastapi/routing.py:65:from starlette._utils import is_async_callable\n./fastapi/routing.py:92: func if is_async_callable(func) elsfull{"status": "ok", "stdout": "./fastapi/routing.py:65:from starlette._utils import is_async_callable\n./fastapi/routing.py:92: func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore\n", "stderr": "", "exit_code": 0} |
| 10 | run_command | {
"command": "cat /workspace/fastapi/routing.py"
} | {"status": "ok", "stdout": "import dataclasses\nimport email.message\nimport functools\nimport inspect\nimport json\nfrom contextlib import AsyncExitStack, asynfull{"status": "ok", "stdout": "import dataclasses\nimport email.message\nimport functools\nimport inspect\nimport json\nfrom contextlib import AsyncExitStack, asynccontextmanager\nfrom enum import Enum, IntEnum\nfrom typing import (\n Any,\n AsyncIterator,\n Awaitable,\n Callable,\n Collection,\n Coroutine,\n Dict,\n List,\n Mapping,\n Optional,\n Sequence,\n Set,\n Tuple,\n Type,\n Union,\n)\n\nfrom annotated_doc import Doc\nfrom fastapi import params, temp_pydantic_v1_params\nfrom fastapi._compat import (\n ModelField,\n Undefined,\n _get_model_config,\n _model_dump,\n _normalize_errors,\n lenient_issubclass,\n)\nfrom fastapi.datastructures import Default, DefaultPlaceholder\nfrom fastapi.dependencies.models import Dependant\nfrom fastapi.dependencies.utils import (\n _should_embed_body_fields,\n get_body_field,\n get_dependant,\n get_flat_dependant,\n get_parameterless_sub_dependant,\n get_typed_return_annotation,\n solve_dependencies,\n)\nfrom fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import (\n FastAPIError,\n RequestValidationError,\n ResponseValidationError,\n WebSocketRequestValidationError,\n)\nfrom fastapi.types import DecoratedCallable, IncEx\nfrom fastapi.utils import (\n create_cloned_field,\n create_model_field,\n generate_unique_id,\n get_value_or_default,\n is_body_allowed_for_status_code,\n)\nfrom pydantic import BaseModel\nfrom starlette import routing\nfrom starlette._exception_handler import wrap_app_handling_exceptions\nfrom starlette._utils import is_async_callable\nfrom starlette.concurrency import run_in_threadpool\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.responses import JSONResponse, Response\nfrom starlette.routing import (\n BaseRoute,\n Match,\n compile_path,\n get_name,\n)\nfrom starlette.routing import Mount as Mount # noqa\nfrom s |
| 11 | run_command | {
"command": "grep -rn \"is_async_callable\" /workspace/starlette | head -20"
} | {"status": "ok", "stdout": "", "stderr": "grep: /workspace/starlette: No such file or directory\n", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "grep: /workspace/starlette: No such file or directory\n", "exit_code": 0} |
| 12 | run_command | {
"command": "grep -rn \"is_async_callable\" /workspace/fastapi | head -20"
} | {"status": "ok", "stdout": "/workspace/fastapi/routing.py:65:from starlette._utils import is_async_callable\n/workspace/fastapi/routing.py:92: func if is_async_full{"status": "ok", "stdout": "/workspace/fastapi/routing.py:65:from starlette._utils import is_async_callable\n/workspace/fastapi/routing.py:92: func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore\n", "stderr": "", "exit_code": 0} |
| 13 | run_command | {
"command": "python3 -c \"import starlette._utils; print(starlette._utils.is_async_callable)\""
} | {"status": "ok", "stdout": "<function is_async_callable at 0x103b28680>\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "<function is_async_callable at 0x103b28680>\n", "stderr": "", "exit_code": 0} |
| 14 | run_command | {
"command": "python3 -c \"import starlette._utils; print(starlette._utils.is_async_callable.__code__.co_name)\""
} | {"status": "ok", "stdout": "is_async_callable\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "is_async_callable\n", "stderr": "", "exit_code": 0} |
| 15-16 ร2 | run_command | {
"command": "python3 -c \"import starlette._utils; import inspect; print(inspect.getsource(starlette._utils.is_async_callable))\""
} | {"status": "ok", "stdout": "def is_async_callable(obj: Any) -> Any:\n while isinstance(obj, functools.partial):\n obj = obj.func\n\n return iscoroutinefunction(full{"status": "ok", "stdout": "def is_async_callable(obj: Any) -> Any:\n while isinstance(obj, functools.partial):\n obj = obj.func\n\n return iscoroutinefunction(obj) or (callable(obj) and iscoroutinefunction(obj.__call__))\n\n", "stderr": "", "exit_code": 0} |
| 17 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\nasync def async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs)\n return wrapped\n\nf1 = async_wrapper(sync_func)\nf2 = wrapper(async_func)\nf3 = functools.partial(async_wrapper(sync_func))\nf4 = functools.partial(wrapper(async_func))\n\nfrom starlette._utils import is_async_callable\nprint(f'f1: {is_async_callable(f1)}') # Expected: True\nprint(f'f2: {is_async_callable(f2)}') # Expected: True (if unwraps)\nprint(f'f3: {is_async_callable(f3)}') # Expected: True\nprint(f'f4: {is_async_callable(f4)}') # Expected: True\n\""
} | {"status": "error", "error_type": "CommandError", "error_message": "<string>:15: RuntimeWarning: coroutine 'async_wrapper' was never awaited\nRuntimeWarning: Enfull{"status": "error", "error_type": "CommandError", "error_message": "<string>:15: RuntimeWarning: coroutine 'async_wrapper' was never awaited\nRuntimeWarning: Enable tracemalloc to get the object allocation traceback\nTraceback (most recent call last):\n File \"<string>\", line 15, in <module>\n f3 = functools.partial(async_wrapper(sync_func))\nTypeError: the first argument must be callable\n<sys>:0: RuntimeWarning: coroutine 'async_wrapper' was never awaited\n", "details": {"stdout": "", "stderr": "<string>:15: RuntimeWarning: coroutine 'async_wrapper' was never awaited\nRuntimeWarning: Enable tracemalloc to get the object allocation traceback\nTraceback (most recent call last):\n File \"<string>\", line 15, in <module>\n f3 = functools.partial(async_wrapper(sync_func))\nTypeError: the first argument must be callable\n<sys>:0: RuntimeWarning: coroutine 'async_wrapper' was never awaited\n", "exit_code": 1}} |
| 18 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\nf1 = async_wrapper(sync_func)\nf2 = wrapper(async_func)\nf3 = functools.partial(async_wrapper(sync_func)) # WRONG: async_wrapper returns a coroutine if it's async_def\n# Wait, I defined async_wrapper as a normal def that returns an async def.\n\n# Correction:\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\nf1 = async_wrapper(sync_func)\nf2 = sync_wrapper(async_func)\nf3 = functools.partial(async_wrapper(sync_func)) # This is still wrong. async_wrapper(sync_func) returns the wrapped function.\nf3 = functools.partial(async_wrapper(sync_func)) # Correct\n\n# Actually, let's just use them:\nf1 = async_wrapper(sync_func)\nf2 = sync_wrapper(async_func)\nf3 = functools.partial(f1)\nf4 = functools.partial(f2)\n\nfrom starlette._utils import is_async_callable\nprint(f'f1: {is_async_callable(f1)}')\nprint(f'f2: {is_async_callable(f2)}')\nprint(f'f3: {is_async_callable(f3)}')\nprint(f'f4: {is_async_callable(f4)}')\n\""
} | {"status": "ok", "stdout": "f1: True\nf2: False\nf3: True\nf4: False\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f1: True\nf2: False\nf3: True\nf4: False\n", "stderr": "", "exit_code": 0} |
| 19 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\nf1 = async_wrapper(sync_func)\nf2 = sync_wrapper(async_func)\nf3 = functools.partial(f1)\nf4 = functools.partial(f2)\n\nfrom starlette._utils import is_async_callable\nprint(f'f1: {is_async_callable(f1)}') # True - because wrapped is async\nprint(f'f2: {is_async_callable(f2)}') # False - because wrapped is sync, and is_async_callable doesn't unwrap wraps\nprint(f'f3: {is_async_callable(f3)}') # True - because partial.func is async\nprint(f'f4: {is_async_callable(f4)}') # False - because partial.func is sync\n\""
} | {"status": "ok", "stdout": "f1: True\nf2: False\nf3: True\nf4: False\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f1: True\nf2: False\nf3: True\nf4: False\n", "stderr": "", "exit_code": 0} |
| 20 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\nf2 = sync_wrapper(async_func)\nprint(f'f2: {inspect.unwrap(f2)} is async: {asyncio.iscoroutinefunction(inspect.unwrap(f2))}')\n\""
} | {"status": "ok", "stdout": "f2: <function async_func at 0x105abb880> is async: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f2: <function async_func at 0x105abb880> is async: True\n", "stderr": "", "exit_code": 0} |
| 21 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\nf2 = sync_wrapper(async_func)\nprint(f'f2: {inspect.iscoroutinefunction(f2)}')\nprint(f'unwrap(f2): {inspect.iscoroutinefunction(inspect.unwrap(f2))}')\n\""
} | {"status": "ok", "stdout": "f2: False\nunwrap(f2): True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f2: False\nunwrap(f2): True\n", "stderr": "", "exit_code": 0} |
| 22 | run_command | {
"command": "cat /workspace/fastapi/dependencies/models.py"
} | {"status": "ok", "stdout": "import inspect\nimport sys\nfrom dataclasses import dataclass, field\nfrom functools import cached_property, partial\nfrom typing imfull{"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, Sequence, 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\n@dataclass\nclass SecurityRequirement:\n security_scheme: SecurityBase\n scopes: Optional[Sequence[str]] = None\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 security_requirements: List[SecurityRequirement] = 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) -> List[str]:\n scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else []\n # This doesn't use a set to |
| 23 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\n# case 1: sync wrapper of async func\nf2 = sync_wrapper(async_func)\n# case 2: async wrapper of sync func\nf1 = async_wrapper(sync_func)\n\nfrom starlette._utils import is_async_callable\nprint(f'f1: {is_async_callable(f1)}') # True (wrapped is async)\nprint(f'f2: {is_async_callable(f2)}') # False (wrapped is sync, is_async_callable doesn't unwrap)\n\""
} | {"status": "ok", "stdout": "f1: True\nf2: False\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f1: True\nf2: False\n", "stderr": "", "exit_code": 0} |
| 24 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\n# case 1: sync wrapper of async func\nf2 = sync_wrapper(async_func)\n# case 2: async wrapper of sync func\nf1 = async_wrapper(sync_func)\n\ndef improved_is_async_callable(obj):\n while isinstance(obj, functools.partial):\n obj = obj.func\n \n if asyncio.iscoroutinefunction(obj) or (callable(obj) and asyncio.iscoroutinefunction(getattr(obj, '__call__', None))):\n return True\n \n unwrapped = inspect.unwrap(obj)\n if asyncio.iscoroutinefunction(unwrapped) or (callable(unwrapped) and asyncio.iscoroutinefunction(getattr(unwrapped, '__call__', None))):\n return True\n \n return False\n\nprint(f'f1: {improved_is_async_callable(f1)}') # True\nprint(f'f2: {improved_is_async_callable(f2)}') # True\n\""
} | {"status": "ok", "stdout": "f1: True\nf2: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f1: True\nf2: True\n", "stderr": "", "exit_code": 0} |
| 25 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\n# f3 = functools.partial(async_wrapper(sync_func))\nf3 = functools.partial(async_wrapper(sync_func))\n# f4 = functools.partial(sync_wrapper(async_func))\nf4 = functools.partial(sync_wrapper(async_func))\n\ndef improved_is_async_callable(obj):\n while isinstance(obj, functools.partial):\n obj = obj.func\n \n if asyncio.iscoroutinefunction(obj) or (callable(obj) and asyncio.iscoroutinefunction(getattr(obj, '__call__', None))):\n return True\n \n unwrapped = inspect.unwrap(obj)\n if asyncio.iscoroutinefunction(unwrapped) or (callable(unwrapped) and asyncio.iscoroutinefunction(getattr(unwrapped, '__call__', None))):\n return True\n \n return False\n\nprint(f'f3: {improved_is_async_callable(f3)}') # True\nprint(f'f4: {improved_is_async_callable(f4)}') # True\n\""
} | {"status": "ok", "stdout": "f3: True\nf4: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f3: True\nf4: True\n", "stderr": "", "exit_code": 0} |
| 26 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\n# test combined\nf5 = functools.partial(sync_wrapper(async_func))\nf6 = functools.partial(async_wrapper(sync_func))\n\ndef improved_is_async_callable(obj):\n while isinstance(obj, functools.partial):\n obj = obj.func\n \n if asyncio.iscoroutinefunction(obj) or (callable(obj) and asyncio.iscoroutinefunction(getattr(obj, '__call__', None))):\n return True\n \n unwrapped = inspect.unwrap(obj)\n if asyncio.iscoroutinefunction(unwrapped) or (callable(unwrapped) and asyncio.iscoroutinefunction(getattr(unwrapped, '__call__', None))):\n return True\n \n return False\n\nprint(f'f5: {improved_is_async_callable(f5)}') # True\nprint(f'f6: {improved_is_async_callable(f6)}') # True\n\""
} | {"status": "ok", "stdout": "f5: True\nf6: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f5: True\nf6: True\n", "stderr": "", "exit_code": 0} |
| 27 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\n# combined wraps and partials\nf7 = functools.partial(sync_wrapper(async_func))\nf8 = sync_wrapper(functools.partial(async_func))\n\ndef improved_is_async_callable(obj):\n # This is tricky. We might need to repeatedly unwrap and check for partials.\n current = obj\n while True:\n if asyncio.iscoroutinefunction(current) or (callable(current) and asyncio.iscoroutinefunction(getattr(current, '__call__', None))):\n return True\n \n if isinstance(current, functools.partial):\n current = current.func\n continue\n \n unwrapped = inspect.unwrap(current)\n if unwrapped is current:\n break\n current = unwrapped\n \n return False\n\nprint(f'f7: {improved_is_async_callable(f7)}') # True\nprint(f'f8: {improved_is_async_callable(f8)}') # True\n\""
} | {"status": "ok", "stdout": "f7: True\nf8: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f7: True\nf8: True\n", "stderr": "", "exit_code": 0} |
| 28 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\n# Combined wraps and partials\nf7 = functools.partial(sync_wrapper(async_func))\nf8 = sync_wrapper(functools.partial(async_func))\n\ndef improved_is_async_callable(obj):\n current = obj\n while True:\n if asyncio.iscoroutinefunction(current) or (callable(current) and asyncio.iscoroutinefunction(getattr(current, '__call__', None))):\n return True\n \n if isinstance(current, functools.partial):\n current = current.func\n continue\n \n unwrapped = inspect.unwrap(current)\n if unwrapped is current:\n break\n current = unwrapped\n \n return False\n\nprint(f'f7: {improved_is_async_callable(f7)}')\nprint(f'f8: {improved_is_async_callable(f8)}')\n\""
} | {"status": "ok", "stdout": "f7: True\nf8: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f7: True\nf8: True\n", "stderr": "", "exit_code": 0} |
| 29 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\n# Test a sync one\nf9 = sync_wrapper(sync_func)\nf10 = functools.partial(f9)\n\ndef improved_is_async_callable(obj):\n current = obj\n while True:\n if asyncio.iscoroutinefunction(current) or (callable(current) and asyncio.iscoroutinefunction(getattr(current, '__call__', None))):\n return True\n \n if isinstance(current, functools.partial):\n current = current.func\n continue\n \n unwrapped = inspect.unwrap(current)\n if unwrapped is current:\n break\n current = unwrapped\n \n return False\n\nprint(f'f9: {improved_is_async_callable(f9)}') # False\nprint(f'f10: {improved_is_async_callable(f10)}') # False\n\""
} | {"status": "ok", "stdout": "f9: False\nf10: False\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f9: False\nf10: False\n", "stderr": "", "exit_code": 0} |
| 30 | run_command | {
"command": "python3 -c \"import functools; import asyncio; import inspect; \ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\nclass SyncCallable:\n def __call__(self): pass\nclass AsyncCallable:\n async def __call__(self): pass\n\nc1 = SyncCallable()\nc2 = AsyncCallable()\nc3 = functools.partial(c1)\nc4 = functools.partial(c2)\n\ndef improved_is_async_callable(obj):\n current = obj\n while True:\n if asyncio.iscoroutinefunction(current) or (callable(current) and asyncio.iscoroutinefunction(getattr(current, '__call__', None))):\n return True\n \n if isinstance(current, functools.partial):\n current = current.func\n continue\n \n unwrapped = inspect.unwrap(current)\n if unwrapped is current:\n break\n current = unwrapped\n \n return False\n\nprint(f'c1: {improved_is_async_callable(c1)}') # False\nprint(f'c2: {improved_is_async_callable(c2)}') # True\nprint(f'c3: {improved_is_async_callable(c3)}') # False\nprint(f'c4: {improved_is_async_callable(c4)}') # True\n\""
} | {"status": "ok", "stdout": "c1: False\nc2: True\nc3: False\nc4: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "c1: False\nc2: True\nc3: False\nc4: True\n", "stderr": "", "exit_code": 0} |
| 31 | run_command | {
"command": "cat /workspace/fastapi/dependencies/models.py"
} | {"status": "ok", "stdout": "import inspect\nimport sys\nfrom dataclasses import dataclass, field\nfrom functools import cached_property, partial\nfrom typing imfull{"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, Sequence, 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\n@dataclass\nclass SecurityRequirement:\n security_scheme: SecurityBase\n scopes: Optional[Sequence[str]] = None\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 security_requirements: List[SecurityRequirement] = 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) -> List[str]:\n scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else []\n # This doesn't use a set to |
| 32 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"fastapi/dependencies/models.py\")\ns = p.read_text()\nold = \"\"\" @cached_property\n def _unwrapped_call(self) -> Any:\n if self.call is None:\n return self.call # pragma: no cover\n unwrapped = inspect.unwrap(self.call)\n if isinstance(unwrapped, partial):\n unwrapped = unwrapped.func\n return unwrapped\"\"\"\nnew = \"\"\" @cached_property\n def _unwrapped_call(self) -> Any:\n if self.call is None:\n return self.call # pragma: no cover\n current = self.call\n while True:\n if isinstance(current, partial):\n current = current.func\n continue\n unwrapped = inspect.unwrap(current)\n if unwrapped is current:\n break\n current = unwrapped\n return current\"\"\"\nassert s.count(old) == 1, (\"old text found this many times:\", s.count(old))\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 33 | run_command | {
"command": "python3 -m py_compile fastapi/dependencies/models.py"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 34 | run_command | {
"command": "python3 -c \"import fastapi.dependencies.models; print('Import successful')\""
} | {"status": "ok", "stdout": "Import successful\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Import successful\n", "stderr": "", "exit_code": 0} |
| 35 | run_command | {
"command": "python3 - <<'PY'\nimport functools\nimport asyncio\nimport inspect\nfrom fastapi.dependencies.models import Dependant\nfrom functools import partial\n\ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\n# Test cases\ncases = [\n (\"sync_func\", sync_func),\n (\"async_func\", async_func),\n (\"sync_wrapped_sync\", sync_wrapper(sync_func)),\n (\"async_wrapped_sync\", async_wrapper(sync_func)),\n (\"sync_wrapped_async\", sync_wrapper(async_func)),\n (\"async_wrapped_async\", async_wrapper(async_func)),\n (\"partial_sync\", partial(sync_func)),\n (\"partial_async\", partial(async_func)),\n (\"partial_sync_wrapped_sync\", partial(sync_wrapper(sync_func))),\n (\"partial_async_wrapped_sync\", partial(async_wrapper(sync_func))),\n (\"partial_sync_wrapped_async\", partial(sync_wrapper(async_func))),\n (\"partial_async_wrapped_async\", partial(async_wrapper(async_func))),\n (\"sync_wrapped_partial_async\", sync_wrapper(partial(async_func))),\n]\n\nfor name, func in cases:\n dep = Dependant(call=func)\n is_coro = dep.is_coroutine_callable\n # Determine expected\n # It's a coroutine if any part of the chain is async\n \n # Manual check for expected\n expected = False\n current = func\n while True:\n if asyncio.iscoroutinefunction(current) or (callable(current) and asyncio.iscoroutinefunction(getattr(current, '__call__', None))):\n expected = True\n break\n if isinstance(current, partial):\n current = current.func\n continue\n unwrapped = inspect.unwrap(current)\n if unwrapped is current:\n break\n current = unwrapped\n \n print(f\"{name:30} | Actual: {str(is_coro):5} | Expected: {str(expected):5} | {'PASS' if is_coro == expected else 'FAIL'}\")\nPY\n"
} | {"status": "ok", "stdout": "sync_func | Actual: False | Expected: False | PASS\nasync_func | Actual: True | Expected: True | PASS\nsync_wrapped_sync | Actual: Ffull{"status": "ok", "stdout": "sync_func | Actual: False | Expected: False | PASS\nasync_func | Actual: True | Expected: True | PASS\nsync_wrapped_sync | Actual: False | Expected: False | PASS\nasync_wrapped_sync | Actual: False | Expected: True | FAIL\nsync_wrapped_async | Actual: True | Expected: True | PASS\nasync_wrapped_async | Actual: True | Expected: True | PASS\npartial_sync | Actual: False | Expected: False | PASS\npartial_async | Actual: True | Expected: True | PASS\npartial_sync_wrapped_sync | Actual: False | Expected: False | PASS\npartial_async_wrapped_sync | Actual: False | Expected: True | FAIL\npartial_sync_wrapped_async | Actual: True | Expected: True | PASS\npartial_async_wrapped_async | Actual: True | Expected: True | PASS\nsync_wrapped_partial_async | Actual: True | Expected: True | PASS\n", "stderr": "", "exit_code": 0} |
| 36 | run_command | {
"command": "python3 - <<'PY'\nimport functools\nimport asyncio\nimport inspect\nfrom fastapi.dependencies.models import Dependant\nfrom functools import partial\n\ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\nf1 = async_wrapper(sync_func)\ndep = Dependant(call=f1)\nprint(f\"f1: {dep._unwrapped_call}\")\nprint(f\"f1 is coro: {dep.is_coroutine_callable}\")\nPY\n"
} | {"status": "ok", "stdout": "f1: <function sync_func at 0x10142f420>\nf1 is coro: False\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f1: <function sync_func at 0x10142f420>\nf1 is coro: False\n", "stderr": "", "exit_code": 0} |
| 37 | run_command | {
"command": "python3 - <<'PY'\nimport functools\nimport asyncio\nimport inspect\nfrom fastapi.dependencies.models import Dependant\nfrom functools import partial\n\ndef sync_func(): pass\nasync def async_func(): pass\ndef sync_wrapper(f):\n @functools.wraps(f)\n def wrapped(*args, **kwargs): return f(*args, **kwargs)\n return wrapped\ndef async_wrapper(f):\n @functools.wraps(f)\n async def wrapped(*args, **kwargs): return await f(*args, **kwargs) if asyncio.iscoroutinefunction(f) else f(*args, **kwargs)\n return wrapped\n\nf1 = async_wrapper(sync_func)\n# f1 is the wrapped function, which is async.\nprint(f\"f1 is async: {asyncio.iscoroutinefunction(f1)}\")\nPY\n"
} | {"status": "ok", "stdout": "f1 is async: True\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "f1 is async: True\n", "stderr": "", "exit_code": 0} |
diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py
index 2a4d9a01..1283585f 100644
--- a/fastapi/dependencies/models.py
+++ b/fastapi/dependencies/models.py
@@ -79,10 +79,16 @@ class Dependant:
def _unwrapped_call(self) -> Any:
if self.call is None:
return self.call # pragma: no cover
- unwrapped = inspect.unwrap(self.call)
- if isinstance(unwrapped, partial):
- unwrapped = unwrapped.func
- return unwrapped
+ current = self.call
+ while True:
+ if isinstance(current, partial):
+ current = current.func
+ continue
+ unwrapped = inspect.unwrap(current)
+ if unwrapped is current:
+ break
+ current = unwrapped
+ return current
@cached_property
def is_gen_callable(self) -> bool:
urn encoder_instance(obj)
if include is not None and not isinstance(include, (set, dict)):
include = set(include)
if exclude is not None and not isinstance(exclude, (set, dict)):
exclude = set(exclude)
if isinstance(obj, (BaseModel, may_v1.BaseModel)):
# TODO: remove when deprecating Pydantic v1
encoders: Dict[Any, Any] = {}
if isinstance(obj, may_v1.BaseModel):
encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
if custom_encoder:
encoders = {**encoders, **custom_encoder}
obj_dict = _model_dump(
obj,
mode="json",
include=include,
exclude=exclude,
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_none=exclude_none,
exclude_defaults=exclude_defaults,
)
if "__root__" in obj_dict:
obj_dict = obj_dict["__root__"]
return jsonable_encoder(
obj_dict,
exclude_none=exclude_none,
exclude_defaults=exclude_defaults,
# TODO: remove when deprecating Pydantic v1
custom_encoder=encoders,
sqlalchemy_safe=sqlalchemy_safe,
)
if dataclasses.is_dataclass(obj):
assert not isinstance(obj, type)
obj_dict = dataclasses.asdict(obj)
return jsonable_encoder(
obj_dict,
include=include,
exclude=exclude,
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
if isinstance(obj, Enum):
return obj.value
if isinstance(obj, PurePath):
return str(obj)
if isinstance(obj, (str, int, float, type(None))):
return obj
if _is_undefined(obj):
return None
if isinstance(obj, dict):
encoded_dict = {}
allowed_keys = set(obj.keys())
if include is not None:
allowed_keys &= set(include)
if exclude is not None:
allowed_keys -= set(exclude)
for key, value in obj.items():
if (
(
not sqlalchemy_safe
or (not isinstance(key, str))
or (not key.startswith("_sa"))
)
and (value is not None or not exclude_none)
and key in allowed_keys
):
encoded_key = jsonable_encoder(
key,
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
encoded_value = jsonable_encoder(
value,
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
encoded_dict[encoded_key] = encoded_value
return encoded_dict
if isinstance(obj, (list, set, frozenset, GeneratorType, tuple, deque)):
encoded_list = []
for item in obj:
encoded_list.append(
jsonable_encoder(
item,
include=include,
exclude=exclude,
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
)
return encoded_list
if type(obj) in ENCODERS_BY_TYPE:
return ENCODERS_BY_TYPE[type(obj)](obj)
for encoder, classes_tuple in encoders_by_class_tuples.items():
if isinstance(obj, classes_tuple):
return encoder(obj)
try:
data = dict(obj)
except Exception as e:
errors: List[Exception] = []
errors.append(e)
try:
data = vars(obj)
except Exception as e:
errors.append(e)
> raise ValueError(errors) from e
E ValueError: [TypeError("'coroutine' object is not iterable"), TypeError('vars() argument must have __dict__ attribute')]
fastapi/encoders.py:345: ValueError
=============================== 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, 10 passed, 1 warning in 0.77s
<sys>:0: RuntimeWarning: coroutine 'ClassInstanceAsyncWrappedDep.__call__' was never awaited