Skip to content

Commit d8fdb0b

Browse files
authored
Merge pull request #86 from tekktrik/doc/add-typing
Add type annotations
2 parents dd1d401 + 4e2c583 commit d8fdb0b

File tree

2 files changed

+51
-36
lines changed

2 files changed

+51
-36
lines changed

adafruit_gps.py

+49-36
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929
import time
3030
from micropython import const
3131

32+
try:
33+
from typing import Optional, Tuple, List
34+
from typing_extensions import Literal
35+
from circuitpython_typing import ReadableBuffer
36+
from busio import UART, I2C
37+
except ImportError:
38+
pass
39+
3240
__version__ = "0.0.0+auto.0"
3341
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_GPS.git"
3442

@@ -75,7 +83,7 @@
7583
# Internal helper parsing functions.
7684
# These handle input that might be none or null and return none instead of
7785
# throwing errors.
78-
def _parse_degrees(nmea_data):
86+
def _parse_degrees(nmea_data: str) -> int:
7987
# Parse a NMEA lat/long data pair 'dddmm.mmmm' into a pure degrees value.
8088
# Where ddd is the degrees, mm.mmmm is the minutes.
8189
if nmea_data is None or len(nmea_data) < 3:
@@ -88,52 +96,52 @@ def _parse_degrees(nmea_data):
8896
minutes = int(raw[0]) % 100 # the mm.
8997
minutes += int(f"{raw[1][:4]:0<4}") / 10000
9098
minutes = int(minutes / 60 * 1000000)
91-
return degrees + minutes # return parsed string in the format dddmmmmmm
99+
return degrees + minutes
92100

93101

94-
def _parse_int(nmea_data):
102+
def _parse_int(nmea_data: str) -> int:
95103
if nmea_data is None or nmea_data == "":
96104
return None
97105
return int(nmea_data)
98106

99107

100-
def _parse_float(nmea_data):
108+
def _parse_float(nmea_data: str) -> float:
101109
if nmea_data is None or nmea_data == "":
102110
return None
103111
return float(nmea_data)
104112

105113

106-
def _parse_str(nmea_data):
114+
def _parse_str(nmea_data: str) -> str:
107115
if nmea_data is None or nmea_data == "":
108116
return None
109117
return str(nmea_data)
110118

111119

112-
def _read_degrees(data, index, neg):
120+
def _read_degrees(data: List[float], index: int, neg: str) -> float:
113121
# This function loses precision with float32
114122
x = data[index] / 1000000
115123
if data[index + 1].lower() == neg:
116124
x *= -1.0
117125
return x
118126

119127

120-
def _read_int_degrees(data, index, neg):
128+
def _read_int_degrees(data: List[float], index: int, neg: str) -> Tuple[int, float]:
121129
deg = data[index] // 1000000
122130
minutes = data[index] % 1000000 / 10000
123131
if data[index + 1].lower() == neg:
124132
deg *= -1
125133
return (deg, minutes)
126134

127135

128-
def _parse_talker(data_type):
136+
def _parse_talker(data_type: bytes) -> Tuple[bytes, bytes]:
129137
# Split the data_type into talker and sentence_type
130138
if data_type[:1] == b"P": # Proprietary codes
131139
return (data_type[:1], data_type[1:])
132140

133141
return (data_type[:2], data_type[2:])
134142

135143

136-
def _parse_data(sentence_type, data):
144+
def _parse_data(sentence_type: int, data: List[str]) -> Optional[List]:
137145
"""Parse sentence data for the specified sentence type and
138146
return a list of parameters in the correct format, or return None.
139147
"""
@@ -217,7 +225,7 @@ class GPS:
217225
GPS modules to read latitude, longitude, and more.
218226
"""
219227

220-
def __init__(self, uart, debug=False):
228+
def __init__(self, uart: UART, debug: bool = False) -> None:
221229
self._uart = uart
222230
# Initialize null starting values for GPS attributes.
223231
self.timestamp_utc = None
@@ -253,7 +261,7 @@ def __init__(self, uart, debug=False):
253261
self._magnetic_variation = None
254262
self.debug = debug
255263

256-
def update(self):
264+
def update(self) -> bool:
257265
"""Check for updated data from the GPS module and process it
258266
accordingly. Returns True if new data was processed, and False if
259267
nothing new was received.
@@ -303,7 +311,7 @@ def update(self):
303311

