Clean up accessing storage.Store helper via hass (#72009)

pull/72011/head
Franck Nijhof 2022-05-17 18:45:57 +02:00 committed by GitHub
parent c8f700c803
commit 5f44d0f8f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 101 additions and 55 deletions

View File

@ -10,6 +10,7 @@ from typing import Any
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.storage import Store
from homeassistant.util import dt as dt_util
from . import models
@ -45,8 +46,8 @@ class AuthStore:
self._users: dict[str, models.User] | None = None
self._groups: dict[str, models.Group] | None = None
self._perm_lookup: PermissionLookup | None = None
self._store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
self._store = Store(
hass, STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
)
self._lock = asyncio.Lock()
@ -315,7 +316,7 @@ class AuthStore:
self._perm_lookup = perm_lookup = PermissionLookup(ent_reg, dev_reg)
if data is None:
if data is None or not isinstance(data, dict):
self._set_defaults()
return

View File

@ -17,6 +17,7 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.exceptions import ServiceNotFound
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.storage import Store
from . import (
MULTI_FACTOR_AUTH_MODULE_SCHEMA,
@ -99,8 +100,8 @@ class NotifyAuthModule(MultiFactorAuthModule):
"""Initialize the user data store."""
super().__init__(hass, config)
self._user_settings: _UsersDict | None = None
self._user_store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
self._user_store = Store(
hass, STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
)
self._include = config.get(CONF_INCLUDE, [])
self._exclude = config.get(CONF_EXCLUDE, [])
@ -118,7 +119,9 @@ class NotifyAuthModule(MultiFactorAuthModule):
if self._user_settings is not None:
return
if (data := await self._user_store.async_load()) is None:
if (data := await self._user_store.async_load()) is None or not isinstance(
data, dict
):
data = {STORAGE_USERS: {}}
self._user_settings = {

View File

@ -10,6 +10,7 @@ import voluptuous as vol
from homeassistant.auth.models import User
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.storage import Store
from . import (
MULTI_FACTOR_AUTH_MODULE_SCHEMA,
@ -76,8 +77,8 @@ class TotpAuthModule(MultiFactorAuthModule):
"""Initialize the user data store."""
super().__init__(hass, config)
self._users: dict[str, str] | None = None
self._user_store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
self._user_store = Store(
hass, STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
)
self._init_lock = asyncio.Lock()
@ -92,7 +93,9 @@ class TotpAuthModule(MultiFactorAuthModule):
if self._users is not None:
return
if (data := await self._user_store.async_load()) is None:
if (data := await self._user_store.async_load()) is None or not isinstance(
data, dict
):
data = {STORAGE_USERS: {}}
self._users = data.get(STORAGE_USERS, {})

View File

@ -14,6 +14,7 @@ from homeassistant.const import CONF_ID
from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.storage import Store
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
from ..models import Credentials, UserMeta
@ -60,8 +61,8 @@ class Data:
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize the user data store."""
self.hass = hass
self._store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
self._store = Store(
hass, STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
)
self._data: dict[str, Any] | None = None
# Legacy mode will allow usernames to start/end with whitespace
@ -79,7 +80,9 @@ class Data:
async def async_load(self) -> None:
"""Load stored data."""
if (data := await self._store.async_load()) is None:
if (data := await self._store.async_load()) is None or not isinstance(
data, dict
):
data = {"users": []}
seen: set[str] = set()
@ -203,7 +206,8 @@ class Data:
async def async_save(self) -> None:
"""Save data."""
await self._store.async_save(self._data)
if self._data is not None:
await self._store.async_save(self._data)
@AUTH_PROVIDERS.register("homeassistant")

View File

@ -11,6 +11,7 @@ import async_timeout
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client
from homeassistant.helpers.storage import Store
from homeassistant.util import dt
_LOGGER = logging.getLogger(__name__)
@ -37,7 +38,7 @@ class Auth:
self.client_secret = client_secret
self._prefs = None
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
self._get_token_lock = asyncio.Lock()

View File

@ -23,6 +23,7 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import (
@ -63,7 +64,7 @@ async def async_setup_entry(
"""Set up the Ambiclimate device from config entry."""
config = entry.data
websession = async_get_clientsession(hass)
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
token_info = await store.async_load()
oauth = ambiclimate.AmbiclimateOAuth(

View File

@ -10,6 +10,7 @@ from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.network import get_url
from homeassistant.helpers.storage import Store
from .const import (
AUTH_CALLBACK_NAME,
@ -102,7 +103,7 @@ class AmbiclimateFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
_LOGGER.error("Failed to get access token", exc_info=True)
return None
store = self.hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
store = Store(self.hass, STORAGE_VERSION, STORAGE_KEY)
await store.async_save(token_info)
return token_info

View File

@ -71,7 +71,7 @@ class Analytics:
ATTR_ONBOARDED: False,
ATTR_UUID: None,
}
self._store: Store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
@property
def preferences(self) -> dict:

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from typing import Final
from homeassistant.core import HomeAssistant
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import UNDEFINED, UndefinedType
from .const import DOMAIN, PREF_PRELOAD_STREAM
@ -35,12 +36,14 @@ class CameraPreferences:
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize camera prefs."""
self._hass = hass
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
self._prefs: dict[str, dict[str, bool]] | None = None
async def async_initialize(self) -> None:
"""Finish initializing the preferences."""
if (prefs := await self._store.async_load()) is None:
if (prefs := await self._store.async_load()) is None or not isinstance(
prefs, dict
):
prefs = {}
self._prefs = prefs

View File

@ -5,6 +5,7 @@ from homeassistant.auth.const import GROUP_ID_ADMIN
from homeassistant.auth.models import User
from homeassistant.components import webhook
from homeassistant.core import callback
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import UNDEFINED
from homeassistant.util.logging import async_create_catching_coro
@ -46,7 +47,7 @@ class CloudPreferences:
def __init__(self, hass):
"""Initialize cloud prefs."""
self._hass = hass
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
self._prefs = None
self._listeners = []

View File

@ -35,6 +35,7 @@ from homeassistant.helpers.dispatcher import (
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.service import verify_domain_control
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType
import homeassistant.util.dt as dt_util
@ -198,7 +199,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
user_data = tokens.pop(USER_DATA, None)
return (tokens, user_data)
store = hass.helpers.storage.Store(STORAGE_VER, STORAGE_KEY)
store = Store(hass, STORAGE_VER, STORAGE_KEY)
tokens, user_data = await load_auth_tokens(store)
client_v2 = evohomeasync2.EvohomeClient(

View File

@ -18,6 +18,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.storage import Store
from homeassistant.util import slugify
from .const import (
@ -32,7 +33,7 @@ from .const import (
async def get_api(hass: HomeAssistant, host: str) -> Freepybox:
"""Get the Freebox API."""
freebox_path = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY).path
freebox_path = Store(hass, STORAGE_VERSION, STORAGE_KEY).path
if not os.path.exists(freebox_path):
await hass.async_add_executor_job(os.makedirs, freebox_path)

View File

@ -22,6 +22,7 @@ from homeassistant.const import CONF_MODE, CONF_NAME, EVENT_THEMES_UPDATED
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.helpers import service
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.storage import Store
from homeassistant.helpers.translation import async_get_translations
from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import async_get_integration, bind_hass
@ -389,11 +390,12 @@ async def _async_setup_themes(
"""Set up themes data and services."""
hass.data[DATA_THEMES] = themes or {}
store = hass.data[DATA_THEMES_STORE] = hass.helpers.storage.Store(
THEMES_STORAGE_VERSION, THEMES_STORAGE_KEY
store = hass.data[DATA_THEMES_STORE] = Store(
hass, THEMES_STORAGE_VERSION, THEMES_STORAGE_KEY
)
theme_data = await store.async_load() or {}
if not (theme_data := await store.async_load()) or not isinstance(theme_data, dict):
theme_data = {}
theme_name = theme_data.get(DATA_DEFAULT_THEME, DEFAULT_THEME)
dark_theme_name = theme_data.get(DATA_DEFAULT_DARK_THEME)

View File

@ -35,8 +35,10 @@ def with_store(orig_func: Callable) -> Callable:
user_id = connection.user.id
if (store := stores.get(user_id)) is None:
store = stores[user_id] = hass.helpers.storage.Store(
STORAGE_VERSION_USER_DATA, f"frontend.user_data_{connection.user.id}"
store = stores[user_id] = Store(
hass,
STORAGE_VERSION_USER_DATA,
f"frontend.user_data_{connection.user.id}",
)
if user_id not in data:

View File

@ -41,6 +41,7 @@ from homeassistant.helpers.device_registry import (
async_get_registry,
)
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.loader import bind_hass
@ -519,7 +520,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
if not await hassio.is_connected():
_LOGGER.warning("Not connected with the supervisor / system too busy!")
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
if (data := await store.async_load()) is None:
data = {}

View File

@ -17,6 +17,7 @@ from homeassistant.auth.const import GROUP_ID_READ_ONLY
from homeassistant.auth.models import User
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.storage import Store
from homeassistant.util import dt as dt_util
from homeassistant.util.network import is_local
@ -108,8 +109,8 @@ def async_user_not_allowed_do_auth(
async def async_setup_auth(hass: HomeAssistant, app: Application) -> None:
"""Create auth middleware for the app."""
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
if (data := await store.async_load()) is None:
store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
if (data := await store.async_load()) is None or not isinstance(data, dict):
data = {}
refresh_token = None

View File

@ -5,6 +5,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant, ServiceCall
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.storage import Store
from homeassistant.util import slugify
from .account import IcloudAccount
@ -81,7 +82,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if entry.unique_id is None:
hass.config_entries.async_update_entry(entry, unique_id=username)
icloud_dir = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
icloud_dir = Store(hass, STORAGE_VERSION, STORAGE_KEY)
account = IcloudAccount(
hass,

View File

@ -13,6 +13,7 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers.storage import Store
from .const import (
CONF_GPS_ACCURACY_THRESHOLD,
@ -113,7 +114,7 @@ class IcloudFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
PyiCloudService,
self._username,
self._password,
self.hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY).path,
Store(self.hass, STORAGE_VERSION, STORAGE_KEY).path,
True,
None,
self._with_family,
@ -162,7 +163,7 @@ class IcloudFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a flow initiated by the user."""
errors = {}
icloud_dir = self.hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
icloud_dir = Store(self.hass, STORAGE_VERSION, STORAGE_KEY)
if not os.path.exists(icloud_dir.path):
await self.hass.async_add_executor_job(os.makedirs, icloud_dir.path)
@ -276,9 +277,7 @@ class IcloudFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
PyiCloudService,
self._username,
self._password,
self.hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY
).path,
Store(self.hass, STORAGE_VERSION, STORAGE_KEY).path,
True,
None,
self._with_family,

View File

@ -10,6 +10,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_DEVICE_ID, CONF_WEBHOOK_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, discovery
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType
from . import websocket_api
@ -37,8 +38,10 @@ PLATFORMS = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the mobile app component."""
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
if (app_config := await store.async_load()) is None:
store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
if (app_config := await store.async_load()) is None or not isinstance(
app_config, dict
):
app_config = {
DATA_CONFIG_ENTRIES: {},
DATA_DELETED_IDS: [],

View File

@ -6,6 +6,7 @@ from typing import Any, cast
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.singleton import singleton
from homeassistant.helpers.storage import Store
from .const import (
ATTR_CONFIGURED_ADAPTERS,
@ -37,9 +38,7 @@ class Network:
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize the Network class."""
self._store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, atomic_writes=True
)
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY, atomic_writes=True)
self._data: dict[str, Any] = {}
self.adapters: list[Adapter] = []

View File

@ -32,6 +32,7 @@ from homeassistant.helpers.dispatcher import (
async_dispatcher_send,
)
from homeassistant.helpers.network import NoURLAvailableError, get_url
from homeassistant.helpers.storage import Store
from .const import (
APP_NAME_PREFIX,
@ -210,8 +211,8 @@ async def setup_smartapp_endpoint(hass: HomeAssistant):
return
# Get/create config to store a unique id for this hass instance.
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
if not (config := await store.async_load()):
store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
if not (config := await store.async_load()) or not isinstance(config, dict):
# Create config
config = {
CONF_INSTANCE_ID: str(uuid4()),
@ -282,7 +283,7 @@ async def unload_smartapp_endpoint(hass: HomeAssistant):
if cloudhook_url and cloud.async_is_logged_in(hass):
await cloud.async_delete_cloudhook(hass, hass.data[DOMAIN][CONF_WEBHOOK_ID])
# Remove cloudhook from storage
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
await store.async_save(
{
CONF_INSTANCE_ID: hass.data[DOMAIN][CONF_INSTANCE_ID],

View File

@ -4,6 +4,7 @@ from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType
from .const import (
@ -106,7 +107,7 @@ class UnifiWirelessClients:
"""Set up client storage."""
self.hass = hass
self.data = {}
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
async def async_load(self):
"""Load data from file."""

View File

@ -10,6 +10,7 @@ from typing import cast
import attr
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.storage import Store
from homeassistant.loader import bind_hass
from .typing import ZhaDeviceType
@ -38,7 +39,7 @@ class ZhaStorage:
"""Initialize the zha device storage."""
self.hass: HomeAssistant = hass
self.devices: MutableMapping[str, ZhaDeviceEntry] = {}
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
@callback
def async_create_device(self, device: ZhaDeviceType) -> ZhaDeviceEntry:

View File

@ -1895,11 +1895,19 @@ class Config:
async def async_load(self) -> None:
"""Load [homeassistant] core config."""
store = self.hass.helpers.storage.Store(
CORE_STORAGE_VERSION, CORE_STORAGE_KEY, private=True, atomic_writes=True
# Circular dep
# pylint: disable=import-outside-toplevel
from .helpers.storage import Store
store = Store(
self.hass,
CORE_STORAGE_VERSION,
CORE_STORAGE_KEY,
private=True,
atomic_writes=True,
)
if not (data := await store.async_load()):
if not (data := await store.async_load()) or not isinstance(data, dict):
return
# In 2021.9 we fixed validation to disallow a path (because that's never correct)
@ -1931,6 +1939,10 @@ class Config:
async def async_store(self) -> None:
"""Store [homeassistant] core config."""
# Circular dep
# pylint: disable=import-outside-toplevel
from .helpers.storage import Store
data = {
"latitude": self.latitude,
"longitude": self.longitude,
@ -1943,7 +1955,11 @@ class Config:
"currency": self.currency,
}
store = self.hass.helpers.storage.Store(
CORE_STORAGE_VERSION, CORE_STORAGE_KEY, private=True, atomic_writes=True
store = Store(
self.hass,
CORE_STORAGE_VERSION,
CORE_STORAGE_KEY,
private=True,
atomic_writes=True,
)
await store.async_save(data)

View File

@ -12,6 +12,7 @@ from homeassistant.loader import bind_hass
from homeassistant.util import slugify
from . import device_registry as dr, entity_registry as er
from .storage import Store
from .typing import UNDEFINED, UndefinedType
DATA_REGISTRY = "area_registry"
@ -47,9 +48,7 @@ class AreaRegistry:
"""Initialize the area registry."""
self.hass = hass
self.areas: MutableMapping[str, AreaEntry] = {}
self._store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, atomic_writes=True
)
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY, atomic_writes=True)
self._normalized_name_area_idx: dict[str, str] = {}
@callback
@ -176,7 +175,7 @@ class AreaRegistry:
areas: MutableMapping[str, AreaEntry] = OrderedDict()
if data is not None:
if isinstance(data, dict):
for area in data["areas"]:
normalized_name = normalize_area_name(area["name"])
areas[area["id"]] = AreaEntry(