Improve fidelity to pylint's standard rules.

This commit is contained in:
Davide Casale
2023-10-26 05:09:10 +02:00
parent ac50f8f884
commit 8e915e42eb
10 changed files with 49 additions and 43 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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 \

View File

@@ -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 })

View File

@@ -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]

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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)