web3 7.0.0b5__py3-none-any.whl → 7.0.0b6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,217 @@
1
+ from copy import (
2
+ copy,
3
+ )
4
+ from types import (
5
+ TracebackType,
6
+ )
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Any,
10
+ Callable,
11
+ Coroutine,
12
+ Dict,
13
+ Generic,
14
+ List,
15
+ Sequence,
16
+ Tuple,
17
+ Type,
18
+ Union,
19
+ cast,
20
+ )
21
+ import warnings
22
+
23
+ from web3._utils.compat import (
24
+ Self,
25
+ )
26
+ from web3.contract.async_contract import (
27
+ AsyncContractFunction,
28
+ )
29
+ from web3.contract.contract import (
30
+ ContractFunction,
31
+ )
32
+ from web3.exceptions import (
33
+ Web3ValueError,
34
+ )
35
+ from web3.types import (
36
+ TFunc,
37
+ TReturn,
38
+ )
39
+
40
+ if TYPE_CHECKING:
41
+ from web3 import ( # noqa: F401
42
+ AsyncWeb3,
43
+ Web3,
44
+ )
45
+ from web3.method import ( # noqa: F401
46
+ Method,
47
+ )
48
+ from web3.providers import ( # noqa: F401
49
+ PersistentConnectionProvider,
50
+ )
51
+ from web3.providers.async_base import ( # noqa: F401
52
+ AsyncJSONBaseProvider,
53
+ )
54
+ from web3.providers.base import ( # noqa: F401
55
+ JSONBaseProvider,
56
+ )
57
+ from web3.types import ( # noqa: F401
58
+ RPCEndpoint,
59
+ RPCResponse,
60
+ )
61
+
62
+
63
+ BATCH_REQUEST_ID = "batch_request" # for use as the cache key for batch requests
64
+
65
+ BatchRequestInformation = Tuple[Tuple["RPCEndpoint", Any], Sequence[Any]]
66
+ RPC_METHODS_UNSUPPORTED_DURING_BATCH = {
67
+ "eth_subscribe",
68
+ "eth_unsubscribe",
69
+ "eth_sendRawTransaction",
70
+ "eth_sendTransaction",
71
+ "eth_signTransaction",
72
+ "eth_sign",
73
+ "eth_signTypedData",
74
+ }
75
+
76
+
77
+ class RequestBatcher(Generic[TFunc]):
78
+ def __init__(self, web3: Union["AsyncWeb3", "Web3"]) -> None:
79
+ self.web3 = web3
80
+ self._requests_info: List[BatchRequestInformation] = []
81
+ self._async_requests_info: List[
82
+ Coroutine[Any, Any, BatchRequestInformation]
83
+ ] = []
84
+ self._initialize_batching()
85
+
86
+ @property
87
+ def _provider(self) -> Union["JSONBaseProvider", "AsyncJSONBaseProvider"]:
88
+ return (
89
+ cast("AsyncJSONBaseProvider", self.web3.provider)
90
+ if self.web3.provider.is_async
91
+ else cast("JSONBaseProvider", self.web3.provider)
92
+ )
93
+
94
+ def _validate_is_batching(self) -> None:
95
+ if not self._provider._is_batching:
96
+ raise Web3ValueError(
97
+ "Batch has already been executed or cancelled. Create a new batch to "
98
+ "issue batched requests."
99
+ )
100
+
101
+ def _initialize_batching(self) -> None:
102
+ self._provider._is_batching = True
103
+ self.clear()
104
+
105
+ def _end_batching(self) -> None:
106
+ self.clear()
107
+ self._provider._is_batching = False
108
+ if self._provider.has_persistent_connection:
109
+ provider = cast("PersistentConnectionProvider", self._provider)
110
+ provider._batch_request_counter = None
111
+
112
+ def add(self, batch_payload: TReturn) -> None:
113
+ self._validate_is_batching()
114
+
115
+ if isinstance(batch_payload, (ContractFunction, AsyncContractFunction)):
116
+ batch_payload = batch_payload.call() # type: ignore
117
+
118
+ # When batching, we don't make a request. Instead, we will get the request
119
+ # information and store it in the `_requests_info` list. So we have to cast the
120
+ # apparent "request" into the BatchRequestInformation type.
121
+ if self._provider.is_async:
122
+ self._async_requests_info.append(
123
+ cast(Coroutine[Any, Any, BatchRequestInformation], batch_payload)
124
+ )
125
+ else:
126
+ self._requests_info.append(cast(BatchRequestInformation, batch_payload))
127
+
128
+ def add_mapping(
129
+ self,
130
+ batch_payload: Dict[
131
+ Union[
132
+ "Method[Callable[..., Any]]",
133
+ Callable[..., Any],
134
+ ContractFunction,
135
+ AsyncContractFunction,
136
+ ],
137
+ List[Any],
138
+ ],
139
+ ) -> None:
140
+ self._validate_is_batching()
141
+ for method, params in batch_payload.items():
142
+ for param in params:
143
+ self.add(method(param))
144
+
145
+ def execute(self) -> List["RPCResponse"]:
146
+ self._validate_is_batching()
147
+ responses = self.web3.manager._make_batch_request(self._requests_info)
148
+ self._end_batching()
149
+ return responses
150
+
151
+ def clear(self) -> None:
152
+ self._requests_info = []
153
+ self._async_requests_info = []
154
+ if self._provider.has_persistent_connection:
155
+ provider = cast("PersistentConnectionProvider", self._provider)
156
+ provider._batch_request_counter = next(copy(provider.request_counter))
157
+
158
+ def cancel(self) -> None:
159
+ self._end_batching()
160
+
161
+ # -- context manager -- #
162
+
163
+ def __enter__(self) -> Self:
164
+ self._initialize_batching()
165
+ return self
166
+
167
+ def __exit__(
168
+ self,
169
+ exc_type: Type[BaseException],
170
+ exc_val: BaseException,
171
+ exc_tb: TracebackType,
172
+ ) -> None:
173
+ self._end_batching()
174
+
175
+ # -- async -- #
176
+
177
+ async def async_execute(self) -> List["RPCResponse"]:
178
+ self._validate_is_batching()
179
+ responses = await self.web3.manager._async_make_batch_request(
180
+ self._async_requests_info
181
+ )
182
+ self._end_batching()
183
+ return responses
184
+
185
+ # -- async context manager -- #
186
+
187
+ async def __aenter__(self) -> Self:
188
+ self._initialize_batching()
189
+ return self
190
+
191
+ async def __aexit__(
192
+ self,
193
+ exc_type: Type[BaseException],
194
+ exc_val: BaseException,
195
+ exc_tb: TracebackType,
196
+ ) -> None:
197
+ self._end_batching()
198
+
199
+
200
+ def sort_batch_response_by_response_ids(
201
+ responses: List["RPCResponse"],
202
+ ) -> List["RPCResponse"]:
203
+ if all(response.get("id") is not None for response in responses):
204
+ # If all responses have an `id`, sort them by `id, since the JSON-RPC 2.0 spec
205
+ # doesn't guarantee order.
206
+ return sorted(responses, key=lambda response: response["id"])
207
+ else:
208
+ # If any response is missing an `id`, which should only happen on particular
209
+ # errors, return them in the order they were received and hope that the
210
+ # provider is returning them in order. Issue a warning.
211
+ warnings.warn(
212
+ "Received batch response with missing `id` for one or more responses. "
213
+ "Relying on provider to return these responses in order.",
214
+ RuntimeWarning,
215
+ stacklevel=2,
216
+ )
217
+ return responses
web3/_utils/caching.py CHANGED
@@ -6,10 +6,13 @@ from typing import (
6
6
  Any,
7
7
  Callable,
8
8
  Coroutine,
9
+ Dict,
9
10
  List,
11
+ Set,
10
12
  Tuple,
11
13
  TypeVar,
12
14
  Union,
15
+ cast,
13
16
  )
