web3 7.0.0b2__py3-none-any.whl → 7.7.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 (144) hide show
  1. ens/__init__.py +13 -2
  2. ens/_normalization.py +4 -4
  3. ens/async_ens.py +27 -15
  4. ens/base_ens.py +3 -1
  5. ens/contract_data.py +2 -2
  6. ens/ens.py +10 -7
  7. ens/exceptions.py +16 -29
  8. ens/specs/nf.json +1 -1
  9. ens/specs/normalization_spec.json +1 -1
  10. ens/utils.py +24 -32
  11. web3/__init__.py +23 -12
  12. web3/_utils/abi.py +157 -263
  13. web3/_utils/async_transactions.py +34 -20
  14. web3/_utils/batching.py +217 -0
  15. web3/_utils/blocks.py +6 -2
  16. web3/_utils/caching/__init__.py +12 -0
  17. web3/_utils/caching/caching_utils.py +433 -0
  18. web3/_utils/caching/request_caching_validation.py +287 -0
  19. web3/_utils/compat/__init__.py +2 -3
  20. web3/_utils/contract_sources/compile_contracts.py +1 -1
  21. web3/_utils/contract_sources/contract_data/ambiguous_function_contract.py +42 -0
  22. web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
  23. web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
  24. web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
  25. web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
  26. web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
  27. web3/_utils/contract_sources/contract_data/event_contracts.py +50 -5
  28. web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
  29. web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
  30. web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
  31. web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
  32. web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
  33. web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
  34. web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
  35. web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
  36. web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
  37. web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
  38. web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
  39. web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
  40. web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
  41. web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
  42. web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
  43. web3/_utils/contracts.py +172 -220
  44. web3/_utils/datatypes.py +5 -1
  45. web3/_utils/decorators.py +6 -1
  46. web3/_utils/empty.py +1 -1
  47. web3/_utils/encoding.py +16 -12
  48. web3/_utils/error_formatters_utils.py +5 -3
  49. web3/_utils/events.py +78 -72
  50. web3/_utils/fee_utils.py +1 -3
  51. web3/_utils/filters.py +24 -22
  52. web3/_utils/formatters.py +2 -2
  53. web3/_utils/http.py +8 -2
  54. web3/_utils/http_session_manager.py +314 -0
  55. web3/_utils/math.py +14 -15
  56. web3/_utils/method_formatters.py +161 -34
  57. web3/_utils/module.py +2 -1
  58. web3/_utils/module_testing/__init__.py +3 -2
  59. web3/_utils/module_testing/eth_module.py +736 -583
  60. web3/_utils/module_testing/go_ethereum_debug_module.py +128 -0
  61. web3/_utils/module_testing/module_testing_utils.py +81 -24
  62. web3/_utils/module_testing/persistent_connection_provider.py +702 -220
  63. web3/_utils/module_testing/utils.py +114 -33
  64. web3/_utils/module_testing/web3_module.py +438 -17
  65. web3/_utils/normalizers.py +13 -11
  66. web3/_utils/rpc_abi.py +10 -22
  67. web3/_utils/threads.py +8 -7
  68. web3/_utils/transactions.py +32 -25
  69. web3/_utils/type_conversion.py +5 -1
  70. web3/_utils/validation.py +20 -17
  71. web3/beacon/__init__.py +5 -0
  72. web3/beacon/api_endpoints.py +3 -0
  73. web3/beacon/async_beacon.py +29 -6
  74. web3/beacon/beacon.py +24 -6
  75. web3/contract/__init__.py +7 -0
  76. web3/contract/async_contract.py +285 -82
  77. web3/contract/base_contract.py +556 -258
  78. web3/contract/contract.py +295 -84
  79. web3/contract/utils.py +251 -55
  80. web3/datastructures.py +49 -34
  81. web3/eth/__init__.py +7 -0
  82. web3/eth/async_eth.py +89 -69
  83. web3/eth/base_eth.py +7 -3
  84. web3/eth/eth.py +43 -66
  85. web3/exceptions.py +158 -83
  86. web3/gas_strategies/time_based.py +8 -6
  87. web3/geth.py +53 -184
  88. web3/main.py +77 -17
  89. web3/manager.py +362 -95
  90. web3/method.py +43 -15
  91. web3/middleware/__init__.py +17 -0
  92. web3/middleware/attrdict.py +12 -22
  93. web3/middleware/base.py +55 -2
  94. web3/middleware/filter.py +45 -23
  95. web3/middleware/formatting.py +6 -3
  96. web3/middleware/names.py +4 -1
  97. web3/middleware/signing.py +15 -6
  98. web3/middleware/stalecheck.py +2 -1
  99. web3/module.py +61 -25
  100. web3/providers/__init__.py +21 -0
  101. web3/providers/async_base.py +87 -32
  102. web3/providers/base.py +77 -32
  103. web3/providers/eth_tester/__init__.py +5 -0
  104. web3/providers/eth_tester/defaults.py +2 -55
  105. web3/providers/eth_tester/main.py +41 -15
  106. web3/providers/eth_tester/middleware.py +16 -17
  107. web3/providers/ipc.py +41 -17
  108. web3/providers/legacy_websocket.py +26 -1
  109. web3/providers/persistent/__init__.py +7 -0
  110. web3/providers/persistent/async_ipc.py +61 -121
  111. web3/providers/persistent/persistent.py +323 -16
  112. web3/providers/persistent/persistent_connection.py +54 -5
  113. web3/providers/persistent/request_processor.py +136 -56
  114. web3/providers/persistent/subscription_container.py +56 -0
  115. web3/providers/persistent/subscription_manager.py +233 -0
  116. web3/providers/persistent/websocket.py +29 -92
  117. web3/providers/rpc/__init__.py +5 -0
  118. web3/providers/rpc/async_rpc.py +73 -18
  119. web3/providers/rpc/rpc.py +73 -30
  120. web3/providers/rpc/utils.py +1 -13
  121. web3/scripts/install_pre_releases.py +33 -0
  122. web3/scripts/parse_pygeth_version.py +16 -0
  123. web3/testing.py +4 -4
  124. web3/tracing.py +9 -5
  125. web3/types.py +141 -74
  126. web3/utils/__init__.py +64 -5
  127. web3/utils/abi.py +790 -10
  128. web3/utils/address.py +8 -0
  129. web3/utils/async_exception_handling.py +20 -11
  130. web3/utils/caching.py +34 -4
  131. web3/utils/exception_handling.py +9 -12
  132. web3/utils/subscriptions.py +285 -0
  133. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/LICENSE +1 -1
  134. web3-7.7.0.dist-info/METADATA +130 -0
  135. web3-7.7.0.dist-info/RECORD +171 -0
  136. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/WHEEL +1 -1
  137. web3/_utils/caching.py +0 -155
  138. web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
  139. web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
  140. web3/_utils/request.py +0 -265
  141. web3-7.0.0b2.dist-info/METADATA +0 -106
  142. web3-7.0.0b2.dist-info/RECORD +0 -163
  143. /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
  144. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/top_level.txt +0 -0
web3/datastructures.py CHANGED
@@ -15,7 +15,6 @@ from typing import (
15
15
  Optional,
16
16
  Sequence,
17
17
  Tuple,
18
- Type,
19
18
  TypeVar,
20
19
  Union,
21
20
  cast,
@@ -25,8 +24,10 @@ from eth_utils import (
25
24
  is_integer,
26
25
  )
27
26
 
28
- from web3._utils.formatters import (
29
- recursive_map,
27
+ from web3.exceptions import (
28
+ Web3AssertionError,
29
+ Web3TypeError,
30
+ Web3ValueError,
30
31
  )
31
32
 
32
33
  # Hashable must be immutable:
@@ -76,16 +77,18 @@ class ReadableAttributeDict(Mapping[TKey, TValue]):
76
77
  builder.text(")")
77
78
 
78
79
  @classmethod
79
- def _apply_if_mapping(cls: Type[T], value: TValue) -> Union[T, TValue]:
80
+ def recursive(cls, value: TValue) -> Any:
81
+ """
82
+ Recursively convert mappings to ReadableAttributeDict instances and
83
+ process nested collections (e.g., lists, sets, and dictionaries).
84
+ """
80
85
  if isinstance(value, Mapping):
81
- # error: Too many arguments for "object"
82
- return cls(value) # type: ignore
83
- else:
84
- return value
85
-
86
- @classmethod
87
- def recursive(cls, value: TValue) -> "ReadableAttributeDict[TKey, TValue]":
88
- return recursive_map(cls._apply_if_mapping, value)
86
+ return cls({k: cls.recursive(v) for k, v in value.items()})
87
+ elif isinstance(value, Sequence) and not isinstance(value, (str, bytes)):
88
+ return type(value)([cls.recursive(v) for v in value]) # type: ignore
89
+ elif isinstance(value, set):
90
+ return {cls.recursive(v) for v in value}
91
+ return value
89
92
 
90
93
 
91
94
  class MutableAttributeDict(
@@ -100,19 +103,21 @@ class MutableAttributeDict(
100
103
 
101
104
  class AttributeDict(ReadableAttributeDict[TKey, TValue], Hashable):
102
105
  """
103
- This provides superficial immutability, someone could hack around it
106
+ Provides superficial immutability, someone could hack around it
104
107
  """
105
108
 
106
109
  def __setattr__(self, attr: str, val: TValue) -> None:
107
110
  if attr == "__dict__":
108
111
  super().__setattr__(attr, val)
109
112
  else:
110
- raise TypeError(
113
+ raise Web3TypeError(
111
114
  "This data is immutable -- create a copy instead of modifying"
112
115
  )
113
116
 
114
117
  def __delattr__(self, key: str) -> None:
115
- raise TypeError("This data is immutable -- create a copy instead of modifying")
118
+ raise Web3TypeError(
119
+ "This data is immutable -- create a copy instead of modifying"
120
+ )
116
121
 
117
122
  def __hash__(self) -> int:
118
123
  return hash(tuple(sorted(tupleize_lists_nested(self).items())))
@@ -143,7 +148,7 @@ def tupleize_lists_nested(d: Mapping[TKey, TValue]) -> AttributeDict[TKey, TValu
143
148
  elif isinstance(v, Mapping):
144
149
  ret[k] = tupleize_lists_nested(v)
145
150
  elif not isinstance(v, Hashable):
146
- raise TypeError(f"Found unhashable type '{type(v).__name__}': {v}")
151
+ raise Web3TypeError(f"Found unhashable type '{type(v).__name__}': {v}")
147
152
  else:
148
153
  ret[k] = v
149
154
  return AttributeDict(ret)
@@ -172,13 +177,13 @@ class NamedElementOnion(Mapping[TKey, TValue]):
172
177
  if name is None:
173
178
  name = cast(TKey, element)
174
179
 
175
- name = self._repr_if_not_hashable(name)
180
+ name = self._build_name(name)
176
181
 
177
182
  if name in self._queue:
178
183
  if name is element:
179
- raise ValueError("You can't add the same un-named instance twice")
184
+ raise Web3ValueError("You can't add the same un-named instance twice")
180
185
  else:
181
- raise ValueError(
186
+ raise Web3ValueError(
182
187
  "You can't add the same name again, use replace instead"
183
188
  )
184
189
 
@@ -195,7 +200,7 @@ class NamedElementOnion(Mapping[TKey, TValue]):
195
200
  to calling :meth:`add` .
196
201
  """
197
202
  if not is_integer(layer):
198
- raise TypeError("The layer for insertion must be an int.")
203
+ raise Web3TypeError("The layer for insertion must be an int.")
199
204
  elif layer != 0 and layer != len(self._queue):
200
205
  raise NotImplementedError(
201
206
  f"You can only insert to the beginning or end of a {type(self)}, "
@@ -209,13 +214,13 @@ class NamedElementOnion(Mapping[TKey, TValue]):
209
214
  if name is None:
210
215
  name = cast(TKey, element)
211
216
 
212
- name = self._repr_if_not_hashable(name)
217
+ name = self._build_name(name)
213
218
 
214
219
  self._queue.move_to_end(name, last=False)
215
220
  elif layer == len(self._queue):
216
221
  return
217
222
  else:
218
- raise AssertionError(
223
+ raise Web3AssertionError(
219
224
  "Impossible to reach: earlier validation raises an error"
220
225
  )
221
226
 
@@ -223,10 +228,10 @@ class NamedElementOnion(Mapping[TKey, TValue]):
223
228
  self._queue.clear()
224
229
 
225
230
  def replace(self, old: TKey, new: TKey) -> TValue:
226
- old_name = self._repr_if_not_hashable(old)
231
+ old_name = self._build_name(old)
227
232
 
228
233
  if old_name not in self._queue:
229
- raise ValueError(
234
+ raise Web3ValueError(
230
235
  "You can't replace unless one already exists, use add instead"
231
236
  )
232
237
 
@@ -238,17 +243,27 @@ class NamedElementOnion(Mapping[TKey, TValue]):
238
243
  self._queue[old_name] = new
239
244
  return to_be_replaced
240
245
 
241
- def _repr_if_not_hashable(self, value: TKey) -> TKey:
246
+ @staticmethod
247
+ def _build_name(value: TKey) -> TKey:
242
248
  try:
243
249
  value.__hash__()
250
+ return value
244
251
  except TypeError:
245
- value = cast(TKey, repr(value))
246
- return value
252
+ # unhashable, unnamed elements
253
+ if not callable(value):
254
+ raise Web3TypeError(
255
+ f"Expected a callable or hashable type, got {type(value)}"
256
+ )
257
+ # This will either be ``Web3Middleware`` class or the ``build`` method of a
258
+ # ``Web3MiddlewareBuilder``. Instantiate with empty ``Web3`` and use a
259
+ # unique identifier with the ``__hash__()`` as the name.
260
+ v = value(None)
261
+ return cast(TKey, f"{v.__class__}<{v.__hash__()}>")
247
262
 
248
263
  def remove(self, old: TKey) -> None:
249
- old_name = self._repr_if_not_hashable(old)
264
+ old_name = self._build_name(old)
250
265
  if old_name not in self._queue:
251
- raise ValueError("You can only remove something that has been added")
266
+ raise Web3ValueError("You can only remove something that has been added")
252
267
  del self._queue[old_name]
253
268
 
254
269
  @property
@@ -260,8 +275,8 @@ class NamedElementOnion(Mapping[TKey, TValue]):
260
275
  return [(val, key) for key, val in reversed(self._queue.items())]
261
276
 
262
277
  def _replace_with_new_name(self, old: TKey, new: TKey) -> None:
263
- old_name = self._repr_if_not_hashable(old)
264
- new_name = self._repr_if_not_hashable(new)
278
+ old_name = self._build_name(old)
279
+ new_name = self._build_name(new)
265
280
 
266
281
  self._queue[new_name] = new
267
282
  found_old = False
@@ -283,11 +298,11 @@ class NamedElementOnion(Mapping[TKey, TValue]):
283
298
  return NamedElementOnion(cast(List[Any], combined.items()))
284
299
 
285
300
  def __contains__(self, element: Any) -> bool:
286
- element_name = self._repr_if_not_hashable(element)
301
+ element_name = self._build_name(element)
287
302
  return element_name in self._queue
288
303
 
289
304
  def __getitem__(self, element: TKey) -> TValue:
290
- element_name = self._repr_if_not_hashable(element)
305
+ element_name = self._build_name(element)
291
306
  return self._queue[element_name]
292
307
 
293
308
  def __len__(self) -> int:
@@ -310,7 +325,7 @@ class NamedElementOnion(Mapping[TKey, TValue]):
310
325
 
311
326
  def as_tuple_of_middleware(self) -> Tuple[TValue, ...]:
312
327
  """
313
- This helps with type hinting since we return `Iterator[TKey]` type, though it's
328
+ Helps with type hinting since we return `Iterator[TKey]` type, though it's
314
329
  actually a `Iterator[TValue]` type, for the `__iter__()` method. This is in
315
330
  order to satisfy the `Mapping` interface.
316
331
  """
web3/eth/__init__.py CHANGED
@@ -8,3 +8,10 @@ from .eth import (
8
8
  Contract,
9
9
  Eth,
10
10
  )
11
+
12
+ __all__ = [
13
+ "AsyncEth",
14
+ "BaseEth",
15
+ "Contract",
16
+ "Eth",
17
+ ]
web3/eth/async_eth.py CHANGED
@@ -4,6 +4,7 @@ from typing import (
4
4
  Any,
5
5
  Awaitable,
6
6
  Callable,
7
+ Dict,
7
8
  List,
8
9
  Optional,
9
10
  Tuple,
@@ -34,6 +35,9 @@ from web3._utils.async_transactions import (
34
35
  from web3._utils.blocks import (
35
36
  select_method_for_block_identifier,
36
37
  )
38
+ from web3._utils.compat import (
39
+ Unpack,
40
+ )
37
41
  from web3._utils.fee_utils import (
38
42
  async_fee_history_priority_fee,
39
43
  )
@@ -56,12 +60,14 @@ from web3.eth.base_eth import (
56
60
  BaseEth,
57
61
  )
58
62
  from web3.exceptions import (
59
- MethodUnavailable,
63
+ MethodNotSupported,
60
64
  OffchainLookup,
61
65
  TimeExhausted,
62
66
  TooManyRequests,
63
67
  TransactionIndexingInProgress,
64
68
  TransactionNotFound,
69
+ Web3RPCError,
70
+ Web3ValueError,
65
71
  )
66
72
  from web3.method import (
67
73
  Method,
@@ -75,6 +81,7 @@ from web3.types import (
75
81
  BlockData,
76
82
  BlockIdentifier,
77
83
  BlockParams,
84
+ BlockReceipts,
78
85
  CreateAccessListResponse,
79
86
  FeeHistory,
80
87
  FilterParams,
@@ -92,11 +99,16 @@ from web3.types import (
92
99
  _Hash32,
93
100
  )
94
101
  from web3.utils import (
102
+ EthSubscription,
95
103
  async_handle_offchain_lookup,
96
104
  )
105
+ from web3.utils.subscriptions import (
106
+ EthSubscriptionHandler,
107
+ )
97
108
 
98
109
  if TYPE_CHECKING:
99
110
  from web3 import AsyncWeb3 # noqa: F401
111
+ from web3.contract.async_contract import AsyncContractEvent # noqa: F401
100
112
 
101
113
 
102
114
  class AsyncEth(BaseEth):
@@ -105,9 +117,9 @@ class AsyncEth(BaseEth):
105
117
 
106
118
  is_async = True
107
119
 
108
- _default_contract_factory: Type[Union[AsyncContract, AsyncContractCaller]] = (
109
- AsyncContract
110
- )
120
+ _default_contract_factory: Type[
121
+ Union[AsyncContract, AsyncContractCaller]
122
+ ] = AsyncContract
111
123
 
112
124
  # eth_accounts
113
125
 
@@ -120,16 +132,16 @@ class AsyncEth(BaseEth):
120
132
  async def accounts(self) -> Tuple[ChecksumAddress]:
121
133
  return await self._accounts()
122
134
 
123
- # eth_hashrate
135
+ # eth_blobBaseFee
124
136
 
125
- _hashrate: Method[Callable[[], Awaitable[int]]] = Method(
126
- RPC.eth_hashrate,
137
+ _eth_blobBaseFee: Method[Callable[[], Awaitable[Wei]]] = Method(
138
+ RPC.eth_blobBaseFee,
127
139
  is_property=True,
128
140
  )
129
141
 
130
142
  @property
131
- async def hashrate(self) -> int:
132
- return await self._hashrate()
143
+ async def blob_base_fee(self) -> Wei:
144
+ return await self._eth_blobBaseFee()
133
145
 
134
146
  # eth_blockNumber
135
147
 
@@ -153,17 +165,6 @@ class AsyncEth(BaseEth):
153
165
  async def chain_id(self) -> int:
154
166
  return await self._chain_id()
155
167
 
156
- # eth_coinbase
157
-
158
- _coinbase: Method[Callable[[], Awaitable[ChecksumAddress]]] = Method(
159
- RPC.eth_coinbase,
160
- is_property=True,
161
- )
162
-
163
- @property
164
- async def coinbase(self) -> ChecksumAddress:
165
- return await self._coinbase()
166
-
167
168
  # eth_gasPrice
168
169
 
169
170
  _gas_price: Method[Callable[[], Awaitable[Wei]]] = Method(
@@ -191,24 +192,14 @@ class AsyncEth(BaseEth):
191
192
  """
192
193
  try:
193
194
  return await self._max_priority_fee()
194
- except (ValueError, MethodUnavailable):
195
+ except Web3RPCError:
195
196
  warnings.warn(
196
197
  "There was an issue with the method eth_maxPriorityFeePerGas. "
197
- "Calculating using eth_feeHistory."
198
+ "Calculating using eth_feeHistory.",
199
+ stacklevel=2,
198
200
  )
199
201
  return await async_fee_history_priority_fee(self)
200
202
 
201
- # eth_mining
202
-
203
- _mining: Method[Callable[[], Awaitable[bool]]] = Method(
204
- RPC.eth_mining,
205
- is_property=True,
206
- )
207
-
208
- @property
209
- async def mining(self) -> bool:
210
- return await self._mining()
211
-
212
203
  # eth_syncing
213
204
 
214
205
  _syncing: Method[Callable[[], Awaitable[Union[SyncStatus, bool]]]] = Method(
@@ -281,7 +272,7 @@ class AsyncEth(BaseEth):
281
272
  max_redirects = self.w3.provider.ccip_read_max_redirects
282
273
 
283
274
  if not max_redirects or max_redirects < 4:
284
- raise ValueError(
275
+ raise Web3ValueError(
285
276
  "ccip_read_max_redirects property on provider must be at least 4."
286
277
  )
287
278
 
@@ -389,15 +380,15 @@ class AsyncEth(BaseEth):
389
380
  # eth_getBlockTransactionCountByHash
390
381
  # eth_getBlockTransactionCountByNumber
391
382
 
392
- get_block_transaction_count: Method[Callable[[BlockIdentifier], Awaitable[int]]] = (
393
- Method(
394
- method_choice_depends_on_args=select_method_for_block_identifier(
395
- if_predefined=RPC.eth_getBlockTransactionCountByNumber,
396
- if_hash=RPC.eth_getBlockTransactionCountByHash,
397
- if_number=RPC.eth_getBlockTransactionCountByNumber,
398
- ),
399
- mungers=[default_root_munger],
400
- )
383
+ get_block_transaction_count: Method[
384
+ Callable[[BlockIdentifier], Awaitable[int]]
385
+ ] = Method(
386
+ method_choice_depends_on_args=select_method_for_block_identifier(
387
+ if_predefined=RPC.eth_getBlockTransactionCountByNumber,
388
+ if_hash=RPC.eth_getBlockTransactionCountByHash,
389
+ if_number=RPC.eth_getBlockTransactionCountByNumber,
390
+ ),
391
+ mungers=[default_root_munger],
401
392
  )
402
393
 
403
394
  # eth_sendTransaction
@@ -424,15 +415,15 @@ class AsyncEth(BaseEth):
424
415
  # eth_getBlockByHash
425
416
  # eth_getBlockByNumber
426
417
 
427
- _get_block: Method[Callable[[BlockIdentifier, bool], Awaitable[BlockData]]] = (
428
- Method(
429
- method_choice_depends_on_args=select_method_for_block_identifier(
430
- if_predefined=RPC.eth_getBlockByNumber,
431
- if_hash=RPC.eth_getBlockByHash,
432
- if_number=RPC.eth_getBlockByNumber,
433
- ),
434
- mungers=[BaseEth.get_block_munger],
435
- )
418
+ _get_block: Method[
419
+ Callable[[BlockIdentifier, bool], Awaitable[BlockData]]
420
+ ] = Method(
421
+ method_choice_depends_on_args=select_method_for_block_identifier(
422
+ if_predefined=RPC.eth_getBlockByNumber,
423
+ if_hash=RPC.eth_getBlockByHash,
424
+ if_number=RPC.eth_getBlockByNumber,
425
+ ),
426
+ mungers=[BaseEth.get_block_munger],
436
427
  )
437
428
 
438
429
  async def get_block(
@@ -440,6 +431,20 @@ class AsyncEth(BaseEth):
440
431
  ) -> BlockData:
441
432
  return await self._get_block(block_identifier, full_transactions)
442
433
 
434
+ # eth_getBlockReceipts
435
+
436
+ _get_block_receipts: Method[
437
+ Callable[[BlockIdentifier], Awaitable[BlockReceipts]]
438
+ ] = Method(
439
+ RPC.eth_getBlockReceipts,
440
+ mungers=[default_root_munger],
441
+ )
442
+
443
+ async def get_block_receipts(
444
+ self, block_identifier: BlockIdentifier
445
+ ) -> BlockReceipts:
446
+ return await self._get_block_receipts(block_identifier)
447
+
443
448
  # eth_getBalance
444
449
 
445
450
  _get_balance: Method[
@@ -575,10 +580,8 @@ class AsyncEth(BaseEth):
575
580
  self.w3, current_transaction, new_transaction
576
581
  )
577
582
 
578
- # todo: Update Any to stricter kwarg checking with TxParams
579
- # https://github.com/python/mypy/issues/4441
580
583
  async def modify_transaction(
581
- self, transaction_hash: _Hash32, **transaction_params: Any
584
+ self, transaction_hash: _Hash32, **transaction_params: Unpack[TxParams]
582
585
  ) -> HexBytes:
583
586
  assert_valid_transaction_params(cast(TxParams, transaction_params))
584
587
 
@@ -622,14 +625,16 @@ class AsyncEth(BaseEth):
622
625
  # eth_signTypedData
623
626
 
624
627
  _sign_typed_data: Method[
625
- Callable[[Union[Address, ChecksumAddress, ENS], str], Awaitable[HexStr]]
628
+ Callable[
629
+ [Union[Address, ChecksumAddress, ENS], Dict[str, Any]], Awaitable[HexStr]
630
+ ]
626
631
  ] = Method(
627
632
  RPC.eth_signTypedData,
628
633
  mungers=[default_root_munger],
629
634
  )
630
635
 
631
636
  async def sign_typed_data(
632
- self, account: Union[Address, ChecksumAddress, ENS], data: str
637
+ self, account: Union[Address, ChecksumAddress, ENS], data: Dict[str, Any]
633
638
  ) -> HexStr:
634
639
  return await self._sign_typed_data(account, data)
635
640
 
@@ -663,9 +668,9 @@ class AsyncEth(BaseEth):
663
668
 
664
669
  # eth_getFilterChanges, eth_getFilterLogs, eth_uninstallFilter
665
670
 
666
- _get_filter_changes: Method[Callable[[HexStr], Awaitable[List[LogReceipt]]]] = (
667
- Method(RPC.eth_getFilterChanges, mungers=[default_root_munger])
668
- )
671
+ _get_filter_changes: Method[
672
+ Callable[[HexStr], Awaitable[List[LogReceipt]]]
673
+ ] = Method(RPC.eth_getFilterChanges, mungers=[default_root_munger])
669
674
 
670
675
  async def get_filter_changes(self, filter_id: HexStr) -> List[LogReceipt]:
671
676
  return await self._get_filter_changes(filter_id)
@@ -714,17 +719,23 @@ class AsyncEth(BaseEth):
714
719
  bool, # newPendingTransactions, full_transactions
715
720
  ]
716
721
  ] = None,
722
+ handler: Optional[EthSubscriptionHandler] = None,
723
+ handler_context: Optional[Dict[str, Any]] = None,
724
+ label: Optional[str] = None,
717
725
  ) -> HexStr:
718
726
  if not isinstance(self.w3.provider, PersistentConnectionProvider):
719
- raise MethodUnavailable(
727
+ raise MethodNotSupported(
720
728
  "eth_subscribe is only supported with providers that support "
721
729
  "persistent connections."
722
730
  )
723
731
 
724
- if subscription_arg is None:
725
- return await self._subscribe(subscription_type)
726
-
727
- return await self._subscribe_with_args(subscription_type, subscription_arg)
732
+ sub = EthSubscription._create_type_aware_subscription(
733
+ subscription_params=(subscription_type, subscription_arg),
734
+ handler=handler,
735
+ handler_context=handler_context or {},
736
+ label=label,
737
+ )
738
+ return await self.w3.subscription_manager.subscribe(sub)
728
739
 
729
740
  _unsubscribe: Method[Callable[[HexStr], Awaitable[bool]]] = Method(
730
741
  RPC.eth_unsubscribe,
@@ -733,22 +744,31 @@ class AsyncEth(BaseEth):
733
744
 
734
745
  async def unsubscribe(self, subscription_id: HexStr) -> bool:
735
746
  if not isinstance(self.w3.provider, PersistentConnectionProvider):
736
- raise MethodUnavailable(
747
+ raise MethodNotSupported(
737
748
  "eth_unsubscribe is only supported with providers that support "
738
749
  "persistent connections."
739
750
  )
740
751
 
741
- return await self._unsubscribe(subscription_id)
752
+ for sub in self.w3.subscription_manager.subscriptions:
753
+ if sub._id == subscription_id:
754
+ return await sub.unsubscribe()
755
+
756
+ raise Web3ValueError(
757
+ f"Cannot unsubscribe subscription with id `{subscription_id}`. "
758
+ "Subscription not found."
759
+ )
742
760
 
743
761
  # -- contract methods -- #
744
762
 
745
763
  @overload
746
- def contract(self, address: None = None, **kwargs: Any) -> Type[AsyncContract]: ...
764
+ def contract(self, address: None = None, **kwargs: Any) -> Type[AsyncContract]:
765
+ ...
747
766
 
748
767
  @overload
749
768
  def contract(
750
769
  self, address: Union[Address, ChecksumAddress, ENS], **kwargs: Any
751
- ) -> AsyncContract: ...
770
+ ) -> AsyncContract:
771
+ ...
752
772
 
753
773
  def contract(
754
774
  self,
web3/eth/base_eth.py CHANGED
@@ -30,6 +30,10 @@ from web3._utils.empty import (
30
30
  from web3._utils.encoding import (
31
31
  to_hex,
32
32
  )
33
+ from web3.exceptions import (
34
+ Web3TypeError,
35
+ Web3ValueError,
36
+ )
33
37
  from web3.module import (
34
38
  Module,
35
39
  )
@@ -194,7 +198,7 @@ class BaseEth(Module):
194
198
  filter_id: Optional[HexStr] = None,
195
199
  ) -> Union[List[FilterParams], List[HexStr], List[str]]:
196
200
  if filter_id and filter_params:
197
- raise TypeError(
201
+ raise Web3TypeError(
198
202
  "Ambiguous invocation: provide either a `filter_params` or a "
199
203
  "`filter_id` argument. Both were supplied."
200
204
  )
@@ -204,14 +208,14 @@ class BaseEth(Module):
204
208
  if filter_params in {"latest", "pending"}:
205
209
  return [filter_params]
206
210
  else:
207
- raise ValueError(
211
+ raise Web3ValueError(
208
212
  "The filter API only accepts the values of `pending` or "
209
213
  "`latest` for string based filters"
210
214
  )
211
215
  elif filter_id and not filter_params:
212
216
  return [filter_id]
213
217
  else:
214
- raise TypeError(
218
+ raise Web3TypeError(
215
219
  "Must provide either filter_params as a string or "
216
220
  "a valid filter object, or a filter_id as a string "
217
221
  "or hex."