From b1bd65dbd191b318325c4b87d626bb5d7967cda7 Mon Sep 17 00:00:00 2001 From: Cycloctane Date: Tue, 14 Oct 2025 21:19:08 +0800 Subject: [PATCH] Make AppRunner's configuration options available in run_app() (#11633) --- CHANGES/11633.feature.rst | 2 ++ aiohttp/web.py | 21 ++++----------------- docs/web_reference.rst | 6 +++++- tests/test_run_app.py | 27 +++++++++++++++++---------- 4 files changed, 28 insertions(+), 28 deletions(-) create mode 100644 CHANGES/11633.feature.rst diff --git a/CHANGES/11633.feature.rst b/CHANGES/11633.feature.rst new file mode 100644 index 00000000000..374d15a2acd --- /dev/null +++ b/CHANGES/11633.feature.rst @@ -0,0 +1,2 @@ +Make configuration options in ``AppRunner`` also available in ``run_app()`` +-- by :user:`Cycloctane`. diff --git a/aiohttp/web.py b/aiohttp/web.py index 895d91e662e..be0797031a1 100644 --- a/aiohttp/web.py +++ b/aiohttp/web.py @@ -277,18 +277,12 @@ async def _run_app( port: int | None = None, path: PathLike | TypingIterable[PathLike] | None = None, sock: socket.socket | TypingIterable[socket.socket] | None = None, - shutdown_timeout: float = 60.0, - keepalive_timeout: float = 75.0, ssl_context: SSLContext | None = None, print: Callable[..., None] | None = print, backlog: int = 128, - access_log_class: type[AbstractAccessLogger] = AccessLogger, - access_log_format: str = AccessLogger.LOG_FORMAT, - access_log: logging.Logger | None = access_logger, - handle_signals: bool = True, reuse_address: bool | None = None, reuse_port: bool | None = None, - handler_cancellation: bool = False, + **kwargs: Any, # TODO(PY311): Use Unpack ) -> None: # An internal function to actually do all dirty job for application running if asyncio.iscoroutine(app): @@ -296,16 +290,7 @@ async def _run_app( app = cast(Application, app) - runner = AppRunner( - app, - handle_signals=handle_signals, - access_log_class=access_log_class, - access_log_format=access_log_format, - access_log=access_log, - keepalive_timeout=keepalive_timeout, - shutdown_timeout=shutdown_timeout, - handler_cancellation=handler_cancellation, - ) + runner = AppRunner(app, **kwargs) await runner.setup() @@ -453,6 +438,7 @@ def run_app( reuse_port: bool | None = None, handler_cancellation: bool = False, loop: asyncio.AbstractEventLoop | None = None, + **kwargs: Any, ) -> None: """Run an app locally""" if loop is None: @@ -485,6 +471,7 @@ def run_app( reuse_address=reuse_address, reuse_port=reuse_port, handler_cancellation=handler_cancellation, + **kwargs, ) ) diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 0e62fd66dad..25f45c38ab2 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -2920,7 +2920,8 @@ Utilities handle_signals=True, \ reuse_address=None, \ reuse_port=None, \ - handler_cancellation=False) + handler_cancellation=False, \ + **kwargs) A high-level function for running an application, serving it until keyboard interrupt and performing a @@ -3032,6 +3033,9 @@ Utilities scalability is a concern. :ref:`aiohttp-web-peer-disconnection` + :param kwargs: additional named parameters to pass into + :class:`AppRunner` constructor. + .. versionadded:: 3.0 Support *access_log_class* parameter. diff --git a/tests/test_run_app.py b/tests/test_run_app.py index e4f306b364b..622fa560e24 100644 --- a/tests/test_run_app.py +++ b/tests/test_run_app.py @@ -926,28 +926,35 @@ async def on_startup(app: web.Application) -> None: exc_handler.assert_called_with(patched_loop, msg) -def test_run_app_keepalive_timeout( +@pytest.mark.parametrize( + "param", + ( + "keepalive_timeout", + "max_line_size", + "max_headers", + "max_field_size", + "lingering_time", + "read_bufsize", + "auto_decompress", + ), +) +def test_run_app_pass_apprunner_kwargs( + param: str, patched_loop: asyncio.AbstractEventLoop, - mocker: MockerFixture, monkeypatch: pytest.MonkeyPatch, ) -> None: - new_timeout = 1234 + m = mock.Mock() base_runner_init_orig = BaseRunner.__init__ def base_runner_init_spy( self: BaseRunner[web.Request], *args: Any, **kwargs: Any ) -> None: - assert kwargs["keepalive_timeout"] == new_timeout + assert kwargs[param] is m base_runner_init_orig(self, *args, **kwargs) app = web.Application() monkeypatch.setattr(BaseRunner, "__init__", base_runner_init_spy) - web.run_app( - app, - keepalive_timeout=new_timeout, - print=stopper(patched_loop), - loop=patched_loop, - ) + web.run_app(app, print=stopper(patched_loop), loop=patched_loop, **{param: m}) def test_run_app_context_vars(patched_loop: asyncio.AbstractEventLoop) -> None: