web3 7.0.0b8__py3-none-any.whl → 7.1.0__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.
Files changed (46) hide show
  1. ens/async_ens.py +16 -7
  2. ens/base_ens.py +3 -1
  3. ens/exceptions.py +2 -7
  4. ens/utils.py +0 -17
  5. web3/_utils/abi.py +100 -257
  6. web3/_utils/compat/__init__.py +1 -0
  7. web3/_utils/contracts.py +116 -205
  8. web3/_utils/encoding.py +4 -5
  9. web3/_utils/events.py +28 -33
  10. web3/_utils/fee_utils.py +2 -2
  11. web3/_utils/filters.py +2 -5
  12. web3/_utils/http_session_manager.py +30 -7
  13. web3/_utils/method_formatters.py +3 -3
  14. web3/_utils/module_testing/eth_module.py +59 -37
  15. web3/_utils/module_testing/module_testing_utils.py +43 -1
  16. web3/_utils/module_testing/persistent_connection_provider.py +2 -0
  17. web3/_utils/module_testing/web3_module.py +8 -8
  18. web3/_utils/normalizers.py +10 -8
  19. web3/_utils/validation.py +5 -7
  20. web3/beacon/api_endpoints.py +3 -0
  21. web3/beacon/async_beacon.py +18 -2
  22. web3/beacon/beacon.py +18 -2
  23. web3/contract/async_contract.py +26 -25
  24. web3/contract/base_contract.py +116 -80
  25. web3/contract/contract.py +26 -25
  26. web3/contract/utils.py +86 -55
  27. web3/datastructures.py +21 -11
  28. web3/eth/async_eth.py +1 -2
  29. web3/eth/eth.py +1 -2
  30. web3/exceptions.py +22 -9
  31. web3/gas_strategies/time_based.py +4 -0
  32. web3/manager.py +34 -12
  33. web3/middleware/base.py +8 -0
  34. web3/middleware/filter.py +3 -3
  35. web3/middleware/signing.py +6 -1
  36. web3/scripts/install_pre_releases.py +33 -0
  37. web3/scripts/parse_pygeth_version.py +16 -0
  38. web3/types.py +5 -45
  39. web3/utils/__init__.py +48 -4
  40. web3/utils/abi.py +575 -10
  41. {web3-7.0.0b8.dist-info → web3-7.1.0.dist-info}/METADATA +10 -10
  42. {web3-7.0.0b8.dist-info → web3-7.1.0.dist-info}/RECORD +46 -44
  43. {web3-7.0.0b8.dist-info → web3-7.1.0.dist-info}/WHEEL +1 -1
  44. /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
  45. {web3-7.0.0b8.dist-info → web3-7.1.0.dist-info}/LICENSE +0 -0
  46. {web3-7.0.0b8.dist-info → web3-7.1.0.dist-info}/top_level.txt +0 -0
web3/contract/utils.py CHANGED
@@ -16,9 +16,16 @@ from eth_abi.exceptions import (
16
16
  DecodingError,
17
17
  )
18
18
  from eth_typing import (
19
+ ABI,
20
+ ABICallable,
21
+ ABIFunction,
19
22
  ChecksumAddress,
20
23
  TypeStr,
21
24
  )
