Skip to content

Commit 652fb27

Browse files
committed
Add annotations for advertising/__init__.py
1 parent d7bf0af commit 652fb27

File tree

1 file changed

+41
-34
lines changed

1 file changed

+41
-34
lines changed

adafruit_ble/advertising/__init__.py

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,27 @@
88

99
import struct
1010

11+
try:
12+
from typing import Dict, Any, Union, List, Optional, Type, Literal, TypeVar
13+
from _bleio import ScanEntry
1114

12-
def to_hex(seq):
15+
LazyObjectField_GivenClass = TypeVar("LazyObjectField_GivenClass")
16+
17+
except ImportError:
18+
pass
19+
20+
21+
def to_hex(seq: bytes) -> str:
1322
"""Pretty prints a byte sequence as hex values."""
1423
return " ".join("{:02x}".format(v) for v in seq)
1524

1625

17-
def to_bytes_literal(seq):
26+
def to_bytes_literal(seq: bytes) -> str:
1827
"""Prints a byte sequence as a Python bytes literal that only uses hex encoding."""
1928
return 'b"' + "".join("\\x{:02x}".format(v) for v in seq) + '"'
2029

2130

22-
def decode_data(data, *, key_encoding="B"):
31+
def decode_data(data: bytes, *, key_encoding: str = "B") -> Dict[Any, Union[bytes, List[bytes]]]:
2332
"""Helper which decodes length encoded structures into a dictionary with the given key
2433
encoding."""
2534
i = 0
@@ -42,7 +51,7 @@ def decode_data(data, *, key_encoding="B"):
4251
return data_dict
4352

4453

45-
def compute_length(data_dict, *, key_encoding="B"):
54+
def compute_length(data_dict: Dict[Any, Union[bytes, List[bytes]]], *, key_encoding: str = "B") -> int:
4655
"""Computes the length of the encoded data dictionary."""
4756
value_size = 0
4857
for value in data_dict.values():
@@ -54,7 +63,7 @@ def compute_length(data_dict, *, key_encoding="B"):
5463
return len(data_dict) + len(data_dict) * struct.calcsize(key_encoding) + value_size
5564

5665

57-
def encode_data(data_dict, *, key_encoding="B"):
66+
def encode_data(data_dict: Dict[Any, Union[bytes, List[bytes]]], *, key_encoding: str = "B") -> bytes:
5867
"""Helper which encodes dictionaries into length encoded structures with the given key
5968
encoding."""
6069
length = compute_length(data_dict, key_encoding=key_encoding)
@@ -72,25 +81,23 @@ def encode_data(data_dict, *, key_encoding="B"):
7281
return bytes(data)
7382

7483

84+
# pylint: disable=too-few-public-methods
7585
class AdvertisingDataField:
7686
"""Top level class for any descriptor classes that live in Advertisement or its subclasses."""
7787

78-
# pylint: disable=too-few-public-methods,unnecessary-pass
79-
pass
80-
8188

8289
class AdvertisingFlag:
8390
"""A single bit flag within an AdvertisingFlags object."""
8491

85-
def __init__(self, bit_position):
92+
def __init__(self, bit_position: int) -> None:
8693
self._bitmask = 1 << bit_position
8794

88-
def __get__(self, obj, cls):
95+
def __get__(self, obj: Optional["AdvertisingFlags"], cls: Type["AdvertisingFlags"]) -> Union[bool, "AdvertisingFlag"]:
8996
if obj is None:
9097
return self
9198
return (obj.flags & self._bitmask) != 0
9299

93-
def __set__(self, obj, value):
100+
def __set__(self, obj: "AdvertisingFlags", value: bool) -> None:
94101
if value:
95102
obj.flags |= self._bitmask
96103
else:
@@ -108,20 +115,20 @@ class AdvertisingFlags(AdvertisingDataField):
108115
"""BR/EDR not supported."""
109116
# BR/EDR flags not included here, since we don't support BR/EDR.
110117

111-
def __init__(self, advertisement, advertising_data_type):
118+
def __init__(self, advertisement: "Advertisement", advertising_data_type: int) -> None:
112119
self._advertisement = advertisement
113120
self._adt = advertising_data_type
114121
self.flags = 0
115122
if self._adt in self._advertisement.data_dict:
116123
self.flags = self._advertisement.data_dict[self._adt][0]
117124

118-
def __len__(self):
125+
def __len__(self) -> Literal[1]:
119126
return 1
120127

121-
def __bytes__(self):
128+
def __bytes__(self) -> bytes:
122129
return bytes([self.flags])
123130

