mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
Use runtime_data in google (#144331)
* Use runtime_data in google * Quality scale
This commit is contained in:
parent
1447392847
commit
253217958b
@ -14,7 +14,6 @@ from gcal_sync.model import DateOrDatetime, Event
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_DEVICE_ID,
|
CONF_DEVICE_ID,
|
||||||
CONF_ENTITIES,
|
CONF_ENTITIES,
|
||||||
@ -34,8 +33,6 @@ from homeassistant.helpers.entity import generate_entity_id
|
|||||||
|
|
||||||
from .api import ApiAuthImpl, get_feature_access
|
from .api import ApiAuthImpl, get_feature_access
|
||||||
from .const import (
|
from .const import (
|
||||||
DATA_SERVICE,
|
|
||||||
DATA_STORE,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
EVENT_DESCRIPTION,
|
EVENT_DESCRIPTION,
|
||||||
EVENT_END_DATE,
|
EVENT_END_DATE,
|
||||||
@ -50,7 +47,7 @@ from .const import (
|
|||||||
EVENT_TYPES_CONF,
|
EVENT_TYPES_CONF,
|
||||||
FeatureAccess,
|
FeatureAccess,
|
||||||
)
|
)
|
||||||
from .store import LocalCalendarStore
|
from .store import GoogleConfigEntry, GoogleRuntimeData, LocalCalendarStore
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -139,11 +136,8 @@ ADD_EVENT_SERVICE_SCHEMA = vol.All(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: GoogleConfigEntry) -> bool:
|
||||||
"""Set up Google from a config entry."""
|
"""Set up Google from a config entry."""
|
||||||
hass.data.setdefault(DOMAIN, {})
|
|
||||||
hass.data[DOMAIN][entry.entry_id] = {}
|
|
||||||
|
|
||||||
# Validate google_calendars.yaml (if present) as soon as possible to return
|
# Validate google_calendars.yaml (if present) as soon as possible to return
|
||||||
# helpful error messages.
|
# helpful error messages.
|
||||||
try:
|
try:
|
||||||
@ -181,9 +175,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
calendar_service = GoogleCalendarService(
|
calendar_service = GoogleCalendarService(
|
||||||
ApiAuthImpl(async_get_clientsession(hass), session)
|
ApiAuthImpl(async_get_clientsession(hass), session)
|
||||||
)
|
)
|
||||||
hass.data[DOMAIN][entry.entry_id][DATA_SERVICE] = calendar_service
|
entry.runtime_data = GoogleRuntimeData(
|
||||||
hass.data[DOMAIN][entry.entry_id][DATA_STORE] = LocalCalendarStore(
|
service=calendar_service,
|
||||||
hass, entry.entry_id
|
store=LocalCalendarStore(hass, entry.entry_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
if entry.unique_id is None:
|
if entry.unique_id is None:
|
||||||
@ -207,27 +201,25 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def async_entry_has_scopes(entry: ConfigEntry) -> bool:
|
def async_entry_has_scopes(entry: GoogleConfigEntry) -> bool:
|
||||||
"""Verify that the config entry desired scope is present in the oauth token."""
|
"""Verify that the config entry desired scope is present in the oauth token."""
|
||||||
access = get_feature_access(entry)
|
access = get_feature_access(entry)
|
||||||
token_scopes = entry.data.get("token", {}).get("scope", [])
|
token_scopes = entry.data.get("token", {}).get("scope", [])
|
||||||
return access.scope in token_scopes
|
return access.scope in token_scopes
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: GoogleConfigEntry) -> bool:
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
hass.data[DOMAIN].pop(entry.entry_id)
|
|
||||||
return unload_ok
|
|
||||||
|
|
||||||
|
|
||||||
async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
async def async_reload_entry(hass: HomeAssistant, entry: GoogleConfigEntry) -> None:
|
||||||
"""Reload config entry if the access options change."""
|
"""Reload config entry if the access options change."""
|
||||||
if not async_entry_has_scopes(entry):
|
if not async_entry_has_scopes(entry):
|
||||||
await hass.config_entries.async_reload(entry.entry_id)
|
await hass.config_entries.async_reload(entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
async def async_remove_entry(hass: HomeAssistant, entry: GoogleConfigEntry) -> None:
|
||||||
"""Handle removal of a local storage."""
|
"""Handle removal of a local storage."""
|
||||||
store = LocalCalendarStore(hass, entry.entry_id)
|
store = LocalCalendarStore(hass, entry.entry_id)
|
||||||
await store.async_remove()
|
await store.async_remove()
|
||||||
|
@ -17,7 +17,6 @@ from oauth2client.client import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.components.application_credentials import AuthImplementation
|
from homeassistant.components.application_credentials import AuthImplementation
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
from homeassistant.helpers.event import (
|
from homeassistant.helpers.event import (
|
||||||
@ -27,6 +26,7 @@ from homeassistant.helpers.event import (
|
|||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .const import CONF_CALENDAR_ACCESS, DEFAULT_FEATURE_ACCESS, FeatureAccess
|
from .const import CONF_CALENDAR_ACCESS, DEFAULT_FEATURE_ACCESS, FeatureAccess
|
||||||
|
from .store import GoogleConfigEntry
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ class DeviceFlow:
|
|||||||
self._listener()
|
self._listener()
|
||||||
|
|
||||||
|
|
||||||
def get_feature_access(config_entry: ConfigEntry) -> FeatureAccess:
|
def get_feature_access(config_entry: GoogleConfigEntry) -> FeatureAccess:
|
||||||
"""Return the desired calendar feature access."""
|
"""Return the desired calendar feature access."""
|
||||||
if config_entry.options and CONF_CALENDAR_ACCESS in config_entry.options:
|
if config_entry.options and CONF_CALENDAR_ACCESS in config_entry.options:
|
||||||
return FeatureAccess[config_entry.options[CONF_CALENDAR_ACCESS]]
|
return FeatureAccess[config_entry.options[CONF_CALENDAR_ACCESS]]
|
||||||
|
@ -37,7 +37,6 @@ from homeassistant.components.calendar import (
|
|||||||
extract_offset,
|
extract_offset,
|
||||||
is_offset_reached,
|
is_offset_reached,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.const import CONF_DEVICE_ID, CONF_ENTITIES, CONF_NAME, CONF_OFFSET
|
from homeassistant.const import CONF_DEVICE_ID, CONF_ENTITIES, CONF_NAME, CONF_OFFSET
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall
|
from homeassistant.core import HomeAssistant, ServiceCall
|
||||||
from homeassistant.exceptions import HomeAssistantError, PlatformNotReady
|
from homeassistant.exceptions import HomeAssistantError, PlatformNotReady
|
||||||
@ -52,7 +51,6 @@ from . import (
|
|||||||
CONF_SEARCH,
|
CONF_SEARCH,
|
||||||
CONF_TRACK,
|
CONF_TRACK,
|
||||||
DEFAULT_CONF_OFFSET,
|
DEFAULT_CONF_OFFSET,
|
||||||
DOMAIN,
|
|
||||||
YAML_DEVICES,
|
YAML_DEVICES,
|
||||||
get_calendar_info,
|
get_calendar_info,
|
||||||
load_config,
|
load_config,
|
||||||
@ -60,8 +58,6 @@ from . import (
|
|||||||
)
|
)
|
||||||
from .api import get_feature_access
|
from .api import get_feature_access
|
||||||
from .const import (
|
from .const import (
|
||||||
DATA_SERVICE,
|
|
||||||
DATA_STORE,
|
|
||||||
EVENT_END_DATE,
|
EVENT_END_DATE,
|
||||||
EVENT_END_DATETIME,
|
EVENT_END_DATETIME,
|
||||||
EVENT_IN,
|
EVENT_IN,
|
||||||
@ -72,6 +68,7 @@ from .const import (
|
|||||||
FeatureAccess,
|
FeatureAccess,
|
||||||
)
|
)
|
||||||
from .coordinator import CalendarQueryUpdateCoordinator, CalendarSyncUpdateCoordinator
|
from .coordinator import CalendarQueryUpdateCoordinator, CalendarSyncUpdateCoordinator
|
||||||
|
from .store import GoogleConfigEntry
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -109,7 +106,7 @@ class GoogleCalendarEntityDescription(CalendarEntityDescription):
|
|||||||
|
|
||||||
def _get_entity_descriptions(
|
def _get_entity_descriptions(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: GoogleConfigEntry,
|
||||||
calendar_item: Calendar,
|
calendar_item: Calendar,
|
||||||
calendar_info: Mapping[str, Any],
|
calendar_info: Mapping[str, Any],
|
||||||
) -> list[GoogleCalendarEntityDescription]:
|
) -> list[GoogleCalendarEntityDescription]:
|
||||||
@ -202,12 +199,12 @@ def _get_entity_descriptions(
|
|||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: GoogleConfigEntry,
|
||||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the google calendar platform."""
|
"""Set up the google calendar platform."""
|
||||||
calendar_service = hass.data[DOMAIN][config_entry.entry_id][DATA_SERVICE]
|
calendar_service = config_entry.runtime_data.service
|
||||||
store = hass.data[DOMAIN][config_entry.entry_id][DATA_STORE]
|
store = config_entry.runtime_data.store
|
||||||
try:
|
try:
|
||||||
result = await calendar_service.async_list_calendars()
|
result = await calendar_service.async_list_calendars()
|
||||||
except ApiException as err:
|
except ApiException as err:
|
||||||
|
@ -11,12 +11,7 @@ from gcal_sync.api import GoogleCalendarService
|
|||||||
from gcal_sync.exceptions import ApiException, ApiForbiddenException
|
from gcal_sync.exceptions import ApiException, ApiForbiddenException
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.config_entries import (
|
from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult, OptionsFlow
|
||||||
SOURCE_REAUTH,
|
|
||||||
ConfigEntry,
|
|
||||||
ConfigFlowResult,
|
|
||||||
OptionsFlow,
|
|
||||||
)
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
@ -38,6 +33,7 @@ from .const import (
|
|||||||
CredentialType,
|
CredentialType,
|
||||||
FeatureAccess,
|
FeatureAccess,
|
||||||
)
|
)
|
||||||
|
from .store import GoogleConfigEntry
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -240,7 +236,7 @@ class OAuth2FlowHandler(
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
@callback
|
@callback
|
||||||
def async_get_options_flow(
|
def async_get_options_flow(
|
||||||
config_entry: ConfigEntry,
|
config_entry: GoogleConfigEntry,
|
||||||
) -> OptionsFlow:
|
) -> OptionsFlow:
|
||||||
"""Create an options flow."""
|
"""Create an options flow."""
|
||||||
return OptionsFlowHandler()
|
return OptionsFlowHandler()
|
||||||
|
@ -9,9 +9,7 @@ DOMAIN = "google"
|
|||||||
CONF_CALENDAR_ACCESS = "calendar_access"
|
CONF_CALENDAR_ACCESS = "calendar_access"
|
||||||
CONF_CREDENTIAL_TYPE = "credential_type"
|
CONF_CREDENTIAL_TYPE = "credential_type"
|
||||||
DATA_CALENDARS = "calendars"
|
DATA_CALENDARS = "calendars"
|
||||||
DATA_SERVICE = "service"
|
|
||||||
DATA_CONFIG = "config"
|
DATA_CONFIG = "config"
|
||||||
DATA_STORE = "store"
|
|
||||||
|
|
||||||
|
|
||||||
class FeatureAccess(Enum):
|
class FeatureAccess(Enum):
|
||||||
|
@ -14,12 +14,13 @@ from gcal_sync.sync import CalendarEventSyncManager
|
|||||||
from gcal_sync.timeline import Timeline
|
from gcal_sync.timeline import Timeline
|
||||||
from ical.iter import SortableItemValue
|
from ical.iter import SortableItemValue
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
|
from .store import GoogleConfigEntry
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15)
|
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15)
|
||||||
@ -47,12 +48,12 @@ def _truncate_timeline(timeline: Timeline, max_events: int) -> Timeline:
|
|||||||
class CalendarSyncUpdateCoordinator(DataUpdateCoordinator[Timeline]):
|
class CalendarSyncUpdateCoordinator(DataUpdateCoordinator[Timeline]):
|
||||||
"""Coordinator for calendar RPC calls that use an efficient sync."""
|
"""Coordinator for calendar RPC calls that use an efficient sync."""
|
||||||
|
|
||||||
config_entry: ConfigEntry
|
config_entry: GoogleConfigEntry
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: GoogleConfigEntry,
|
||||||
sync: CalendarEventSyncManager,
|
sync: CalendarEventSyncManager,
|
||||||
name: str,
|
name: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -108,12 +109,12 @@ class CalendarQueryUpdateCoordinator(DataUpdateCoordinator[list[Event]]):
|
|||||||
for limitations in the calendar API for supporting search.
|
for limitations in the calendar API for supporting search.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config_entry: ConfigEntry
|
config_entry: GoogleConfigEntry
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: GoogleConfigEntry,
|
||||||
calendar_service: GoogleCalendarService,
|
calendar_service: GoogleCalendarService,
|
||||||
name: str,
|
name: str,
|
||||||
calendar_id: str,
|
calendar_id: str,
|
||||||
|
@ -4,11 +4,10 @@ import datetime
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.diagnostics import async_redact_data
|
from homeassistant.components.diagnostics import async_redact_data
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .const import DATA_STORE, DOMAIN
|
from .store import GoogleConfigEntry
|
||||||
|
|
||||||
TO_REDACT = {
|
TO_REDACT = {
|
||||||
"id",
|
"id",
|
||||||
@ -40,7 +39,7 @@ def redact_store(data: dict[str, Any]) -> dict[str, Any]:
|
|||||||
|
|
||||||
|
|
||||||
async def async_get_config_entry_diagnostics(
|
async def async_get_config_entry_diagnostics(
|
||||||
hass: HomeAssistant, config_entry: ConfigEntry
|
hass: HomeAssistant, config_entry: GoogleConfigEntry
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Return diagnostics for a config entry."""
|
"""Return diagnostics for a config entry."""
|
||||||
payload: dict[str, Any] = {
|
payload: dict[str, Any] = {
|
||||||
@ -49,7 +48,7 @@ async def async_get_config_entry_diagnostics(
|
|||||||
"system_timezone": str(datetime.datetime.now().astimezone().tzinfo),
|
"system_timezone": str(datetime.datetime.now().astimezone().tzinfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
store = hass.data[DOMAIN][config_entry.entry_id][DATA_STORE]
|
store = config_entry.runtime_data.store
|
||||||
data = await store.async_load()
|
if data := await store.async_load():
|
||||||
payload["store"] = redact_store(data)
|
payload["store"] = redact_store(data)
|
||||||
return payload
|
return payload
|
||||||
|
@ -40,11 +40,7 @@ rules:
|
|||||||
to increase functionality such as checking for the specific contents
|
to increase functionality such as checking for the specific contents
|
||||||
of a unique id assigned to a config entry.
|
of a unique id assigned to a config entry.
|
||||||
docs-actions: done
|
docs-actions: done
|
||||||
runtime-data:
|
runtime-data: done
|
||||||
status: todo
|
|
||||||
comment: |
|
|
||||||
The integration stores config entry data in `hass.data` and should be
|
|
||||||
updated to use `runtime_data`.
|
|
||||||
|
|
||||||
# Silver
|
# Silver
|
||||||
log-when-unavailable: done
|
log-when-unavailable: done
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from gcal_sync.api import GoogleCalendarService
|
||||||
from gcal_sync.store import CalendarStore
|
from gcal_sync.store import CalendarStore
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.storage import Store
|
from homeassistant.helpers.storage import Store
|
||||||
|
|
||||||
@ -19,6 +22,16 @@ STORAGE_VERSION = 1
|
|||||||
# Buffer writes every few minutes (plus guaranteed to be written at shutdown)
|
# Buffer writes every few minutes (plus guaranteed to be written at shutdown)
|
||||||
STORAGE_SAVE_DELAY_SECONDS = 120
|
STORAGE_SAVE_DELAY_SECONDS = 120
|
||||||
|
|
||||||
|
type GoogleConfigEntry = ConfigEntry[GoogleRuntimeData]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GoogleRuntimeData:
|
||||||
|
"""Google runtime data."""
|
||||||
|
|
||||||
|
service: GoogleCalendarService
|
||||||
|
store: LocalCalendarStore
|
||||||
|
|
||||||
|
|
||||||
class LocalCalendarStore(CalendarStore):
|
class LocalCalendarStore(CalendarStore):
|
||||||
"""Storage for local persistence of calendar and event data."""
|
"""Storage for local persistence of calendar and event data."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user