blockapi 2.10.2__tar.gz → 2.10.4__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 (114) hide show
  1. {blockapi-2.10.2 → blockapi-2.10.4}/PKG-INFO +3 -6
  2. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/__init__.py +0 -1
  3. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/services.py +3 -0
  4. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/test_opensea.py +3 -1
  5. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/test_simple_hash.py +3 -1
  6. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_data.py +0 -6
  7. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_enumerate_classes.py +1 -4
  8. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/utils/datetime.py +6 -1
  9. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/__init__.py +0 -1
  10. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/debank.py +3 -0
  11. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/unisat.py +2 -2
  12. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/base.py +4 -4
  13. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/coins.py +0 -9
  14. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/models.py +4 -3
  15. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/PKG-INFO +3 -6
  16. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/SOURCES.txt +1 -12
  17. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/requires.txt +2 -5
  18. {blockapi-2.10.2 → blockapi-2.10.4}/setup.py +3 -6
  19. blockapi-2.10.2/blockapi/test/v2/api/perpetual/test_perpetual.py +0 -94
  20. blockapi-2.10.2/blockapi/test/v2/api/synthetix/test_synthetix.py +0 -166
  21. blockapi-2.10.2/blockapi/v2/__init__.py +0 -0
  22. blockapi-2.10.2/blockapi/v2/api/covalenth/__init__.py +0 -0
  23. blockapi-2.10.2/blockapi/v2/api/perpetual/__init__.py +0 -1
  24. blockapi-2.10.2/blockapi/v2/api/perpetual/perp_abi.py +0 -264
  25. blockapi-2.10.2/blockapi/v2/api/perpetual/perpetual.py +0 -253
  26. blockapi-2.10.2/blockapi/v2/api/synthetix/__init__.py +0 -7
  27. blockapi-2.10.2/blockapi/v2/api/synthetix/synthetix.py +0 -431
  28. blockapi-2.10.2/blockapi/v2/api/synthetix/synthetix_abi.py +0 -5780
  29. blockapi-2.10.2/blockapi/v2/api/web3_utils.py +0 -142
  30. {blockapi-2.10.2 → blockapi-2.10.4}/LICENSE.md +0 -0
  31. {blockapi-2.10.2 → blockapi-2.10.4}/README.md +0 -0
  32. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/__init__.py +0 -0
  33. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/test_blockapi.py +0 -0
  34. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/test_num.py +0 -0
  35. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/test_random_user_agent.py +0 -0
  36. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/__init__.py +0 -0
  37. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/__init__.py +0 -0
  38. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/conftest.py +0 -0
  39. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
  40. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
  41. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
  42. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/__init__.py +0 -0
  43. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
  44. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
  45. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_bitaps_ltc.py +0 -0
  46. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchain_info.py +0 -0
  47. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchainos.py +0 -0
  48. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
  49. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
  50. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
  51. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_cosmos.py +0 -0
  52. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_ethplorer.py +0 -0
  53. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_haskoin.py +0 -0
  54. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_litecoinspace.py +0 -0
  55. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_multisources.py +0 -0
  56. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
  57. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_solana.py +0 -0
  58. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
  59. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_sui.py +0 -0
  60. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_terra.py +0 -0
  61. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
  62. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_trezor_zec.py +0 -0
  63. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_base.py +0 -0
  64. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_blockchain_api.py +0 -0
  65. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
  66. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_generic.py +0 -0
  67. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_models.py +0 -0
  68. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test_data.py +0 -0
  69. {blockapi-2.10.2/blockapi/test/v2/api/perpetual → blockapi-2.10.4/blockapi/utils}/__init__.py +0 -0
  70. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/utils/address.py +0 -0
  71. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/utils/num.py +0 -0
  72. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/utils/user_agent.py +0 -0
  73. {blockapi-2.10.2/blockapi/test/v2/api/synthetix → blockapi-2.10.4/blockapi/v2}/__init__.py +0 -0
  74. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/bitaps.py +0 -0
  75. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/blockchain_info.py +0 -0
  76. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/blockchainos.py +0 -0
  77. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/blockchair.py +0 -0
  78. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/cosmos.py +0 -0
  79. {blockapi-2.10.2/blockapi/utils → blockapi-2.10.4/blockapi/v2/api/covalenth}/__init__.py +0 -0
  80. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
  81. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/astar.py +0 -0
  82. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/avalanche.py +0 -0
  83. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/axie.py +0 -0
  84. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/base.py +0 -0
  85. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
  86. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/ethereum.py +0 -0
  87. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/fantom.py +0 -0
  88. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/heco.py +0 -0
  89. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/iotex.py +0 -0
  90. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/klaytn.py +0 -0
  91. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
  92. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/palm.py +0 -0
  93. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/polygon.py +0 -0
  94. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/rsk.py +0 -0
  95. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/debank_maps.py +0 -0
  96. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/ethplorer.py +0 -0
  97. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/haskoin.py +0 -0
  98. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/litecoinspace.py +0 -0
  99. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/__init__.py +0 -0
  100. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/magic_eden.py +0 -0
  101. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/opensea.py +0 -0
  102. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/simple_hash.py +0 -0
  103. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/optimistic_etherscan.py +0 -0
  104. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/solana.py +0 -0
  105. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/subscan.py +0 -0
  106. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/sui.py +0 -0
  107. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/terra.py +0 -0
  108. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/trezor.py +0 -0
  109. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/blockchain_mapping.py +0 -0
  110. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/coin_mapping.py +0 -0
  111. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/dependency_links.txt +0 -0
  112. {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/top_level.txt +0 -0
  113. {blockapi-2.10.2 → blockapi-2.10.4}/pyproject.toml +0 -0
  114. {blockapi-2.10.2 → blockapi-2.10.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blockapi
3
- Version: 2.10.2
3
+ Version: 2.10.4
4
4
  Summary: BlockAPI library
5
5
  Home-page: https://github.com/crypkit/blockapi
6
6
  Author: Devmons s.r.o.
@@ -9,18 +9,15 @@ Description-Content-Type: text/markdown
9
9
  License-File: LICENSE.md
10
10
  Requires-Dist: requests<3.0,>=2.28
11
11
  Requires-Dist: python-dateutil>=2.8.0
12
+ Requires-Dist: cytoolz>=0.12.0
13
+ Requires-Dist: eth-utils>=2.0.0
12
14
  Requires-Dist: coinaddrng==1.1.1
13
- Requires-Dist: web3<8.0.0,>=5.2.2
14
- Requires-Dist: bs4>=0.0.1
15
- Requires-Dist: lxml>=4.4.1
16
15
  Requires-Dist: pydantic>=1.10.2
17
- Requires-Dist: marko<2.0.0,>=1.3.0
18
16
  Requires-Dist: fake_useragent>=1.1.3
19
17
  Requires-Dist: pytest
20
18
  Requires-Dist: pytest-vcr
21
19
  Requires-Dist: requests_mock>=1.9.3
22
20
  Requires-Dist: attrs<23.0.0,>=17.4.0
23
- Requires-Dist: solders>=0.22.0
24
21
  Requires-Dist: base58>=2.1.0
25
22
  Requires-Dist: aiohttp<3.14
26
23
  Dynamic: author
@@ -1,4 +1,3 @@
1
- import inspect
2
1
  import random
3
2
 
4
3
  import coinaddrng
@@ -56,6 +56,9 @@ class Service(ABC):
56
56
  response = reqobj.get(request_url, headers=headers)
57
57
 
58
58
  self.last_response = response
59
+ # Naive local time on purpose: only used to measure elapsed time against
60
+ # datetime.now() in wait_for_next_request (rate limiting), never compared
61
+ # with tz-aware datetimes.
59
62
  self.last_response_time = datetime.now()
60
63
 
61
64
  if response.status_code != 200:
@@ -162,7 +162,9 @@ def test_parse_nfts(requests_mock, api, nfts_response, nfts_next_response):
162
162
  == 'data:application/json;base64,eyJuYW1lIjoiVW5pc3dhcCAtIDElIC0gUFJJTUUvV0VUSCAtIDMzMC4yMDw+NzgwLjI5In0='
163
163
  )
164
164
  assert not data.metadata
165
- assert data.updated_time == datetime.datetime(2023, 8, 15, 13, 56, 39, 759414)
165
+ assert data.updated_time == datetime.datetime(
166
+ 2023, 8, 15, 13, 56, 39, 759414, tzinfo=datetime.timezone.utc
167
+ )
166
168
  assert not data.is_disabled
167
169
  assert not data.is_nsfw
168
170
  assert data.blockchain == Blockchain.ETHEREUM
@@ -55,7 +55,9 @@ def test_parse_nfts(requests_mock, api, nfts_response):
55
55
  )
