|
6 | 6 | import logging |
7 | 7 | import re |
8 | 8 | import traceback |
9 | | -import typing |
10 | 9 | import warnings |
11 | 10 | import zlib |
12 | 11 | from abc import ABC, abstractmethod |
@@ -468,10 +467,10 @@ def __init__( |
468 | 467 |
|
469 | 468 | self.custom_response_validation_http_code = custom_response_validation_http_code |
470 | 469 |
|
471 | | - # _request_param_name caches the name of any Request-typed parameter in the handler (None = "not found"). |
472 | | - # _request_param_checked avoids re-scanning the signature on every invocation. |
473 | | - self._request_param_name: str | None = None |
474 | | - self._request_param_name_checked: bool = False |
| 470 | + # Caches the name of any Request-typed parameter in the handler. |
| 471 | + # Avoids re-scanning the signature on every invocation. |
| 472 | + self.request_param_name: str | None = None |
| 473 | + self.request_param_name_checked: bool = False |
475 | 474 |
|
476 | 475 | def __call__( |
477 | 476 | self, |
@@ -1638,16 +1637,23 @@ def my_middleware(app, next_middleware): |
1638 | 1637 | return next_middleware(app) |
1639 | 1638 | ``` |
1640 | 1639 | """ |
| 1640 | + cached: Request | None = self.context.get("_request") |
| 1641 | + if cached is not None: |
| 1642 | + return cached |
| 1643 | + |
1641 | 1644 | route: Route | None = self.context.get("_route") |
1642 | 1645 | if route is None: |
1643 | 1646 | raise RuntimeError( |
1644 | 1647 | "app.request is only available after route resolution. Use it inside middleware or a route handler.", |
1645 | 1648 | ) |
1646 | | - return Request( |
| 1649 | + |
| 1650 | + request = Request( |
1647 | 1651 | route_path=route.openapi_path, |
1648 | 1652 | path_parameters=self.context.get("_route_args", {}), |
1649 | 1653 | current_event=self.current_event, |
1650 | 1654 | ) |
| 1655 | + self.context["_request"] = request |
| 1656 | + return request |
1651 | 1657 |
|
1652 | 1658 |
|
1653 | 1659 | class MiddlewareFrame: |
@@ -1723,10 +1729,12 @@ def __call__(self, app: ApiGatewayResolver) -> dict | tuple | Response: |
1723 | 1729 |
|
1724 | 1730 | def _find_request_param_name(func: Callable) -> str | None: |
1725 | 1731 | """Return the name of the first parameter annotated as ``Request``, or ``None``.""" |
| 1732 | + from typing import get_type_hints |
| 1733 | + |
1726 | 1734 | try: |
1727 | 1735 | # get_type_hints resolves string annotations from ``from __future__ import annotations`` |
1728 | | - # using the function's own module globals — no pydantic dependency required. |
1729 | | - hints = typing.get_type_hints(func) |
| 1736 | + # using the function's own module globals. |
| 1737 | + hints = get_type_hints(func) |
1730 | 1738 | except Exception: |
1731 | 1739 | hints = {} |
1732 | 1740 |
|
@@ -1770,11 +1778,11 @@ def _registered_api_adapter( |
1770 | 1778 | # Lookup is cached on the Route object to avoid repeated signature inspection. |
1771 | 1779 | route: Route | None = app.context.get("_route") |
1772 | 1780 | if route is not None: |
1773 | | - if not route._request_param_name_checked: |
1774 | | - route._request_param_name = _find_request_param_name(next_middleware) |
1775 | | - route._request_param_name_checked = True |
1776 | | - if route._request_param_name: |
1777 | | - route_args = {**route_args, route._request_param_name: app.request} |
| 1781 | + if not route.request_param_name_checked: |
| 1782 | + route.request_param_name = _find_request_param_name(next_middleware) |
| 1783 | + route.request_param_name_checked = True |
| 1784 | + if route.request_param_name: |
| 1785 | + route_args = {**route_args, route.request_param_name: app.request} |
1778 | 1786 |
|
1779 | 1787 | return app._to_response(next_middleware(**route_args)) |
1780 | 1788 |
|
|
0 commit comments