Reduce executor jobs needed to setup filesize (#112490)

* Reduce executor jobs needed to setup filesize

Move the _get_full_path check into the coordinator so everything
can happen in the executor at setup time

* Reduce executor jobs needed to setup filesize

Move the _get_full_path check into the coordinator so everything
can happen in the executor at setup time

* Update homeassistant/components/filesize/coordinator.py

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
J. Nick Koston 2024-03-06 09:54:01 -10:00 committed by GitHub
parent 248f2ac2fb
commit 96b2d4f9f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 25 additions and 23 deletions

View File

@ -1,35 +1,17 @@
"""The filesize component.""" """The filesize component."""
from __future__ import annotations from __future__ import annotations
import pathlib
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_FILE_PATH from homeassistant.const import CONF_FILE_PATH
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from .const import PLATFORMS from .const import PLATFORMS
from .coordinator import FileSizeCoordinator from .coordinator import FileSizeCoordinator
def _get_full_path(hass: HomeAssistant, path: str) -> str:
"""Check if path is valid, allowed and return full path."""
get_path = pathlib.Path(path)
if not get_path.exists() or not get_path.is_file():
raise ConfigEntryNotReady(f"Can not access file {path}")
if not hass.config.is_allowed_path(path):
raise ConfigEntryNotReady(f"Filepath {path} is not valid or allowed")
return str(get_path.absolute())
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up from a config entry.""" """Set up from a config entry."""
full_path = await hass.async_add_executor_job( coordinator = FileSizeCoordinator(hass, entry.data[CONF_FILE_PATH])
_get_full_path, hass, entry.data[CONF_FILE_PATH]
)
coordinator = FileSizeCoordinator(hass, full_path)
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
import os import os
import pathlib
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@ -17,7 +18,7 @@ _LOGGER = logging.getLogger(__name__)
class FileSizeCoordinator(DataUpdateCoordinator[dict[str, int | float | datetime]]): class FileSizeCoordinator(DataUpdateCoordinator[dict[str, int | float | datetime]]):
"""Filesize coordinator.""" """Filesize coordinator."""
def __init__(self, hass: HomeAssistant, path: str) -> None: def __init__(self, hass: HomeAssistant, unresolved_path: str) -> None:
"""Initialize filesize coordinator.""" """Initialize filesize coordinator."""
super().__init__( super().__init__(
hass, hass,
@ -26,15 +27,34 @@ class FileSizeCoordinator(DataUpdateCoordinator[dict[str, int | float | datetime
update_interval=timedelta(seconds=60), update_interval=timedelta(seconds=60),
always_update=False, always_update=False,
) )
self._path = path self._unresolved_path = unresolved_path
self._path: pathlib.Path | None = None
async def _async_update_data(self) -> dict[str, float | int | datetime]: def _get_full_path(self) -> pathlib.Path:
"""Check if path is valid, allowed and return full path."""
path = self._unresolved_path
get_path = pathlib.Path(path)
if not self.hass.config.is_allowed_path(path):
raise UpdateFailed(f"Filepath {path} is not valid or allowed")
if not get_path.exists() or not get_path.is_file():
raise UpdateFailed(f"Can not access file {path}")
return get_path.absolute()
def _update(self) -> os.stat_result:
"""Fetch file information.""" """Fetch file information."""
if not self._path:
self._path = self._get_full_path()
try: try:
statinfo = await self.hass.async_add_executor_job(os.stat, self._path) return self._path.stat()
except OSError as error: except OSError as error:
raise UpdateFailed(f"Can not retrieve file statistics {error}") from error raise UpdateFailed(f"Can not retrieve file statistics {error}") from error
async def _async_update_data(self) -> dict[str, float | int | datetime]:
"""Fetch file information."""
statinfo = await self.hass.async_add_executor_job(self._update)
size = statinfo.st_size size = statinfo.st_size
last_updated = dt_util.utc_from_timestamp(statinfo.st_mtime) last_updated = dt_util.utc_from_timestamp(statinfo.st_mtime)