From dac6370145539e76f7920f286cdf68e9e0d19100 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 25 Jan 2025 22:57:58 -0800 Subject: [PATCH 1/3] Update approach to looking up SystemObject choices --- .../config_client/interfaces/types.py | 37 +++++++------------ src/aiovantage/objects/system_object.py | 7 ++-- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/aiovantage/config_client/interfaces/types.py b/src/aiovantage/config_client/interfaces/types.py index 5e837c49..4ca08314 100644 --- a/src/aiovantage/config_client/interfaces/types.py +++ b/src/aiovantage/config_client/interfaces/types.py @@ -1,36 +1,25 @@ """ObjectChoice type definition.""" -import inspect from dataclasses import dataclass, field from functools import cache -from types import ModuleType -from typing import Any +from importlib import import_module +from inspect import getmembers, isclass -from aiovantage import objects - - -def get_all_module_classes(module: ModuleType) -> list[type[Any]]: - """Get all classes from a module.""" - classes: list[type[Any]] = [] - for _, cls in inspect.getmembers(module, inspect.isclass): - classes.append(cls) - - return classes +from aiovantage.objects import SystemObject @cache -def get_all_object_choices(module: ModuleType) -> list[dict[str, Any]]: +def get_all_object_choices() -> list[dict[str, str | type[SystemObject]]]: """Get all object choices from a module.""" - choices: list[dict[str, Any]] = [] - for cls in get_all_module_classes(module): - # Get the name of the XML element - meta = getattr(cls, "Meta", None) - name = getattr(meta, "name", cls.__qualname__) - - # Add the xsdata choice - choices.append({"name": name, "type": cls}) + # Load all SystemObject types into memory + module = import_module("aiovantage.objects") - return choices + # Build and return choices list + return [ + {"name": cls.vantage_type(), "type": cls} + for _, cls in getmembers(module, isclass) + if issubclass(cls, SystemObject) + ] @dataclass @@ -47,6 +36,6 @@ class ObjectChoice: choice: object = field( metadata={ "type": "Wildcard", - "choices": get_all_object_choices(objects), # type: ignore + "choices": get_all_object_choices(), }, ) diff --git a/src/aiovantage/objects/system_object.py b/src/aiovantage/objects/system_object.py index e6c67ae3..8ff05722 100644 --- a/src/aiovantage/objects/system_object.py +++ b/src/aiovantage/objects/system_object.py @@ -58,9 +58,8 @@ class SystemObject: }, ) - @property - def vantage_type(self) -> str: - """Return the Vantage type of the object.""" - cls = type(self) + @classmethod + def vantage_type(cls) -> str: + """Return the Vantage type for this object.""" cls_meta = getattr(cls, "Meta", None) return getattr(cls_meta, "name", cls.__qualname__) From c143528e7f70c6aae7f45f448075db9b3a0d9e1b Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 25 Jan 2025 22:58:32 -0800 Subject: [PATCH 2/3] Remove event stream connection, rely on lazy connection --- src/aiovantage/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/aiovantage/__init__.py b/src/aiovantage/__init__.py index 5e2dac52..3f9abcf6 100644 --- a/src/aiovantage/__init__.py +++ b/src/aiovantage/__init__.py @@ -286,9 +286,6 @@ async def initialize(self, fetch_state: bool = True) -> None: *[controller.initialize(fetch_state) for controller in self._controllers] ) - # Start the event stream - await self.event_stream.start() - def subscribe(self, callback: EventCallback[SystemObject]) -> Callable[[], None]: """Subscribe to state changes for all objects. From 14d23dd74d186588304d755ca79cb3e7f5f3c78c Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 25 Jan 2025 22:58:47 -0800 Subject: [PATCH 3/3] Minor typing issues --- src/aiovantage/command_client/commands.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/aiovantage/command_client/commands.py b/src/aiovantage/command_client/commands.py index 0b282633..658d8db5 100644 --- a/src/aiovantage/command_client/commands.py +++ b/src/aiovantage/command_client/commands.py @@ -3,11 +3,10 @@ import asyncio import logging import re -from collections.abc import Sequence from dataclasses import dataclass -from decimal import Decimal from ssl import SSLContext from types import TracebackType +from typing import Any from typing_extensions import Self @@ -29,8 +28,8 @@ class CommandResponse: """Wrapper for command responses.""" command: str - args: Sequence[str] - data: Sequence[str] + args: list[str] + data: list[str] class CommandClient: @@ -78,7 +77,7 @@ def close(self) -> None: async def command( self, command: str, - *params: str | int | float | Decimal, + *params: Any, force_quotes: bool = False, connection: CommandConnection | None = None, ) -> CommandResponse: @@ -112,7 +111,7 @@ async def command( async def raw_request( self, request: str, connection: CommandConnection | None = None - ) -> Sequence[str]: + ) -> list[str]: """Send a raw command to the Host Command service and return all response lines. Handles authentication if required, and raises an exception if the response line