async-substrate-interface 1.2.1__tar.gz → 1.2.2__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 (26) hide show
  1. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/PKG-INFO +1 -1
  2. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/async_substrate.py +39 -12
  3. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/sync_substrate.py +8 -3
  4. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface.egg-info/PKG-INFO +1 -1
  5. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/pyproject.toml +1 -1
  6. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/LICENSE +0 -0
  7. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/README.md +0 -0
  8. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/__init__.py +0 -0
  9. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/const.py +0 -0
  10. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/errors.py +0 -0
  11. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/protocols.py +0 -0
  12. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/substrate_addons.py +0 -0
  13. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/type_registry.py +0 -0
  14. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/types.py +0 -0
  15. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/utils/__init__.py +0 -0
  16. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/utils/cache.py +0 -0
  17. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/utils/decoding.py +0 -0
  18. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/utils/hasher.py +0 -0
  19. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface/utils/storage.py +0 -0
  20. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface.egg-info/SOURCES.txt +0 -0
  21. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface.egg-info/dependency_links.txt +0 -0
  22. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface.egg-info/requires.txt +0 -0
  23. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/async_substrate_interface.egg-info/top_level.txt +0 -0
  24. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/setup.cfg +0 -0
  25. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/tests/test_old_new.py +0 -0
  26. {async_substrate_interface-1.2.1 → async_substrate_interface-1.2.2}/tests/test_substrate_addons.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: async-substrate-interface
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: Asyncio library for interacting with substrate. Mostly API-compatible with py-substrate-interface
5
5
  Author: Opentensor Foundation
6
6
  Author-email: BD Himes <b@latent.to>
@@ -9,6 +9,8 @@ import inspect
9
9
  import logging
10
10
  import ssl
11
11
  import time
12
+ import warnings
13
+ from unittest.mock import AsyncMock
12
14
  from hashlib import blake2b
