Skip to content

Commit 7f4e154

Browse files
committed
lint: add almost all annotations to pass mypy --strict
One remains, for a context manager's __exit__: adafruit_tinylora.py:240: error: Function is missing a type annotation for one or more arguments [no-untyped-def] Not sure how this should be annotated, but it's not annotated in upstream cpython 3.12 either. Added type aliases bytearray2, bytearray4, etc to signal that the bytearrays passed must be 2 bytes, 4 bytes, etc. In adafruit_tinylora_encryption.py, there's a "state" matrix for the AES implementation there. It was mixing str and byte/int, which apparently works fine on circuitpython but fails on cpython. Change the state matrix to a bytearray, as was likely intended. Fixes #50.
1 parent 8f25b30 commit 7f4e154

File tree

5 files changed

+170
-63
lines changed

5 files changed

+170
-63
lines changed

adafruit_tinylora/adafruit_tinylora.py

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,29 @@
2727

2828
import time
2929
from random import randint
30-
from micropython import const
30+
3131
import adafruit_bus_device.spi_device
32+
from micropython import const
33+
3234
from adafruit_tinylora.adafruit_tinylora_encryption import AES
3335

36+
try: # typing
37+
from typing import Annotated, Optional, TypeAlias, Union
38+
39+
import busio.SPI
40+
import digitalio.DigitalInOut
41+
from typing_extensions import Self # Python <3.11
42+
43+
# type aliases
44+
bytearray2: TypeAlias = Annotated[bytearray, 2]
45+
bytearray4: TypeAlias = Annotated[bytearray, 4]
46+
bytearray16: TypeAlias = Annotated[bytearray, 16]
47+
48+
registeraddress: TypeAlias = Union[const, int]
49+
except ImportError:
50+
pass
51+
52+
3453
__version__ = "0.0.0+auto.0"
3554
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TinyLoRa.git"
3655

@@ -70,7 +89,13 @@
7089
class TTN:
7190
"""TTN Class"""
7291

73-
def __init__(self, dev_address, net_key, app_key, country="US"):
92+
def __init__(
93+
self,
94+
dev_address: bytearray4,
95+
net_key: bytearray16,
96+
app_key: bytearray16,
97+
country: str = "US",
98+
):
7499
"""Interface for TheThingsNetwork
75100
:param bytearray dev_address: TTN Device Address.
76101
:param bytearray net_key: TTN Network Key.
@@ -83,22 +108,22 @@ def __init__(self, dev_address, net_key, app_key, country="US"):
83108
self.region = country
84109

85110
@property
86-
def country(self):
111+
def country(self) -> str:
87112
"""Returns the TTN Frequency Country."""
88113
return self.region
89114

90115
@property
91-
def device_address(self):
116+
def device_address(self) -> bytearray4:
92117
"""Returns the TTN Device Address."""
93118
return self.dev_addr
94119

95120
@property
96-
def application_key(self):
121+
def application_key(self) -> bytearray16:
97122
"""Returns the TTN Application Key."""
98123
return self.app_key
99124

100125
@property
101-
def network_key(self):
126+
def network_key(self) -> bytearray16:
102127
"""Returns the TTN Network Key."""
103128
return self.net_key
104129

@@ -108,10 +133,18 @@ class TinyLoRa:
108133
"""TinyLoRa Interface"""
109134

110135
# SPI Write Buffer
111-
_BUFFER = bytearray(2)
136+
_BUFFER: bytearray2 = bytearray(2)
112137

113138
# pylint: disable=too-many-arguments,invalid-name
114-
def __init__(self, spi, cs, irq, rst, ttn_config, channel=None):
139+
def __init__(
140+
self,
141+
spi: busio.SPI,
142+
cs: digitalio.DigitalInOut,
143+
irq: digitalio.DigitalInOut,
144+
rst: digitalio.DigitalInOut,
145+
ttn_config: digitalio.DigitalInOut,
146+
channel: Optional[int] = None,
147+
):
115148
"""Interface for a HopeRF RFM95/6/7/8(w) radio module. Sets module up for sending to
116149
The Things Network.
117150
@@ -141,13 +174,13 @@ def __init__(self, spi, cs, irq, rst, ttn_config, channel=None):
141174
if self._version != 18:
142175
raise TypeError("Can not detect LoRa Module. Please check wiring!")
143176
# Set Frequency registers
144-
self._rfm_msb = None
145-
self._rfm_mid = None
146-
self._rfm_lsb = None
177+
self._rfm_msb: Optional[registeraddress] = None
178+
self._rfm_mid: Optional[registeraddress] = None
179+
self._rfm_lsb: Optional[registeraddress] = None
147180
# Set datarate registers
148-
self._sf = None
149-
self._bw = None
150-
self._modemcfg = None
181+
self._sf: Optional[registeraddress] = None
182+
self._bw: Optional[registeraddress] = None
183+
self._modemcfg: Optional[registeraddress] = None
151184
self.set_datarate("SF7BW125")
152185
# Set regional frequency plan
153186
# pylint: disable=import-outside-toplevel
@@ -201,13 +234,13 @@ def __init__(self, spi, cs, irq, rst, ttn_config, channel=None):
201234
# Give the lora object ttn configuration
202235
self._ttn_config = ttn_config
203236

