From 40ddab317dcaed0b825a7b5607f0e5d6f0edd534 Mon Sep 17 00:00:00 2001 From: Yernat Yestekov Date: Tue, 11 Aug 2026 19:35:15 -0700 Subject: [PATCH 1/2] test(mcp): drive MCP tool calls through asyncio.run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `asyncio.get_event_loop()` outside a running loop has warned since 3.12 and raises `RuntimeError: There is no current event loop` on 3.14, so the whole module fails there — 20+ tests — while only emitting a DeprecationWarning on the interpreters CI currently pins. `asyncio.run` is the supported spelling for driving a coroutine from sync test code. Verified by running the module under `-W error::DeprecationWarning`, which reproduces the 3.14 failure: the previous spelling errors out, this one passes all 85 tests. Co-Authored-By: Claude Opus 5 (1M context) --- implementations/python/tests/test_mcp_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/implementations/python/tests/test_mcp_server.py b/implementations/python/tests/test_mcp_server.py index 57c736697..89f409bad 100644 --- a/implementations/python/tests/test_mcp_server.py +++ b/implementations/python/tests/test_mcp_server.py @@ -31,7 +31,7 @@ def _text(result) -> str: def _call(server, tool: str, args: dict | None = None) -> str: """Synchronously call a tool and return its text.""" - return asyncio.get_event_loop().run_until_complete(_async_call(server, tool, args or {})) + return asyncio.run(_async_call(server, tool, args or {})) async def _async_call(server, tool: str, args: dict) -> str: @@ -897,7 +897,7 @@ def test_server_has_all_tools(self): # Using the real registration surface (rather than a hand-copied # literal) means a drift between what the server exposes and what # raes_tool_surface advertises cannot pass silently. - registered = asyncio.get_event_loop().run_until_complete(server.list_tools()) + registered = asyncio.run(server.list_tools()) registered_names = {tool.name for tool in registered} assert registered_names, "server registered no tools" From 19e53e969a96852d83b796be1c6dabfa5b3f9472 Mon Sep 17 00:00:00 2001 From: Yernat Yestekov Date: Tue, 11 Aug 2026 20:18:05 -0700 Subject: [PATCH 2/2] ci: test every interpreter the project claims to support `requires-python = ">=3.11"` is open-ended and the trove classifiers advertise 3.11 and 3.12, but every workflow pins 3.12, so the project publishes to interpreters nothing exercises. That is how the `asyncio.get_event_loop()` call fixed in the parent commit stayed invisible: it was latent on every version above 3.12 and only surfaced when uv happened to select 3.14. A new `interpreters` job runs the hermetic unit suite on 3.11, 3.12, 3.13 and 3.14, with `fail-fast: false` so one version failing still reports the others. `verify` deliberately stays single-version: it owns the coverage artifact Sonar consumes and the Isabelle replay, and neither varies by interpreter. Classifiers now list 3.13 and 3.14, which the file's own comment asks for ("Keep this list in step with `requires-python`"). Verified locally before wiring it up: the hermetic suite is 6313 passed on 3.11.15 and on 3.14.4, both with the full locked dependency set including the governed z3-solver 4.16.0.0 pin. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ implementations/python/pyproject.toml | 2 ++ 2 files changed, 25 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f06b150bc..0a81b6b95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,6 +91,29 @@ jobs: - name: Run fuzz session run: uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s fuzz + # Every interpreter `requires-python` admits and the trove classifiers + # advertise. `verify` stays single-version because it owns the coverage + # artifact Sonar consumes and the Isabelle replay, neither of which varies by + # interpreter; this job carries the compatibility signal on the hermetic suite + # alone, so a release cannot advertise a version nothing exercises. + interpreters: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13", "3.14"] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v8 + - name: Run unit suite + env: + UV_PYTHON: ${{ matrix.python-version }} + run: uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s tests + # Opt-in, non-blocking, runtime-gated container integration tests (RUN-314). # Kept out of the hermetic `verify` graph; the `docker` marker tests self-skip # when no runtime is present, and this whole job never fails the build. diff --git a/implementations/python/pyproject.toml b/implementations/python/pyproject.toml index 4616679d9..dd0593397 100644 --- a/implementations/python/pyproject.toml +++ b/implementations/python/pyproject.toml @@ -14,6 +14,8 @@ classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] dependencies = [ "typer>=0.12.0",