Merge pull request #12752 from esphome/bump-2025.12.3

2025.12.3
This commit is contained in:
Jonathan Swoboda
2025-12-30 09:31:31 -05:00
committed by GitHub
7 changed files with 115 additions and 23 deletions

View File

@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 2025.12.2
PROJECT_NUMBER = 2025.12.3
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@@ -5,7 +5,7 @@ Constants already defined in esphome.const are not duplicated here and must be i
"""
import logging
from typing import TYPE_CHECKING, Any
from typing import Any
from esphome import codegen as cg, config_validation as cv
from esphome.const import CONF_ITEMS
@@ -96,13 +96,9 @@ class LValidator:
return None
if isinstance(value, Lambda):
# Local import to avoid circular import
from .lvcode import CodeContext, LambdaContext
from .lvcode import get_lambda_context_args
if TYPE_CHECKING:
# CodeContext does not have get_automation_parameters
# so we need to assert the type here
assert isinstance(CodeContext.code_context, LambdaContext)
args = args or CodeContext.code_context.get_automation_parameters()
args = args or get_lambda_context_args()
return cg.RawExpression(
call_lambda(
await cg.process_lambda(value, args, return_type=self.rtype)

View File

@@ -1,5 +1,5 @@
import re
from typing import TYPE_CHECKING, Any
from typing import Any
import esphome.codegen as cg
from esphome.components import image
@@ -404,14 +404,9 @@ class TextValidator(LValidator):
self, value: Any, args: list[tuple[SafeExpType, str]] | None = None
) -> Expression:
# Local import to avoid circular import at module level
from .lvcode import get_lambda_context_args
from .lvcode import CodeContext, LambdaContext
if TYPE_CHECKING:
# CodeContext does not have get_automation_parameters
# so we need to assert the type here
assert isinstance(CodeContext.code_context, LambdaContext)
args = args or CodeContext.code_context.get_automation_parameters()
args = args or get_lambda_context_args()
if isinstance(value, dict):
if format_str := value.get(CONF_FORMAT):

View File

@@ -1,4 +1,5 @@
import abc
from typing import TYPE_CHECKING
from esphome import codegen as cg
from esphome.config import Config
@@ -200,6 +201,21 @@ class LvContext(LambdaContext):
return self.add(*args)
def get_lambda_context_args() -> list[tuple[SafeExpType, str]]:
"""Get automation parameters from the current lambda context if available.
When called from outside LVGL's context (e.g., from interval),
CodeContext.code_context will be None, so return empty args.
"""
if CodeContext.code_context is None:
return []
if TYPE_CHECKING:
# CodeContext base class doesn't define get_automation_parameters(),
# but LambdaContext and LvContext (the concrete implementations) do.
assert isinstance(CodeContext.code_context, LambdaContext)
return CodeContext.code_context.get_automation_parameters()
class LocalVariable(MockObj):
"""
Create a local variable and enclose the code using it within a block.

View File

@@ -4,7 +4,7 @@ from enum import Enum
from esphome.enum import StrEnum
__version__ = "2025.12.2"
__version__ = "2025.12.3"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
VALID_SUBSTITUTIONS_CHARACTERS = (

View File

@@ -99,14 +99,11 @@ def storage_should_clean(old: StorageJSON | None, new: StorageJSON) -> bool:
def storage_should_update_cmake_cache(old: StorageJSON, new: StorageJSON) -> bool:
if (
# ESP32 uses CMake for both Arduino and ESP-IDF frameworks
return (
old.loaded_integrations != new.loaded_integrations
or old.loaded_platforms != new.loaded_platforms
) and new.core_platform == PLATFORM_ESP32:
from esphome.components.esp32 import FRAMEWORK_ESP_IDF
return new.framework == FRAMEWORK_ESP_IDF
return False
) and new.core_platform == PLATFORM_ESP32
def update_storage_json() -> None:

View File

@@ -9,6 +9,13 @@ from unittest.mock import MagicMock, patch
import pytest
from esphome.const import (
PLATFORM_BK72XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_RP2040,
PLATFORM_RTL87XX,
)
from esphome.core import EsphomeError
from esphome.storage_json import StorageJSON
from esphome.writer import (
@@ -21,6 +28,7 @@ from esphome.writer import (
clean_build,
clean_cmake_cache,
storage_should_clean,
storage_should_update_cmake_cache,
update_storage_json,
write_cpp,
write_gitignore,
@@ -164,6 +172,86 @@ def test_storage_edge_case_from_empty_integrations(
assert storage_should_clean(old, new) is False
# Tests for storage_should_update_cmake_cache
@pytest.mark.parametrize("framework", ["arduino", "esp-idf"])
def test_storage_should_update_cmake_cache_when_integration_added_esp32(
create_storage: Callable[..., StorageJSON],
framework: str,
) -> None:
"""Test cmake cache update triggered when integration added on ESP32."""
old = create_storage(
loaded_integrations=["api", "wifi"],
core_platform=PLATFORM_ESP32,
framework=framework,
)
new = create_storage(
loaded_integrations=["api", "wifi", "restart"],
core_platform=PLATFORM_ESP32,
framework=framework,
)
assert storage_should_update_cmake_cache(old, new) is True
def test_storage_should_update_cmake_cache_when_platform_changed_esp32(
create_storage: Callable[..., StorageJSON],
) -> None:
"""Test cmake cache update triggered when platforms change on ESP32."""
old = create_storage(
loaded_integrations=["api", "wifi"],
loaded_platforms={"sensor"},
core_platform=PLATFORM_ESP32,
framework="arduino",
)
new = create_storage(
loaded_integrations=["api", "wifi"],
loaded_platforms={"sensor", "binary_sensor"},
core_platform=PLATFORM_ESP32,
framework="arduino",
)
assert storage_should_update_cmake_cache(old, new) is True
def test_storage_should_not_update_cmake_cache_when_nothing_changes(
create_storage: Callable[..., StorageJSON],
) -> None:
"""Test cmake cache not updated when nothing changes."""
old = create_storage(
loaded_integrations=["api", "wifi"],
core_platform=PLATFORM_ESP32,
framework="arduino",
)
new = create_storage(
loaded_integrations=["api", "wifi"],
core_platform=PLATFORM_ESP32,
framework="arduino",
)
assert storage_should_update_cmake_cache(old, new) is False
@pytest.mark.parametrize(
"core_platform",
[PLATFORM_ESP8266, PLATFORM_RP2040, PLATFORM_BK72XX, PLATFORM_RTL87XX],
)
def test_storage_should_not_update_cmake_cache_for_non_esp32(
create_storage: Callable[..., StorageJSON],
core_platform: str,
) -> None:
"""Test cmake cache not updated for non-ESP32 platforms."""
old = create_storage(
loaded_integrations=["api", "wifi"],
core_platform=core_platform,
framework="arduino",
)
new = create_storage(
loaded_integrations=["api", "wifi", "restart"],
core_platform=core_platform,
framework="arduino",
)
assert storage_should_update_cmake_cache(old, new) is False
@patch("esphome.writer.clean_build")
@patch("esphome.writer.StorageJSON")
@patch("esphome.writer.storage_path")