56
56
  assert not data.metadata_url
57
57
  assert not data.metadata
58
- assert data.updated_time == datetime.datetime(2023, 3, 11, 3, 46, 15)
58
+ assert data.updated_time == datetime.datetime(
59
+ 2023, 3, 11, 3, 46, 15, tzinfo=datetime.timezone.utc
60
+ )
59
61
  assert not data.is_disabled
60
62
  assert not data.is_nsfw
61
63
  assert data.blockchain == Blockchain.BITCOIN
@@ -10,7 +10,6 @@ from blockapi.v2.api import (
10
10
  EthplorerApi,
11
11
  KusamaSubscanApi,
12
12
  OptimismEtherscanApi,
13
- PerpetualApi,
14
13
  PolkadotSubscanApi,
15
14
  SolanaApi,
16
15
  SubscanApi,
@@ -32,7 +31,6 @@ from blockapi.v2.api.covalenth.moonbeam import MoonBeamCovalentApi
32
31
  from blockapi.v2.api.covalenth.palm import PalmCovalentApi
33
32
  from blockapi.v2.api.covalenth.polygon import PolygonCovalentApi
34
33
  from blockapi.v2.api.covalenth.rsk import RskCovalentApi
35
- from blockapi.v2.api.synthetix import SynthetixApi
36
34
 
37
35
  # TODO create method for auto loading all classes
38
36
  from blockapi.v2.base import BalanceMixin, IBalance
@@ -93,8 +91,6 @@ API_CLASSES = [
93
91
  PolkadotSubscanApi,
94
92
  KusamaSubscanApi,
95
93
  CosmosApi,
96
- SynthetixApi,
97
- PerpetualApi,
98
94
  BlockchairBitcoinApi,
99
95
  ]
100
96
 
@@ -187,8 +183,6 @@ def yield_api_balance_classes():
187
183
  CosmosApiBase,
188
184
  CovalentApiBase,
189
185
  DebankApi,
190
- PerpetualApi,
191
- SynthetixApi,
192
186
  SubscanApi,
193
187
  TrezorApi,
194
188
  ),
