Create async_config_entry_first_refresh to reduce coordinator boilerplate (#48451)

This commit is contained in:
J. Nick Koston 2021-03-29 12:51:39 -10:00 committed by GitHub
parent 569c536a8e
commit a851bff95a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 181 additions and 225 deletions

View file

@ -13,6 +13,7 @@ import requests
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import CALLBACK_TYPE, Event, HassJob, HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import entity, event
from homeassistant.util.dt import utcnow
@ -57,6 +58,7 @@ class DataUpdateCoordinator(Generic[T]):
self._unsub_refresh: CALLBACK_TYPE | None = None
self._request_refresh_task: asyncio.TimerHandle | None = None
self.last_update_success = True
self.last_exception: Exception | None = None
if request_refresh_debouncer is None:
request_refresh_debouncer = Debouncer(
@ -140,7 +142,25 @@ class DataUpdateCoordinator(Generic[T]):
raise NotImplementedError("Update method not implemented")
return await self.update_method()
async def async_config_entry_first_refresh(self) -> None:
"""Refresh data for the first time when a config entry is setup.
Will automatically raise ConfigEntryNotReady if the refresh
fails. Additionally logging is handled by config entry setup
to ensure that multiple retries do not cause log spam.
"""
await self._async_refresh(log_failures=False)
if self.last_update_success:
return
ex = ConfigEntryNotReady()
ex.__cause__ = self.last_exception
raise ex
async def async_refresh(self) -> None:
"""Refresh data and log errors."""
await self._async_refresh(log_failures=True)
async def _async_refresh(self, log_failures: bool = True) -> None:
"""Refresh data."""
if self._unsub_refresh:
self._unsub_refresh()
@ -152,37 +172,50 @@ class DataUpdateCoordinator(Generic[T]):
try:
self.data = await self._async_update_data()
except (asyncio.TimeoutError, requests.exceptions.Timeout):
except (asyncio.TimeoutError, requests.exceptions.Timeout) as err:
self.last_exception = err
if self.last_update_success:
self.logger.error("Timeout fetching %s data", self.name)
if log_failures:
self.logger.error("Timeout fetching %s data", self.name)
self.last_update_success = False
except (aiohttp.ClientError, requests.exceptions.RequestException) as err:
self.last_exception = err
if self.last_update_success:
self.logger.error("Error requesting %s data: %s", self.name, err)
self.last_update_success = False
except urllib.error.URLError as err:
if self.last_update_success:
if err.reason == "timed out":
self.logger.error("Timeout fetching %s data", self.name)
else:
if log_failures:
self.logger.error("Error requesting %s data: %s", self.name, err)
self.last_update_success = False
except UpdateFailed as err:
except urllib.error.URLError as err:
self.last_exception = err
if self.last_update_success:
self.logger.error("Error fetching %s data: %s", self.name, err)
if log_failures:
if err.reason == "timed out":
self.logger.error("Timeout fetching %s data", self.name)
else:
self.logger.error(
"Error requesting %s data: %s", self.name, err
)
self.last_update_success = False
except UpdateFailed as err:
self.last_exception = err
if self.last_update_success:
if log_failures:
self.logger.error("Error fetching %s data: %s", self.name, err)
self.last_update_success = False
except NotImplementedError as err:
self.last_exception = err
raise err
except Exception as err: # pylint: disable=broad-except
self.last_exception = err
self.last_update_success = False
self.logger.exception(
"Unexpected error fetching %s data: %s", self.name, err
)
if log_failures:
self.logger.exception(
"Unexpected error fetching %s data: %s", self.name, err
)
else:
if not self.last_update_success: