async def test_handling_service_not_found(mock_request): """Test handling unauth exceptions.""" with pytest.raises(HTTPInternalServerError): await request_handler_factory( Mock(requires_auth=False), AsyncMock(side_effect=ServiceNotFound("test", "test")), )(mock_request)
async def async_call(self, domain: str, service: str, service_data: Optional[Dict] = None, blocking: bool = False, context: Optional[Context] = None) -> Optional[bool]: """ Call a service. Specify blocking=True to wait till service is executed. Waits a maximum of SERVICE_CALL_LIMIT. If blocking = True, will return boolean if service executed successfully within SERVICE_CALL_LIMIT. This method will fire an event to call the service. This event will be picked up by this ServiceRegistry and any other ServiceRegistry that is listening on the EventBus. Because the service is sent as an event you are not allowed to use the keys ATTR_DOMAIN and ATTR_SERVICE in your service_data. 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 if handler.schema: processed_data = handler.schema(service_data) else: processed_data = service_data service_call = ServiceCall(domain, service, processed_data, context) self._hass.bus.async_fire(EVENT_CALL_SERVICE, { ATTR_DOMAIN: domain.lower(), ATTR_SERVICE: service.lower(), ATTR_SERVICE_DATA: service_data, }, context=context) if not blocking: self._hass.async_create_task( self._safe_execute(handler, service_call)) return None try: with timeout(SERVICE_CALL_LIMIT): await asyncio.shield( self._execute_service(handler, service_call)) return True except asyncio.TimeoutError: return False
async def test_handling_service_not_found(mock_request): """Test handling unauth exceptions.""" with pytest.raises(HTTPInternalServerError): await request_handler_factory( Mock(requires_auth=False), mock_coro_func(exception=ServiceNotFound('test', 'test')) )(mock_request)
async def async_call( self, domain: str, service: str, service_data: Optional[Dict] = None, blocking: bool = False, context: Optional[Context] = None, limit: Optional[float] = SERVICE_CALL_LIMIT, ) -> Optional[bool]: """ Call a service. Specify blocking=True to wait until service is executed. Waits a maximum of limit, which may be None for no timeout. If blocking = True, will return boolean if service executed successfully within limit. This method will fire an event to indicate the service has been called. Because the service is sent as an event you are not allowed to use the keys ATTR_DOMAIN and ATTR_SERVICE in your service_data. 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 if handler.schema: processed_data = handler.schema(service_data) else: processed_data = service_data service_call = ServiceCall(domain, service, processed_data, context) self._hass.bus.async_fire( EVENT_CALL_SERVICE, { ATTR_DOMAIN: domain.lower(), ATTR_SERVICE: service.lower(), ATTR_SERVICE_DATA: service_data, }, context=context, ) if not blocking: self._hass.async_create_task( self._safe_execute(handler, service_call)) return None try: async with timeout(limit): await asyncio.shield( self._execute_service(handler, service_call)) return True except asyncio.TimeoutError: return False
async def async_call( self, domain: str, service: str, service_data: Optional[Dict] = None, blocking: bool = False, context: Optional[Context] = None, limit: Optional[float] = SERVICE_CALL_LIMIT, ) -> Optional[bool]: """ Call a service. Specify blocking=True to wait until service is executed. Waits a maximum of limit, which may be None for no timeout. If blocking = True, will return boolean if service executed successfully within limit. This method will fire an event to indicate the service has been called. Because the service is sent as an event you are not allowed to use the keys ATTR_DOMAIN and ATTR_SERVICE in your service_data. 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 if handler.schema: processed_data = handler.schema(service_data) else: processed_data = service_data service_call = ServiceCall(domain, service, processed_data, context) self._hass.bus.async_fire( EVENT_CALL_SERVICE, { ATTR_DOMAIN: domain.lower(), ATTR_SERVICE: service.lower(), ATTR_SERVICE_DATA: service_data, }, context=context, ) coro = self._execute_service(handler, service_call) if not blocking: self._run_service_in_background(coro, service_call) return None task = self._hass.async_create_task(coro) try: await asyncio.wait({task}, timeout=limit) except asyncio.CancelledError: # Task calling us was cancelled, so cancel service call task, and wait for # it to be cancelled, within reason, before leaving. _LOGGER.debug("Service call was cancelled: %s", service_call) task.cancel() await asyncio.wait({task}, timeout=SERVICE_CALL_LIMIT) raise if task.cancelled(): # Service call task was cancelled some other way, such as during shutdown. _LOGGER.debug("Service was cancelled: %s", service_call) raise asyncio.CancelledError if task.done(): # Propagate any exceptions that might have happened during service call. task.result() # Service call completed successfully! return True # Service call task did not complete before timeout expired. # Let it keep running in background. self._run_service_in_background(task, service_call) _LOGGER.debug("Service did not complete before timeout: %s", service_call) return False