Skip to content

Commit

Permalink
Merge pull request #74 from adafruit/pylint-update
Browse files Browse the repository at this point in the history
Ran black, updated to pylint 2.x
  • Loading branch information
kattni authored Mar 17, 2020
2 parents f50290b + e5385fa commit 2052ff6
Show file tree
Hide file tree
Showing 28 changed files with 763 additions and 411 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
source actions-ci/install.sh
- name: Pip install pylint, black, & Sphinx
run: |
pip install --force-reinstall pylint==1.9.2 black==19.10b0 Sphinx sphinx-rtd-theme
pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme
- name: Library version
run: git describe --dirty --always --tags
- name: PyLint
Expand Down
54 changes: 39 additions & 15 deletions adafruit_ble/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
building on the native `_bleio` module.
"""
#pylint: disable=wrong-import-position
# pylint: disable=wrong-import-position
import sys
if sys.implementation.name == 'circuitpython' and sys.implementation.version[0] <= 4:

if sys.implementation.name == "circuitpython" and sys.implementation.version[0] <= 4:
raise ImportError(
"This release is not compatible with CircuitPython 4.x; use library release 1.x.x")
#pylint: enable=wrong-import-position
"This release is not compatible with CircuitPython 4.x; use library release 1.x.x"
)
# pylint: enable=wrong-import-position

import _bleio

Expand All @@ -41,6 +43,7 @@
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git"


class BLEConnection:
"""
Represents a connection to a peer BLE device.
Expand All @@ -49,6 +52,7 @@ class BLEConnection:
:param bleio_connection _bleio.Connection: the native `_bleio.Connection` object to wrap
"""

def __init__(self, bleio_connection):
self._bleio_connection = bleio_connection
# _bleio.Service objects representing services found during discovery.
Expand All @@ -61,7 +65,9 @@ def _discover_remote(self, uuid):
if uuid in self._discovered_bleio_services:
remote_service = self._discovered_bleio_services[uuid]
else:
results = self._bleio_connection.discover_remote_services((uuid.bleio_uuid,))
results = self._bleio_connection.discover_remote_services(
(uuid.bleio_uuid,)
)
if results:
remote_service = results[0]
self._discovered_bleio_services[uuid] = remote_service
Expand Down Expand Up @@ -140,6 +146,7 @@ def disconnect(self):
"""Disconnect from peer."""
self._bleio_connection.disconnect()


class BLERadio:
"""
BLERadio provides the interfaces for BLE advertising,
Expand Down Expand Up @@ -172,17 +179,28 @@ def start_advertising(self, advertisement, scan_response=None, interval=0.1):
scan_response.tx_power = self.tx_power
if scan_response:
scan_response_bytes = bytes(scan_response)
self._adapter.start_advertising(advertisement_bytes,
scan_response=scan_response_bytes,
connectable=advertisement.connectable,
interval=interval)
self._adapter.start_advertising(
advertisement_bytes,
scan_response=scan_response_bytes,
connectable=advertisement.connectable,
interval=interval,
)

def stop_advertising(self):
"""Stops advertising."""
self._adapter.stop_advertising()

def start_scan(self, *advertisement_types, buffer_size=512, extended=False, timeout=None,
interval=0.1, window=0.1, minimum_rssi=-80, active=True):
def start_scan(
self,
*advertisement_types,
buffer_size=512,
extended=False,
timeout=None,
interval=0.1,
window=0.1,
minimum_rssi=-80,
active=True
):
"""
Starts scanning. Returns an iterator of advertisement objects of the types given in
advertisement_types. The iterator will block until an advertisement is heard or the scan
Expand Down Expand Up @@ -214,10 +232,16 @@ def start_scan(self, *advertisement_types, buffer_size=512, extended=False, time
prefixes = b""
if advertisement_types:
prefixes = b"".join(adv.prefix for adv in advertisement_types)
for entry in self._adapter.start_scan(prefixes=prefixes, buffer_size=buffer_size,
extended=extended, timeout=timeout,
interval=interval, window=window,
minimum_rssi=minimum_rssi, active=active):
for entry in self._adapter.start_scan(
prefixes=prefixes,
buffer_size=buffer_size,
extended=extended,
timeout=timeout,
interval=interval,
window=window,
minimum_rssi=minimum_rssi,
active=active,
):
adv_type = Advertisement
for possible_type in advertisement_types:
if possible_type.matches(entry) and issubclass(possible_type, adv_type):
Expand Down
39 changes: 30 additions & 9 deletions adafruit_ble/advertising/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@

import struct


def to_hex(seq):
"""Pretty prints a byte sequence as hex values."""
return " ".join("{:02x}".format(v) for v in seq)


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


def decode_data(data, *, key_encoding="B"):
"""Helper which decodes length encoded structures into a dictionary with the given key
Expand All @@ -45,7 +48,7 @@ def decode_data(data, *, key_encoding="B"):
if item_length == 0:
break
key = struct.unpack_from(key_encoding, data, i)[0]
value = data[i + key_size:i + item_length]
value = data[i + key_size : i + item_length]
if key in data_dict:
if not isinstance(data_dict[key], list):
data_dict[key] = [data_dict[key]]
Expand All @@ -55,6 +58,7 @@ def decode_data(data, *, key_encoding="B"):
i += item_length
return data_dict


def compute_length(data_dict, *, key_encoding="B"):
"""Computes the length of the encoded data dictionary."""
value_size = 0
Expand All @@ -66,6 +70,7 @@ def compute_length(data_dict, *, key_encoding="B"):
value_size += len(value)
return len(data_dict) + len(data_dict) * struct.calcsize(key_encoding) + value_size