304312
return result
305313

306-
def send_command(self, command, add_checksum=True):
314+
def send_command(self, command: bytes, add_checksum: bool = True) -> None:
307315
"""Send a command string to the GPS. If add_checksum is True (the
308316
default) a NMEA checksum will automatically be computed and added.
309317
Note you should NOT add the leading $ and trailing * to the command
@@ -320,48 +328,48 @@ def send_command(self, command, add_checksum=True):
320328
self.write(b"\r\n")
321329

322330
@property
323-
def has_fix(self):
331+
def has_fix(self) -> bool:
324332
"""True if a current fix for location information is available."""
325333
return self.fix_quality is not None and self.fix_quality >= 1
326334

327335
@property
328-
def has_3d_fix(self):
336+
def has_3d_fix(self) -> bool:
329337
"""Returns true if there is a 3d fix available.
330338
use has_fix to determine if a 2d fix is available,
331339
passing it the same data"""
332340
return self.fix_quality_3d is not None and self.fix_quality_3d >= 2
333341

334342
@property
335-
def datetime(self):
343+
def datetime(self) -> Optional[time.struct_time]:
336344
"""Return struct_time object to feed rtc.set_time_source() function"""
337345
return self.timestamp_utc
338346

339347
@property
340-
def nmea_sentence(self):
348+
def nmea_sentence(self) -> Optional[str]:
341349
"""Return raw_sentence which is the raw NMEA sentence read from the GPS"""
342350
return self._raw_sentence
343351

344-
def read(self, num_bytes):
352+
def read(self, num_bytes: Optional[int]) -> Optional[bytes]:
345353
"""Read up to num_bytes of data from the GPS directly, without parsing.
346-
Returns a bytearray with up to num_bytes or None if nothing was read"""
354+
Returns a bytestring with up to num_bytes or None if nothing was read"""
347355
return self._uart.read(num_bytes)
348356

349-
def write(self, bytestr):
357+
def write(self, bytestr: ReadableBuffer) -> Optional[int]:
350358
"""Write a bytestring data to the GPS directly, without parsing
351359
or checksums"""
352360
return self._uart.write(bytestr)
353361

354362
@property
355-
def in_waiting(self):
363+
def in_waiting(self) -> int:
356364
"""Returns number of bytes available in UART read buffer"""
357365
return self._uart.in_waiting
358366

