Skip to content

Type annotations #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions adafruit_bluefruit_connect/_xyz_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

"""

from __future__ import annotations

import struct

from .packet import Packet
Expand All @@ -20,37 +22,37 @@
class _XYZPacket(Packet):
"""A packet of x, y, z float values. Used for several different Bluefruit controller packets."""

_FMT_PARSE = "<xxfffx"
PACKET_LENGTH = struct.calcsize(_FMT_PARSE)
_FMT_PARSE: str = "<xxfffx"
PACKET_LENGTH: int = struct.calcsize(_FMT_PARSE)
# _FMT_CONSTRUCT doesn't include the trailing checksum byte.
_FMT_CONSTRUCT = "<2sfff"
_FMT_CONSTRUCT: str = "<2sfff"
# _TYPE_HEADER is set by each concrete subclass.

def __init__(self, x, y, z):
def __init__(self, x: float, y: float, z: float) -> None:
# Construct an _XYZPacket subclass object
# from the given x, y, and z float values, and type character.
self._x = x
self._y = y
self._z = z

def to_bytes(self):
def to_bytes(self) -> bytes:
"""Return the bytes needed to send this packet."""
partial_packet = struct.pack(
self._FMT_CONSTRUCT, self._TYPE_HEADER, self._x, self._y, self._z
)
return self.add_checksum(partial_packet)

@property
def x(self):
def x(self) -> float:
"""The x value."""
return self._x

@property
def y(self):
def y(self) -> float:
"""The y value."""
return self._y

@property
def z(self):
def z(self) -> float:
"""The z value."""
return self._z
4 changes: 3 additions & 1 deletion adafruit_bluefruit_connect/accelerometer_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@

"""

from __future__ import annotations

from ._xyz_packet import _XYZPacket


class AccelerometerPacket(_XYZPacket):
"""A packet of x, y, z float values from an accelerometer."""

# Everything else is handled by _XYZPacket.
_TYPE_HEADER = b"!A"
_TYPE_HEADER: bytes = b"!A"


# Register this class with the superclass. This allows the user to import only what is needed.
Expand Down
47 changes: 27 additions & 20 deletions adafruit_bluefruit_connect/button_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,46 @@

"""

from __future__ import annotations

import struct

from .packet import Packet

try:
from typing import Optional # adjust these as needed
except ImportError:
pass


class ButtonPacket(Packet):
"""A packet containing a button name and its state."""

BUTTON_1 = "1"
BUTTON_1: str = "1"
"""Code for Button 1 on the Bluefruit LE Connect app Control Pad screen."""
BUTTON_2 = "2"
BUTTON_2: str = "2"
"""Button 2."""
BUTTON_3 = "3"
BUTTON_3: str = "3"
"""Button 3."""
BUTTON_4 = "4"
BUTTON_4: str = "4"
"""Button 4."""
# pylint: disable= invalid-name
UP = "5"
UP: str = "5"
"""Up Button."""
DOWN = "6"
DOWN: str = "6"
"""Down Button."""
LEFT = "7"
LEFT: str = "7"
"""Left Button."""
RIGHT = "8"
RIGHT: str = "8"
"""Right Button."""

_FMT_PARSE = "<xxssx"
PACKET_LENGTH = struct.calcsize(_FMT_PARSE)
_FMT_PARSE: str = "<xxssx"
PACKET_LENGTH: int = struct.calcsize(_FMT_PARSE)
# _FMT_CONSTRUCT doesn't include the trailing checksum byte.
_FMT_CONSTRUCT = "<2sss"
_TYPE_HEADER = b"!B"
_FMT_CONSTRUCT: str = "<2sss"
_TYPE_HEADER: bytes = b"!B"

def __init__(self, button, pressed):
def __init__(self, button: str, pressed: bool) -> None:
"""Construct a ButtonPacket from a button name and the button's state.

:param str button: a single character denoting the button
Expand All @@ -59,11 +66,11 @@ def __init__(self, button, pressed):
except Exception as err:
raise ValueError("Button must be a single char.") from err

self._button = button
self._pressed = pressed
self._button: str = button
self._pressed: bool = pressed

@classmethod
def parse_private(cls, packet):
def parse_private(cls, packet: bytes) -> Optional[Packet]:
"""Construct a ButtonPacket from an incoming packet.
Do not call this directly; call Packet.from_bytes() instead.
pylint makes it difficult to call this method _parse(), hence the name.
Expand All @@ -73,9 +80,9 @@ def parse_private(cls, packet):
raise ValueError("Bad button press/release value")
return cls(chr(button[0]), pressed == b"1")

def to_bytes(self):
def to_bytes(self) -> bytes:
"""Return the bytes needed to send this packet."""
partial_packet = struct.pack(
partial_packet: bytes = struct.pack(
self._FMT_CONSTRUCT,
self._TYPE_HEADER,
bytes(self._button, "utf-8"),
Expand All @@ -84,13 +91,13 @@ def to_bytes(self):
return self.add_checksum(partial_packet)

@property
def button(self):
def button(self) -> str:
"""A single character string (not bytes) specifying the button that
the user pressed or released."""
return self._button

@property
def pressed(self):
def pressed(self) -> bool:
"""``True`` if button is pressed, or ``False`` if it is released."""
return self._pressed

Expand Down
25 changes: 16 additions & 9 deletions adafruit_bluefruit_connect/color_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,58 @@

"""

