Coverage for src/bluetooth_sig/types/data_types.py: 100%

58 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-30 00:10 +0000

1"""Data types for Bluetooth SIG standards.""" 

2 

3from __future__ import annotations 

4 

5from typing import Any 

6 

7import msgspec 

8 

9from .base_types import SIGInfo 

10from .context import CharacteristicContext 

11from .descriptor_types import DescriptorData 

12from .gatt_enums import GattProperty, ValueType 

13from .uuid import BluetoothUUID 

14 

15 

16class ParseFieldError(msgspec.Struct, frozen=True, kw_only=True): 

17 """Represents a field-level parsing error with diagnostic information. 

18 

19 This provides structured error information similar to Pydantic's validation 

20 errors, making it easier to debug which specific field failed and why. 

21 

22 Attributes: 

23 field: Name of the field that failed (e.g., "temperature", "flags") 

24 reason: Human-readable description of why parsing failed 

25 offset: Optional byte offset where the field starts in raw data 

26 raw_slice: Optional raw bytes that were being parsed when error occurred 

27 

28 """ 

29 

30 field: str 

31 reason: str 

32 offset: int | None = None 

33 raw_slice: bytes | None = None 

34 

35 

36class CharacteristicInfo(SIGInfo): 

37 """Information about a Bluetooth characteristic.""" 

38 

39 value_type: ValueType = ValueType.UNKNOWN 

40 unit: str = "" 

41 properties: list[GattProperty] = msgspec.field(default_factory=list) 

42 

43 

44class ServiceInfo(SIGInfo): 

45 """Information about a Bluetooth service.""" 

46 

47 characteristics: list[CharacteristicInfo] = msgspec.field(default_factory=list) 

48 

49 

50class CharacteristicData(msgspec.Struct, kw_only=True): 

51 """Parsed characteristic data with validation results. 

52 

53 Provides structured error reporting with field-level diagnostics and parse traces 

54 to help identify exactly where and why parsing failed. 

55 

56 NOTE: This struct intentionally has more attributes than the standard limit 

57 to provide complete diagnostic information. The additional fields (field_errors, 

58 parse_trace) are essential for actionable error reporting and debugging. 

59 """ 

60 

61 info: CharacteristicInfo 

62 value: Any | None = None 

63 raw_data: bytes = b"" 

64 parse_success: bool = False 

65 error_message: str = "" 

66 source_context: CharacteristicContext = msgspec.field(default_factory=CharacteristicContext) 

67 field_errors: list[ParseFieldError] = msgspec.field(default_factory=list) 

68 parse_trace: list[str] = msgspec.field(default_factory=list) 

69 descriptors: dict[str, DescriptorData] = msgspec.field(default_factory=dict) 

70 

71 @property 

72 def name(self) -> str: 

73 """Get the characteristic name from info.""" 

74 return self.info.name 

75 

76 @property 

77 def properties(self) -> list[GattProperty]: 

78 """Get the properties as strings for protocol compatibility.""" 

79 return self.info.properties 

80 

81 @property 

82 def uuid(self) -> BluetoothUUID: 

83 """Get the characteristic UUID from info.""" 

84 return self.info.uuid 

85 

86 @property 

87 def unit(self) -> str: 

88 """Get the characteristic unit from info.""" 

89 return self.info.unit 

90 

91 

92class ValidationResult(SIGInfo): 

93 """Result of data validation.""" 

94 

95 is_valid: bool = True 

96 expected_length: int | None = None 

97 actual_length: int | None = None 

98 error_message: str = "" 

99 

100 

101class CharacteristicRegistration(msgspec.Struct, kw_only=True): 

102 """Unified metadata for custom UUID registration.""" 

103 

104 uuid: BluetoothUUID 

105 name: str = "" 

106 id: str | None = None 

107 summary: str = "" 

108 unit: str = "" 

109 value_type: ValueType = ValueType.STRING 

110 

111 

112class ServiceRegistration(msgspec.Struct, kw_only=True): 

113 """Unified metadata for custom UUID registration.""" 

114 

115 uuid: BluetoothUUID 

116 name: str = "" 

117 id: str | None = None 

118 summary: str = ""