Skip to content

Commit ae14633

Browse files
author
Paul Robinson
committedSep 8, 2022
[WIP] Async filters feature branch (ethereum#2588)
* async filters eth module
1 parent 7145564 commit ae14633

File tree

2 files changed

+127
-48
lines changed

2 files changed

+127
-48
lines changed
 

‎web3/_utils/module_testing/eth_module.py

+61-13
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,64 @@ def test_async_provider_default_block(
14031403
# reset to default
14041404
async_w3.eth.default_block = "latest"
14051405

1406+
@pytest.mark.asyncio
1407+
async def test_async_eth_new_filter(self, async_w3: "Web3") -> None:
1408+
filter = await async_w3.eth.filter({})
1409+
1410+
changes = await async_w3.eth.get_filter_changes(
1411+
filter.filter_id
1412+
) # type: ignore
1413+
assert is_list_like(changes)
1414+
assert not changes
1415+
1416+
logs = await async_w3.eth.get_filter_logs(filter.filter_id) # type: ignore
1417+
assert is_list_like(logs)
1418+
assert not logs
1419+
1420+
result = await async_w3.eth.uninstall_filter(filter.filter_id) # type: ignore
1421+
assert result is True
1422+
1423+
@pytest.mark.asyncio
1424+
async def test_async_eth_new_block_filter(self, async_w3: "Web3") -> None:
1425+
filter = await async_w3.eth.filter("latest")
1426+
assert is_string(filter.filter_id)
1427+
1428+
changes = await async_w3.eth.get_filter_changes(
1429+
filter.filter_id
1430+
) # type: ignore
1431+
assert is_list_like(changes)
1432+
assert not changes
1433+
1434+
result = await async_w3.eth.uninstall_filter(filter.filter_id) # type: ignore
1435+
assert result is True
1436+
1437+
@pytest.mark.asyncio
1438+
async def test_async_eth_new_pending_transaction_filter(
1439+
self, async_w3: "Web3"
1440+
) -> None:
1441+
filter = await async_w3.eth.filter("pending")
1442+
assert is_string(filter.filter_id)
1443+
1444+
changes = await async_w3.eth.get_filter_changes(
1445+
filter.filter_id
1446+
) # type: ignore
1447+
assert is_list_like(changes)
1448+
assert not changes
1449+
1450+
result = await async_w3.eth.uninstall_filter(filter.filter_id) # type: ignore
1451+
assert result is True
1452+
1453+
@pytest.mark.asyncio
1454+
async def test_async_eth_uninstall_filter(self, async_w3: "Web3") -> None:
1455+
filter = await async_w3.eth.filter({})
1456+
assert is_string(filter.filter_id)
1457+
1458+
success = await async_w3.eth.uninstall_filter(filter.filter_id) # type: ignore
1459+
assert success is True
1460+
1461+
failure = await async_w3.eth.uninstall_filter(filter.filter_id) # type: ignore
1462+
assert failure is False
1463+
14061464

14071465
class EthModuleTest:
14081466
def test_eth_syncing(self, w3: "Web3") -> None:
@@ -3093,7 +3151,7 @@ def test_eth_getUncleByBlockNumberAndIndex(self, w3: "Web3") -> None:
30933151
# TODO: how do we make uncles....
30943152
pass
30953153

3096-
def test_eth_newFilter(self, w3: "Web3") -> None:
3154+
def test_eth_new_filter(self, w3: "Web3") -> None:
30973155
filter = w3.eth.filter({})
30983156

30993157
changes = w3.eth.get_filter_changes(filter.filter_id)
@@ -3107,35 +3165,25 @@ def test_eth_newFilter(self, w3: "Web3") -> None:
31073165
result = w3.eth.uninstall_filter(filter.filter_id)
31083166
assert result is True
31093167

3110-
def test_eth_newBlockFilter(self, w3: "Web3") -> None:
3168+
def test_eth_new_block_filter(self, w3: "Web3") -> None:
31113169
filter = w3.eth.filter("latest")
31123170
assert is_string(filter.filter_id)
31133171

31143172
changes = w3.eth.get_filter_changes(filter.filter_id)
31153173
assert is_list_like(changes)
31163174
assert not changes
31173175

3118-
# TODO: figure out why this fails in go-ethereum
3119-
# logs = w3.eth.get_filter_logs(filter.filter_id)
3120-
# assert is_list_like(logs)
3121-
# assert not logs
3122-
31233176
result = w3.eth.uninstall_filter(filter.filter_id)
31243177
assert result is True
31253178

3126-
def test_eth_newPendingTransactionFilter(self, w3: "Web3") -> None:
3179+
def test_eth_new_pending_transaction_filter(self, w3: "Web3") -> None:
31273180
filter = w3.eth.filter("pending")
31283181
assert is_string(filter.filter_id)
31293182

31303183
changes = w3.eth.get_filter_changes(filter.filter_id)
31313184
assert is_list_like(changes)
31323185
assert not changes
31333186

3134-
# TODO: figure out why this fails in go-ethereum
3135-
# logs = w3.eth.get_filter_logs(filter.filter_id)
3136-
# assert is_list_like(logs)
3137-
# assert not logs
3138-
31393187
result = w3.eth.uninstall_filter(filter.filter_id)
31403188
assert result is True
31413189

‎web3/eth.py

+66-35
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,35 @@ def set_contract_factory(
346346
) -> None:
347347
self.defaultContractFactory = contractFactory
348348

349+
def filter_munger(
350+
self,
351+
filter_params: Optional[Union[str, FilterParams]] = None,
352+
filter_id: Optional[HexStr] = None,
353+
) -> Union[List[FilterParams], List[HexStr], List[str]]:
354+
if filter_id and filter_params:
355+
raise TypeError(
356+
"Ambiguous invocation: provide either a `filter_params` or a "
357+
"`filter_id` argument. Both were supplied."
358+
)
359+
if isinstance(filter_params, dict):
360+
return [filter_params]
361+
elif is_string(filter_params):
362+
if filter_params in ["latest", "pending"]:
363+
return [filter_params]
364+
else:
365+
raise ValueError(
366+
"The filter API only accepts the values of `pending` or "
367+
"`latest` for string based filters"
368+
)
369+
elif filter_id and not filter_params:
370+
return [filter_id]
371+
else:
372+
raise TypeError(
373+
"Must provide either filter_params as a string or "
374+
"a valid filter object, or a filter_id as a string "
375+
"or hex."
376+
)
377+
349378

350379
class AsyncEth(BaseEth):
351380
is_async = True
@@ -597,6 +626,37 @@ async def get_storage_at(
597626
) -> HexBytes:
598627
return await self._get_storage_at(account, position, block_identifier)
599628

629+
filter: Method[Callable[..., Awaitable[Any]]] = Method(
630+
method_choice_depends_on_args=select_filter_method(
631+
if_new_block_filter=RPC.eth_newBlockFilter,
632+
if_new_pending_transaction_filter=RPC.eth_newPendingTransactionFilter,
633+
if_new_filter=RPC.eth_newFilter,
634+
),
635+
mungers=[BaseEth.filter_munger],
636+
)
637+
638+
_get_filter_changes: Method[
639+
Callable[[HexStr], Awaitable[List[LogReceipt]]]
640+
] = Method(RPC.eth_getFilterChanges, mungers=[default_root_munger])
641+
642+
async def get_filter_changes(self, filter_id: HexStr) -> List[LogReceipt]:
643+
return await self._get_filter_changes(filter_id)
644+
645+
_get_filter_logs: Method[Callable[[HexStr], Awaitable[List[LogReceipt]]]] = Method(
646+
RPC.eth_getFilterLogs, mungers=[default_root_munger]
647+
)
648+
649+
async def get_filter_logs(self, filter_id: HexStr) -> List[LogReceipt]:
650+
return await self._get_filter_logs(filter_id)
651+
652+
_uninstall_filter: Method[Callable[[HexStr], Awaitable[bool]]] = Method(
653+
RPC.eth_uninstallFilter,
654+
mungers=[default_root_munger],
655+
)
656+
657+
async def uninstall_filter(self, filter_id: HexStr) -> bool:
658+
return await self._uninstall_filter(filter_id)
659+
600660

601661
class Eth(BaseEth):
602662
defaultContractFactory: Type[Union[Contract, ContractCaller]] = Contract
@@ -902,42 +962,13 @@ def fee_history(
902962
) -> FeeHistory:
903963
return self._fee_history(block_count, newest_block, reward_percentiles)
904964

905-
def filter_munger(
906-
self,
907-
filter_params: Optional[Union[str, FilterParams]] = None,
908-
filter_id: Optional[HexStr] = None,
909-
) -> Union[List[FilterParams], List[HexStr], List[str]]:
910-
if filter_id and filter_params:
911-
raise TypeError(
912-
"Ambiguous invocation: provide either a `filter_params` or a "
913-
"`filter_id` argument. Both were supplied."
914-
)
915-
if isinstance(filter_params, dict):
916-
return [filter_params]
917-
elif is_string(filter_params):
918-
if filter_params in ["latest", "pending"]:
919-
return [filter_params]
920-
else:
921-
raise ValueError(
922-
"The filter API only accepts the values of `pending` or "
923-
"`latest` for string based filters"
924-
)
925-
elif filter_id and not filter_params:
926-
return [filter_id]
927-
else:
928-
raise TypeError(
929-
"Must provide either filter_params as a string or "
930-
"a valid filter object, or a filter_id as a string "
931-
"or hex."
932-
)
933-
934965
filter: Method[Callable[..., Any]] = Method(
935966
method_choice_depends_on_args=select_filter_method(
936967
if_new_block_filter=RPC.eth_newBlockFilter,
937968
if_new_pending_transaction_filter=RPC.eth_newPendingTransactionFilter,
938969
if_new_filter=RPC.eth_newFilter,
939970
),
940-
mungers=[filter_munger],
971+
mungers=[BaseEth.filter_munger],
941972
)
942973

943974
get_filter_changes: Method[Callable[[HexStr], List[LogReceipt]]] = Method(
@@ -948,6 +979,11 @@ def filter_munger(
948979
RPC.eth_getFilterLogs, mungers=[default_root_munger]
949980
)
950981

982+
uninstall_filter: Method[Callable[[HexStr], bool]] = Method(
983+
RPC.eth_uninstallFilter,
984+
mungers=[default_root_munger],
985+
)
986+
951987
get_logs: Method[Callable[[FilterParams], List[LogReceipt]]] = Method(
952988
RPC.eth_getLogs, mungers=[default_root_munger]
953989
)
@@ -962,11 +998,6 @@ def filter_munger(
962998
mungers=[default_root_munger],
963999
)
9641000

965-
uninstall_filter: Method[Callable[[HexStr], bool]] = Method(
966-
RPC.eth_uninstallFilter,
967-
mungers=[default_root_munger],
968-
)
969-
9701001
get_work: Method[Callable[[], List[HexBytes]]] = Method(
9711002
RPC.eth_getWork,
9721003
is_property=True,

0 commit comments

Comments
 (0)
Please sign in to comment.