py-near 1.1.45__tar.gz → 1.1.47__tar.gz

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 (43) hide show
  1. {py_near-1.1.45 → py_near-1.1.47}/PKG-INFO +4 -4
  2. {py_near-1.1.45 → py_near-1.1.47}/pyproject.toml +6 -6
  3. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/providers.py +80 -60
  4. {py_near-1.1.45 → py_near-1.1.47}/LICENSE +0 -0
  5. {py_near-1.1.45 → py_near-1.1.47}/README.md +0 -0
  6. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/__init__.py +0 -0
  7. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/account.py +0 -0
  8. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/constants.py +0 -0
  9. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/__init__.py +0 -0
  10. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/__pycache__/__init__.cpython-311.pyc +0 -0
  11. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/__pycache__/core.cpython-311.pyc +0 -0
  12. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/__pycache__/fts.cpython-311.pyc +0 -0
  13. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/core.py +0 -0
  14. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/ft/__init__.py +0 -0
  15. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/ft/__pycache__/__init__.cpython-311.pyc +0 -0
  16. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/ft/__pycache__/async_client.cpython-311.pyc +0 -0
  17. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/ft/__pycache__/exceptions.cpython-311.pyc +0 -0
  18. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/ft/__pycache__/models.cpython-311.pyc +0 -0
  19. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/ft/async_client.py +0 -0
  20. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/ft/exceptions.py +0 -0
  21. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/ft/models.py +0 -0
  22. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/fts.py +0 -0
  23. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/keypom/__init__.py +0 -0
  24. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/keypom/async_client.py +0 -0
  25. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/keypom/exceptions.py +0 -0
  26. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/keypom/models.py +0 -0
  27. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/staking/__init__.py +0 -0
  28. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/staking/__pycache__/__init__.cpython-311.pyc +0 -0
  29. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/staking/__pycache__/async_client.cpython-311.pyc +0 -0
  30. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/staking/__pycache__/exceptions.cpython-311.pyc +0 -0
  31. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/staking/__pycache__/models.cpython-311.pyc +0 -0
  32. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/staking/async_client.py +0 -0
  33. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/staking/exceptions.py +0 -0
  34. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/dapps/staking/models.py +0 -0
  35. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/exceptions/__init__.py +0 -0
  36. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/exceptions/__pycache__/__init__.cpython-311.pyc +0 -0
  37. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/exceptions/__pycache__/exceptions.cpython-311.pyc +0 -0
  38. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/exceptions/__pycache__/provider.cpython-311.pyc +0 -0
  39. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/exceptions/exceptions.py +0 -0
  40. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/exceptions/provider.py +0 -0
  41. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/models.py +0 -0
  42. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/transactions.py +0 -0
  43. {py_near-1.1.45 → py_near-1.1.47}/src/py_near/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py-near
3
- Version: 1.1.45
3
+ Version: 1.1.47
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
@@ -12,9 +12,9 @@ Classifier: Programming Language :: Python :: 3.9
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
- Requires-Dist: aiohttp (>=3.7.4,<4.0.0)
16
- Requires-Dist: ed25519 (>=1.5,<2.0)
17
- Requires-Dist: py-near-primitives (>=0.2.3,<0.3.0)
15
+ Requires-Dist: ed25519 (==1.5)
16
+ Requires-Dist: httpx (==0.27.0)
17
+ Requires-Dist: py-near-primitives (==0.2.3)
18
18
  Description-Content-Type: text/markdown
19
19
 
20
20
  # py-near
@@ -1,15 +1,15 @@
1
1
  [tool.poetry]
2
2
  name = "py-near"
3
- version = "1.1.45"
3
+ version = "1.1.47"
4
4
  description="Pretty simple and fully asynchronous framework for working with NEAR blockchain"
5
5
  authors = ["pvolnov <petr@herewallet.app>"]
6
6
  readme = "README.md"
7
7
 
8
8
  [tool.poetry.dependencies]
9
9
  python = "^3.7"
10
- ed25519 = "^1.5"
11
- aiohttp = "^3.7.4"
12
- py-near-primitives = "^0.2.3"
10
+ ed25519 = "1.5"
11
+ httpx = "0.27.0"
12
+ py-near-primitives = "0.2.3"
13
13
 
14
14
  [tool.poetry.dev-dependencies]
15
15
  black = "^21.12b0"
@@ -22,12 +22,12 @@ base58 = "^2.1.1"
22
22
 
23
23
  [project]
24
24
  name = "py-near"
25
- version = "1.1.45"
25
+ version = "1.1.47"
26
26
  description = "Pretty simple and fully asynchronous framework for working with NEAR blockchaink"
