Skip to content

Commit

Permalink
Asyncify filters (#2744)
Browse files Browse the repository at this point in the history
* Asyncify filters
  • Loading branch information
pacrob committed Dec 23, 2022
1 parent 39859aa commit 9f08272
Show file tree
Hide file tree
Showing 33 changed files with 2,449 additions and 430 deletions.
71 changes: 36 additions & 35 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import pytest
import pytest_asyncio
import time
import warnings

Expand All @@ -14,27 +15,11 @@
EthereumTesterProvider,
)


class PollDelayCounter:
def __init__(self, initial_delay=0, max_delay=1, initial_step=0.01):
self.initial_delay = initial_delay
self.initial_step = initial_step
self.max_delay = max_delay
self.current_delay = initial_delay

def __call__(self):
delay = self.current_delay

if self.current_delay == 0:
self.current_delay += self.initial_step
else:
self.current_delay *= 2
self.current_delay = min(self.current_delay, self.max_delay)

return delay

def reset(self):
self.current_delay = self.initial_delay
from tests.utils import (
PollDelayCounter,
_async_wait_for_block_fixture_logic,
_async_wait_for_transaction_fixture_logic,
)


@pytest.fixture()
Expand All @@ -46,25 +31,12 @@ def is_testrpc_provider(provider):
return isinstance(provider, EthereumTesterProvider)


def is_async_testrpc_provider(provider):
return isinstance(provider, AsyncEthereumTesterProvider)


@pytest.fixture()
def skip_if_testrpc():

def _skip_if_testrpc(w3):
if is_testrpc_provider(w3.provider):
pytest.skip()
return _skip_if_testrpc


@pytest.fixture()
def async_skip_if_testrpc():

def _skip_if_testrpc(async_w3):
if is_async_testrpc_provider(async_w3.provider):
pytest.skip()
return _skip_if_testrpc


Expand All @@ -76,6 +48,7 @@ def _wait_for_miner_start(w3, timeout=60):
while not w3.eth.mining or not w3.eth.hashrate:
time.sleep(poll_delay_counter())
timeout.check()

return _wait_for_miner_start


Expand All @@ -89,6 +62,7 @@ def _wait_for_block(w3, block_number=1, timeout=None):
while w3.eth.block_number < block_number:
w3.manager.request_blocking("evm_mine", [])
timeout.sleep(poll_delay_counter())

return _wait_for_block


Expand All @@ -105,6 +79,7 @@ def _wait_for_transaction(w3, txn_hash, timeout=120):
timeout.check()

return txn_receipt

return _wait_for_transaction


Expand All @@ -123,4 +98,30 @@ def w3_strict_abi():

@pytest.fixture(autouse=True)
def print_warnings():
warnings.simplefilter('always')
warnings.simplefilter("always")


# --- async --- #


def is_async_testrpc_provider(provider):
return isinstance(provider, AsyncEthereumTesterProvider)


@pytest.fixture()
def async_skip_if_testrpc():
def _skip_if_testrpc(async_w3):
if is_async_testrpc_provider(async_w3.provider):
pytest.skip()

return _skip_if_testrpc


@pytest_asyncio.fixture()
async def async_wait_for_block():
return _async_wait_for_block_fixture_logic


@pytest_asyncio.fixture()
async def async_wait_for_transaction():
return _async_wait_for_transaction_fixture_logic
1 change: 1 addition & 0 deletions newsfragments/2744.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added async functionality to filter
6 changes: 4 additions & 2 deletions tests/core/contracts/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
)
import pytest_asyncio

