]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🐛 Fix `inspect.getcoroutinefunction()` can break testing with `unittest.mock.patch...
authorsecrett2633 <65999962+secrett2633@users.noreply.github.com>
Sat, 20 Sep 2025 16:30:34 +0000 (01:30 +0900)
committerGitHub <noreply@github.com>
Sat, 20 Sep 2025 16:30:34 +0000 (18:30 +0200)
fastapi/dependencies/utils.py
fastapi/routing.py

index 081b63a8bdcef8d0743e0cd4a2900d37897642cc..1b15e64594508118fdf1a7035c0e5a0ef0cb180d 100644 (file)
@@ -1,4 +1,5 @@
 import inspect
+import sys
 from contextlib import AsyncExitStack, contextmanager
 from copy import copy, deepcopy
 from dataclasses import dataclass
@@ -73,6 +74,11 @@ from starlette.responses import Response
 from starlette.websockets import WebSocket
 from typing_extensions import Annotated, get_args, get_origin
 
+if sys.version_info >= (3, 13):  # pragma: no cover
+    from inspect import iscoroutinefunction
+else:  # pragma: no cover
+    from asyncio import iscoroutinefunction
+
 multipart_not_installed_error = (
     'Form data requires "python-multipart" to be installed. \n'
     'You can install "python-multipart" with: \n\n'
@@ -529,11 +535,11 @@ def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
 
 def is_coroutine_callable(call: Callable[..., Any]) -> bool:
     if inspect.isroutine(call):
-        return inspect.iscoroutinefunction(call)
+        return iscoroutinefunction(call)
     if inspect.isclass(call):
         return False
     dunder_call = getattr(call, "__call__", None)  # noqa: B004
-    return inspect.iscoroutinefunction(dunder_call)
+    return iscoroutinefunction(dunder_call)
 
 
 def is_async_gen_callable(call: Callable[..., Any]) -> bool:
index 5418ad9826f273f8d4aa2a40caa6d1eff27e400e..f620ced5fa504239d07486b0acb5aef19bbacbc7 100644 (file)
@@ -1,8 +1,8 @@
-import asyncio
 import dataclasses
 import email.message
 import inspect
 import json
+import sys
 from contextlib import AsyncExitStack, asynccontextmanager
 from enum import Enum, IntEnum
 from typing import (
@@ -76,6 +76,11 @@ from starlette.types import AppType, ASGIApp, Lifespan, Scope
 from starlette.websockets import WebSocket
 from typing_extensions import Annotated, Doc, deprecated
 
+if sys.version_info >= (3, 13):  # pragma: no cover
+    from inspect import iscoroutinefunction
+else:  # pragma: no cover
+    from asyncio import iscoroutinefunction
+
 
 def _prepare_response_content(
     res: Any,
@@ -232,7 +237,7 @@ def get_request_handler(
     embed_body_fields: bool = False,
 ) -> Callable[[Request], Coroutine[Any, Any, Response]]:
     assert dependant.call is not None, "dependant.call must be a function"
-    is_coroutine = asyncio.iscoroutinefunction(dependant.call)
+    is_coroutine = iscoroutinefunction(dependant.call)
     is_body_form = body_field and isinstance(body_field.field_info, params.Form)
     if isinstance(response_class, DefaultPlaceholder):
         actual_response_class: Type[Response] = response_class.value