25
+ from eth_utils.abi import (
26
+ filter_abi_by_type,
27
+ get_abi_output_types,
28
+ )
22
29
  from eth_utils.toolz import (
23
30
  compose,
24
31
  curry,
@@ -28,8 +35,6 @@ from hexbytes import (
28
35
  )
29
36
 
30
37
  from web3._utils.abi import (
31
- filter_by_type,
32
- get_abi_output_types,
33
38
  map_abi_data,
34
39
  named_tree,
35
40
  recursive_dict_to_namedtuple,
@@ -37,8 +42,10 @@ from web3._utils.abi import (
37
42
  from web3._utils.async_transactions import (
38
43
  async_fill_transaction_defaults,
39
44
  )
45
+ from web3._utils.compat import (
46
+ TypeAlias,
47
+ )
40
48
  from web3._utils.contracts import (
41
- find_matching_fn_abi,
42
49
  prepare_transaction,
43
50
  )
44
51
  from web3._utils.normalizers import (
@@ -52,14 +59,16 @@ from web3.exceptions import (
52
59
  Web3ValueError,
53
60
  )
54
61
  from web3.types import (
55
- ABI,
56
- ABIFunction,
62
+ ABIElementIdentifier,
57
63
  BlockIdentifier,
58
- FunctionIdentifier,
64
+ RPCEndpoint,
59
65
  StateOverride,
60
66
  TContractFn,
61
67
  TxParams,
62
68
  )
69
+ from web3.utils.abi import (
70
+ get_abi_element,
71
+ )
63
72
 
64
73
  if TYPE_CHECKING:
65
74
  from web3 import ( # noqa: F401
@@ -77,8 +86,8 @@ ACCEPTABLE_EMPTY_STRINGS = ["0x", b"0x", "", b""]
77
86
  def format_contract_call_return_data_curried(
78
87
  async_w3: Union["AsyncWeb3", "Web3"],
79
88
  decode_tuples: bool,
80
- fn_abi: ABIFunction,
81
- function_identifier: FunctionIdentifier,
89
+ fn_abi: ABICallable,
90
+ abi_element_identifier: ABIElementIdentifier,
82
91
  normalizers: Tuple[Callable[..., Any], ...],
83
92
  output_types: Sequence[TypeStr],
84
93
  return_data: Any,
@@ -92,7 +101,7 @@ def format_contract_call_return_data_curried(
92
101
  output_data = async_w3.codec.decode(output_types, return_data)
93
102
  except DecodingError as e:
94
103
  msg = (
95
- f"Could not decode contract function call to {function_identifier} "
104
+ f"Could not decode contract function call to {abi_element_identifier} "
96
105
  f"with return data: {str(return_data)}, output_types: {output_types}"
97
106
  )
98
107
  raise BadFunctionCallOutput(msg) from e
@@ -103,7 +112,7 @@ def format_contract_call_return_data_curried(
103
112
  )
104
113
  normalized_data = map_abi_data(_normalizers, output_types, output_data)
105
114
 
106
- if decode_tuples:
115
+ if decode_tuples and fn_abi["type"] == "function":
107
116
  decoded = named_tree(fn_abi["outputs"], normalized_data)
108
117
  normalized_data = recursive_dict_to_namedtuple(decoded)
109
118
 
@@ -114,11 +123,11 @@ def call_contract_function(
114
123
  w3: "Web3",
115
124
  address: ChecksumAddress,
116
125
  normalizers: Tuple[Callable[..., Any], ...],
117
- function_identifier: FunctionIdentifier,
126
+ abi_element_identifier: ABIElementIdentifier,
118
127
  transaction: TxParams,
119
128
  block_id: Optional[BlockIdentifier] = None,
120
129
  contract_abi: Optional[ABI] = None,
121
- fn_abi: Optional[ABIFunction] = None,
130
+ abi_callable: Optional[ABICallable] = None,
122
131
  state_override: Optional[StateOverride] = None,
123
132
  ccip_read_enabled: Optional[bool] = None,
124
133
  decode_tuples: Optional[bool] = False,
@@ -132,9 +141,9 @@ def call_contract_function(
132
141
  call_transaction = prepare_transaction(
133
142
  address,
134
143
  w3,
135
- fn_identifier=function_identifier,
144
+ abi_element_identifier=abi_element_identifier,
136
145
  contract_abi=contract_abi,
137
- fn_abi=fn_abi,
146
+ abi_callable=abi_callable,
138
147
  transaction=transaction,
139
148
  fn_args=args,
140
149
  fn_kwargs=kwargs,
@@ -147,17 +156,27 @@ def call_contract_function(
147
156
  ccip_read_enabled=ccip_read_enabled,
148
157
  )
149
158
 
150
- if fn_abi is None:
151
- fn_abi = find_matching_fn_abi(
152
- contract_abi, w3.codec, function_identifier, args, kwargs
159
+ if abi_callable is None:
160
+ abi_callable = cast(
161
+ ABIFunction,
162
+ get_abi_element(
163
+ contract_abi,
164
+ abi_element_identifier,
165
+ *args,
166
+ abi_codec=w3.codec,
167
+ **kwargs,
168
+ ),
153
169
  )
154
170
 
155
- output_types = get_abi_output_types(fn_abi)
171
+ # get the output types, which only exist for function types
172
+ output_types = []
173
+ if abi_callable["type"] == "function":
174
+ output_types = get_abi_output_types(abi_callable)
156
175
 
157
176
  provider = w3.provider
158
177
  if hasattr(provider, "_is_batching") and provider._is_batching:
159
- # request_information == ((method, params), response_formatters)
160
- request_information = tuple(return_data)
178
+ BatchingReturnData: TypeAlias = Tuple[Tuple[RPCEndpoint, Any], Tuple[Any, ...]]
179
+ request_information = tuple(cast(BatchingReturnData, return_data))
161
180
  method_and_params = request_information[0]
162
181
 
163
182
  # append return data formatting to result formatters
@@ -168,8 +187,8 @@ def call_contract_function(
168
187
  format_contract_call_return_data_curried(
169
188
  w3,
170
189
  decode_tuples,
171
- fn_abi,
172
- function_identifier,
190
+ abi_callable,
191
+ abi_element_identifier,
173
192
  normalizers,
174
193
  output_types,
175
194
  ),
@@ -198,7 +217,7 @@ def call_contract_function(
198
217
  )
199
218
  else:
200
219
  msg = (
201
- f"Could not decode contract function call to {function_identifier} "
220
+ f"Could not decode contract function call to {abi_element_identifier} "
202
221
  f"with return data: {str(return_data)}, output_types: {output_types}"
203
222
  )
204
223
  raise BadFunctionCallOutput(msg) from e
@@ -209,8 +228,8 @@ def call_contract_function(
209
228
  )
210
229
  normalized_data = map_abi_data(_normalizers, output_types, output_data)
211
230
 
212
- if decode_tuples:
213
- decoded = named_tree(fn_abi["outputs"], normalized_data)
231
+ if decode_tuples and abi_callable["type"] == "function":
232
+ decoded = named_tree(abi_callable["outputs"], normalized_data)
214
233
  normalized_data = recursive_dict_to_namedtuple(decoded)
215
234
 
216
235
  if len(normalized_data) == 1:
@@ -222,7 +241,7 @@ def call_contract_function(
222
241
  def transact_with_contract_function(
223
242
  address: ChecksumAddress,
224
243
  w3: "Web3",
225
- function_name: Optional[FunctionIdentifier] = None,
244
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
226
245
  transaction: Optional[TxParams] = None,
227
246
  contract_abi: Optional[ABI] = None,
228
247
  fn_abi: Optional[ABIFunction] = None,
@@ -236,10 +255,10 @@ def transact_with_contract_function(
236
255
  transact_transaction = prepare_transaction(
237
256
  address,
238
257
  w3,
239
- fn_identifier=function_name,
258
+ abi_element_identifier=abi_element_identifier,
240
259
  contract_abi=contract_abi,
241
260
  transaction=transaction,
242
- fn_abi=fn_abi,
261
+ abi_callable=fn_abi,
243
262
  fn_args=args,
244
263
  fn_kwargs=kwargs,
245
264
  )
@@ -251,7 +270,7 @@ def transact_with_contract_function(
251
270
  def estimate_gas_for_function(
252
271
  address: ChecksumAddress,
253
272
  w3: "Web3",
254
- fn_identifier: Optional[FunctionIdentifier] = None,
273
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
255
274
  transaction: Optional[TxParams] = None,
256
275
  contract_abi: Optional[ABI] = None,
257
276
  fn_abi: Optional[ABIFunction] = None,
@@ -269,9 +288,9 @@ def estimate_gas_for_function(
269
288
  estimate_transaction = prepare_transaction(
270
289
  address,
271
290
  w3,
272
- fn_identifier=fn_identifier,
291
+ abi_element_identifier=abi_element_identifier,
273
292
  contract_abi=contract_abi,
274
- fn_abi=fn_abi,
293
+ abi_callable=fn_abi,
275
294
  transaction=transaction,
276
295
  fn_args=args,
277
296
  fn_kwargs=kwargs,
@@ -283,7 +302,7 @@ def estimate_gas_for_function(
283
302
  def build_transaction_for_function(
284
303
  address: ChecksumAddress,
285
304
  w3: "Web3",
286
- function_name: Optional[FunctionIdentifier] = None,
305
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
287
306
  transaction: Optional[TxParams] = None,
288
307
  contract_abi: Optional[ABI] = None,
289
308
  fn_abi: Optional[ABIFunction] = None,
@@ -299,9 +318,9 @@ def build_transaction_for_function(
299
318
  prepared_transaction = prepare_transaction(
300
319
  address,
301
320
  w3,
302
- fn_identifier=function_name,
321
+ abi_element_identifier=abi_element_identifier,
303
322
  contract_abi=contract_abi,
304
- fn_abi=fn_abi,
323
+ abi_callable=fn_abi,
305
324
  transaction=transaction,
306
325
  fn_args=args,
307
326
  fn_kwargs=kwargs,
@@ -319,14 +338,14 @@ def find_functions_by_identifier(
319
338
  callable_check: Callable[..., Any],
320
339
  function_type: Type[TContractFn],
321
340
  ) -> List[TContractFn]:
322
- fns_abi = filter_by_type("function", contract_abi)
341
+ fns_abi = filter_abi_by_type("function", contract_abi)
323
342
  return [
324
343
  function_type.factory(
325
344
  fn_abi["name"],
326
345
  w3=w3,
327
346
  contract_abi=contract_abi,
328
347
  address=address,
329
- function_identifier=fn_abi["name"],
348
+ abi_element_identifier=fn_abi["name"],
330
349
  abi=fn_abi,
331
350
  )
332
351
  for fn_abi in fns_abi
@@ -353,7 +372,7 @@ async def async_call_contract_function(
353
372
  async_w3: "AsyncWeb3",
354
373
  address: ChecksumAddress,
355
374
  normalizers: Tuple[Callable[..., Any], ...],
356
- function_identifier: FunctionIdentifier,
375
+ abi_element_identifier: ABIElementIdentifier,
357
376
  transaction: TxParams,
358
377
  block_id: Optional[BlockIdentifier] = None,
359
378
  contract_abi: Optional[ABI] = None,
@@ -371,9 +390,9 @@ async def async_call_contract_function(
371
390
  call_transaction = prepare_transaction(
372
391
  address,
373
392
  async_w3,
374
- fn_identifier=function_identifier,
393
+ abi_element_identifier=abi_element_identifier,
375
394
  contract_abi=contract_abi,
376
- fn_abi=fn_abi,
395
+ abi_callable=fn_abi,
377
396
  transaction=transaction,
378
397
  fn_args=args,
379
398
  fn_kwargs=kwargs,
@@ -387,18 +406,28 @@ async def async_call_contract_function(
387
406
  )
388
407
 
389
408
  if fn_abi is None:
390
- fn_abi = find_matching_fn_abi(
391
- contract_abi, async_w3.codec, function_identifier, args, kwargs
409
+ fn_abi = cast(
410
+ ABIFunction,
411
+ get_abi_element(
412
+ contract_abi,
413
+ abi_element_identifier,
414
+ *args,
415
+ abi_codec=async_w3.codec,
416
+ **kwargs,
417
+ ),
392
418
  )
393
419
 
394
- output_types = get_abi_output_types(fn_abi)
420
+ # get the output types, which only exist for function types
421
+ output_types = []
422
+ if fn_abi["type"] == "function":
423
+ output_types = get_abi_output_types(fn_abi)
395
424
 
396
425
  if async_w3.provider._is_batching:
397
426
  contract_call_return_data_formatter = format_contract_call_return_data_curried(
398
427
  async_w3,
399
428
  decode_tuples,
400
429
  fn_abi,
401
- function_identifier,
430
+ abi_element_identifier,
402
431
  normalizers,
403
432
  output_types,
404
433
  )
@@ -410,8 +439,10 @@ async def async_call_contract_function(
410
439
  current_request_id, contract_call_return_data_formatter
411
440
  )
412
441
  else:
413
- # request_information == ((method, params), response_formatters)
414
- request_information = tuple(return_data)
442
+ BatchingReturnData: TypeAlias = Tuple[
443
+ Tuple[RPCEndpoint, Any], Tuple[Any, ...]
444
+ ]
445
+ request_information = tuple(cast(BatchingReturnData, return_data))
415
446
  method_and_params = request_information[0]
416
447
 
417
448
  # append return data formatter to result formatters
@@ -446,7 +477,7 @@ async def async_call_contract_function(
446
477
  )
447
478
  else:
448
479
  msg = (
449
- f"Could not decode contract function call to {function_identifier} "
480
+ f"Could not decode contract function call to {abi_element_identifier} "
450
481
  f"with return data: {str(return_data)}, output_types: {output_types}"
451
482
  )
452
483
  raise BadFunctionCallOutput(msg) from e
@@ -467,7 +498,7 @@ async def async_call_contract_function(
467
498
  async def async_transact_with_contract_function(
468
499
  address: ChecksumAddress,
469
500
  async_w3: "AsyncWeb3",
470
- function_name: Optional[FunctionIdentifier] = None,
501
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
471
502
  transaction: Optional[TxParams] = None,
472
503
  contract_abi: Optional[ABI] = None,
473
504
  fn_abi: Optional[ABIFunction] = None,
@@ -481,10 +512,10 @@ async def async_transact_with_contract_function(
481
512
  transact_transaction = prepare_transaction(
482
513
  address,
483
514
  async_w3,
484
- fn_identifier=function_name,
515
+ abi_element_identifier=abi_element_identifier,
485
516
  contract_abi=contract_abi,
486
517
  transaction=transaction,
487
- fn_abi=fn_abi,
518
+ abi_callable=fn_abi,
488
519
  fn_args=args,
489
520
  fn_kwargs=kwargs,
490
521
  )
@@ -496,7 +527,7 @@ async def async_transact_with_contract_function(
496
527
  async def async_estimate_gas_for_function(
497
528
  address: ChecksumAddress,
498
529
  async_w3: "AsyncWeb3",
499
- fn_identifier: Optional[FunctionIdentifier] = None,
530
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
500
531
  transaction: Optional[TxParams] = None,
501
532
  contract_abi: Optional[ABI] = None,
502
533
  fn_abi: Optional[ABIFunction] = None,
@@ -514,9 +545,9 @@ async def async_estimate_gas_for_function(
514
545
  estimate_transaction = prepare_transaction(
515
546
  address,
516
547
  async_w3,
517
- fn_identifier=fn_identifier,
548
+ abi_element_identifier=abi_element_identifier,
518
549
  contract_abi=contract_abi,
519
- fn_abi=fn_abi,
550
+ abi_callable=fn_abi,
520
551
  transaction=transaction,
521
552
  fn_args=args,
522
553
  fn_kwargs=kwargs,
@@ -530,7 +561,7 @@ async def async_estimate_gas_for_function(
530
561
  async def async_build_transaction_for_function(
531
562
  address: ChecksumAddress,
532
563
  async_w3: "AsyncWeb3",
533
- function_name: Optional[FunctionIdentifier] = None,
564
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
534
565
  transaction: Optional[TxParams] = None,
535
566
  contract_abi: Optional[ABI] = None,
536
567
  fn_abi: Optional[ABIFunction] = None,
@@ -546,9 +577,9 @@ async def async_build_transaction_for_function(
546
577
  prepared_transaction = prepare_transaction(
547
578
  address,
548
579
  async_w3,
549
- fn_identifier=function_name,
580
+ abi_element_identifier=abi_element_identifier,
550
581
  contract_abi=contract_abi,
551
- fn_abi=fn_abi,
582
+ abi_callable=fn_abi,
552
583
  transaction=transaction,
553
584
  fn_args=args,
554
585
  fn_kwargs=kwargs,
web3/datastructures.py CHANGED
@@ -182,7 +182,7 @@ class NamedElementOnion(Mapping[TKey, TValue]):
182
182
  if name is None:
183
183
  name = cast(TKey, element)
184
184
 
185
- name = self._repr_if_not_hashable(name)
185
+ name = self._build_name(name)
186
186
 
187
187
  if name in self._queue:
188
188
  if name is element:
@@ -219,7 +219,7 @@ class NamedElementOnion(Mapping[TKey, TValue]):
219
219
  if name is None:
220
220
  name = cast(TKey, element)
221
221
 
222
- name = self._repr_if_not_hashable(name)
222
+ name = self._build_name(name)
223
223
 
224
224
  self._queue.move_to_end(name, last=False)
225
225
  elif layer == len(self._queue):
@@ -233,7 +233,7 @@ class NamedElementOnion(Mapping[TKey, TValue]):
233
233
  self._queue.clear()
234
234
 
235
235
  def replace(self, old: TKey, new: TKey) -> TValue:
236
- old_name = self._repr_if_not_hashable(old)
236
+ old_name = self._build_name(old)
237
237
 
238
238
  if old_name not in self._queue:
239
239
  raise Web3ValueError(
@@ -248,15 +248,25 @@ class NamedElementOnion(Mapping[TKey, TValue]):
248
248
  self._queue[old_name] = new
249
249
  return to_be_replaced
250
250
 
251
- def _repr_if_not_hashable(self, value: TKey) -> TKey:
251
+ @staticmethod
252
+ def _build_name(value: TKey) -> TKey:
252
253
  try:
253
254
  value.__hash__()
255
+ return value
254
256
  except TypeError:
255
- value = cast(TKey, repr(value))
256
- return value
257
+ # unhashable, unnamed elements
258
+ if not callable(value):
259
+ raise Web3TypeError(
260
+ f"Expected a callable or hashable type, got {type(value)}"
261
+ )
262
+ # This will either be ``Web3Middleware`` class or the ``build`` method of a
263
+ # ``Web3MiddlewareBuilder``. Instantiate with empty ``Web3`` and use a
264
+ # unique identifier with the ``__hash__()`` as the name.
265
+ v = value(None)
266
+ return cast(TKey, f"{v.__class__}<{v.__hash__()}>")
257
267
 
258
268
  def remove(self, old: TKey) -> None:
259
- old_name = self._repr_if_not_hashable(old)
269
+ old_name = self._build_name(old)
260
270
  if old_name not in self._queue:
261
271
  raise Web3ValueError("You can only remove something that has been added")
262
272
  del self._queue[old_name]
@@ -270,8 +280,8 @@ class NamedElementOnion(Mapping[TKey, TValue]):
270
280
  return [(val, key) for key, val in reversed(self._queue.items())]
271
281
 
272
282
  def _replace_with_new_name(self, old: TKey, new: TKey) -> None:
273
- old_name = self._repr_if_not_hashable(old)
274
- new_name = self._repr_if_not_hashable(new)
283
+ old_name = self._build_name(old)
284
+ new_name = self._build_name(new)
275
285
 
276
286
  self._queue[new_name] = new
277
287
  found_old = False
@@ -293,11 +303,11 @@ class NamedElementOnion(Mapping[TKey, TValue]):
293
303
  return NamedElementOnion(cast(List[Any], combined.items()))
294
304
 
295
305
  def __contains__(self, element: Any) -> bool:
296
- element_name = self._repr_if_not_hashable(element)
306
+ element_name = self._build_name(element)
297
307
  return element_name in self._queue
298
308
 
299
309
  def __getitem__(self, element: TKey) -> TValue:
300
- element_name = self._repr_if_not_hashable(element)
310
+ element_name = self._build_name(element)
301
311
  return self._queue[element_name]
302
312
 
303
313
  def __len__(self) -> int:
web3/eth/async_eth.py CHANGED
@@ -732,8 +732,7 @@ class AsyncEth(BaseEth):
732
732
  # -- contract methods -- #
733
733
 
734
734
  @overload
735
- # mypy error: Overloaded function signatures 1 and 2 overlap with incompatible return types # noqa: E501
736
- def contract(self, address: None = None, **kwargs: Any) -> Type[AsyncContract]: # type: ignore[overload-overlap] # noqa: E501
735
+ def contract(self, address: None = None, **kwargs: Any) -> Type[AsyncContract]:
737
736
  ...
738
737
 
739
738
  @overload
web3/eth/eth.py CHANGED
@@ -629,8 +629,7 @@ class Eth(BaseEth):
629
629
  )
630
630
 
631
631
  @overload
632
- # type error: Overloaded function signatures 1 and 2 overlap with incompatible return types # noqa: E501
633
- def contract(self, address: None = None, **kwargs: Any) -> Type[Contract]: # type: ignore[overload-overlap] # noqa: E501
632
+ def contract(self, address: None = None, **kwargs: Any) -> Type[Contract]:
634
633
  ...
635
634
 
636
635
  @overload
web3/exceptions.py CHANGED
@@ -8,10 +8,6 @@ from typing import (
8
8
  Union,
9
9
  )
10
10
 
11
- from eth_utils import (
12
- ValidationError,
13
- )
14
-
15
11
  from web3.types import (
16
12
  BlockData,
17
13
  RPCResponse,
@@ -164,7 +160,7 @@ class MismatchedABI(Web3Exception):
164
160
  """
165
161
 
166
162
 
167
- class ABIEventFunctionNotFound(AttributeError, MismatchedABI):
163
+ class ABIEventNotFound(AttributeError, MismatchedABI):
168
164
  """
169
165
  Raised when an attempt is made to access an event
170
166
  that does not exist in the ABI.
@@ -178,14 +174,25 @@ class ABIFunctionNotFound(AttributeError, MismatchedABI):
178
174
  """
179
175
 
180
176
 
181
- class FallbackNotFound(Web3Exception):
177
+ class ABIConstructorNotFound(Web3Exception):
178
+ """
179
+ Raised when a constructor function doesn't exist in contract.
180
+ """
181
+
182
+
183
+ class ABIFallbackNotFound(Web3Exception):
184
+ """
185
+ Raised when a fallback function doesn't exist in contract.
186
+ """
187
+
188
+
189
+ class ABIReceiveNotFound(Web3Exception):
182
190
  """
183
- Raised when fallback function doesn't exist in contract.
191
+ Raised when a receive function doesn't exist in contract.
184
192
  """
185
193
 
186
194
 
187
- # type ignored because subclassing ValidationError which has type Any
188
- class Web3ValidationError(Web3Exception, ValidationError): # type: ignore[misc]
195
+ class Web3ValidationError(Web3Exception):
189
196
  """
190
197
  Raised when a supplied value is invalid.
191
198
  """
@@ -364,6 +371,12 @@ class MethodUnavailable(Web3RPCError):
364
371
  """
365
372
 
366
373
 
374
+ class RequestTimedOut(Web3RPCError):
375
+ """
376
+ Raised when a request to the node times out.
377
+ """
378
+
379
+
367
380
  class TransactionNotFound(Web3RPCError):
368
381
  """
369
382
  Raised when a tx hash used to look up a tx in a jsonrpc call cannot be found.
@@ -5,6 +5,7 @@ from typing import (
5
5
  Iterable,
6
6
  Sequence,
7
7
  Tuple,
8
+ cast,
8
9
  )
9
10
 
10
11
  from eth_typing import (
@@ -35,6 +36,7 @@ from web3.exceptions import (
35
36
  from web3.types import (
36
37
  BlockNumber,
37
38
  GasPriceStrategy,
39
+ TxData,
38
40
  TxParams,
39
41
  Wei,
40
42
  )
@@ -84,6 +86,7 @@ def _get_raw_miner_data(
84
86
  latest = w3.eth.get_block("latest", full_transactions=True)
85
87
 
86
88
  for transaction in latest["transactions"]:
89
+ transaction = cast(TxData, transaction)
87
90
  yield (latest["miner"], latest["hash"], transaction["gasPrice"])
88
91
 
89
92
  block = latest
@@ -96,6 +99,7 @@ def _get_raw_miner_data(
96
99
  # block numbers to make caching the data easier to implement.
97
100
  block = w3.eth.get_block(block["parentHash"], full_transactions=True)
98
101
  for transaction in block["transactions"]:
102
+ transaction = cast(TxData, transaction)
99
103
  yield (block["miner"], block["hash"], transaction["gasPrice"])
100
104
 
101
105
 
web3/manager.py CHANGED
@@ -37,6 +37,7 @@ from web3.exceptions import (
37
37
  BadResponseFormat,
38
38
  MethodUnavailable,
39
39
  ProviderConnectionError,
40
+ RequestTimedOut,
40
41
  TaskNotRunning,
41
42
  Web3RPCError,
42
43
  Web3TypeError,
@@ -89,6 +90,13 @@ if TYPE_CHECKING:
89
90
 
90
91
 
91
92
  NULL_RESPONSES = [None, HexBytes("0x"), "0x"]
93
+ KNOWN_REQUEST_TIMEOUT_MESSAGING = {
94
+ # Note: It's important to be very explicit here and not too broad. We don't want
95
+ # to accidentally catch a message that is not for a request timeout. In the worst
96
+ # case, we raise something more generic like `Web3RPCError`. JSON-RPC unfortunately
97
+ # has not standardized error codes for request timeouts.
98
+ "request timed out", # go-ethereum
99
+ }
92
100
  METHOD_NOT_FOUND = -32601
93
101
 
94
102
 
@@ -185,6 +193,7 @@ def _validate_response(
185
193
  response, 'Response must include either "error" or "result".'
186
194
  )
187
195
  elif "error" in response:
196
+ web3_rpc_error: Optional[Web3RPCError] = None
188
197
  error = response["error"]
189
198
 
190
199
  # raise the error when the value is a string
@@ -195,6 +204,13 @@ def _validate_response(
195
204
  "JSON-RPC 2.0 specification.",
196
205
  )
197
206
 
207
+ # errors must include a message
208
+ error_message = error.get("message")
209
+ if not isinstance(error_message, str):
210
+ _raise_bad_response_format(
211
+ response, 'error["message"] is required and must be a string value.'
212
+ )
213
+
198
214
  # errors must include an integer code
199
215
  code = error.get("code")
200
216
  if not isinstance(code, int):
@@ -202,7 +218,7 @@ def _validate_response(
202
218
  response, 'error["code"] is required and must be an integer value.'
203
219
  )
204
220
  elif code == METHOD_NOT_FOUND:
205
- exception = MethodUnavailable(
221
+ web3_rpc_error = MethodUnavailable(
206
222
  repr(error),
207
223
  rpc_response=response,
208
224
  user_message=(
@@ -211,20 +227,26 @@ def _validate_response(
211
227
  "currently enabled."
212
228
  ),
213
229
  )
214
- logger.error(exception.user_message)
215
- logger.debug(f"RPC error response: {response}")
216
- raise exception
217
-
218
- # errors must include a message
219
- error_message = error.get("message")
220
- if not isinstance(error_message, str):
221
- _raise_bad_response_format(
222
- response, 'error["message"] is required and must be a string value.'
230
+ elif any(
231
+ # parse specific timeout messages
232
+ timeout_str in error_message.lower()
233
+ for timeout_str in KNOWN_REQUEST_TIMEOUT_MESSAGING
234
+ ):
235
+ web3_rpc_error = RequestTimedOut(
236
+ repr(error),
237
+ rpc_response=response,
238
+ user_message=(
239
+ "The request timed out. Check the connection to your node and "
240
+ "try again."
241
+ ),
223
242
  )
224
243
 
225
- apply_error_formatters(error_formatters, response)
244
+ if web3_rpc_error is None:
245
+ # if no condition was met above, raise a more generic `Web3RPCError`
246
+ web3_rpc_error = Web3RPCError(repr(error), rpc_response=response)
247
+
248
+ response = apply_error_formatters(error_formatters, response)
226
249
 
227
- web3_rpc_error = Web3RPCError(repr(error), rpc_response=response)
228
250
  logger.error(web3_rpc_error.user_message)
229
251
  logger.debug(f"RPC error response: {response}")
230
252
  raise web3_rpc_error