Skip to content

Commit 9982f13

Browse files
realjohnwardkclowes
authored andcommitted
Implement hasattr for contract events
1 parent 727306b commit 9982f13

File tree

4 files changed

+49
-1
lines changed

4 files changed

+49
-1
lines changed

newsfragments/1560.bugfix.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Fixed hasattr overloader method in the web3.ContractEvent class by implementing a try/except handler
2+
that returns False if an exception is raised in the __getattr__ overloader method
3+
(since __getattr__ HAS to be called in every __hasattr__ call).
4+
5+
Created an Exception class called 'ABIEventFunctionNotFound', which inherits from both AttributeError and
6+
MismatchedABI, and replaced the MismatchedABI raise with a raise to the created class in the __getattr__
7+
overloader method of the web3.ContractEvent object.
8+
9+
Created the test scripts 'test_contract_events_hasattr.py' and 'test_contract_events_getattr.py'

tests/core/contracts/test_extracting_event_data.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
get_event_data,
1313
)
1414
from web3.exceptions import (
15+
ABIEventFunctionNotFound,
1516
LogTopicError,
1617
ValidationError,
1718
)
@@ -113,6 +114,29 @@ def dup_txn_receipt(
113114
return wait_for_transaction(web3, dup_txn_hash)
114115

115116

117+
@pytest.fixture()
118+
def single_event_abi():
119+
return '''[{"anonymous":false,"inputs":[{"indexed":false,"name":"value","type":"uint256"}],"name":"Increased","type":"event"}]''' # noqa: E501
120+
121+
122+
def test_contract_event_getattr(web3, single_event_abi):
123+
contract = web3.eth.contract(abi=single_event_abi)
124+
assert getattr(contract.events, "Increased")
125+
126+
127+
def test_contract_event_getattr_raises_error(web3, single_event_abi):
128+
contract = web3.eth.contract(abi=single_event_abi)
129+
130+
with pytest.raises(ABIEventFunctionNotFound):
131+
getattr(contract.events, "Decreased")
132+
133+
134+
def test_contract_event_hasattr(web3, single_event_abi):
135+
contract = web3.eth.contract(abi=single_event_abi)
136+
assert hasattr(contract.events, "Increased") is True
137+
assert hasattr(contract.events, "Decreased") is False
138+
139+
116140
@pytest.mark.parametrize(
117141
'contract_fn,event_name,call_args,expected_args',
118142
(

web3/contract.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
MutableAttributeDict,
111111
)
112112
from web3.exceptions import (
113+
ABIEventFunctionNotFound,
113114
BadFunctionCallOutput,
114115
BlockNumberOutofRange,
115116
FallbackNotFound,
@@ -239,7 +240,7 @@ def __getattr__(self, event_name: str) -> "ContractEvent":
239240
"Are you sure you provided the correct contract abi?"
240241
)
241242
elif event_name not in self.__dict__['_events']:
242-
raise MismatchedABI(
243+
raise ABIEventFunctionNotFound(
243244
"The event '{}' was not found in this contract's abi. ".format(event_name),
244245
"Are you sure you provided the correct contract abi?"
245246
)
@@ -257,6 +258,12 @@ def __iter__(self) -> Iterable["ContractEvent"]:
257258
for event in self._events:
258259
yield self[event['name']]
259260

261+
def __hasattr__(self, event_name: str) -> bool:
262+
try:
263+
return event_name in self.__dict__['_events']
264+
except ABIEventFunctionNotFound:
265+
return False
266+
260267

261268
class Contract:
262269
"""Base class for Contract proxy classes.

web3/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ class MismatchedABI(Exception):
7070
pass
7171

7272

73+
class ABIEventFunctionNotFound(AttributeError, MismatchedABI):
74+
"""
75+
Raised when an attempt is made to access an event
76+
that does not exist in the ABI.
77+
"""
78+
pass
79+
80+
7381
class FallbackNotFound(Exception):
7482
"""
7583
Raised when fallback function doesn't exist in contract.

0 commit comments

Comments
 (0)