from _utils import (
from tests.core.contracts.utils import (
async_deploy,
async_partial,
deploy,
)
from tests.utils import (
async_partial,
)
from web3._utils.module_testing.emitter_contract import (
CONTRACT_EMITTER_ABI,
CONTRACT_EMITTER_CODE,
Expand Down
2 changes: 1 addition & 1 deletion tests/core/contracts/test_contract_call_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
)
import pytest_asyncio

from _utils import (
from tests.core.contracts.utils import (
async_deploy,
deploy,
)
Expand Down
2 changes: 1 addition & 1 deletion tests/core/contracts/test_contract_caller_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest_asyncio

from _utils import (
from tests.core.contracts.utils import (
async_deploy,
deploy,
)
Expand Down
12 changes: 0 additions & 12 deletions tests/core/contracts/_utils.py → tests/core/contracts/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import asyncio

from eth_utils.toolz import (
identity,
)
Expand Down Expand Up @@ -27,13 +25,3 @@ async def async_deploy(async_web3, Contract, apply_func=identity, args=None):
assert contract.address == address
assert len(await async_web3.eth.get_code(contract.address)) > 0
return contract


def async_partial(f, *args, **kwargs):
async def f2(*args2, **kwargs2):
result = f(*args, *args2, **kwargs, **kwargs2)
if asyncio.iscoroutinefunction(f):
result = await result
return result

return f2
49 changes: 49 additions & 0 deletions tests/core/eth-module/test_eth_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import pytest

import pytest_asyncio

from web3 import Web3
from web3._utils.filters import (
AsyncBlockFilter,
AsyncLogFilter,
AsyncTransactionFilter,
BlockFilter,
LogFilter,
TransactionFilter,
)
from web3.eth import (
AsyncEth,
)
from web3.providers.eth_tester.main import (
AsyncEthereumTesterProvider,
)


def test_Eth_filter_creates_correct_filter_type(w3):
filter1 = w3.eth.filter("latest")
assert isinstance(filter1, BlockFilter)
filter2 = w3.eth.filter("pending")
assert isinstance(filter2, TransactionFilter)
filter3 = w3.eth.filter({})
assert isinstance(filter3, LogFilter)


# --- async --- #


@pytest_asyncio.fixture()
async def async_w3():
provider = AsyncEthereumTesterProvider()
w3 = Web3(provider, modules={"eth": [AsyncEth]}, middlewares=[])
return w3


@pytest.mark.asyncio
async def test_AsyncEth_filter_creates_correct_filter_type(async_w3):

filter1 = await async_w3.eth.filter("latest")
assert isinstance(filter1, AsyncBlockFilter)
filter2 = await async_w3.eth.filter("pending")
assert isinstance(filter2, AsyncTransactionFilter)
filter3 = await async_w3.eth.filter({})
assert isinstance(filter3, AsyncLogFilter)
91 changes: 62 additions & 29 deletions tests/core/filtering/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@
encode_hex,
event_signature_to_log_topic,
)
import pytest_asyncio

from web3 import Web3
from tests.core.filtering.utils import (
_async_emitter_fixture_logic,
_async_w3_fixture_logic,
_emitter_fixture_logic,
_w3_fixture_logic,
)
from tests.utils import (
async_partial,
)
from web3._utils.module_testing.emitter_contract import (
CONTRACT_EMITTER_ABI,
CONTRACT_EMITTER_CODE,
CONTRACT_EMITTER_RUNTIME,
)
from web3.middleware import (
local_filter_middleware,
)
from web3.providers.eth_tester import (
EthereumTesterProvider,
)


@pytest.fixture(
Expand All @@ -27,17 +30,7 @@
ids=["local_filter_middleware", "node_based_filter"],
)
def w3(request):
use_filter_middleware = request.param
provider = EthereumTesterProvider()
w3 = Web3(provider)
if use_filter_middleware:
w3.middleware_onion.add(local_filter_middleware)
return w3


@pytest.fixture(autouse=True)
def wait_for_mining_start(w3, wait_for_block):
wait_for_block(w3)
return _w3_fixture_logic(request)


@pytest.fixture()
Expand Down Expand Up @@ -71,16 +64,9 @@ def Emitter(w3, EMITTER):

@pytest.fixture()
def emitter(w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func):
wait_for_block(w3)
deploy_txn_hash = Emitter.constructor().transact({"gas": 10000000})
deploy_receipt = wait_for_transaction(w3, deploy_txn_hash)
contract_address = address_conversion_func(deploy_receipt["contractAddress"])

bytecode = w3.eth.get_code(contract_address)
assert bytecode == Emitter.bytecode_runtime
_emitter = Emitter(address=contract_address)
assert _emitter.address == contract_address
return _emitter
return _emitter_fixture_logic(
w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func
)


class LogFunctions:
Expand Down Expand Up @@ -163,7 +149,7 @@ def emitter_log_topics():
return LogTopics


def return_filter(contract=None, args=[]):
def return_filter(contract, args):
event_name = args[0]
kwargs = apply_key_map({"filter": "argument_filters"}, args[1])
if "fromBlock" not in kwargs:
Expand All @@ -174,3 +160,50 @@ def return_filter(contract=None, args=[]):
@pytest.fixture(scope="module")
def create_filter(request):
return functools.partial(return_filter)


# --- async --- #


@pytest.fixture(
scope="function",
params=[True, False],
ids=["async_local_filter_middleware", "node_based_filter"],
)
def async_w3(request):
return _async_w3_fixture_logic(request)


@pytest.fixture()
def AsyncEmitter(async_w3, EMITTER):
return async_w3.eth.contract(**EMITTER)


@pytest_asyncio.fixture()
async def async_emitter(
async_w3,
AsyncEmitter,
async_wait_for_transaction,
async_wait_for_block,
address_conversion_func,
):
return await _async_emitter_fixture_logic(
async_w3,
AsyncEmitter,
async_wait_for_transaction,
async_wait_for_block,
address_conversion_func,
)


async def async_return_filter(contract, args):
event_name = args[0]
kwargs = apply_key_map({"filter": "argument_filters"}, args[1])
if "fromBlock" not in kwargs:
kwargs["fromBlock"] = "latest"
return await contract.events[event_name].create_filter(**kwargs)


@pytest_asyncio.fixture(scope="module")
async def async_create_filter(request):
return async_partial(async_return_filter)
Loading

0 comments on commit 9f08272

Please sign in to comment.