Coverage for src/bluetooth_sig/registry/browse_groups.py: 75%
48 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
1"""Browse group identifiers registry for Bluetooth SIG browse group identifiers."""
3from __future__ import annotations
5import msgspec
7from bluetooth_sig.registry.base import BaseRegistry
8from bluetooth_sig.registry.utils import find_bluetooth_sig_path, load_yaml_uuids, parse_bluetooth_uuid
9from bluetooth_sig.types.uuid import BluetoothUUID
12class BrowseGroupInfo(msgspec.Struct, frozen=True, kw_only=True):
13 """Information about a Bluetooth SIG browse group identifier."""
15 uuid: BluetoothUUID
16 name: str
17 id: str
20class BrowseGroupsRegistry(BaseRegistry[BrowseGroupInfo]):
21 """Registry for Bluetooth SIG browse group identifiers."""
23 def __init__(self) -> None:
24 """Initialize the browse groups registry."""
25 super().__init__()
26 self._browse_groups: dict[str, BrowseGroupInfo] = {}
27 self._name_to_info: dict[str, BrowseGroupInfo] = {}
28 self._id_to_info: dict[str, BrowseGroupInfo] = {}
29 self._load_browse_groups()
31 def _load_browse_groups(self) -> None:
32 """Load browse groups from the Bluetooth SIG YAML file."""
33 base_path = find_bluetooth_sig_path()
34 if not base_path:
35 return
37 # Load browse group UUIDs
38 browse_groups_yaml = base_path / "uuids" / "browse_group_identifiers.yaml"
39 if browse_groups_yaml.exists():
40 for item in load_yaml_uuids(browse_groups_yaml):
41 try:
42 uuid = parse_bluetooth_uuid(item["uuid"])
43 name = item["name"]
44 browse_group_id = item["id"]
46 info = BrowseGroupInfo(uuid=uuid, name=name, id=browse_group_id)
48 # Store by UUID string for fast lookup
49 self._browse_groups[uuid.short_form.upper()] = info
50 self._name_to_info[name.lower()] = info
51 self._id_to_info[browse_group_id] = info
53 except (KeyError, ValueError):
54 # Skip malformed entries
55 continue
57 def get_browse_group_info(self, uuid: str | int | BluetoothUUID) -> BrowseGroupInfo | None:
58 """Get browse group information by UUID.
60 Args:
61 uuid: The UUID to look up (string, int, or BluetoothUUID)
63 Returns:
64 BrowseGroupInfo if found, None otherwise
65 """
66 try:
67 bt_uuid = parse_bluetooth_uuid(uuid)
68 return self._browse_groups.get(bt_uuid.short_form.upper())
69 except ValueError:
70 return None
72 def get_browse_group_info_by_name(self, name: str) -> BrowseGroupInfo | None:
73 """Get browse group information by name (case insensitive).
75 Args:
76 name: The browse group name to look up
78 Returns:
79 BrowseGroupInfo if found, None otherwise
80 """
81 return self._name_to_info.get(name.lower())
83 def get_browse_group_info_by_id(self, browse_group_id: str) -> BrowseGroupInfo | None:
84 """Get browse group information by browse group ID.
86 Args:
87 browse_group_id: The browse group ID to look up
89 Returns:
90 BrowseGroupInfo if found, None otherwise
91 """
92 return self._id_to_info.get(browse_group_id)
94 def is_browse_group_uuid(self, uuid: str | int | BluetoothUUID) -> bool:
95 """Check if a UUID corresponds to a known browse group.
97 Args:
98 uuid: The UUID to check
100 Returns:
101 True if the UUID is a known browse group, False otherwise
102 """
103 return self.get_browse_group_info(uuid) is not None
105 def get_all_browse_groups(self) -> list[BrowseGroupInfo]:
106 """Get all browse groups in the registry.
108 Returns:
109 List of all BrowseGroupInfo objects
110 """
111 return list(self._browse_groups.values())
114# Global instance for convenience
115browse_groups_registry = BrowseGroupsRegistry.get_instance()