From 68945e8814578f3329c2694bc375b1876f61fcc5 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Wed, 28 Jul 2021 00:12:32 -0700 Subject: [PATCH] Enable strict static type checking for nest integration (#53535) --- .strict-typing | 1 + homeassistant/components/ffmpeg/__init__.py | 2 +- homeassistant/components/nest/api.py | 3 ++- homeassistant/components/nest/camera_sdm.py | 12 +++++++++--- homeassistant/components/nest/climate_sdm.py | 14 ++++++++++---- homeassistant/components/nest/device_info.py | 4 +++- homeassistant/components/nest/manifest.json | 2 +- mypy.ini | 11 +++++++++++ requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 10 files changed, 40 insertions(+), 13 deletions(-) diff --git a/.strict-typing b/.strict-typing index 40d69f7cb56..e32af5db563 100644 --- a/.strict-typing +++ b/.strict-typing @@ -63,6 +63,7 @@ homeassistant.components.mailbox.* homeassistant.components.media_player.* homeassistant.components.mysensors.* homeassistant.components.nam.* +homeassistant.components.nest.* homeassistant.components.netatmo.* homeassistant.components.network.* homeassistant.components.no_ip.* diff --git a/homeassistant/components/ffmpeg/__init__.py b/homeassistant/components/ffmpeg/__init__.py index 55e34a547e3..52e034c6265 100644 --- a/homeassistant/components/ffmpeg/__init__.py +++ b/homeassistant/components/ffmpeg/__init__.py @@ -94,7 +94,7 @@ async def async_get_image( input_source: str, output_format: str = IMAGE_JPEG, extra_cmd: str | None = None, -): +) -> bytes | None: """Get an image from a frame of an RTSP stream.""" manager = hass.data[DATA_FFMPEG] ffmpeg = ImageFrame(manager.binary) diff --git a/homeassistant/components/nest/api.py b/homeassistant/components/nest/api.py index 8affad958b7..426a651461a 100644 --- a/homeassistant/components/nest/api.py +++ b/homeassistant/components/nest/api.py @@ -1,6 +1,7 @@ """API for Google Nest Device Access bound to Home Assistant OAuth.""" import datetime +from typing import cast from aiohttp import ClientSession from google.oauth2.credentials import Credentials @@ -33,7 +34,7 @@ class AsyncConfigEntryAuth(AbstractAuth): """Return a valid access token for SDM API.""" if not self._oauth_session.valid_token: await self._oauth_session.async_ensure_token_valid() - return self._oauth_session.token["access_token"] + return cast(str, self._oauth_session.token["access_token"]) async def async_get_creds(self) -> Credentials: """Return an OAuth credential for Pub/Sub Subscriber.""" diff --git a/homeassistant/components/nest/camera_sdm.py b/homeassistant/components/nest/camera_sdm.py index 862b6dbdffb..5f5fdbc8d93 100644 --- a/homeassistant/components/nest/camera_sdm.py +++ b/homeassistant/components/nest/camera_sdm.py @@ -9,10 +9,11 @@ from google_nest_sdm.camera_traits import ( CameraEventImageTrait, CameraImageTrait, CameraLiveStreamTrait, - CameraMotionTrait, + EventImageGenerator, RtspStream, ) from google_nest_sdm.device import Device +from google_nest_sdm.event import ImageEventBase from google_nest_sdm.exceptions import GoogleNestException from haffmpeg.tools import IMAGE_JPEG @@ -121,6 +122,7 @@ class NestCamera(Camera): _LOGGER.debug("Fetching stream url") self._stream = await trait.generate_rtsp_stream() self._schedule_stream_refresh() + assert self._stream if self._stream.expires_at < utcnow(): _LOGGER.warning("Stream already expired") return self._stream.rtsp_stream_url @@ -198,7 +200,11 @@ class NestCamera(Camera): if not trait: return None # Reuse image bytes if they have already been fetched - event = trait.last_event + if not isinstance(trait, EventImageGenerator): + return None + event: ImageEventBase | None = trait.last_event + if not event: + return None if self._event_id is not None and self._event_id == event.event_id: return self._event_image_bytes _LOGGER.debug("Generating event image URL for event_id %s", event.event_id) @@ -211,7 +217,7 @@ class NestCamera(Camera): return image_bytes async def _async_fetch_active_event_image( - self, trait: CameraMotionTrait + self, trait: EventImageGenerator ) -> bytes | None: """Return image bytes for an active event.""" try: diff --git a/homeassistant/components/nest/climate_sdm.py b/homeassistant/components/nest/climate_sdm.py index 51daa7fbb9c..04954cc7a07 100644 --- a/homeassistant/components/nest/climate_sdm.py +++ b/homeassistant/components/nest/climate_sdm.py @@ -1,13 +1,14 @@ """Support for Google Nest SDM climate devices.""" from __future__ import annotations -from typing import Any +from typing import Any, cast from google_nest_sdm.device import Device from google_nest_sdm.device_traits import FanTrait, TemperatureTrait from google_nest_sdm.exceptions import GoogleNestException from google_nest_sdm.thermostat_traits import ( ThermostatEcoTrait, + ThermostatHeatCoolTrait, ThermostatHvacTrait, ThermostatModeTrait, ThermostatTemperatureSetpointTrait, @@ -184,15 +185,20 @@ class ThermostatEntity(ClimateEntity): @property def _target_temperature_trait( self, - ) -> ThermostatEcoTrait | ThermostatTemperatureSetpointTrait | None: + ) -> ThermostatHeatCoolTrait | None: """Return the correct trait with a target temp depending on mode.""" if ( self.preset_mode == PRESET_ECO and ThermostatEcoTrait.NAME in self._device.traits ): - return self._device.traits[ThermostatEcoTrait.NAME] + return cast( + ThermostatEcoTrait, self._device.traits[ThermostatEcoTrait.NAME] + ) if ThermostatTemperatureSetpointTrait.NAME in self._device.traits: - return self._device.traits[ThermostatTemperatureSetpointTrait.NAME] + return cast( + ThermostatTemperatureSetpointTrait, + self._device.traits[ThermostatTemperatureSetpointTrait.NAME], + ) return None @property diff --git a/homeassistant/components/nest/device_info.py b/homeassistant/components/nest/device_info.py index 7b10fabcd61..6278547f216 100644 --- a/homeassistant/components/nest/device_info.py +++ b/homeassistant/components/nest/device_info.py @@ -61,4 +61,6 @@ class NestDeviceInfo: # The API intentionally returns minimal information about specific # devices, instead relying on traits, but we can infer a generic model # name based on the type - return DEVICE_TYPE_MAP.get(self._device.type, "Unknown") + if self._device.type in DEVICE_TYPE_MAP: + return DEVICE_TYPE_MAP[self._device.type] + return "Unknown" diff --git a/homeassistant/components/nest/manifest.json b/homeassistant/components/nest/manifest.json index dce39edbacf..05cfa261ef4 100644 --- a/homeassistant/components/nest/manifest.json +++ b/homeassistant/components/nest/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "dependencies": ["ffmpeg", "http"], "documentation": "https://www.home-assistant.io/integrations/nest", - "requirements": ["python-nest==4.1.0", "google-nest-sdm==0.3.0"], + "requirements": ["python-nest==4.1.0", "google-nest-sdm==0.3.4"], "codeowners": ["@allenporter"], "quality_scale": "platinum", "dhcp": [ diff --git a/mypy.ini b/mypy.ini index e5c9ccca2dd..32800994e42 100644 --- a/mypy.ini +++ b/mypy.ini @@ -704,6 +704,17 @@ no_implicit_optional = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.nest.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +no_implicit_optional = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.netatmo.*] check_untyped_defs = true disallow_incomplete_defs = true diff --git a/requirements_all.txt b/requirements_all.txt index f99e4ad57ac..eb2781ac5e2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -707,7 +707,7 @@ google-cloud-pubsub==2.1.0 google-cloud-texttospeech==0.4.0 # homeassistant.components.nest -google-nest-sdm==0.3.0 +google-nest-sdm==0.3.4 # homeassistant.components.google_travel_time googlemaps==2.5.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 12f4e7296ad..ce04a77f864 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -404,7 +404,7 @@ google-api-python-client==1.6.4 google-cloud-pubsub==2.1.0 # homeassistant.components.nest -google-nest-sdm==0.3.0 +google-nest-sdm==0.3.4 # homeassistant.components.google_travel_time googlemaps==2.5.1