Skip to content

Commit 4943417

Browse files
Varun SharmaCopilot
andcommitted
fix: add Python 3.10 compat for BaseExceptionGroup import
On Python < 3.11, BaseExceptionGroup and ExceptionGroup are not builtins. Import them from the exceptiongroup backport package conditionally. Also fix coverage miss on unreachable pytest.fail line and revert unnecessary builtins ruff config. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 349661c commit 4943417

File tree

3 files changed

+14
-8
lines changed

3 files changed

+14
-8
lines changed

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ executionEnvironments = [
126126
line-length = 120
127127
target-version = "py310"
128128
extend-exclude = ["README.md", "README.v2.md"]
129-
builtins = ["BaseExceptionGroup", "ExceptionGroup"]
130129

131130
[tool.ruff.lint]
132131
select = [

src/mcp/shared/_task_group.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@
1212

1313
from __future__ import annotations
1414

15+
import sys
1516
from types import TracebackType
1617

1718
import anyio
1819
from anyio.abc import TaskGroup
1920

21+
if sys.version_info < (3, 11):
22+
from exceptiongroup import BaseExceptionGroup
23+
2024

2125
def collapse_exception_group(exc: BaseExceptionGroup) -> BaseException: # type: ignore[type-arg]
2226
"""Unwrap nested single-exception BaseExceptionGroups.

tests/shared/test_task_group.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
"""Tests for mcp.shared._task_group — collapsing ExceptionGroup wrapper."""
22

3+
import sys
4+
35
import anyio
46
import pytest
7+
from anyio.abc import TaskStatus
58

69
from mcp.shared._task_group import (
710
_CollapsingTaskGroup,
811
collapse_exception_group,
912
create_mcp_task_group,
1013
)
1114

15+
if sys.version_info < (3, 11):
16+
from exceptiongroup import BaseExceptionGroup, ExceptionGroup
17+
1218
# ---------------------------------------------------------------------------
1319
# collapse_exception_group unit tests
1420
# ---------------------------------------------------------------------------
@@ -121,7 +127,7 @@ async def test_cancel_scope_is_delegated() -> None:
121127
async def test_start_delegates_to_task_group() -> None:
122128
"""start() delegates to the underlying task group."""
123129

124-
async def task_with_status(*, task_status: anyio.abc.TaskStatus[str] = anyio.TASK_STATUS_IGNORED) -> None:
130+
async def task_with_status(*, task_status: TaskStatus[str] = anyio.TASK_STATUS_IGNORED) -> None:
125131
task_status.started("ready")
126132
await anyio.sleep(999)
127133

@@ -144,15 +150,12 @@ async def test_task_group_not_entered_raises() -> None:
144150
@pytest.mark.anyio
145151
async def test_collapsed_exception_preserves_cause_chain() -> None:
146152
"""The collapsed exception has the original ExceptionGroup as __cause__."""
147-
try:
153+
with pytest.raises(RuntimeError, match="root cause") as exc_info:
148154
async with create_mcp_task_group() as tg:
149155

150156
async def failing() -> None:
151157
raise RuntimeError("root cause")
152158

153159
tg.start_soon(failing)
154-
except RuntimeError as exc:
155-
assert isinstance(exc.__cause__, BaseExceptionGroup)
156-
assert str(exc) == "root cause"
157-
else:
158-
pytest.fail("Expected RuntimeError")
160+
161+
assert isinstance(exc_info.value.__cause__, BaseExceptionGroup)

0 commit comments

Comments
 (0)