From b43d0877e70b5154696951f0d2ad1d66826cb6d7 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Tue, 29 Jun 2021 19:53:57 +0200 Subject: [PATCH] ESPHome Migrate to dataclasses (#52305) --- homeassistant/components/esphome/__init__.py | 2 +- .../components/esphome/entry_data.py | 56 ++++++++----------- .../components/esphome/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 5 files changed, 27 insertions(+), 37 deletions(-) diff --git a/homeassistant/components/esphome/__init__.py b/homeassistant/components/esphome/__init__.py index 2490c0bdbd3..b91197b019c 100644 --- a/homeassistant/components/esphome/__init__.py +++ b/homeassistant/components/esphome/__init__.py @@ -555,7 +555,7 @@ async def _register_service( "example": "['Example text', 'Another example']", "selector": {"object": {}}, }, - }[arg.type_] + }[arg.type] schema[vol.Required(arg.name)] = metadata["validator"] fields[arg.name] = { "name": arg.name, diff --git a/homeassistant/components/esphome/entry_data.py b/homeassistant/components/esphome/entry_data.py index 49655de8fb7..1e19780ed0b 100644 --- a/homeassistant/components/esphome/entry_data.py +++ b/homeassistant/components/esphome/entry_data.py @@ -2,6 +2,7 @@ from __future__ import annotations import asyncio +from dataclasses import dataclass, field from typing import TYPE_CHECKING, Any, Callable from aioesphomeapi import ( @@ -22,7 +23,6 @@ from aioesphomeapi import ( TextSensorInfo, UserService, ) -import attr from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback @@ -49,32 +49,31 @@ INFO_TYPE_TO_PLATFORM = { } -@attr.s +@dataclass class RuntimeEntryData: """Store runtime data for esphome config entries.""" - _storage_contents: dict | None = None - - entry_id: str = attr.ib() - client: APIClient = attr.ib() - store: Store = attr.ib() - state: dict[str, dict[str, Any]] = attr.ib(factory=dict) - info: dict[str, dict[str, Any]] = attr.ib(factory=dict) + entry_id: str + client: APIClient + store: Store + state: dict[str, dict[str, Any]] = field(default_factory=dict) + info: dict[str, dict[str, Any]] = field(default_factory=dict) # A second list of EntityInfo objects # This is necessary for when an entity is being removed. HA requires # some static info to be accessible during removal (unique_id, maybe others) # If an entity can't find anything in the info array, it will look for info here. - old_info: dict[str, dict[str, Any]] = attr.ib(factory=dict) + old_info: dict[str, dict[str, Any]] = field(default_factory=dict) - services: dict[int, UserService] = attr.ib(factory=dict) - available: bool = attr.ib(default=False) - device_info: DeviceInfo | None = attr.ib(default=None) - api_version: APIVersion = attr.ib(factory=APIVersion) - cleanup_callbacks: list[Callable[[], None]] = attr.ib(factory=list) - disconnect_callbacks: list[Callable[[], None]] = attr.ib(factory=list) - loaded_platforms: set[str] = attr.ib(factory=set) - platform_load_lock: asyncio.Lock = attr.ib(factory=asyncio.Lock) + services: dict[int, UserService] = field(default_factory=dict) + available: bool = False + device_info: DeviceInfo | None = None + api_version: APIVersion = field(default_factory=APIVersion) + cleanup_callbacks: list[Callable[[], None]] = field(default_factory=list) + disconnect_callbacks: list[Callable[[], None]] = field(default_factory=list) + loaded_platforms: set[str] = field(default_factory=set) + platform_load_lock: asyncio.Lock = field(default_factory=asyncio.Lock) + _storage_contents: dict | None = None @callback def async_update_entity( @@ -142,20 +141,15 @@ class RuntimeEntryData: return [], [] self._storage_contents = restored.copy() - self.device_info = _attr_obj_from_dict( - DeviceInfo, **restored.pop("device_info") - ) - self.api_version = _attr_obj_from_dict( - APIVersion, **restored.pop("api_version", {}) - ) - + self.device_info = DeviceInfo.from_dict(restored.pop("device_info")) + self.api_version = APIVersion.from_dict(restored.pop("api_version")) infos = [] for comp_type, restored_infos in restored.items(): if comp_type not in COMPONENT_TYPE_TO_INFO: continue for info in restored_infos: cls = COMPONENT_TYPE_TO_INFO[comp_type] - infos.append(_attr_obj_from_dict(cls, **info)) + infos.append(cls.from_dict(info)) services = [] for service in restored.get("services", []): services.append(UserService.from_dict(service)) @@ -164,13 +158,13 @@ class RuntimeEntryData: async def async_save_to_store(self) -> None: """Generate dynamic data to store and save it to the filesystem.""" store_data = { - "device_info": attr.asdict(self.device_info), + "device_info": self.device_info.to_dict(), "services": [], - "api_version": attr.asdict(self.api_version), + "api_version": self.api_version.to_dict(), } for comp_type, infos in self.info.items(): - store_data[comp_type] = [attr.asdict(info) for info in infos.values()] + store_data[comp_type] = [info.to_dict() for info in infos.values()] for service in self.services.values(): store_data["services"].append(service.to_dict()) @@ -182,7 +176,3 @@ class RuntimeEntryData: return store_data self.store.async_delay_save(_memorized_storage, SAVE_DELAY) - - -def _attr_obj_from_dict(cls, **kwargs): - return cls(**{key: kwargs[key] for key in attr.fields_dict(cls) if key in kwargs}) diff --git a/homeassistant/components/esphome/manifest.json b/homeassistant/components/esphome/manifest.json index 284fdc25956..e69299a4a43 100644 --- a/homeassistant/components/esphome/manifest.json +++ b/homeassistant/components/esphome/manifest.json @@ -3,7 +3,7 @@ "name": "ESPHome", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/esphome", - "requirements": ["aioesphomeapi==3.1.0"], + "requirements": ["aioesphomeapi==4.0.1"], "zeroconf": ["_esphomelib._tcp.local."], "codeowners": ["@OttoWinter", "@jesserockz"], "after_dependencies": ["zeroconf", "tag"], diff --git a/requirements_all.txt b/requirements_all.txt index 27d81dd8eec..6d5d1aee10b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -160,7 +160,7 @@ aioeafm==0.1.2 aioemonitor==1.0.5 # homeassistant.components.esphome -aioesphomeapi==3.1.0 +aioesphomeapi==4.0.1 # homeassistant.components.flo aioflo==0.4.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ff553882fe2..c60ff0d2eb0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -100,7 +100,7 @@ aioeafm==0.1.2 aioemonitor==1.0.5 # homeassistant.components.esphome -aioesphomeapi==3.1.0 +aioesphomeapi==4.0.1 # homeassistant.components.flo aioflo==0.4.1