Skip to content

Commit 8c65062

Browse files
authored
Several optimizations to automations (#35007)
1 parent f3d7910 commit 8c65062

File tree

15 files changed

+331
-326
lines changed

15 files changed

+331
-326
lines changed

homeassistant/components/automation/__init__.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Allow to set up simple automation rules via the config file."""
2+
import asyncio
23
import importlib
34
import logging
45
from typing import Any, Awaitable, Callable, List, Optional, Set
@@ -127,13 +128,11 @@ def automations_with_entity(hass: HomeAssistant, entity_id: str) -> List[str]:
127128

128129
component = hass.data[DOMAIN]
129130

130-
results = []
131-
132-
for automation_entity in component.entities:
133-
if entity_id in automation_entity.referenced_entities:
134-
results.append(automation_entity.entity_id)
135-
136-
return results
131+
return [
132+
automation_entity.entity_id
133+
for automation_entity in component.entities
134+
if entity_id in automation_entity.referenced_entities
135+
]
137136

138137

139138
@callback
@@ -160,13 +159,11 @@ def automations_with_device(hass: HomeAssistant, device_id: str) -> List[str]:
160159

161160
component = hass.data[DOMAIN]
162161

163-
results = []
164-
165-
for automation_entity in component.entities:
166-
if device_id in automation_entity.referenced_devices:
167-
results.append(automation_entity.entity_id)
168-
169-
return results
162+
return [
163+
automation_entity.entity_id
164+
for automation_entity in component.entities
165+
if device_id in automation_entity.referenced_devices
166+
]
170167

171168

172169
@callback
@@ -443,26 +440,29 @@ async def _async_attach_triggers(
443440
self, home_assistant_start: bool
444441
) -> Optional[Callable[[], None]]:
445442
"""Set up the triggers."""
446-
removes = []
447443
info = {"name": self._name, "home_assistant_start": home_assistant_start}
448444

445+
triggers = []
449446
for conf in self._trigger_config:
450447
platform = importlib.import_module(f".{conf[CONF_PLATFORM]}", __name__)
451448

452-
remove = await platform.async_attach_trigger( # type: ignore
453-
self.hass, conf, self.async_trigger, info
449+
triggers.append(
450+
platform.async_attach_trigger( # type: ignore
451+
self.hass, conf, self.async_trigger, info
452+
)
454453
)
455454

456-
if not remove:
457-
_LOGGER.error("Error setting up trigger %s", self._name)
458-
continue
455+
results = await asyncio.gather(*triggers)
459456

460-
_LOGGER.info("Initialized trigger %s", self._name)
461-
removes.append(remove)
457+
if None in results:
458+
_LOGGER.error("Error setting up trigger %s", self._name)
462459

460+
removes = [remove for remove in results if remove is not None]
463461
if not removes:
464462
return None
465463

464+
_LOGGER.info("Initialized trigger %s", self._name)
465+
466466
@callback
467467
def remove_triggers():
468468
"""Remove attached triggers."""

homeassistant/components/automation/config.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,19 @@ async def async_validate_config_item(hass, config, full_config=None):
3636
config[CONF_TRIGGER] = triggers
3737

3838
if CONF_CONDITION in config:
39-
conditions = []
40-
for cond in config[CONF_CONDITION]:
41-
cond = await condition.async_validate_condition_config(hass, cond)
42-
conditions.append(cond)
43-
config[CONF_CONDITION] = conditions
44-
45-
actions = []
46-
for action in config[CONF_ACTION]:
47-
action = await script.async_validate_action_config(hass, action)
48-
actions.append(action)
49-
config[CONF_ACTION] = actions
39+
config[CONF_CONDITION] = await asyncio.gather(
40+
*[
41+
condition.async_validate_condition_config(hass, cond)
42+
for cond in config[CONF_CONDITION]
43+
]
44+
)
45+
46+
config[CONF_ACTION] = await asyncio.gather(
47+
*[
48+
script.async_validate_action_config(hass, action)
49+
for action in config[CONF_ACTION]
50+
]
51+
)
5052

5153
return config
5254

@@ -69,16 +71,18 @@ async def _try_async_validate_config_item(hass, config, full_config=None):
6971

7072
async def async_validate_config(hass, config):
7173
"""Validate config."""
72-
automations = []
7374
validated_automations = await asyncio.gather(
7475
*(
7576
_try_async_validate_config_item(hass, p_config, config)
7677
for _, p_config in config_per_platform(config, DOMAIN)
7778
)
7879
)
79-
for validated_automation in validated_automations:
80-
if validated_automation is not None:
81-
automations.append(validated_automation)
80+
81+
automations = [
82+
validated_automation
83+
for validated_automation in validated_automations
84+
if validated_automation is not None
85+
]
8286

8387
# Create a copy of the configuration with all config for current
8488
# component removed and add validated config back in.

homeassistant/components/automation/litejet.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,13 @@ def released():
8585
cancel_pressed_more_than()
8686
cancel_pressed_more_than = None
8787
held_time = dt_util.utcnow() - pressed_time
88-
if held_less_than is not None and held_time < held_less_than:
89-
if held_more_than is None or held_time > held_more_than:
90-
hass.add_job(call_action)
88+
89+
if (
90+
held_less_than is not None
91+
and held_time < held_less_than
92+
and (held_more_than is None or held_time > held_more_than)
93+
):
94+
hass.add_job(call_action)
9195

9296
hass.data["litejet_system"].on_switch_pressed(number, pressed)
9397
hass.data["litejet_system"].on_switch_released(number, released)

homeassistant/components/automation/zone.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@ def zone_automation_listener(entity, from_s, to_s):
4747
return
4848

4949
zone_state = hass.states.get(zone_entity_id)
50-
if from_s:
51-
from_match = condition.zone(hass, zone_state, from_s)
52-
else:
53-
from_match = False
50+
from_match = condition.zone(hass, zone_state, from_s) if from_s else False
5451
to_match = condition.zone(hass, zone_state, to_s)
5552

5653
if (

tests/components/automation/test_event.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ async def test_if_fires_on_event(hass, calls):
4646

4747
hass.bus.async_fire("test_event")
4848
await hass.async_block_till_done()
49-
assert 1 == len(calls)
49+
assert len(calls) == 1
5050

5151

5252
async def test_if_fires_on_event_extra_data(hass, calls):
@@ -64,14 +64,14 @@ async def test_if_fires_on_event_extra_data(hass, calls):
6464

6565
hass.bus.async_fire("test_event", {"extra_key": "extra_data"})
6666
await hass.async_block_till_done()
67-
assert 1 == len(calls)
67+
assert len(calls) == 1
6868

6969
await common.async_turn_off(hass)
7070
await hass.async_block_till_done()
7171

7272
hass.bus.async_fire("test_event")
7373
await hass.async_block_till_done()
74-
assert 1 == len(calls)
74+
assert len(calls) == 1
7575

7676

7777
async def test_if_fires_on_event_with_data(hass, calls):
@@ -93,7 +93,7 @@ async def test_if_fires_on_event_with_data(hass, calls):
9393

9494
hass.bus.async_fire("test_event", {"some_attr": "some_value", "another": "value"})
9595
await hass.async_block_till_done()
96-
assert 1 == len(calls)
96+
assert len(calls) == 1
9797

9898

9999
async def test_if_fires_on_event_with_empty_data_config(hass, calls):
@@ -119,7 +119,7 @@ async def test_if_fires_on_event_with_empty_data_config(hass, calls):
119119

120120
hass.bus.async_fire("test_event", {"some_attr": "some_value", "another": "value"})
121121
await hass.async_block_till_done()
122-
assert 1 == len(calls)
122+
assert len(calls) == 1
123123

124124

125125
async def test_if_fires_on_event_with_nested_data(hass, calls):
@@ -143,7 +143,7 @@ async def test_if_fires_on_event_with_nested_data(hass, calls):
143143
"test_event", {"parent_attr": {"some_attr": "some_value", "another": "value"}}
144144
)
145145
await hass.async_block_till_done()
146-
assert 1 == len(calls)
146+
assert len(calls) == 1
147147

148148

149149
async def test_if_not_fires_if_event_data_not_matches(hass, calls):
@@ -165,4 +165,4 @@ async def test_if_not_fires_if_event_data_not_matches(hass, calls):
165165

166166
hass.bus.async_fire("test_event", {"some_attr": "some_other_value"})
167167
await hass.async_block_till_done()
168-
assert 0 == len(calls)
168+
assert len(calls) == 0

tests/components/automation/test_geo_location.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,11 @@ async def test_if_fires_on_zone_enter(hass, calls):
8383
)
8484
await hass.async_block_till_done()
8585

86-
assert 1 == len(calls)
86+
assert len(calls) == 1
8787
assert calls[0].context.parent_id == context.id
8888
assert (
89-
"geo_location - geo_location.entity - hello - hello - test"
90-
== calls[0].data["some"]
89+
calls[0].data["some"]
90+
== "geo_location - geo_location.entity - hello - hello - test"
9191
)
9292

9393
# Set out of zone again so we can trigger call
@@ -108,7 +108,7 @@ async def test_if_fires_on_zone_enter(hass, calls):
108108
)
109109
await hass.async_block_till_done()
110110

111-
assert 1 == len(calls)
111+
assert len(calls) == 1
112112

113113

114114
async def test_if_not_fires_for_enter_on_zone_leave(hass, calls):
@@ -143,7 +143,7 @@ async def test_if_not_fires_for_enter_on_zone_leave(hass, calls):
143143
)
144144
await hass.async_block_till_done()
145145

146-
assert 0 == len(calls)
146+
assert len(calls) == 0
147147

148148

149149
async def test_if_fires_on_zone_leave(hass, calls):
@@ -178,7 +178,7 @@ async def test_if_fires_on_zone_leave(hass, calls):
178178
)
179179
await hass.async_block_till_done()
180180

181-
assert 1 == len(calls)
181+
assert len(calls) == 1
182182

183183

184184
async def test_if_not_fires_for_leave_on_zone_enter(hass, calls):
@@ -213,7 +213,7 @@ async def test_if_not_fires_for_leave_on_zone_enter(hass, calls):
213213
)
214214
await hass.async_block_till_done()
215215

216-
assert 0 == len(calls)
216+
assert len(calls) == 0
217217

218218

219219
async def test_if_fires_on_zone_appear(hass, calls):
@@ -258,10 +258,10 @@ async def test_if_fires_on_zone_appear(hass, calls):
258258
)
259259
await hass.async_block_till_done()
260260

261-
assert 1 == len(calls)
261+
assert len(calls) == 1
262262
assert calls[0].context.parent_id == context.id
263263
assert (
264-
"geo_location - geo_location.entity - - hello - test" == calls[0].data["some"]
264+
calls[0].data["some"] == "geo_location - geo_location.entity - - hello - test"
265265
)
266266

267267

@@ -308,7 +308,7 @@ async def test_if_fires_on_zone_disappear(hass, calls):
308308
hass.states.async_remove("geo_location.entity")
309309
await hass.async_block_till_done()
310310

311-
assert 1 == len(calls)
311+
assert len(calls) == 1
312312
assert (
313-
"geo_location - geo_location.entity - hello - - test" == calls[0].data["some"]
313+
calls[0].data["some"] == "geo_location - geo_location.entity - hello - - test"
314314
)

tests/components/automation/test_init.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ async def test_service_specify_entity_id(hass, calls):
148148

149149
hass.bus.async_fire("test_event")
150150
await hass.async_block_till_done()
151-
assert 1 == len(calls)
151+
assert len(calls) == 1
152152
assert ["hello.world"] == calls[0].data.get(ATTR_ENTITY_ID)
153153

154154

@@ -170,7 +170,7 @@ async def test_service_specify_entity_id_list(hass, calls):
170170

171171
hass.bus.async_fire("test_event")
172172
await hass.async_block_till_done()
173-
assert 1 == len(calls)
173+
assert len(calls) == 1
174174
assert ["hello.world", "hello.world2"] == calls[0].data.get(ATTR_ENTITY_ID)
175175

176176

@@ -192,10 +192,10 @@ async def test_two_triggers(hass, calls):
192192

193193
hass.bus.async_fire("test_event")
194194
await hass.async_block_till_done()
195-
assert 1 == len(calls)
195+
assert len(calls) == 1
196196
hass.states.async_set("test.entity", "hello")
197197
await hass.async_block_till_done()
198-
assert 2 == len(calls)
198+
assert len(calls) == 2
199199

200200

201201
async def test_trigger_service_ignoring_condition(hass, calls):
@@ -268,17 +268,17 @@ async def test_two_conditions_with_and(hass, calls):
268268
hass.states.async_set(entity_id, 100)
269269
hass.bus.async_fire("test_event")
270270
await hass.async_block_till_done()
271-
assert 1 == len(calls)
271+
assert len(calls) == 1
272272

273273
hass.states.async_set(entity_id, 101)
274274
hass.bus.async_fire("test_event")
275275
await hass.async_block_till_done()
276-
assert 1 == len(calls)
276+
assert len(calls) == 1
277277

278278
hass.states.async_set(entity_id, 151)
279279
hass.bus.async_fire("test_event")
280280
await hass.async_block_till_done()
281-
assert 1 == len(calls)
281+
assert len(calls) == 1
282282

283283

284284
async def test_automation_list_setting(hass, calls):
@@ -302,11 +302,11 @@ async def test_automation_list_setting(hass, calls):
302302

303303
hass.bus.async_fire("test_event")
304304
await hass.async_block_till_done()
305-
assert 1 == len(calls)
305+
assert len(calls) == 1
306306

307307
hass.bus.async_fire("test_event_2")
308308
await hass.async_block_till_done()
309-
assert 2 == len(calls)
309+
assert len(calls) == 2
310310

311311

312312
async def test_automation_calling_two_actions(hass, calls):
@@ -368,15 +368,15 @@ async def test_shared_context(hass, calls):
368368
assert event_mock.call_count == 2
369369

370370
# Verify automation triggered evenet for 'hello' automation
371-
args, kwargs = event_mock.call_args_list[0]
371+
args, _ = event_mock.call_args_list[0]
372372
first_trigger_context = args[0].context
373373
assert first_trigger_context.parent_id == context.id
374374
# Ensure event data has all attributes set
375375
assert args[0].data.get(ATTR_NAME) is not None
376376
assert args[0].data.get(ATTR_ENTITY_ID) is not None
377377

378378
# Ensure context set correctly for event fired by 'hello' automation
379-
args, kwargs = first_automation_listener.call_args
379+
args, _ = first_automation_listener.call_args
380380
assert args[0].context is first_trigger_context
381381

382382
# Ensure the 'hello' automation state has the right context
@@ -385,7 +385,7 @@ async def test_shared_context(hass, calls):
385385
assert state.context is first_trigger_context
386386

387387
# Verify automation triggered evenet for 'bye' automation
388-
args, kwargs = event_mock.call_args_list[1]
388+
args, _ = event_mock.call_args_list[1]
389389
second_trigger_context = args[0].context
390390
assert second_trigger_context.parent_id == first_trigger_context.id
391391
# Ensure event data has all attributes set

0 commit comments

Comments
 (0)