py-near 1.1.14__py3-none-any.whl → 1.1.16__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.
- py_near/account.py +7 -2
- py_near/exceptions/provider.py +1 -1
- py_near/providers.py +73 -23
- {py_near-1.1.14.dist-info → py_near-1.1.16.dist-info}/METADATA +2 -1
- {py_near-1.1.14.dist-info → py_near-1.1.16.dist-info}/RECORD +7 -7
- {py_near-1.1.14.dist-info → py_near-1.1.16.dist-info}/WHEEL +1 -1
- {py_near-1.1.14.dist-info → py_near-1.1.16.dist-info}/LICENSE +0 -0
py_near/account.py
CHANGED
@@ -368,17 +368,22 @@ class Account(object):
|
|
368
368
|
)
|
369
369
|
|
370
370
|
async def view_function(
|
371
|
-
self,
|
371
|
+
self,
|
372
|
+
contract_id: str,
|
373
|
+
method_name: str,
|
374
|
+
args: dict,
|
375
|
+
block_id: Optional[int] = None,
|
372
376
|
) -> ViewFunctionResult:
|
373
377
|
"""
|
374
378
|
Call view function on smart contract. View function is read only function, it can't change state
|
375
379
|
:param contract_id: smart contract account id
|
376
380
|
:param method_name: method name to call
|
377
381
|
:param args: json args to call method
|
382
|
+
:param block_id: execution view transaction in block with given id
|
378
383
|
:return: result of view function call
|
379
384
|
"""
|
380
385
|
result = await self._provider.view_call(
|
381
|
-
contract_id, method_name, json.dumps(args).encode("utf8")
|
386
|
+
contract_id, method_name, json.dumps(args).encode("utf8"), block_id=block_id
|
382
387
|
)
|
383
388
|
if "error" in result:
|
384
389
|
raise ViewFunctionError(result["error"])
|
py_near/exceptions/provider.py
CHANGED
@@ -119,7 +119,7 @@ class InvalidTransactionError(TransactionError):
|
|
119
119
|
|
120
120
|
|
121
121
|
class TxExecutionError(InvalidTransactionError):
|
122
|
-
def __init__(self, data, error_json=None, **kwargs):
|
122
|
+
def __init__(self, data={}, error_json=None, **kwargs):
|
123
123
|
super().__init__(error_json=error_json)
|
124
124
|
if isinstance(data, str):
|
125
125
|
data = json.loads(data)
|
py_near/providers.py
CHANGED
@@ -6,7 +6,7 @@ from typing import Optional
|
|
6
6
|
import aiohttp
|
7
7
|
from aiohttp import ClientResponseError, ClientConnectorError, ServerDisconnectedError
|
8
8
|
from loguru import logger
|
9
|
-
|
9
|
+
import datetime
|
10
10
|
from py_near import constants
|
11
11
|
from py_near.constants import TIMEOUT_WAIT_RPC
|
12
12
|
from py_near.exceptions.exceptions import RpcNotAvailableError
|
@@ -51,21 +51,67 @@ class JsonProvider(object):
|
|
51
51
|
self._rpc_addresses = rpc_addr
|
52
52
|
else:
|
53
53
|
self._rpc_addresses = [rpc_addr]
|
54
|
+
self._available_rpcs = self._rpc_addresses.copy()
|
55
|
+
self._last_rpc_addr_check = 0
|
56
|
+
|
57
|
+
async def check_available_rpcs(self):
|
58
|
+
available_rpcs = []
|
59
|
+
for rpc_addr in self._rpc_addresses:
|
60
|
+
try:
|
61
|
+
async with aiohttp.ClientSession() as session:
|
62
|
+
timestamp_start = datetime.datetime.utcnow().timestamp()
|
63
|
+
r = await session.get(
|
64
|
+
"%s/status" % rpc_addr, timeout=TIMEOUT_WAIT_RPC
|
65
|
+
)
|
66
|
+
if r.status == 200:
|
67
|
+
data = json.loads(await r.text())
|
68
|
+
if not data["sync_info"]["syncing"]:
|
69
|
+
available_rpcs.append(
|
70
|
+
(
|
71
|
+
rpc_addr,
|
72
|
+
datetime.datetime.utcnow().timestamp()
|
73
|
+
- timestamp_start,
|
74
|
+
)
|
75
|
+
)
|
76
|
+
continue
|
77
|
+
if rpc_addr in self._available_rpcs:
|
78
|
+
if r.status == 200:
|
79
|
+
logger.error(f"Remove async RPC : {rpc_addr}")
|
80
|
+
else:
|
81
|
+
logger.error(
|
82
|
+
f"Remove rpc because of error {r.status}: {rpc_addr}"
|
83
|
+
)
|
84
|
+
except Exception as e:
|
85
|
+
if rpc_addr in self._available_rpcs:
|
86
|
+
logger.error(f"Remove rpc: {e}")
|
87
|
+
self._available_rpcs = [
|
88
|
+
r[0] for r in sorted(available_rpcs, key=lambda x: x[1])
|
89
|
+
]
|
54
90
|
|
55
91
|
async def call_rpc_request(self, method, params, timeout=TIMEOUT_WAIT_RPC):
|
92
|
+
if (
|
93
|
+
self._last_rpc_addr_check < datetime.datetime.now().timestamp() - 30
|
94
|
+
or not self._available_rpcs
|
95
|
+
):
|
96
|
+
self._last_rpc_addr_check = datetime.datetime.now().timestamp()
|
97
|
+
if self._available_rpcs:
|
98
|
+
asyncio.create_task(self.check_available_rpcs())
|
99
|
+
else:
|
100
|
+
logger.warning("No RPC available, rechecking")
|
101
|
+
await self.check_available_rpcs()
|
102
|
+
|
103
|
+
if not self._available_rpcs:
|
104
|
+
raise RpcNotAvailableError("No RPC available")
|
105
|
+
|
56
106
|
j = {"method": method, "params": params, "id": "dontcare", "jsonrpc": "2.0"}
|
57
107
|
|
58
108
|
content = None
|
59
|
-
for rpc_addr in self.
|
109
|
+
for rpc_addr in self._available_rpcs:
|
60
110
|
try:
|
61
111
|
async with aiohttp.ClientSession() as session:
|
62
112
|
r = await session.post(rpc_addr, json=j, timeout=timeout)
|
63
113
|
r.raise_for_status()
|
64
114
|
content = json.loads(await r.text())
|
65
|
-
if self._rpc_addresses[0] != rpc_addr:
|
66
|
-
logger.info(f"Rpc update: {rpc_addr}")
|
67
|
-
self._rpc_addresses.remove(rpc_addr)
|
68
|
-
self._rpc_addresses.insert(0, rpc_addr)
|
69
115
|
break
|
70
116
|
except (
|
71
117
|
RPCTimeoutError,
|
@@ -154,7 +200,7 @@ class JsonProvider(object):
|
|
154
200
|
raise
|
155
201
|
|
156
202
|
async def get_status(self):
|
157
|
-
for rpc_addr in self.
|
203
|
+
for rpc_addr in self._available_rpcs:
|
158
204
|
try:
|
159
205
|
async with aiohttp.ClientSession() as session:
|
160
206
|
r = await session.get(
|
@@ -162,11 +208,7 @@ class JsonProvider(object):
|
|
162
208
|
)
|
163
209
|
if r.status == 200:
|
164
210
|
data = json.loads(await r.text())
|
165
|
-
if not data["sync_info"][
|
166
|
-
"syncing"
|
167
|
-
]: # RPC is not in syncing process
|
168
|
-
self._rpc_addresses.remove(rpc_addr)
|
169
|
-
self._rpc_addresses.insert(0, rpc_addr)
|
211
|
+
if not data["sync_info"]["syncing"]:
|
170
212
|
return data
|
171
213
|
except (
|
172
214
|
ClientResponseError,
|
@@ -224,17 +266,25 @@ class JsonProvider(object):
|
|
224
266
|
},
|
225
267
|
)
|
226
268
|
|
227
|
-
async def view_call(
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
269
|
+
async def view_call(
|
270
|
+
self,
|
271
|
+
account_id,
|
272
|
+
method_name,
|
273
|
+
args,
|
274
|
+
finality="optimistic",
|
275
|
+
block_id: Optional[int] = None,
|
276
|
+
):
|
277
|
+
body = {
|
278
|
+
"request_type": "call_function",
|
279
|
+
"account_id": account_id,
|
280
|
+
"method_name": method_name,
|
281
|
+
"args_base64": base64.b64encode(args).decode("utf8"),
|
282
|
+
}
|
283
|
+
if block_id:
|
284
|
+
body["block_id"] = block_id
|
285
|
+
else:
|
286
|
+
body["finality"] = finality
|
287
|
+
return await self.json_rpc("query", body)
|
238
288
|
|
239
289
|
async def get_block(self, block_id):
|
240
290
|
return await self.json_rpc("block", [block_id])
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: py-near
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.16
|
4
4
|
Summary: Pretty simple and fully asynchronous framework for working with NEAR blockchain
|
5
5
|
Author: pvolnov
|
6
6
|
Author-email: petr@herewallet.app
|
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3.8
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.9
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
14
15
|
Requires-Dist: aiohttp (>=3.7.4,<4.0.0)
|
15
16
|
Requires-Dist: ed25519 (>=1.5,<2.0)
|
16
17
|
Requires-Dist: py-near-primitives (>=0.2.3,<0.3.0)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
py_near/__init__.py,sha256=t5fAxjaU8dN8xpQR2vz0ZGhfTkdVy2RCbkhJhZFglk4,50
|
2
|
-
py_near/account.py,sha256=
|
2
|
+
py_near/account.py,sha256=tMlQCCgI7H40pr1geArrUbQpaT7bP6wROVnFnfdRmG8,16484
|
3
3
|
py_near/constants.py,sha256=inaWIuwmF1EB5JSB0ynnZY5rKY_QsxhF9KuCOhPsM6k,164
|
4
4
|
py_near/dapps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
py_near/dapps/core.py,sha256=LtN9aW2gw2mvEdhzQcQJIidtjv-XL1xjb0LK8DzqtqE,231
|
@@ -18,12 +18,12 @@ py_near/dapps/staking/exceptions.py,sha256=UjXLFsDQX0vDGS9CGO7HE9XpLD0vovFNUzCb1
|
|
18
18
|
py_near/dapps/staking/models.py,sha256=zC5M_pc1oMqHq4GaYif1uwFbW6acD2BsiA9rbyiaUTs,124
|
19
19
|
py_near/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
py_near/exceptions/exceptions.py,sha256=qG-aBYAsyCXcdzmZ84n9wVHCLkuWnd16XZTVprJfUVM,5462
|
21
|
-
py_near/exceptions/provider.py,sha256=
|
21
|
+
py_near/exceptions/provider.py,sha256=K-wexgjPJ8sw42JePwaP7R5dJEIn9DoFJRvVcURsx6s,7718
|
22
22
|
py_near/models.py,sha256=_JMpwtI6kP6740jaUPN1JRQIIDGXmL7tXLlR-JvRPXc,9417
|
23
|
-
py_near/providers.py,sha256=
|
23
|
+
py_near/providers.py,sha256=a70uIFoQeMBL28Dih5tD3WXmrsIDfenQBL_vVW-S_Ic,11807
|
24
24
|
py_near/transactions.py,sha256=QAXegv2JpKISk92NaChtIH6-QPHrcWbrwdKH_lH4TsU,3186
|
25
25
|
py_near/utils.py,sha256=FirRH93ydH1cwjn0-sNrZeIn3BRD6QHedrP2VkAdJ6g,126
|
26
|
-
py_near-1.1.
|
27
|
-
py_near-1.1.
|
28
|
-
py_near-1.1.
|
29
|
-
py_near-1.1.
|
26
|
+
py_near-1.1.16.dist-info/LICENSE,sha256=I_GOA9xJ35FiL-KnYXZJdATkbO2KcV2dK2enRGVxzKM,1023
|
27
|
+
py_near-1.1.16.dist-info/METADATA,sha256=LQnPUz_D_f3z-BkCJnbYTqHconYGsjI29EgLzy5mUoY,4713
|
28
|
+
py_near-1.1.16.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
29
|
+
py_near-1.1.16.dist-info/RECORD,,
|
File without changes
|