429 files
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user