204-
def __enter__(self):
237+
def __enter__(self) -> Self:
205238
return self
206239

207-
def __exit__(self, exception_type, exception_value, traceback):
240+
def __exit__(self, exception_type, exception_value, traceback) -> None:
208241
self.deinit()
209242

210-
def deinit(self):
243+
def deinit(self) -> None:
211244
"""Deinitializes the TinyLoRa object properties and pins."""
212245
self._irq = None
213246
self._rst = None
@@ -220,7 +253,9 @@ def deinit(self):
220253
self._bw = None
221254
self._modemcfg = None
222255

223-
def send_data(self, data, data_length, frame_counter, timeout=2):
256+
def send_data(
257+
self, data: bytearray, data_length: int, frame_counter: int, timeout: int = 2
258+
) -> None:
224259
"""Function to assemble and send data
225260
:param data: data to send
226261
:param data_length: length of data to send
@@ -258,15 +293,15 @@ def send_data(self, data, data_length, frame_counter, timeout=2):
258293
# recalculate packet length
259294
lora_pkt_len += data_length
260295
# Calculate MIC
261-
mic = bytearray(4)
296+
mic: bytearray4 = bytearray(4)
262297
mic = aes.calculate_mic(lora_pkt, lora_pkt_len, mic)
263298
# load mic in package
264299
lora_pkt[lora_pkt_len : lora_pkt_len + 4] = mic[0:4]
265300
# recalculate packet length (add MIC length)
266301
lora_pkt_len += 4
267302
self.send_packet(lora_pkt, lora_pkt_len, timeout)
268303

269-
def send_packet(self, lora_packet, packet_length, timeout):
304+
def send_packet(self, lora_packet: bytearray, packet_length: int, timeout: int) -> None:
270305
"""Sends a LoRa packet using the RFM Module
271306
:param bytearray lora_packet: assembled LoRa packet from send_data
272307
:param int packet_length: length of LoRa packet to send
@@ -312,10 +347,11 @@ def send_packet(self, lora_packet, packet_length, timeout):
312347
if timed_out:
313348
raise RuntimeError("Timeout during packet send")
314349

315-
def set_datarate(self, datarate):
350+
def set_datarate(self, datarate: str) -> None:
316351
"""Sets the RFM Datarate
317352
:param datarate: Bandwidth and Frequency Plan
318353
"""
354+
# TODO: Convert these to enum
319355
data_rates = {
320356
"SF7BW125": (0x74, 0x72, 0x04),
321357
"SF7BW250": (0x74, 0x82, 0x04),
@@ -330,13 +366,15 @@ def set_datarate(self, datarate):
330366
except KeyError as err:
331367
raise KeyError("Invalid or Unsupported Datarate.") from err
332368

333-
def set_channel(self, channel):
369+
def set_channel(self, channel: int) -> None:
334370
"""Sets the RFM Channel (if single-channel)
335371
:param int channel: Transmit Channel (0 through 7).
336372
"""
337373
self._rfm_msb, self._rfm_mid, self._rfm_lsb = self._frequencies[channel]
338374

339-
def _read_into(self, address, buf, length=None):
375+
def _read_into(
376+
self, address: registeraddress, buf: bytearray2, length: Optional[int] = None
377+
) -> None:
340378
"""Read a number of bytes from the specified address into the
341379
provided buffer. If length is not specified (default) the entire buffer
342380
will be filled.
@@ -353,14 +391,14 @@ def _read_into(self, address, buf, length=None):
353391
device.write(self._BUFFER, end=1)
354392
device.readinto(buf, end=length)
355393

356-
def _read_u8(self, address):
394+
def _read_u8(self, address: registeraddress) -> int:
357395
"""Read a single byte from the provided address and return it.
358396
:param bytearray address: Register Address.
359397
"""
360398
self._read_into(address, self._BUFFER, length=1)
361399
return self._BUFFER[0]
362400

363-
def _write_u8(self, address, val):
401+
def _write_u8(self, address: registeraddress, val: int) -> None:
364402
"""Writes to the RFM register given an address and data.
365403
:param bytearray address: Register Address.
366404
:param val: Data to write.
@@ -370,3 +408,6 @@ def _write_u8(self, address, val):
370408
self._BUFFER[1] = val
371409
# pylint: disable=no-member
372410
device.write(self._BUFFER, end=2)
411+
# pylint: disable=no-member
412+
device.write(self._BUFFER, end=2)
413+
device.write(self._BUFFER, end=2)

0 commit comments

Comments
 (0)