From 2082fbad0b52b7c612c1ccb9875ac04f1469b3dc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 31 Mar 2025 20:15:15 -1000 Subject: [PATCH 1/9] Increment version to 3.11.16.dev0 (#10661) --- aiohttp/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiohttp/__init__.py b/aiohttp/__init__.py index aba86dc3a32..acfef952d61 100644 --- a/aiohttp/__init__.py +++ b/aiohttp/__init__.py @@ -1,4 +1,4 @@ -__version__ = "3.11.15" +__version__ = "3.11.16.dev0" from typing import TYPE_CHECKING, Tuple From 83a9df574187b432589637a2596e029b0bcf6e33 Mon Sep 17 00:00:00 2001 From: layday Date: Tue, 1 Apr 2025 12:25:50 +0200 Subject: [PATCH 2/9] =?UTF-8?q?Replace=20deprecated=20`asyncio.iscoroutine?= =?UTF-8?q?function`=20with=20its=20counterpart=E2=80=A6=20(#10664)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … from `inspect` (#10634) (cherry picked from commit 77ad7d7ea173eda1306297d275b2d5f7348f9f60) --- CHANGES/10634.bugfix.rst | 2 ++ aiohttp/pytest_plugin.py | 6 +++--- aiohttp/web_urldispatcher.py | 8 +++++--- aiohttp/worker.py | 5 ++++- 4 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 CHANGES/10634.bugfix.rst diff --git a/CHANGES/10634.bugfix.rst b/CHANGES/10634.bugfix.rst new file mode 100644 index 00000000000..d6ec64a607e --- /dev/null +++ b/CHANGES/10634.bugfix.rst @@ -0,0 +1,2 @@ +Replaced deprecated ``asyncio.iscoroutinefunction`` with its counterpart from ``inspect`` +-- by :user:`layday`. diff --git a/aiohttp/pytest_plugin.py b/aiohttp/pytest_plugin.py index 158fd684b7a..128dc46081d 100644 --- a/aiohttp/pytest_plugin.py +++ b/aiohttp/pytest_plugin.py @@ -98,7 +98,7 @@ def pytest_fixture_setup(fixturedef): # type: ignore[no-untyped-def] if inspect.isasyncgenfunction(func): # async generator fixture is_async_gen = True - elif asyncio.iscoroutinefunction(func): + elif inspect.iscoroutinefunction(func): # regular async fixture is_async_gen = False else: @@ -200,14 +200,14 @@ def _passthrough_loop_context(loop, fast=False): # type: ignore[no-untyped-def] def pytest_pycollect_makeitem(collector, name, obj): # type: ignore[no-untyped-def] """Fix pytest collecting for coroutines.""" - if collector.funcnamefilter(name) and asyncio.iscoroutinefunction(obj): + if collector.funcnamefilter(name) and inspect.iscoroutinefunction(obj): return list(collector._genfunctions(name, obj)) def pytest_pyfunc_call(pyfuncitem): # type: ignore[no-untyped-def] """Run coroutines in an event loop instead of a normal function call.""" fast = pyfuncitem.config.getoption("--aiohttp-fast") - if asyncio.iscoroutinefunction(pyfuncitem.function): + if inspect.iscoroutinefunction(pyfuncitem.function): existing_loop = pyfuncitem.funcargs.get( "proactor_loop" ) or pyfuncitem.funcargs.get("loop", None) diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py index 6443c500a33..28ae2518fec 100644 --- a/aiohttp/web_urldispatcher.py +++ b/aiohttp/web_urldispatcher.py @@ -180,8 +180,8 @@ def __init__( if expect_handler is None: expect_handler = _default_expect_handler - assert asyncio.iscoroutinefunction( - expect_handler + assert inspect.iscoroutinefunction(expect_handler) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(expect_handler) ), f"Coroutine is expected, got {expect_handler!r}" method = method.upper() @@ -189,7 +189,9 @@ def __init__( raise ValueError(f"{method} is not allowed HTTP method") assert callable(handler), handler - if asyncio.iscoroutinefunction(handler): + if inspect.iscoroutinefunction(handler) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(handler) + ): pass elif inspect.isgeneratorfunction(handler): warnings.warn( diff --git a/aiohttp/worker.py b/aiohttp/worker.py index 8ed121ac955..f7281bfde75 100644 --- a/aiohttp/worker.py +++ b/aiohttp/worker.py @@ -1,6 +1,7 @@ """Async gunicorn worker for aiohttp.web""" import asyncio +import inspect import os import re import signal @@ -71,7 +72,9 @@ async def _run(self) -> None: runner = None if isinstance(self.wsgi, Application): app = self.wsgi - elif asyncio.iscoroutinefunction(self.wsgi): + elif inspect.iscoroutinefunction(self.wsgi) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(self.wsgi) + ): wsgi = await self.wsgi() if isinstance(wsgi, web.AppRunner): runner = wsgi From a60d447aa0e518425b889eb16a2ed54f286e41fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:38:56 +0000 Subject: [PATCH 3/9] Bump virtualenv from 20.29.3 to 20.30.0 (#10666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [virtualenv](https://github.com/pypa/virtualenv) from 20.29.3 to 20.30.0.
Release notes

Sourced from virtualenv's releases.

20.30.0

What's Changed

New Contributors

Full Changelog: https://github.com/pypa/virtualenv/compare/20.29.3...20.30.0

Changelog

Sourced from virtualenv's changelog.

v20.30.0 (2025-03-31)

Features - 20.30.0

- Add support for `GraalPy
<https://github.com/oracle/graalpython>`_. (:issue:`2832`)

Bugfixes - 20.30.0

  • Upgrade embedded wheels:

    • setuptools to 78.1.0 from 75.3.2 (:issue:2863)
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=virtualenv&package-manager=pip&previous-version=20.29.3&new-version=20.30.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements/constraints.txt | 2 +- requirements/dev.txt | 2 +- requirements/lint.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index a88d3895a16..142c09092b0 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -279,7 +279,7 @@ uvloop==0.21.0 ; platform_system != "Windows" # -r requirements/lint.in valkey==6.1.0 # via -r requirements/lint.in -virtualenv==20.29.3 +virtualenv==20.30.0 # via pre-commit wait-for-it==2.3.0 # via -r requirements/test.in diff --git a/requirements/dev.txt b/requirements/dev.txt index 4414468a31f..b9e52c24751 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -270,7 +270,7 @@ uvloop==0.21.0 ; platform_system != "Windows" and implementation_name == "cpytho # -r requirements/lint.in valkey==6.1.0 # via -r requirements/lint.in -virtualenv==20.29.3 +virtualenv==20.30.0 # via pre-commit wait-for-it==2.3.0 # via -r requirements/test.in diff --git a/requirements/lint.txt b/requirements/lint.txt index ff910da444b..c400e12cea0 100644 --- a/requirements/lint.txt +++ b/requirements/lint.txt @@ -109,5 +109,5 @@ uvloop==0.21.0 ; platform_system != "Windows" # via -r requirements/lint.in valkey==6.1.0 # via -r requirements/lint.in -virtualenv==20.29.3 +virtualenv==20.30.0 # via pre-commit From b65000da599aeb2c9f340387b499a83b3d4ea598 Mon Sep 17 00:00:00 2001 From: layday Date: Tue, 1 Apr 2025 14:18:39 +0200 Subject: [PATCH 4/9] =?UTF-8?q?Replace=20deprecated=20`asyncio.iscoroutine?= =?UTF-8?q?function`=20with=20its=20counterpart=E2=80=A6=20(#10663)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … from `inspect` (#10634) (cherry picked from commit 77ad7d7ea173eda1306297d275b2d5f7348f9f60) --- CHANGES/10634.bugfix.rst | 2 ++ aiohttp/pytest_plugin.py | 6 +++--- aiohttp/web_urldispatcher.py | 8 +++++--- aiohttp/worker.py | 5 ++++- 4 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 CHANGES/10634.bugfix.rst diff --git a/CHANGES/10634.bugfix.rst b/CHANGES/10634.bugfix.rst new file mode 100644 index 00000000000..d6ec64a607e --- /dev/null +++ b/CHANGES/10634.bugfix.rst @@ -0,0 +1,2 @@ +Replaced deprecated ``asyncio.iscoroutinefunction`` with its counterpart from ``inspect`` +-- by :user:`layday`. diff --git a/aiohttp/pytest_plugin.py b/aiohttp/pytest_plugin.py index 7ce60faa4a4..21d6ea7bbcd 100644 --- a/aiohttp/pytest_plugin.py +++ b/aiohttp/pytest_plugin.py @@ -98,7 +98,7 @@ def pytest_fixture_setup(fixturedef): # type: ignore[no-untyped-def] if inspect.isasyncgenfunction(func): # async generator fixture is_async_gen = True - elif asyncio.iscoroutinefunction(func): + elif inspect.iscoroutinefunction(func): # regular async fixture is_async_gen = False else: @@ -200,14 +200,14 @@ def _passthrough_loop_context(loop, fast=False): # type: ignore[no-untyped-def] def pytest_pycollect_makeitem(collector, name, obj): # type: ignore[no-untyped-def] """Fix pytest collecting for coroutines.""" - if collector.funcnamefilter(name) and asyncio.iscoroutinefunction(obj): + if collector.funcnamefilter(name) and inspect.iscoroutinefunction(obj): return list(collector._genfunctions(name, obj)) def pytest_pyfunc_call(pyfuncitem): # type: ignore[no-untyped-def] """Run coroutines in an event loop instead of a normal function call.""" fast = pyfuncitem.config.getoption("--aiohttp-fast") - if asyncio.iscoroutinefunction(pyfuncitem.function): + if inspect.iscoroutinefunction(pyfuncitem.function): existing_loop = pyfuncitem.funcargs.get( "proactor_loop" ) or pyfuncitem.funcargs.get("loop", None) diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py index 6443c500a33..28ae2518fec 100644 --- a/aiohttp/web_urldispatcher.py +++ b/aiohttp/web_urldispatcher.py @@ -180,8 +180,8 @@ def __init__( if expect_handler is None: expect_handler = _default_expect_handler - assert asyncio.iscoroutinefunction( - expect_handler + assert inspect.iscoroutinefunction(expect_handler) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(expect_handler) ), f"Coroutine is expected, got {expect_handler!r}" method = method.upper() @@ -189,7 +189,9 @@ def __init__( raise ValueError(f"{method} is not allowed HTTP method") assert callable(handler), handler - if asyncio.iscoroutinefunction(handler): + if inspect.iscoroutinefunction(handler) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(handler) + ): pass elif inspect.isgeneratorfunction(handler): warnings.warn( diff --git a/aiohttp/worker.py b/aiohttp/worker.py index 8ed121ac955..f7281bfde75 100644 --- a/aiohttp/worker.py +++ b/aiohttp/worker.py @@ -1,6 +1,7 @@ """Async gunicorn worker for aiohttp.web""" import asyncio +import inspect import os import re import signal @@ -71,7 +72,9 @@ async def _run(self) -> None: runner = None if isinstance(self.wsgi, Application): app = self.wsgi - elif asyncio.iscoroutinefunction(self.wsgi): + elif inspect.iscoroutinefunction(self.wsgi) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(self.wsgi) + ): wsgi = await self.wsgi() if isinstance(wsgi, web.AppRunner): runner = wsgi From be154728df86462aa5b4bb74a508dd2025ec8bfd Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 1 Apr 2025 11:41:52 -1000 Subject: [PATCH 5/9] [PR #10672/35c979b backport][3.11] Fix headers being mutated if passed to web.Response as a CIMultiDict (#10673) If `CIMultiDict` is passed in we need to make a copy to avoid mutating it. In some cases we used to copy these twice which was fixed in #10045 but for this case that was the only copy being made and the source of this regression. fixes #10670 (cherry picked from commit 35c979be79dcc75ecbf7270ccc9fde264e5e2948) --- CHANGES/10672.bugfix.rst | 1 + aiohttp/web_response.py | 4 +--- tests/test_web_response.py | 14 +++++++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 CHANGES/10672.bugfix.rst diff --git a/CHANGES/10672.bugfix.rst b/CHANGES/10672.bugfix.rst new file mode 100644 index 00000000000..a4434f8c87a --- /dev/null +++ b/CHANGES/10672.bugfix.rst @@ -0,0 +1 @@ +Fixed :class:`multidict.CIMultiDict` being mutated when passed to :class:`aiohttp.web.Response` -- by :user:`bdraco`. diff --git a/aiohttp/web_response.py b/aiohttp/web_response.py index e498a905caf..367ac6e8c0a 100644 --- a/aiohttp/web_response.py +++ b/aiohttp/web_response.py @@ -629,10 +629,8 @@ def __init__( if headers is None: real_headers: CIMultiDict[str] = CIMultiDict() - elif not isinstance(headers, CIMultiDict): - real_headers = CIMultiDict(headers) else: - real_headers = headers # = cast('CIMultiDict[str]', headers) + real_headers = CIMultiDict(headers) if content_type is not None and "charset" in content_type: raise ValueError("charset must not be in content_type argument") diff --git a/tests/test_web_response.py b/tests/test_web_response.py index 0591426c57b..95769161804 100644 --- a/tests/test_web_response.py +++ b/tests/test_web_response.py @@ -10,7 +10,7 @@ import aiosignal import pytest -from multidict import CIMultiDict, CIMultiDictProxy +from multidict import CIMultiDict, CIMultiDictProxy, MultiDict from re_assert import Matches from aiohttp import HttpVersion, HttpVersion10, HttpVersion11, hdrs @@ -1479,3 +1479,15 @@ def test_text_is_json_encoded(self) -> None: def test_content_type_is_overrideable(self) -> None: resp = json_response({"foo": 42}, content_type="application/vnd.json+api") assert "application/vnd.json+api" == resp.content_type + + +@pytest.mark.parametrize("loose_header_type", (MultiDict, CIMultiDict, dict)) +async def test_passing_cimultidict_to_web_response_not_mutated( + loose_header_type: type, +) -> None: + req = make_request("GET", "/") + headers = loose_header_type({}) + resp = Response(body=b"answer", headers=headers) + await resp.prepare(req) + assert resp.content_length == 6 + assert not headers From 6a3d83579923271acd33749be2a9c5c81c175dc4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 1 Apr 2025 12:10:22 -1000 Subject: [PATCH 6/9] [PR #10675/048ef4c backport][3.11] Remove useless nonlocal statements in tests (#10677) discovered by new flake8 in https://github.com/aio-libs/aiohttp/pull/10653 (cherry picked from commit 048ef4c617130ef5a29a70ad67e34d9395891ac1) --- tests/test_client_ws_functional.py | 3 +-- tests/test_helpers.py | 1 - tests/test_web_server.py | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/test_client_ws_functional.py b/tests/test_client_ws_functional.py index 54cd5e92f80..0ca57ab3ab2 100644 --- a/tests/test_client_ws_functional.py +++ b/tests/test_client_ws_functional.py @@ -315,7 +315,6 @@ async def test_concurrent_close(aiohttp_client) -> None: client_ws = None async def handler(request): - nonlocal client_ws ws = web.WebSocketResponse() await ws.prepare(request) @@ -936,7 +935,7 @@ async def delayed_send_frame( message: bytes, opcode: int, compress: Optional[int] = None ) -> None: assert opcode == WSMsgType.PING - nonlocal cancelled, ping_started + nonlocal cancelled ping_started.set_result(None) try: await asyncio.sleep(1) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 2a83032e557..a343cbdfedf 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -351,7 +351,6 @@ async def test_timer_context_timeout_does_swallow_cancellation() -> None: ctx = helpers.TimerContext(loop) async def task_with_timeout() -> None: - nonlocal ctx new_task = asyncio.current_task() assert new_task is not None with pytest.raises(asyncio.TimeoutError): diff --git a/tests/test_web_server.py b/tests/test_web_server.py index 9098ef9e7bf..d2f1341afe0 100644 --- a/tests/test_web_server.py +++ b/tests/test_web_server.py @@ -347,7 +347,6 @@ async def test_handler_cancellation(unused_port_socket: socket.socket) -> None: port = sock.getsockname()[1] async def on_request(_: web.Request) -> web.Response: - nonlocal event try: await asyncio.sleep(10) except asyncio.CancelledError: @@ -389,7 +388,7 @@ async def test_no_handler_cancellation(unused_port_socket: socket.socket) -> Non started = False async def on_request(_: web.Request) -> web.Response: - nonlocal done_event, started, timeout_event + nonlocal started started = True await asyncio.wait_for(timeout_event.wait(), timeout=5) done_event.set() From d3c4543fb4ccd3bfb6f03d4d7939bad48ac59970 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 1 Apr 2025 13:05:24 -1000 Subject: [PATCH 7/9] [PR #10672/35c979b backport][3.12] Fix headers being mutated if passed to web.Response as a CIMultiDict (#10674) --- CHANGES/10672.bugfix.rst | 1 + aiohttp/web_response.py | 4 +--- tests/test_web_response.py | 14 +++++++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 CHANGES/10672.bugfix.rst diff --git a/CHANGES/10672.bugfix.rst b/CHANGES/10672.bugfix.rst new file mode 100644 index 00000000000..a4434f8c87a --- /dev/null +++ b/CHANGES/10672.bugfix.rst @@ -0,0 +1 @@ +Fixed :class:`multidict.CIMultiDict` being mutated when passed to :class:`aiohttp.web.Response` -- by :user:`bdraco`. diff --git a/aiohttp/web_response.py b/aiohttp/web_response.py index a1955ca0d9e..151fbea3473 100644 --- a/aiohttp/web_response.py +++ b/aiohttp/web_response.py @@ -639,10 +639,8 @@ def __init__( if headers is None: real_headers: CIMultiDict[str] = CIMultiDict() - elif not isinstance(headers, CIMultiDict): - real_headers = CIMultiDict(headers) else: - real_headers = headers # = cast('CIMultiDict[str]', headers) + real_headers = CIMultiDict(headers) if content_type is not None and "charset" in content_type: raise ValueError("charset must not be in content_type argument") diff --git a/tests/test_web_response.py b/tests/test_web_response.py index 0a2c5273080..54176ea661b 100644 --- a/tests/test_web_response.py +++ b/tests/test_web_response.py @@ -11,7 +11,7 @@ import aiosignal import pytest -from multidict import CIMultiDict, CIMultiDictProxy +from multidict import CIMultiDict, CIMultiDictProxy, MultiDict from re_assert import Matches from aiohttp import HttpVersion, HttpVersion10, HttpVersion11, hdrs @@ -1501,3 +1501,15 @@ def test_text_is_json_encoded(self) -> None: def test_content_type_is_overrideable(self) -> None: resp = json_response({"foo": 42}, content_type="application/vnd.json+api") assert "application/vnd.json+api" == resp.content_type + + +@pytest.mark.parametrize("loose_header_type", (MultiDict, CIMultiDict, dict)) +async def test_passing_cimultidict_to_web_response_not_mutated( + loose_header_type: type, +) -> None: + req = make_request("GET", "/") + headers = loose_header_type({}) + resp = Response(body=b"answer", headers=headers) + await resp.prepare(req) + assert resp.content_length == 6 + assert not headers From cca85c46027d7172d9aa7b022098a036aef906b8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 1 Apr 2025 13:33:26 -1000 Subject: [PATCH 8/9] [PR #10675/048ef4c backport][3.12] Remove useless nonlocal statements in tests (#10678) discovered by new flake8 in https://github.com/aio-libs/aiohttp/pull/10653 (cherry picked from commit 048ef4c617130ef5a29a70ad67e34d9395891ac1) --- tests/test_client_ws_functional.py | 3 +-- tests/test_helpers.py | 1 - tests/test_web_server.py | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/test_client_ws_functional.py b/tests/test_client_ws_functional.py index 54cd5e92f80..0ca57ab3ab2 100644 --- a/tests/test_client_ws_functional.py +++ b/tests/test_client_ws_functional.py @@ -315,7 +315,6 @@ async def test_concurrent_close(aiohttp_client) -> None: client_ws = None async def handler(request): - nonlocal client_ws ws = web.WebSocketResponse() await ws.prepare(request) @@ -936,7 +935,7 @@ async def delayed_send_frame( message: bytes, opcode: int, compress: Optional[int] = None ) -> None: assert opcode == WSMsgType.PING - nonlocal cancelled, ping_started + nonlocal cancelled ping_started.set_result(None) try: await asyncio.sleep(1) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 2a83032e557..a343cbdfedf 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -351,7 +351,6 @@ async def test_timer_context_timeout_does_swallow_cancellation() -> None: ctx = helpers.TimerContext(loop) async def task_with_timeout() -> None: - nonlocal ctx new_task = asyncio.current_task() assert new_task is not None with pytest.raises(asyncio.TimeoutError): diff --git a/tests/test_web_server.py b/tests/test_web_server.py index 9098ef9e7bf..d2f1341afe0 100644 --- a/tests/test_web_server.py +++ b/tests/test_web_server.py @@ -347,7 +347,6 @@ async def test_handler_cancellation(unused_port_socket: socket.socket) -> None: port = sock.getsockname()[1] async def on_request(_: web.Request) -> web.Response: - nonlocal event try: await asyncio.sleep(10) except asyncio.CancelledError: @@ -389,7 +388,7 @@ async def test_no_handler_cancellation(unused_port_socket: socket.socket) -> Non started = False async def on_request(_: web.Request) -> web.Response: - nonlocal done_event, started, timeout_event + nonlocal started started = True await asyncio.wait_for(timeout_event.wait(), timeout=5) done_event.set() From c723b3ce07b614d0c5fc7806d17f64b2f8ef268a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 1 Apr 2025 14:36:56 -1000 Subject: [PATCH 9/9] Release 3.11.16 (#10679) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Screenshot 2025-04-01 at 1 42 52 PM --- CHANGES.rst | 27 +++++++++++++++++++++++++++ CHANGES/10634.bugfix.rst | 2 -- CHANGES/10672.bugfix.rst | 1 - aiohttp/__init__.py | 2 +- 4 files changed, 28 insertions(+), 4 deletions(-) delete mode 100644 CHANGES/10634.bugfix.rst delete mode 100644 CHANGES/10672.bugfix.rst diff --git a/CHANGES.rst b/CHANGES.rst index c2654b99214..00d728e775d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,6 +10,33 @@ .. towncrier release notes start +3.11.16 (2025-04-01) +==================== + +Bug fixes +--------- + +- Replaced deprecated ``asyncio.iscoroutinefunction`` with its counterpart from ``inspect`` + -- by :user:`layday`. + + + *Related issues and pull requests on GitHub:* + :issue:`10634`. + + + +- Fixed :class:`multidict.CIMultiDict` being mutated when passed to :class:`aiohttp.web.Response` -- by :user:`bdraco`. + + + *Related issues and pull requests on GitHub:* + :issue:`10672`. + + + + +---- + + 3.11.15 (2025-03-31) ==================== diff --git a/CHANGES/10634.bugfix.rst b/CHANGES/10634.bugfix.rst deleted file mode 100644 index d6ec64a607e..00000000000 --- a/CHANGES/10634.bugfix.rst +++ /dev/null @@ -1,2 +0,0 @@ -Replaced deprecated ``asyncio.iscoroutinefunction`` with its counterpart from ``inspect`` --- by :user:`layday`. diff --git a/CHANGES/10672.bugfix.rst b/CHANGES/10672.bugfix.rst deleted file mode 100644 index a4434f8c87a..00000000000 --- a/CHANGES/10672.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed :class:`multidict.CIMultiDict` being mutated when passed to :class:`aiohttp.web.Response` -- by :user:`bdraco`. diff --git a/aiohttp/__init__.py b/aiohttp/__init__.py index acfef952d61..93b06c7367a 100644 --- a/aiohttp/__init__.py +++ b/aiohttp/__init__.py @@ -1,4 +1,4 @@ -__version__ = "3.11.16.dev0" +__version__ = "3.11.16" from typing import TYPE_CHECKING, Tuple