Skip to content

Commit 93a7af5

Browse files
pacrobbanteg
andauthored
Decode tuples per abi (#2799)
* add decode_tuples option to contract creation * use new `named_tree` func to parse event info in `decode_transaction_data` --------- Co-authored-by: banteg <[email protected]>
1 parent cb48514 commit 93a7af5

16 files changed

+802
-71
lines changed

docs/web3.contract.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,29 @@ Each Contract Factory exposes the following properties.
146146
The runtime part of the contract bytecode string. May be ``None`` if not
147147
provided during factory creation.
148148

149+
150+
.. py:attribute:: Contract.decode_tuples
151+
152+
If a Tuple/Struct is returned by a contract function, this flag defines whether
153+
to apply the field names from the ABI to the returned data.
154+
If False, the returned value will be a normal Python `Tuple`. If True, the returned
155+
value will be a Python `NamedTuple` of the class `ABIDecodedNamedTuple`.
156+
157+
NamedTuples have some restrictions regarding field names.
158+
web3.py sets `NamedTuple`'s `rename=True`, so disallowed field names may be
159+
different than expected. See the [Python docs](https://docs.python.org/3/library/collections.html#collections.namedtuple)
160+
for more information.
161+
162+
Defaults to ``False`` if not provided during factory creation.
163+
164+
149165
.. py:attribute:: Contract.functions
150166
151167
This provides access to contract functions as attributes. For example:
152168
``myContract.functions.MyMethod()``. The exposed contract functions are classes of the
153169
type :py:class:`ContractFunction`.
154170

171+
155172
.. py:attribute:: Contract.events
156173
157174
This provides access to contract events as attributes. For example:

docs/web3.eth.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,7 @@ Contracts
14541454
- ``bytecode_runtime``
14551455
- ``clone_bin``
14561456
- ``dev_doc``
1457+
- ``decode_tuples``
14571458
- ``interface``
14581459
- ``metadata``
14591460
- ``opcodes``

newsfragments/2799.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add decode_tuples option to contract instantiation

tests/core/contracts/conftest.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
from web3._utils.contract_sources.contract_data.string_contract import (
5151
STRING_CONTRACT_DATA,
5252
)
53+
from web3._utils.contract_sources.contract_data.tuple_contracts import (
54+
NESTED_TUPLE_CONTRACT_DATA,
55+
TUPLE_CONTRACT_DATA,
56+
)
5357

5458

5559
@pytest.fixture(scope="session")
@@ -340,6 +344,44 @@ def revert_contract(w3, address_conversion_func):
340344
return deploy(w3, revert_contract_factory, address_conversion_func)
341345

342346

347+
@pytest.fixture
348+
def tuple_contract(w3, address_conversion_func):
349+
tuple_contract_factory = w3.eth.contract(**TUPLE_CONTRACT_DATA)
350+
return deploy(w3, tuple_contract_factory, address_conversion_func)
351+
352+
353+
@pytest.fixture
354+
def nested_tuple_contract(w3, address_conversion_func):
355+
nested_tuple_contract_factory = w3.eth.contract(**NESTED_TUPLE_CONTRACT_DATA)
356+
return deploy(w3, nested_tuple_contract_factory, address_conversion_func)
357+
358+
359+
TUPLE_CONTRACT_DATA_DECODE_TUPLES = {
360+
**TUPLE_CONTRACT_DATA,
361+
"decode_tuples": True,
362+
}
363+
364+
365+
NESTED_TUPLE_CONTRACT_DATA_DECODE_TUPLES = {
366+
**NESTED_TUPLE_CONTRACT_DATA,
367+
"decode_tuples": True,
368+
}
369+
370+
371+
@pytest.fixture
372+
def tuple_contract_with_decode_tuples(w3, address_conversion_func):
373+
tuple_contract_factory = w3.eth.contract(**TUPLE_CONTRACT_DATA_DECODE_TUPLES)
374+
return deploy(w3, tuple_contract_factory, address_conversion_func)
375+
376+
377+
@pytest.fixture
378+
def nested_tuple_contract_with_decode_tuples(w3, address_conversion_func):
379+
nested_tuple_contract_factory = w3.eth.contract(
380+
**NESTED_TUPLE_CONTRACT_DATA_DECODE_TUPLES
381+
)
382+
return deploy(w3, nested_tuple_contract_factory, address_conversion_func)
383+
384+
343385
@pytest.fixture
344386
def some_address(address_conversion_func):
345387
return address_conversion_func("0x5B2063246F2191f18F2675ceDB8b28102e957458")
@@ -563,6 +605,46 @@ async def async_revert_contract(async_w3, address_conversion_func):
563605
)
564606

565607

608+
@pytest_asyncio.fixture
609+
async def async_tuple_contract(async_w3, address_conversion_func):
610+
async_tuple_contract_factory = async_w3.eth.contract(**TUPLE_CONTRACT_DATA)
611+
return await async_deploy(
612+
async_w3, async_tuple_contract_factory, address_conversion_func
613+
)
614+
615+
616+
@pytest_asyncio.fixture
617+
async def async_nested_tuple_contract(async_w3, address_conversion_func):
618+
async_nested_tuple_contract_factory = async_w3.eth.contract(
619+
**NESTED_TUPLE_CONTRACT_DATA
620+
)
621+
return await async_deploy(
622+
async_w3, async_nested_tuple_contract_factory, address_conversion_func
623+
)
624+
625+
626+
@pytest_asyncio.fixture
627+
async def async_tuple_contract_with_decode_tuples(async_w3, address_conversion_func):
628+
async_tuple_contract_factory = async_w3.eth.contract(
629+
**TUPLE_CONTRACT_DATA_DECODE_TUPLES
630+
)
631+
return await async_deploy(
632+
async_w3, async_tuple_contract_factory, address_conversion_func
633+
)
634+
635+
636+
@pytest_asyncio.fixture
637+
async def async_nested_tuple_contract_with_decode_tuples(
638+
async_w3, address_conversion_func
639+
):
640+
async_nested_tuple_contract_factory = async_w3.eth.contract(
641+
**NESTED_TUPLE_CONTRACT_DATA_DECODE_TUPLES
642+
)
643+
return await async_deploy(
644+
async_w3, async_nested_tuple_contract_factory, address_conversion_func
645+
)
646+
647+
566648
async def async_invoke_contract(
567649
api_call_desig="call",
568650
contract=None,

0 commit comments

Comments
 (0)