14
17
 
15
18
  from eth_utils import (
@@ -69,7 +72,11 @@ class RequestInformation:
69
72
  self,
70
73
  method: "RPCEndpoint",
71
74
  params: Any,
72
- response_formatters: Tuple[Callable[..., Any], ...],
75
+ response_formatters: Tuple[
76
+ Union[Dict[str, Callable[..., Any]], Callable[..., Any]],
77
+ Callable[..., Any],
78
+ Callable[..., Any],
79
+ ],
73
80
  subscription_id: str = None,
74
81
  ):
75
82
  self.method = method
@@ -87,7 +94,24 @@ def is_cacheable_request(
87
94
  return False
88
95
 
89
96
 
90
- # -- request caching decorators -- #
97
+ # -- request caching -- #
98
+
99
+
100
+ CACHEABLE_REQUESTS = cast(
101
+ Set["RPCEndpoint"],
102
+ (
103
+ "eth_chainId",
104
+ "eth_getBlockByHash",
105
+ "eth_getBlockTransactionCountByHash",
106
+ "eth_getRawTransactionByHash",
107
+ "eth_getTransactionByBlockHashAndIndex",
108
+ "eth_getTransactionByHash",
109
+ "eth_getUncleByBlockHashAndIndex",
110
+ "eth_getUncleCountByBlockHash",
111
+ "net_version",
112
+ "web3_clientVersion",
113
+ ),
114
+ )
91
115
 
92
116
 
93
117
  def _should_cache_response(response: "RPCResponse") -> bool:
@@ -11,4 +11,5 @@
11
11
  from typing_extensions import (
12
12
  NotRequired, # py311
13
13
  Self, # py311
14
+ Unpack, # py311
14
15
  )
web3/_utils/events.py CHANGED
@@ -444,8 +444,8 @@ class EventFilterBuilder(BaseEventFilterBuilder):
444
444
  if not isinstance(w3, web3.Web3):
445
445
  raise Web3ValueError(f"Invalid web3 argument: got: {w3!r}")
446
446
 
447
- for arg in AttributeDict.values(self.args):
448
- arg._immutable = True # type: ignore[attr-defined]
447
+ for arg in self.args.values():
448
+ arg._immutable = True
449
449
  self._immutable = True
450
450
 
451
451
  log_filter = cast("LogFilter", w3.eth.filter(self.filter_params))
@@ -220,7 +220,7 @@ class AsyncEthModuleTest:
220
220
  txn_hash = await async_w3.eth.send_transaction(txn_params)
221
221
 
222
222
  modified_txn_hash = await async_w3.eth.modify_transaction(
223
- txn_hash, gasPrice=(cast(int, txn_params["gasPrice"]) * 2), value=2
223
+ txn_hash, gasPrice=(cast(Wei, txn_params["gasPrice"] * 2)), value=Wei(2)
224
224
  )
225
225
  modified_txn = await async_w3.eth.get_transaction(modified_txn_hash)
226
226
 
@@ -252,9 +252,9 @@ class AsyncEthModuleTest:
252
252
 
253
253
  modified_txn_hash = await async_w3.eth.modify_transaction(
254
254
  txn_hash,
255
- value=2,
256
- maxPriorityFeePerGas=(cast(Wei, txn_params["maxPriorityFeePerGas"]) * 2),
257
- maxFeePerGas=(cast(Wei, txn_params["maxFeePerGas"]) * 2),
255
+ value=Wei(2),
256
+ maxPriorityFeePerGas=(cast(Wei, txn_params["maxPriorityFeePerGas"] * 2)),
257
+ maxFeePerGas=(cast(Wei, txn_params["maxFeePerGas"] * 2)),
258
258
  )
259
259
  modified_txn = await async_w3.eth.get_transaction(modified_txn_hash)
260
260
 
@@ -721,7 +721,7 @@ class AsyncEthModuleTest:
721
721
  "gasPrice": 10**9,
722
722
  }
