diff --git a/luno_python/base_client.py b/luno_python/base_client.py index ed7f7f7..fba61d3 100644 --- a/luno_python/base_client.py +++ b/luno_python/base_client.py @@ -70,10 +70,13 @@ def do(self, method, path, req=None, auth=False): :type req: object :type auth: bool """ - try: - params = json.loads(json.dumps(req)) - except Exception: + if req is None: params = None + else: + try: + params = json.loads(json.dumps(req)) + except TypeError as e: + raise TypeError("luno: request parameters must be JSON-serializable: %s" % str(e)) from e headers = {"User-Agent": self.make_user_agent()} args = dict(timeout=self.timeout, params=params, headers=headers) if auth: diff --git a/tests/test_client.py b/tests/test_client.py index 2b40d14..2ee8885 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,3 +1,5 @@ +from decimal import Decimal + import pytest import requests import requests_mock @@ -262,3 +264,29 @@ def test_get_balances_with_malformed_response(): # Test without account_id on malformed response result = c.get_balances() assert result == MOCK_MALFORMED_RESPONSE + + +def test_client_do_with_non_serializable_params(): + """Test that non-JSON-serializable parameters raise a clear error.""" + c = Client() + c.set_base_url("mock://test/") + + # Test with Decimal (not JSON-serializable) + with pytest.raises(TypeError) as exc_info: + c.do("GET", "/", req={"amount": Decimal("10.5")}) + assert "JSON-serializable" in str(exc_info.value) + + # Test with custom object (not JSON-serializable) + class CustomObject: + pass + + with pytest.raises(TypeError) as exc_info: + c.do("GET", "/", req={"obj": CustomObject()}) + assert "JSON-serializable" in str(exc_info.value) + + # Test with None request (should not raise) + adapter = requests_mock.Adapter() + c.session.mount("mock", adapter) + adapter.register_uri("GET", "mock://test/", json={"result": "ok"}) + result = c.do("GET", "/", req=None) + assert result["result"] == "ok"