27
27
  authors = [ {name = "pvolnov", email = "petr@herewallet.app"} ]
28
28
  requires-python = ">=3.7"
29
29
  license = {file = "LICENSE"}
30
- dependencies=["base58", "ed25519", "aiohttp", "py-near-primitives", "pydantic"]
30
+ dependencies=["base58", "ed25519", "httpx", "py-near-primitives", "pydantic"]
31
31
  keywords = ["python", "near", "async"]
32
32
  classifiers = [
33
33
  "Programming Language :: Python :: 3",
@@ -5,8 +5,7 @@ import json
5
5
  from collections import Counter
6
6
  from typing import Optional
7
7
 
8
- import aiohttp
9
- from aiohttp import ClientResponseError, ClientConnectorError, ServerDisconnectedError
8
+ import httpx
10
9
  from loguru import logger
11
10
 
12
11
  from py_near.constants import TIMEOUT_WAIT_RPC
@@ -61,6 +60,7 @@ class JsonProvider(object):
61
60
  self._last_rpc_addr_check = 0
62
61
  self.allow_broadcast = allow_broadcast
63
62
  self._timeout = timeout
63
+ self._client: httpx.AsyncClient = httpx.AsyncClient()
64
64
 
65
65
  async def shutdown(self):
66
66
  pass
@@ -94,35 +94,41 @@ class JsonProvider(object):
94
94
  "id": 1,
95
95
  }
96
96
  auth_key = "py-near"
97
+ rpc_addr_url = rpc_addr
97
98
  if "@" in rpc_addr:
98
- auth_key = rpc_addr.split("//")[1].split("@")[0]
99
- rpc_addr = rpc_addr.replace(auth_key + "@", "")
100
- async with aiohttp.ClientSession() as session:
101
- async with session.post(rpc_addr, json=data, headers={
99
+ auth_key = rpc_addr_url.split("//")[1].split("@")[0]
100
+ rpc_addr_url = rpc_addr_url.replace(auth_key + "@", "")
101
+
102
+ r = await self._client.post(
103
+ rpc_addr_url,
104
+ json=data,
105
+ headers={
102
106
  "Referer": "https://tgapp.herewallet.app",
103
107
  "Authorization": f"Bearer {auth_key}",
104
- }) as r:
105
- if r.status == 200:
106
- data = json.loads(await r.text())["result"]
107
- if data["sync_info"]["syncing"]:
108
- last_block_ts = datetime.datetime.fromisoformat(
109
- data["sync_info"]["latest_block_time"]
110
- )
111
- diff = (
112
- datetime.datetime.utcnow().timestamp()
113
- - last_block_ts.timestamp()
114
- )
115
- is_syncing = diff > 60
116
- else:
117
- is_syncing = False
118
- if is_syncing:
119
- logger.error(f"Remove async RPC : {rpc_addr} ({diff})")
120
- continue
121
- available_rpcs.append(rpc_addr)
122
- else:
123
- logger.error(
124
- f"Remove rpc because of error {r.status}: {rpc_addr}"
125
- )
108
+ },
109
+ )
110
+ if r.status_code == 200:
111
+ data = json.loads(r.text)["result"]
112
+ diff = 0
113
+ if data["sync_info"]["syncing"]:
114
+ last_block_ts = datetime.datetime.fromisoformat(
115
+ data["sync_info"]["latest_block_time"]
116
+ )
117
+ diff = (
118
+ datetime.datetime.utcnow().timestamp()
119
+ - last_block_ts.timestamp()
120
+ )
121
+ is_syncing = diff > 60
122
+ else:
123
+ is_syncing = False
124
+ if is_syncing:
125
+ logger.error(f"Remove async RPC : {rpc_addr} ({diff})")
126
+ continue
127
+ available_rpcs.append(rpc_addr)
128
+ else:
129
+ logger.error(
130
+ f"Remove rpc because of error {r.status_code}: {rpc_addr}"
131
+ )
126
132
  except Exception as e:
127
133
  if rpc_addr in self._available_rpcs:
128
134
  logger.error(f"Remove rpc: {e}")
@@ -146,24 +152,26 @@ class JsonProvider(object):
146
152
  if "@" in rpc_call_addr:
147
153
  auth_key = rpc_call_addr.split("//")[1].split("@")[0]
148
154
  rpc_call_addr = rpc_call_addr.replace(auth_key + "@", "")
