From fb59eb1a97628792f5e6e8ffaa030d4451bf1ea1 Mon Sep 17 00:00:00 2001 From: huangyi Date: Mon, 24 Mar 2025 20:24:19 +0800 Subject: [PATCH 1/4] pass is_async to handler --- respx/models.py | 16 ++++++++-------- respx/router.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/respx/models.py b/respx/models.py index 9690324..59b650a 100644 --- a/respx/models.py +++ b/respx/models.py @@ -327,7 +327,7 @@ def _next_side_effect( return effect def _call_side_effect( - self, effect: CallableSideEffect, request: httpx.Request, **kwargs: Any + self, effect: CallableSideEffect, request: httpx.Request, is_async: bool, **kwargs: Any ) -> RouteResultTypes: # Add route kwarg if the side effect wants it argspec = inspect.getfullargspec(effect) @@ -338,7 +338,7 @@ def _call_side_effect( try: # Call side effect - result: RouteResultTypes = effect(request, **kwargs) + result: RouteResultTypes = effect(request, is_async, **kwargs) except Exception as error: raise SideEffectError(self, origin=error) from error @@ -357,7 +357,7 @@ def _call_side_effect( return result def _resolve_side_effect( - self, request: httpx.Request, **kwargs: Any + self, request: httpx.Request, is_async: bool, **kwargs: Any ) -> RouteResultTypes: effect = self._next_side_effect() @@ -379,17 +379,17 @@ def _resolve_side_effect( # Handle `Callable` side effect elif callable(effect): - result = self._call_side_effect(effect, request, **kwargs) + result = self._call_side_effect(effect, request, is_async, **kwargs) return result # Resolved effect is a mocked response return effect - def resolve(self, request: httpx.Request, **kwargs: Any) -> RouteResultTypes: + def resolve(self, request: httpx.Request, is_async: bool, **kwargs: Any) -> RouteResultTypes: result: RouteResultTypes = None if self._side_effect: - result = self._resolve_side_effect(request, **kwargs) + result = self._resolve_side_effect(request, is_async, **kwargs) if result is None: return None # Side effect resolved as a non-matching route @@ -406,7 +406,7 @@ def resolve(self, request: httpx.Request, **kwargs: Any) -> RouteResultTypes: return result - def match(self, request: httpx.Request) -> RouteResultTypes: + def match(self, request: httpx.Request, is_async: bool) -> RouteResultTypes: """ Matches and resolves request with given patterns and optional side effect. @@ -424,7 +424,7 @@ def match(self, request: httpx.Request) -> RouteResultTypes: if self._pass_through: return request - result = self.resolve(request, **context) + result = self.resolve(request, is_async, **context) return result diff --git a/respx/router.py b/respx/router.py index 449a5a4..8fa49d6 100644 --- a/respx/router.py +++ b/respx/router.py @@ -276,7 +276,7 @@ def resolver(self, request: httpx.Request) -> Generator[ResolvedRoute, None, Non def resolve(self, request: httpx.Request) -> ResolvedRoute: with self.resolver(request) as resolved: for route in self.routes: - prospect = route.match(request) + prospect = route.match(request, False) if prospect is not None: resolved.route = route resolved.response = cast(ResolvedResponseTypes, prospect) @@ -290,7 +290,7 @@ def resolve(self, request: httpx.Request) -> ResolvedRoute: async def aresolve(self, request: httpx.Request) -> ResolvedRoute: with self.resolver(request) as resolved: for route in self.routes: - prospect: RouteResultTypes = route.match(request) + prospect: RouteResultTypes = route.match(request, True) # Await async side effect and wrap any exception if inspect.isawaitable(prospect): From 4e2a29a3de5cf79d50f4c4837d68bcca2ce90f5b Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 21 May 2025 15:35:46 +0800 Subject: [PATCH 2/4] reflect callback signature --- respx/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/respx/models.py b/respx/models.py index 59b650a..499ce07 100644 --- a/respx/models.py +++ b/respx/models.py @@ -327,7 +327,7 @@ def _next_side_effect( return effect def _call_side_effect( - self, effect: CallableSideEffect, request: httpx.Request, is_async: bool, **kwargs: Any + self, effect: CallableSideEffect, request: httpx.Request, is_async: bool, **kwargs: Any ) -> RouteResultTypes: # Add route kwarg if the side effect wants it argspec = inspect.getfullargspec(effect) @@ -335,10 +335,12 @@ def _call_side_effect( warn(f"Matched context contains reserved word `route`: {self.pattern!r}") if "route" in argspec.args: kwargs["route"] = self + if "is_async" in argspec.args: + kwargs["is_async"] = is_async try: # Call side effect - result: RouteResultTypes = effect(request, is_async, **kwargs) + result: RouteResultTypes = effect(request, **kwargs) except Exception as error: raise SideEffectError(self, origin=error) from error From 113da69d2e0507e72d45cbc02d47a34b2c7590ee Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 21 May 2025 15:51:43 +0800 Subject: [PATCH 3/4] reserve is_async --- respx/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/respx/models.py b/respx/models.py index 499ce07..67d6765 100644 --- a/respx/models.py +++ b/respx/models.py @@ -333,6 +333,8 @@ def _call_side_effect( argspec = inspect.getfullargspec(effect) if "route" in kwargs: warn(f"Matched context contains reserved word `route`: {self.pattern!r}") + if "is_async" in kwargs: + warn(f"Matched context contains reserved word `is_async`: {self.pattern!r}") if "route" in argspec.args: kwargs["route"] = self if "is_async" in argspec.args: From f0be2c88ad95f04f95497b638341ca36e96034df Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 23 May 2025 10:49:41 +0800 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Jonas Lundberg --- respx/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/respx/models.py b/respx/models.py index 67d6765..2f12caa 100644 --- a/respx/models.py +++ b/respx/models.py @@ -327,7 +327,7 @@ def _next_side_effect( return effect def _call_side_effect( - self, effect: CallableSideEffect, request: httpx.Request, is_async: bool, **kwargs: Any + self, effect: CallableSideEffect, request: httpx.Request, /, is_async: bool, **kwargs: Any ) -> RouteResultTypes: # Add route kwarg if the side effect wants it argspec = inspect.getfullargspec(effect) @@ -361,7 +361,7 @@ def _call_side_effect( return result def _resolve_side_effect( - self, request: httpx.Request, is_async: bool, **kwargs: Any + self, request: httpx.Request, /, is_async: bool, **kwargs: Any ) -> RouteResultTypes: effect = self._next_side_effect() @@ -389,7 +389,7 @@ def _resolve_side_effect( # Resolved effect is a mocked response return effect - def resolve(self, request: httpx.Request, is_async: bool, **kwargs: Any) -> RouteResultTypes: + def resolve(self, request: httpx.Request, /, is_async: bool, **kwargs: Any) -> RouteResultTypes: result: RouteResultTypes = None if self._side_effect: @@ -410,7 +410,7 @@ def resolve(self, request: httpx.Request, is_async: bool, **kwargs: Any) -> Rout return result - def match(self, request: httpx.Request, is_async: bool) -> RouteResultTypes: + def match(self, request: httpx.Request, /, is_async: bool) -> RouteResultTypes: """ Matches and resolves request with given patterns and optional side effect.