@@ -5,7 +5,7 @@ from blockapi.test.v2.test_data import (
5
5
  yield_api_balance_classes,
6
6
  yield_covalent_api_classes,
7
7
  )
8
- from blockapi.v2.api import DebankApi, EthplorerApi, PerpetualApi
8
+ from blockapi.v2.api import DebankApi, EthplorerApi
9
9
  from blockapi.v2.api.covalenth.arbitrum import ArbitrumCovalentApi
10
10
  from blockapi.v2.api.covalenth.astar import AstarCovalentApi
11
11
  from blockapi.v2.api.covalenth.avalanche import AvalancheCovalentApi
@@ -20,7 +20,6 @@ from blockapi.v2.api.covalenth.moonbeam import MoonBeamCovalentApi
20
20
  from blockapi.v2.api.covalenth.palm import PalmCovalentApi
21
21
  from blockapi.v2.api.covalenth.polygon import PolygonCovalentApi
22
22
  from blockapi.v2.api.covalenth.rsk import RskCovalentApi
23
- from blockapi.v2.api.synthetix import SynthetixApi
24
23
 
25
24
 
26
25
  def test_enumerate_subclasses():
@@ -29,8 +28,6 @@ def test_enumerate_subclasses():
29
28
  assert classes
30
29
  assert EthplorerApi.__name__ in classes
31
30
  assert DebankApi.__name__ not in classes
32
- assert PerpetualApi.__name__ not in classes
33
- assert SynthetixApi.__name__ not in classes
34
31
 
35
32
  for cls in classes:
36
33
  assert 'Base' not in cls
@@ -12,7 +12,12 @@ def parse_dt(dt: Union[str, int, float]) -> datetime:
12
12
  try:
13
13
  return datetime.fromtimestamp(int(dt), tz=timezone.utc)
