diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index f68d34f..e7c562a 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -30,8 +30,8 @@ jobs: python -m pip install . - name: Lint with flake8 and black run: | - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics + flake8 . --count --statistics --show-source --ignore=E501,W503,W605,E722 + flake8 . --count --statistics --exit-zero --max-complexity=10 --ignore=E501,W503 black . --check - name: Test with pytest run: | diff --git a/docs/conf.py b/docs/conf.py index 05b3cd3..3283c91 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -214,13 +214,13 @@ htmlhelp_basename = "aMQTTdoc" latex_elements = { # The paper size ('letterpaper' or 'a4paper'). - #'papersize': 'letterpaper', + # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', + # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. - #'preamble': '', + # 'preamble': '', # Latex figure (float) alignment - #'figure_align': 'htbp', + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples diff --git a/hbmqtt/adapters.py b/hbmqtt/adapters.py index 810013a..bfc10dc 100644 --- a/hbmqtt/adapters.py +++ b/hbmqtt/adapters.py @@ -1,7 +1,7 @@ # Copyright (c) 2015 Nicolas JOUANIN # # See the file license.txt for copying permission. -import asyncio + import io from websockets.protocol import WebSocketCommonProtocol from websockets.exceptions import ConnectionClosed @@ -13,19 +13,20 @@ class ReaderAdapter: """ Base class for all network protocol reader adapter. - Reader adapters are used to adapt read operations on the network depending on the protocol used + Reader adapters are used to adapt read operations on the network depending on the + protocol used """ async def read(self, n=-1) -> bytes: """ - Read up to n bytes. If n is not provided, or set to -1, read until EOF and return all read bytes. - If the EOF was received and the internal buffer is empty, return an empty bytes object. - :return: packet read as bytes data + Read up to n bytes. If n is not provided, or set to -1, read until EOF and + return all read bytes. If the EOF was received and the internal buffer is + empty, return an empty bytes object. :return: packet read as bytes data """ def feed_eof(self): """ - Acknowleddge EOF + Acknowledge EOF """ @@ -33,7 +34,8 @@ class WriterAdapter: """ Base class for all network protocol writer adapter. - Writer adapters are used to adapt write operations on the network depending on the protocol used + Writer adapters are used to adapt write operations on the network depending on + the protocol used """ def write(self, data): diff --git a/hbmqtt/broker.py b/hbmqtt/broker.py index 71c403f..de51571 100644 --- a/hbmqtt/broker.py +++ b/hbmqtt/broker.py @@ -1,7 +1,7 @@ # Copyright (c) 2015 Nicolas JOUANIN # # See the file license.txt for copying permission. -from typing import Optional, Dict, Union +from typing import Optional import logging import ssl import websockets @@ -147,7 +147,7 @@ class Broker: MQTT 3.1.1 compliant broker implementation :param config: Example Yaml config - :param loop: asyncio loop to use. Defaults to ``asyncio.get_event_loop()`` if none is given + :param loop: asyncio loop to use. Defaults to ``asyncio.get_event_loop()``. :param plugin_namespace: Plugin namespace to use when loading plugin entry_points. Defaults to ``hbmqtt.broker.plugins`` """ diff --git a/hbmqtt/client.py b/hbmqtt/client.py index 0a83933..4f24b79 100644 --- a/hbmqtt/client.py +++ b/hbmqtt/client.py @@ -200,7 +200,7 @@ class MQTTClient: while self.client_tasks: task = self.client_tasks.pop() task.cancel() - except IndexError as err: + except IndexError: pass async def reconnect(self, cleansession=None): diff --git a/hbmqtt/mqtt/connack.py b/hbmqtt/mqtt/connack.py index 99f9af5..ad9a4ed 100644 --- a/hbmqtt/mqtt/connack.py +++ b/hbmqtt/mqtt/connack.py @@ -1,7 +1,6 @@ # Copyright (c) 2015 Nicolas JOUANIN # # See the file license.txt for copying permission. -import asyncio from hbmqtt.mqtt.packet import CONNACK, MQTTPacket, MQTTFixedHeader, MQTTVariableHeader from hbmqtt.codecs import read_or_raise, bytes_to_int from hbmqtt.errors import HBMQTTException diff --git a/hbmqtt/mqtt/connect.py b/hbmqtt/mqtt/connect.py index 94544c2..cbd1d9b 100644 --- a/hbmqtt/mqtt/connect.py +++ b/hbmqtt/mqtt/connect.py @@ -1,7 +1,6 @@ # Copyright (c) 2015 Nicolas JOUANIN # # See the file license.txt for copying permission. -import asyncio from hbmqtt.codecs import ( bytes_to_int, diff --git a/hbmqtt/mqtt/protocol/broker_handler.py b/hbmqtt/mqtt/protocol/broker_handler.py index 44556ff..bda3eb1 100644 --- a/hbmqtt/mqtt/protocol/broker_handler.py +++ b/hbmqtt/mqtt/protocol/broker_handler.py @@ -1,7 +1,6 @@ # Copyright (c) 2015 Nicolas JOUANIN # # See the file license.txt for copying permission. -import asyncio from asyncio import futures, Queue from hbmqtt.mqtt.protocol.handler import ProtocolHandler from hbmqtt.mqtt.connack import ( diff --git a/hbmqtt/mqtt/protocol/client_handler.py b/hbmqtt/mqtt/protocol/client_handler.py index ad10ab8..e4eaa91 100644 --- a/hbmqtt/mqtt/protocol/client_handler.py +++ b/hbmqtt/mqtt/protocol/client_handler.py @@ -3,7 +3,6 @@ # See the file license.txt for copying permission. import asyncio from asyncio import futures -import sys from hbmqtt.mqtt.protocol.handler import ProtocolHandler, EVENT_MQTT_PACKET_RECEIVED from hbmqtt.mqtt.disconnect import DisconnectPacket from hbmqtt.mqtt.pingreq import PingReqPacket @@ -120,7 +119,7 @@ class ClientProtocolHandler(ProtocolHandler): try: waiter = self._subscriptions_waiter.get(packet_id) waiter.set_result(suback.payload.return_codes) - except KeyError as ke: + except KeyError: self.logger.warning( "Received SUBACK for unknown pending subscription with Id: %s" % packet_id @@ -144,7 +143,7 @@ class ClientProtocolHandler(ProtocolHandler): try: waiter = self._unsubscriptions_waiter.get(packet_id) waiter.set_result(None) - except KeyError as ke: + except KeyError: self.logger.warning( "Received UNSUBACK for unknown pending subscription with Id: %s" % packet_id diff --git a/hbmqtt/mqtt/suback.py b/hbmqtt/mqtt/suback.py index 9b557cd..29ab4ca 100644 --- a/hbmqtt/mqtt/suback.py +++ b/hbmqtt/mqtt/suback.py @@ -1,8 +1,6 @@ # Copyright (c) 2015 Nicolas JOUANIN # # See the file license.txt for copying permission. -import asyncio - from hbmqtt.mqtt.packet import ( MQTTPacket, MQTTFixedHeader, @@ -25,9 +23,9 @@ class SubackPayload(MQTTPayload): RETURN_CODE_02 = 0x02 RETURN_CODE_80 = 0x80 - def __init__(self, return_codes=[]): + def __init__(self, return_codes=None): super().__init__() - self.return_codes = return_codes + self.return_codes = return_codes or [] def __repr__(self): return type(self).__name__ + "(return_codes={0})".format( diff --git a/hbmqtt/mqtt/subscribe.py b/hbmqtt/mqtt/subscribe.py index 8ac0398..864447c 100644 --- a/hbmqtt/mqtt/subscribe.py +++ b/hbmqtt/mqtt/subscribe.py @@ -25,9 +25,9 @@ class SubscribePayload(MQTTPayload): __slots__ = ("topics",) - def __init__(self, topics=[]): + def __init__(self, topics=None): super().__init__() - self.topics = topics + self.topics = topics or [] def to_bytes( self, fixed_header: MQTTFixedHeader, variable_header: MQTTVariableHeader @@ -55,7 +55,7 @@ class SubscribePayload(MQTTPayload): qos = bytes_to_int(qos_byte) topics.append((topic, qos)) read_bytes += 2 + len(topic.encode("utf-8")) + 1 - except NoDataException as exc: + except NoDataException: break return cls(topics) diff --git a/hbmqtt/mqtt/unsubscribe.py b/hbmqtt/mqtt/unsubscribe.py index cf4187d..a289e24 100644 --- a/hbmqtt/mqtt/unsubscribe.py +++ b/hbmqtt/mqtt/unsubscribe.py @@ -19,9 +19,9 @@ class UnubscribePayload(MQTTPayload): __slots__ = ("topics",) - def __init__(self, topics=[]): + def __init__(self, topics=None): super().__init__() - self.topics = topics + self.topics = topics or [] def to_bytes( self, fixed_header: MQTTFixedHeader, variable_header: MQTTVariableHeader diff --git a/hbmqtt/plugins/authentication.py b/hbmqtt/plugins/authentication.py index 6f99974..a4f92dd 100644 --- a/hbmqtt/plugins/authentication.py +++ b/hbmqtt/plugins/authentication.py @@ -2,7 +2,6 @@ # # See the file license.txt for copying permission. import logging -import asyncio from passlib.apps import custom_app_context as pwd_context @@ -55,7 +54,7 @@ class AnonymousAuthPlugin(BaseAuthPlugin): "Authentication failure: session has an empty username" ) except KeyError: - self.context.logger.warning("Session informations not available") + self.context.logger.warning("Session information not available") authenticated = False return authenticated @@ -74,8 +73,8 @@ class FileAuthPlugin(BaseAuthPlugin): self.context.logger.debug( "Reading user database from %s" % password_file ) - for l in f: - line = l.strip() + for line in f: + line = line.strip() if not line.startswith("#"): # Allow comments in files (username, pwd_hash) = line.split(sep=":", maxsplit=3) if username: diff --git a/hbmqtt/plugins/logging.py b/hbmqtt/plugins/logging.py index 8612bda..4b76d1b 100644 --- a/hbmqtt/plugins/logging.py +++ b/hbmqtt/plugins/logging.py @@ -4,7 +4,6 @@ import logging -import asyncio from functools import partial diff --git a/hbmqtt/plugins/manager.py b/hbmqtt/plugins/manager.py index 3a7e8a4..4d7d043 100644 --- a/hbmqtt/plugins/manager.py +++ b/hbmqtt/plugins/manager.py @@ -8,7 +8,6 @@ import pkg_resources import logging import asyncio import copy -import sys from collections import namedtuple @@ -31,9 +30,9 @@ class BaseContext: class PluginManager: """ - Wraps setuptools Entry point mechanism to provide a basic plugin system. - Plugins are loaded for a given namespace (group). - This plugin manager uses coroutines to run plugin call asynchronously in an event queue + Wraps setuptools Entry point mechanism to provide a basic plugin system. Plugins + are loaded for a given namespace (group). This plugin manager uses coroutines to + run plugin call asynchronously in an event queue """ def __init__(self, namespace, context, loop=None): @@ -95,7 +94,8 @@ class PluginManager: async def close(self): """ Free PluginManager resources and cancel pending event methods - This method call a close() coroutine for each plugin, allowing plugins to close and free resources + This method call a close() coroutine for each plugin, allowing plugins to close + and free resources :return: """ await self.map_plugin_coro("close") @@ -118,8 +118,8 @@ class PluginManager: Fire an event to plugins. PluginManager schedule async calls for each plugin on method called "on_" + event_name For example, on_connect will be called on event 'connect' - Method calls are schedule in the asyn loop. wait parameter must be set to true to wait until all - mehtods are completed. + Method calls are schedule in the async loop. wait parameter must be set to true + to wait until all methods are completed. :param event_name: :param args: :param kwargs: @@ -159,7 +159,8 @@ class PluginManager: Schedule a given coroutine call for each plugin. The coro called get the Plugin instance as first argument of its method call :param coro: coro to call on each plugin - :param filter_plugins: list of plugin names to filter (only plugin whose name is in filter are called). + :param filter_plugins: list of plugin names to filter (only plugin whose name is + in filter are called). None will call all plugins. [] will call None. :param args: arguments to pass to coro :param kwargs: arguments to pass to coro diff --git a/hbmqtt/plugins/persistence.py b/hbmqtt/plugins/persistence.py index b022054..e61e70a 100644 --- a/hbmqtt/plugins/persistence.py +++ b/hbmqtt/plugins/persistence.py @@ -1,7 +1,6 @@ # Copyright (c) 2015 Nicolas JOUANIN # # See the file license.txt for copying permission. -import asyncio import sqlite3 import pickle diff --git a/hbmqtt/plugins/sys/broker.py b/hbmqtt/plugins/sys/broker.py index 3cb1dd2..77e1dda 100644 --- a/hbmqtt/plugins/sys/broker.py +++ b/hbmqtt/plugins/sys/broker.py @@ -2,12 +2,12 @@ # # See the file license.txt for copying permission. from datetime import datetime +from collections import deque +import asyncio + import hbmqtt from hbmqtt.mqtt.packet import PUBLISH from hbmqtt.codecs import int_to_bytes_str -import asyncio -import sys -from collections import deque DOLLAR_SYS_ROOT = "$SYS/broker/" @@ -69,7 +69,7 @@ class BrokerSysPlugin: sys_interval = int(self.context.config.get("sys_interval", 0)) if sys_interval > 0: self.context.logger.debug( - "Setup $SYS broadcasting every %d secondes" % sys_interval + "Setup $SYS broadcasting every %d seconds" % sys_interval ) self.sys_handle = self.context.loop.call_later( sys_interval, self.broadcast_dollar_sys_topics diff --git a/hbmqtt/plugins/topic_checking.py b/hbmqtt/plugins/topic_checking.py index 451d146..b52a156 100644 --- a/hbmqtt/plugins/topic_checking.py +++ b/hbmqtt/plugins/topic_checking.py @@ -1,6 +1,3 @@ -import asyncio - - class BaseTopicPlugin: def __init__(self, context): self.context = context diff --git a/hbmqtt/scripts/pub_script.py b/hbmqtt/scripts/pub_script.py index 524994b..1a58d3a 100644 --- a/hbmqtt/scripts/pub_script.py +++ b/hbmqtt/scripts/pub_script.py @@ -129,13 +129,13 @@ async def do_pub(client, arguments): logger.info("%s Disconnected from broker" % client.client_id) except ConnectException as ce: logger.fatal("connection to '%s' failed: %r" % (arguments["--url"], ce)) - except asyncio.CancelledError as cae: - logger.fatal("Publish canceled due to prvious error") + except asyncio.CancelledError: + logger.fatal("Publish canceled due to previous error") def main(*args, **kwargs): - if sys.version_info[:2] < (3, 4): - logger.fatal("Error: Python 3.4+ is required") + if sys.version_info[:2] < (3, 6): + logger.fatal("Error: Python 3.6+ is required") sys.exit(-1) arguments = docopt(__doc__, version=hbmqtt.__version__) @@ -148,7 +148,6 @@ def main(*args, **kwargs): level = logging.INFO logging.basicConfig(level=level, format=formatter) - config = None if arguments["-c"]: config = read_yaml_config(arguments["-c"]) else: diff --git a/hbmqtt/scripts/sub_script.py b/hbmqtt/scripts/sub_script.py index baa79b7..7d3057d 100644 --- a/hbmqtt/scripts/sub_script.py +++ b/hbmqtt/scripts/sub_script.py @@ -106,17 +106,16 @@ async def do_sub(client, arguments): await client.disconnect() except ConnectException as ce: logger.fatal("connection to '%s' failed: %r" % (arguments["--url"], ce)) - except asyncio.CancelledError as cae: - logger.fatal("Publish canceled due to prvious error") + except asyncio.CancelledError: + logger.fatal("Publish canceled due to previous error") def main(*args, **kwargs): - if sys.version_info[:2] < (3, 4): - logger.fatal("Error: Python 3.4+ is required") + if sys.version_info[:2] < (3, 6): + logger.fatal("Error: Python 3.6+ is required") sys.exit(-1) arguments = docopt(__doc__, version=hbmqtt.__version__) - # print(arguments) formatter = "[%(asctime)s] :: %(levelname)s - %(message)s" if arguments["-d"]: diff --git a/tests/test_broker.py b/tests/test_broker.py index 50a09e0..153f0ef 100644 --- a/tests/test_broker.py +++ b/tests/test_broker.py @@ -1,11 +1,9 @@ # Copyright (c) 2015 Nicolas JOUANIN # # See the file license.txt for copying permission. -import sys import asyncio import logging -import unittest -from unittest.mock import patch, call, MagicMock +from unittest.mock import call, MagicMock import pytest @@ -20,7 +18,6 @@ from hbmqtt.broker import ( EVENT_BROKER_CLIENT_SUBSCRIBED, EVENT_BROKER_CLIENT_UNSUBSCRIBED, EVENT_BROKER_MESSAGE_RECEIVED, - Broker, ) from hbmqtt.client import MQTTClient, ConnectException from hbmqtt.mqtt import ( @@ -432,8 +429,11 @@ async def test_client_subscribe_publish_dollar_topic_1(broker): message = None try: message = await sub_client.deliver_message(timeout=2) - except Exception as e: + except asyncio.TimeoutError: pass + except RuntimeError as e: + # The loop is closed with pending tasks. Needs fine tuning. + log.warning(e) assert message is None await sub_client.disconnect() await asyncio.sleep(0.1) @@ -455,8 +455,11 @@ async def test_client_subscribe_publish_dollar_topic_2(broker): message = None try: message = await sub_client.deliver_message(timeout=2) - except Exception as e: + except asyncio.TimeoutError: pass + except RuntimeError as e: + # The loop is closed with pending tasks. Needs fine tuning. + log.warning(e) assert message is None await sub_client.disconnect() await asyncio.sleep(0.1)