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

37 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-11 20:14 +0000

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

2 

3from __future__ import annotations 

4 

5from datetime import datetime 

6 

7import msgspec 

8 

9from .base_types import SIGInfo 

10from .gatt_enums import ValueType 

11 

12 

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

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

15 

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

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

18 

19 Attributes: 

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

21 reason: Human-readable description of why parsing failed 

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

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

24 

25 """ 

26 

27 field: str 

28 reason: str 

29 offset: int | None = None 

30 raw_slice: bytes | None = None 

31 

32 

33class DateData(msgspec.Struct, frozen=True, kw_only=True): 

34 """Shared data type for date values with year, month, and day fields.""" 

35 

36 year: int 

37 month: int 

38 day: int 

39 

40 def to_datetime(self) -> datetime: 

41 """Convert to Python datetime (time components set to 00:00:00). 

42 

43 Returns: 

44 datetime object with date components 

45 """ 

46 return datetime(self.year, self.month, self.day) 

47 

48 

49class CharacteristicInfo(SIGInfo): 

50 """Information about a Bluetooth characteristic from SIG/YAML specifications. 

51 

52 This contains only static metadata resolved from YAML or SIG specs. 

53 Runtime properties (read/write/notify capabilities) are stored separately 

54 on the BaseCharacteristic instance as they're discovered from the actual device. 

55 """ 

56 

57 value_type: ValueType = ValueType.UNKNOWN 

58 unit: str = "" 

59 

60 

61class ServiceInfo(SIGInfo): 

62 """Information about a Bluetooth service.""" 

63 

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

65 

66 

67class ValidationAccumulator: 

68 """Result of characteristic data validation with error/warning accumulation. 

69 

70 Used during parsing to accumulate validation issues from multiple validation steps. 

71 Provides methods to add errors/warnings and check overall validity. 

72 """ 

73 

74 def __init__(self) -> None: 

75 """Initialize empty validation result.""" 

76 self.errors: list[str] = [] 

77 self.warnings: list[str] = [] 

78 

79 def add_error(self, message: str) -> None: 

80 """Add a validation error message. 

81 

82 Args: 

83 message: Error message to add 

84 """ 

85 self.errors.append(message) 

86 

87 def add_warning(self, message: str) -> None: 

88 """Add a validation warning message. 

89 

90 Args: 

91 message: Warning message to add 

92 """ 

93 self.warnings.append(message) 

94 

95 @property 

96 def valid(self) -> bool: 

97 """Check if validation passed (no errors). 

98 

99 Returns: 

100 True if no errors, False otherwise 

101 """ 

102 return len(self.errors) == 0 

103 

104 

105class ValidationResult(msgspec.Struct, frozen=True, kw_only=True): 

106 """Summary of validation results for external API consumption. 

107 

108 Lightweight validation result for API responses, not for accumulation. 

109 """ 

110 

111 is_valid: bool 

112 actual_length: int 

113 expected_length: int | None = None 

114 error_message: str = ""