14
14
  except ValueError:
15
- return parse_date(dt)
15
+ parsed = parse_date(dt)
16
+ # Assume UTC for strings that carry no timezone, so parse_dt always
17
+ # returns a tz-aware datetime (consistent with the numeric paths).
18
+ if parsed.tzinfo is None:
19
+ parsed = parsed.replace(tzinfo=timezone.utc)
20
+ return parsed
16
21
  elif isinstance(dt, int) or isinstance(dt, float):
17
22
  return datetime.fromtimestamp(dt, tz=timezone.utc)
18
23
  else:
@@ -12,7 +12,6 @@ from blockapi.v2.api.ethplorer import EthplorerApi
12
12
  from blockapi.v2.api.haskoin import HaskoinApi
13
13
  from blockapi.v2.api.litecoinspace import LitecoinSpaceApi
14
14
  from blockapi.v2.api.optimistic_etherscan import OptimismEtherscanApi
15
- from blockapi.v2.api.perpetual import PerpetualApi, perp_contract_address
16
15
  from blockapi.v2.api.solana import SolanaApi, SolscanApi
17
16
  from blockapi.v2.api.subscan import KusamaSubscanApi, PolkadotSubscanApi, SubscanApi
18
17
  from blockapi.v2.api.terra import TerraApi
@@ -243,6 +243,9 @@ class DebankProtocolCache:
243
243
  def __init__(self, timeout: int = 3600):
244
244
  self._timeout: int = timeout
245
245
  self._data: Dict[str, Protocol] = {}
246
+ # Naive local time on purpose: _timelimit is only ever compared against
247
+ # other datetime.now() values here (cache TTL), never mixed with the
248
+ # tz-aware datetimes used elsewhere, so there is no naive/aware hazard.
246
249
  self._timelimit = datetime.now()
247
250
 
248
251
  def invalidate(self):
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from typing import Optional, Dict, Generator, Tuple
3
3
  from enum import Enum
4
- from datetime import datetime
4
+ from datetime import datetime, timezone
5
5
 
6
6
  from blockapi.v2.base import BlockchainApi, INftParser, INftProvider, ISleepProvider
7
7
  from blockapi.v2.coins import COIN_BTC
@@ -670,7 +670,7 @@ class UnisatApi(BlockchainApi, INftParser, INftProvider):
670
670
  try:
671
671
  timestamp_seconds = timestamp / 1000
672
672
  formatted_time = datetime.fromtimestamp(
673
- timestamp_seconds
673
+ timestamp_seconds, tz=timezone.utc
674
674
  ).isoformat()
675
675
  except (ValueError, TypeError, OverflowError):
676
676
  logger.warning(
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import time
3
3
  from abc import ABC
4
- from datetime import datetime, timedelta
4
+ from datetime import datetime, timedelta, timezone
5
5
  from typing import Dict, List, Optional
6
6
  from urllib.parse import urljoin
7
7
 
@@ -107,7 +107,7 @@ class CustomizableBlockchainApi(ABC):
107
107
  return FetchResult(
108
108
  status_code=1,
109
109
  errors=[str(connection_error)],
110
- time=datetime.utcnow(),
110
+ time=datetime.now(timezone.utc),
111
111
  )
112
112
 
113
113
  self.sleep_provider.sleep(self.base_url, seconds=sleep_seconds)
@@ -155,7 +155,7 @@ class CustomizableBlockchainApi(ABC):
155
155
  headers=dict(),
156
156
  errors=[f'{type(ex).__name__}: {str(ex)}'],
157
157
  extra=extra,
158
- time=datetime.utcnow(),
158
+ time=datetime.now(timezone.utc),
159
159
  )
160
160
 
161
161
  time = self._get_response_time(response.headers)
@@ -236,7 +236,7 @@ class CustomizableBlockchainApi(ABC):
236
236
  return parse_dt(date_str)
237
237
 
238
238
  if age_str := headers.get('age'):
239
- return datetime.utcnow() - timedelta(seconds=int(age_str))
239
+ return datetime.now(timezone.utc) - timedelta(seconds=int(age_str))
240
240
 
241
241
  return None
242
242
 
@@ -431,15 +431,6 @@ COIN_DOGE = Coin(
431
431
  info=CoinInfo(coingecko_id=CoingeckoId.DOGECOIN),
432
432
  )
