def test_async_add_opp_job_schedule_callback(): """Test that we schedule coroutines and add jobs to the job pool.""" opp = MagicMock() job = MagicMock() ha.OpenPeerPower.async_add_opp_job(opp, ha.OppJob(ha.callback(job))) assert len(opp.loop.call_soon.mock_calls) == 1 assert len(opp.loop.create_task.mock_calls) == 0 assert len(opp.add_job.mock_calls) == 0
def test_async_add_opp_job_schedule_partial_callback(): """Test that we schedule partial coros and add jobs to the job pool.""" opp = MagicMock() job = MagicMock() partial = functools.partial(ha.callback(job)) ha.OpenPeerPower.async_add_opp_job(opp, ha.OppJob(partial)) assert len(opp.loop.call_soon.mock_calls) == 1 assert len(opp.loop.create_task.mock_calls) == 0 assert len(opp.add_job.mock_calls) == 0
def test_async_run_opp_job_calls_callback(): """Test that the callback annotation is respected.""" opp = MagicMock() calls = [] def job(): calls.append(1) ha.OpenPeerPower.async_run_opp_job(opp, ha.OppJob(ha.callback(job))) assert len(calls) == 1 assert len(opp.async_add_job.mock_calls) == 0
async def async_added_to_opp(self): """Subscribe to children and template state changes.""" @callback def _async_on_dependency_update(event): """Update ha state when dependencies update.""" self.async_set_context(event.context) self.async_schedule_update_op_state(True) @callback def _async_on_template_update(event, updates): """Update ha state when dependencies update.""" result = updates.pop().result if isinstance(result, TemplateError): self._state_template_result = None else: self._state_template_result = result if event: self.async_set_context(event.context) self.async_schedule_update_op_state(True) if self._state_template is not None: result = async_track_template_result( self.opp, [TrackTemplate(self._state_template, None)], _async_on_template_update, ) self.opp.bus.async_listen_once( EVENT_OPENPEERPOWER_START, callback(lambda _: result.async_refresh())) self.async_on_remove(result.async_remove) depend = copy(self._children) for entity in self._attrs.values(): depend.append(entity[0]) self.async_on_remove( self.opp.helpers.event.async_track_state_change_event( list(set(depend)), _async_on_dependency_update))
async def test_state_triggers(opp): """Test sensor with state triggers.""" opp.states.async_set("sensor.test_monitored", STATE_OFF) config = { "binary_sensor": { "name": "Test_Binary", "platform": "bayesian", "observations": [ { "platform": "state", "entity_id": "sensor.test_monitored", "to_state": "off", "prob_given_true": 999.9, "prob_given_false": 999.4, }, ], "prior": 0.2, "probability_threshold": 0.32, } } await async_setup_component(opp, "binary_sensor", config) await opp.async_block_till_done() assert opp.states.get("binary_sensor.test_binary").state == STATE_OFF events = [] opp.helpers.event.async_track_state_change_event( "binary_sensor.test_binary", callback(lambda event: events.append(event))) context = Context() opp.states.async_set("sensor.test_monitored", STATE_ON, context=context) await opp.async_block_till_done() await opp.async_block_till_done() assert events[0].context == context
async def test_master_state_with_template(opp): """Test the state_template option.""" opp.states.async_set("input_boolean.test", STATE_OFF) opp.states.async_set("media_player.mock1", STATE_OFF) templ = ( '{% if states.input_boolean.test.state == "off" %}on' "{% else %}{{ states.media_player.mock1.state }}{% endif %}" ) await async_setup_component( opp, "media_player", { "media_player": { "platform": "universal", "name": "tv", "state_template": templ, } }, ) await opp.async_block_till_done() assert len(opp.states.async_all()) == 3 await opp.async_start() await opp.async_block_till_done() assert opp.states.get("media_player.tv").state == STATE_ON events = [] opp.helpers.event.async_track_state_change_event( "media_player.tv", callback(lambda event: events.append(event)) ) context = Context() opp.states.async_set("input_boolean.test", STATE_ON, context=context) await opp.async_block_till_done() assert opp.states.get("media_player.tv").state == STATE_OFF assert events[0].context == context
def catch_log_exception( func: Callable[..., Any], format_err: Callable[..., Any], *args: Any) -> Callable[..., None] | Callable[..., Awaitable[None]]: """Decorate a callback to catch and log exceptions.""" # Check for partials to properly determine if coroutine function check_func = func while isinstance(check_func, partial): check_func = check_func.func wrapper_func: Callable[..., None] | Callable[..., Awaitable[None]] if asyncio.iscoroutinefunction(check_func): async_func = cast(Callable[..., Awaitable[None]], func) @wraps(async_func) async def async_wrapper(*args: Any) -> None: """Catch and log exception.""" try: await async_func(*args) except Exception: # pylint: disable=broad-except log_exception(format_err, *args) wrapper_func = async_wrapper else: @wraps(func) def wrapper(*args: Any) -> None: """Catch and log exception.""" try: func(*args) except Exception: # pylint: disable=broad-except log_exception(format_err, *args) if is_callback(check_func): wrapper = callback(wrapper) wrapper_func = wrapper return wrapper_func
async def async_setup(opp: OpenPeerPower, config: ConfigType) -> bool: """Set up an input select.""" component = EntityComponent(_LOGGER, DOMAIN, opp) id_manager = collection.IDManager() yaml_collection = collection.YamlCollection( logging.getLogger(f"{__name__}.yaml_collection"), id_manager) collection.sync_entity_lifecycle(opp, DOMAIN, DOMAIN, component, yaml_collection, InputSelect.from_yaml) storage_collection = InputSelectStorageCollection( Store(opp, STORAGE_VERSION, STORAGE_KEY), logging.getLogger(f"{__name__}.storage_collection"), id_manager, ) collection.sync_entity_lifecycle(opp, DOMAIN, DOMAIN, component, storage_collection, InputSelect) await yaml_collection.async_load([{ CONF_ID: id_, **cfg } for id_, cfg in config.get(DOMAIN, {}).items()]) await storage_collection.async_load() collection.StorageCollectionWebsocket(storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS).async_setup(opp) async def reload_service_handler(service_call: ServiceCall) -> None: """Reload yaml entities.""" conf = await component.async_prepare_reload(skip_reset=True) if conf is None: conf = {DOMAIN: {}} await yaml_collection.async_load([{ CONF_ID: id_, **cfg } for id_, cfg in conf.get(DOMAIN, {}).items()]) openpeerpower.helpers.service.async_register_admin_service( opp, DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA, ) component.async_register_entity_service( SERVICE_SELECT_OPTION, {vol.Required(ATTR_OPTION): cv.string}, "async_select_option", ) component.async_register_entity_service( SERVICE_SELECT_NEXT, {vol.Optional(ATTR_CYCLE, default=True): bool}, "async_next", ) component.async_register_entity_service( SERVICE_SELECT_PREVIOUS, {vol.Optional(ATTR_CYCLE, default=True): bool}, "async_previous", ) component.async_register_entity_service( SERVICE_SELECT_FIRST, {}, callback(lambda entity, call: entity.async_select_index(0)), ) component.async_register_entity_service( SERVICE_SELECT_LAST, {}, callback(lambda entity, call: entity.async_select_index(-1)), ) component.async_register_entity_service( SERVICE_SET_OPTIONS, { vol.Required(ATTR_OPTIONS): vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]) }, "async_set_options", ) return True
async def _subscribe_topics(sub_state, topics): # Optionally mark message handlers as callback for topic in topics.values(): if "msg_callback" in topic and "event_loop_safe" in topic: topic["msg_callback"] = callback(topic["msg_callback"]) return await async_subscribe_topics(opp, sub_state, topics)