723
723
  signed = keyfile_account.sign_transaction(txn)
724
- txn_hash = await async_w3.eth.send_raw_transaction(signed.rawTransaction)
724
+ txn_hash = await async_w3.eth.send_raw_transaction(signed.raw_transaction)
725
725
  assert txn_hash == HexBytes(signed.hash)
726
726
 
727
727
  @pytest.mark.asyncio
@@ -3657,7 +3657,7 @@ class EthModuleTest:
3657
3657
  txn_hash = w3.eth.send_transaction(txn_params)
3658
3658
 
3659
3659
  modified_txn_hash = w3.eth.modify_transaction(
3660
- txn_hash, gasPrice=(cast(int, txn_params["gasPrice"]) * 2), value=2
3660
+ txn_hash, gasPrice=(cast(Wei, txn_params["gasPrice"] * 2)), value=Wei(2)
3661
3661
  )
3662
3662
  modified_txn = w3.eth.get_transaction(modified_txn_hash)
3663
3663
 
@@ -3686,9 +3686,9 @@ class EthModuleTest:
3686
3686
 
3687
3687
  modified_txn_hash = w3.eth.modify_transaction(
3688
3688
  txn_hash,
3689
- value=2,
3690
- maxPriorityFeePerGas=(cast(Wei, txn_params["maxPriorityFeePerGas"]) * 2),
3691
- maxFeePerGas=(cast(Wei, txn_params["maxFeePerGas"]) * 2),
3689
+ value=Wei(2),
3690
+ maxPriorityFeePerGas=(cast(Wei, txn_params["maxPriorityFeePerGas"] * 2)),
3691
+ maxFeePerGas=(cast(Wei, txn_params["maxFeePerGas"] * 2)),
3692
3692
  )
3693
3693
  modified_txn = w3.eth.get_transaction(modified_txn_hash)
3694
3694
 
@@ -3720,7 +3720,7 @@ class EthModuleTest:
3720
3720
  "gasPrice": 10**9,
3721
3721
  }
3722
3722
  signed = keyfile_account.sign_transaction(txn)
3723
- txn_hash = w3.eth.send_raw_transaction(signed.rawTransaction)
3723
+ txn_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
3724
3724
  assert txn_hash == HexBytes(signed.hash)
3725
3725
 
3726
3726
  def test_eth_call(self, w3: "Web3", math_contract: "Contract") -> None:
@@ -177,6 +177,12 @@ class WebSocketMessageStreamMock:
177
177
  self.messages = deque(messages) if messages else deque()
178
178
  self.raise_exception = raise_exception
179
179
 
180
+ def __await__(self) -> Generator[Any, Any, "Self"]:
181
+ async def __async_init__() -> "Self":
182
+ return self
183
+
184
+ return __async_init__().__await__()
185
+
180
186
  def __aiter__(self) -> "Self":
181
187
  return self
182
188
 
@@ -189,6 +195,13 @@ class WebSocketMessageStreamMock:
189
195
 
190
196
  return self.messages.popleft()
191
197
 
198
+ @staticmethod
199
+ async def pong() -> Literal[False]:
200
+ return False
201
+
202
+ async def connect(self) -> None:
203
+ pass
204
+
192
205
  async def send(self, data: bytes) -> None:
193
206
  pass
194
207