Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions blockapi/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ def request(
response = reqobj.get(request_url, headers=headers)

self.last_response = response
# Naive local time on purpose: only used to measure elapsed time against
# datetime.now() in wait_for_next_request (rate limiting), never compared
# with tz-aware datetimes.
self.last_response_time = datetime.now()

if response.status_code != 200:
Expand Down
4 changes: 2 additions & 2 deletions blockapi/test/v2/api/debank/test_debank_usage_parser.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime
from datetime import datetime, timezone
from decimal import Decimal


Expand All @@ -10,4 +10,4 @@ def test_can_parse_usage(usage_parser, debank_usage_response):
stats = parsed.stats[0]
assert stats.remains == Decimal('351978')
assert stats.usage == Decimal('13162')
assert stats.date == datetime(2023, 3, 20)
assert stats.date == datetime(2023, 3, 20, tzinfo=timezone.utc)
4 changes: 3 additions & 1 deletion blockapi/test/v2/api/nft/test_opensea.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@ def test_parse_nfts(requests_mock, api, nfts_response, nfts_next_response):
== 'data:application/json;base64,eyJuYW1lIjoiVW5pc3dhcCAtIDElIC0gUFJJTUUvV0VUSCAtIDMzMC4yMDw+NzgwLjI5In0='
)
assert not data.metadata
assert data.updated_time == datetime.datetime(2023, 8, 15, 13, 56, 39, 759414)
assert data.updated_time == datetime.datetime(
2023, 8, 15, 13, 56, 39, 759414, tzinfo=datetime.timezone.utc
)
assert not data.is_disabled
assert not data.is_nsfw
assert data.blockchain == Blockchain.ETHEREUM
Expand Down
4 changes: 3 additions & 1 deletion blockapi/test/v2/api/nft/test_simple_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ def test_parse_nfts(requests_mock, api, nfts_response):
)
assert not data.metadata_url
assert not data.metadata
assert data.updated_time == datetime.datetime(2023, 3, 11, 3, 46, 15)
assert data.updated_time == datetime.datetime(
2023, 3, 11, 3, 46, 15, tzinfo=datetime.timezone.utc
)
assert not data.is_disabled
assert not data.is_nsfw
assert data.blockchain == Blockchain.BITCOIN
Expand Down
7 changes: 6 additions & 1 deletion blockapi/utils/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ def parse_dt(dt: Union[str, int, float]) -> datetime:
try:
return datetime.fromtimestamp(int(dt), tz=timezone.utc)
except ValueError:
return parse_date(dt)
parsed = parse_date(dt)
# Assume UTC for strings that carry no timezone, so parse_dt always
# returns a tz-aware datetime (consistent with the numeric paths).
if parsed.tzinfo is None:
parsed = parsed.replace(tzinfo=timezone.utc)
return parsed
elif isinstance(dt, int) or isinstance(dt, float):
return datetime.fromtimestamp(dt, tz=timezone.utc)
else:
Expand Down
3 changes: 3 additions & 0 deletions blockapi/v2/api/debank.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ class DebankProtocolCache:
def __init__(self, timeout: int = 3600):
self._timeout: int = timeout
self._data: Dict[str, Protocol] = {}
# Naive local time on purpose: _timelimit is only ever compared against
# other datetime.now() values here (cache TTL), never mixed with the
# tz-aware datetimes used elsewhere, so there is no naive/aware hazard.
self._timelimit = datetime.now()

def invalidate(self):
Expand Down
4 changes: 2 additions & 2 deletions blockapi/v2/api/nft/unisat.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from typing import Optional, Dict, Generator, Tuple
from enum import Enum
from datetime import datetime
from datetime import datetime, timezone

from blockapi.v2.base import BlockchainApi, INftParser, INftProvider, ISleepProvider
from blockapi.v2.coins import COIN_BTC
Expand Down Expand Up @@ -670,7 +670,7 @@ def _yield_parsed_offers(
try:
timestamp_seconds = timestamp / 1000
formatted_time = datetime.fromtimestamp(
timestamp_seconds
timestamp_seconds, tz=timezone.utc
).isoformat()
except (ValueError, TypeError, OverflowError):
logger.warning(
Expand Down
8 changes: 4 additions & 4 deletions blockapi/v2/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
import time
from abc import ABC
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from typing import Dict, List, Optional
from urllib.parse import urljoin

Expand Down Expand Up @@ -107,7 +107,7 @@ def get_data(
return FetchResult(
status_code=1,
errors=[str(connection_error)],
time=datetime.utcnow(),
time=datetime.now(timezone.utc),
)

self.sleep_provider.sleep(self.base_url, seconds=sleep_seconds)
Expand Down Expand Up @@ -155,7 +155,7 @@ def get_data(
headers=dict(),
errors=[f'{type(ex).__name__}: {str(ex)}'],
extra=extra,
time=datetime.utcnow(),
time=datetime.now(timezone.utc),
)

time = self._get_response_time(response.headers)
Expand Down Expand Up @@ -236,7 +236,7 @@ def _get_response_time(headers) -> Optional[datetime]:
return parse_dt(date_str)

if age_str := headers.get('age'):
return datetime.utcnow() - timedelta(seconds=int(age_str))
return datetime.now(timezone.utc) - timedelta(seconds=int(age_str))

return None

Expand Down
6 changes: 4 additions & 2 deletions blockapi/v2/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import json
from datetime import datetime
from datetime import datetime, timezone
from decimal import Decimal
from enum import Enum
from typing import Dict, List, Literal, Optional, Union
Expand Down Expand Up @@ -863,7 +863,9 @@ def from_api(
contract=contract,
blockchain=blockchain,
offerer=offerer,
start_time=parse_dt(start_time) if start_time else datetime.utcnow(),
start_time=(
parse_dt(start_time) if start_time else datetime.now(timezone.utc)
),
end_time=parse_dt(end_time) if end_time else None,
offer_coin=offer_coin,
offer_contract=offer_contract.lower() if offer_contract else None,
Expand Down
Loading