diff --git a/src/a2a/client/errors.py b/src/a2a/client/errors.py index 890c3726a..106a05d68 100644 --- a/src/a2a/client/errors.py +++ b/src/a2a/client/errors.py @@ -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.""" @@ -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})' + class A2AClientTimeoutError(A2AClientError): """Client exception for timeout errors during a request.""" @@ -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.""" @@ -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.""" @@ -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.""" @@ -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})' diff --git a/tests/client/test_errors.py b/tests/client/test_errors.py index 60636bd37..c3b065f45 100644 --- a/tests/client/test_errors.py +++ b/tests/client/test_errors.py @@ -3,6 +3,13 @@ import pytest from a2a.client import A2AClientError, A2AClientHTTPError, A2AClientJSONError +from a2a.client.errors import ( + A2AClientInvalidArgsError, + A2AClientInvalidStateError, + A2AClientJSONRPCError, + A2AClientTimeoutError, +) +from a2a.types import JSONRPCError, JSONRPCErrorResponse class TestA2AClientError: @@ -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') @@ -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') @@ -108,6 +130,57 @@ 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 = JSONRPCErrorResponse( + id='test-1', + error=JSONRPCError(code=-32601, message='Method not found'), + ) + error = A2AClientJSONRPCError(response) + assert ( + repr(error) + == "A2AClientJSONRPCError(JSONRPCError(code=-32601, data=None, message='Method not found'))" + ) + + class TestExceptionHierarchy: """Test the exception hierarchy and relationships."""