from __future__ import annotations

import struct

from .packet import Packet

try:
from typing import Optional, Tuple # adjust these as needed
except ImportError:
pass


class ColorPacket(Packet):
"""A packet containing an RGB color value."""

_FMT_PARSE = "<xx3Bx"
PACKET_LENGTH = struct.calcsize(_FMT_PARSE)
_FMT_PARSE: str = "<xx3Bx"
PACKET_LENGTH: int = struct.calcsize(_FMT_PARSE)
# _FMT_CONSTRUCT doesn't include the trailing checksum byte.
_FMT_CONSTRUCT = "<2s3B"
_TYPE_HEADER = b"!C"
_FMT_CONSTRUCT: str = "<2s3B"
_TYPE_HEADER: bytes = b"!C"

def __init__(self, color):
def __init__(self, color: Tuple) -> None:
"""Construct a ColorPacket from a 3-element :class:`tuple` of RGB
values, or from an int color value 0xRRGGBB.

:param tuple/int color: an RGB :class:`tuple` ``(red, green, blue)``
or an int color value ``0xRRGGBB``
"""
if isinstance(color, int):
self._color = tuple(color.to_bytes(3, "big"))
self._color: Tuple = tuple(color.to_bytes(3, "big"))
elif len(color) == 3 and all(0 <= c <= 255 for c in color):
self._color = color
else:
raise ValueError("Color must be an integer 0xRRGGBB or a tuple(r,g,b)")

@classmethod
def parse_private(cls, packet):
def parse_private(cls, packet: bytes) -> Optional[Packet]:
"""Construct a ColorPacket from an incoming packet.
Do not call this directly; call Packet.from_bytes() instead.
pylint makes it difficult to call this method _parse(), hence the name.
"""
return cls(struct.unpack(cls._FMT_PARSE, packet))

def to_bytes(self):
def to_bytes(self) -> bytes:
"""Return the bytes needed to send this packet."""
partial_packet = struct.pack(
self._FMT_CONSTRUCT, self._TYPE_HEADER, *self._color
)
return self.add_checksum(partial_packet)

@property
def color(self):
def color(self) -> tuple:
"""A :class:`tuple` ``(red, green blue)`` representing the color the
user chose in the BlueFruit Connect app."""
return self._color
Expand Down
4 changes: 3 additions & 1 deletion adafruit_bluefruit_connect/gyro_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@

"""

from __future__ import annotations

from ._xyz_packet import _XYZPacket


class GyroPacket(_XYZPacket):
"""A packet of x, y, z float values from a gyroscope."""

# Everything else is handled by _XYZPacket.
_TYPE_HEADER = b"!G"
_TYPE_HEADER: bytes = b"!G"


# Register this class with the superclass. This allows the user to import only what is needed.
Expand Down
20 changes: 11 additions & 9 deletions adafruit_bluefruit_connect/location_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

"""

from __future__ import annotations

import struct

from .packet import Packet
Expand All @@ -20,19 +22,19 @@
class LocationPacket(Packet):
"""A packet of latitude, longitude, and altitude values."""

_FMT_PARSE = "<xxfffx"
PACKET_LENGTH = struct.calcsize(_FMT_PARSE)
_FMT_PARSE: str = "<xxfffx"
PACKET_LENGTH: int = struct.calcsize(_FMT_PARSE)
# _FMT_CONSTRUCT doesn't include the trailing checksum byte.
_FMT_CONSTRUCT = "<2sfff"
_TYPE_HEADER = b"!L"
_FMT_CONSTRUCT: str = "<2sfff"
_TYPE_HEADER: bytes = b"!L"

def __init__(self, latitude, longitude, altitude):
def __init__(self, latitude: float, longitude: float, altitude: float) -> None:
"""Construct a LocationPacket from the given values."""
self._latitude = latitude
self._longitude = longitude
self._altitude = altitude

def to_bytes(self):
def to_bytes(self) -> bytes:
"""Return the bytes needed to send this packet."""
partial_packet = struct.pack(
self._FMT_CONSTRUCT,
Expand All @@ -44,17 +46,17 @@ def to_bytes(self):
return self.add_checksum(partial_packet)

@property
def latitude(self):
def latitude(self) -> float:
"""The latitude value."""
return self._latitude

@property
def longitude(self):
def longitude(self) -> float:
"""The longitude value."""
return self._longitude

@property
def altitude(self):
def altitude(self) -> float:
"""The altitude value."""
return self._altitude

Expand Down
4 changes: 3 additions & 1 deletion adafruit_bluefruit_connect/magnetometer_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@

"""

from __future__ import annotations

from ._xyz_packet import _XYZPacket


class MagnetometerPacket(_XYZPacket):
"""A packet of x, y, z float values from a magnetometer."""

# Everything else is handled by _XYZPacket.
_TYPE_HEADER = b"!M"
_TYPE_HEADER: bytes = b"!M"


# Register this class with the superclass. This allows the user to import only what is needed.
Expand Down
Loading