Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Table of Contents
troubleshooting
web3.eth.account
filters
contracts
web3.contract
abi_types
middleware
internals
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion docs/web3.eth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1453,7 +1453,7 @@ Contracts
- ``src_map_runtime``
- ``user_doc``

See :doc:`./contracts` for more information about how to use contracts.
See :doc:`web3.contract` for more information about how to use contracts.

.. py:method:: Eth.set_contract_factory(contractFactoryClass)

Expand Down
1 change: 1 addition & 0 deletions newsfragments/2567.breaking.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reorganized contract to contract.py, async_contract.py, base_contract.py and utils.py. In this change there was a small breaking change where the constructor of BaseContractCaller contract_function_class was defaulting to a ContractFunction now there is no default. This was done to seperate the base class from the implementation.
4 changes: 1 addition & 3 deletions tests/core/contracts/test_contract_util_functions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import pytest

from web3._utils.contracts import (
validate_payable,
)
from web3.contract import (
async_parse_block_identifier,
async_parse_block_identifier_int,
parse_block_identifier,
parse_block_identifier_int,
validate_payable,
)
from web3.exceptions import (
BlockNumberOutofRange,
Expand Down
24 changes: 10 additions & 14 deletions tests/core/filtering/test_contract_get_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,10 @@ def test_contract_get_logs_range(
log_entries = list(contract.events.LogNoArguments.get_logs())
assert len(log_entries) == 1

log_entries = list(
contract.events.LogNoArguments.get_logs(from_block=2, to_block=3)
)
log_entries = list(contract.events.LogNoArguments.get_logs(fromBlock=2, toBlock=3))
assert len(log_entries) == 1

log_entries = list(
contract.events.LogNoArguments.get_logs(from_block=1, to_block=2)
)
log_entries = list(contract.events.LogNoArguments.get_logs(fromBlock=1, toBlock=2))
assert len(log_entries) == 0


Expand All @@ -74,19 +70,19 @@ def test_contract_get_logs_argument_filter(
for txn_hash in txn_hashes:
wait_for_transaction(w3, txn_hash)

all_logs = contract.events.LogTripleWithIndex.get_logs(from_block=1)
all_logs = contract.events.LogTripleWithIndex.get_logs(fromBlock=1)
assert len(all_logs) == 4

# Filter all entries where arg1 in (1, 2)
partial_logs = contract.events.LogTripleWithIndex.get_logs(
from_block=1,
fromBlock=1,
argument_filters={"arg1": [1, 2]},
)
assert len(partial_logs) == 2

# Filter all entries where arg0 == 1
partial_logs = contract.events.LogTripleWithIndex.get_logs(
from_block=1,
fromBlock=1,
argument_filters={"arg0": 1},
)
assert len(partial_logs) == 4
Expand Down Expand Up @@ -146,13 +142,13 @@ async def test_async_contract_get_logs_range(
assert len(log_entries) == 1

contract_logs = await contract.events.LogNoArguments.get_logs(
from_block=2, to_block=3
fromBlock=2, toBlock=3
)
log_entries = list(contract_logs)
assert len(log_entries) == 1

contract_logs = await contract.events.LogNoArguments.get_logs(
from_block=1, to_block=2
fromBlock=1, toBlock=2
)
log_entries = list(contract_logs)
assert len(log_entries) == 0
Expand Down Expand Up @@ -185,19 +181,19 @@ async def test_async_contract_get_logs_argument_filter(
for txn_hash in txn_hashes:
await async_wait_for_transaction(async_w3, txn_hash)

all_logs = await contract.events.LogTripleWithIndex.get_logs(from_block=1)
all_logs = await contract.events.LogTripleWithIndex.get_logs(fromBlock=1)
assert len(all_logs) == 4

# Filter all entries where arg1 in (1, 2)
partial_logs = await contract.events.LogTripleWithIndex.get_logs(
from_block=1,
fromBlock=1,
argument_filters={"arg1": [1, 2]},
)
assert len(partial_logs) == 2

# Filter all entries where arg0 == 1
partial_logs = await contract.events.LogTripleWithIndex.get_logs(
from_block=1,
fromBlock=1,
argument_filters={"arg0": 1},
)
assert len(partial_logs) == 4
66 changes: 66 additions & 0 deletions web3/_utils/contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
map_abi_data,
merge_args_and_kwargs,
)
from web3._utils.blocks import (
is_hex_encoded_block_hash,
)
from web3._utils.encoding import (
to_hex,
)
Expand All @@ -65,12 +68,15 @@
abi_string_to_text,
)
from web3.exceptions import (
BlockNumberOutofRange,
Web3ValidationError,
)
from web3.types import (
ABI,
ABIEvent,
ABIFunction,
BlockIdentifier,
BlockNumber,
TxParams,
)

Expand Down Expand Up @@ -374,3 +380,63 @@ def _get_argument_readable_type(arg: Any) -> str:
return "address"

return arg.__class__.__name__


def parse_block_identifier(
w3: "Web3", block_identifier: BlockIdentifier
) -> BlockIdentifier:
if block_identifier is None:
return w3.eth.default_block
if isinstance(block_identifier, int):
return parse_block_identifier_int(w3, block_identifier)
elif block_identifier in ["latest", "earliest", "pending", "safe", "finalized"]:
return block_identifier
elif isinstance(block_identifier, bytes) or is_hex_encoded_block_hash(
block_identifier
):
return w3.eth.get_block(block_identifier)["number"]
else:
raise BlockNumberOutofRange


def parse_block_identifier_int(w3: "Web3", block_identifier_int: int) -> BlockNumber:
if block_identifier_int >= 0:
block_num = block_identifier_int
else:
last_block = w3.eth.get_block("latest")["number"]
block_num = last_block + block_identifier_int + 1
if block_num < 0:
raise BlockNumberOutofRange
return BlockNumber(block_num)


async def async_parse_block_identifier(
w3: "Web3", block_identifier: BlockIdentifier
) -> BlockIdentifier:
if block_identifier is None:
return w3.eth.default_block
if isinstance(block_identifier, int):
return await async_parse_block_identifier_int(w3, block_identifier)
elif block_identifier in ["latest", "earliest", "pending", "safe", "finalized"]:
return block_identifier
elif isinstance(block_identifier, bytes) or is_hex_encoded_block_hash(
block_identifier
):
requested_block = await w3.eth.get_block(block_identifier) # type: ignore
return requested_block["number"]
else:
raise BlockNumberOutofRange


async def async_parse_block_identifier_int(
w3: "Web3", block_identifier_int: int
) -> BlockNumber:
if block_identifier_int >= 0:
block_num = block_identifier_int
else:
last_block = await w3.eth.get_block("latest") # type: ignore
last_block_num = last_block.number
block_num = last_block_num + block_identifier_int + 1
if block_num < 0:
raise BlockNumberOutofRange
return BlockNumber(block_num)
Loading