429 files

This commit is contained in:
Home Assistant Version Control
2026-08-30 02:43:31 +00:00
parent 472c19bceb
commit 963cce81a7
566 changed files with 50311 additions and 47616 deletions
+57 -37
View File
@@ -8,13 +8,9 @@ import importlib
from pathlib import Path
from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast, final
from awesomeversion import AwesomeVersion
import voluptuous as vol
from homeassistant.const import (
EVENT_CORE_CONFIG_UPDATE,
__short_version__ as current_version,
)
from homeassistant.const import EVENT_CORE_CONFIG_UPDATE
from homeassistant.core import (
Event,
HomeAssistant,
@@ -107,6 +103,7 @@ class AbstractSpookService(AbstractSpookServiceBase):
self.service,
self.domain,
)
return
LOGGER.debug(
"Registering Spook service: %s.%s",
@@ -183,15 +180,20 @@ class AbstractSpookEntityService(AbstractSpookServiceBase, Generic[_EntityT]):
if not (
platform := next(
platform
for platform in self.hass.data[DATA_ENTITY_PLATFORM][self.domain]
if platform.domain == self.platform
(
platform
for platform in self.hass.data.get(DATA_ENTITY_PLATFORM, {}).get(
self.domain, []
)
if platform.domain == self.platform
),
None,
)
):
msg = (
f"Could not find platform {self.platform} for domain "
f"{self.domain} to register service: "
f"{self.domain}.{self.service}",
f"{self.domain}.{self.service}"
)
raise RuntimeError(msg)
@@ -229,10 +231,10 @@ class AbstractSpookEntityComponentService(AbstractSpookServiceBase, Generic[_Ent
self.service,
)
if self.domain not in self.hass.data[DATA_INSTANCES]:
if self.domain not in self.hass.data.get(DATA_INSTANCES, {}):
msg = (
f"Could not find entity component {self.domain} to register "
f"service: {self.domain}.{self.service}",
f"service: {self.domain}.{self.service}"
)
raise RuntimeError(msg)
@@ -279,26 +281,13 @@ class SpookServiceManager:
# Load service schemas
integration = await async_get_integration(self.hass, DOMAIN)
# Ensure compatibility with Home Assistant version
# As of Home Assistant 2025.10, the _load_services_file function no
# longer has the hass parameter.
if AwesomeVersion(current_version) >= AwesomeVersion("2025.10"):
self._service_schemas = cast(
dict[str, Any],
await self.hass.async_add_executor_job(
_load_services_file,
integration,
),
)
else:
self._service_schemas = cast(
dict[str, Any],
await self.hass.async_add_executor_job(
_load_services_file,
self.hass,
integration,
),
)
self._service_schemas = cast(
dict[str, Any],
await self.hass.async_add_executor_job(
_load_services_file,
integration,
),
)
modules: list[ModuleType] = []
@@ -317,6 +306,23 @@ class SpookServiceManager:
await self.hass.async_add_import_executor_job(_load_all_service_modules)
for module in modules:
self._async_setup_service_module(module)
await self.async_inject_service_translations()
self._translation_listener = self.hass.bus.async_listen(
EVENT_CORE_CONFIG_UPDATE,
self._async_core_config_updated,
)
@callback
def _async_setup_service_module(self, module: ModuleType) -> None:
"""Set up a single service module, isolating failures.
A service that fails to set up must not prevent the rest of Spook
from loading.
"""
service: AbstractSpookServiceBase | None = None
try:
service = module.SpookService(self.hass)
if isinstance(
service,
@@ -333,12 +339,26 @@ class SpookServiceManager:
).pop(service.service)
self.async_register_service(service)
await self.async_inject_service_translations()
self._translation_listener = self.hass.bus.async_listen(
EVENT_CORE_CONFIG_UPDATE,
self._async_core_config_updated,
)
# pylint: disable-next=broad-exception-caught
except Exception: # noqa: BLE001
# If the service this one overrides was already unregistered,
# restore it; a failing setup must not silently remove a core
# service until the next restart.
if (
isinstance(service, ReplaceExistingService)
and service.overriden_service is not None
):
# pylint: disable-next=protected-access
self.hass.services._services.setdefault( # noqa: SLF001
service.domain,
{},
)[service.service] = service.overriden_service
LOGGER.exception(
"Spook service %s failed to set up and has been skipped; "
"please report this issue at "
"https://github.com/frenck/spook/issues",
module.__name__,
)
@callback
def async_register_service(self, service: AbstractSpookService) -> None: