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
30 changes: 9 additions & 21 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
"""Shared test fixtures, constants, and markers.
"""Shared test fixtures and constants.

Centralizes the API key / base URL resolution, the live client fixtures
(``datamaxi`` / ``telegram`` / ``naver``), and the ``_FLAKY_PROD_DATA_XFAIL``
marker that ``test_call.py`` and ``test_integration.py`` previously
copy-pasted verbatim.
Centralizes the API key / base URL resolution and the live client fixtures
(``datamaxi`` / ``telegram`` / ``naver``).
"""

import os
Expand All @@ -16,34 +14,24 @@
# honor DATAMAXI_API_KEY (preferred) and the legacy API_KEY.
API_KEY = os.getenv("DATAMAXI_API_KEY") or os.getenv("API_KEY")
BASE_URL = os.getenv("BASE_URL") or "https://api.datamaxiplus.com"

# Shared xfail marker for tests whose outcome depends on prod-data
# availability — funding-rate / naver-trend state are NATS-warmed in-memory
# caches on the API pods, so any cold-start of the API fleet leaves them
# temporarily empty and the smoke-style tests raise ServerError(500, "no data
# found"). Marked strict=False so they pass cleanly once the cache is hot.
_FLAKY_PROD_DATA_XFAIL = pytest.mark.xfail(
reason=(
"Depends on prod NATS-warmed state; intermittent 500 'no data found' "
"on cold pods. Pre-existing flakiness — unrelated to SDK regen."
),
strict=False,
)
# Live-lane timeout: larger than the SDK's 10s default so slow prod endpoints
# (e.g. unfiltered premium) don't ReadTimeout on the smoke/integration tests.
TIMEOUT = int(os.getenv("DATAMAXI_TIMEOUT") or "30")


@pytest.fixture(scope="module")
def datamaxi():
"""Create Datamaxi client for live tests."""
return Datamaxi(api_key=API_KEY, base_url=BASE_URL)
return Datamaxi(api_key=API_KEY, base_url=BASE_URL, timeout=TIMEOUT)


@pytest.fixture(scope="module")
def telegram():
"""Create Telegram client for live tests."""
return Telegram(api_key=API_KEY, base_url=BASE_URL)
return Telegram(api_key=API_KEY, base_url=BASE_URL, timeout=TIMEOUT)


@pytest.fixture(scope="module")
def naver():
"""Create Naver client for live tests."""
return Naver(api_key=API_KEY, base_url=BASE_URL)
return Naver(api_key=API_KEY, base_url=BASE_URL, timeout=TIMEOUT)
6 changes: 2 additions & 4 deletions tests/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import pytest

from tests.conftest import API_KEY, _FLAKY_PROD_DATA_XFAIL
from tests.conftest import API_KEY

# Live alive-check / smoke lane: a thin subset of test_integration.py that
# pings each endpoint once. Skipped without a key and deselected from the
Expand Down Expand Up @@ -70,7 +70,6 @@ def test_cex_wallet_status(datamaxi):
datamaxi.cex.wallet_status.assets(exchange="binance")


@_FLAKY_PROD_DATA_XFAIL
def test_funding_rate(datamaxi):
"""Smoke test for funding rate endpoints."""
datamaxi.funding_rate.history(exchange="binance", symbol="BTC-USDT")
Expand All @@ -87,7 +86,7 @@ def test_forex(datamaxi):

def test_premium(datamaxi):
"""Smoke test for premium endpoints."""
datamaxi.premium()
datamaxi.premium(limit=10)
datamaxi.premium.exchanges()


Expand All @@ -97,7 +96,6 @@ def test_telegram(telegram):
telegram.messages()


@_FLAKY_PROD_DATA_XFAIL
def test_naver(naver):
"""Smoke test for naver endpoints."""
naver.symbols()
Expand Down
39 changes: 5 additions & 34 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import pandas as pd
from datetime import datetime, timedelta

from datamaxi.error import ClientError
from tests.conftest import API_KEY, _FLAKY_PROD_DATA_XFAIL
from datamaxi.error import ParameterRequiredError
from tests.conftest import API_KEY

# Live integration lane: exercises prod endpoints with every supported param.
# Skipped without a key and deselected from the keyless CI lane via the
Expand Down Expand Up @@ -74,9 +74,9 @@ def test_symbols_with_exchange_only(self, datamaxi):
assert len(result) > 0

def test_symbols_with_market_only(self, datamaxi):
"""Test getting symbols with only market - requires exchange in API."""
# Note: API requires exchange parameter, so this should raise ClientError
with pytest.raises(ClientError):
"""Test getting symbols with only market - exchange is mandatory."""
# exchange is a required param, validated client-side before the API call.
with pytest.raises(ParameterRequiredError):
datamaxi.cex.candle.symbols(market="spot")

def test_intervals(self, datamaxi):
Expand Down Expand Up @@ -553,7 +553,6 @@ def test_history_both_from_and_to_datetime(self, datamaxi):
toDateTime=to_dt,
)

@_FLAKY_PROD_DATA_XFAIL
def test_latest_basic(self, datamaxi):
"""Test basic latest funding rate fetch."""
result = datamaxi.funding_rate.latest(
Expand All @@ -563,7 +562,6 @@ def test_latest_basic(self, datamaxi):
assert isinstance(result, pd.DataFrame)
assert len(result) == 1

@_FLAKY_PROD_DATA_XFAIL
def test_latest_pandas_false(self, datamaxi):
"""Test latest funding rate with pandas=False."""
result = datamaxi.funding_rate.latest(
Expand Down Expand Up @@ -675,33 +673,11 @@ def test_premium_token_include(self, datamaxi):
result = datamaxi.premium(token_include="bitcoin", limit=10)
assert isinstance(result, pd.DataFrame)

@pytest.mark.xfail(
reason=(
"Flaky against prod data — the SDK raises ValueError('no data found') "
"whenever /api/v1/premium returns an empty page, and the specific "
"(token_exclude=SHIB, limit=10) combination hits an empty window "
"depending on the active premium feed. Test has failed continuously "
"on Python 3.14 since 2026-04-22 (well before this PR). Tracked for "
"a follow-up that either makes the SDK return empty cleanly or picks "
"params with guaranteed-non-empty output."
),
strict=False,
)
def test_premium_token_exclude(self, datamaxi):
"""Test premium data with token_exclude filter."""
result = datamaxi.premium(token_exclude="SHIB", limit=10)
assert isinstance(result, pd.DataFrame)

@pytest.mark.xfail(
reason=(
"Same flake as test_premium_token_exclude — premium(pandas=False, "
"limit=10) intermittently hits an empty page on prod and the SDK "
"raises instead of returning the empty envelope. Pre-existing "
"(failing since 2026-04-22); follow-up should normalize empty-result "
"behavior in the SDK."
),
strict=False,
)
def test_premium_pandas_false(self, datamaxi):
"""Test premium data with pandas=False."""
result = datamaxi.premium(pandas=False, limit=10)
Expand Down Expand Up @@ -839,27 +815,23 @@ def test_messages_pagination_next_request(self, telegram):
class TestNaver:
"""Test Naver endpoints with all parameters."""

@_FLAKY_PROD_DATA_XFAIL
def test_symbols(self, naver):
"""Test getting supported symbols."""
result = naver.symbols()
assert isinstance(result, list)
assert len(result) > 0

@_FLAKY_PROD_DATA_XFAIL
def test_trend_basic(self, naver):
"""Test basic trend data fetch."""
result = naver.trend("BTC")
assert hasattr(result, "head")
assert len(result) > 0

@_FLAKY_PROD_DATA_XFAIL
def test_trend_different_symbol(self, naver):
"""Test trend data for different symbol."""
result = naver.trend("ETH")
assert hasattr(result, "head")

@_FLAKY_PROD_DATA_XFAIL
def test_trend_pandas_false(self, naver):
"""Test trend data with pandas=False."""
result = naver.trend("BTC", pandas=False)
Expand Down Expand Up @@ -899,7 +871,6 @@ def test_wallet_status_dataframe_index(self, datamaxi):
result = datamaxi.cex.wallet_status(exchange="binance", asset="BTC")
assert result.index.name == "network"

@_FLAKY_PROD_DATA_XFAIL
def test_funding_rate_latest_single_row(self, datamaxi):
"""Test that latest funding rate returns single row."""
result = datamaxi.funding_rate.latest(
Expand Down
Loading