From 5a659a179383debe4385500a9e5ed524e9763f4d Mon Sep 17 00:00:00 2001 From: aio-libs bot Date: Mon, 18 May 2026 06:27:13 -0700 Subject: [PATCH 1/5] Split CLAUDE.md into shared aio-libs context layers (#12618) --- .gitignore | 3 +++ CHANGES/12617.contrib.rst | 9 +++++++++ CHANGES/12618.contrib.rst | 1 + CLAUDE.md | 3 +++ 4 files changed, 16 insertions(+) create mode 100644 CHANGES/12617.contrib.rst create mode 120000 CHANGES/12618.contrib.rst diff --git a/.gitignore b/.gitignore index 0081b62ae7f..ee06baff610 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,6 @@ sources var/* venv virtualenv.py + +# Claude Code per-checkout overrides +CLAUDE.local.md diff --git a/CHANGES/12617.contrib.rst b/CHANGES/12617.contrib.rst new file mode 100644 index 00000000000..fab91aea8e0 --- /dev/null +++ b/CHANGES/12617.contrib.rst @@ -0,0 +1,9 @@ +Restructured the root :file:`CLAUDE.md` to import contributor +context from a shared ``aio-libs`` layer +(``~/.claude/aio-libs/context.md``), a project-specific layer +(``~/.claude/aio-libs/aiohttp/context.md``), the in-tree +:file:`AGENTS.md`, and an optional per-checkout +:file:`CLAUDE.local.md` override (added to :file:`.gitignore`), +so shared ``aio-libs`` guidance can live outside the repository +while project rules continue to load automatically in Claude +Code -- by :user:`aiolibsbot`. diff --git a/CHANGES/12618.contrib.rst b/CHANGES/12618.contrib.rst new file mode 120000 index 00000000000..7efbc0b7ed6 --- /dev/null +++ b/CHANGES/12618.contrib.rst @@ -0,0 +1 @@ +12617.contrib.rst \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 43c994c2d36..30ceb187918 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1 +1,4 @@ +@~/.claude/aio-libs/context.md +@~/.claude/aio-libs/aiohttp/context.md @AGENTS.md +@CLAUDE.local.md From b391f7beec755dac3977f930f0f7705337240a35 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 18 May 2026 07:17:55 -0700 Subject: [PATCH 2/5] Add timeouts to test runners to prevent CI hangs (#12619) --- .github/workflows/ci-cd.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index b1bde397283..e69bab0d951 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -182,6 +182,7 @@ jobs: fail-fast: true runs-on: ${{ matrix.os }}-latest continue-on-error: ${{ matrix.experimental }} + timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v6 @@ -294,6 +295,7 @@ jobs: os: [ubuntu] fail-fast: true runs-on: ${{ matrix.os }}-latest + timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v6 @@ -422,6 +424,7 @@ jobs: matrix: os: [ubuntu, windows] runs-on: ${{ matrix.os }}-latest + timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v6 From 3db06d9c18b4c0494fbe54ff84adc51b336dcd83 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 18 May 2026 07:55:58 -0700 Subject: [PATCH 3/5] Shrink three slow tests without changing their intent (#12606) --- CHANGES/12606.contrib.rst | 6 ++++++ tests/test_client_functional.py | 8 ++++---- tests/test_http_parser.py | 8 +++++--- 3 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 CHANGES/12606.contrib.rst diff --git a/CHANGES/12606.contrib.rst b/CHANGES/12606.contrib.rst new file mode 100644 index 00000000000..72925114e8c --- /dev/null +++ b/CHANGES/12606.contrib.rst @@ -0,0 +1,6 @@ +Reduced runtime of several of the slowest unit tests +(decompress size-limit payloads from 64 MiB to 2 MiB, +``test_chunk_splits_after_pause`` chunk count from 50000 +to 20000, and ``test_set_cookies_max_age`` sleep from 2 +seconds to 1.1 seconds) without changing what they +exercise -- by :user:`bdraco`. diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index cfc2d4529c5..10953516a0a 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -2416,7 +2416,7 @@ async def test_payload_decompress_size_limit(aiohttp_client: AiohttpClient) -> N we raise DecompressSizeError. """ # Create a highly compressible payload. - payload_size = 64 * 2**20 + payload_size = 2 * 2**20 original = b"A" * payload_size compressed = zlib.compress(original) assert len(original) > DEFAULT_CHUNK_SIZE @@ -2448,7 +2448,7 @@ async def test_payload_decompress_size_limit_brotli( """Test that brotli decompression size limit triggers DecompressSizeError.""" assert brotli is not None # Create a highly compressible payload - payload_size = 64 * 2**20 + payload_size = 2 * 2**20 original = b"A" * payload_size compressed = brotli.compress(original) assert len(original) > DEFAULT_CHUNK_SIZE @@ -2479,7 +2479,7 @@ async def test_payload_decompress_size_limit_zstd( """Test that zstd decompression size limit triggers DecompressSizeError.""" assert ZstdCompressor is not None # Create a highly compressible payload. - payload_size = 64 * 2**20 + payload_size = 2 * 2**20 original = b"A" * payload_size compressor = ZstdCompressor() compressed = compressor.compress(original) + compressor.flush() @@ -2904,7 +2904,7 @@ async def handler(request: web.Request) -> web.Response: assert 200 == resp.status cookie_names = {c.key for c in client.session.cookie_jar} assert cookie_names == {"c1", "c2", "c3"} - await asyncio.sleep(2) + await asyncio.sleep(1.1) cookie_names = {c.key for c in client.session.cookie_jar} assert cookie_names == {"c1", "c2"} diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py index fa71d9aa2ed..147785def1c 100644 --- a/tests/test_http_parser.py +++ b/tests/test_http_parser.py @@ -1155,9 +1155,10 @@ def test_max_header_value_size_under_limit(parser: HttpRequestParser) -> None: async def test_chunk_splits_after_pause(parser: HttpRequestParser) -> None: + num_chunks = 20000 # comfortably above the 16385 pause threshold text = ( b"GET /test HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n" - + b"1\r\nb\r\n" * 50000 + + b"1\r\nb\r\n" * num_chunks + b"0\r\n\r\n" ) @@ -1168,8 +1169,9 @@ async def test_chunk_splits_after_pause(parser: HttpRequestParser) -> None: assert len(payload._http_chunk_splits) == 16385 # We should still get the full result after read(), as it will continue processing. result = await payload.read() - assert len(result) == 50000 # Compare len first, as it's easier to debug in diff. - assert result == b"b" * 50000 + # Compare len first, as it's easier to debug in diff. + assert len(result) == num_chunks + assert result == b"b" * num_chunks async def test_compressed_with_tail(response: HttpResponseParser) -> None: From 3bca18a8398e5045bc2332a521d535b84ef1fa12 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 18 May 2026 07:58:24 -0700 Subject: [PATCH 4/5] Add per-test pytest-timeout to surface hung tests (#12624) --- .github/workflows/ci-cd.yml | 4 ++-- CHANGES/12624.contrib.rst | 4 ++++ requirements/test-common.in | 1 + requirements/test-common.txt | 2 ++ requirements/test-ft.txt | 2 ++ requirements/test.txt | 2 ++ setup.cfg | 3 +++ 7 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 CHANGES/12624.contrib.rst diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index e69bab0d951..9a366681b87 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -348,7 +348,7 @@ jobs: PIP_USER: 1 run: >- PATH="${HOME}/Library/Python/3.11/bin:${HOME}/.local/bin:${PATH}" - pytest --junitxml=junit.xml --cov=aiohttp/ --cov=tests/ -m autobahn + pytest --junitxml=junit.xml --cov=aiohttp/ --cov=tests/ --timeout=0 -m autobahn shell: bash - name: Turn coverage into xml env: @@ -411,7 +411,7 @@ jobs: uses: CodSpeedHQ/action@v4 with: mode: instrumentation - run: python -Im pytest --no-cov -vvvvv --codspeed --durations=30 + run: python -Im pytest --no-cov -vvvvv --codspeed --durations=30 --timeout=0 cython-coverage: diff --git a/CHANGES/12624.contrib.rst b/CHANGES/12624.contrib.rst new file mode 100644 index 00000000000..0c7e2a0a548 --- /dev/null +++ b/CHANGES/12624.contrib.rst @@ -0,0 +1,4 @@ +Added a default 120-second per-test timeout via ``pytest-timeout`` so a +hung test surfaces by name in CI output instead of getting hidden behind +the job-level timeout added in :pr:`12619`. The ``autobahn`` and +benchmark jobs opt out with ``--timeout=0`` -- by :user:`bdraco`. diff --git a/requirements/test-common.in b/requirements/test-common.in index b50aed3be7f..9b3c5839b1f 100644 --- a/requirements/test-common.in +++ b/requirements/test-common.in @@ -9,6 +9,7 @@ pytest pytest-aiohttp pytest-cov pytest-mock +pytest-timeout pytest-xdist pytest_codspeed python-on-whales diff --git a/requirements/test-common.txt b/requirements/test-common.txt index 94aa95d62be..1faa93e7c1f 100644 --- a/requirements/test-common.txt +++ b/requirements/test-common.txt @@ -111,6 +111,8 @@ pytest-cov==7.1.0 # via -r requirements/test-common.in pytest-mock==3.15.1 # via -r requirements/test-common.in +pytest-timeout==2.4.0 + # via -r requirements/test-common.in pytest-xdist==3.8.0 # via -r requirements/test-common.in python-dateutil==2.9.0.post0 diff --git a/requirements/test-ft.txt b/requirements/test-ft.txt index fcad3f25513..073a4360a15 100644 --- a/requirements/test-ft.txt +++ b/requirements/test-ft.txt @@ -134,6 +134,8 @@ pytest-cov==7.1.0 # via -r requirements/test-common.in pytest-mock==3.15.1 # via -r requirements/test-common.in +pytest-timeout==2.4.0 + # via -r requirements/test-common.in pytest-xdist==3.8.0 # via -r requirements/test-common.in python-dateutil==2.9.0.post0 diff --git a/requirements/test.txt b/requirements/test.txt index 16cb56e094f..3c84d9304c1 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -134,6 +134,8 @@ pytest-cov==7.1.0 # via -r requirements/test-common.in pytest-mock==3.15.1 # via -r requirements/test-common.in +pytest-timeout==2.4.0 + # via -r requirements/test-common.in pytest-xdist==3.8.0 # via -r requirements/test-common.in python-dateutil==2.9.0.post0 diff --git a/setup.cfg b/setup.cfg index 8a721800cf3..e78606ecd57 100644 --- a/setup.cfg +++ b/setup.cfg @@ -58,6 +58,9 @@ addopts = # Disable entry-point auto-load, otherwise we miss coverage. -p no:aiohttp asyncio_mode = auto +# 2-minute per-test timeout so a hung test surfaces by name instead of taking +# down the whole job. Autobahn and benchmark jobs override with `--timeout=0`. +timeout = 120 filterwarnings = error ignore:module 'ssl' has no attribute 'OP_NO_COMPRESSION'. The Python interpreter is compiled against OpenSSL < 1.0.0. Ref. https.//docs.python.org/3/library/ssl.html#ssl.OP_NO_COMPRESSION:UserWarning From 3ef0965259a20aecfe8dd9c29791c5c73f769e35 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 16:47:49 +0000 Subject: [PATCH 5/5] [pre-commit.ci] pre-commit autoupdate (#12628) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 12f2c8678e9..ce55819c793 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -64,7 +64,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black-pre-commit-mirror - rev: '26.3.1' + rev: '26.5.0' hooks: - id: black language_version: python3 # Should be a command that runs python