124-
def __str__(self):
131+
def __str__(self) -> str:
125132
parts = []
126133
for attr in dir(self.__class__):
127134
attribute_instance = getattr(self.__class__, attr)
@@ -136,48 +143,48 @@ class String(AdvertisingDataField):
136143
137144
Not null terminated once encoded because length is always transmitted."""
138145

139-
def __init__(self, *, advertising_data_type):
146+
def __init__(self, *, advertising_data_type: int) -> None:
140147
self._adt = advertising_data_type
141148

142-
def __get__(self, obj, cls):
149+
def __get__(self, obj: Optional["Advertisement"], cls: Type["Advertisement"]) -> Optional[Union[str, "String"]]:
143150
if obj is None:
144151
return self
145152
if self._adt not in obj.data_dict:
146153
return None
147154
return str(obj.data_dict[self._adt], "utf-8")
148155

149-
def __set__(self, obj, value):
156+
def __set__(self, obj: "Advertisement", value: str) -> None:
150157
obj.data_dict[self._adt] = value.encode("utf-8")
151158

152159

153160
class Struct(AdvertisingDataField):
154161
"""`struct` encoded data in an Advertisement."""
155162

156-
def __init__(self, struct_format, *, advertising_data_type):
163+
def __init__(self, struct_format: str, *, advertising_data_type: int) -> None:
157164
self._format = struct_format
158165
self._adt = advertising_data_type
159166

160-
def __get__(self, obj, cls):
167+
def __get__(self, obj: Optional["Advertisement"], cls: Type["Advertisement"]) -> Optional[Union[Any, "Struct"]]:
161168
if obj is None:
162169
return self
163170
if self._adt not in obj.data_dict:
164171
return None
165172
return struct.unpack(self._format, obj.data_dict[self._adt])[0]
166173

167-
def __set__(self, obj, value):
174+
def __set__(self, obj: "Advertisement", value: Any) -> None:
168175
obj.data_dict[self._adt] = struct.pack(self._format, value)
169176

170177

171178
class LazyObjectField(AdvertisingDataField):
172179
"""Non-data descriptor useful for lazily binding a complex object to an advertisement object."""
173180

174-
def __init__(self, cls, attribute_name, *, advertising_data_type, **kwargs):
181+
def __init__(self, cls: Any, attribute_name: str, *, advertising_data_type: int, **kwargs) -> None:
175182
self._cls = cls
176183
self._attribute_name = attribute_name
177184
self._adt = advertising_data_type
178185
self._kwargs = kwargs
179186

180-
def __get__(self, obj, cls):
187+
def __get__(self, obj: Optional["Advertisement"], cls: Type["Advertisement"]) -> Any:
181188
if obj is None:
182189
return self
183190
# Return None if our object is immutable and the data is not present.
@@ -190,7 +197,7 @@ def __get__(self, obj, cls):
190197
return bound_obj
191198

192199
@property
193-
def advertising_data_type(self):
200+
def advertising_data_type(self) -> int:
194201
"""Return the data type value used to indicate this field."""
195202
return self._adt
196203

@@ -237,7 +244,7 @@ class Advertisement:
237244
# MAX_LEGACY_DATA_SIZE = 31
238245
# """Data size in a regular BLE packet."""
239246

240-
def __init__(self, *, entry=None):
247+
def __init__(self, *, entry: Optional[ScanEntry] = None) -> None:
241248
"""Create an empty advertising packet or one from a ScanEntry."""
242249
if entry:
243250
self.data_dict = decode_data(entry.advertisement_bytes)
@@ -255,13 +262,13 @@ def __init__(self, *, entry=None):
255262
self.scan_response = False
256263

257264
@property
258-
def rssi(self):
265+
def rssi(self) -> Optional[int]:
259266
"""Signal strength of the scanned advertisement. Only available on Advertisements returned
260267
from `BLERadio.start_scan()`. (read-only)"""
261268
return self._rssi
262269

263270
@classmethod
264-
def get_prefix_bytes(cls):
271+
def get_prefix_bytes(cls) -> Optional[bytes]:
265272
"""Return a merged version of match_prefixes as a single bytes object,
266273
with length headers.
267274
"""
@@ -281,15 +288,15 @@ def get_prefix_bytes(cls):
281288
return cls._prefix_bytes
282289

283290
@classmethod
284-
def matches(cls, entry):
291+
def matches(cls, entry: ScanEntry) -> bool:
285292
"""Returns ``True`` if the given `_bleio.ScanEntry` advertisement fields
286293
matches all of the given prefixes in the `match_prefixes` tuple attribute.
287294
Subclasses may override this to match any instead of all.
288295
"""
289296
return cls.matches_prefixes(entry, all_=True)
290297

291298
@classmethod
292-
def matches_prefixes(cls, entry, *, all_):
299+
def matches_prefixes(cls, entry: ScanEntry, *, all_: bool) -> bool:
293300
"""Returns ``True`` if the given `_bleio.ScanEntry` advertisement fields
294301
match any or all of the given prefixes in the `match_prefixes` tuple attribute.
295302
If ``all_`` is ``True``, all the prefixes must match. If ``all_`` is ``False``,
@@ -298,16 +305,16 @@ def matches_prefixes(cls, entry, *, all_):
298305
# Returns True if cls.get_prefix_bytes() is empty.
299306
return entry.matches(cls.get_prefix_bytes(), all=all_)
300307

301-
def __bytes__(self):
308+
def __bytes__(self) -> bytes:
302309
"""The raw packet bytes."""
303310
return encode_data(self.data_dict)
304311

305-
def __eq__(self, other):
312+
def __eq__(self, other) -> bool:
306313
if isinstance(other, Advertisement):
307314
return self.data_dict == other.data_dict
308315
return False
309316

310-
def __str__(self):
317+
def __str__(self) -> str:
311318
parts = []
312319
for attr in dir(self.__class__):
313320
attribute_instance = getattr(self.__class__, attr)
@@ -324,10 +331,10 @@ def __str__(self):
324331
parts.append("{}={}".format(attr, str(value)))
325332
return "<{} {} >".format(self.__class__.__name__, " ".join(parts))
326333

327-
def __len__(self):
334+
def __len__(self) -> int:
328335
return compute_length(self.data_dict)
329336

330-
def __repr__(self):
337+
def __repr__(self) -> str:
331338
return "Advertisement(data={})".format(
332339
to_bytes_literal(encode_data(self.data_dict))
333340
)

0 commit comments

Comments
 (0)