diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 5e3ffefd..99e092bc 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -40,17 +40,15 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - name: Set up test environment variables run: | echo "POSTGRES_TEST_DSN=postgresql+asyncpg://a2a:a2a_password@localhost:5432/a2a_test" >> $GITHUB_ENV echo "MYSQL_TEST_DSN=mysql+aiomysql://a2a:a2a_password@localhost:3306/a2a_test" >> $GITHUB_ENV - - name: Install uv + - name: Install uv for Python ${{ matrix.python-version }} uses: astral-sh/setup-uv@v6 + with: + python-version: ${{ matrix.python-version }} - name: Add uv to PATH run: | echo "$HOME/.cargo/bin" >> $GITHUB_PATH diff --git a/src/a2a/server/request_handlers/default_request_handler.py b/src/a2a/server/request_handlers/default_request_handler.py index 2549d087..1dfce760 100644 --- a/src/a2a/server/request_handlers/default_request_handler.py +++ b/src/a2a/server/request_handlers/default_request_handler.py @@ -195,7 +195,7 @@ async def _setup_message_execution( if task.status.state in TERMINAL_TASK_STATES: raise ServerError( error=InvalidParamsError( - message=f'Task {task.id} is in terminal state: {task.status.state}' + message=f'Task {task.id} is in terminal state: {task.status.state.value}' ) ) @@ -437,7 +437,7 @@ async def on_resubscribe_to_task( if task.status.state in TERMINAL_TASK_STATES: raise ServerError( error=InvalidParamsError( - message=f'Task {task.id} is in terminal state: {task.status.state}' + message=f'Task {task.id} is in terminal state: {task.status.state.value}' ) ) diff --git a/tests/server/apps/jsonrpc/test_jsonrpc_app.py b/tests/server/apps/jsonrpc/test_jsonrpc_app.py index e0cadab6..6b86e7e7 100644 --- a/tests/server/apps/jsonrpc/test_jsonrpc_app.py +++ b/tests/server/apps/jsonrpc/test_jsonrpc_app.py @@ -92,7 +92,7 @@ def test_jsonrpc_app_build_method_abstract_raises_typeerror( # This will fail at definition time if an abstract method is not implemented with pytest.raises( TypeError, - match="Can't instantiate abstract class IncompleteJSONRPCApp with abstract method build", + match=".*abstract class IncompleteJSONRPCApp .* abstract method '?build'?", ): class IncompleteJSONRPCApp(JSONRPCApplication): diff --git a/tests/server/events/test_event_queue.py b/tests/server/events/test_event_queue.py index ffe74877..ecb7d814 100644 --- a/tests/server/events/test_event_queue.py +++ b/tests/server/events/test_event_queue.py @@ -1,4 +1,5 @@ import asyncio +import sys from typing import Any from unittest.mock import ( @@ -195,15 +196,22 @@ async def test_enqueue_event_when_closed(event_queue: EventQueue) -> None: await child_queue.dequeue_event(no_wait=True) +@pytest.fixture +def expected_queue_closed_exception(): + if sys.version_info < (3, 13): + return asyncio.QueueEmpty + return asyncio.QueueShutDown + + @pytest.mark.asyncio async def test_dequeue_event_closed_and_empty_no_wait( - event_queue: EventQueue, + event_queue: EventQueue, expected_queue_closed_exception ) -> None: """Test dequeue_event raises QueueEmpty when closed, empty, and no_wait=True.""" await event_queue.close() assert event_queue.is_closed() # Ensure queue is actually empty (e.g. by trying a non-blocking get on internal queue) - with pytest.raises(asyncio.QueueEmpty): + with pytest.raises(expected_queue_closed_exception): event_queue.queue.get_nowait() with pytest.raises(asyncio.QueueEmpty, match='Queue is closed.'): @@ -212,14 +220,12 @@ async def test_dequeue_event_closed_and_empty_no_wait( @pytest.mark.asyncio async def test_dequeue_event_closed_and_empty_waits_then_raises( - event_queue: EventQueue, + event_queue: EventQueue, expected_queue_closed_exception ) -> None: """Test dequeue_event raises QueueEmpty eventually when closed, empty, and no_wait=False.""" await event_queue.close() assert event_queue.is_closed() - with pytest.raises( - asyncio.QueueEmpty - ): # Should still raise QueueEmpty as per current implementation + with pytest.raises(expected_queue_closed_exception): event_queue.queue.get_nowait() # verify internal queue is empty # This test is tricky because await event_queue.dequeue_event() would hang if not for the close check.