149
- async with aiohttp.ClientSession() as session:
150
- r = await session.post(
151
- rpc_call_addr,
152
- json=j,
153
- timeout=self._timeout,
154
- headers={
155
- "Referer": "https://tgapp.herewallet.app",
156
- "Authorization": f"Bearer {auth_key}",
157
- }, # NEAR RPC requires Referer header
158
- )
159
- if r.status == 200:
160
- return json.loads(await r.text())
161
- return {
162
- "error": {
163
- "cause": {"name": "RPC_ERROR", "message": f"Status: {r.status}"},
164
- "data": await r.text(),
165
- }
155
+ r = await self._client.post(
156
+ rpc_call_addr,
157
+ json=j,
158
+ timeout=self._timeout,
159
+ headers={
160
+ "Referer": "https://tgapp.herewallet.app",
161
+ "Authorization": f"Bearer {auth_key}",
162
+ },
163
+ )
164
+ if r.status_code == 200:
165
+ return json.loads(r.text)
166
+ return {
167
+ "error": {
168
+ "cause": {
169
+ "name": "RPC_ERROR",
170
+ "message": f"Status: {r.status_code}",
171
+ },
172
+ "data": r.text,
166
173
  }
174
+ }
167
175
 
168
176
  if broadcast or threshold:
169
177
  pending = [
@@ -172,6 +180,8 @@ class JsonProvider(object):
172
180
 
173
181
  responses = []
174
182
  correct_responses = []
183
+ result = None
184
+
175
185
  while pending and len(pending):
176
186
  done, pending = await asyncio.wait(
177
187
  pending, return_when=asyncio.FIRST_COMPLETED
@@ -188,14 +198,21 @@ class JsonProvider(object):
188
198
  array = [hash(json.dumps(x)) for x in responses]
189
199
  most_frequent_element = self.most_frequent_by_hash(array)
190
200
  correct_responses = [
191
- x for x in responses if hash(json.dumps(x)) == most_frequent_element
201
+ x
202
+ for x in responses
203
+ if hash(json.dumps(x)) == most_frequent_element
192
204
  ]
193
205
  if len(correct_responses) >= threshold:
194
206
  for task in pending:
195
207
  task.cancel()
196
- return most_frequent_element
197
- raise RpcEmptyResponse(f"Threshold not reached: {len(correct_responses)}/{threshold}")
208
+ return correct_responses[0]
209
+ if threshold and threshold > 0:
210
+ raise RpcEmptyResponse(
211
+ f"Threshold not reached: {len(correct_responses)}/{threshold}"
212
+ )
213
+ return result
198
214
  else:
215
+ res = None
199
216
  for rpc_addr in self._available_rpcs:
200
217
  try:
201
218
  res = await f(rpc_addr)
@@ -204,7 +221,7 @@ class JsonProvider(object):
204
221
  except Exception as e:
205
222
  logger.error(f"Rpc error: {e}")
206
223
  continue
207
- raise RpcEmptyResponse("RPC returned empty response")
224
+ return res
208
225
 
209
226
  @staticmethod
210
227
  def get_error_from_response(content: dict):
@@ -309,7 +326,7 @@ class JsonProvider(object):
309
326
 
310
327
  async def get_status(self):
311
328
  await self.check_available_rpcs()
312
- for rpc_addr in self._available_rpcs:
329
+ for rpc_addr in self._available_rpcs.copy():
313
330
  try:
314
331
  data = {
315
332
  "jsonrpc": "2.0",
@@ -317,16 +334,19 @@ class JsonProvider(object):
317
334
  "params": {"finality": "final"},
318
335
  "id": 1,
319
336
  }
320
- async with aiohttp.ClientSession() as session:
321
- async with session.post(rpc_addr, json=data) as r:
322
- if r.status == 200:
323
- return json.loads(await r.text())["result"]
324
- except (
325
- ClientResponseError,
326
- ClientConnectorError,
327
- ServerDisconnectedError,
328
- ConnectionError,
329
- ) as e:
337
+ headers = {
338
+ "Referer": "https://tgapp.herewallet.app",
339
+ }
340
+ if "@" in rpc_addr:
341
+ auth_key = rpc_addr.split("//")[1].split("@")[0]
342
+ rpc_addr = rpc_addr.replace(auth_key + "@", "")
343
+ headers = {
344
+ "Authorization": f"Bearer {auth_key}"
345
+ }
346
+ r = await self._client.post(rpc_addr, json=data, headers=headers)
347
+ if r.status_code == 200:
348
+ return json.loads(r.text)["result"]
349
+ except ConnectionError as e:
330
350
  logger.error(f"Rpc get status error: {e}")
331
351
  except Exception as e:
332
352
  logger.error(e)
File without changes
File without changes
File without changes
File without changes