Skip to content
Merged
28 changes: 28 additions & 0 deletions src/a2a/client/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ def __init__(self, status_code: int, message: str):
self.message = message
super().__init__(f'HTTP Error {status_code}: {message}')

def __repr__(self) -> str:
"""Returns an unambiguous representation showing structured attributes."""
return (
f'{self.__class__.__name__}('
f'status_code={self.status_code!r}, '
f'message={self.message!r})'
)


class A2AClientJSONError(A2AClientError):
"""Client exception for JSON errors during response parsing or validation."""
Expand All @@ -34,6 +42,10 @@ def __init__(self, message: str):
self.message = message
super().__init__(f'JSON Error: {message}')

def __repr__(self) -> str:
"""Returns an unambiguous representation showing structured attributes."""
return f'{self.__class__.__name__}(message={self.message!r})'
Comment thread
ishymko marked this conversation as resolved.


class A2AClientTimeoutError(A2AClientError):
"""Client exception for timeout errors during a request."""
Expand All @@ -47,6 +59,10 @@ def __init__(self, message: str):
self.message = message
super().__init__(f'Timeout Error: {message}')

def __repr__(self) -> str:
"""Returns an unambiguous representation showing structured attributes."""
return f'{self.__class__.__name__}(message={self.message!r})'


class A2AClientInvalidArgsError(A2AClientError):
"""Client exception for invalid arguments passed to a method."""
Expand All @@ -60,6 +76,10 @@ def __init__(self, message: str):
self.message = message
super().__init__(f'Invalid arguments error: {message}')

def __repr__(self) -> str:
"""Returns an unambiguous representation showing structured attributes."""
return f'{self.__class__.__name__}(message={self.message!r})'


class A2AClientInvalidStateError(A2AClientError):
"""Client exception for an invalid client state."""
Expand All @@ -73,6 +93,10 @@ def __init__(self, message: str):
self.message = message
super().__init__(f'Invalid state error: {message}')

def __repr__(self) -> str:
"""Returns an unambiguous representation showing structured attributes."""
return f'{self.__class__.__name__}(message={self.message!r})'


class A2AClientJSONRPCError(A2AClientError):
"""Client exception for JSON-RPC errors returned by the server."""
Expand All @@ -85,3 +109,7 @@ def __init__(self, error: JSONRPCErrorResponse):
"""
self.error = error.error
super().__init__(f'JSON-RPC Error {error.error}')

def __repr__(self) -> str:
"""Returns an unambiguous representation showing the JSON-RPC error object."""
return f'{self.__class__.__name__}({self.error!r})'
67 changes: 67 additions & 0 deletions tests/client/test_errors.py
Comment thread
ishymko marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
from typing import NoReturn
from unittest.mock import MagicMock

import pytest

from a2a.client import A2AClientError, A2AClientHTTPError, A2AClientJSONError
from a2a.client.errors import (
A2AClientInvalidArgsError,
A2AClientInvalidStateError,
A2AClientJSONRPCError,
A2AClientTimeoutError,
)


class TestA2AClientError:
Expand Down Expand Up @@ -35,6 +42,14 @@ def test_message_formatting(self) -> None:
error = A2AClientHTTPError(500, 'Internal Server Error')
assert str(error) == 'HTTP Error 500: Internal Server Error'

def test_repr(self) -> None:
"""Test that __repr__ shows structured attributes."""
error = A2AClientHTTPError(404, 'Not Found')
assert (
repr(error)
== "A2AClientHTTPError(status_code=404, message='Not Found')"
)

def test_inheritance(self) -> None:
"""Test that A2AClientHTTPError inherits from A2AClientError."""
error = A2AClientHTTPError(400, 'Bad Request')
Expand Down Expand Up @@ -81,6 +96,13 @@ def test_message_formatting(self) -> None:
error = A2AClientJSONError('Missing required field')
assert str(error) == 'JSON Error: Missing required field'

def test_repr(self) -> None:
"""Test that __repr__ shows structured attributes."""
error = A2AClientJSONError('Invalid JSON format')
assert (
repr(error) == "A2AClientJSONError(message='Invalid JSON format')"
)

def test_inheritance(self) -> None:
"""Test that A2AClientJSONError inherits from A2AClientError."""
error = A2AClientJSONError('Parsing error')
Expand Down Expand Up @@ -108,6 +130,51 @@ def test_with_various_messages(self) -> None:
assert str(error) == f'JSON Error: {message}'


class TestA2AClientTimeoutErrorRepr:
"""Test __repr__ for A2AClientTimeoutError."""

def test_repr(self) -> None:
"""Test that __repr__ shows structured attributes."""
error = A2AClientTimeoutError('Request timed out')
assert (
repr(error) == "A2AClientTimeoutError(message='Request timed out')"
)


class TestA2AClientInvalidArgsErrorRepr:
"""Test __repr__ for A2AClientInvalidArgsError."""

def test_repr(self) -> None:
"""Test that __repr__ shows structured attributes."""
error = A2AClientInvalidArgsError('Missing required param')
assert (
repr(error)
== "A2AClientInvalidArgsError(message='Missing required param')"
)


class TestA2AClientInvalidStateErrorRepr:
"""Test __repr__ for A2AClientInvalidStateError."""

def test_repr(self) -> None:
"""Test that __repr__ shows structured attributes."""
error = A2AClientInvalidStateError('Client not initialized')
assert (
repr(error)
== "A2AClientInvalidStateError(message='Client not initialized')"
)


class TestA2AClientJSONRPCErrorRepr:
"""Test __repr__ for A2AClientJSONRPCError."""

def test_repr(self) -> None:
"""Test that __repr__ shows the JSON-RPC error object."""
response = MagicMock()
error = A2AClientJSONRPCError(response)
Comment thread
ishymko marked this conversation as resolved.
assert repr(error) == f'A2AClientJSONRPCError({response.error!r})'


class TestExceptionHierarchy:
"""Test the exception hierarchy and relationships."""

Expand Down
Loading