From a679bc516fc48fe38015282c63c3b82ba5a124b2 Mon Sep 17 00:00:00 2001 From: ZeliardM <140266236+ZeliardM@users.noreply.github.com> Date: Fri, 6 Nov 2026 18:50:15 -0500 Subject: [PATCH] Stop Windows test runs from running out of loopback ports (#1839) Windows has no native socketpair, so the self-pipe of every asyncio event loop is a loopback TCP connection, and closing it leaves a port in TIME_WAIT for two minutes. With a new event loop for each test, a run that gets through about 16,000 tests within two minutes uses up the dynamic port range, and the Windows test jobs hang until the 6-hour job limit. This PR runs the tests on one event loop per session, so a full run opens about 100 socket pairs instead of about 26,000, and runs the Windows jobs with xdist again. In details: - `asyncio_default_fixture_loop_scope` and `asyncio_default_test_loop_scope` are `session`. - CI: Windows runs `pytest -n auto` like the other OSes, and the test jobs get a 30-minute limit. Co-authored-by: Claude Opus 5.5 --- .github/workflows/ci.yml | 7 ++----- pyproject.toml | 5 ++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8878bb54..eeb64afa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,7 @@ jobs: name: Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} needs: lint runs-on: ${{ matrix.os }} + timeout-minutes: 30 strategy: matrix: python-version: [3.11, 3.12, 3.13, 3.14, 3.15] @@ -80,11 +81,7 @@ jobs: id: run-pytests-with-code-coverage shell: bash run: | - if [[ "${{ runner.os }}" == "Windows" ]]; then - uv run pytest -n0 --cov kasa --cov-report xml - else - uv run pytest -n auto --cov kasa --cov-report xml - fi + uv run pytest -n auto --cov kasa --cov-report xml - name: Upload Code Coverage to Codecov id: upload-code-coverage-to-codecov diff --git a/pyproject.toml b/pyproject.toml index 65ca5e12..f048c8a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -114,7 +114,10 @@ markers = [ "requires_dummy: test requires dummy data to pass, skipped on real devices", ] asyncio_mode = "auto" -asyncio_default_fixture_loop_scope = "function" +# One event loop for the run, not one per test: on Windows each loop opens a +# loopback TCP connection, and thousands of them use up the dynamic ports. +asyncio_default_fixture_loop_scope = "session" +asyncio_default_test_loop_scope = "session" #timeout = 10 # dist=loadgroup enables grouping of tests into single worker. # required as caplog doesn't play nicely with multiple workers.