Skip to content

Commit

Permalink
Merge pull request #2982 from pacrob/test-for-default-middlewares
Browse files Browse the repository at this point in the history
Remove middlewares marked for deletion
  • Loading branch information
reedsa committed Jun 15, 2023
2 parents a90b963 + 09997fa commit f3834ef
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 40 deletions.
7 changes: 0 additions & 7 deletions docs/internals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,6 @@ function be called. For example, if you were writing a middleware which cached
responses for certain methods your middleware would likely not call the
``make_request`` method, but instead get the response from some local cache.

By default, Web3 will use the ``web3.middleware.pythonic_middleware``. This
middleware performs the following translations for requests and responses.

* Numeric request parameters will be converted to their hexadecimal representation
* Numeric responses will be converted from their hexadecimal representations to
their integer representations.

The ``RequestManager`` object exposes the ``middleware_onion`` object to manage middlewares. It
is also exposed on the ``Web3`` object for convenience. That API is detailed in
:ref:`Modifying_Middleware`.
Expand Down
73 changes: 48 additions & 25 deletions docs/middleware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,26 @@ More information is available in the "Internals: :ref:`internals__middlewares`"
Default Middleware
------------------

Some middlewares are added by default if you do not supply any. The defaults
are likely to change regularly, so this list may not include the latest version's defaults.
You can find the latest defaults in the constructor in ``web3/manager.py``
Middlewares are added by default if you don't add any.

Sync middlewares include:

* ``gas_price_strategy``
* ``name_to_address``
* ``attrdict``
* ``validation``
* ``abi``
* ``gas_estimate``

Async middlewares include:

* ``gas_price_strategy``
* ``attrdict``
* ``validation``
* ``gas_estimate``

The defaults are found in ``default_middlewares`` and ``async_default_middlewares``
methods in ``web3/manager.py``.

AttributeDict
~~~~~~~~~~~~~
Expand Down Expand Up @@ -59,15 +76,6 @@ AttributeDict
(where the ENS contract is deployed), for all other cases will result in an
``InvalidAddress`` error

Pythonic
~~~~~~~~~~~~

.. py:method:: web3.middleware.pythonic_middleware
This converts arguments and returned values to python primitives,
where appropriate. For example, it converts the raw hex string returned by the RPC call
``eth_blockNumber`` into an ``int``.

Gas Price Strategy
~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -105,6 +113,15 @@ HTTPRequestRetry
methods to be retried in order to not resend transactions, excluded methods are:
``eth_sendTransaction``, ``personal_signAndSendTransaction``, ``personal_sendTransaction``.

Validation
~~~~~~~~~~~~~~~~~~~~~~~~

.. py:method:: web3.middleware.validation_middleware
web3.middleware.async_validation_middleware
This middleware includes block and transaction validators which perform validations
for transaction parameters.

.. _Modifying_Middleware:

Configuring Middleware
Expand Down Expand Up @@ -198,9 +215,12 @@ To add or remove items in different layers, use the following API:
.. code-block:: python
>>> w3 = Web3(...)
>>> w3.middleware_onion.add(web3.middleware.pythonic_middleware)
>>> w3.middleware_onion.add(web3.middleware.gas_price_strategy_middleware)
# or
>>> w3.middleware_onion.add(web3.middleware.gas_price_strategy_middleware, 'gas_price_strategy')
# or
>>> w3.middleware_onion.add(web3.middleware.pythonic_middleware, 'pythonic')
>>> async_w3 = AsyncWeb3(...)
>>> async_w3.middleware_onion.add(web3.middleware.async_gas_price_strategy_middleware, 'gas_price_strategy')
.. py:method:: Web3.middleware_onion.inject(middleware, name=None, layer=None)
Expand All @@ -212,11 +232,14 @@ To add or remove items in different layers, use the following API:

