Refactor project structure to organize APIs (#24)
* Refactor project structure "api" * fix bug conversione delle valute fiat in stablecoin in BinanceWrapper * Refactor: WrapperHandler for managing API wrappers with retry logic; update related modules and tests * Refactor: Update ProductInfo and Price classes to include aggregation methods; remove standalone aggregation functions * fix docs
This commit was merged in pull request #24.
This commit is contained in:
committed by
GitHub
parent
517842c834
commit
093a7f5a48
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
from app.agents import AppModels
|
||||
from app.agents.predictor import PREDICTOR_INSTRUCTIONS, PredictorInput, PredictorOutput, PredictorStyle
|
||||
from app.base.markets import ProductInfo
|
||||
from app.api.base.markets import ProductInfo
|
||||
|
||||
def unified_checks(model: AppModels, input: PredictorInput) -> None:
|
||||
llm = model.get_agent(PREDICTOR_INSTRUCTIONS, output_schema=PredictorOutput) # type: ignore[arg-type]
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
import pytest
|
||||
from app.markets.binance import BinanceWrapper
|
||||
import asyncio
|
||||
from app.api.markets.binance import BinanceWrapper
|
||||
|
||||
# fix warning about no event loop
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def event_loop():
|
||||
"""
|
||||
Ensure there is an event loop for the duration of the tests.
|
||||
"""
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
yield loop
|
||||
loop.close()
|
||||
|
||||
|
||||
@pytest.mark.market
|
||||
@pytest.mark.api
|
||||
@@ -51,3 +64,18 @@ class TestBinance:
|
||||
assert entry.close > 0
|
||||
assert entry.high > 0
|
||||
assert entry.timestamp != ''
|
||||
|
||||
def test_binance_fiat_conversion(self):
|
||||
market = BinanceWrapper(currency="USD")
|
||||
assert market.currency == "USDT"
|
||||
product = market.get_product("BTC")
|
||||
assert product is not None
|
||||
assert product.symbol == "BTC"
|
||||
assert product.price > 0
|
||||
|
||||
market = BinanceWrapper(currency="EUR")
|
||||
assert market.currency == "EUR"
|
||||
product = market.get_product("BTC")
|
||||
assert product is not None
|
||||
assert product.symbol == "BTC"
|
||||
assert product.price > 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
import pytest
|
||||
from app.markets import CoinBaseWrapper
|
||||
from app.api.markets import CoinBaseWrapper
|
||||
|
||||
@pytest.mark.market
|
||||
@pytest.mark.api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
import pytest
|
||||
from app.markets import CryptoCompareWrapper
|
||||
from app.api.markets import CryptoCompareWrapper
|
||||
|
||||
@pytest.mark.market
|
||||
@pytest.mark.api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
import pytest
|
||||
from app.news import CryptoPanicWrapper
|
||||
from app.api.news import CryptoPanicWrapper
|
||||
|
||||
|
||||
@pytest.mark.limited
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from app.news import DuckDuckGoWrapper
|
||||
from app.api.news import DuckDuckGoWrapper
|
||||
|
||||
|
||||
@pytest.mark.news
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from app.news import GoogleNewsWrapper
|
||||
from app.api.news import GoogleNewsWrapper
|
||||
|
||||
|
||||
@pytest.mark.news
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
import pytest
|
||||
from app.news import NewsApiWrapper
|
||||
from app.api.news import NewsApiWrapper
|
||||
|
||||
|
||||
@pytest.mark.news
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
import pytest
|
||||
from app.social.reddit import MAX_COMMENTS, RedditWrapper
|
||||
from app.api.social.reddit import MAX_COMMENTS, RedditWrapper
|
||||
|
||||
@pytest.mark.social
|
||||
@pytest.mark.api
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from app.markets import YFinanceWrapper
|
||||
from app.api.markets import YFinanceWrapper
|
||||
|
||||
@pytest.mark.market
|
||||
@pytest.mark.api
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from app.markets import MarketAPIsTool
|
||||
from app.api.markets import MarketAPIsTool
|
||||
|
||||
|
||||
@pytest.mark.tools
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from app.news import NewsAPIsTool
|
||||
from app.api.news import NewsAPIsTool
|
||||
|
||||
|
||||
@pytest.mark.tools
|
||||
@@ -12,7 +12,7 @@ class TestNewsAPITool:
|
||||
|
||||
def test_news_api_tool_get_top(self):
|
||||
tool = NewsAPIsTool()
|
||||
result = tool.wrapper_handler.try_call(lambda w: w.get_top_headlines(limit=2))
|
||||
result = tool.handler.try_call(lambda w: w.get_top_headlines(limit=2))
|
||||
assert isinstance(result, list)
|
||||
assert len(result) > 0
|
||||
for article in result:
|
||||
@@ -21,7 +21,7 @@ class TestNewsAPITool:
|
||||
|
||||
def test_news_api_tool_get_latest(self):
|
||||
tool = NewsAPIsTool()
|
||||
result = tool.wrapper_handler.try_call(lambda w: w.get_latest_news(query="crypto", limit=2))
|
||||
result = tool.handler.try_call(lambda w: w.get_latest_news(query="crypto", limit=2))
|
||||
assert isinstance(result, list)
|
||||
assert len(result) > 0
|
||||
for article in result:
|
||||
@@ -30,7 +30,7 @@ class TestNewsAPITool:
|
||||
|
||||
def test_news_api_tool_get_top__all_results(self):
|
||||
tool = NewsAPIsTool()
|
||||
result = tool.wrapper_handler.try_call_all(lambda w: w.get_top_headlines(limit=2))
|
||||
result = tool.handler.try_call_all(lambda w: w.get_top_headlines(limit=2))
|
||||
assert isinstance(result, dict)
|
||||
assert len(result.keys()) > 0
|
||||
for _provider, articles in result.items():
|
||||
@@ -40,7 +40,7 @@ class TestNewsAPITool:
|
||||
|
||||
def test_news_api_tool_get_latest__all_results(self):
|
||||
tool = NewsAPIsTool()
|
||||
result = tool.wrapper_handler.try_call_all(lambda w: w.get_latest_news(query="crypto", limit=2))
|
||||
result = tool.handler.try_call_all(lambda w: w.get_latest_news(query="crypto", limit=2))
|
||||
assert isinstance(result, dict)
|
||||
assert len(result.keys()) > 0
|
||||
for _provider, articles in result.items():
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from app.social import SocialAPIsTool
|
||||
from app.api.social import SocialAPIsTool
|
||||
|
||||
|
||||
@pytest.mark.tools
|
||||
@@ -12,7 +12,7 @@ class TestSocialAPIsTool:
|
||||
|
||||
def test_social_api_tool_get_top(self):
|
||||
tool = SocialAPIsTool()
|
||||
result = tool.wrapper_handler.try_call(lambda w: w.get_top_crypto_posts(limit=2))
|
||||
result = tool.handler.try_call(lambda w: w.get_top_crypto_posts(limit=2))
|
||||
assert isinstance(result, list)
|
||||
assert len(result) > 0
|
||||
for post in result:
|
||||
@@ -21,10 +21,10 @@ class TestSocialAPIsTool:
|
||||
|
||||
def test_social_api_tool_get_top__all_results(self):
|
||||
tool = SocialAPIsTool()
|
||||
result = tool.wrapper_handler.try_call_all(lambda w: w.get_top_crypto_posts(limit=2))
|
||||
result = tool.handler.try_call_all(lambda w: w.get_top_crypto_posts(limit=2))
|
||||
assert isinstance(result, dict)
|
||||
assert len(result.keys()) > 0
|
||||
for provider, posts in result.items():
|
||||
for _provider, posts in result.items():
|
||||
for post in posts:
|
||||
assert post.title is not None
|
||||
assert post.time is not None
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from app.base.markets import ProductInfo, Price
|
||||
from app.utils.market_aggregation import aggregate_history_prices, aggregate_product_info
|
||||
from app.api.base.markets import ProductInfo, Price
|
||||
|
||||
|
||||
@pytest.mark.aggregator
|
||||
@@ -34,7 +33,7 @@ class TestMarketDataAggregator:
|
||||
"Provider3": [self.__product("BTC", 49900.0, 900.0, "USD")],
|
||||
}
|
||||
|
||||
aggregated = aggregate_product_info(products)
|
||||
aggregated = ProductInfo.aggregate(products)
|
||||
assert len(aggregated) == 1
|
||||
|
||||
info = aggregated[0]
|
||||
@@ -58,7 +57,7 @@ class TestMarketDataAggregator:
|
||||
],
|
||||
}
|
||||
|
||||
aggregated = aggregate_product_info(products)
|
||||
aggregated = ProductInfo.aggregate(products)
|
||||
assert len(aggregated) == 2
|
||||
|
||||
btc_info = next((p for p in aggregated if p.symbol == "BTC"), None)
|
||||
@@ -81,7 +80,7 @@ class TestMarketDataAggregator:
|
||||
"Provider1": [],
|
||||
"Provider2": [],
|
||||
}
|
||||
aggregated = aggregate_product_info(products)
|
||||
aggregated = ProductInfo.aggregate(products)
|
||||
assert len(aggregated) == 0
|
||||
|
||||
def test_aggregate_product_info_with_partial_data(self):
|
||||
@@ -89,7 +88,7 @@ class TestMarketDataAggregator:
|
||||
"Provider1": [self.__product("BTC", 50000.0, 1000.0, "USD")],
|
||||
"Provider2": [],
|
||||
}
|
||||
aggregated = aggregate_product_info(products)
|
||||
aggregated = ProductInfo.aggregate(products)
|
||||
assert len(aggregated) == 1
|
||||
info = aggregated[0]
|
||||
assert info.symbol == "BTC"
|
||||
@@ -120,7 +119,7 @@ class TestMarketDataAggregator:
|
||||
price.set_timestamp(timestamp_s=timestamp_2h_ago)
|
||||
timestamp_2h_ago = price.timestamp
|
||||
|
||||
aggregated = aggregate_history_prices(prices)
|
||||
aggregated = Price.aggregate(prices)
|
||||
assert len(aggregated) == 2
|
||||
assert aggregated[0].timestamp == timestamp_1h_ago
|
||||
assert aggregated[0].high == pytest.approx(50050.0, rel=1e-3) # type: ignore
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from app.utils.wrapper_handler import WrapperHandler
|
||||
from app.api.wrapper_handler import WrapperHandler
|
||||
|
||||
class MockWrapper:
|
||||
def do_something(self) -> str:
|
||||
|
||||
Reference in New Issue
Block a user