Coverage for src / bluetooth_sig / types / data_types.py: 95%
37 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-18 11:17 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-18 11:17 +0000
1"""Data types for Bluetooth SIG standards."""
3from __future__ import annotations
5from datetime import datetime
7import msgspec
9from .base_types import SIGInfo
12class ParseFieldError(msgspec.Struct, frozen=True, kw_only=True):
13 """Represents a field-level parsing error with diagnostic information.
15 This provides structured error information similar to Pydantic's validation
16 errors, making it easier to debug which specific field failed and why.
18 Attributes:
19 field: Name of the field that failed (e.g., "temperature", "flags")
20 reason: Human-readable description of why parsing failed
21 offset: Optional byte offset where the field starts in raw data
22 raw_slice: Optional raw bytes that were being parsed when error occurred
24 """
26 field: str
27 reason: str
28 offset: int | None = None
29 raw_slice: bytes | None = None
32class DateData(msgspec.Struct, frozen=True, kw_only=True):
33 """Shared data type for date values with year, month, and day fields."""
35 year: int
36 month: int
37 day: int
39 def to_datetime(self) -> datetime:
40 """Convert to Python datetime (time components set to 00:00:00).
42 Returns:
43 datetime object with date components
44 """
45 return datetime(self.year, self.month, self.day)
48class CharacteristicInfo(SIGInfo):
49 """Information about a Bluetooth characteristic from SIG/YAML specifications.
51 This contains only static metadata resolved from YAML or SIG specs.
52 Runtime properties (read/write/notify capabilities) are stored separately
53 on the BaseCharacteristic instance as they're discovered from the actual device.
54 """
56 python_type: type | str | None = None
57 is_bitfield: bool = False
58 unit: str = ""
61class ServiceInfo(SIGInfo):
62 """Information about a Bluetooth service."""
64 characteristics: list[CharacteristicInfo] = msgspec.field(default_factory=list[CharacteristicInfo])
67class ValidationAccumulator:
68 """Result of characteristic data validation with error/warning accumulation.
70 Used during parsing to accumulate validation issues from multiple validation steps.
71 Provides methods to add errors/warnings and check overall validity.
72 """
74 def __init__(self) -> None:
75 """Initialize empty validation result."""
76 self.errors: list[str] = []
77 self.warnings: list[str] = []
79 def add_error(self, message: str) -> None:
80 """Add a validation error message.
82 Args:
83 message: Error message to add
84 """
85 self.errors.append(message)
87 def add_warning(self, message: str) -> None:
88 """Add a validation warning message.
90 Args:
91 message: Warning message to add
92 """
93 self.warnings.append(message)
95 @property
96 def valid(self) -> bool:
97 """Check if validation passed (no errors).
99 Returns:
100 True if no errors, False otherwise
101 """
102 return len(self.errors) == 0
105class ValidationResult(msgspec.Struct, frozen=True, kw_only=True):
106 """Summary of validation results for external API consumption.
108 Lightweight validation result for API responses, not for accumulation.
109 """
111 is_valid: bool
112 actual_length: int
113 expected_length: int | None = None
114 error_message: str = ""