1
mirror of https://github.com/home-assistant/core synced 2024-07-12 07:21:24 +02:00

Small cleanups to service calls (#95873)

This commit is contained in:
J. Nick Koston 2023-07-05 02:25:38 -05:00 committed by GitHub
parent 9109b5fead
commit 91f334ca59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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: