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.
- ens/__init__.py +13 -2
- ens/_normalization.py +4 -4
- ens/async_ens.py +27 -15
- ens/base_ens.py +3 -1
- ens/contract_data.py +2 -2
- ens/ens.py +10 -7
- ens/exceptions.py +16 -29
- ens/specs/nf.json +1 -1
- ens/specs/normalization_spec.json +1 -1
- ens/utils.py +24 -32
- web3/__init__.py +23 -12
- web3/_utils/abi.py +157 -263
- web3/_utils/async_transactions.py +34 -20
- web3/_utils/batching.py +217 -0
- web3/_utils/blocks.py +6 -2
- web3/_utils/caching/__init__.py +12 -0
- web3/_utils/caching/caching_utils.py +433 -0
- web3/_utils/caching/request_caching_validation.py +287 -0
- web3/_utils/compat/__init__.py +2 -3
- web3/_utils/contract_sources/compile_contracts.py +1 -1
- web3/_utils/contract_sources/contract_data/ambiguous_function_contract.py +42 -0
- web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
- web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/event_contracts.py +50 -5
- web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
- web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
- web3/_utils/contracts.py +172 -220
- web3/_utils/datatypes.py +5 -1
- web3/_utils/decorators.py +6 -1
- web3/_utils/empty.py +1 -1
- web3/_utils/encoding.py +16 -12
- web3/_utils/error_formatters_utils.py +5 -3
- web3/_utils/events.py +78 -72
- web3/_utils/fee_utils.py +1 -3
- web3/_utils/filters.py +24 -22
- web3/_utils/formatters.py +2 -2
- web3/_utils/http.py +8 -2
- web3/_utils/http_session_manager.py +314 -0
- web3/_utils/math.py +14 -15
- web3/_utils/method_formatters.py +161 -34
- web3/_utils/module.py +2 -1
- web3/_utils/module_testing/__init__.py +3 -2
- web3/_utils/module_testing/eth_module.py +736 -583
- web3/_utils/module_testing/go_ethereum_debug_module.py +128 -0
- web3/_utils/module_testing/module_testing_utils.py +81 -24
- web3/_utils/module_testing/persistent_connection_provider.py +702 -220
- web3/_utils/module_testing/utils.py +114 -33
- web3/_utils/module_testing/web3_module.py +438 -17
- web3/_utils/normalizers.py +13 -11
- web3/_utils/rpc_abi.py +10 -22
- web3/_utils/threads.py +8 -7
- web3/_utils/transactions.py +32 -25
- web3/_utils/type_conversion.py +5 -1
- web3/_utils/validation.py +20 -17
- web3/beacon/__init__.py +5 -0
- web3/beacon/api_endpoints.py +3 -0
- web3/beacon/async_beacon.py +29 -6
- web3/beacon/beacon.py +24 -6
- web3/contract/__init__.py +7 -0
- web3/contract/async_contract.py +285 -82
- web3/contract/base_contract.py +556 -258
- web3/contract/contract.py +295 -84
- web3/contract/utils.py +251 -55
- web3/datastructures.py +49 -34
- web3/eth/__init__.py +7 -0
- web3/eth/async_eth.py +89 -69
- web3/eth/base_eth.py +7 -3
- web3/eth/eth.py +43 -66
- web3/exceptions.py +158 -83
- web3/gas_strategies/time_based.py +8 -6
- web3/geth.py +53 -184
- web3/main.py +77 -17
- web3/manager.py +362 -95
- web3/method.py +43 -15
- web3/middleware/__init__.py +17 -0
- web3/middleware/attrdict.py +12 -22
- web3/middleware/base.py +55 -2
- web3/middleware/filter.py +45 -23
- web3/middleware/formatting.py +6 -3
- web3/middleware/names.py +4 -1
- web3/middleware/signing.py +15 -6
- web3/middleware/stalecheck.py +2 -1
- web3/module.py +61 -25
- web3/providers/__init__.py +21 -0
- web3/providers/async_base.py +87 -32
- web3/providers/base.py +77 -32
- web3/providers/eth_tester/__init__.py +5 -0
- web3/providers/eth_tester/defaults.py +2 -55
- web3/providers/eth_tester/main.py +41 -15
- web3/providers/eth_tester/middleware.py +16 -17
- web3/providers/ipc.py +41 -17
- web3/providers/legacy_websocket.py +26 -1
- web3/providers/persistent/__init__.py +7 -0
- web3/providers/persistent/async_ipc.py +61 -121
- web3/providers/persistent/persistent.py +323 -16
- web3/providers/persistent/persistent_connection.py +54 -5
- web3/providers/persistent/request_processor.py +136 -56
- web3/providers/persistent/subscription_container.py +56 -0
- web3/providers/persistent/subscription_manager.py +233 -0
- web3/providers/persistent/websocket.py +29 -92
- web3/providers/rpc/__init__.py +5 -0
- web3/providers/rpc/async_rpc.py +73 -18
- web3/providers/rpc/rpc.py +73 -30
- web3/providers/rpc/utils.py +1 -13
- web3/scripts/install_pre_releases.py +33 -0
- web3/scripts/parse_pygeth_version.py +16 -0
- web3/testing.py +4 -4
- web3/tracing.py +9 -5
- web3/types.py +141 -74
- web3/utils/__init__.py +64 -5
- web3/utils/abi.py +790 -10
- web3/utils/address.py +8 -0
- web3/utils/async_exception_handling.py +20 -11
- web3/utils/caching.py +34 -4
- web3/utils/exception_handling.py +9 -12
- web3/utils/subscriptions.py +285 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/LICENSE +1 -1
- web3-7.7.0.dist-info/METADATA +130 -0
- web3-7.7.0.dist-info/RECORD +171 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/WHEEL +1 -1
- web3/_utils/caching.py +0 -155
- web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
- web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
- web3/_utils/request.py +0 -265
- web3-7.0.0b2.dist-info/METADATA +0 -106
- web3-7.0.0b2.dist-info/RECORD +0 -163
- /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/top_level.txt +0 -0
web3/utils/address.py
CHANGED
|
@@ -9,6 +9,9 @@ from eth_utils import (
|
|
|
9
9
|
)
|
|
10
10
|
import rlp
|
|
11
11
|
|
|
12
|
+
from web3.exceptions import (
|
|
13
|
+
Web3ValidationError,
|
|
14
|
+
)
|
|
12
15
|
from web3.types import (
|
|
13
16
|
HexStr,
|
|
14
17
|
Nonce,
|
|
@@ -30,6 +33,11 @@ def get_create2_address(
|
|
|
30
33
|
Determine the resulting `CREATE2` opcode contract address for a sender, salt and
|
|
31
34
|
bytecode.
|
|
32
35
|
"""
|
|
36
|
+
if len(to_bytes(hexstr=salt)) != 32:
|
|
37
|
+
raise Web3ValidationError(
|
|
38
|
+
f"`salt` must be 32 bytes, {len(to_bytes(hexstr=salt))} != 32"
|
|
39
|
+
)
|
|
40
|
+
|
|
33
41
|
contract_address = keccak(
|
|
34
42
|
b"\xff"
|
|
35
43
|
+ to_bytes(hexstr=sender)
|
|
@@ -3,6 +3,10 @@ from typing import (
|
|
|
3
3
|
Dict,
|
|
4
4
|
)
|
|
5
5
|
|
|
6
|
+
from aiohttp import (
|
|
7
|
+
ClientSession,
|
|
8
|
+
ClientTimeout,
|
|
9
|
+
)
|
|
6
10
|
from eth_abi import (
|
|
7
11
|
abi,
|
|
8
12
|
)
|
|
@@ -10,10 +14,8 @@ from eth_typing import (
|
|
|
10
14
|
URI,
|
|
11
15
|
)
|
|
12
16
|
|
|
13
|
-
from web3._utils.
|
|
14
|
-
|
|
15
|
-
async_get_response_from_get_request,
|
|
16
|
-
async_get_response_from_post_request,
|
|
17
|
+
from web3._utils.http import (
|
|
18
|
+
DEFAULT_HTTP_TIMEOUT,
|
|
17
19
|
)
|
|
18
20
|
from web3._utils.type_conversion import (
|
|
19
21
|
to_bytes_if_hex,
|
|
@@ -41,6 +43,7 @@ async def async_handle_offchain_lookup(
|
|
|
41
43
|
"`sender` value does not equal `to` address in transaction."
|
|
42
44
|
)
|
|
43
45
|
|
|
46
|
+
session = ClientSession()
|
|
44
47
|
for url in offchain_lookup_payload["urls"]:
|
|
45
48
|
formatted_url = URI(
|
|
46
49
|
str(url)
|
|
@@ -50,27 +53,30 @@ async def async_handle_offchain_lookup(
|
|
|
50
53
|
|
|
51
54
|
try:
|
|
52
55
|
if "{data}" in url and "{sender}" in url:
|
|
53
|
-
response = await
|
|
54
|
-
|
|
55
|
-
response = await async_get_response_from_post_request(
|
|
56
|
-
formatted_url,
|
|
57
|
-
data={"data": formatted_data, "sender": formatted_sender},
|
|
56
|
+
response = await session.get(
|
|
57
|
+
formatted_url, timeout=ClientTimeout(DEFAULT_HTTP_TIMEOUT)
|
|
58
58
|
)
|
|
59
59
|
else:
|
|
60
|
-
|
|
60
|
+
response = await session.post(
|
|
61
|
+
formatted_url,
|
|
62
|
+
json={"data": formatted_data, "sender": formatted_sender},
|
|
63
|
+
timeout=ClientTimeout(DEFAULT_HTTP_TIMEOUT),
|
|
64
|
+
)
|
|
61
65
|
except Exception:
|
|
62
66
|
continue # try next url if timeout or issues making the request
|
|
63
67
|
|
|
64
68
|
if (
|
|
65
69
|
400 <= response.status <= 499
|
|
66
70
|
): # if request returns 400 error, raise exception
|
|
71
|
+
await session.close()
|
|
67
72
|
response.raise_for_status()
|
|
68
73
|
if not 200 <= response.status <= 299: # if not 400 error, try next url
|
|
69
74
|
continue
|
|
70
75
|
|
|
71
|
-
result = await
|
|
76
|
+
result = await response.json()
|
|
72
77
|
|
|
73
78
|
if "data" not in result.keys():
|
|
79
|
+
await session.close()
|
|
74
80
|
raise Web3ValidationError(
|
|
75
81
|
"Improperly formatted response for offchain lookup HTTP request"
|
|
76
82
|
" - missing 'data' field."
|
|
@@ -91,5 +97,8 @@ async def async_handle_offchain_lookup(
|
|
|
91
97
|
]
|
|
92
98
|
)
|
|
93
99
|
|
|
100
|
+
await session.close()
|
|
94
101
|
return encoded_data_with_function_selector
|
|
102
|
+
|
|
103
|
+
await session.close()
|
|
95
104
|
raise MultipleFailedRequests("Offchain lookup failed for supplied urls.")
|
web3/utils/caching.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
from collections import (
|
|
2
3
|
OrderedDict,
|
|
3
4
|
)
|
|
5
|
+
from enum import (
|
|
6
|
+
Enum,
|
|
7
|
+
)
|
|
8
|
+
import time
|
|
4
9
|
from typing import (
|
|
5
10
|
Any,
|
|
6
11
|
Dict,
|
|
@@ -10,28 +15,31 @@ from typing import (
|
|
|
10
15
|
)
|
|
11
16
|
|
|
12
17
|
|
|
18
|
+
class RequestCacheValidationThreshold(Enum):
|
|
19
|
+
FINALIZED = "finalized"
|
|
20
|
+
SAFE = "safe"
|
|
21
|
+
|
|
22
|
+
|
|
13
23
|
class SimpleCache:
|
|
14
24
|
def __init__(self, size: int = 100):
|
|
15
25
|
self._size = size
|
|
16
26
|
self._data: OrderedDict[str, Any] = OrderedDict()
|
|
17
27
|
|
|
18
28
|
def cache(self, key: str, value: Any) -> Tuple[Any, Dict[str, Any]]:
|
|
19
|
-
evicted_items =
|
|
29
|
+
evicted_items = {}
|
|
20
30
|
# If the key is already in the OrderedDict just update it
|
|
21
31
|
# and don't evict any values. Ideally, we could still check to see
|
|
22
32
|
# if there are too many items in the OrderedDict but that may rearrange
|
|
23
33
|
# the order it should be unlikely that the size could grow over the limit
|
|
24
34
|
if key not in self._data:
|
|
25
35
|
while len(self._data) >= self._size:
|
|
26
|
-
if evicted_items is None:
|
|
27
|
-
evicted_items = {}
|
|
28
36
|
k, v = self._data.popitem(last=False)
|
|
29
37
|
evicted_items[k] = v
|
|
30
38
|
self._data[key] = value
|
|
31
39
|
|
|
32
40
|
# Return the cached value along with the evicted items at the same time. No
|
|
33
41
|
# need to reach back into the cache to grab the value.
|
|
34
|
-
return value, evicted_items
|
|
42
|
+
return value, evicted_items or None
|
|
35
43
|
|
|
36
44
|
def get_cache_entry(self, key: str) -> Optional[Any]:
|
|
37
45
|
return self._data[key] if key in self._data else None
|
|
@@ -48,8 +56,30 @@ class SimpleCache:
|
|
|
48
56
|
|
|
49
57
|
return self._data.pop(key)
|
|
50
58
|
|
|
59
|
+
def popitem(self, last: bool = True) -> Tuple[str, Any]:
|
|
60
|
+
return self._data.popitem(last=last)
|
|
61
|
+
|
|
51
62
|
def __contains__(self, key: str) -> bool:
|
|
52
63
|
return key in self._data
|
|
53
64
|
|
|
54
65
|
def __len__(self) -> int:
|
|
55
66
|
return len(self._data)
|
|
67
|
+
|
|
68
|
+
# -- async utility methods -- #
|
|
69
|
+
|
|
70
|
+
async def async_await_and_popitem(
|
|
71
|
+
self, last: bool = True, timeout: float = 10.0
|
|
72
|
+
) -> Tuple[str, Any]:
|
|
73
|
+
start = time.time()
|
|
74
|
+
end_time = start + timeout
|
|
75
|
+
while True:
|
|
76
|
+
await asyncio.sleep(0)
|
|
77
|
+
try:
|
|
78
|
+
return self.popitem(last=last)
|
|
79
|
+
except KeyError:
|
|
80
|
+
now = time.time()
|
|
81
|
+
if now >= end_time:
|
|
82
|
+
raise asyncio.TimeoutError(
|
|
83
|
+
"Timeout waiting for item to be available"
|
|
84
|
+
)
|
|
85
|
+
await asyncio.sleep(min(0.1, end_time - now))
|
web3/utils/exception_handling.py
CHANGED
|
@@ -9,10 +9,10 @@ from eth_abi import (
|
|
|
9
9
|
from eth_typing import (
|
|
10
10
|
URI,
|
|
11
11
|
)
|
|
12
|
+
import requests
|
|
12
13
|
|
|
13
|
-
from web3._utils.
|
|
14
|
-
|
|
15
|
-
get_response_from_post_request,
|
|
14
|
+
from web3._utils.http import (
|
|
15
|
+
DEFAULT_HTTP_TIMEOUT,
|
|
16
16
|
)
|
|
17
17
|
from web3._utils.type_conversion import (
|
|
18
18
|
to_bytes_if_hex,
|
|
@@ -40,6 +40,7 @@ def handle_offchain_lookup(
|
|
|
40
40
|
"Returned `sender` value does not equal `to` address in transaction."
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
+
session = requests.Session()
|
|
43
44
|
for url in offchain_lookup_payload["urls"]:
|
|
44
45
|
formatted_url = URI(
|
|
45
46
|
str(url)
|
|
@@ -49,17 +50,13 @@ def handle_offchain_lookup(
|
|
|
49
50
|
|
|
50
51
|
try:
|
|
51
52
|
if "{data}" in url and "{sender}" in url:
|
|
52
|
-
response =
|
|
53
|
-
|
|
54
|
-
response =
|
|
53
|
+
response = session.get(formatted_url, timeout=DEFAULT_HTTP_TIMEOUT)
|
|
54
|
+
else:
|
|
55
|
+
response = session.post(
|
|
55
56
|
formatted_url,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"sender": formatted_sender,
|
|
59
|
-
},
|
|
57
|
+
json={"data": formatted_data, "sender": formatted_sender},
|
|
58
|
+
timeout=DEFAULT_HTTP_TIMEOUT,
|
|
60
59
|
)
|
|
61
|
-
else:
|
|
62
|
-
raise Web3ValidationError("url not formatted properly.")
|
|
63
60
|
except Exception:
|
|
64
61
|
continue # try next url if timeout or issues making the request
|
|
65
62
|
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
TYPE_CHECKING,
|
|
3
|
+
Any,
|
|
4
|
+
Callable,
|
|
5
|
+
Coroutine,
|
|
6
|
+
Dict,
|
|
7
|
+
Generic,
|
|
8
|
+
List,
|
|
9
|
+
Optional,
|
|
10
|
+
Sequence,
|
|
11
|
+
TypeVar,
|
|
12
|
+
Union,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from eth_typing import (
|
|
16
|
+
Address,
|
|
17
|
+
ChecksumAddress,
|
|
18
|
+
HexStr,
|
|
19
|
+
)
|
|
20
|
+
from hexbytes import (
|
|
21
|
+
HexBytes,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from web3.exceptions import (
|
|
25
|
+
Web3AttributeError,
|
|
26
|
+
Web3ValueError,
|
|
27
|
+
)
|
|
28
|
+
from web3.types import (
|
|
29
|
+
BlockData,
|
|
30
|
+
FilterParams,
|
|
31
|
+
LogReceipt,
|
|
32
|
+
SyncProgress,
|
|
33
|
+
TxData,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from web3 import (
|
|
38
|
+
AsyncWeb3,
|
|
39
|
+
)
|
|
40
|
+
from web3.providers.persistent.subscription_manager import (
|
|
41
|
+
SubscriptionManager,
|
|
42
|
+
)
|
|
43
|
+
from web3.types import EthSubscriptionResult # noqa: F401
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
TSubscriptionResult = TypeVar("TSubscriptionResult", bound="EthSubscriptionResult")
|
|
47
|
+
TSubscription = TypeVar("TSubscription", bound="EthSubscription[Any]")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class EthSubscriptionContext(Generic[TSubscription, TSubscriptionResult]):
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
async_w3: "AsyncWeb3",
|
|
54
|
+
subscription: TSubscription,
|
|
55
|
+
result: TSubscriptionResult,
|
|
56
|
+
**kwargs: Any,
|
|
57
|
+
) -> None:
|
|
58
|
+
self.async_w3 = async_w3
|
|
59
|
+
self.subscription = subscription
|
|
60
|
+
self.result = result
|
|
61
|
+
self.__dict__.update(kwargs)
|
|
62
|
+
|
|
63
|
+
def __getattr__(self, item: str) -> Any:
|
|
64
|
+
if item in self.__dict__:
|
|
65
|
+
return self.__dict__[item]
|
|
66
|
+
raise Web3AttributeError(
|
|
67
|
+
f"'{self.__class__.__name__}' object has no attribute '{item}'"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
EthSubscriptionHandler = Callable[
|
|
72
|
+
[EthSubscriptionContext[Any, Any]], Coroutine[Any, Any, None]
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def handler_wrapper(
|
|
77
|
+
handler: Optional[EthSubscriptionHandler],
|
|
78
|
+
) -> Optional[EthSubscriptionHandler]:
|
|
79
|
+
"""Wrap the handler to add bookkeeping and context creation."""
|
|
80
|
+
if handler is None:
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
async def wrapped_handler(
|
|
84
|
+
context: EthSubscriptionContext[TSubscription, TSubscriptionResult],
|
|
85
|
+
) -> None:
|
|
86
|
+
sub = context.subscription
|
|
87
|
+
sub.handler_call_count += 1
|
|
88
|
+
sub.manager.total_handler_calls += 1
|
|
89
|
+
sub.manager.logger.debug(
|
|
90
|
+
f"Subscription handler called.\n"
|
|
91
|
+
f" label: {sub.label}\n"
|
|
92
|
+
f" call count: {sub.handler_call_count}\n"
|
|
93
|
+
f" total handler calls: {sub.manager.total_handler_calls}"
|
|
94
|
+
)
|
|
95
|
+
await handler(context)
|
|
96
|
+
|
|
97
|
+
return wrapped_handler
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class EthSubscription(Generic[TSubscriptionResult]):
|
|
101
|
+
_id: HexStr = None
|
|
102
|
+
manager: "SubscriptionManager" = None
|
|
103
|
+
|
|
104
|
+
def __init__(
|
|
105
|
+
self: TSubscription,
|
|
106
|
+
subscription_params: Optional[Sequence[Any]] = None,
|
|
107
|
+
handler: Optional[EthSubscriptionHandler] = None,
|
|
108
|
+
handler_context: Optional[Dict[str, Any]] = None,
|
|
109
|
+
label: Optional[str] = None,
|
|
110
|
+
) -> None:
|
|
111
|
+
self._subscription_params = subscription_params
|
|
112
|
+
self._handler = handler_wrapper(handler)
|
|
113
|
+
self._handler_context = handler_context or {}
|
|
114
|
+
self._label = label
|
|
115
|
+
self.handler_call_count = 0
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def _create_type_aware_subscription(
|
|
119
|
+
cls,
|
|
120
|
+
subscription_params: Optional[Sequence[Any]],
|
|
121
|
+
handler: Optional[EthSubscriptionHandler] = None,
|
|
122
|
+
handler_context: Optional[Dict[str, Any]] = None,
|
|
123
|
+
label: Optional[str] = None,
|
|
124
|
+
) -> "EthSubscription[Any]":
|
|
125
|
+
subscription_type = subscription_params[0]
|
|
126
|
+
subscription_arg = (
|
|
127
|
+
subscription_params[1] if len(subscription_params) > 1 else None
|
|
128
|
+
)
|
|
129
|
+
if subscription_type == "newHeads":
|
|
130
|
+
return NewHeadsSubscription(
|
|
131
|
+
handler=handler, handler_context=handler_context, label=label
|
|
132
|
+
)
|
|
133
|
+
elif subscription_type == "logs":
|
|
134
|
+
subscription_arg = subscription_arg or {}
|
|
135
|
+
return LogsSubscription(
|
|
136
|
+
**subscription_arg,
|
|
137
|
+
handler=handler,
|
|
138
|
+
handler_context=handler_context,
|
|
139
|
+
label=label,
|
|
140
|
+
)
|
|
141
|
+
elif subscription_type == "newPendingTransactions":
|
|
142
|
+
subscription_arg = subscription_arg or False
|
|
143
|
+
return PendingTxSubscription(
|
|
144
|
+
full_transactions=subscription_arg,
|
|
145
|
+
handler=handler,
|
|
146
|
+
handler_context=handler_context,
|
|
147
|
+
label=label,
|
|
148
|
+
)
|
|
149
|
+
elif subscription_type == "syncing":
|
|
150
|
+
return SyncingSubscription(
|
|
151
|
+
handler=handler, handler_context=handler_context, label=label
|
|
152
|
+
)
|
|
153
|
+
else:
|
|
154
|
+
params = (
|
|
155
|
+
(subscription_type, subscription_arg)
|
|
156
|
+
if subscription_arg
|
|
157
|
+
else (subscription_type,)
|
|
158
|
+
)
|
|
159
|
+
return cls(
|
|
160
|
+
params,
|
|
161
|
+
handler=handler,
|
|
162
|
+
handler_context=handler_context,
|
|
163
|
+
label=label,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def subscription_params(self) -> Sequence[Any]:
|
|
168
|
+
return self._subscription_params
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def label(self) -> str:
|
|
172
|
+
if not self._label:
|
|
173
|
+
self._label = f"{self.__class__.__name__}{self.subscription_params}"
|
|
174
|
+
return self._label
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def id(self) -> HexStr:
|
|
178
|
+
if not self._id:
|
|
179
|
+
raise Web3ValueError("No `id` found for subscription.")
|
|
180
|
+
return self._id
|
|
181
|
+
|
|
182
|
+
async def unsubscribe(self) -> bool:
|
|
183
|
+
return await self.manager.unsubscribe(self)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
LogsSubscriptionContext = EthSubscriptionContext[
|
|
187
|
+
"LogsSubscription", "EthSubscriptionResult"
|
|
188
|
+
]
|
|
189
|
+
LogsSubscriptionHandler = Callable[[LogsSubscriptionContext], Coroutine[Any, Any, None]]
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class LogsSubscription(EthSubscription[LogReceipt]):
|
|
193
|
+
def __init__(
|
|
194
|
+
self,
|
|
195
|
+
address: Optional[
|
|
196
|
+
Union[Address, ChecksumAddress, List[Address], List[ChecksumAddress]]
|
|
197
|
+
] = None,
|
|
198
|
+
topics: Optional[List[HexStr]] = None,
|
|
199
|
+
handler: LogsSubscriptionHandler = None,
|
|
200
|
+
handler_context: Optional[Dict[str, Any]] = None,
|
|
201
|
+
label: Optional[str] = None,
|
|
202
|
+
) -> None:
|
|
203
|
+
self.address = address
|
|
204
|
+
self.topics = topics
|
|
205
|
+
|
|
206
|
+
logs_filter: FilterParams = {}
|
|
207
|
+
if address:
|
|
208
|
+
logs_filter["address"] = address
|
|
209
|
+
if topics:
|
|
210
|
+
logs_filter["topics"] = topics
|
|
211
|
+
self.logs_filter = logs_filter
|
|
212
|
+
|
|
213
|
+
super().__init__(
|
|
214
|
+
subscription_params=("logs", logs_filter),
|
|
215
|
+
handler=handler,
|
|
216
|
+
handler_context=handler_context,
|
|
217
|
+
label=label,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
NewHeadsSubscriptionContext = EthSubscriptionContext["NewHeadsSubscription", BlockData]
|
|
222
|
+
NewHeadsSubscriptionHandler = Callable[
|
|
223
|
+
[NewHeadsSubscriptionContext], Coroutine[Any, Any, None]
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class NewHeadsSubscription(EthSubscription[BlockData]):
|
|
228
|
+
def __init__(
|
|
229
|
+
self,
|
|
230
|
+
label: Optional[str] = None,
|
|
231
|
+
handler: Optional[NewHeadsSubscriptionHandler] = None,
|
|
232
|
+
handler_context: Optional[Dict[str, Any]] = None,
|
|
233
|
+
) -> None:
|
|
234
|
+
super().__init__(
|
|
235
|
+
subscription_params=("newHeads",),
|
|
236
|
+
handler=handler,
|
|
237
|
+
handler_context=handler_context,
|
|
238
|
+
label=label,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
PendingTxSubscriptionContext = EthSubscriptionContext[
|
|
243
|
+
"PendingTxSubscription", Union[HexBytes, TxData]
|
|
244
|
+
]
|
|
245
|
+
PendingTxSubscriptionHandler = Callable[
|
|
246
|
+
[PendingTxSubscriptionContext], Coroutine[Any, Any, None]
|
|
247
|
+
]
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class PendingTxSubscription(EthSubscription[Union[HexBytes, TxData]]):
|
|
251
|
+
def __init__(
|
|
252
|
+
self,
|
|
253
|
+
full_transactions: bool = False,
|
|
254
|
+
label: Optional[str] = None,
|
|
255
|
+
handler: Optional[PendingTxSubscriptionHandler] = None,
|
|
256
|
+
handler_context: Optional[Dict[str, Any]] = None,
|
|
257
|
+
) -> None:
|
|
258
|
+
self.full_transactions = full_transactions
|
|
259
|
+
super().__init__(
|
|
260
|
+
subscription_params=("newPendingTransactions", full_transactions),
|
|
261
|
+
handler=handler,
|
|
262
|
+
handler_context=handler_context,
|
|
263
|
+
label=label,
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
SyncingSubscriptionContext = EthSubscriptionContext["SyncingSubscription", SyncProgress]
|
|
268
|
+
SyncingSubscriptionHandler = Callable[
|
|
269
|
+
[SyncingSubscriptionContext], Coroutine[Any, Any, None]
|
|
270
|
+
]
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class SyncingSubscription(EthSubscription[SyncProgress]):
|
|
274
|
+
def __init__(
|
|
275
|
+
self,
|
|
276
|
+
label: Optional[str] = None,
|
|
277
|
+
handler: Optional[SyncingSubscriptionHandler] = None,
|
|
278
|
+
handler_context: Optional[Dict[str, Any]] = None,
|
|
279
|
+
) -> None:
|
|
280
|
+
super().__init__(
|
|
281
|
+
subscription_params=("syncing",),
|
|
282
|
+
handler=handler,
|
|
283
|
+
handler_context=handler_context,
|
|
284
|
+
label=label,
|
|
285
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2016 The Ethereum Foundation
|
|
3
|
+
Copyright (c) 2016-2024 The Ethereum Foundation
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: web3
|
|
3
|
+
Version: 7.7.0
|
|
4
|
+
Summary: web3: A Python library for interacting with Ethereum
|
|
5
|
+
Home-page: https://github.com/ethereum/web3.py
|
|
6
|
+
Author: The Ethereum Foundation
|
|
7
|
+
Author-email: snakecharmers@ethereum.org
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: ethereum
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Requires-Python: >=3.8, <4
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: eth-abi>=5.0.1
|
|
25
|
+
Requires-Dist: eth-account>=0.13.1
|
|
26
|
+
Requires-Dist: eth-hash[pycryptodome]>=0.5.1
|
|
27
|
+
Requires-Dist: eth-typing>=5.0.0
|
|
28
|
+
Requires-Dist: eth-utils>=5.0.0
|
|
29
|
+
Requires-Dist: hexbytes>=1.2.0
|
|
30
|
+
Requires-Dist: aiohttp>=3.7.4.post0
|
|
31
|
+
Requires-Dist: pydantic>=2.4.0
|
|
32
|
+
Requires-Dist: pywin32>=223; platform_system == "Windows"
|
|
33
|
+
Requires-Dist: requests>=2.23.0
|
|
34
|
+
Requires-Dist: typing-extensions>=4.0.1
|
|
35
|
+
Requires-Dist: types-requests>=2.0.0
|
|
36
|
+
Requires-Dist: websockets<14.0.0,>=10.0.0
|
|
37
|
+
Requires-Dist: pyunormalize>=15.0.0
|
|
38
|
+
Provides-Extra: tester
|
|
39
|
+
Requires-Dist: eth-tester[py-evm]<0.13.0b1,>=0.12.0b1; extra == "tester"
|
|
40
|
+
Requires-Dist: py-geth>=5.1.0; extra == "tester"
|
|
41
|
+
Provides-Extra: dev
|
|
42
|
+
Requires-Dist: build>=0.9.0; extra == "dev"
|
|
43
|
+
Requires-Dist: bumpversion>=0.5.3; extra == "dev"
|
|
44
|
+
Requires-Dist: ipython; extra == "dev"
|
|
45
|
+
Requires-Dist: setuptools>=38.6.0; extra == "dev"
|
|
46
|
+
Requires-Dist: tqdm>4.32; extra == "dev"
|
|
47
|
+
Requires-Dist: twine>=1.13; extra == "dev"
|
|
48
|
+
Requires-Dist: wheel; extra == "dev"
|
|
49
|
+
Requires-Dist: sphinx>=6.0.0; extra == "dev"
|
|
50
|
+
Requires-Dist: sphinx-autobuild>=2021.3.14; extra == "dev"
|
|
51
|
+
Requires-Dist: sphinx_rtd_theme>=1.0.0; extra == "dev"
|
|
52
|
+
Requires-Dist: towncrier<22,>=21; extra == "dev"
|
|
53
|
+
Requires-Dist: pytest-asyncio<0.23,>=0.18.1; extra == "dev"
|
|
54
|
+
Requires-Dist: pytest-mock>=1.10; extra == "dev"
|
|
55
|
+
Requires-Dist: pytest-xdist>=2.4.0; extra == "dev"
|
|
56
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
57
|
+
Requires-Dist: flaky>=3.7.0; extra == "dev"
|
|
58
|
+
Requires-Dist: hypothesis>=3.31.2; extra == "dev"
|
|
59
|
+
Requires-Dist: tox>=4.0.0; extra == "dev"
|
|
60
|
+
Requires-Dist: mypy==1.10.0; extra == "dev"
|
|
61
|
+
Requires-Dist: pre-commit>=3.4.0; extra == "dev"
|
|
62
|
+
Requires-Dist: eth-tester[py-evm]<0.13.0b1,>=0.12.0b1; extra == "dev"
|
|
63
|
+
Requires-Dist: py-geth>=5.1.0; extra == "dev"
|
|
64
|
+
Provides-Extra: docs
|
|
65
|
+
Requires-Dist: sphinx>=6.0.0; extra == "docs"
|
|
66
|
+
Requires-Dist: sphinx-autobuild>=2021.3.14; extra == "docs"
|
|
67
|
+
Requires-Dist: sphinx_rtd_theme>=1.0.0; extra == "docs"
|
|
68
|
+
Requires-Dist: towncrier<22,>=21; extra == "docs"
|
|
69
|
+
Provides-Extra: test
|
|
70
|
+
Requires-Dist: pytest-asyncio<0.23,>=0.18.1; extra == "test"
|
|
71
|
+
Requires-Dist: pytest-mock>=1.10; extra == "test"
|
|
72
|
+
Requires-Dist: pytest-xdist>=2.4.0; extra == "test"
|
|
73
|
+
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
74
|
+
Requires-Dist: flaky>=3.7.0; extra == "test"
|
|
75
|
+
Requires-Dist: hypothesis>=3.31.2; extra == "test"
|
|
76
|
+
Requires-Dist: tox>=4.0.0; extra == "test"
|
|
77
|
+
Requires-Dist: mypy==1.10.0; extra == "test"
|
|
78
|
+
Requires-Dist: pre-commit>=3.4.0; extra == "test"
|
|
79
|
+
Requires-Dist: eth-tester[py-evm]<0.13.0b1,>=0.12.0b1; extra == "test"
|
|
80
|
+
Requires-Dist: py-geth>=5.1.0; extra == "test"
|
|
81
|
+
Dynamic: author
|
|
82
|
+
Dynamic: author-email
|
|
83
|
+
Dynamic: classifier
|
|
84
|
+
Dynamic: description
|
|
85
|
+
Dynamic: description-content-type
|
|
86
|
+
Dynamic: home-page
|
|
87
|
+
Dynamic: keywords
|
|
88
|
+
Dynamic: license
|
|
89
|
+
Dynamic: provides-extra
|
|
90
|
+
Dynamic: requires-dist
|
|
91
|
+
Dynamic: requires-python
|
|
92
|
+
Dynamic: summary
|
|
93
|
+
|
|
94
|
+
# web3.py
|
|
95
|
+
|
|
96
|
+
[](https://discord.gg/GHryRvPB84)
|
|
97
|
+
[](https://circleci.com/gh/ethereum/web3.py)
|
|
98
|
+
[](https://badge.fury.io/py/web3)
|
|
99
|
+
[](https://pypi.python.org/pypi/web3)
|
|
100
|
+
[](https://web3py.readthedocs.io/en/latest/?badge=latest)
|
|
101
|
+
|
|
102
|
+
## A Python Library for Interacting with Ethereum
|
|
103
|
+
|
|
104
|
+
web3.py allows you to interact with the Ethereum blockchain using Python, enabling you to build decentralized applications, interact with smart contracts, and much more.
|
|
105
|
+
|
|
106
|
+
- Python 3.8+ support
|
|
107
|
+
|
|
108
|
+
______________________________________________________________________
|
|
109
|
+
|
|
110
|
+
## Quickstart
|
|
111
|
+
|
|
112
|
+
[Get started in 5 minutes](https://web3py.readthedocs.io/en/latest/quickstart.html) or
|
|
113
|
+
[take a tour](https://web3py.readthedocs.io/en/latest/overview.html) of the library.
|
|
114
|
+
|
|
115
|
+
## Documentation
|
|
116
|
+
|
|
117
|
+
For additional guides, examples, and APIs, see the [documentation](https://web3py.readthedocs.io/en/latest/).
|
|
118
|
+
|
|
119
|
+
## Want to Help?
|
|
120
|
+
|
|
121
|
+
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
|
|
122
|
+
guidelines for [contributing](https://web3py.readthedocs.io/en/latest/contributing.html),
|
|
123
|
+
then check out issues that are labeled
|
|
124
|
+
[Good First Issue](https://github.com/ethereum/web3.py/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+First+Issue%22).
|
|
125
|
+
|
|
126
|
+
______________________________________________________________________
|
|
127
|
+
|
|
128
|
+
## Questions on Implementation or Usage?
|
|
129
|
+
|
|
130
|
+
Join the conversation in the Ethereum Python Community [Discord](https://discord.gg/GHryRvPB84).
|