diff --git a/esphome/components/adc/__init__.py b/esphome/components/adc/__init__.py index 1bd5121998..10b7df8638 100644 --- a/esphome/components/adc/__init__.py +++ b/esphome/components/adc/__init__.py @@ -10,6 +10,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S2, VARIANT_ESP32S3, ) +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_ANALOG, @@ -19,7 +20,6 @@ from esphome.const import ( PlatformFramework, ) from esphome.core import CORE -from esphome.helpers import filter_source_files_from_platform CODEOWNERS = ["@esphome/core"] diff --git a/esphome/components/debug/__init__.py b/esphome/components/debug/__init__.py index 0a5756b8bd..500dfac1fe 100644 --- a/esphome/components/debug/__init__.py +++ b/esphome/components/debug/__init__.py @@ -1,4 +1,5 @@ import esphome.codegen as cg +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_BLOCK, @@ -9,7 +10,6 @@ from esphome.const import ( CONF_LOOP_TIME, PlatformFramework, ) -from esphome.helpers import filter_source_files_from_platform CODEOWNERS = ["@OttoWinter"] DEPENDENCIES = ["logger"] diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py index 5df9a23e47..55826f52bb 100644 --- a/esphome/components/deep_sleep/__init__.py +++ b/esphome/components/deep_sleep/__init__.py @@ -11,6 +11,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S2, VARIANT_ESP32S3, ) +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_DEFAULT, @@ -29,7 +30,6 @@ from esphome.const import ( PLATFORM_ESP8266, PlatformFramework, ) -from esphome.helpers import filter_source_files_from_platform WAKEUP_PINS = { VARIANT_ESP32: [ diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 3c9f112e66..0d32bc97c2 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -2,6 +2,7 @@ from esphome import automation import esphome.codegen as cg from esphome.components import esp32 from esphome.components.const import CONF_REQUEST_HEADERS +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_ESP8266_DISABLE_SSL_SUPPORT, @@ -17,7 +18,7 @@ from esphome.const import ( __version__, ) from esphome.core import CORE, Lambda -from esphome.helpers import IS_MACOS, filter_source_files_from_platform +from esphome.helpers import IS_MACOS DEPENDENCIES = ["network"] AUTO_LOAD = ["json", "watchdog"] diff --git a/esphome/components/i2c/__init__.py b/esphome/components/i2c/__init__.py index 8b47403d67..4172b23845 100644 --- a/esphome/components/i2c/__init__.py +++ b/esphome/components/i2c/__init__.py @@ -3,6 +3,7 @@ import logging from esphome import pins import esphome.codegen as cg from esphome.components import esp32 +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_ADDRESS, @@ -22,7 +23,6 @@ from esphome.const import ( ) from esphome.core import CORE, coroutine_with_priority import esphome.final_validate as fv -from esphome.helpers import filter_source_files_from_platform LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@esphome/core"] diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 287f424467..f641c1776d 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -3,6 +3,7 @@ import logging from os.path import dirname, isfile, join import esphome.codegen as cg +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_BOARD, @@ -24,7 +25,6 @@ from esphome.const import ( __version__, ) from esphome.core import CORE -from esphome.helpers import filter_source_files_from_platform from . import gpio # noqa from .const import ( diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index 001f99623c..9ac2999696 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -21,6 +21,7 @@ from esphome.components.libretiny.const import ( COMPONENT_LN882X, COMPONENT_RTL87XX, ) +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_ARGS, @@ -45,7 +46,6 @@ from esphome.const import ( PlatformFramework, ) from esphome.core import CORE, Lambda, coroutine_with_priority -from esphome.helpers import filter_source_files_from_platform CODEOWNERS = ["@esphome/core"] logger_ns = cg.esphome_ns.namespace("logger") diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index 22f416c94f..e32d39cede 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components.esp32 import add_idf_component +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_DISABLED, @@ -11,7 +12,6 @@ from esphome.const import ( PlatformFramework, ) from esphome.core import CORE, coroutine_with_priority -from esphome.helpers import filter_source_files_from_platform CODEOWNERS = ["@esphome/core"] DEPENDENCIES = ["network"] diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 989a1a650b..1a6fcabf42 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -5,6 +5,7 @@ from esphome.automation import Condition import esphome.codegen as cg from esphome.components import logger from esphome.components.esp32 import add_idf_sdkconfig_option +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_AVAILABILITY, @@ -57,7 +58,6 @@ from esphome.const import ( PlatformFramework, ) from esphome.core import CORE, coroutine_with_priority -from esphome.helpers import filter_source_files_from_platform DEPENDENCIES = ["network"] diff --git a/esphome/components/nextion/__init__.py b/esphome/components/nextion/__init__.py index 651e0ae5a4..8adc49d68c 100644 --- a/esphome/components/nextion/__init__.py +++ b/esphome/components/nextion/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg from esphome.components import uart +from esphome.config_helpers import filter_source_files_from_platform from esphome.const import PlatformFramework -from esphome.helpers import filter_source_files_from_platform nextion_ns = cg.esphome_ns.namespace("nextion") Nextion = nextion_ns.class_("Nextion", cg.PollingComponent, uart.UARTDevice) diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index 83e637342b..4d5b8a61e2 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -1,5 +1,6 @@ from esphome import automation import esphome.codegen as cg +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_ESPHOME, @@ -10,7 +11,6 @@ from esphome.const import ( PlatformFramework, ) from esphome.core import CORE, coroutine_with_priority -from esphome.helpers import filter_source_files_from_platform CODEOWNERS = ["@esphome/core"] AUTO_LOAD = ["md5", "safe_mode"] diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index 82efe36879..dffc088085 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -1,6 +1,7 @@ from esphome import pins import esphome.codegen as cg from esphome.components import esp32, esp32_rmt, remote_base +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_BUFFER_SIZE, @@ -18,7 +19,6 @@ from esphome.const import ( PlatformFramework, ) from esphome.core import CORE, TimePeriod -from esphome.helpers import filter_source_files_from_platform CONF_FILTER_SYMBOLS = "filter_symbols" CONF_RECEIVE_SYMBOLS = "receive_symbols" diff --git a/esphome/components/remote_transmitter/__init__.py b/esphome/components/remote_transmitter/__init__.py index dbda8a7752..47a46ff56b 100644 --- a/esphome/components/remote_transmitter/__init__.py +++ b/esphome/components/remote_transmitter/__init__.py @@ -1,6 +1,7 @@ from esphome import automation, pins import esphome.codegen as cg from esphome.components import esp32, esp32_rmt, remote_base +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_CARRIER_DUTY_PERCENT, @@ -15,7 +16,6 @@ from esphome.const import ( PlatformFramework, ) from esphome.core import CORE -from esphome.helpers import filter_source_files_from_platform AUTO_LOAD = ["remote_base"] diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index d949da0a60..58bfc3f411 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -13,6 +13,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S2, VARIANT_ESP32S3, ) +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_CLK_PIN, @@ -35,7 +36,6 @@ from esphome.const import ( ) from esphome.core import CORE, coroutine_with_priority import esphome.final_validate as fv -from esphome.helpers import filter_source_files_from_platform CODEOWNERS = ["@esphome/core", "@clydebarrow"] spi_ns = cg.esphome_ns.namespace("spi") diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index 1bfcef8f61..7d4c6360fe 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -2,6 +2,7 @@ import re from esphome import automation, pins import esphome.codegen as cg +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_AFTER, @@ -31,7 +32,6 @@ from esphome.const import ( ) from esphome.core import CORE import esphome.final_validate as fv -from esphome.helpers import filter_source_files_from_platform from esphome.yaml_util import make_data_base CODEOWNERS = ["@esphome/core"] diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index a5a88862bf..cb98325427 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -3,6 +3,7 @@ from esphome.automation import Condition import esphome.codegen as cg from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant from esphome.components.network import IPAddress +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_AP, @@ -43,7 +44,6 @@ from esphome.const import ( ) from esphome.core import CORE, HexInt, coroutine_with_priority import esphome.final_validate as fv -from esphome.helpers import filter_source_files_from_platform from . import wpa2_eap diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py index 54242bc259..5ecd665abe 100644 --- a/esphome/config_helpers.py +++ b/esphome/config_helpers.py @@ -1,4 +1,13 @@ -from esphome.const import CONF_ID +from collections.abc import Callable + +from esphome.const import ( + CONF_ID, + KEY_CORE, + KEY_TARGET_FRAMEWORK, + KEY_TARGET_PLATFORM, + PlatformFramework, +) +from esphome.core import CORE class Extend: @@ -103,3 +112,45 @@ def merge_config(full_old, full_new): return new return merge(full_old, full_new) + + +def filter_source_files_from_platform( + files_map: dict[str, set[PlatformFramework]], +) -> Callable[[], list[str]]: + """Helper to build a FILTER_SOURCE_FILES function from platform mapping. + + Args: + files_map: Dict mapping filename to set of PlatformFramework enums + that should compile this file + + Returns: + Function that returns list of files to exclude for current platform + """ + # Pre-build lookup map from (platform, framework) tuples to PlatformFramework enum + _PLATFORM_FRAMEWORK_LOOKUP = {pf.value: pf for pf in PlatformFramework} + + def filter_source_files() -> list[str]: + # Get current platform/framework + core_data = CORE.data.get(KEY_CORE, {}) + target_platform = core_data.get(KEY_TARGET_PLATFORM) + target_framework = core_data.get(KEY_TARGET_FRAMEWORK) + + if not target_platform or not target_framework: + return [] + + # Direct lookup of current PlatformFramework + current_platform_framework = _PLATFORM_FRAMEWORK_LOOKUP.get( + (target_platform, target_framework) + ) + + if not current_platform_framework: + return [] + + # Return files that should be excluded for current platform + return [ + filename + for filename, platforms in files_map.items() + if current_platform_framework not in platforms + ] + + return filter_source_files diff --git a/esphome/core/config.py b/esphome/core/config.py index 4dc2e67e1d..f73369f28f 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -6,6 +6,7 @@ from pathlib import Path from esphome import automation, core import esphome.codegen as cg +from esphome.config_helpers import filter_source_files_from_platform import esphome.config_validation as cv from esphome.const import ( CONF_AREA, @@ -41,7 +42,6 @@ from esphome.const import ( from esphome.core import CORE, coroutine_with_priority from esphome.helpers import ( copy_file_if_changed, - filter_source_files_from_platform, fnv1a_32bit_hash, get_str_env, walk_files, diff --git a/esphome/helpers.py b/esphome/helpers.py index 7df2fbdea2..bf0e3b5cf7 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -1,5 +1,4 @@ import codecs -from collections.abc import Callable from contextlib import suppress import ipaddress import logging @@ -8,12 +7,8 @@ from pathlib import Path import platform import re import tempfile -from typing import TYPE_CHECKING from urllib.parse import urlparse -if TYPE_CHECKING: - from esphome.const import PlatformFramework - _LOGGER = logging.getLogger(__name__) IS_MACOS = platform.system() == "Darwin" @@ -510,54 +505,3 @@ _DISALLOWED_CHARS = re.compile(r"[^a-zA-Z0-9-_]") def sanitize(value): """Same behaviour as `helpers.cpp` method `str_sanitize`.""" return _DISALLOWED_CHARS.sub("_", value) - - -def filter_source_files_from_platform( - files_map: dict[str, set["PlatformFramework"]], -) -> Callable[[], list[str]]: - """Helper to build a FILTER_SOURCE_FILES function from platform mapping. - - Args: - files_map: Dict mapping filename to set of PlatformFramework enums - that should compile this file - - Returns: - Function that returns list of files to exclude for current platform - """ - # Import here to avoid circular imports - from esphome.const import ( - KEY_CORE, - KEY_TARGET_FRAMEWORK, - KEY_TARGET_PLATFORM, - PlatformFramework, - ) - from esphome.core import CORE - - # Pre-build lookup map from (platform, framework) tuples to PlatformFramework enum - _PLATFORM_FRAMEWORK_LOOKUP = {pf.value: pf for pf in PlatformFramework} - - def filter_source_files() -> list[str]: - # Get current platform/framework - core_data = CORE.data.get(KEY_CORE, {}) - target_platform = core_data.get(KEY_TARGET_PLATFORM) - target_framework = core_data.get(KEY_TARGET_FRAMEWORK) - - if not target_platform or not target_framework: - return [] - - # Direct lookup of current PlatformFramework - current_platform_framework = _PLATFORM_FRAMEWORK_LOOKUP.get( - (target_platform, target_framework) - ) - - if not current_platform_framework: - return [] - - # Return files that should be excluded for current platform - return [ - filename - for filename, platforms in files_map.items() - if current_platform_framework not in platforms - ] - - return filter_source_files