def encode_data(data_dict, *, key_encoding="B"):
"""Helper which encodes dictionaries into length encoded structures with the given key
encoding."""
Expand All @@ -79,17 +84,21 @@ def encode_data(data_dict, *, key_encoding="B"):
item_length = key_size + len(value)
struct.pack_into("B", data, i, item_length)
struct.pack_into(key_encoding, data, i + 1, key)
data[i + 1 + key_size: i + 1 + item_length] = bytes(value)
data[i + 1 + key_size : i + 1 + item_length] = bytes(value)
i += 1 + item_length
return data


class AdvertisingDataField:
"""Top level class for any descriptor classes that live in Advertisement or its subclasses."""

# pylint: disable=too-few-public-methods,unnecessary-pass
pass


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

def __init__(self, bit_position):
self._bitmask = 1 << bit_position

Expand All @@ -102,6 +111,7 @@ def __set__(self, obj, value):
else:
obj.flags &= ~self._bitmask


class AdvertisingFlags(AdvertisingDataField):
"""Standard advertising flags"""

Expand Down Expand Up @@ -135,10 +145,12 @@ def __str__(self):
parts.append(attr)
return "<AdvertisingFlags {} >".format(" ".join(parts))


class String(AdvertisingDataField):
"""UTF-8 encoded string in an Advertisement.
Not null terminated once encoded because length is always transmitted."""

def __init__(self, *, advertising_data_type):
self._adt = advertising_data_type

Expand All @@ -152,8 +164,10 @@ def __get__(self, obj, cls):
def __set__(self, obj, value):
obj.data_dict[self._adt] = value.encode("utf-8")


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

def __init__(self, struct_format, *, advertising_data_type):
self._format = struct_format
self._adt = advertising_data_type
Expand All @@ -171,6 +185,7 @@ def __set__(self, obj, value):

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

def __init__(self, cls, attribute_name, *, advertising_data_type, **kwargs):
self._cls = cls
self._attribute_name = attribute_name
Expand All @@ -197,15 +212,17 @@ def advertising_data_type(self):
# TODO: Add __set_name__ support to CircuitPython so that we automatically tell the descriptor
# instance the attribute name it has and the class it is on.


class Advertisement:
"""Core Advertisement type"""
prefix = b"\x00" # This is an empty prefix and will match everything.

prefix = b"\x00" # This is an empty prefix and will match everything.
flags = LazyObjectField(AdvertisingFlags, "flags", advertising_data_type=0x01)
short_name = String(advertising_data_type=0x08)
"""Short local device name (shortened to fit)."""
complete_name = String(advertising_data_type=0x09)
"""Complete local device name."""
tx_power = Struct("<b", advertising_data_type=0x0a)
tx_power = Struct("<b", advertising_data_type=0x0A)
"""Transmit power level"""
# DEVICE_ID = 0x10
# """Device identifier."""
Expand Down Expand Up @@ -242,7 +259,7 @@ def from_entry(cls, entry):
self = cls()
self.data_dict = decode_data(entry.advertisement_bytes)
self.address = entry.address
self._rssi = entry.rssi # pylint: disable=protected-access
self._rssi = entry.rssi # pylint: disable=protected-access
self.connectable = entry.connectable
self.scan_response = entry.scan_response
self.mutable = False
Expand Down Expand Up @@ -272,8 +289,10 @@ def __str__(self):
for attr in dir(self.__class__):
attribute_instance = getattr(self.__class__, attr)
if issubclass(attribute_instance.__class__, AdvertisingDataField):
if (issubclass(attribute_instance.__class__, LazyObjectField) and
not attribute_instance.advertising_data_type in self.data_dict):
if (
issubclass(attribute_instance.__class__, LazyObjectField)
and not attribute_instance.advertising_data_type in self.data_dict
):
# Skip uninstantiated lazy objects; if we get
# their value, they will be be instantiated.
continue
Expand All @@ -286,4 +305,6 @@ def __len__(self):
return compute_length(self.data_dict)

def __repr__(self):
return "Advertisement(data={})".format(to_bytes_literal(encode_data(self.data_dict)))
return "Advertisement(data={})".format(
to_bytes_literal(encode_data(self.data_dict))
)
29 changes: 17 additions & 12 deletions adafruit_ble/advertising/adafruit.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,29 @@
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git"

_MANUFACTURING_DATA_ADT = const(0xff)
_MANUFACTURING_DATA_ADT = const(0xFF)
_ADAFRUIT_COMPANY_ID = const(0x0822)
_COLOR_DATA_ID = const(0x0000)


class AdafruitColor(Advertisement):
"""Broadcast a single RGB color."""

# This prefix matches all
prefix = struct.pack("<BBHBH",
0x6,
_MANUFACTURING_DATA_ADT,
_ADAFRUIT_COMPANY_ID,
struct.calcsize("<HI"),
_COLOR_DATA_ID)
manufacturer_data = LazyObjectField(ManufacturerData,
"manufacturer_data",
advertising_data_type=_MANUFACTURING_DATA_ADT,
company_id=_ADAFRUIT_COMPANY_ID,
key_encoding="<H")
prefix = struct.pack(
"<BBHBH",
0x6,
_MANUFACTURING_DATA_ADT,
_ADAFRUIT_COMPANY_ID,
struct.calcsize("<HI"),
_COLOR_DATA_ID,
)
manufacturer_data = LazyObjectField(
ManufacturerData,
"manufacturer_data",
advertising_data_type=_MANUFACTURING_DATA_ADT,
company_id=_ADAFRUIT_COMPANY_ID,
key_encoding="<H",
)
color = ManufacturerDataField(_COLOR_DATA_ID, "<I")
"""Color to broadcast as RGB integer."""
Loading

0 comments on commit 2052ff6

Please sign in to comment.