blockapi 2.10.3__tar.gz → 2.10.5__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 (103) hide show
  1. {blockapi-2.10.3 → blockapi-2.10.5}/PKG-INFO +1 -1
  2. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/services.py +3 -0
  3. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/nft/test_opensea.py +3 -1
  4. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/nft/test_simple_hash.py +3 -1
  5. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/utils/datetime.py +6 -1
  6. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/debank.py +7 -11
  7. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/nft/unisat.py +2 -2
  8. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/base.py +4 -4
  9. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/models.py +8 -6
  10. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi.egg-info/PKG-INFO +1 -1
  11. {blockapi-2.10.3 → blockapi-2.10.5}/setup.py +1 -1
  12. {blockapi-2.10.3 → blockapi-2.10.5}/LICENSE.md +0 -0
  13. {blockapi-2.10.3 → blockapi-2.10.5}/README.md +0 -0
  14. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/__init__.py +0 -0
  15. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/__init__.py +0 -0
  16. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/test_blockapi.py +0 -0
  17. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/test_num.py +0 -0
  18. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/test_random_user_agent.py +0 -0
  19. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/__init__.py +0 -0
  20. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/__init__.py +0 -0
  21. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/conftest.py +0 -0
  22. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
  23. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
  24. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
  25. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/nft/__init__.py +0 -0
  26. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
  27. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
  28. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_bitaps_ltc.py +0 -0
  29. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_blockchain_info.py +0 -0
  30. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_blockchainos.py +0 -0
  31. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
  32. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
  33. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
  34. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_cosmos.py +0 -0
  35. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_ethplorer.py +0 -0
  36. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_haskoin.py +0 -0
  37. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_litecoinspace.py +0 -0
  38. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_multisources.py +0 -0
  39. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
  40. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_solana.py +0 -0
  41. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
  42. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_sui.py +0 -0
  43. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_terra.py +0 -0
  44. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
  45. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/api/test_trezor_zec.py +0 -0
  46. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/test_base.py +0 -0
  47. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/test_blockchain_api.py +0 -0
  48. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
  49. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/test_data.py +0 -0
  50. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/test_enumerate_classes.py +0 -0
  51. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/test_generic.py +0 -0
  52. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test/v2/test_models.py +0 -0
  53. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/test_data.py +0 -0
  54. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/utils/__init__.py +0 -0
  55. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/utils/address.py +0 -0
  56. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/utils/num.py +0 -0
  57. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/utils/user_agent.py +0 -0
  58. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/__init__.py +0 -0
  59. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/__init__.py +0 -0
  60. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/bitaps.py +0 -0
  61. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/blockchain_info.py +0 -0
  62. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/blockchainos.py +0 -0
  63. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/blockchair.py +0 -0
  64. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/cosmos.py +0 -0
  65. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/__init__.py +0 -0
  66. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
  67. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/astar.py +0 -0
  68. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/avalanche.py +0 -0
  69. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/axie.py +0 -0
  70. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/base.py +0 -0
  71. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
  72. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/ethereum.py +0 -0
  73. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/fantom.py +0 -0
  74. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/heco.py +0 -0
  75. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/iotex.py +0 -0
  76. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/klaytn.py +0 -0
  77. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
  78. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/palm.py +0 -0
  79. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/polygon.py +0 -0
  80. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/covalenth/rsk.py +0 -0
  81. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/debank_maps.py +0 -0
  82. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/ethplorer.py +0 -0
  83. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/haskoin.py +0 -0
  84. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/litecoinspace.py +0 -0
  85. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/nft/__init__.py +0 -0
  86. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/nft/magic_eden.py +0 -0
  87. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/nft/opensea.py +0 -0
  88. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/nft/simple_hash.py +0 -0
  89. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/optimistic_etherscan.py +0 -0
  90. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/solana.py +0 -0
  91. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/subscan.py +0 -0
  92. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/sui.py +0 -0
  93. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/terra.py +0 -0
  94. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/api/trezor.py +0 -0
  95. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/blockchain_mapping.py +0 -0
  96. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/coin_mapping.py +0 -0
  97. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi/v2/coins.py +0 -0
  98. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi.egg-info/SOURCES.txt +0 -0
  99. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi.egg-info/dependency_links.txt +0 -0
  100. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi.egg-info/requires.txt +0 -0
  101. {blockapi-2.10.3 → blockapi-2.10.5}/blockapi.egg-info/top_level.txt +0 -0
  102. {blockapi-2.10.3 → blockapi-2.10.5}/pyproject.toml +0 -0
  103. {blockapi-2.10.3 → blockapi-2.10.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blockapi
3
- Version: 2.10.3
3
+ Version: 2.10.5
4
4
  Summary: BlockAPI library
5
5
  Home-page: https://github.com/crypkit/blockapi
6
6
  Author: Devmons s.r.o.
@@ -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
@@ -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:
@@ -180,10 +180,7 @@ class DebankProtocolParser:
180
180
 
181
181
  @staticmethod
182
182
  def parse_item(item: DebankModelProtocol) -> Optional[Protocol]:
183
- blockchain = get_blockchain_from_debank_chain(item.chain)
184
- if not blockchain:
185
- logger.warning(f'No blockchain found for protocol {item.id}. Skipping.')
186
- return None
183
+ blockchain = get_blockchain_from_debank_chain(item.chain) or item.chain
187
184
 
188
185
  return Protocol.from_api(
189
186
  protocol_id=item.id,
@@ -243,6 +240,9 @@ class DebankProtocolCache:
243
240
  def __init__(self, timeout: int = 3600):
244
241
  self._timeout: int = timeout
245
242
  self._data: Dict[str, Protocol] = {}
243
+ # Naive local time on purpose: _timelimit is only ever compared against
244
+ # other datetime.now() values here (cache TTL), never mixed with the
245
+ # tz-aware datetimes used elsewhere, so there is no naive/aware hazard.
246
246
  self._timelimit = datetime.now()
247
247
 
248
248
  def invalidate(self):
@@ -326,12 +326,6 @@ class DebankBalanceParser:
326
326
  )
327
327
  return None
328
328
 
329
- if not coin.blockchain:
330
- logger.error(
331
- f'DeBank: Skipping balance - could not parse blockchain "{balance_item.chain}". Amount={amount} (raw={raw_amount})'
332
- )
333
- return None
334
-
335
329
  if asset_type == AssetType.INVESTMENT and amount < 0:
336
330
  asset_type = AssetType.DEBT
337
331
  amount = -amount
@@ -360,7 +354,9 @@ class DebankBalanceParser:
360
354
 
361
355
  def get_coin(self, balance_item: DebankModelBalanceItem) -> Coin:
362
356
  contract = balance_item.id
363
- blockchain = get_blockchain_from_debank_chain(balance_item.chain)
357
+ blockchain = (
358
+ get_blockchain_from_debank_chain(balance_item.chain) or balance_item.chain
359
+ )
364
360
  symbol = self.get_symbol(balance_item)
365
361
 
366
362
  coingecko_id = get_coingecko_id(contract, symbol)
@@ -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
 
@@ -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
@@ -561,7 +561,7 @@ class Coin:
561
561
  symbol: str
562
562
  name: str
563
563
  decimals: int
564
- blockchain: Blockchain
564
+ blockchain: Union[Blockchain, str]
565
565
  address: Optional[str] = attr.ib(default=None)
566
566
  standards: Optional[List[str]] = attr.ib(default=None)
567
567
  protocol_id: Optional[str] = attr.ib(default=None)
@@ -576,7 +576,7 @@ class Coin:
576
576
  @classmethod
577
577
  def from_api(
578
578
  cls,
579
- blockchain: Blockchain,
579
+ blockchain: Union[Blockchain, str],
580
580
  decimals: Union[int, str],
581
581
  symbol: Optional[str] = None,
582
582
  name: Optional[str] = None,
@@ -607,7 +607,7 @@ class CoingeckoMapping:
607
607
  @attr.s(auto_attribs=True, slots=True, frozen=True)
608
608
  class Protocol:
609
609
  protocol_id: str
610
- chain: Blockchain
610
+ chain: Union[Blockchain, str]
611
611
  name: str
612
612
  user_deposit: Decimal
613
613
  site_url: Optional[str] = attr.ib(default=None)
@@ -619,7 +619,7 @@ class Protocol:
619
619
  cls,
620
620
  *,
621
621
  protocol_id: str,
622
- chain: Blockchain,
622
+ chain: Union[Blockchain, str],
623
623
  name: str,
624
624
  user_deposit: Union[str, float, int],
625
625
  site_url: Optional[str] = None,
@@ -863,7 +863,9 @@ class NftOffer:
863
863
  contract=contract,
864
864
  blockchain=blockchain,
865
865
  offerer=offerer,
866
- 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
+ ),
867
869
  end_time=parse_dt(end_time) if end_time else None,
868
870
  offer_coin=offer_coin,
869
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.3
3
+ Version: 2.10.5
4
4
  Summary: BlockAPI library
5
5
  Home-page: https://github.com/crypkit/blockapi
6
6
  Author: Devmons s.r.o.
@@ -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.3"
9
+ __version__ = "2.10.5"
10
10
 
11
11
  setuptools.setup(
12
12
  name='blockapi',
File without changes
File without changes
File without changes
File without changes