From 62366e97083db4daf0bce521a166f34a8b753df5 Mon Sep 17 00:00:00 2001 From: fselmo Date: Wed, 19 Jul 2023 13:13:32 -0600 Subject: [PATCH] Changes since PR #3048 was put up for review - Add web3.providers.websocket.rst to .gitignore - Put back formatters for eth_getCode / remove unnecessary ``compose()`` - Add read-friendly comment splitting Web3 from AsyncWeb3 in main.py - Use correct class name in docstring - Friendlier message when exception is raised connecting to websocket endpoint - Friendlier message for websocket restricted_kwargs; use a merge of default + provided websocket_kwargs with the provided values taking precedence - Validate "ws://" / "wss://" in websocket endpoint - Use Dict[str, Any] for websocket_kwargs type --- .gitignore | 1 + docs/web3.providers.websocket.rst | 29 -------------------- web3/_utils/method_formatters.py | 2 +- web3/main.py | 5 +++- web3/providers/websocket/websocket_v2.py | 34 ++++++++++++++++++------ 5 files changed, 32 insertions(+), 39 deletions(-) delete mode 100644 docs/web3.providers.websocket.rst diff --git a/.gitignore b/.gitignore index 359068dc2d..ed1b949468 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ docs/web3.gas_strategies.rst docs/web3.middleware.rst docs/web3.providers.eth_tester.rst docs/web3.providers.rst +docs/web3.providers.websocket.rst docs/web3.rst docs/web3.scripts.release.rst docs/web3.scripts.rst diff --git a/docs/web3.providers.websocket.rst b/docs/web3.providers.websocket.rst deleted file mode 100644 index 07bfddd034..0000000000 --- a/docs/web3.providers.websocket.rst +++ /dev/null @@ -1,29 +0,0 @@ -web3.providers.websocket package -================================ - -Submodules ----------- - -web3.providers.websocket.websocket module ------------------------------------------ - -.. automodule:: web3.providers.websocket.websocket - :members: - :undoc-members: - :show-inheritance: - -web3.providers.websocket.websocket\_v2 module ---------------------------------------------- - -.. automodule:: web3.providers.websocket.websocket_v2 - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: web3.providers.websocket - :members: - :undoc-members: - :show-inheritance: diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py index e6b8d3ab31..156be338d4 100644 --- a/web3/_utils/method_formatters.py +++ b/web3/_utils/method_formatters.py @@ -484,7 +484,7 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]: to_hex_if_integer, 0, ), - RPC.eth_getCode: compose(apply_formatter_at_index(to_hex_if_integer, 1)), + RPC.eth_getCode: apply_formatter_at_index(to_hex_if_integer, 1), RPC.eth_getStorageAt: apply_formatter_at_index(to_hex_if_integer, 2), RPC.eth_getTransactionByBlockNumberAndIndex: compose( apply_formatter_at_index(to_hex_if_integer, 0), diff --git a/web3/main.py b/web3/main.py index 5fc079a3f9..2330c8fc32 100644 --- a/web3/main.py +++ b/web3/main.py @@ -430,6 +430,9 @@ def ens(self, new_ens: Union[ENS, "Empty"]) -> None: self._ens = new_ens +# -- async -- # + + class AsyncWeb3(BaseWeb3): # mypy Types eth: AsyncEth @@ -505,7 +508,7 @@ def persistent_websocket( ) -> "_PersistentConnectionWeb3": """ Establish a persistent connection via websockets to a websocket provider using - a WebsocketProviderV2 instance. + a ``PersistentConnectionProvider`` instance. """ return _PersistentConnectionWeb3( provider, diff --git a/web3/providers/websocket/websocket_v2.py b/web3/providers/websocket/websocket_v2.py index 0cde0851ca..fc4ad70e51 100644 --- a/web3/providers/websocket/websocket_v2.py +++ b/web3/providers/websocket/websocket_v2.py @@ -3,6 +3,7 @@ import os from typing import ( Any, + Dict, Optional, Union, ) @@ -10,6 +11,9 @@ from eth_typing import ( URI, ) +from toolz import ( + merge, +) from websockets.client import ( connect, ) @@ -31,6 +35,7 @@ DEFAULT_PING_INTERVAL = 30 # 30 seconds DEFAULT_PING_TIMEOUT = 300 # 5 minutes +VALID_WEBSOCKET_URI_PREFIXES = {"ws://", "wss://"} RESTRICTED_WEBSOCKET_KWARGS = {"uri", "loop"} DEFAULT_WEBSOCKET_KWARGS = { # set how long to wait between pings from the server @@ -51,26 +56,34 @@ class WebsocketProviderV2(PersistentConnectionProvider): def __init__( self, endpoint_uri: Optional[Union[URI, str]] = None, - websocket_kwargs: Optional[Any] = None, + websocket_kwargs: Optional[Dict[str, Any]] = None, call_timeout: Optional[int] = None, ) -> None: self.endpoint_uri = URI(endpoint_uri) if self.endpoint_uri is None: self.endpoint_uri = get_default_endpoint() - if websocket_kwargs is None: - websocket_kwargs = DEFAULT_WEBSOCKET_KWARGS - else: + if not any( + self.endpoint_uri.startswith(prefix) + for prefix in VALID_WEBSOCKET_URI_PREFIXES + ): + raise Web3ValidationError( + f"Websocket endpoint uri must begin with 'ws://' or 'wss://': " + f"{self.endpoint_uri}" + ) + + if websocket_kwargs is not None: found_restricted_keys = set(websocket_kwargs).intersection( RESTRICTED_WEBSOCKET_KWARGS ) if found_restricted_keys: raise Web3ValidationError( - f"{RESTRICTED_WEBSOCKET_KWARGS} are not allowed " - f"in websocket_kwargs, found: {found_restricted_keys}" + f"Found restricted keys for websocket_kwargs: " + f"{found_restricted_keys}." ) - self.websocket_kwargs = websocket_kwargs + self.websocket_kwargs = merge(DEFAULT_WEBSOCKET_KWARGS, websocket_kwargs or {}) + super().__init__(endpoint_uri, call_timeout=call_timeout) def __str__(self) -> str: @@ -93,7 +106,12 @@ async def is_connected(self, show_traceback: bool = False) -> bool: return False async def connect(self) -> None: - self.ws = await connect(self.endpoint_uri, **self.websocket_kwargs) + try: + self.ws = await connect(self.endpoint_uri, **self.websocket_kwargs) + except Exception as e: + raise ProviderConnectionError( + f"Could not connect to endpoint: {self.endpoint_uri}" + ) from e async def disconnect(self) -> None: await self.ws.close()