433
433
 
434
- COIN_SNX = Coin(
435
- symbol='SNX',
436
- name='Synthetix',
437
- decimals=18,
438
- address='0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f',
439
- blockchain=Blockchain.ETHEREUM,
440
- info=CoinInfo(coingecko_id=CoingeckoId.SYNTHETIX),
441
- )
442
-
443
434
 
444
435
  COIN_CANTO = Coin(
445
436
  symbol='CANTO',
@@ -1,5 +1,5 @@
1
1
  import json
2
- from datetime import datetime
2
+ from datetime import datetime, timezone
3
3
  from decimal import Decimal
4
4
  from enum import Enum
5
5
  from typing import Dict, List, Literal, Optional, Union
@@ -473,7 +473,6 @@ class CoingeckoId(str, Enum):
473
473
  SOLANA = 'solana'
474
474
  SONGBIRD = 'songbird'
475
475
  SUI = 'sui'
476
- SYNTHETIX = 'havven'
477
476
  TELOS = 'telos'
478
477
  USDC = 'usd-coin'
479
478
  WANCHAIN = 'wanchain'
@@ -864,7 +863,9 @@ class NftOffer:
864
863
  contract=contract,
865
864
  blockchain=blockchain,
866
865
  offerer=offerer,
867
- start_time=parse_dt(start_time) if start_time else datetime.utcnow(),
866
+ start_time=(
867
+ parse_dt(start_time) if start_time else datetime.now(timezone.utc)
868
+ ),
868
869
  end_time=parse_dt(end_time) if end_time else None,
869
870
  offer_coin=offer_coin,
870
871
  offer_contract=offer_contract.lower() if offer_contract else None,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blockapi
3
- Version: 2.10.2
3
+ Version: 2.10.4
4
4
  Summary: BlockAPI library
5
5
  Home-page: https://github.com/crypkit/blockapi
6
6
  Author: Devmons s.r.o.
@@ -9,18 +9,15 @@ Description-Content-Type: text/markdown
9
9
  License-File: LICENSE.md
10
10
  Requires-Dist: requests<3.0,>=2.28
11
11
  Requires-Dist: python-dateutil>=2.8.0
12
+ Requires-Dist: cytoolz>=0.12.0
13
+ Requires-Dist: eth-utils>=2.0.0
12
14
  Requires-Dist: coinaddrng==1.1.1
13
- Requires-Dist: web3<8.0.0,>=5.2.2
14
- Requires-Dist: bs4>=0.0.1
15
- Requires-Dist: lxml>=4.4.1
16
15
  Requires-Dist: pydantic>=1.10.2
17
- Requires-Dist: marko<2.0.0,>=1.3.0
18
16
  Requires-Dist: fake_useragent>=1.1.3
19
17
  Requires-Dist: pytest
20
18
  Requires-Dist: pytest-vcr
21
19
  Requires-Dist: requests_mock>=1.9.3
22
20
  Requires-Dist: attrs<23.0.0,>=17.4.0
23
- Requires-Dist: solders>=0.22.0
24
21
  Requires-Dist: base58>=2.1.0
25
22
  Requires-Dist: aiohttp<3.14
26
23
  Dynamic: author
@@ -51,10 +51,6 @@ blockapi/test/v2/api/nft/test_magic_eden.py
51
51
  blockapi/test/v2/api/nft/test_opensea.py
52
52
  blockapi/test/v2/api/nft/test_simple_hash.py
53
53
  blockapi/test/v2/api/nft/test_unisat.py
54
- blockapi/test/v2/api/perpetual/__init__.py
55
- blockapi/test/v2/api/perpetual/test_perpetual.py
56
- blockapi/test/v2/api/synthetix/__init__.py
57
- blockapi/test/v2/api/synthetix/test_synthetix.py
58
54
  blockapi/utils/__init__.py
59
55
  blockapi/utils/address.py
60
56
  blockapi/utils/datetime.py
@@ -83,7 +79,6 @@ blockapi/v2/api/subscan.py
83
79
  blockapi/v2/api/sui.py
84
80
  blockapi/v2/api/terra.py
85
81
  blockapi/v2/api/trezor.py
86
- blockapi/v2/api/web3_utils.py
87
82
  blockapi/v2/api/covalenth/__init__.py
88
83
  blockapi/v2/api/covalenth/arbitrum.py
89
84
  blockapi/v2/api/covalenth/astar.py
@@ -104,10 +99,4 @@ blockapi/v2/api/nft/__init__.py
104
99
  blockapi/v2/api/nft/magic_eden.py
105
100
  blockapi/v2/api/nft/opensea.py
106
101
  blockapi/v2/api/nft/simple_hash.py
107
- blockapi/v2/api/nft/unisat.py
108
- blockapi/v2/api/perpetual/__init__.py
109
- blockapi/v2/api/perpetual/perp_abi.py
110
- blockapi/v2/api/perpetual/perpetual.py
111
- blockapi/v2/api/synthetix/__init__.py
112
- blockapi/v2/api/synthetix/synthetix.py
113
- blockapi/v2/api/synthetix/synthetix_abi.py
102
+ blockapi/v2/api/nft/unisat.py
@@ -1,16 +1,13 @@
1
1
  requests<3.0,>=2.28
2
2
  python-dateutil>=2.8.0
3
+ cytoolz>=0.12.0
4
+ eth-utils>=2.0.0
3
5
  coinaddrng==1.1.1
4
- web3<8.0.0,>=5.2.2
5
- bs4>=0.0.1
6
- lxml>=4.4.1
7
6
  pydantic>=1.10.2
8
- marko<2.0.0,>=1.3.0
9
7
  fake_useragent>=1.1.3
10
8
  pytest
11
9
  pytest-vcr
12
10
  requests_mock>=1.9.3
13
11
  attrs<23.0.0,>=17.4.0
14
- solders>=0.22.0
15
12
  base58>=2.1.0
16
13
  aiohttp<3.14
@@ -6,7 +6,7 @@ with open("README.md", "r") as f:
6
6
 
7
7
  PACKAGES = find_packages(where='.')
8
8
 
9
- __version__ = "2.10.2"
9
+ __version__ = "2.10.4"
10
10
 
11
11
  setuptools.setup(
12
12
  name='blockapi',
@@ -20,18 +20,15 @@ setuptools.setup(
20
20
  install_requires=[
21
21
  'requests>=2.28,<3.0',
22
22
  'python-dateutil>=2.8.0',
23
+ 'cytoolz>=0.12.0',
24
+ 'eth-utils>=2.0.0',
23
25
  'coinaddrng==1.1.1',
24
- 'web3>=5.2.2,<8.0.0',
25
- 'bs4>=0.0.1',
26
- 'lxml>=4.4.1',
27
26
  'pydantic>=1.10.2',
28
- 'marko>=1.3.0,<2.0.0',
29
27
  'fake_useragent>=1.1.3',
30
28
  'pytest',
31
29
  'pytest-vcr',
32
30
  'requests_mock>=1.9.3',
33
31
  'attrs>=17.4.0,<23.0.0',
34
- 'solders>=0.22.0',
35
32
  'base58>=2.1.0',
36
33
  # vcrpy incompatible with 3.14, remove once vcrpy>8.1.1 is out
37
34
  'aiohttp<3.14',
@@ -1,94 +0,0 @@
1
- import os
2
-
3
- import pytest
4
- from _decimal import Decimal
5
-
6
- from blockapi.v2.api import PerpetualApi, perp_contract_address
7
- from blockapi.v2.base import ApiException
8
- from blockapi.v2.models import FetchResult
9
-
10
-
11
- @pytest.fixture
12
- def perp_api():
13
- return PerpetualApi('http://localhost:2048/')
14
-
15
-
16
- test_address = '0x134089B387E22f52b1e06CC80d9a5F622032EF74'
17
-
18
-
19
- @pytest.mark.skip(
20
- reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
21
- )
22
- def test_perp_contract_address():
23
- contract = perp_contract_address('PERP')
24
- assert contract == '0xbC396689893D065F41bc2C6EcbeE5e0085233447'
25
-
26
-
27
- @pytest.mark.skip(
28
- reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
29
- )
30
- def test_perp_invalid_contract_raises():
31
- with pytest.raises(ValueError, match='Invalid contract name.'):
32
- perp_contract_address("abc")
33
-
34
-
35
- def test_perp_has_coin(perp_api):
36
- assert perp_api.coin.symbol == 'PERP'
37
-
38
-
39
- def filter_infura_key(request):
40
- if 'infura.io' in request.host:
41
- request.uri = 'https://mainnet.infura.io/v3/API_KEY_FILTERED'
42
- return request
43
-
44
-
45
- @pytest.mark.integration
46
- @pytest.mark.skip(
47
- reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
48
- )
49
- def test_fetch():
50
- key = os.environ.get('INFURA_API_KEY')
51
- api = PerpetualApi(f'https://mainnet.infura.io/v3/{key}')
52
- raw = api.fetch_balances(test_address)
53
- assert raw.data
54
-
55
-
56
- @pytest.mark.integration
57
- @pytest.mark.skip(
58
- reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
59
- )
60
- def test_fetch_error():
61
- api = PerpetualApi(f'https://mainnet.infura.io/v3/no-key')
62
- raw = api.fetch_balances(test_address)
63
- assert raw.status_code == 401
64
- assert (
65
- raw.errors[0]
66
- == '401 Client Error: Unauthorized for url: https://mainnet.infura.io/v3/no-key'
67
- )
68
-
69
-
70
- @pytest.mark.skip(
71
- reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
72
- )
73
- def test_fetch_error_raises_from_get_balances():
74
- api = PerpetualApi(f'https://mainnet.infura.io/v3/no-key')
75
- with pytest.raises(ApiException) as exc:
76
- api.get_balance(test_address)
77
-
78
- assert exc.match('401 Client Error: Unauthorized for url')
79
-
80
-
81
- def test_parse(perp_api):
82
- raw = FetchResult(
83
- status_code=200,
84
- data=dict(
85
- staking_claimable='1.10',
86
- vesting_claimable='2.02',
87
- vesting_locked='3.30',
88
- ),
89
- )
90
-
91
- parsed = perp_api.parse_balances(raw)
92
-
93
- assert parsed.data[0].balance == Decimal('3.12')
94
- assert parsed.data[1].balance == Decimal('3.30')
@@ -1,166 +0,0 @@
1
- from decimal import Decimal
2
- from unittest.mock import patch
3
-
4
- import pytest
5
-
6
- from blockapi.test.v2.api.conftest import read_file
7
- from blockapi.v2.api.synthetix import (
8
- SynthetixMainnetApi,
9
- SynthetixOptimismApi,
10
- snx_contract_address,
11
- )
12
- from blockapi.v2.models import AssetType, BalanceItem, Blockchain, Coin
13
-
14
- test_address = '0xE2e4F2A725E42D0F0EF6291F46c430F963482001'
15
- contract_name = 'Synthetix'
16
-
17
-
18
- def mock_redirect(requests_mock, source, target, text):
19
- requests_mock.get(source, status_code=302, headers={'location': target})
20
- requests_mock.get(target, text=text)
21
-
22
-
23
- def test_snx_contract_address_mainnet(requests_mock):
24
- mock_redirect(
25
- requests_mock,
26
- source='https://contracts.synthetix.io/Synthetix',
27
- target='https://etherscan.io/address/0x08F30Ecf2C15A783083ab9D5b9211c22388d0564',
28
- text='',
29
- )
30
-
31
- assert (
32
- snx_contract_address(contract_name)
33
- == '0x08F30Ecf2C15A783083ab9D5b9211c22388d0564'
34
- )
35
-
36
-
37
- def test_snx_contract_address_optimism(requests_mock):
38
- text = read_file('synthetix/data/contracts.md')
39
- requests_mock.get(
40
- 'https://raw.githubusercontent.com/Synthetixio/synthetix-docs/master/content/addresses.md',
41
- text=text,
42
- )
43
-
44
- assert (
45
- snx_contract_address(contract_name, 'optimism')
46
- == '0x49B35BE7D96888C02F342552aB218d859599aCeb'
47
- )
48
-
49
-
50
- def test_invalid_contract_raises(requests_mock):
51
- requests_mock.get('https://contracts.synthetix.io/abc', status_code=404)
52
-
53
- with pytest.raises(ValueError, match='Contract abc not found'):
54
- snx_contract_address('abc')
55
-
56
-
57
- def test_invalid_contract_optimism_raises(requests_mock):
58
- text = read_file('synthetix/data/contracts.md')
59
- requests_mock.get(
60
- 'https://raw.githubusercontent.com/Synthetixio/synthetix-docs/master/content/addresses.md',
61
- text=text,
62
- )
63
-
64
- with pytest.raises(ValueError, match='Contract abc not found'):
65
- snx_contract_address('abc', 'optimism')
66
-
67
-
68
- def test_create_with_custom_api():
69
- api = SynthetixMainnetApi(api_url='http://localhost:1234/')
70
- assert api.w3.provider.endpoint_uri == 'http://localhost:1234/'
71
-
72
-
73
- def test_create_with_custom_optimism_api():
74
- api = SynthetixOptimismApi(api_url='http://localhost:1234/')
75
- assert api.w3.provider.endpoint_uri == 'http://localhost:1234/'
76
-
77
-
78
- @pytest.mark.skip("For some reason VCR cassette doesn't work properly")
79
- @pytest.mark.vcr()
80
- def test_synthetix_optimism_api():
81
- api = SynthetixOptimismApi(api_url='https://mainnet.optimism.io/')
82
- balances = api.get_balance(test_address)
83
-
84
- assert balances == [
85
- BalanceItem(
86
- balance=Decimal('376576.311381339269627458'),
87
- balance_raw=Decimal('376576311381339269627458'),
88
- raw={},
89
- coin=Coin(
90
- symbol='sUSD',
91
- name='sUSD',
92
- decimals=18,
93
- blockchain=Blockchain.OPTIMISM,
94
- address='0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9',
95
- standards=None,
96
- protocol_id=None,
97
- info=None,
98
- ),
99
- asset_type=AssetType.DEBT,
100
- ),
101
- BalanceItem(
102
- balance=Decimal('528051.112125559541484602'),
103
- balance_raw=Decimal('528051112125559541484602'),
104
- raw={},
105
- coin=Coin(
106
- symbol='SNX',
107
- name='SNX',
108
- decimals=18,
109
- blockchain=Blockchain.OPTIMISM,
110
- address='0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4',
111
- standards=None,
112
- protocol_id=None,
113
- info=None,
114
- ),
115
- asset_type=AssetType.STAKED,
116
- ),
117
- BalanceItem(
118
- balance=Decimal('188153.171065910534455462'),
119
- balance_raw=Decimal('188153171065910534455462'),
120
- raw={},
121
- coin=Coin(
122
- symbol='SNX',
123
- name='SNX',
124
- decimals=18,
125
- blockchain=Blockchain.OPTIMISM,
126
- address='0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4',
127
- standards=None,
128
- protocol_id=None,
129
- info=None,
130
- ),
131
- asset_type=AssetType.VESTING,
132
- ),
133
- ]
134
-
135
-
136
- @pytest.fixture()
137
- def mocked_get_synth_contract():
138
- with patch(
139
- 'blockapi.v2.api.synthetix.synthetix.SynthetixApi._get_synth_contract'
140
- ) as patched:
141
- patched.return_value = '0x0000000000000000000000000000000000000000'
142
- yield patched
143
-
144
-
145
- def test_yield_balances_from_staking(mocked_get_synth_contract):
146
- api = SynthetixMainnetApi(api_url='http://localhost:1234/')
147
- staking = {
148
- 'transferable': Decimal(10),
149
- 'debt': Decimal(10),
150
- 'staked': Decimal(10),
151
- 'vesting': Decimal(8),
152
- 'collateral': Decimal(100),
153
- 'rewards': {
154
- 'exchange': Decimal(2),
155
- 'staking': Decimal(3),
156
- },
157
- 'liquidation_reward': Decimal(3),
158
- }
159
-
160
- balances = list(api.yield_balances_from_staking(staking))
161
-
162
- assert balances[2].asset_type == AssetType.STAKED
163
- assert balances[2].balance_raw == Decimal(89)
164
-
165
- assert balances[3].asset_type == AssetType.PRICED_VESTING
166
- assert balances[3].balance_raw == Decimal(8)
File without changes
File without changes
@@ -1 +0,0 @@
1
- from blockapi.v2.api.perpetual.perpetual import PerpetualApi, perp_contract_address