mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 17:05:36 +00:00
Merge branch 'templatable-value-specialize' into test_merge_to_beta_again
This commit is contained in:
@@ -9,7 +9,6 @@ from esphome.const import (
|
||||
CONF_VALUE,
|
||||
)
|
||||
from esphome.core import CoroPriority, coroutine_with_priority
|
||||
from esphome.cpp_generator import LambdaExpression
|
||||
from esphome.types import ConfigType
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
@@ -109,16 +108,8 @@ async def globals_set_to_code(config, action_id, template_arg, args):
|
||||
full_id, paren = await cg.get_variable_with_full_id(config[CONF_ID])
|
||||
template_arg = cg.TemplateArguments(full_id.type, *template_arg)
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
value = config[CONF_VALUE]
|
||||
if cg.is_template(value):
|
||||
templ = await cg.templatable(value, args, None, to_exp=cg.RawExpression)
|
||||
else:
|
||||
# Wrap raw constant in a stateless lambda for TemplatableFn storage.
|
||||
# Use RawExpression for the value since T is a template parameter
|
||||
# (the C++ compiler handles the type deduction).
|
||||
raw_value = cg.RawExpression(value)
|
||||
templ = LambdaExpression(
|
||||
f"return {cg.safe_exp(raw_value)};", args, capture="", return_type=None
|
||||
)
|
||||
templ = await cg.templatable(
|
||||
config[CONF_VALUE], args, None, to_exp=cg.RawExpression
|
||||
)
|
||||
cg.add(var.set_value(templ))
|
||||
return var
|
||||
|
||||
@@ -848,9 +848,11 @@ async def templatable(
|
||||
# Automatically wrap static strings in ESPHOME_F() for PROGMEM storage on ESP8266.
|
||||
# On other platforms ESPHOME_F() is a no-op returning const char*.
|
||||
return FlashStringLiteral(value)
|
||||
# For non-string types, wrap constants in stateless lambdas so that
|
||||
# TemplatableFn (used by TEMPLATABLE_VALUE macro) stores them as function pointers.
|
||||
if output_type is not None and output_type is not std_string:
|
||||
# Wrap non-string constants in stateless lambdas so that TemplatableFn
|
||||
# (used by TEMPLATABLE_VALUE macro) stores them as function pointers.
|
||||
# When output_type is None, the lambda omits the return type annotation
|
||||
# and the C++ compiler deduces it (used by globals where T is unknown).
|
||||
if output_type is not std_string:
|
||||
return LambdaExpression(
|
||||
f"return {safe_exp(value)};",
|
||||
args,
|
||||
|
||||
@@ -652,11 +652,11 @@ async def test_templatable__empty_string_with_std_string() -> None:
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_templatable__string_with_none_output_type() -> None:
|
||||
"""Static string with output_type=None returns raw string (no wrapping)."""
|
||||
"""Static string with output_type=None returns stateless lambda (no return type)."""
|
||||
result = await cg.templatable("hello", [], None)
|
||||
|
||||
assert isinstance(result, str)
|
||||
assert result == "hello"
|
||||
assert isinstance(result, cg.LambdaExpression)
|
||||
assert result.capture == ""
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -678,10 +678,11 @@ async def test_templatable__string_with_non_string_output_type() -> None:
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_templatable__with_to_exp_callable() -> None:
|
||||
"""When to_exp is provided, it is applied to non-template values."""
|
||||
"""When to_exp is provided with output_type=None, result is lambda-wrapped."""
|
||||
result = await cg.templatable(42, [], None, to_exp=lambda x: x * 2)
|
||||
|
||||
assert result == 84
|
||||
assert isinstance(result, cg.LambdaExpression)
|
||||
assert result.capture == ""
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -695,11 +696,12 @@ async def test_templatable__with_to_exp_callable_and_output_type() -> None:
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_templatable__with_to_exp_dict() -> None:
|
||||
"""When to_exp is a dict, value is looked up."""
|
||||
"""When to_exp is a dict, value is looked up and lambda-wrapped."""
|
||||
mapping: dict[str, int] = {"on": 1, "off": 0}
|
||||
result = await cg.templatable("on", [], None, to_exp=mapping)
|
||||
|
||||
assert result == 1
|
||||
assert isinstance(result, cg.LambdaExpression)
|
||||
assert result.capture == ""
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user