.. code-block:: python
# Either of these will put the pythonic middleware at the innermost layer
# Either of these will put the gas_price_strategy middleware at the innermost layer
>>> w3 = Web3(...)
>>> w3.middleware_onion.inject(web3.middleware.pythonic_middleware, layer=0)
>>> w3.middleware_onion.inject(web3.middleware.gas_price_strategy_middleware, layer=0)
# or
>>> w3.middleware_onion.inject(web3.middleware.gas_price_strategy_middleware, 'gas_price_strategy', layer=0)
# or
>>> w3.middleware_onion.inject(web3.middleware.pythonic_middleware, 'pythonic', layer=0)
>>> async_w3 = AsyncWeb3(...)
>>> async_w3.middleware_onion.inject(web3.middleware.async_gas_price_strategy_middleware, 'gas_price_strategy', layer=0)
.. py:method:: Web3.middleware_onion.remove(middleware)
Expand All @@ -227,9 +250,9 @@ To add or remove items in different layers, use the following API:
.. code-block:: python
>>> w3 = Web3(...)
>>> w3.middleware_onion.remove(web3.middleware.pythonic_middleware)
>>> w3.middleware_onion.remove(web3.middleware.gas_price_strategy_middleware)
# or
>>> w3.middleware_onion.remove('pythonic')
>>> w3.middleware_onion.remove('gas_price_strategy')
.. py:method:: Web3.middleware_onion.replace(old_middleware, new_middleware)
Expand All @@ -239,18 +262,18 @@ To add or remove items in different layers, use the following API:

.. code-block:: python
>>> from web3.middleware import pythonic_middleware, attrdict_middleware
>>> from web3.middleware import gas_price_strategy_middleware, attrdict_middleware
>>> w3 = Web3(...)
>>> w3.middleware_onion.replace(pythonic_middleware, attrdict_middleware)
>>> w3.middleware_onion.replace(gas_price_strategy_middleware, attrdict_middleware)
# this is now referenced by the new middleware object, so to remove it:
>>> w3.middleware_onion.remove(attrdict_middleware)
# or, if it was named
>>> w3.middleware_onion.replace('pythonic', attrdict_middleware)
>>> w3.middleware_onion.replace('gas_price_strategy', attrdict_middleware)
# this is still referenced by the original name, so to remove it:
>>> w3.middleware_onion.remove('pythonic')
>>> w3.middleware_onion.remove('gas_price_strategy')
.. py:method:: Web3.middleware_onion.clear()
Expand All @@ -271,7 +294,7 @@ To add or remove items in different layers, use the following API:
>>> w3_1 = Web3(...)
# add uniquely named middleware:
>>> w3_1.middleware_onion.add(web3.middleware.pythonic_middleware, 'test_middleware')
>>> w3_1.middleware_onion.add(web3.middleware.gas_price_strategy_middleware, 'test_middleware')
# export middlewares from first w3 instance
>>> middlewares = w3_1.middleware_onion.middlewares
Expand Down Expand Up @@ -437,7 +460,7 @@ errors like the example below when interacting with your EVM node.
.. code-block:: shell
web3.exceptions.ExtraDataLengthError: The field extraData is 97 bytes, but should be
32. It is quite likely that you are connected to a POA chain. Refer to
1. It is quite likely that you are connected to a POA chain. Refer to
http://web3py.readthedocs.io/en/stable/middleware.html#proof-of-authority
for more details. The full extraData is: HexBytes('...')
Expand Down
1 change: 1 addition & 0 deletions newsfragments/2972.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removed references to deprecated middlewares with new tests to check default middlewares
47 changes: 47 additions & 0 deletions tests/core/manager/test_default_middlewares.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from web3.manager import (
RequestManager,
)
from web3.middleware import (
abi_middleware,
async_attrdict_middleware,
async_buffered_gas_estimate_middleware,
async_gas_price_strategy_middleware,
async_validation_middleware,
attrdict_middleware,
buffered_gas_estimate_middleware,
gas_price_strategy_middleware,
name_to_address_middleware,
validation_middleware,
)


def test_default_sync_middlwares(w3):
expected_middlewares = [
(gas_price_strategy_middleware, "gas_price_strategy"),
(name_to_address_middleware(w3), "name_to_address"),
(attrdict_middleware, "attrdict"),
(validation_middleware, "validation"),
(abi_middleware, "abi"),
(buffered_gas_estimate_middleware, "gas_estimate"),
]

default_middlewares = RequestManager.default_middlewares(w3)

for x in range(len(default_middlewares)):
assert default_middlewares[x][0].__name__ == expected_middlewares[x][0].__name__
assert default_middlewares[x][1] == expected_middlewares[x][1]


def test_default_async_middlwares():
expected_middlewares = [
(async_gas_price_strategy_middleware, "gas_price_strategy"),
(async_attrdict_middleware, "attrdict"),
(async_validation_middleware, "validation"),
(async_buffered_gas_estimate_middleware, "gas_estimate"),
]

default_middlewares = RequestManager.async_default_middlewares()

