Small cleanups to service calls (#95873)
This commit is contained in:
parent
9109b5fead
commit
91f334ca59
1 changed files with 43 additions and 42 deletions
|
@ -1693,7 +1693,7 @@ class Service:
|
|||
class ServiceCall:
|
||||
"""Representation of a call to a service."""
|
||||
|
||||
__slots__ = ["domain", "service", "data", "context", "return_response"]
|
||||
__slots__ = ("domain", "service", "data", "context", "return_response")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -1704,8 +1704,8 @@ class ServiceCall:
|
|||
return_response: bool = False,
|
||||
) -> None:
|
||||
"""Initialize a service call."""
|
||||
self.domain = domain.lower()
|
||||
self.service = service.lower()
|
||||
self.domain = domain
|
||||
self.service = service
|
||||
self.data = ReadOnlyDict(data or {})
|
||||
self.context = context or Context()
|
||||
self.return_response = return_response
|
||||
|
@ -1890,15 +1890,20 @@ class ServiceRegistry:
|
|||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
domain = domain.lower()
|
||||
service = service.lower()
|
||||
context = context or Context()
|
||||
service_data = service_data or {}
|
||||
|
||||
try:
|
||||
handler = self._services[domain][service]
|
||||
except KeyError:
|
||||
raise ServiceNotFound(domain, service) from None
|
||||
# Almost all calls are already lower case, so we avoid
|
||||
# calling lower() on the arguments in the common case.
|
||||
domain = domain.lower()
|
||||
service = service.lower()
|
||||
try:
|
||||
handler = self._services[domain][service]
|
||||
except KeyError:
|
||||
raise ServiceNotFound(domain, service) from None
|
||||
|
||||
if return_response:
|
||||
if not blocking:
|
||||
|
@ -1938,8 +1943,8 @@ class ServiceRegistry:
|
|||
self._hass.bus.async_fire(
|
||||
EVENT_CALL_SERVICE,
|
||||
{
|
||||
ATTR_DOMAIN: domain.lower(),
|
||||
ATTR_SERVICE: service.lower(),
|
||||
ATTR_DOMAIN: domain,
|
||||
ATTR_SERVICE: service,
|
||||
ATTR_SERVICE_DATA: service_data,
|
||||
},
|
||||
context=context,
|
||||
|
@ -1947,7 +1952,10 @@ class ServiceRegistry:
|
|||
|
||||
coro = self._execute_service(handler, service_call)
|
||||
if not blocking:
|
||||
self._run_service_in_background(coro, service_call)
|
||||
self._hass.async_create_task(
|
||||
self._run_service_call_catch_exceptions(coro, service_call),
|
||||
f"service call background {service_call.domain}.{service_call.service}",
|
||||
)
|
||||
return None
|
||||
|
||||
response_data = await coro
|
||||
|
@ -1959,49 +1967,42 @@ class ServiceRegistry:
|
|||
)
|
||||
return response_data
|
||||
|
||||
def _run_service_in_background(
|
||||
async def _run_service_call_catch_exceptions(
|
||||
self,
|
||||
coro_or_task: Coroutine[Any, Any, Any] | asyncio.Task[Any],
|
||||
service_call: ServiceCall,
|
||||
) -> None:
|
||||
"""Run service call in background, catching and logging any exceptions."""
|
||||
|
||||
async def catch_exceptions() -> None:
|
||||
try:
|
||||
await coro_or_task
|
||||
except Unauthorized:
|
||||
_LOGGER.warning(
|
||||
"Unauthorized service called %s/%s",
|
||||
service_call.domain,
|
||||
service_call.service,
|
||||
)
|
||||
except asyncio.CancelledError:
|
||||
_LOGGER.debug("Service was cancelled: %s", service_call)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Error executing service: %s", service_call)
|
||||
|
||||
self._hass.async_create_task(
|
||||
catch_exceptions(),
|
||||
f"service call background {service_call.domain}.{service_call.service}",
|
||||
)
|
||||
try:
|
||||
await coro_or_task
|
||||
except Unauthorized:
|
||||
_LOGGER.warning(
|
||||
"Unauthorized service called %s/%s",
|
||||
service_call.domain,
|
||||
service_call.service,
|
||||
)
|
||||
except asyncio.CancelledError:
|
||||
_LOGGER.debug("Service was cancelled: %s", service_call)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Error executing service: %s", service_call)
|
||||
|
||||
async def _execute_service(
|
||||
self, handler: Service, service_call: ServiceCall
|
||||
) -> ServiceResponse:
|
||||
"""Execute a service."""
|
||||
if handler.job.job_type == HassJobType.Coroutinefunction:
|
||||
return await cast(
|
||||
Callable[[ServiceCall], Awaitable[ServiceResponse]],
|
||||
handler.job.target,
|
||||
)(service_call)
|
||||
if handler.job.job_type == HassJobType.Callback:
|
||||
return cast(Callable[[ServiceCall], ServiceResponse], handler.job.target)(
|
||||
service_call
|
||||
)
|
||||
return await self._hass.async_add_executor_job(
|
||||
cast(Callable[[ServiceCall], ServiceResponse], handler.job.target),
|
||||
service_call,
|
||||
)
|
||||
job = handler.job
|
||||
target = job.target
|
||||
if job.job_type == HassJobType.Coroutinefunction:
|
||||
if TYPE_CHECKING:
|
||||
target = cast(Callable[..., Coroutine[Any, Any, _R]], target)
|
||||
return await target(service_call)
|
||||
if job.job_type == HassJobType.Callback:
|
||||
if TYPE_CHECKING:
|
||||
target = cast(Callable[..., _R], target)
|
||||
return target(service_call)
|
||||
if TYPE_CHECKING:
|
||||
target = cast(Callable[..., _R], target)
|
||||
return await self._hass.async_add_executor_job(target, service_call)
|
||||
|
||||
|
||||
class Config:
|
||||
|
|
Loading…
Add table
Reference in a new issue