13
15
  from typing import (
14
16
  Optional,
@@ -530,7 +532,16 @@ class Websocket:
530
532
  self._exit_task = None
531
533
  self._open_subscriptions = 0
532
534
  self._options = options if options else {}
533
- self.last_received = time.time()
535
+ try:
536
+ now = asyncio.get_running_loop().time()
537
+ except RuntimeError:
538
+ warnings.warn(
539
+ "You are instantiating the AsyncSubstrateInterface Websocket outside of an event loop. "
540
+ "Verify this is intended."
541
+ )
542
+ now = asyncio.new_event_loop().time()
543
+ self.last_received = now
544
+ self.last_sent = now
534
545
 
535
546
  async def __aenter__(self):
536
547
  async with self._lock:
@@ -538,7 +549,14 @@ class Websocket:
538
549
  await self.connect()
539
550
  return self
540
551
 
552
+ @staticmethod
553
+ async def loop_time() -> float:
554
+ return asyncio.get_running_loop().time()
555
+
541
556
  async def connect(self, force=False):
557
+ now = await self.loop_time()
558
+ self.last_received = now
559
+ self.last_sent = now
542
560
  if self._exit_task:
543
561
  self._exit_task.cancel()
544
562
  if not self._initialized or force:
@@ -594,7 +612,7 @@ class Websocket:
594
612
  try:
595
613
  # TODO consider wrapping this in asyncio.wait_for and use that for the timeout logic
596
614
  response = json.loads(await self.ws.recv(decode=False))
597
- self.last_received = time.time()
615
+ self.last_received = await self.loop_time()
598
616
  async with self._lock:
599
617
  # note that these 'subscriptions' are all waiting sent messages which have not received
600
618
  # responses, and thus are not the same as RPC 'subscriptions', which are unique
@@ -630,12 +648,12 @@ class Websocket:
630
648
  Returns:
631
649
  id: the internal ID of the request (incremented int)
632
650
  """
633
- # async with self._lock:
634
651
  original_id = get_next_id()
635
652
  # self._open_subscriptions += 1
636
653
  await self.max_subscriptions.acquire()
637
654
  try:
638
655
  await self.ws.send(json.dumps({**payload, **{"id": original_id}}))
656
+ self.last_sent = await self.loop_time()
639
657
  return original_id
640
658
  except (ConnectionClosed, ssl.SSLError, EOFError):
641
659
  async with self._lock:
@@ -697,13 +715,16 @@ class AsyncSubstrateInterface(SubstrateMixin):
697
715
  self.chain_endpoint = url
698
716
  self.url = url
699
717
  self._chain = chain_name
700
- self.ws = Websocket(
701
- url,
702
- options={
703
- "max_size": self.ws_max_size,
704
- "write_limit": 2**16,
705
- },
706
- )
718
+ if not _mock:
719
+ self.ws = Websocket(
720
+ url,
721
+ options={
722
+ "max_size": self.ws_max_size,
723
+ "write_limit": 2**16,
724
+ },
725
+ )
726
+ else:
727
+ self.ws = AsyncMock(spec=Websocket)
707
728
  self._lock = asyncio.Lock()
708
729
  self.config = {
709
730
  "use_remote_preset": use_remote_preset,
@@ -726,9 +747,11 @@ class AsyncSubstrateInterface(SubstrateMixin):
726
747
  self._initializing = False
727
748
  self.registry_type_map = {}
728
749
  self.type_id_to_name = {}
750
+ self._mock = _mock
729
751
 
730
752
  async def __aenter__(self):
731
- await self.initialize()
753
+ if not self._mock:
754
+ await self.initialize()
732
755
  return self
733
756
 
734
757
  async def initialize(self):
@@ -2120,7 +2143,11 @@ class AsyncSubstrateInterface(SubstrateMixin):
2120
2143
 
2121
2144
  if request_manager.is_complete:
2122
2145
  break
2123
- if time.time() - self.ws.last_received >= self.retry_timeout:
2146
+ if (
2147
+ (current_time := await self.ws.loop_time()) - self.ws.last_received
2148
+ >= self.retry_timeout
2149
+ and current_time - self.ws.last_sent >= self.retry_timeout
2150
+ ):
2124
2151
  if attempt >= self.max_retries:
2125
2152
  logger.warning(
2126
2153
  f"Timed out waiting for RPC requests {attempt} times. Exiting."
@@ -3,6 +3,7 @@ import logging
3
3
  import socket
4
4
  from hashlib import blake2b
5
5
  from typing import Optional, Union, Callable, Any
6
+ from unittest.mock import MagicMock
6
7
 
7
8
  from bt_decode import MetadataV15, PortableRegistry, decode as decode_by_type_string
8
9
  from scalecodec import (
@@ -13,7 +14,7 @@ from scalecodec import (
13
14
  MultiAccountId,
14
15
  )
15
16
  from scalecodec.base import RuntimeConfigurationObject, ScaleBytes, ScaleType
16
- from websockets.sync.client import connect
17
+ from websockets.sync.client import connect, ClientConnection
17
18
  from websockets.exceptions import ConnectionClosed
18
19
 
19
20
  from async_substrate_interface.const import SS58_FORMAT
@@ -522,14 +523,18 @@ class SubstrateInterface(SubstrateMixin):
522
523
  )
523
524
  self.metadata_version_hex = "0x0f000000" # v15
524
525
  self.reload_type_registry()
525
- self.ws = self.connect(init=True)
526
526
  self.registry_type_map = {}
527
527
  self.type_id_to_name = {}
528
+ self._mock = _mock
528
529
  if not _mock:
530
+ self.ws = self.connect(init=True)
529
531
  self.initialize()
532
+ else:
533
+ self.ws = MagicMock(spec=ClientConnection)
530
534
 
531
535
  def __enter__(self):
532
- self.initialize()
536
+ if not self._mock:
537
+ self.initialize()
533
538
  return self
534
539
 
535
540
  def __del__(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: async-substrate-interface
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: Asyncio library for interacting with substrate. Mostly API-compatible with py-substrate-interface
5
5
  Author: Opentensor Foundation
6
6
  Author-email: BD Himes <b@latent.to>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "async-substrate-interface"
3
- version = "1.2.1"
3
+ version = "1.2.2"
4
4
  description = "Asyncio library for interacting with substrate. Mostly API-compatible with py-substrate-interface"
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }