mirror of
https://github.com/aljazceru/bitfinex-api-py.git
synced 2025-12-19 06:44:22 +01:00
Improve fidelity to pylint's standard rules.
This commit is contained in:
16
.pylintrc
16
.pylintrc
@@ -3,28 +3,20 @@ py-version=3.8.0
|
|||||||
|
|
||||||
[MESSAGES CONTROL]
|
[MESSAGES CONTROL]
|
||||||
disable=
|
disable=
|
||||||
multiple-imports,
|
|
||||||
missing-docstring,
|
missing-docstring,
|
||||||
logging-not-lazy,
|
multiple-imports,
|
||||||
logging-fstring-interpolation,
|
|
||||||
too-few-public-methods,
|
too-few-public-methods,
|
||||||
too-many-public-methods,
|
too-many-instance-attributes
|
||||||
too-many-instance-attributes,
|
|
||||||
dangerous-default-value,
|
|
||||||
inconsistent-return-statements,
|
|
||||||
|
|
||||||
[SIMILARITIES]
|
|
||||||
min-similarity-lines=6
|
|
||||||
|
|
||||||
[VARIABLES]
|
[VARIABLES]
|
||||||
allowed-redefined-builtins=type,dir,id,all,format,len
|
allowed-redefined-builtins=all,dir,format,id,len,type
|
||||||
|
|
||||||
[FORMAT]
|
[FORMAT]
|
||||||
max-line-length=120
|
max-line-length=120
|
||||||
expected-line-ending-format=LF
|
expected-line-ending-format=LF
|
||||||
|
|
||||||
[BASIC]
|
[BASIC]
|
||||||
good-names=t,f,id,ip,on,pl,tf,to,A,B,C,D,E,F
|
good-names=f,t,id,ip,on,pl,tf,to,A,B,C,D,E,F
|
||||||
|
|
||||||
[TYPECHECK]
|
[TYPECHECK]
|
||||||
generated-members=websockets
|
generated-members=websockets
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from typing import \
|
from typing import \
|
||||||
TYPE_CHECKING, List, Literal, Optional
|
TYPE_CHECKING, List, Optional
|
||||||
|
|
||||||
from bfxapi._utils.logging import ColorLogger
|
from bfxapi._utils.logging import ColorLogger
|
||||||
|
|
||||||
@@ -23,8 +23,7 @@ class Client:
|
|||||||
wss_host: str = WSS_HOST,
|
wss_host: str = WSS_HOST,
|
||||||
filters: Optional[List[str]] = None,
|
filters: Optional[List[str]] = None,
|
||||||
timeout: Optional[int] = 60 * 15,
|
timeout: Optional[int] = 60 * 15,
|
||||||
log_filename: Optional[str] = None,
|
log_filename: Optional[str] = None
|
||||||
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO"
|
|
||||||
) -> None:
|
) -> None:
|
||||||
credentials: Optional["_Credentials"] = None
|
credentials: Optional["_Credentials"] = None
|
||||||
|
|
||||||
@@ -40,7 +39,7 @@ class Client:
|
|||||||
|
|
||||||
self.rest = BfxRestInterface(rest_host, api_key, api_secret)
|
self.rest = BfxRestInterface(rest_host, api_key, api_secret)
|
||||||
|
|
||||||
logger = ColorLogger("bfxapi", level=log_level)
|
logger = ColorLogger("bfxapi", level="INFO")
|
||||||
|
|
||||||
if log_filename:
|
if log_filename:
|
||||||
logger.register(filename=log_filename)
|
logger.register(filename=log_filename)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from ...types import serializers
|
|||||||
|
|
||||||
from ...types.serializers import _Notification
|
from ...types.serializers import _Notification
|
||||||
|
|
||||||
|
#pylint: disable-next=too-many-public-methods
|
||||||
class RestAuthEndpoints(Middleware):
|
class RestAuthEndpoints(Middleware):
|
||||||
def get_user_info(self) -> UserInfo:
|
def get_user_info(self) -> UserInfo:
|
||||||
return serializers.UserInfo \
|
return serializers.UserInfo \
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ class RestMerchantEndpoints(Middleware):
|
|||||||
def get_merchant_settings(self, key: MerchantSettingsKey) -> Any:
|
def get_merchant_settings(self, key: MerchantSettingsKey) -> Any:
|
||||||
return self._post("auth/r/ext/pay/settings/get", body={ "key": key })
|
return self._post("auth/r/ext/pay/settings/get", body={ "key": key })
|
||||||
|
|
||||||
|
#pylint: disable-next=dangerous-default-value
|
||||||
def list_merchant_settings(self, keys: List[MerchantSettingsKey] = []) -> Dict[MerchantSettingsKey, Any]:
|
def list_merchant_settings(self, keys: List[MerchantSettingsKey] = []) -> Dict[MerchantSettingsKey, Any]:
|
||||||
return self._post("auth/r/ext/pay/settings/list", body={ "keys": keys })
|
return self._post("auth/r/ext/pay/settings/list", body={ "keys": keys })
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from ...types import \
|
|||||||
|
|
||||||
from ...types import serializers
|
from ...types import serializers
|
||||||
|
|
||||||
|
#pylint: disable-next=too-many-public-methods
|
||||||
class RestPublicEndpoints(Middleware):
|
class RestPublicEndpoints(Middleware):
|
||||||
def conf(self, config: Config) -> Any:
|
def conf(self, config: Config) -> Any:
|
||||||
return self._get(f"conf/{config}")[0]
|
return self._get(f"conf/{config}")[0]
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ class _Type:
|
|||||||
|
|
||||||
class _Serializer(Generic[T]):
|
class _Serializer(Generic[T]):
|
||||||
def __init__(self, name: str, klass: Type[_Type], labels: List[str],
|
def __init__(self, name: str, klass: Type[_Type], labels: List[str],
|
||||||
*, flat: bool = False, ignore: List[str] = [ "_PLACEHOLDER" ]):
|
*, flat: bool = False):
|
||||||
self.name, self.klass, self.__labels, self.__flat, self.__ignore = name, klass, labels, flat, ignore
|
self.name, self.klass, self.__labels, self.__flat = name, klass, labels, flat
|
||||||
|
|
||||||
def _serialize(self, *args: Any) -> Iterable[Tuple[str, Any]]:
|
def _serialize(self, *args: Any) -> Iterable[Tuple[str, Any]]:
|
||||||
if self.__flat:
|
if self.__flat:
|
||||||
@@ -46,14 +46,14 @@ class _Serializer(Generic[T]):
|
|||||||
"arguments should contain the same amount of elements.")
|
"arguments should contain the same amount of elements.")
|
||||||
|
|
||||||
for index, label in enumerate(self.__labels):
|
for index, label in enumerate(self.__labels):
|
||||||
if label not in self.__ignore:
|
if label != "_PLACEHOLDER":
|
||||||
yield label, args[index]
|
yield label, args[index]
|
||||||
|
|
||||||
def parse(self, *values: Any) -> T:
|
def parse(self, *values: Any) -> T:
|
||||||
return cast(T, self.klass(**dict(self._serialize(*values))))
|
return cast(T, self.klass(**dict(self._serialize(*values))))
|
||||||
|
|
||||||
def get_labels(self) -> List[str]:
|
def get_labels(self) -> List[str]:
|
||||||
return [ label for label in self.__labels if label not in self.__ignore ]
|
return [ label for label in self.__labels if label != "_PLACEHOLDER" ]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __flatten(cls, array: List[Any]) -> List[Any]:
|
def __flatten(cls, array: List[Any]) -> List[Any]:
|
||||||
@@ -68,8 +68,8 @@ class _Serializer(Generic[T]):
|
|||||||
class _RecursiveSerializer(_Serializer, Generic[T]):
|
class _RecursiveSerializer(_Serializer, Generic[T]):
|
||||||
def __init__(self, name: str, klass: Type[_Type], labels: List[str],
|
def __init__(self, name: str, klass: Type[_Type], labels: List[str],
|
||||||
*, serializers: Dict[str, _Serializer[Any]],
|
*, serializers: Dict[str, _Serializer[Any]],
|
||||||
flat: bool = False, ignore: List[str] = [ "_PLACEHOLDER" ]):
|
flat: bool = False):
|
||||||
super().__init__(name, klass, labels, flat=flat, ignore=ignore)
|
super().__init__(name, klass, labels, flat=flat)
|
||||||
|
|
||||||
self.serializers = serializers
|
self.serializers = serializers
|
||||||
|
|
||||||
@@ -83,14 +83,14 @@ class _RecursiveSerializer(_Serializer, Generic[T]):
|
|||||||
return cast(T, self.klass(**serialization))
|
return cast(T, self.klass(**serialization))
|
||||||
|
|
||||||
def generate_labeler_serializer(name: str, klass: Type[T], labels: List[str],
|
def generate_labeler_serializer(name: str, klass: Type[T], labels: List[str],
|
||||||
*, flat: bool = False, ignore: List[str] = [ "_PLACEHOLDER" ]
|
*, flat: bool = False
|
||||||
) -> _Serializer[T]:
|
) -> _Serializer[T]:
|
||||||
return _Serializer[T](name, klass, labels, \
|
return _Serializer[T](name, klass, labels, \
|
||||||
flat=flat, ignore=ignore)
|
flat=flat)
|
||||||
|
|
||||||
def generate_recursive_serializer(name: str, klass: Type[T], labels: List[str],
|
def generate_recursive_serializer(name: str, klass: Type[T], labels: List[str],
|
||||||
*, serializers: Dict[str, _Serializer[Any]],
|
*, serializers: Dict[str, _Serializer[Any]],
|
||||||
flat: bool = False, ignore: List[str] = [ "_PLACEHOLDER" ]
|
flat: bool = False
|
||||||
) -> _RecursiveSerializer[T]:
|
) -> _RecursiveSerializer[T]:
|
||||||
return _RecursiveSerializer[T](name, klass, labels, \
|
return _RecursiveSerializer[T](name, klass, labels, \
|
||||||
serializers=serializers, flat=flat, ignore=ignore)
|
serializers=serializers, flat=flat)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class _Notification(_Serializer, Generic[T]):
|
|||||||
__LABELS = [ "mts", "type", "message_id", "_PLACEHOLDER", "data", "code", "status", "text" ]
|
__LABELS = [ "mts", "type", "message_id", "_PLACEHOLDER", "data", "code", "status", "text" ]
|
||||||
|
|
||||||
def __init__(self, serializer: Optional[_Serializer] = None, is_iterable: bool = False):
|
def __init__(self, serializer: Optional[_Serializer] = None, is_iterable: bool = False):
|
||||||
super().__init__("Notification", Notification, _Notification.__LABELS, ignore = [ "_PLACEHOLDER" ])
|
super().__init__("Notification", Notification, _Notification.__LABELS)
|
||||||
|
|
||||||
self.serializer, self.is_iterable = serializer, is_iterable
|
self.serializer, self.is_iterable = serializer, is_iterable
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ from typing import \
|
|||||||
Optional, Any
|
Optional, Any
|
||||||
|
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from socket import gaierror
|
from socket import gaierror
|
||||||
|
|
||||||
from asyncio import Task
|
from asyncio import Task
|
||||||
|
|
||||||
import \
|
import \
|
||||||
@@ -68,6 +68,7 @@ class _Delay:
|
|||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
self.__backoff_delay = _Delay.__BACKOFF_MIN
|
self.__backoff_delay = _Delay.__BACKOFF_MIN
|
||||||
|
|
||||||
|
#pylint: disable-next=too-many-instance-attributes
|
||||||
class BfxWebSocketClient(Connection):
|
class BfxWebSocketClient(Connection):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
host: str,
|
host: str,
|
||||||
@@ -101,6 +102,7 @@ class BfxWebSocketClient(Connection):
|
|||||||
stack_trace = traceback.format_exception( \
|
stack_trace = traceback.format_exception( \
|
||||||
type(exception), exception, exception.__traceback__)
|
type(exception), exception, exception.__traceback__)
|
||||||
|
|
||||||
|
#pylint: disable-next=logging-not-lazy
|
||||||
self.__logger.critical(header + "\n" + \
|
self.__logger.critical(header + "\n" + \
|
||||||
str().join(stack_trace)[:-1])
|
str().join(stack_trace)[:-1])
|
||||||
|
|
||||||
@@ -158,12 +160,11 @@ class BfxWebSocketClient(Connection):
|
|||||||
|
|
||||||
if isinstance(error, ConnectionClosedError) and error.code in (1006, 1012):
|
if isinstance(error, ConnectionClosedError) and error.code in (1006, 1012):
|
||||||
if error.code == 1006:
|
if error.code == 1006:
|
||||||
self.__logger.error("Connection lost: no close frame " \
|
self.__logger.error("Connection lost: trying to reconnect...")
|
||||||
"received or sent (1006). Trying to reconnect...")
|
|
||||||
|
|
||||||
if error.code == 1012:
|
if error.code == 1012:
|
||||||
self.__logger.info("WSS server is about to restart, clients need " \
|
self.__logger.warning("WSS server is restarting: all " \
|
||||||
"to reconnect (server sent 20051). Reconnection attempt in progress...")
|
"clients need to reconnect (server sent 20051).")
|
||||||
|
|
||||||
if self.__timeout:
|
if self.__timeout:
|
||||||
asyncio.get_event_loop().call_later(
|
asyncio.get_event_loop().call_later(
|
||||||
@@ -177,10 +178,14 @@ class BfxWebSocketClient(Connection):
|
|||||||
_delay.reset()
|
_delay.reset()
|
||||||
elif ((isinstance(error, InvalidStatusCode) and error.status_code == 408) or \
|
elif ((isinstance(error, InvalidStatusCode) and error.status_code == 408) or \
|
||||||
isinstance(error, gaierror)) and self.__reconnection:
|
isinstance(error, gaierror)) and self.__reconnection:
|
||||||
self.__logger.warning(
|
#pylint: disable-next=logging-fstring-interpolation
|
||||||
f"_Reconnection attempt was unsuccessful (no.{self.__reconnection['attempts']}). " \
|
self.__logger.warning("Reconnection attempt unsuccessful (no." \
|
||||||
f"Next reconnection attempt in {int(_delay.peek())}.0 seconds. (at the moment " \
|
f"{self.__reconnection['attempts']}): next attempt in " \
|
||||||
f"the client has been offline for {datetime.now() - self.__reconnection['timestamp']})")
|
f"~{int(_delay.peek())}.0s.")
|
||||||
|
|
||||||
|
#pylint: disable-next=logging-fstring-interpolation
|
||||||
|
self.__logger.info(f"The client has been offline for " \
|
||||||
|
f"{datetime.now() - self.__reconnection['timestamp']}.")
|
||||||
|
|
||||||
self.__reconnection["attempts"] += 1
|
self.__reconnection["attempts"] += 1
|
||||||
else:
|
else:
|
||||||
@@ -196,9 +201,10 @@ class BfxWebSocketClient(Connection):
|
|||||||
async def __connect(self) -> None:
|
async def __connect(self) -> None:
|
||||||
async with websockets.client.connect(self._host) as websocket:
|
async with websockets.client.connect(self._host) as websocket:
|
||||||
if self.__reconnection:
|
if self.__reconnection:
|
||||||
self.__logger.info(f"_Reconnection attempt successful (no.{self.__reconnection['attempts']}): The " \
|
#pylint: disable-next=logging-fstring-interpolation
|
||||||
f"client has been offline for a total of {datetime.now() - self.__reconnection['timestamp']} " \
|
self.__logger.warning("Reconnection attempt successful (no." \
|
||||||
f"(connection lost on: {self.__reconnection['timestamp']:%d-%m-%Y at %H:%M:%S}).")
|
f"{self.__reconnection['attempts']}): recovering " \
|
||||||
|
"connection state...")
|
||||||
|
|
||||||
self.__reconnection = None
|
self.__reconnection = None
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class AuthEventsHandler:
|
|||||||
|
|
||||||
def handle(self, abbrevation: str, stream: Any) -> None:
|
def handle(self, abbrevation: str, stream: Any) -> None:
|
||||||
if abbrevation == "n":
|
if abbrevation == "n":
|
||||||
return self.__notification(stream)
|
self.__notification(stream)
|
||||||
|
|
||||||
for abbrevations, serializer in AuthEventsHandler.__SERIALIZERS.items():
|
for abbrevations, serializer in AuthEventsHandler.__SERIALIZERS.items():
|
||||||
if abbrevation in abbrevations:
|
if abbrevation in abbrevations:
|
||||||
@@ -45,12 +45,11 @@ class AuthEventsHandler:
|
|||||||
|
|
||||||
if all(isinstance(sub_stream, list) for sub_stream in stream):
|
if all(isinstance(sub_stream, list) for sub_stream in stream):
|
||||||
data = [ serializer.parse(*sub_stream) for sub_stream in stream ]
|
data = [ serializer.parse(*sub_stream) for sub_stream in stream ]
|
||||||
else: data = serializer.parse(*stream)
|
else:
|
||||||
|
data = serializer.parse(*stream)
|
||||||
|
|
||||||
self.__event_emitter.emit(event, data)
|
self.__event_emitter.emit(event, data)
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
def __notification(self, stream: Any) -> None:
|
def __notification(self, stream: Any) -> None:
|
||||||
event: str = "notification"
|
event: str = "notification"
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class PublicChannelsHandler:
|
|||||||
elif subscription["channel"] == "status":
|
elif subscription["channel"] == "status":
|
||||||
self.__status_channel_handler(cast(Status, subscription), stream)
|
self.__status_channel_handler(cast(Status, subscription), stream)
|
||||||
|
|
||||||
|
#pylint: disable-next=inconsistent-return-statements
|
||||||
def __ticker_channel_handler(self, subscription: Ticker, stream: List[Any]):
|
def __ticker_channel_handler(self, subscription: Ticker, stream: List[Any]):
|
||||||
if subscription["symbol"].startswith("t"):
|
if subscription["symbol"].startswith("t"):
|
||||||
return self.__event_emitter.emit("t_ticker_update", subscription, \
|
return self.__event_emitter.emit("t_ticker_update", subscription, \
|
||||||
@@ -44,6 +45,7 @@ class PublicChannelsHandler:
|
|||||||
return self.__event_emitter.emit("f_ticker_update", subscription, \
|
return self.__event_emitter.emit("f_ticker_update", subscription, \
|
||||||
serializers.FundingCurrencyTicker.parse(*stream[0]))
|
serializers.FundingCurrencyTicker.parse(*stream[0]))
|
||||||
|
|
||||||
|
#pylint: disable-next=inconsistent-return-statements
|
||||||
def __trades_channel_handler(self, subscription: Trades, stream: List[Any]):
|
def __trades_channel_handler(self, subscription: Trades, stream: List[Any]):
|
||||||
if (event := stream[0]) and event in [ "te", "tu", "fte", "ftu" ]:
|
if (event := stream[0]) and event in [ "te", "tu", "fte", "ftu" ]:
|
||||||
events = { "te": "t_trade_execution", "tu": "t_trade_execution_update", \
|
events = { "te": "t_trade_execution", "tu": "t_trade_execution_update", \
|
||||||
@@ -67,6 +69,7 @@ class PublicChannelsHandler:
|
|||||||
[ serializers.FundingCurrencyTrade.parse(*sub_stream) \
|
[ serializers.FundingCurrencyTrade.parse(*sub_stream) \
|
||||||
for sub_stream in stream[0] ])
|
for sub_stream in stream[0] ])
|
||||||
|
|
||||||
|
#pylint: disable-next=inconsistent-return-statements
|
||||||
def __book_channel_handler(self, subscription: Book, stream: List[Any]):
|
def __book_channel_handler(self, subscription: Book, stream: List[Any]):
|
||||||
if subscription["symbol"].startswith("t"):
|
if subscription["symbol"].startswith("t"):
|
||||||
if all(isinstance(sub_stream, list) for sub_stream in stream[0]):
|
if all(isinstance(sub_stream, list) for sub_stream in stream[0]):
|
||||||
@@ -86,6 +89,7 @@ class PublicChannelsHandler:
|
|||||||
return self.__event_emitter.emit("f_book_update", subscription, \
|
return self.__event_emitter.emit("f_book_update", subscription, \
|
||||||
serializers.FundingCurrencyBook.parse(*stream[0]))
|
serializers.FundingCurrencyBook.parse(*stream[0]))
|
||||||
|
|
||||||
|
#pylint: disable-next=inconsistent-return-statements
|
||||||
def __raw_book_channel_handler(self, subscription: Book, stream: List[Any]):
|
def __raw_book_channel_handler(self, subscription: Book, stream: List[Any]):
|
||||||
if subscription["symbol"].startswith("t"):
|
if subscription["symbol"].startswith("t"):
|
||||||
if all(isinstance(sub_stream, list) for sub_stream in stream[0]):
|
if all(isinstance(sub_stream, list) for sub_stream in stream[0]):
|
||||||
@@ -105,6 +109,7 @@ class PublicChannelsHandler:
|
|||||||
return self.__event_emitter.emit("f_raw_book_update", subscription, \
|
return self.__event_emitter.emit("f_raw_book_update", subscription, \
|
||||||
serializers.FundingCurrencyRawBook.parse(*stream[0]))
|
serializers.FundingCurrencyRawBook.parse(*stream[0]))
|
||||||
|
|
||||||
|
#pylint: disable-next=inconsistent-return-statements
|
||||||
def __candles_channel_handler(self, subscription: Candles, stream: List[Any]):
|
def __candles_channel_handler(self, subscription: Candles, stream: List[Any]):
|
||||||
if all(isinstance(sub_stream, list) for sub_stream in stream[0]):
|
if all(isinstance(sub_stream, list) for sub_stream in stream[0]):
|
||||||
return self.__event_emitter.emit("candles_snapshot", subscription, \
|
return self.__event_emitter.emit("candles_snapshot", subscription, \
|
||||||
@@ -114,6 +119,7 @@ class PublicChannelsHandler:
|
|||||||
return self.__event_emitter.emit("candles_update", subscription, \
|
return self.__event_emitter.emit("candles_update", subscription, \
|
||||||
serializers.Candle.parse(*stream[0]))
|
serializers.Candle.parse(*stream[0]))
|
||||||
|
|
||||||
|
#pylint: disable-next=inconsistent-return-statements
|
||||||
def __status_channel_handler(self, subscription: Status, stream: List[Any]):
|
def __status_channel_handler(self, subscription: Status, stream: List[Any]):
|
||||||
if subscription["key"].startswith("deriv:"):
|
if subscription["key"].startswith("deriv:"):
|
||||||
return self.__event_emitter.emit("derivatives_status_update", subscription, \
|
return self.__event_emitter.emit("derivatives_status_update", subscription, \
|
||||||
@@ -123,6 +129,7 @@ class PublicChannelsHandler:
|
|||||||
return self.__event_emitter.emit("liquidation_feed_update", subscription, \
|
return self.__event_emitter.emit("liquidation_feed_update", subscription, \
|
||||||
serializers.Liquidation.parse(*stream[0][0]))
|
serializers.Liquidation.parse(*stream[0][0]))
|
||||||
|
|
||||||
|
#pylint: disable-next=inconsistent-return-statements
|
||||||
def __checksum_handler(self, subscription: Book, value: int):
|
def __checksum_handler(self, subscription: Book, value: int):
|
||||||
return self.__event_emitter.emit( \
|
return self.__event_emitter.emit( \
|
||||||
"checksum", subscription, value & 0xFFFFFFFF)
|
"checksum", subscription, value & 0xFFFFFFFF)
|
||||||
|
|||||||
Reference in New Issue
Block a user