Skip to content

Commit

Permalink
Deprecate processReceipt and createFilter in favor of snake_case (#2876)
Browse files Browse the repository at this point in the history
* Deprecate processReceipt, add process_receipt

* Deprecate and snake_case createFilter

* Add newsfragment
  • Loading branch information
kclowes committed Mar 13, 2023
1 parent dd354d3 commit af9ba32
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 47 deletions.
41 changes: 26 additions & 15 deletions docs/contracts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,9 @@ Each Contract Factory exposes the following methods.
>>> contract_data = token_contract.constructor(web3.eth.coinbase, 12345).build_transaction(transaction)
>>> web3.eth.send_transaction(contract_data)
.. _contract_createFilter:
.. _contract_create_filter:

.. py:classmethod:: Contract.events.your_event_name.createFilter(fromBlock=block, toBlock=block, \
.. py:classmethod:: Contract.events.your_event_name.create_filter(fromBlock=block, toBlock=block, \
argument_filters={"arg1": "value"}, topics=[])
Creates a new event filter, an instance of :py:class:`web3.utils.filters.LogFilter`.
Expand All @@ -313,6 +313,12 @@ Each Contract Factory exposes the following methods.
- ``argument_filters``, optional. Expects a dictionary of argument names and values. When provided event logs are filtered for the event argument values. Event arguments can be both indexed or unindexed. Indexed values with be translated to their corresponding topic arguments. Unindexed arguments will be filtered using a regular expression.
- ``topics`` optional, accepts the standard JSON-RPC topics argument. See the JSON-RPC documentation for `eth_newFilter <https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter>`_ more information on the ``topics`` parameters.

.. py:classmethod:: Contract.events.your_event_name.createFilter(fromBlock=block, toBlock=block, \
argument_filters={"arg1": "value"}, topics=[])
.. warning:: Deprecated: ``createFilter`` has been deprecated in favor of
:ref:`Contract.events.your_event_name.create_filter<contract_create_filter>`

.. py:classmethod:: Contract.events.your_event_name.build_filter()
Creates a EventFilterBuilder instance with the event abi, and the contract address if called from a deployed contract instance. The EventFilterBuilder provides a convenient way to construct the filter parameters with value checking against the event abi. It allows for defining multiple match values or of single values through the match_any and match_single methods.
Expand Down Expand Up @@ -340,7 +346,6 @@ Each Contract Factory exposes the following methods.
filter_builder.fromBlock = "latest"
filter_builder.fromBlock = 0 # raises a ValueError
.. py:classmethod:: Contract.deploy(transaction=None, args=None)
.. warning:: Deprecated: this method is deprecated in favor of
Expand Down Expand Up @@ -968,25 +973,25 @@ For example:
myContract = web3.eth.contract(address=contract_address, abi=contract_abi)
tx_hash = myContract.functions.myFunction().transact()
receipt = web3.eth.get_transaction_receipt(tx_hash)
myContract.events.myEvent().processReceipt(receipt)
myContract.events.myEvent().process_receipt(receipt)
:py:class:`ContractEvent` provides methods to interact with contract events. Positional and keyword arguments supplied to the contract event subclass will be used to find the contract event by signature.

.. _processReceipt:
.. _process_receipt:

.. py:method:: ContractEvents.myEvent(*args, **kwargs).processReceipt(transaction_receipt, errors=WARN)
.. py:method:: ContractEvents.myEvent(*args, **kwargs).process_receipt(transaction_receipt, errors=WARN)
:noindex:

Extracts the pertinent logs from a transaction receipt.

If there are no errors, ``processReceipt`` returns a tuple of :ref:`Event Log Objects <event-log-object>`, emitted from the event (e.g. ``myEvent``),
If there are no errors, ``process_receipt`` returns a tuple of :ref:`Event Log Objects <event-log-object>`, emitted from the event (e.g. ``myEvent``),
with decoded ouput.

.. code-block:: python
>>> tx_hash = contract.functions.myFunction(12345).transact({'to':contract_address})
>>> tx_receipt = w3.eth.get_transaction_receipt(tx_hash)
>>> rich_logs = contract.events.myEvent().processReceipt(tx_receipt)
>>> rich_logs = contract.events.myEvent().process_receipt(tx_receipt)
>>> rich_logs[0]['args']
{'myArg': 12345}
Expand All @@ -1003,7 +1008,7 @@ For example:
>>> tx_hash = contract.functions.myFunction(12345).transact({'to':contract_address})
>>> tx_receipt = w3.eth.get_transaction_receipt(tx_hash)
>>> processed_logs = contract.events.myEvent().processReceipt(tx_receipt)
>>> processed_logs = contract.events.myEvent().process_receipt(tx_receipt)
>>> processed_logs
(
AttributeDict({
Expand All @@ -1021,7 +1026,7 @@ For example:
# Or, if there were errors encountered during processing:
>>> from web3.logs import STRICT, IGNORE, DISCARD, WARN
>>> processed_logs = contract.events.myEvent().processReceipt(tx_receipt, errors=IGNORE)
>>> processed_logs = contract.events.myEvent().process_receipt(tx_receipt, errors=IGNORE)
>>> processed_logs
(
AttributeDict({
Expand All @@ -1039,15 +1044,21 @@ For example:
'errors': LogTopicError('Expected 1 log topics. Got 0')})
})
)
>>> processed_logs = contract.events.myEvent().processReceipt(tx_receipt, errors=DISCARD)
>>> processed_logs = contract.events.myEvent().process_receipt(tx_receipt, errors=DISCARD)
>>> assert processed_logs == ()
True
.. py:method:: ContractEvents.myEvent(*args, **kwargs).processReceipt(transaction_receipt, errors=WARN)
:noindex:

.. warning:: Deprecation: processReceipt is deprecated in favor of
:ref:`ContractEvents.myEvent.process_receipt<process_receipt>`

.. _process_log:

.. py:method:: ContractEvents.myEvent(*args, **kwargs).process_log(log)
Similar to processReceipt_, but only processes one log at a time, instead of a whole transaction receipt.
Similar to process_receipt_, but only processes one log at a time, instead of a whole transaction receipt.
Will return a single :ref:`Event Log Object <event-log-object>` if there are no errors encountered during processing. If an error is encountered during processing, it will be raised.

.. code-block:: python
Expand Down Expand Up @@ -1097,7 +1108,7 @@ Event Log Object
* ``blockNumber``: Number - the block number where this log was in. null
when it's pending.

.. testsetup:: createFilter
.. testsetup:: create_filter

from web3 import Web3
from hexbytes import HexBytes
Expand All @@ -1120,9 +1131,9 @@ Event Log Object
tx_hash = contract.functions.transfer(alice, 10).transact({'gas': 899000, 'gasPrice': Web3.toWei(1, 'gwei')})
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

.. doctest:: createFilter
.. doctest:: create_filter

>>> transfer_filter = my_token_contract.events.Transfer.createFilter(fromBlock="0x0", argument_filters={'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf'})
>>> transfer_filter = my_token_contract.events.Transfer.create_filter(fromBlock="0x0", argument_filters={'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf'})
>>> transfer_filter.get_new_entries()
[AttributeDict({'args': AttributeDict({'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',
'to': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',
Expand Down
2 changes: 1 addition & 1 deletion docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ The script can be run with: ``python ./eventscanner.py <your JSON-RPC API URL>``
This method is detached from any contract instance.
This is a stateless method, as opposed to createFilter.
This is a stateless method, as opposed to create_filter.
It can be safely called against nodes which do not provide `eth_newFilter` API, like Infura.
"""
Expand Down
8 changes: 4 additions & 4 deletions docs/filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The :meth:`web3.eth.Eth.filter` method can be used to set up filters for:

.. code-block:: python
event_filter = mycontract.events.myEvent.createFilter(fromBlock='latest', argument_filters={'arg1':10})
event_filter = mycontract.events.myEvent.create_filter(fromBlock='latest', argument_filters={'arg1':10})
Or built manually by supplying `valid filter params <https://github.com/ethereum/execution-apis/blob/bea0266c42919a2fb3ee524fb91e624a23bc17c5/src/schemas/filter.json#L28>`_:

Expand Down Expand Up @@ -129,15 +129,15 @@ Event Log Filters
-----------------

You can set up a filter for event logs using the web3.py contract api:
:meth:`web3.contract.Contract.events.your_event_name.createFilter`, which provides some conveniences for
:meth:`web3.contract.Contract.events.your_event_name.create_filter`, which provides some conveniences for
creating event log filters. Refer to the following example:

.. code-block:: python
event_filter = myContract.events.<event_name>.createFilter(fromBlock="latest", argument_filters={'arg1':10})
event_filter = myContract.events.<event_name>.create_filter(fromBlock="latest", argument_filters={'arg1':10})
event_filter.get_new_entries()
See :meth:`web3.contract.Contract.events.your_event_name.createFilter()` documentation for more information.
See :meth:`web3.contract.Contract.events.your_event_name.create_filter()` documentation for more information.

You can set up an event log filter like the one above with ``web3.eth.filter`` by supplying a
dictionary containing the standard filter parameters. Assuming that ``arg1`` is indexed, the
Expand Down
4 changes: 2 additions & 2 deletions docs/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ a contract, you can leverage Web3.py filters.
>>> new_filter = web3.eth.filter('latest')
# Use case: filter for contract event "MyEvent"
>>> new_filter = deployed_contract.events.MyEvent.createFilter(fromBlock='latest')
>>> new_filter = deployed_contract.events.MyEvent.create_filter(fromBlock='latest')
# retrieve filter results:
>>> new_filter.get_all_entries()
Expand All @@ -285,7 +285,7 @@ API
- :meth:`web3.eth.get_filter_logs() <web3.eth.Eth.get_filter_logs>`
- :meth:`web3.eth.uninstall_filter() <web3.eth.Eth.uninstall_filter>`
- :meth:`web3.eth.get_logs() <web3.eth.Eth.get_logs>`
- :meth:`Contract.events.your_event_name.createFilter() <web3.contract.Contract.events.your_event_name.createFilter>`
- :meth:`Contract.events.your_event_name.create_filter() <web3.contract.Contract.events.your_event_name.create_filter>`
- :meth:`Contract.events.your_event_name.build_filter() <web3.contract.Contract.events.your_event_name.build_filter>`
- :meth:`Filter.get_new_entries() <web3.utils.filters.Filter.get_new_entries>`
- :meth:`Filter.get_all_entries() <web3.utils.filters.Filter.get_all_entries>`
Expand Down
2 changes: 1 addition & 1 deletion docs/releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2183,7 +2183,7 @@ Released Mar 27, 2018
until a third-party audit is complete & resolved.
- New API for contract deployment, which enables gas estimation, local signing, etc.
See :meth:`~web3.contract.Contract.constructor`.
- Find contract events with :ref:`contract.events.$my_event.createFilter() <contract_createFilter>`
- Find contract events with :ref:`contract.events.$my_event.createFilter() <contract_create_filter>`
- Support auto-complete for contract methods.
- Upgrade most dependencies to stable

Expand Down
1 change: 1 addition & 0 deletions newsfragments/2876.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deprecate createFilter and processReceipt, in favor of create_filter and process_receipt
52 changes: 42 additions & 10 deletions tests/core/contracts/test_extracting_event_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ def test_event_rich_log(
event_instance = emitter.events[event_name]()

if process_receipt:
processed_logs = event_instance.processReceipt(txn_receipt)
processed_logs = event_instance.process_receipt(txn_receipt)
assert len(processed_logs) == 1
rich_log = processed_logs[0]
elif not process_receipt:
Expand All @@ -620,7 +620,7 @@ def test_event_rich_log(

quiet_event = emitter.events['LogBytes']
with pytest.warns(UserWarning, match=warning_msg):
empty_rich_log = quiet_event().processReceipt(txn_receipt)
empty_rich_log = quiet_event().process_receipt(txn_receipt)
assert empty_rich_log == tuple()


Expand All @@ -638,7 +638,7 @@ def test_event_rich_log_with_byte_args(
event_instance = emitter.events.LogListArgs()

if process_receipt:
processed_logs = event_instance.processReceipt(txn_receipt)
processed_logs = event_instance.process_receipt(txn_receipt)
assert len(processed_logs) == 1
rich_log = processed_logs[0]
elif not process_receipt:
Expand Down Expand Up @@ -670,7 +670,7 @@ def test_receipt_processing_with_discard_flag(

event_instance = indexed_event_contract.events.LogSingleWithIndex()

returned_logs = event_instance.processReceipt(dup_txn_receipt, errors=DISCARD)
returned_logs = event_instance.process_receipt(dup_txn_receipt, errors=DISCARD)
assert returned_logs == ()


Expand All @@ -682,7 +682,7 @@ def test_receipt_processing_with_ignore_flag(
wait_for_transaction):

event_instance = indexed_event_contract.events.LogSingleWithIndex()
returned_logs = event_instance.processReceipt(dup_txn_receipt, errors=IGNORE)
returned_logs = event_instance.process_receipt(dup_txn_receipt, errors=IGNORE)
assert len(returned_logs) == 2

# Check that the correct error is appended to the log
Expand Down Expand Up @@ -711,7 +711,7 @@ def test_receipt_processing_with_warn_flag(
event_instance = indexed_event_contract.events.LogSingleWithIndex()

with pytest.warns(UserWarning, match='Expected 1 log topics. Got 0'):
returned_logs = event_instance.processReceipt(dup_txn_receipt, errors=WARN)
returned_logs = event_instance.process_receipt(dup_txn_receipt, errors=WARN)
assert len(returned_logs) == 0


Expand All @@ -723,7 +723,7 @@ def test_receipt_processing_with_strict_flag(
event_instance = indexed_event_contract.events.LogSingleWithIndex()

with pytest.raises(LogTopicError, match="Expected 1 log topics. Got 0"):
event_instance.processReceipt(dup_txn_receipt, errors=STRICT)
event_instance.process_receipt(dup_txn_receipt, errors=STRICT)


def test_receipt_processing_with_invalid_flag(
Expand All @@ -734,7 +734,7 @@ def test_receipt_processing_with_invalid_flag(
event_instance = indexed_event_contract.events.LogSingleWithIndex()

with pytest.raises(AttributeError, match="Error flag must be one of: "):
event_instance.processReceipt(dup_txn_receipt, errors='not-a-flag')
event_instance.process_receipt(dup_txn_receipt, errors='not-a-flag')


def test_receipt_processing_with_no_flag(
Expand All @@ -745,7 +745,7 @@ def test_receipt_processing_with_no_flag(
event_instance = indexed_event_contract.events.LogSingleWithIndex()

with pytest.warns(UserWarning, match='Expected 1 log topics. Got 0'):
returned_log = event_instance.processReceipt(dup_txn_receipt)
returned_log = event_instance.process_receipt(dup_txn_receipt)
assert len(returned_log) == 0


Expand All @@ -760,7 +760,7 @@ def test_single_log_processing_with_errors(


def test_get_all_entries_with_nested_tuple_event(web3, emitter):
struct_args_filter = emitter.events.LogStructArgs.createFilter(fromBlock=0)
struct_args_filter = emitter.events.LogStructArgs.create_filter(fromBlock=0)

tx_hash = emitter.functions.logStruct(1, (2, 3, (4, ))).transact({'gas': 100000})
web3.eth.wait_for_transaction_receipt(tx_hash)
Expand Down Expand Up @@ -814,3 +814,35 @@ def test_processLog_is_deprecated(
assert rich_log['transactionIndex'] == txn_receipt['transactionIndex']
assert is_same_address(rich_log['address'], emitter.address)
assert rich_log['event'] == 'LogListArgs'


def test_processReceipt_emits_deprecation_warning(
web3,
emitter,
wait_for_transaction):

txn_hash = emitter.functions.logListArgs([b'13'], [b'54']).transact()
txn_receipt = wait_for_transaction(web3, txn_hash)

event_instance = emitter.events.LogListArgs()

with pytest.warns(
DeprecationWarning,
match='processReceipt is deprecated in favor of process_receipt'
):
processed_logs = event_instance.processReceipt(txn_receipt)
assert len(processed_logs) == 1
rich_log = processed_logs[0]
expected_args = {
'arg0': b'H\x7f\xad\xb3\x16zAS7\xa5\x0c\xfe\xe2%T\xb7\x17\x81p\xf04~\x8d(\x93\x8e\x19\x97k\xd9"1', # noqa: E501
'arg1': [b'54']
}
assert rich_log['args'] == expected_args
assert rich_log.args == expected_args
for arg in expected_args:
assert getattr(rich_log.args, arg) == expected_args[arg]
assert rich_log['blockHash'] == txn_receipt['blockHash']
assert rich_log['blockNumber'] == txn_receipt['blockNumber']
assert rich_log['transactionIndex'] == txn_receipt['transactionIndex']
assert is_same_address(rich_log['address'], emitter.address)
assert rich_log['event'] == 'LogListArgs'
2 changes: 1 addition & 1 deletion tests/core/filtering/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def return_filter(
kwargs = apply_key_map({'filter': 'argument_filters'}, args[1])
if 'fromBlock' not in kwargs:
kwargs['fromBlock'] = 'latest'
return contract.events[event_name].createFilter(**kwargs)
return contract.events[event_name].create_filter(**kwargs)


@pytest.fixture(scope="module")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def test_merged_topic_list_event(
'0x0000000000000000000000000000000000000000000000000000000000000457', # 1111
]
with pytest.raises(TypeError):
emitter.events.LogTripleWithIndex().createFilter(
emitter.events.LogTripleWithIndex().create_filter(
fromBlock="latest",
topics=manual_topics,
argument_filters={'arg0': 2222, 'arg1': 2222, 'arg2': 2222})

0 comments on commit af9ba32

Please sign in to comment.