From b8640666d727521322fe03fbf6c6d846cb81b688 Mon Sep 17 00:00:00 2001 From: Ian McEwen Date: Tue, 19 Mar 2024 12:35:42 -0700 Subject: [PATCH 1/4] Fix some outstanding pylint issues (or disable the checks) --- meshtastic/__main__.py | 2 +- meshtastic/globals.py | 2 +- meshtastic/mesh_interface.py | 7 +++---- meshtastic/node.py | 5 ++--- meshtastic/stream_interface.py | 2 +- meshtastic/tests/test_main.py | 4 ++-- meshtastic/tests/test_node.py | 2 +- meshtastic/tests/test_util.py | 2 +- meshtastic/util.py | 4 ++-- meshtastic/version.py | 4 +++- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index 13c5af4c..3e7d4a4f 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -1260,7 +1260,7 @@ def initParser(): help="Request telemetry from a node. " "You need pass the destination ID as argument with '--dest'. " "For repeaters, the nodeNum is required.", - action="store_true", + action="store_true", ) parser.add_argument( diff --git a/meshtastic/globals.py b/meshtastic/globals.py index 07ae2e3a..0673de6c 100644 --- a/meshtastic/globals.py +++ b/meshtastic/globals.py @@ -24,7 +24,7 @@ def getInstance(): def __init__(self): """Constructor for the Globals CLass""" if Globals.__instance is not None: - raise Exception("This class is a singleton") + raise Exception("This class is a singleton") # pylint: disable=W0719 else: Globals.__instance = self self.args = None diff --git a/meshtastic/mesh_interface.py b/meshtastic/mesh_interface.py index 5f5b56db..cf64205f 100644 --- a/meshtastic/mesh_interface.py +++ b/meshtastic/mesh_interface.py @@ -23,7 +23,6 @@ BROADCAST_ADDR, BROADCAST_NUM, LOCAL_ADDR, - OUR_APP_VERSION, ResponseHandler, protocols, publishingThread, @@ -440,7 +439,7 @@ def sendTelemetry(self, destinationId=BROADCAST_ADDR, wantResponse=False): destinationId = int(destinationId[1:], 16) else: destinationId = int(destinationId) - + self.sendData( r, destinationId=destinationId, @@ -469,7 +468,7 @@ def onResponseTelemetry(self, p): ) if telemetry.device_metrics.air_util_tx is not None: print(f"Transmit air utilization: {telemetry.device_metrics.air_util_tx:.2f}%") - + elif p["decoded"]["portnum"] == 'ROUTING_APP': if p["decoded"]["routing"]["errorReason"] == 'NO_RESPONSE': our_exit("No response from node. At least firmware 2.1.22 is required on the destination node.") @@ -556,7 +555,7 @@ def waitForTraceRoute(self, waitFactor): success = self._timeout.waitForTraceRoute(waitFactor, self._acknowledgment) if not success: raise Exception("Timed out waiting for traceroute") - + def waitForTelemetry(self): """Wait for telemetry""" success = self._timeout.waitForTelemetry(self._acknowledgment) diff --git a/meshtastic/node.py b/meshtastic/node.py index c5a57bdd..9df4b508 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -115,6 +115,7 @@ def onResponseRequestSettings(self, p): print(f"{str(camel_to_snake(field))}:\n{str(config_values)}") def requestConfig(self, configType): + """Request the config from the node via admin message""" if self == self.iface.localNode: onResponse = None else: @@ -688,9 +689,6 @@ def onResponseRequestChannel(self, p): logging.debug(f"Received channel {stripnl(c)}") index = c.index - # for stress testing, we can always download all channels - fastChannelDownload = True - if index >= 8 - 1: logging.debug("Finished downloading channels") @@ -703,6 +701,7 @@ def onResponseRequestChannel(self, p): self._requestChannel(index + 1) def onAckNak(self, p): + """Informative handler for ACK/NAK responses""" if p["decoded"]["routing"]["errorReason"] != "NONE": print( f'Received a NAK, error reason: {p["decoded"]["routing"]["errorReason"]}' diff --git a/meshtastic/stream_interface.py b/meshtastic/stream_interface.py index fd0daebd..b5dc894c 100644 --- a/meshtastic/stream_interface.py +++ b/meshtastic/stream_interface.py @@ -32,7 +32,7 @@ def __init__(self, debugOut=None, noProto=False, connectNow=True): """ if not hasattr(self, "stream") and not noProto: - raise Exception( + raise Exception( # pylint: disable=W0719 "StreamInterface is now abstract (to update existing code create SerialInterface instead)" ) self._rxBuf = bytes() # empty diff --git a/meshtastic/tests/test_main.py b/meshtastic/tests/test_main.py index 23d7e5e1..6a0312ad 100644 --- a/meshtastic/tests/test_main.py +++ b/meshtastic/tests/test_main.py @@ -23,7 +23,7 @@ tunnelMain, ) -from ..channel_pb2 import Channel +from ..channel_pb2 import Channel # pylint: disable=E0611 # from ..ble_interface import BLEInterface from ..node import Node @@ -388,7 +388,7 @@ def test_main_onConnected_exception(capsys): Globals.getInstance().set_args(sys.argv) def throw_an_exception(junk): - raise Exception("Fake exception.") + raise Exception("Fake exception.") # pylint: disable=W0719 iface = MagicMock(autospec=SerialInterface) with patch("meshtastic.serial_interface.SerialInterface", return_value=iface): diff --git a/meshtastic/tests/test_node.py b/meshtastic/tests/test_node.py index 8500ecd7..5e1314e6 100644 --- a/meshtastic/tests/test_node.py +++ b/meshtastic/tests/test_node.py @@ -7,7 +7,7 @@ import pytest # from ..admin_pb2 import AdminMessage -from ..channel_pb2 import Channel +from ..channel_pb2 import Channel # pylint: disable=E0611 from ..node import Node from ..serial_interface import SerialInterface diff --git a/meshtastic/tests/test_util.py b/meshtastic/tests/test_util.py index df760d15..b058b02c 100644 --- a/meshtastic/tests/test_util.py +++ b/meshtastic/tests/test_util.py @@ -177,7 +177,7 @@ def test_catchAndIgnore(caplog): """Test catchAndIgnore() does not actually throw an exception, but just logs""" def some_closure(): - raise Exception("foo") + raise Exception("foo") # pylint: disable=W0719 with caplog.at_level(logging.DEBUG): catchAndIgnore("something", some_closure) diff --git a/meshtastic/util.py b/meshtastic/util.py index 0c2fd448..d6b60409 100644 --- a/meshtastic/util.py +++ b/meshtastic/util.py @@ -109,7 +109,7 @@ def stripnl(s): def fixme(message): """Raise an exception for things that needs to be fixed""" - raise Exception(f"FIXME: {message}") + raise Exception(f"FIXME: {message}") # pylint: disable=W0719 def catchAndIgnore(reason, closure): @@ -193,7 +193,7 @@ def waitForTraceRoute(self, waitFactor, acknowledgment, attr="receivedTraceRoute return True time.sleep(self.sleepInterval) return False - + def waitForTelemetry(self, acknowledgment): """Block until telemetry response is received. Returns True if telemetry response has been received.""" self.reset() diff --git a/meshtastic/version.py b/meshtastic/version.py index bdc69eb4..1856fd56 100644 --- a/meshtastic/version.py +++ b/meshtastic/version.py @@ -1,3 +1,4 @@ +"""Version lookup utilities, isolated for cleanliness""" import sys try: from importlib.metadata import version @@ -5,7 +6,8 @@ import pkg_resources def get_active_version(): + """Get the currently active version using importlib, or pkg_resources if we must""" if "importlib.metadata" in sys.modules: return version("meshtastic") else: - return pkg_resources.get_distribution("meshtastic").version + return pkg_resources.get_distribution("meshtastic").version # pylint: disable=E0601 From 16a1af6a130e880fea87832af6de401ee068cf09 Mon Sep 17 00:00:00 2001 From: Ian McEwen Date: Tue, 19 Mar 2024 12:58:44 -0700 Subject: [PATCH 2/4] Create MeshInterface.MeshInterfaceError to specialize errors in that file --- meshtastic/mesh_interface.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/meshtastic/mesh_interface.py b/meshtastic/mesh_interface.py index cf64205f..e6f0a5be 100644 --- a/meshtastic/mesh_interface.py +++ b/meshtastic/mesh_interface.py @@ -47,6 +47,12 @@ class MeshInterface: debugOut """ + class MeshInterfaceError(Exception): + """An exception class for general mesh interface errors""" + def __init__(self, message): + self.message = message + super().__init__(self.message) + def __init__(self, debugOut=None, noProto=False): """Constructor @@ -313,7 +319,7 @@ def sendData( f"mesh_pb2.Constants.DATA_PAYLOAD_LEN: {mesh_pb2.Constants.DATA_PAYLOAD_LEN}" ) if len(data) > mesh_pb2.Constants.DATA_PAYLOAD_LEN: - raise Exception("Data payload too big") + raise MeshInterface.MeshInterfaceError("Data payload too big") if ( portNum == portnums_pb2.PortNum.UNKNOWN_APP @@ -542,25 +548,25 @@ def waitForConfig(self): and self.localNode.waitForConfig() ) if not success: - raise Exception("Timed out waiting for interface config") + raise MeshInterface.MeshInterfaceError("Timed out waiting for interface config") def waitForAckNak(self): """Wait for the ack/nak""" success = self._timeout.waitForAckNak(self._acknowledgment) if not success: - raise Exception("Timed out waiting for an acknowledgment") + raise MeshInterface.MeshInterfaceError("Timed out waiting for an acknowledgment") def waitForTraceRoute(self, waitFactor): """Wait for trace route""" success = self._timeout.waitForTraceRoute(waitFactor, self._acknowledgment) if not success: - raise Exception("Timed out waiting for traceroute") + raise MeshInterface.MeshInterfaceError("Timed out waiting for traceroute") def waitForTelemetry(self): """Wait for telemetry""" success = self._timeout.waitForTelemetry(self._acknowledgment) if not success: - raise Exception("Timed out waiting for telemetry") + raise MeshInterface.MeshInterfaceError("Timed out waiting for telemetry") def getMyNodeInfo(self): """Get info about my node.""" @@ -595,7 +601,7 @@ def _waitConnected(self, timeout=30.0): and raise an exception""" if not self.noProto: if not self.isConnected.wait(timeout): # timeout after x seconds - raise Exception("Timed out waiting for connection completion") + raise MeshInterface.MeshInterfaceError("Timed out waiting for connection completion") # If we failed while connecting, raise the connection to the client if self.failure: @@ -604,7 +610,7 @@ def _waitConnected(self, timeout=30.0): def _generatePacketId(self): """Get a new unique packet ID""" if self.currentPacketId is None: - raise Exception("Not connected yet, can not generate packet") + raise MeshInterface.MeshInterfaceError("Not connected yet, can not generate packet") else: self.currentPacketId = (self.currentPacketId + 1) & 0xFFFFFFFF return self.currentPacketId @@ -773,7 +779,7 @@ def _handleFromRadio(self, fromRadioBytes): failmsg = None if failmsg: - self.failure = Exception(failmsg) + self.failure = MeshInterface.MeshInterfaceError(failmsg) self.isConnected.set() # let waitConnected return this exception self.close() @@ -919,7 +925,7 @@ def _nodeNumToId(self, num): def _getOrCreateByNum(self, nodeNum): """Given a nodenum find the NodeInfo in the DB (or create if necessary)""" if nodeNum == BROADCAST_NUM: - raise Exception("Can not create/find nodenum by the broadcast num") + raise MeshInterface.MeshInterfaceError("Can not create/find nodenum by the broadcast num") if nodeNum in self.nodesByNum: return self.nodesByNum[nodeNum] From bf56521a5328e957c4d1452750a492ba3b7db05c Mon Sep 17 00:00:00 2001 From: Ian McEwen Date: Tue, 19 Mar 2024 13:00:06 -0700 Subject: [PATCH 3/4] Create Tunnel.TunnelError for specialized errors in that file --- meshtastic/tunnel.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/meshtastic/tunnel.py b/meshtastic/tunnel.py index b3fe7d4f..63412b7e 100644 --- a/meshtastic/tunnel.py +++ b/meshtastic/tunnel.py @@ -38,6 +38,12 @@ def onTunnelReceive(packet, interface): # pylint: disable=W0613 class Tunnel: """A TUN based IP tunnel over meshtastic""" + class TunnelError(Exception): + """An exception class for general tunnel errors""" + def __init__(self, message): + self.message = message + super().__init__(self.message) + def __init__(self, iface, subnet="10.115", netmask="255.255.0.0"): """ Constructor @@ -47,19 +53,19 @@ def __init__(self, iface, subnet="10.115", netmask="255.255.0.0"): """ if not iface: - raise Exception("Tunnel() must have a interface") + raise Tunnel.TunnelError("Tunnel() must have a interface") if not subnet: - raise Exception("Tunnel() must have a subnet") + raise Tunnel.TunnelError("Tunnel() must have a subnet") if not netmask: - raise Exception("Tunnel() must have a netmask") + raise Tunnel.TunnelError("Tunnel() must have a netmask") self.iface = iface self.subnetPrefix = subnet if platform.system() != "Linux": - raise Exception("Tunnel() can only be run instantiated on a Linux system") + raise Tunnel.TunnelError("Tunnel() can only be run instantiated on a Linux system") our_globals = Globals.getInstance() our_globals.set_tunnelInstance(self) From 9b5943192db0aa5a74c13c8c71e2102149b1a1e7 Mon Sep 17 00:00:00 2001 From: Ian McEwen Date: Tue, 19 Mar 2024 13:18:15 -0700 Subject: [PATCH 4/4] Make pylint happy with ble_interface.py --- meshtastic/ble_interface.py | 55 +++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/meshtastic/ble_interface.py b/meshtastic/ble_interface.py index dbe87cdd..c4b542f9 100644 --- a/meshtastic/ble_interface.py +++ b/meshtastic/ble_interface.py @@ -3,12 +3,12 @@ import logging import time import struct +import asyncio from threading import Thread, Event -from meshtastic.mesh_interface import MeshInterface -from meshtastic.util import our_exit from bleak import BleakScanner, BleakClient -import asyncio +from meshtastic.mesh_interface import MeshInterface +from meshtastic.util import our_exit SERVICE_UUID = "6ba1b218-15a8-461f-9fa8-5dcae273eafd" TORADIO_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7" @@ -17,13 +17,14 @@ class BLEInterface(MeshInterface): + """MeshInterface using BLE to connect to devices""" class BLEError(Exception): + """An exception class for BLE errors""" def __init__(self, message): self.message = message super().__init__(self.message) - - class BLEState(): + class BLEState(): # pylint: disable=C0115 THREADS = False BLE = False MESH = False @@ -69,13 +70,14 @@ def __init__(self, address, noProto = False, debugOut = None): self.client.start_notify(FROMNUM_UUID, self.from_num_handler) - async def from_num_handler(self, _, b): + async def from_num_handler(self, _, b): # pylint: disable=C0116 from_num = struct.unpack('