From 5b2d869011859a0a48407f2093c81ea466df95dd Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Mon, 4 Mar 2024 14:16:15 -0700 Subject: [PATCH 1/5] Add `user_message` to `Web3Exception` --- web3/exceptions.py | 11 +++++++++++ web3/manager.py | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/web3/exceptions.py b/web3/exceptions.py index 217c4744c1..ae3d50ab07 100644 --- a/web3/exceptions.py +++ b/web3/exceptions.py @@ -30,6 +30,16 @@ class Web3Exception(Exception): # deal with other exceptions """ + def __init__( + self, + *args: Any, + user_message: Optional[str] = None, + **kwargs: Any, + ): + super().__init__(*args) + # Assign properties of Web3Exception + self.__dict__.update(locals()) + class BadFunctionCallOutput(Web3Exception): """ @@ -274,6 +284,7 @@ def __init__( message: Optional[str] = None, data: Optional[Union[str, Dict[str, str]]] = None, ): + super().__init__(message, data) self.message = message self.data = data diff --git a/web3/manager.py b/web3/manager.py index 67a69f94e0..a70fce3c10 100644 --- a/web3/manager.py +++ b/web3/manager.py @@ -276,7 +276,11 @@ def formatted_response( if not isinstance(code, int): _raise_bad_response_format(response, "error['code'] must be an integer") elif code == METHOD_NOT_FOUND: - raise MethodUnavailable(error) + raise MethodUnavailable( + error, + user_message="Check your node provider's API docs to see what " + "methods are supported", + ) # Errors must include a message if not isinstance(error.get("message"), str): From a3bb4cdb95e07cc7cf90e7ccb1bedc09ef27dac2 Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Tue, 12 Mar 2024 11:00:33 -0600 Subject: [PATCH 2/5] Move block-utils tests to core --- .../block-utils/test_select_method_for_block_identifier.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/core/{core => }/block-utils/test_select_method_for_block_identifier.py (100%) diff --git a/tests/core/core/block-utils/test_select_method_for_block_identifier.py b/tests/core/block-utils/test_select_method_for_block_identifier.py similarity index 100% rename from tests/core/core/block-utils/test_select_method_for_block_identifier.py rename to tests/core/block-utils/test_select_method_for_block_identifier.py From 7ac05d3702fbb9f738795cb6477bb8424d876a10 Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Tue, 12 Mar 2024 11:00:49 -0600 Subject: [PATCH 3/5] Tests for raising Web3Exception --- tests/core/exceptions/test_exceptions.py | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/core/exceptions/test_exceptions.py diff --git a/tests/core/exceptions/test_exceptions.py b/tests/core/exceptions/test_exceptions.py new file mode 100644 index 0000000000..956294bf14 --- /dev/null +++ b/tests/core/exceptions/test_exceptions.py @@ -0,0 +1,30 @@ +import pytest + +from web3.exceptions import ( + Web3Exception, +) + + +def test_web3exception_with_user_message(): + with pytest.raises(Web3Exception) as exception: + raise Web3Exception(user_message="This failed!") + assert exception.type is Web3Exception + assert exception.value.user_message == "This failed!" + + +def test_web3exception_with_kwargs(): + with pytest.raises(Web3Exception) as exception: + raise Web3Exception(data={"message": "Unable to fulfill your request."}) + assert exception.type is Web3Exception + assert exception.value.user_message is None + assert ( + exception.value.kwargs["data"]["message"] == "Unable to fulfill your request." + ) + + +def test_web3exception_with_args(): + with pytest.raises(Web3Exception) as exception: + raise Web3Exception("failed") + assert exception.type is Web3Exception + assert exception.value.user_message is None + assert exception.value.args[0] == "failed" From 329b0513dd0d7373d881e02989d0bee0ac79081f Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Wed, 13 Mar 2024 10:18:59 -0600 Subject: [PATCH 4/5] Explicit assignment of `user_message` kwarg, disallow kwargs in general --- tests/core/exceptions/test_exceptions.py | 14 ++++++++------ web3/exceptions.py | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/core/exceptions/test_exceptions.py b/tests/core/exceptions/test_exceptions.py index 956294bf14..e613cb517d 100644 --- a/tests/core/exceptions/test_exceptions.py +++ b/tests/core/exceptions/test_exceptions.py @@ -13,13 +13,15 @@ def test_web3exception_with_user_message(): def test_web3exception_with_kwargs(): - with pytest.raises(Web3Exception) as exception: + with pytest.raises(TypeError) as exception: raise Web3Exception(data={"message": "Unable to fulfill your request."}) - assert exception.type is Web3Exception - assert exception.value.user_message is None - assert ( - exception.value.kwargs["data"]["message"] == "Unable to fulfill your request." - ) + + # For Python > 3.9, str exception includes 'Web3Exception.' + expected = "__init__() got an unexpected keyword argument 'data'" + actual = str(exception.value) + assert exception.type is TypeError + assert hasattr(exception.value, "data") is False + assert expected in actual def test_web3exception_with_args(): diff --git a/web3/exceptions.py b/web3/exceptions.py index ae3d50ab07..154290533a 100644 --- a/web3/exceptions.py +++ b/web3/exceptions.py @@ -34,11 +34,11 @@ def __init__( self, *args: Any, user_message: Optional[str] = None, - **kwargs: Any, ): super().__init__(*args) + # Assign properties of Web3Exception - self.__dict__.update(locals()) + self.user_message = user_message class BadFunctionCallOutput(Web3Exception): From a4d4283ba3561ab441e79f5b563dccb502b7141c Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Thu, 14 Mar 2024 09:16:05 -0600 Subject: [PATCH 5/5] Newsfragment for #3282 --- newsfragments/3282.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/3282.feature.rst diff --git a/newsfragments/3282.feature.rst b/newsfragments/3282.feature.rst new file mode 100644 index 0000000000..00b905b374 --- /dev/null +++ b/newsfragments/3282.feature.rst @@ -0,0 +1 @@ +Add ``user_message`` kwarg for human readable ``Web3Exception`` messages. \ No newline at end of file