Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asyncify filters #2744

Merged
merged 11 commits into from
Dec 23, 2022
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