python 3.9 and 3.10 compatibility

This commit is contained in:
Gilles Boccon-Gibod
2025-08-30 12:07:08 -07:00
parent 116dc9b319
commit 91ba2f61f1
4 changed files with 33 additions and 10 deletions

View File

@@ -468,7 +468,7 @@ BT_HDP_SINK_SERVICE = UUID.from_16_bits(0x1402,
@dataclasses.dataclass @dataclasses.dataclass
class ClassOfDevice: class ClassOfDevice:
# fmt: off # fmt: off
class MajorServiceClasses(enum.IntFlag): class MajorServiceClasses(utils.CompatibleIntFlag):
LIMITED_DISCOVERABLE_MODE = (1 << 0) LIMITED_DISCOVERABLE_MODE = (1 << 0)
LE_AUDIO = (1 << 1) LE_AUDIO = (1 << 1)
POSITIONING = (1 << 3) POSITIONING = (1 << 3)
@@ -1647,7 +1647,7 @@ class AdvertisingData:
THREE_D_INFORMATION_DATA = 0x3D THREE_D_INFORMATION_DATA = 0x3D
MANUFACTURER_SPECIFIC_DATA = 0xFF MANUFACTURER_SPECIFIC_DATA = 0xFF
class Flags(enum.IntFlag): class Flags(utils.CompatibleIntFlag):
LE_LIMITED_DISCOVERABLE_MODE = 1 << 0 LE_LIMITED_DISCOVERABLE_MODE = 1 << 0
LE_GENERAL_DISCOVERABLE_MODE = 1 << 1 LE_GENERAL_DISCOVERABLE_MODE = 1 << 1
BR_EDR_NOT_SUPPORTED = 1 << 2 BR_EDR_NOT_SUPPORTED = 1 << 2
@@ -2153,7 +2153,7 @@ class LeRole(enum.IntEnum):
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Security Manager OOB Flag # Security Manager OOB Flag
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
class SecurityManagerOutOfBandFlag(enum.IntFlag): class SecurityManagerOutOfBandFlag(utils.CompatibleIntFlag):
""" """
See Supplement to the Bluetooth Core Specification, Part A See Supplement to the Bluetooth Core Specification, Part A
1.7 SECURITY MANAGER OUT OF BAND (OOB) 1.7 SECURITY MANAGER OUT OF BAND (OOB)

View File

@@ -25,7 +25,7 @@ from __future__ import annotations
import dataclasses import dataclasses
import math import math
import struct import struct
from typing import Any, ClassVar, Literal, Optional, TypeVar, Union, overload from typing import Any, ClassVar, Sequence
from typing_extensions import Self from typing_extensions import Self
@@ -70,7 +70,7 @@ class ListOfServiceUUIDs(core.DataType):
"""Base class for complete or incomplete lists of UUIDs.""" """Base class for complete or incomplete lists of UUIDs."""
_uuid_size: ClassVar[int] = 0 _uuid_size: ClassVar[int] = 0
uuids: list[core.UUID] uuids: Sequence[core.UUID]
@classmethod @classmethod
def from_bytes(cls, data: bytes) -> ListOfServiceUUIDs: def from_bytes(cls, data: bytes) -> ListOfServiceUUIDs:
@@ -215,7 +215,7 @@ class Flags(int, core.DataType):
return self.to_bytes(length=bytes_length, byteorder="little") return self.to_bytes(length=bytes_length, byteorder="little")
def value_string(self) -> str: def value_string(self) -> str:
return core.AdvertisingData.Flags(self).name or "" return core.AdvertisingData.Flags(self).composite_name
@dataclasses.dataclass @dataclasses.dataclass
@@ -293,6 +293,13 @@ class FixedSizeBytesDataType(bytes, core.DataType):
def __str__(self) -> str: def __str__(self) -> str:
return core.DataType.__str__(self) return core.DataType.__str__(self)
def __bytes__(self) -> bytes: # pylint: disable=E0308
# Python < 3.11 compatibility (before 3.11, the byte class does not have
# a __bytes__ method).
# Concatenate with an empty string to perform a direct conversion without
# calling bytes() explicity, which may cause an infinite recursion.
return b"" + self
class ClassOfDevice(core.ClassOfDevice, core.DataType): class ClassOfDevice(core.ClassOfDevice, core.DataType):
""" """
@@ -416,7 +423,7 @@ class SecurityManagerOutOfBandFlag(int, core.DataType):
return core.DataType.__str__(self) return core.DataType.__str__(self)
def value_string(self) -> str: def value_string(self) -> str:
return core.SecurityManagerOutOfBandFlag(self).name or "" return core.SecurityManagerOutOfBandFlag(self).composite_name
class SecurityManagerTKValue(FixedSizeBytesDataType): class SecurityManagerTKValue(FixedSizeBytesDataType):
@@ -751,7 +758,7 @@ class LeSupportedFeatures(int, core.DataType):
return self.to_bytes(length=bytes_length, byteorder="little") return self.to_bytes(length=bytes_length, byteorder="little")
def value_string(self) -> str: def value_string(self) -> str:
return hci.LeFeatureMask(self).name or "" return hci.LeFeatureMask(self).composite_name
@dataclasses.dataclass @dataclasses.dataclass

View File

@@ -1322,7 +1322,7 @@ class LeFeature(SpecableEnum):
MONITORING_ADVERTISERS = 64 MONITORING_ADVERTISERS = 64
FRAME_SPACE_UPDATE = 65 FRAME_SPACE_UPDATE = 65
class LeFeatureMask(enum.IntFlag): class LeFeatureMask(utils.CompatibleIntFlag):
LE_ENCRYPTION = 1 << LeFeature.LE_ENCRYPTION LE_ENCRYPTION = 1 << LeFeature.LE_ENCRYPTION
CONNECTION_PARAMETERS_REQUEST_PROCEDURE = 1 << LeFeature.CONNECTION_PARAMETERS_REQUEST_PROCEDURE CONNECTION_PARAMETERS_REQUEST_PROCEDURE = 1 << LeFeature.CONNECTION_PARAMETERS_REQUEST_PROCEDURE
EXTENDED_REJECT_INDICATION = 1 << LeFeature.EXTENDED_REJECT_INDICATION EXTENDED_REJECT_INDICATION = 1 << LeFeature.EXTENDED_REJECT_INDICATION
@@ -1463,7 +1463,7 @@ class LmpFeature(SpecableEnum):
SLOT_AVAILABILITY_MASK = 138 SLOT_AVAILABILITY_MASK = 138
TRAIN_NUDGING = 139 TRAIN_NUDGING = 139
class LmpFeatureMask(enum.IntFlag): class LmpFeatureMask(utils.CompatibleIntFlag):
# Page 0 (Legacy LMP features) # Page 0 (Legacy LMP features)
LMP_3_SLOT_PACKETS = (1 << LmpFeature.LMP_3_SLOT_PACKETS) LMP_3_SLOT_PACKETS = (1 << LmpFeature.LMP_3_SLOT_PACKETS)
LMP_5_SLOT_PACKETS = (1 << LmpFeature.LMP_5_SLOT_PACKETS) LMP_5_SLOT_PACKETS = (1 << LmpFeature.LMP_5_SLOT_PACKETS)

View File

@@ -500,6 +500,22 @@ class OpenIntEnum(enum.IntEnum):
return obj return obj
# -----------------------------------------------------------------------------
class CompatibleIntFlag(enum.IntFlag):
"""
Subclass of `enum.IntFlag` with a `composite_name` property that behaves like the
`name` property of the `enum.IntFlag` implementation for python vesions >= 3.11
"""
@property
def composite_name(self) -> str:
return '|'.join(
name
for flag in self.__class__
if self.value & flag.value and (name := flag.name) is not None
)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
class ByteSerializable(Protocol): class ByteSerializable(Protocol):
""" """