359-
def readline(self):
360-
"""Returns a newline terminated bytearray, must have timeout set for
367+
def readline(self) -> Optional[bytes]:
368+
"""Returns a newline terminated bytestring, must have timeout set for
361369
the underlying UART or this will block forever!"""
362370
return self._uart.readline()
363371

364-
def _read_sentence(self):
372+
def _read_sentence(self) -> Optional[str]:
365373
# Parse any NMEA sentence that is available.
366374
# pylint: disable=len-as-condition
367375
# This needs to be refactored when it can be tested.
@@ -394,7 +402,7 @@ def _read_sentence(self):
394402
# At this point we don't have a valid sentence
395403
return None
396404

397-
def _parse_sentence(self):
405+
def _parse_sentence(self) -> Optional[Tuple[str, str]]:
398406
sentence = self._read_sentence()
399407

400408
# sentence is a valid NMEA with a valid checksum
@@ -411,7 +419,7 @@ def _parse_sentence(self):
411419
data_type = sentence[1:delimiter]
412420
return (data_type, sentence[delimiter + 1 :])
413421

414-
def _update_timestamp_utc(self, time_utc, date=None):
422+
def _update_timestamp_utc(self, time_utc: str, date: Optional[str] = None) -> None:
415423
hours = int(time_utc[0:2])
416424
mins = int(time_utc[2:4])
417425
secs = int(time_utc[4:6])
@@ -431,7 +439,7 @@ def _update_timestamp_utc(self, time_utc, date=None):
431439
(year, month, day, hours, mins, secs, 0, 0, -1)
432440
)
433441

434-
def _parse_gll(self, data):
442+
def _parse_gll(self, data: List[str]) -> bool:
435443
# GLL - Geographic Position - Latitude/Longitude
436444

437445
if data is None or len(data) != 7:
@@ -459,7 +467,7 @@ def _parse_gll(self, data):
459467

460468
return True
461469

462-
def _parse_rmc(self, data):
470+
def _parse_rmc(self, data: List[str]) -> bool:
463471
# RMC - Recommended Minimum Navigation Information
464472

465473
if data is None or len(data) not in (12, 13):
@@ -505,7 +513,7 @@ def _parse_rmc(self, data):
505513

506514
return True
507515

508-
def _parse_gga(self, data):
516+
def _parse_gga(self, data: List[str]) -> bool:
509517
# GGA - Global Positioning System Fix Data
510518

511519
if data is None or len(data) != 14:
@@ -557,7 +565,7 @@ def _parse_gga(self, data):
557565

558566
return True
559567

560-
def _parse_gsa(self, talker, data):
568+
def _parse_gsa(self, talker: bytes, data: List[str]) -> bool:
561569
# GSA - GPS DOP and active satellites
562570

563571
if data is None or len(data) not in (17, 18):
@@ -596,7 +604,7 @@ def _parse_gsa(self, talker, data):
596604

597605
return True
598606

599-
def _parse_gsv(self, talker, data):
607+
def _parse_gsv(self, talker: bytes, data: List[str]) -> bool:
600608
# GSV - Satellites in view
601609
# pylint: disable=too-many-branches
602610

@@ -675,8 +683,13 @@ class GPS_GtopI2C(GPS):
675683
"""
676684

677685
def __init__(
678-
self, i2c_bus, *, address=_GPSI2C_DEFAULT_ADDRESS, debug=False, timeout=5
679-
):
686+
self,
687+
i2c_bus: I2C,
688+
*,
689+
address: int = _GPSI2C_DEFAULT_ADDRESS,
690+
debug: bool = False,
691+
timeout: float = 5.0,
692+
) -> None:
680693
from adafruit_bus_device import ( # pylint: disable=import-outside-toplevel
681694
i2c_device,
682695
)
@@ -688,7 +701,7 @@ def __init__(
688701
self._internalbuffer = []
689702
self._timeout = timeout
690703

691-
def read(self, num_bytes=1):
704+
def read(self, num_bytes: int = 1) -> bytearray:
692705
"""Read up to num_bytes of data from the GPS directly, without parsing.
693706
Returns a bytearray with up to num_bytes or None if nothing was read"""
694707
result = []
@@ -704,19 +717,19 @@ def read(self, num_bytes=1):
704717
self._lastbyte = char # keep track of the last character approved
705718
return bytearray(result)
706719

707-
def write(self, bytestr):
720+
def write(self, bytestr: ReadableBuffer) -> None:
708721
"""Write a bytestring data to the GPS directly, without parsing
709722
or checksums"""
710723
with self._i2c as i2c:
711724
i2c.write(bytestr)
712725

713726
@property
714-
def in_waiting(self):
727+
def in_waiting(self) -> Literal[16]:
715728
"""Returns number of bytes available in UART read buffer, always 16
716729
since I2C does not have the ability to know how much data is available"""
717730
return 16
718731

719-
def readline(self):
732+
def readline(self) -> Optional[bytearray]:
720733
"""Returns a newline terminated bytearray, must have timeout set for
721734
the underlying UART or this will block forever!"""
722735
timeout = time.monotonic() + self._timeout

requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
Adafruit-Blinka
66
adafruit-circuitpython-busdevice
77
pyserial
8+
adafruit-circuitpython-typing
9+
typing-extensions~=4.0

0 commit comments

Comments
 (0)