From 775be354a6935394013094835c999f015a85b8c7 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Fri, 20 May 2022 07:47:18 -0700 Subject: [PATCH] Cleanup nest async methods that do not need to actually await (#72170) Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> --- homeassistant/components/nest/__init__.py | 9 ++++-- homeassistant/components/nest/camera_sdm.py | 14 +++------ homeassistant/components/nest/climate_sdm.py | 12 ++------ homeassistant/components/nest/const.py | 1 + .../components/nest/device_trigger.py | 13 ++++---- homeassistant/components/nest/diagnostics.py | 27 +++++++---------- homeassistant/components/nest/media_source.py | 21 ++++++------- homeassistant/components/nest/sensor_sdm.py | 13 ++------ tests/components/nest/test_diagnostics.py | 30 +------------------ 9 files changed, 43 insertions(+), 97 deletions(-) diff --git a/homeassistant/components/nest/__init__.py b/homeassistant/components/nest/__init__.py index 7d8353738ff..0920b37e6ef 100644 --- a/homeassistant/components/nest/__init__.py +++ b/homeassistant/components/nest/__init__.py @@ -54,6 +54,7 @@ from . import api, config_flow from .const import ( CONF_PROJECT_ID, CONF_SUBSCRIBER_ID, + DATA_DEVICE_MANAGER, DATA_NEST_CONFIG, DATA_SDM, DATA_SUBSCRIBER, @@ -63,8 +64,8 @@ from .events import EVENT_NAME_MAP, NEST_EVENT from .legacy import async_setup_legacy, async_setup_legacy_entry from .media_source import ( async_get_media_event_store, + async_get_media_source_devices, async_get_transcoder, - get_media_source_devices, ) _LOGGER = logging.getLogger(__name__) @@ -205,7 +206,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: raise ConfigEntryNotReady from err try: - await subscriber.async_get_device_manager() + device_manager = await subscriber.async_get_device_manager() except ApiException as err: if DATA_NEST_UNAVAILABLE not in hass.data[DOMAIN]: _LOGGER.error("Device manager error: %s", err) @@ -215,6 +216,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN].pop(DATA_NEST_UNAVAILABLE, None) hass.data[DOMAIN][DATA_SUBSCRIBER] = subscriber + hass.data[DOMAIN][DATA_DEVICE_MANAGER] = device_manager hass.config_entries.async_setup_platforms(entry, PLATFORMS) @@ -232,6 +234,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) if unload_ok: hass.data[DOMAIN].pop(DATA_SUBSCRIBER) + hass.data[DOMAIN].pop(DATA_DEVICE_MANAGER) hass.data[DOMAIN].pop(DATA_NEST_UNAVAILABLE, None) return unload_ok @@ -275,7 +278,7 @@ class NestEventViewBase(HomeAssistantView, ABC): if not user.permissions.check_entity(entry.entity_id, POLICY_READ): raise Unauthorized(entity_id=entry.entity_id) - devices = await get_media_source_devices(self.hass) + devices = async_get_media_source_devices(self.hass) if not (nest_device := devices.get(device_id)): return self._json_error( f"No Nest Device found for '{device_id}'", HTTPStatus.NOT_FOUND diff --git a/homeassistant/components/nest/camera_sdm.py b/homeassistant/components/nest/camera_sdm.py index a46af2979f4..6e14100e881 100644 --- a/homeassistant/components/nest/camera_sdm.py +++ b/homeassistant/components/nest/camera_sdm.py @@ -15,19 +15,20 @@ from google_nest_sdm.camera_traits import ( StreamingProtocol, ) from google_nest_sdm.device import Device +from google_nest_sdm.device_manager import DeviceManager from google_nest_sdm.exceptions import ApiException from homeassistant.components.camera import Camera, CameraEntityFeature from homeassistant.components.camera.const import StreamType from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.exceptions import HomeAssistantError, PlatformNotReady +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.util.dt import utcnow -from .const import DATA_SUBSCRIBER, DOMAIN +from .const import DATA_DEVICE_MANAGER, DOMAIN from .device_info import NestDeviceInfo _LOGGER = logging.getLogger(__name__) @@ -43,14 +44,7 @@ async def async_setup_sdm_entry( ) -> None: """Set up the cameras.""" - subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] - try: - device_manager = await subscriber.async_get_device_manager() - except ApiException as err: - raise PlatformNotReady from err - - # Fetch initial data so we have data when entities subscribe. - + device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER] entities = [] for device in device_manager.devices.values(): if ( diff --git a/homeassistant/components/nest/climate_sdm.py b/homeassistant/components/nest/climate_sdm.py index 89048b9f624..bbbf83501f7 100644 --- a/homeassistant/components/nest/climate_sdm.py +++ b/homeassistant/components/nest/climate_sdm.py @@ -4,8 +4,8 @@ from __future__ import annotations from typing import Any, cast from google_nest_sdm.device import Device +from google_nest_sdm.device_manager import DeviceManager from google_nest_sdm.device_traits import FanTrait, TemperatureTrait -from google_nest_sdm.exceptions import ApiException from google_nest_sdm.thermostat_traits import ( ThermostatEcoTrait, ThermostatHeatCoolTrait, @@ -30,11 +30,10 @@ from homeassistant.components.climate.const import ( from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.core import HomeAssistant -from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .const import DATA_SUBSCRIBER, DOMAIN +from .const import DATA_DEVICE_MANAGER, DOMAIN from .device_info import NestDeviceInfo # Mapping for sdm.devices.traits.ThermostatMode mode field @@ -80,12 +79,7 @@ async def async_setup_sdm_entry( ) -> None: """Set up the client entities.""" - subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] - try: - device_manager = await subscriber.async_get_device_manager() - except ApiException as err: - raise PlatformNotReady from err - + device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER] entities = [] for device in device_manager.devices.values(): if ThermostatHvacTrait.NAME in device.traits: diff --git a/homeassistant/components/nest/const.py b/homeassistant/components/nest/const.py index 7aabcfe8d77..bd951756eae 100644 --- a/homeassistant/components/nest/const.py +++ b/homeassistant/components/nest/const.py @@ -3,6 +3,7 @@ DOMAIN = "nest" DATA_SDM = "sdm" DATA_SUBSCRIBER = "subscriber" +DATA_DEVICE_MANAGER = "device_manager" DATA_NEST_CONFIG = "nest_config" WEB_AUTH_DOMAIN = DOMAIN diff --git a/homeassistant/components/nest/device_trigger.py b/homeassistant/components/nest/device_trigger.py index 9078f97f135..e2f4288d122 100644 --- a/homeassistant/components/nest/device_trigger.py +++ b/homeassistant/components/nest/device_trigger.py @@ -1,6 +1,7 @@ """Provides device automations for Nest.""" from __future__ import annotations +from google_nest_sdm.device_manager import DeviceManager import voluptuous as vol from homeassistant.components.automation import ( @@ -20,7 +21,7 @@ from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback from homeassistant.helpers import device_registry as dr from homeassistant.helpers.typing import ConfigType -from .const import DATA_SUBSCRIBER, DOMAIN +from .const import DATA_DEVICE_MANAGER, DOMAIN from .events import DEVICE_TRAIT_TRIGGER_MAP, NEST_EVENT DEVICE = "device" @@ -45,14 +46,12 @@ def async_get_nest_device_id(hass: HomeAssistant, device_id: str) -> str | None: return None -async def async_get_device_trigger_types( +@callback +def async_get_device_trigger_types( hass: HomeAssistant, nest_device_id: str ) -> list[str]: """List event triggers supported for a Nest device.""" - # All devices should have already been loaded so any failures here are - # "shouldn't happen" cases - subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] - device_manager = await subscriber.async_get_device_manager() + device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER] if not (nest_device := device_manager.devices.get(nest_device_id)): raise InvalidDeviceAutomationConfig(f"Nest device not found {nest_device_id}") @@ -72,7 +71,7 @@ async def async_get_triggers( nest_device_id = async_get_nest_device_id(hass, device_id) if not nest_device_id: raise InvalidDeviceAutomationConfig(f"Device not found {device_id}") - trigger_types = await async_get_device_trigger_types(hass, nest_device_id) + trigger_types = async_get_device_trigger_types(hass, nest_device_id) return [ { CONF_PLATFORM: DEVICE, diff --git a/homeassistant/components/nest/diagnostics.py b/homeassistant/components/nest/diagnostics.py index d178d52393e..c21842d5939 100644 --- a/homeassistant/components/nest/diagnostics.py +++ b/homeassistant/components/nest/diagnostics.py @@ -6,43 +6,39 @@ from typing import Any from google_nest_sdm import diagnostics from google_nest_sdm.device import Device +from google_nest_sdm.device_manager import DeviceManager from google_nest_sdm.device_traits import InfoTrait -from google_nest_sdm.exceptions import ApiException from homeassistant.components.camera import diagnostics as camera_diagnostics from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.device_registry import DeviceEntry -from .const import DATA_SDM, DATA_SUBSCRIBER, DOMAIN +from .const import DATA_DEVICE_MANAGER, DATA_SDM, DOMAIN REDACT_DEVICE_TRAITS = {InfoTrait.NAME} -async def _get_nest_devices( +@callback +def _async_get_nest_devices( hass: HomeAssistant, config_entry: ConfigEntry ) -> dict[str, Device]: """Return dict of available devices.""" if DATA_SDM not in config_entry.data: return {} - if DATA_SUBSCRIBER not in hass.data[DOMAIN]: + if DATA_DEVICE_MANAGER not in hass.data[DOMAIN]: return {} - subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] - device_manager = await subscriber.async_get_device_manager() - devices: dict[str, Device] = device_manager.devices - return devices + device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER] + return device_manager.devices async def async_get_config_entry_diagnostics( hass: HomeAssistant, config_entry: ConfigEntry ) -> dict: """Return diagnostics for a config entry.""" - try: - nest_devices = await _get_nest_devices(hass, config_entry) - except ApiException as err: - return {"error": str(err)} + nest_devices = _async_get_nest_devices(hass, config_entry) if not nest_devices: return {} data: dict[str, Any] = { @@ -65,10 +61,7 @@ async def async_get_device_diagnostics( device: DeviceEntry, ) -> dict: """Return diagnostics for a device.""" - try: - nest_devices = await _get_nest_devices(hass, config_entry) - except ApiException as err: - return {"error": str(err)} + nest_devices = _async_get_nest_devices(hass, config_entry) nest_device_id = next(iter(device.identifiers))[1] nest_device = nest_devices.get(nest_device_id) return nest_device.get_diagnostics() if nest_device else {} diff --git a/homeassistant/components/nest/media_source.py b/homeassistant/components/nest/media_source.py index 7a8ae49bdbc..e4e26153b3a 100644 --- a/homeassistant/components/nest/media_source.py +++ b/homeassistant/components/nest/media_source.py @@ -25,6 +25,7 @@ import os from google_nest_sdm.camera_traits import CameraClipPreviewTrait, CameraEventImageTrait from google_nest_sdm.device import Device +from google_nest_sdm.device_manager import DeviceManager from google_nest_sdm.event import EventImageType, ImageEventBase from google_nest_sdm.event_media import ( ClipPreviewSession, @@ -50,13 +51,13 @@ from homeassistant.components.media_source.models import ( MediaSourceItem, PlayMedia, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import device_registry as dr from homeassistant.helpers.storage import Store from homeassistant.helpers.template import DATE_STR_FORMAT from homeassistant.util import dt as dt_util -from .const import DATA_SUBSCRIBER, DOMAIN +from .const import DATA_DEVICE_MANAGER, DOMAIN from .device_info import NestDeviceInfo from .events import EVENT_NAME_MAP, MEDIA_SOURCE_EVENT_TITLE_MAP @@ -267,13 +268,13 @@ async def async_get_media_source(hass: HomeAssistant) -> MediaSource: return NestMediaSource(hass) -async def get_media_source_devices(hass: HomeAssistant) -> Mapping[str, Device]: +@callback +def async_get_media_source_devices(hass: HomeAssistant) -> Mapping[str, Device]: """Return a mapping of device id to eligible Nest event media devices.""" - if DATA_SUBSCRIBER not in hass.data[DOMAIN]: + if DATA_DEVICE_MANAGER not in hass.data[DOMAIN]: # Integration unloaded, or is legacy nest integration return {} - subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] - device_manager = await subscriber.async_get_device_manager() + device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER] device_registry = dr.async_get(hass) devices = {} for device in device_manager.devices.values(): @@ -339,7 +340,7 @@ class NestMediaSource(MediaSource): media_id: MediaId | None = parse_media_id(item.identifier) if not media_id: raise Unresolvable("No identifier specified for MediaSourceItem") - devices = await self.devices() + devices = async_get_media_source_devices(self.hass) if not (device := devices.get(media_id.device_id)): raise Unresolvable( "Unable to find device with identifier: %s" % item.identifier @@ -376,7 +377,7 @@ class NestMediaSource(MediaSource): _LOGGER.debug( "Browsing media for identifier=%s, media_id=%s", item.identifier, media_id ) - devices = await self.devices() + devices = async_get_media_source_devices(self.hass) if media_id is None: # Browse the root and return child devices browse_root = _browse_root() @@ -443,10 +444,6 @@ class NestMediaSource(MediaSource): ) return _browse_image_event(media_id, device, single_image) - async def devices(self) -> Mapping[str, Device]: - """Return all event media related devices.""" - return await get_media_source_devices(self.hass) - async def _async_get_clip_preview_sessions( device: Device, diff --git a/homeassistant/components/nest/sensor_sdm.py b/homeassistant/components/nest/sensor_sdm.py index b9c13f6b9c7..d33aa3eff8b 100644 --- a/homeassistant/components/nest/sensor_sdm.py +++ b/homeassistant/components/nest/sensor_sdm.py @@ -4,8 +4,8 @@ from __future__ import annotations import logging from google_nest_sdm.device import Device +from google_nest_sdm.device_manager import DeviceManager from google_nest_sdm.device_traits import HumidityTrait, TemperatureTrait -from google_nest_sdm.exceptions import ApiException from homeassistant.components.sensor import ( SensorDeviceClass, @@ -15,10 +15,9 @@ from homeassistant.components.sensor import ( from homeassistant.config_entries import ConfigEntry from homeassistant.const import PERCENTAGE, TEMP_CELSIUS from homeassistant.core import HomeAssistant -from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .const import DATA_SUBSCRIBER, DOMAIN +from .const import DATA_DEVICE_MANAGER, DOMAIN from .device_info import NestDeviceInfo _LOGGER = logging.getLogger(__name__) @@ -37,13 +36,7 @@ async def async_setup_sdm_entry( ) -> None: """Set up the sensors.""" - subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] - try: - device_manager = await subscriber.async_get_device_manager() - except ApiException as err: - _LOGGER.warning("Failed to get devices: %s", err) - raise PlatformNotReady from err - + device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER] entities: list[SensorEntity] = [] for device in device_manager.devices.values(): if TemperatureTrait.NAME in device.traits: diff --git a/tests/components/nest/test_diagnostics.py b/tests/components/nest/test_diagnostics.py index b69f5970c2d..8e28222e356 100644 --- a/tests/components/nest/test_diagnostics.py +++ b/tests/components/nest/test_diagnostics.py @@ -2,7 +2,7 @@ from unittest.mock import patch -from google_nest_sdm.exceptions import ApiException, SubscriberException +from google_nest_sdm.exceptions import SubscriberException import pytest from homeassistant.components.nest.const import DOMAIN @@ -139,34 +139,6 @@ async def test_setup_susbcriber_failure( assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {} -async def test_device_manager_failure( - hass, - hass_client, - config_entry, - setup_platform, - create_device, -): - """Test configuration error.""" - create_device.create(raw_data=DEVICE_API_DATA) - await setup_platform() - assert config_entry.state is ConfigEntryState.LOADED - - device_registry = dr.async_get(hass) - device = device_registry.async_get_device({(DOMAIN, NEST_DEVICE_ID)}) - assert device is not None - - with patch( - "homeassistant.components.nest.diagnostics._get_nest_devices", - side_effect=ApiException("Device manager failure"), - ): - assert await get_diagnostics_for_config_entry( - hass, hass_client, config_entry - ) == {"error": "Device manager failure"} - assert await get_diagnostics_for_device( - hass, hass_client, config_entry, device - ) == {"error": "Device manager failure"} - - @pytest.mark.parametrize("nest_test_config", [TEST_CONFIG_LEGACY]) async def test_legacy_config_entry_diagnostics( hass, hass_client, config_entry, setup_base_platform