mirror of
https://github.com/esphome/esphome.git
synced 2026-02-24 10:18:23 -07:00
tweaks
This commit is contained in:
@@ -62,14 +62,16 @@ def register_action(
|
||||
action_type: MockObjClass,
|
||||
schema: cv.Schema,
|
||||
*,
|
||||
deferred: bool = False,
|
||||
deferred: bool = True,
|
||||
):
|
||||
"""Register an action type.
|
||||
|
||||
Set ``deferred=True`` if this action stores trigger arguments for later
|
||||
execution (e.g. delay, wait_until, script.wait). This tells the code
|
||||
generator to use owning types (std::string) instead of non-owning views
|
||||
(StringRef) for string arguments, preventing dangling references.
|
||||
Actions default to ``deferred=True`` (safe default), meaning string
|
||||
arguments use owning std::string to prevent dangling references.
|
||||
|
||||
Set ``deferred=False`` only for actions that complete synchronously
|
||||
and never store trigger arguments for later execution. This allows
|
||||
the code generator to use non-owning StringRef for zero-copy access.
|
||||
"""
|
||||
return ACTION_REGISTRY.register(name, action_type, schema, deferred=deferred)
|
||||
|
||||
@@ -351,7 +353,6 @@ async def component_is_idle_condition_to_code(
|
||||
"delay",
|
||||
DelayAction,
|
||||
cv.templatable(cv.positive_time_period_milliseconds),
|
||||
deferred=True,
|
||||
)
|
||||
async def delay_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -382,6 +383,7 @@ async def delay_action_to_code(
|
||||
cv.has_at_least_one_key(CONF_THEN, CONF_ELSE),
|
||||
cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL),
|
||||
),
|
||||
deferred=False,
|
||||
)
|
||||
async def if_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -410,6 +412,7 @@ async def if_action_to_code(
|
||||
cv.Required(CONF_THEN): validate_action_list,
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
)
|
||||
async def while_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -433,6 +436,7 @@ async def while_action_to_code(
|
||||
cv.Required(CONF_THEN): validate_action_list,
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
)
|
||||
async def repeat_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -461,7 +465,7 @@ _validate_wait_until = cv.maybe_simple_value(
|
||||
)
|
||||
|
||||
|
||||
@register_action("wait_until", WaitUntilAction, _validate_wait_until, deferred=True)
|
||||
@register_action("wait_until", WaitUntilAction, _validate_wait_until)
|
||||
async def wait_until_action_to_code(
|
||||
config: ConfigType,
|
||||
action_id: ID,
|
||||
@@ -477,7 +481,7 @@ async def wait_until_action_to_code(
|
||||
return var
|
||||
|
||||
|
||||
@register_action("lambda", LambdaAction, cv.lambda_)
|
||||
@register_action("lambda", LambdaAction, cv.lambda_, deferred=False)
|
||||
async def lambda_action_to_code(
|
||||
config: ConfigType,
|
||||
action_id: ID,
|
||||
@@ -496,6 +500,7 @@ async def lambda_action_to_code(
|
||||
cv.Required(CONF_ID): cv.use_id(cg.PollingComponent),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
)
|
||||
async def component_update_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -515,6 +520,7 @@ async def component_update_action_to_code(
|
||||
cv.Required(CONF_ID): cv.use_id(cg.PollingComponent),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
)
|
||||
async def component_suspend_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -537,6 +543,7 @@ async def component_suspend_action_to_code(
|
||||
),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
)
|
||||
async def component_resume_action_to_code(
|
||||
config: ConfigType,
|
||||
|
||||
@@ -172,7 +172,9 @@ BLE_REMOVE_BOND_ACTION_SCHEMA = cv.Schema(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"ble_client.disconnect", BLEDisconnectAction, BLE_CONNECT_ACTION_SCHEMA
|
||||
"ble_client.disconnect",
|
||||
BLEDisconnectAction,
|
||||
BLE_CONNECT_ACTION_SCHEMA,
|
||||
)
|
||||
async def ble_disconnect_to_code(config, action_id, template_arg, args):
|
||||
parent = await cg.get_variable(config[CONF_ID])
|
||||
@@ -180,7 +182,9 @@ async def ble_disconnect_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"ble_client.connect", BLEConnectAction, BLE_CONNECT_ACTION_SCHEMA
|
||||
"ble_client.connect",
|
||||
BLEConnectAction,
|
||||
BLE_CONNECT_ACTION_SCHEMA,
|
||||
)
|
||||
async def ble_connect_to_code(config, action_id, template_arg, args):
|
||||
parent = await cg.get_variable(config[CONF_ID])
|
||||
@@ -188,7 +192,9 @@ async def ble_connect_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"ble_client.ble_write", BLEWriteAction, BLE_WRITE_ACTION_SCHEMA
|
||||
"ble_client.ble_write",
|
||||
BLEWriteAction,
|
||||
BLE_WRITE_ACTION_SCHEMA,
|
||||
)
|
||||
async def ble_write_to_code(config, action_id, template_arg, args):
|
||||
parent = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -160,6 +160,7 @@ async def to_code(config):
|
||||
cv.Optional(validate_parameter_name): cv.templatable(cv.valid),
|
||||
},
|
||||
),
|
||||
deferred=False,
|
||||
)
|
||||
async def script_execute_action_to_code(config, action_id, template_arg, args):
|
||||
def convert(type: str):
|
||||
@@ -208,6 +209,7 @@ async def script_execute_action_to_code(config, action_id, template_arg, args):
|
||||
"script.stop",
|
||||
ScriptStopAction,
|
||||
maybe_simple_id({cv.Required(CONF_ID): cv.use_id(Script)}),
|
||||
deferred=False,
|
||||
)
|
||||
async def script_stop_action_to_code(config, action_id, template_arg, args):
|
||||
full_id, paren = await cg.get_variable_with_full_id(config[CONF_ID])
|
||||
@@ -219,7 +221,6 @@ async def script_stop_action_to_code(config, action_id, template_arg, args):
|
||||
"script.wait",
|
||||
ScriptWaitAction,
|
||||
maybe_simple_id({cv.Required(CONF_ID): cv.use_id(Script)}),
|
||||
deferred=True,
|
||||
)
|
||||
async def script_wait_action_to_code(config, action_id, template_arg, args):
|
||||
full_id, paren = await cg.get_variable_with_full_id(config[CONF_ID])
|
||||
|
||||
@@ -25,7 +25,7 @@ class RegistryEntry:
|
||||
type_id: "MockObjClass",
|
||||
schema: "Schema",
|
||||
*,
|
||||
deferred: bool = False,
|
||||
deferred: bool = True,
|
||||
):
|
||||
self.name = name
|
||||
self.fun = fun
|
||||
@@ -58,7 +58,7 @@ class Registry(dict[str, RegistryEntry]):
|
||||
type_id: "MockObjClass",
|
||||
schema: "Schema",
|
||||
*,
|
||||
deferred: bool = False,
|
||||
deferred: bool = True,
|
||||
):
|
||||
def decorator(fun: Callable[..., Any]):
|
||||
self[name] = RegistryEntry(name, fun, type_id, schema, deferred=deferred)
|
||||
|
||||
@@ -10,10 +10,13 @@ from esphome.util import RegistryEntry
|
||||
|
||||
|
||||
def _make_registry(deferred_actions: set[str]) -> dict[str, RegistryEntry]:
|
||||
"""Create a mock ACTION_REGISTRY with specified deferred actions."""
|
||||
"""Create a mock ACTION_REGISTRY with specified deferred actions.
|
||||
|
||||
Uses the default deferred=True, matching the real registry behavior.
|
||||
"""
|
||||
registry: dict[str, RegistryEntry] = {}
|
||||
for name in deferred_actions:
|
||||
registry[name] = RegistryEntry(name, lambda: None, None, None, deferred=True)
|
||||
registry[name] = RegistryEntry(name, lambda: None, None, None)
|
||||
return registry
|
||||
|
||||
|
||||
@@ -72,10 +75,23 @@ def test_has_deferred_actions_non_deferred(
|
||||
assert has_deferred_actions([{"logger.log": "hello"}]) is False
|
||||
|
||||
|
||||
def test_has_deferred_actions_unknown(mock_registry: dict[str, RegistryEntry]) -> None:
|
||||
def test_has_deferred_actions_unknown_not_in_registry(
|
||||
mock_registry: dict[str, RegistryEntry],
|
||||
) -> None:
|
||||
"""Unknown actions not in registry are not flagged (only registered actions count)."""
|
||||
assert has_deferred_actions([{"unknown.action": "value"}]) is False
|
||||
|
||||
|
||||
def test_has_deferred_actions_default_deferred(
|
||||
mock_registry: dict[str, RegistryEntry],
|
||||
) -> None:
|
||||
"""Actions registered without explicit deferred=False default to deferred=True."""
|
||||
mock_registry["some.action"] = RegistryEntry(
|
||||
"some.action", lambda: None, None, None
|
||||
)
|
||||
assert has_deferred_actions([{"some.action": "value"}]) is True
|
||||
|
||||
|
||||
def test_has_deferred_actions_nested_in_then(
|
||||
mock_registry: dict[str, RegistryEntry],
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user