Add tests subpackage. Add TestRestSerializersAndTypes and TestWebsocketSerializersAndTypes unit tests. Fix consistency bugs between serializers and types.

This commit is contained in:
Davide Casale
2023-02-01 17:05:25 +01:00
parent 40a48184da
commit 05784cc8ec
8 changed files with 125 additions and 5 deletions

View File

@@ -28,6 +28,9 @@ class _Serializer(Generic[T]):
def parse(self, *values: Any, skip: Optional[List[str]] = None) -> T:
return cast(T, self.klass(**dict(self._serialize(*values, skip=skip))))
def get_labels(self) -> List[str]:
return [ label for label in self.__labels if label not in self.__IGNORE ]
class _RecursiveSerializer(_Serializer, Generic[T]):
def __init__(self, name: str, klass: Type[_Type], labels: List[str], serializers: Dict[str, _Serializer[Any]], IGNORE: List[str] = ["_PLACEHOLDER"]):
super().__init__(name, klass, labels, IGNORE)

View File

@@ -4,6 +4,26 @@ from .. labeler import generate_labeler_serializer, generate_recursive_serialize
from .. notification import _Notification
__serializers__ = [
"PlatformStatus", "TradingPairTicker", "FundingCurrencyTicker",
"TickersHistory", "TradingPairTrade", "FundingCurrencyTrade",
"TradingPairBook", "FundingCurrencyBook", "TradingPairRawBook",
"FundingCurrencyRawBook", "Statistic", "Candle",
"DerivativesStatus", "Liquidation", "Leaderboard",
"FundingStatistic", "PulseProfile", "PulseMessage",
"TradingMarketAveragePrice", "FundingMarketAveragePrice", "FxRate",
"Order", "Position", "Trade",
"FundingTrade", "OrderTrade", "Ledger",
"FundingOffer", "FundingCredit", "FundingLoan",
"FundingAutoRenew", "FundingInfo", "Wallet",
"Transfer", "Withdrawal", "DepositAddress",
"Invoice", "Movement", "SymbolMarginInfo",
"BaseMarginInfo", "Claim", "IncreaseInfo",
"Increase", "PositionHistory", "PositionSnapshot",
"PositionAudit", "DerivativePositionCollateral", "DerivativePositionCollateralLimits",
]
#region Serializers definition for Rest Public Endpoints
PlatformStatus = generate_labeler_serializer("PlatformStatus", klass=types.PlatformStatus, labels=[
@@ -308,7 +328,7 @@ Position = generate_labeler_serializer("Position", klass=types.Position, labels=
Trade = generate_labeler_serializer("Trade", klass=types.Trade, labels=[
"id",
"pair",
"symbol",
"mts_create",
"order_id",
"exec_amount",
@@ -333,7 +353,7 @@ FundingTrade = generate_labeler_serializer("FundingTrade", klass=types.FundingTr
OrderTrade = generate_labeler_serializer("OrderTrade", klass=types.OrderTrade, labels=[
"id",
"pair",
"symbol",
"mts_create",
"order_id",
"exec_amount",

View File

@@ -6,12 +6,32 @@ from .. labeler import _Type
from .. notification import Notification
from .. utils.encoder import JSON
__types__ = [
"PlatformStatus", "TradingPairTicker", "FundingCurrencyTicker",
"TickersHistory", "TradingPairTrade", "FundingCurrencyTrade",
"TradingPairBook", "FundingCurrencyBook", "TradingPairRawBook",
"FundingCurrencyRawBook", "Statistic", "Candle",
"DerivativesStatus", "Liquidation", "Leaderboard",
"FundingStatistic", "PulseProfile", "PulseMessage",
"TradingMarketAveragePrice", "FundingMarketAveragePrice", "FxRate",
"Order", "Position", "Trade",
"FundingTrade", "OrderTrade", "Ledger",
"FundingOffer", "FundingCredit", "FundingLoan",
"FundingAutoRenew", "FundingInfo", "Wallet",
"Transfer", "Withdrawal", "DepositAddress",
"Invoice", "Movement", "SymbolMarginInfo",
"BaseMarginInfo", "Claim", "IncreaseInfo",
"Increase", "PositionHistory", "PositionSnapshot",
"PositionAudit", "DerivativePositionCollateral", "DerivativePositionCollateralLimits",
]
#region Type hinting for Rest Public Endpoints
@dataclass
class PlatformStatus(_Type):
status: int
@dataclass
class TradingPairTicker(_Type):
symbol: Optional[str]

8
bfxapi/tests/__init__.py Normal file
View File

@@ -0,0 +1,8 @@
import unittest
from .test_rest_serializers_and_types import TestRestSerializersAndTypes
from .test_websocket_serializers_and_types import TestWebsocketSerializersAndTypes
NAME = "tests"
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,23 @@
import unittest
from ..rest import serializers, types
class TestRestSerializersAndTypes(unittest.TestCase):
def test_consistency(self):
__types__ = list(map(types.__dict__.get, types.__types__))
for serializer in map(serializers.__dict__.get, serializers.__serializers__):
type = types.__dict__.get(serializer.name)
__types__.remove(type)
self.assertIsNotNone(type, f"_Serializer <{serializer.name}>: no respective _Type found in bfxapi.rest.types.")
self.assertEqual(serializer.klass, type, f"_Serializer <{serializer.name}>.klass: field does not match with respective _Type in bfxapi.rest.types.")
self.assertListEqual(serializer.get_labels(), list(type.__annotations__),
f"_Serializer <{serializer.name}> and _Type <{type.__name__}> must have matching labels and fields.")
for type in __types__:
self.fail(f"_Type <{type.__name__}>: no respective _Serializer found in bfxapi.rest.serializers.")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,23 @@
import unittest
from ..websocket import serializers, types
class TestWebsocketSerializersAndTypes(unittest.TestCase):
def test_consistency(self):
__types__ = list(map(types.__dict__.get, types.__types__))
for serializer in map(serializers.__dict__.get, serializers.__serializers__):
type = types.__dict__.get(serializer.name)
__types__.remove(type)
self.assertIsNotNone(type, f"_Serializer <{serializer.name}>: no respective _Type found in bfxapi.websocket.types.")
self.assertEqual(serializer.klass, type, f"_Serializer <{serializer.name}>.klass: field does not match with respective _Type in bfxapi.websocket.types.")
self.assertListEqual(serializer.get_labels(), list(type.__annotations__),
f"_Serializer <{serializer.name}> and _Type <{type.__name__}> must have matching labels and fields.")
for type in __types__:
self.fail(f"_Type <{type.__name__}>: no respective _Serializer found in bfxapi.websocket.serializers.")
if __name__ == "__main__":
unittest.main()

View File

@@ -4,6 +4,17 @@ from .. labeler import generate_labeler_serializer
from .. notification import _Notification
__serializers__ = [
"TradingPairTicker", "FundingCurrencyTicker", "TradingPairTrade",
"FundingCurrencyTrade", "TradingPairBook", "FundingCurrencyBook",
"TradingPairRawBook", "FundingCurrencyRawBook", "Candle",
"DerivativesStatus",
"Order", "Position", "Trade",
"FundingOffer", "FundingCredit", "FundingLoan",
"Wallet", "Balance",
]
#region Serializers definition for Websocket Public Channels
TradingPairTicker = generate_labeler_serializer("TradingPairTicker", klass=types.TradingPairTicker, labels=[
@@ -32,7 +43,7 @@ FundingCurrencyTicker = generate_labeler_serializer("FundingCurrencyTicker", kla
"last_price",
"volume",
"high",
"low"
"low",
"_PLACEHOLDER",
"_PLACEHOLDER",
"frr_amount_available"
@@ -100,7 +111,7 @@ DerivativesStatus = generate_labeler_serializer("DerivativesStatus", klass=types
"next_funding_accrued",
"next_funding_step",
"_PLACEHOLDER",
"current_funding"
"current_funding",
"_PLACEHOLDER",
"_PLACEHOLDER",
"mark_price",

View File

@@ -6,6 +6,17 @@ from ..labeler import _Type
from ..notification import Notification
from .. utils.encoder import JSON
__types__ = [
"TradingPairTicker", "FundingCurrencyTicker", "TradingPairTrade",
"FundingCurrencyTrade", "TradingPairBook", "FundingCurrencyBook",
"TradingPairRawBook", "FundingCurrencyRawBook", "Candle",
"DerivativesStatus",
"Order", "Position", "Trade",
"FundingOffer", "FundingCredit", "FundingLoan",
"Wallet", "Balance",
]
#region Type hinting for Websocket Public Channels
@dataclass
@@ -143,6 +154,7 @@ class Position(_Type):
pl_perc: float
price_liq: float
leverage: float
flag: int
position_id: int
mts_create: int
mts_update: int