for x in range(len(default_middlewares)):
assert default_middlewares[x][0].__name__ == expected_middlewares[x][0].__name__
assert default_middlewares[x][1] == expected_middlewares[x][1]
56 changes: 56 additions & 0 deletions tests/core/providers/test_http_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,29 @@
from web3._utils import (
request,
)
from web3.eth import (
Eth,
)
from web3.exceptions import (
ProviderConnectionError,
)
from web3.geth import (
Geth,
GethAdmin,
GethPersonal,
GethTxPool,
)
from web3.middleware import (
abi_middleware,
attrdict_middleware,
buffered_gas_estimate_middleware,
gas_price_strategy_middleware,
name_to_address_middleware,
validation_middleware,
)
from web3.net import (
Net,
)
from web3.providers import (
HTTPProvider,
)
Expand All @@ -39,6 +59,42 @@ def test_init_kwargs():
assert w3.manager.provider == provider


def test_web3_with_http_provider_has_default_middlewares_and_modules() -> None:
adapter = HTTPAdapter(pool_connections=20, pool_maxsize=20)
session = Session()
session.mount("http://", adapter)
session.mount("https://", adapter)

provider = HTTPProvider(endpoint_uri=URI, session=session)
w3 = Web3(provider)

# assert default modules
assert isinstance(w3.eth, Eth)
assert isinstance(w3.net, Net)
assert isinstance(w3.geth, Geth)
assert isinstance(w3.geth.admin, GethAdmin)
assert isinstance(w3.geth.personal, GethPersonal)
assert isinstance(w3.geth.txpool, GethTxPool)

# assert default middleware

# the following length check should fail and will need to be added to once more
# middlewares are added to the defaults
assert len(w3.middleware_onion.middlewares) == 6

assert (
w3.middleware_onion.get("gas_price_strategy") == gas_price_strategy_middleware
)
assert (
w3.middleware_onion.get("name_to_address").__name__
== name_to_address_middleware(w3).__name__
)
assert w3.middleware_onion.get("attrdict") == attrdict_middleware
assert w3.middleware_onion.get("validation") == validation_middleware
assert w3.middleware_onion.get("gas_estimate") == buffered_gas_estimate_middleware
assert w3.middleware_onion.get("abi") == abi_middleware


def test_user_provided_session():
adapter = HTTPAdapter(pool_connections=20, pool_maxsize=20)
session = Session()
Expand Down
4 changes: 2 additions & 2 deletions tests/ens/test_ens.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
)
from web3.middleware import (
async_validation_middleware,
pythonic_middleware,
gas_price_strategy_middleware,
)
from web3.providers.eth_tester import (
AsyncEthereumTesterProvider,
)


def test_from_web3_inherits_web3_middlewares(w3):
test_middleware = pythonic_middleware
test_middleware = gas_price_strategy_middleware
w3.middleware_onion.add(test_middleware, "test_middleware")

ns = ENS.from_web3(w3)
Expand Down
10 changes: 4 additions & 6 deletions web3/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
buffered_gas_estimate_middleware,
gas_price_strategy_middleware,
name_to_address_middleware,
pythonic_middleware,
request_parameter_normalizer,
validation_middleware,
)
from web3.providers import (
Expand Down Expand Up @@ -136,23 +134,23 @@ def provider(self, provider: Union["BaseProvider", "AsyncBaseProvider"]) -> None
def default_middlewares(w3: "Web3") -> List[Tuple[Middleware, str]]:
"""
List the default middlewares for the request manager.
Leaving ens unspecified will prevent the middleware from resolving names.
Leaving w3 unspecified will prevent the middleware from resolving names.
Documentation should remain in sync with these defaults.
"""
return [
(request_parameter_normalizer, "request_param_normalizer"), # Delete
(gas_price_strategy_middleware, "gas_price_strategy"),
(name_to_address_middleware(w3), "name_to_address"), # Add Async
(attrdict_middleware, "attrdict"),
(pythonic_middleware, "pythonic"), # Delete
(validation_middleware, "validation"),
(abi_middleware, "abi"), # Delete
(abi_middleware, "abi"),
(buffered_gas_estimate_middleware, "gas_estimate"),
]

@staticmethod
def async_default_middlewares() -> List[Tuple[AsyncMiddleware, str]]:
"""
List the default async middlewares for the request manager.
Documentation should remain in sync with these defaults.
"""
return [
(async_gas_price_strategy_middleware, "gas_price_strategy"),
Expand Down

0 comments on commit f3834ef

Please sign in to comment.