From 78a0ffb8127d735971a17ff9e52175da254cfe50 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 15 Oct 2026 00:15:51 +1300 Subject: [PATCH] [core] Drop unused return values from FINAL_VALIDATE_SCHEMA validators loader.py declares final_validate_schema as Callable[[ConfigType], None] and config.py discards whatever it returns, so a validator wired straight to FINAL_VALIDATE_SCHEMA that ends in "return config" implies the value matters when it does not. Drop those returns and annotate the functions -> None. Validators composed into a cv.All still return their config, since each one feeds the next. Returned validation calls are kept as plain statements so no validation step is lost. --- esphome/components/audio_http/media_source.py | 9 ++++----- esphome/components/cdc_acm_uart/bridge/__init__.py | 3 +-- esphome/components/ecocomfort2/__init__.py | 3 +-- .../esp32_power_management/power_management.py | 3 +-- esphome/components/espnow/__init__.py | 7 +++---- esphome/components/homeassistant/__init__.py | 5 ++--- esphome/components/image/__init__.py | 5 ++--- esphome/components/mipi_rgb/display.py | 2 +- esphome/components/sendspin/__init__.py | 3 +-- esphome/components/sendspin/switch/__init__.py | 5 ++--- esphome/components/serial_proxy/__init__.py | 3 +-- esphome/components/spi/__init__.py | 5 ++--- esphome/components/tas58xx/binary_sensor.py | 5 ++--- esphome/components/teleinfo/__init__.py | 3 +-- esphome/components/tfluna/button/__init__.py | 3 +-- esphome/components/tmc2209/sensor/__init__.py | 5 ++--- esphome/components/tmc22xx/__init__.py | 3 +-- esphome/components/tmp102/binary_sensor.py | 4 ++-- esphome/components/tmp102/number.py | 3 +-- esphome/components/tmp102/text_sensor.py | 4 ++-- esphome/components/uart_mux/__init__.py | 3 +-- esphome/components/uart_tcp/__init__.py | 3 +-- esphome/components/usb_host/__init__.py | 3 +-- tests/component_tests/animation/test_init.py | 6 ++++-- tests/component_tests/online_image/test_init.py | 6 ++++-- .../sendspin/test_unpaired_access.py | 6 ++++-- tests/unit_tests/components/test_audio_http.py | 3 ++- tests/unit_tests/components/test_espnow.py | 14 +++++++------- tests/unit_tests/components/test_usb_host.py | 6 ++---- 29 files changed, 59 insertions(+), 74 deletions(-) diff --git a/esphome/components/audio_http/media_source.py b/esphome/components/audio_http/media_source.py index 6c491379c89..740e27238bd 100644 --- a/esphome/components/audio_http/media_source.py +++ b/esphome/components/audio_http/media_source.py @@ -29,7 +29,7 @@ def _request_micro_decoder(config: ConfigType) -> ConfigType: return config -def _inherit_ca_certificate_path(config: ConfigType) -> ConfigType: +def _inherit_ca_certificate_path(config: ConfigType) -> None: # Default to the CA certificate configured on the http_request component so # HTTPS playback verifies against the same trust anchor without repeating # the option on every source. Needed because audio_http sources are often @@ -37,15 +37,15 @@ def _inherit_ca_certificate_path(config: ConfigType) -> ConfigType: # The PEM replaces the built-in certificate bundle as the sole trust anchor, # so make the inheritance visible in the log. if CONF_CA_CERTIFICATE_PATH in config: - return config + return fconf = fv.full_config.get() if CONF_HTTP_REQUEST not in fconf: - return config + return http_request_config = fconf[CONF_HTTP_REQUEST] # Mirror http_request's own semantics: it only applies its CA when SSL # verification is enabled, so neither does the inheritance. if not http_request_config.get(CONF_VERIFY_SSL, True): - return config + return if ca_cert_path := http_request_config.get(CONF_CA_CERTIFICATE_PATH): _LOGGER.info( "audio_http source '%s' is inheriting ca_certificate_path from the " @@ -55,7 +55,6 @@ def _inherit_ca_certificate_path(config: ConfigType) -> ConfigType: ) # Already validated by http_request's schema; the value is a resolved Path. config[CONF_CA_CERTIFICATE_PATH] = ca_cert_path - return config FINAL_VALIDATE_SCHEMA = _inherit_ca_certificate_path diff --git a/esphome/components/cdc_acm_uart/bridge/__init__.py b/esphome/components/cdc_acm_uart/bridge/__init__.py index 133ea92a483..98dda70e5d7 100644 --- a/esphome/components/cdc_acm_uart/bridge/__init__.py +++ b/esphome/components/cdc_acm_uart/bridge/__init__.py @@ -48,7 +48,7 @@ def _reject_debug(uart_conf: ConfigType) -> ConfigType: return uart_conf -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() # Bridges of any platform must own their interfaces exclusively; shared ring # buffers and overwritten callbacks would corrupt both streams silently. The @@ -81,7 +81,6 @@ def _final_validate(config: ConfigType) -> ConfigType: ) fv.id_declaration_match_schema(_reject_debug)(config[CONF_UART_ID]) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/ecocomfort2/__init__.py b/esphome/components/ecocomfort2/__init__.py index 8a0e1654188..fb68c6ce7a2 100644 --- a/esphome/components/ecocomfort2/__init__.py +++ b/esphome/components/ecocomfort2/__init__.py @@ -57,7 +57,7 @@ async def to_code(config: ConfigType) -> None: cg.add(var.set_time(await cg.get_variable(time_id))) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: # The unit only talks over an encrypted, bonded link ble_conf = fv.full_config.get()[esp32_ble.DOMAIN] if ( @@ -69,7 +69,6 @@ def _final_validate(config: ConfigType) -> ConfigType: "ecocomfort2 needs esp32_ble configured with io_capability: none, " "auth_req_mode: sc_bond and max_key_size: 16" ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/esp32_power_management/power_management.py b/esphome/components/esp32_power_management/power_management.py index e9b6d6462cd..7ac4b4744d9 100644 --- a/esphome/components/esp32_power_management/power_management.py +++ b/esphome/components/esp32_power_management/power_management.py @@ -206,7 +206,7 @@ async def to_code(config: ConfigType) -> None: add_idf_sdkconfig_option("CONFIG_IEEE802154_SLEEP_ENABLE", True) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() entries = full_config.get(power_management.DOMAIN, []) if sum(entry.get(CONF_PLATFORM) == DOMAIN for entry in entries) > 1: @@ -248,7 +248,6 @@ def _final_validate(config: ConfigType) -> ConfigType: f"{CONF_POWER_DOWN_FLASH} is not allowed when the device has PSRAM", path=[CONF_POWER_DOWN_FLASH], ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/espnow/__init__.py b/esphome/components/espnow/__init__.py index e5abb16b1c3..52791429fc6 100644 --- a/esphome/components/espnow/__init__.py +++ b/esphome/components/espnow/__init__.py @@ -148,21 +148,20 @@ CONFIG_SCHEMA = cv.All( ) -def _validate_variant(config: ConfigType) -> ConfigType: +def _validate_variant(config: ConfigType) -> None: # ESP-NOW rides the Wi-Fi PHY. Radio-less esp32 variants have no native # ESP-NOW; only the ESP32-P4 has a path, via the esp32_hosted shim that # supplies the esp_now_* symbols. Fail here with a clear message instead of # letting the build reach an "undefined reference to esp_now_*" link error. if not CORE.is_esp32: - return config + return variant = get_esp32_variant() if wifi.variant_has_wifi(variant): - return config + return if variant != VARIANT_ESP32P4: raise cv.Invalid(f"ESP-NOW is not supported on {variant} (no Wi-Fi radio)") if ESP32_HOSTED_DOMAIN not in fv.full_config.get(): raise cv.Invalid(f"ESP-NOW on {variant} requires the esp32_hosted component") - return config FINAL_VALIDATE_SCHEMA = _validate_variant diff --git a/esphome/components/homeassistant/__init__.py b/esphome/components/homeassistant/__init__.py index 3851bc3c0bc..4d2270f6f84 100644 --- a/esphome/components/homeassistant/__init__.py +++ b/esphome/components/homeassistant/__init__.py @@ -44,10 +44,10 @@ HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA = cv.Schema( ) -def final_validate_entity_id(config: ConfigType) -> ConfigType: +def final_validate_entity_id(config: ConfigType) -> None: """Without an entity_id, the entity must be a wizard input, as Home Assistant then supplies it.""" if CONF_ENTITY_ID in config: - return config + return from esphome.components.api import wizard if config[CONF_ID].id not in wizard.wizard_input_ids( @@ -56,7 +56,6 @@ def final_validate_entity_id(config: ConfigType) -> ConfigType: raise cv.Invalid( f"{CONF_ENTITY_ID} is required unless this entity is a wizard input" ) - return config def setup_home_assistant_entity(var: MockObj, config: ConfigType) -> None: diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index 668a78f3cbf..2e880d6c583 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -599,7 +599,7 @@ def legacy_platform_migration_warning( domain: str, platform: str, removal_version: str ) -> tuple[ Callable[[ConfigType], ConfigType], - Callable[[ConfigType], ConfigType], + Callable[[ConfigType], None], ]: """Build the per-entry capture and one-shot warning validators for a deprecated top-level component that is now an ``image:`` platform. @@ -618,7 +618,7 @@ def legacy_platform_migration_warning( data.setdefault(entries_key, []).append(dict(config)) return config - def finalize(config: ConfigType) -> ConfigType: + def finalize(config: ConfigType) -> None: data = CORE.data.setdefault(domain, {}) if not data.get(shown_key): data[shown_key] = True @@ -639,7 +639,6 @@ def legacy_platform_migration_warning( domain, yaml_util.dump({DOMAIN: migrated}), ) - return config return capture, finalize diff --git a/esphome/components/mipi_rgb/display.py b/esphome/components/mipi_rgb/display.py index 71234c2f25b..21057190290 100644 --- a/esphome/components/mipi_rgb/display.py +++ b/esphome/components/mipi_rgb/display.py @@ -264,7 +264,7 @@ def _final_validate(config: ConfigType) -> None: # If no drawing methods are configured, and LVGL is not enabled, show a test card config[CONF_SHOW_TEST_CARD] = True if CONF_SPI_ID in config: - config = spi.final_validate_device_schema( + spi.final_validate_device_schema( "mipi_rgb", require_miso=False, require_mosi=True )(config) diff --git a/esphome/components/sendspin/__init__.py b/esphome/components/sendspin/__init__.py index c557a7960d2..2adf625caad 100644 --- a/esphome/components/sendspin/__init__.py +++ b/esphome/components/sendspin/__init__.py @@ -317,7 +317,7 @@ def _has_pairing_method(config: ConfigType) -> bool: return CONF_STATIC_PAIRING_CODE in config or _offers_dynamic_pairing_code(config) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: dynamic_code = _offers_dynamic_pairing_code(config) # The protocol allows only one pairing code method. if dynamic_code and CONF_STATIC_PAIRING_CODE in config: @@ -334,7 +334,6 @@ def _final_validate(config: ConfigType) -> ConfigType: CONF_UNPAIRED_ACCESS, CONF_STATIC_PAIRING_CODE, ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/sendspin/switch/__init__.py b/esphome/components/sendspin/switch/__init__.py index 63d30d0c033..32869a8eb12 100644 --- a/esphome/components/sendspin/switch/__init__.py +++ b/esphome/components/sendspin/switch/__init__.py @@ -65,7 +65,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() switch_type = config[CONF_TYPE] same_type = [ @@ -77,7 +77,7 @@ def _final_validate(config: ConfigType) -> ConfigType: if len(same_type) > 1: raise cv.Invalid(f"Only one sendspin '{switch_type}' switch is allowed") if switch_type != CONF_UNPAIRED_ACCESS: - return config + return hub_config = full_config.get(DOMAIN, {}) if CONF_UNPAIRED_ACCESS in hub_config: raise cv.Invalid( @@ -91,7 +91,6 @@ def _final_validate(config: ConfigType) -> ConfigType: CONF_UNPAIRED_ACCESS, CONF_STATIC_PAIRING_CODE, ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/serial_proxy/__init__.py b/esphome/components/serial_proxy/__init__.py index a8767280504..f6c7977a7e2 100644 --- a/esphome/components/serial_proxy/__init__.py +++ b/esphome/components/serial_proxy/__init__.py @@ -76,13 +76,12 @@ CONFIG_SCHEMA = ( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: is_usb = is_usb_uart_channel(config[CONF_UART_ID], fv.full_config.get()) if config[CONF_PORT_TYPE] == "USB_SERIAL" and not is_usb: raise cv.Invalid( f"{CONF_PORT_TYPE} USB_SERIAL requires {CONF_UART_ID} to be a usb_uart channel" ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index d6949cc5909..480008c9817 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -539,13 +539,13 @@ def _walk_config(value: Any, path: tuple[Any, ...] = ()): yield from _walk_config(child, (*path, index)) -def _final_validate(config: Any) -> Any: +def _final_validate(config: Any) -> None: buses = config if isinstance(config, list) else [config] software_bus_ids = { bus[CONF_ID] for bus in buses if CONF_INTERFACE_INDEX not in bus } if not software_bus_ids: - return config + return for candidate, path in _walk_config(fv.full_config.get()): if ( candidate.get(CONF_PSRAM_DMA) @@ -553,7 +553,6 @@ def _final_validate(config: Any) -> Any: ): with cv.prepend_path([cv.ROOT_CONFIG_PATH, *path, CONF_PSRAM_DMA]): raise cv.Invalid("psram_dma requires a hardware SPI interface") - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/tas58xx/binary_sensor.py b/esphome/components/tas58xx/binary_sensor.py index d0577398741..499462f1ed0 100644 --- a/esphome/components/tas58xx/binary_sensor.py +++ b/esphome/components/tas58xx/binary_sensor.py @@ -55,13 +55,13 @@ CONFIG_SCHEMA = cv.Schema( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: fconf = fv.full_config.get() hub_path = fconf.get_path_for_id(config[CONF_TAS58XX_ID]) hub_conf = fconf.get_config_for_path(hub_path[:-1]) if hub_conf[CONF_MODEL] == DAC_TAS5825M: - return config + return unsupported = sorted(frozenset(TAS5825M_ONLY_FAULT_SENSORS).intersection(config)) if unsupported: @@ -69,7 +69,6 @@ def _final_validate(config: ConfigType) -> ConfigType: f"binary_sensor platform tas58xx: '{', '.join(unsupported)}' is only available for 'model: {DAC_TAS5825M}' " f"- Remove from YAML for 'model: {hub_conf[CONF_MODEL]}'" ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/teleinfo/__init__.py b/esphome/components/teleinfo/__init__.py index 5a6a01f6695..0da41fc13a5 100644 --- a/esphome/components/teleinfo/__init__.py +++ b/esphome/components/teleinfo/__init__.py @@ -36,7 +36,7 @@ CONFIG_SCHEMA = ( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: # Historical mode runs at 1200 baud, standard mode at 9600 baud. baud_rate = 1200 if config[CONF_HISTORICAL_MODE] else 9600 uart.final_validate_device_schema( @@ -46,7 +46,6 @@ def _final_validate(config: ConfigType) -> ConfigType: parity="EVEN", stop_bits=1, )(config) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/tfluna/button/__init__.py b/esphome/components/tfluna/button/__init__.py index 753ac7de333..bbabd9ceae6 100644 --- a/esphome/components/tfluna/button/__init__.py +++ b/esphome/components/tfluna/button/__init__.py @@ -49,12 +49,11 @@ def _validate_factory_default_address(config: ConfigType) -> ConfigType: return config -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: if CONF_FACTORY_RESET in config: fv.id_declaration_match_schema(_validate_factory_default_address)( config[CONF_TFLUNA_ID] ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/tmc2209/sensor/__init__.py b/esphome/components/tmc2209/sensor/__init__.py index dd5aadcf7ca..85fe87b0d81 100644 --- a/esphome/components/tmc2209/sensor/__init__.py +++ b/esphome/components/tmc2209/sensor/__init__.py @@ -56,9 +56,9 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: if CONF_ACTUAL_CURRENT not in config: - return config + return full_config = fv.full_config.get() path = full_config.get_path_for_id(config[CONF_TMC2209_ID])[:-1] if full_config.get_config_for_path(path).get(CONF_ANALOG_CURRENT_SCALE): @@ -67,7 +67,6 @@ def _final_validate(config: ConfigType) -> ConfigType: "the current then depends on VREF", path=[CONF_ACTUAL_CURRENT], ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/tmc22xx/__init__.py b/esphome/components/tmc22xx/__init__.py index da760dde2c5..94139f40824 100644 --- a/esphome/components/tmc22xx/__init__.py +++ b/esphome/components/tmc22xx/__init__.py @@ -110,7 +110,7 @@ def _validate_analog_current_scale(config: ConfigType) -> ConfigType: return config -def final_validate(config: ConfigType) -> ConfigType: +def final_validate(config: ConfigType) -> None: """Reject two drivers of the family with the same address on one UART bus.""" for other in fv.full_config.get().get("stepper", []): if other is config: @@ -123,7 +123,6 @@ def final_validate(config: ConfigType) -> ConfigType: f"Address {config[CONF_ADDRESS]} is already used by '{other[CONF_ID]}' " "on the same UART bus" ) - return config async def new_tmc22xx(config: ConfigType) -> cg.Pvariable: diff --git a/esphome/components/tmp102/binary_sensor.py b/esphome/components/tmp102/binary_sensor.py index eb23206b981..b1ecdf7f00f 100644 --- a/esphome/components/tmp102/binary_sensor.py +++ b/esphome/components/tmp102/binary_sensor.py @@ -14,8 +14,8 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema().extend( ) -def _final_validate(config: ConfigType) -> ConfigType: - return validate_unique_child(config, "binary_sensor") +def _final_validate(config: ConfigType) -> None: + validate_unique_child(config, "binary_sensor") FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/tmp102/number.py b/esphome/components/tmp102/number.py index e353a8d1183..a396cedd745 100644 --- a/esphome/components/tmp102/number.py +++ b/esphome/components/tmp102/number.py @@ -51,12 +51,11 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: validate_unique_child(config, "number") full = fv.full_config.get() parent = full.get_config_for_path(full.get_path_for_id(config[CONF_TMP102_ID])[:-1]) add_number_parent(config[CONF_TMP102_ID], parent.get(CONF_EXTENDED_MODE, False)) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/tmp102/text_sensor.py b/esphome/components/tmp102/text_sensor.py index 5d901bfab89..72d0f6e8bcd 100644 --- a/esphome/components/tmp102/text_sensor.py +++ b/esphome/components/tmp102/text_sensor.py @@ -17,8 +17,8 @@ CONFIG_SCHEMA = text_sensor.text_sensor_schema( ) -def _final_validate(config: ConfigType) -> ConfigType: - return validate_unique_child(config, "text_sensor") +def _final_validate(config: ConfigType) -> None: + validate_unique_child(config, "text_sensor") FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/uart_mux/__init__.py b/esphome/components/uart_mux/__init__.py index f97a7b2cb3e..eb07a7549d9 100644 --- a/esphome/components/uart_mux/__init__.py +++ b/esphome/components/uart_mux/__init__.py @@ -37,7 +37,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: # Two muxes on one bridge would each believe they own the bus. owned = fv.full_config.get().data.setdefault(DOMAIN, set()) bridge_id = str(config[CONF_BRIDGE_ID]) @@ -48,7 +48,6 @@ def _final_validate(config: ConfigType) -> ConfigType: [CONF_BRIDGE_ID], ) owned.add(bridge_id) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/uart_tcp/__init__.py b/esphome/components/uart_tcp/__init__.py index 9d62d48d7c2..b7d3dc511b4 100644 --- a/esphome/components/uart_tcp/__init__.py +++ b/esphome/components/uart_tcp/__init__.py @@ -81,7 +81,7 @@ def _reject_dummy_receiver(uart_conf: ConfigType) -> ConfigType: return uart_conf -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: # A second reader would split the bytes with this one, and every connect # discards what the other reader has not read yet. full_config = fv.full_config.get() @@ -122,7 +122,6 @@ def _final_validate(config: ConfigType) -> ConfigType: [CONF_PORT], ) ports.add(port) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/usb_host/__init__.py b/esphome/components/usb_host/__init__.py index 317cec8236b..c11fcac4e17 100644 --- a/esphome/components/usb_host/__init__.py +++ b/esphome/components/usb_host/__init__.py @@ -93,7 +93,7 @@ def validate_usb_clients(configs: list[ConfigType]) -> list[ConfigType]: return configs -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: # Any two overlapping clients could otherwise open the same device devices = config.get(CONF_DEVICES) or [] uarts = fv.full_config.get().get("usb_uart") or [] @@ -117,7 +117,6 @@ def _final_validate(config: ConfigType) -> ConfigType: if redundant else "narrow its filter so it no longer matches that device", ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/tests/component_tests/animation/test_init.py b/tests/component_tests/animation/test_init.py index 1b5dd0d54cf..ee7109fd502 100644 --- a/tests/component_tests/animation/test_init.py +++ b/tests/component_tests/animation/test_init.py @@ -28,6 +28,7 @@ def test_warn_legacy_animation_warns_once( ) -> None: """The deprecation warning fires exactly once and never mutates the config.""" config: ConfigType = {"id": "test_animation", "file": "anim.gif", "type": "rgb565"} + unchanged = dict(config) # A per-entry capture (CONFIG_SCHEMA step) records the raw entry so the # one-shot warning can print a pasteable migrated block. @@ -35,10 +36,11 @@ def test_warn_legacy_animation_warns_once( with caplog.at_level(logging.WARNING): # First call: flag not yet set -> warns and records the flag. - assert _warn_legacy_animation(config) is config + _warn_legacy_animation(config) # Second call: flag already set -> stays silent (the dedup branch). - assert _warn_legacy_animation(config) is config + _warn_legacy_animation(config) + assert config == unchanged assert CORE.data[DOMAIN]["legacy_warning_shown"] is True warnings = [r for r in caplog.records if r.levelno == logging.WARNING] assert len(warnings) == 1 diff --git a/tests/component_tests/online_image/test_init.py b/tests/component_tests/online_image/test_init.py index 76b00ff5ff6..b754ad07be8 100644 --- a/tests/component_tests/online_image/test_init.py +++ b/tests/component_tests/online_image/test_init.py @@ -28,6 +28,7 @@ def test_warn_legacy_online_image_warns_once( ) -> None: """The deprecation warning fires exactly once and never mutates the config.""" config: ConfigType = {"id": "test_online_image", "url": "http://example.com/i.png"} + unchanged = dict(config) # A per-entry capture (CONFIG_SCHEMA step) records the raw entry so the # one-shot warning can print a pasteable migrated block. @@ -35,10 +36,11 @@ def test_warn_legacy_online_image_warns_once( with caplog.at_level(logging.WARNING): # First call: flag not yet set -> warns and records the flag. - assert _warn_legacy_online_image(config) is config + _warn_legacy_online_image(config) # Second call: flag already set -> stays silent (the dedup branch). - assert _warn_legacy_online_image(config) is config + _warn_legacy_online_image(config) + assert config == unchanged assert CORE.data[DOMAIN]["legacy_warning_shown"] is True warnings = [r for r in caplog.records if r.levelno == logging.WARNING] assert len(warnings) == 1 diff --git a/tests/component_tests/sendspin/test_unpaired_access.py b/tests/component_tests/sendspin/test_unpaired_access.py index 8660ba9f7cf..2a6471b2eb0 100644 --- a/tests/component_tests/sendspin/test_unpaired_access.py +++ b/tests/component_tests/sendspin/test_unpaired_access.py @@ -114,7 +114,8 @@ def test_switch_without_hub_key_accepted( set_core_config(PlatformFramework.ESP32_IDF, full_config={DOMAIN: {"id": HUB_ID}}) config = _switch_config(CONF_UNPAIRED_ACCESS) - assert SWITCH_FINAL_VALIDATE_SCHEMA(config) is config + # Should not raise. + SWITCH_FINAL_VALIDATE_SCHEMA(config) def test_switch_without_pairing_method_warns( @@ -153,7 +154,8 @@ def test_enabled_switch_ignores_hub_key(set_core_config: SetCoreConfigCallable) ) config = _switch_config("enabled") - assert SWITCH_FINAL_VALIDATE_SCHEMA(config) is config + # Should not raise. + SWITCH_FINAL_VALIDATE_SCHEMA(config) @pytest.mark.parametrize("switch_type", ["enabled", CONF_UNPAIRED_ACCESS]) diff --git a/tests/unit_tests/components/test_audio_http.py b/tests/unit_tests/components/test_audio_http.py index 94355c09c98..714cf771d6f 100644 --- a/tests/unit_tests/components/test_audio_http.py +++ b/tests/unit_tests/components/test_audio_http.py @@ -15,7 +15,8 @@ def _source_config() -> ConfigType: def _run(full_config: dict, config: ConfigType) -> ConfigType: token = fv.full_config.set(full_config) try: - return _inherit_ca_certificate_path(config) + _inherit_ca_certificate_path(config) + return config finally: fv.full_config.reset(token) diff --git a/tests/unit_tests/components/test_espnow.py b/tests/unit_tests/components/test_espnow.py index 762e660139c..1ee5ff5528b 100644 --- a/tests/unit_tests/components/test_espnow.py +++ b/tests/unit_tests/components/test_espnow.py @@ -27,20 +27,20 @@ def _run( full_config: dict, config: ConfigType, platform: str = PLATFORM_ESP32, -) -> ConfigType: +) -> None: monkeypatch.setattr("esphome.components.espnow.get_esp32_variant", lambda: variant) monkeypatch.setitem(CORE.data, KEY_CORE, {KEY_TARGET_PLATFORM: platform}) token = fv.full_config.set(full_config) try: - return _validate_variant(config) + _validate_variant(config) finally: fv.full_config.reset(token) def test_variant_with_native_wifi_passes(monkeypatch) -> None: - """A variant with a native Wi-Fi PHY needs no shim; config passes through.""" + """A variant with a native Wi-Fi PHY needs no shim, so validation passes.""" config = {"id": "espnow"} - assert _run(monkeypatch, VARIANT_ESP32C3, {}, config) is config + _run(monkeypatch, VARIANT_ESP32C3, {}, config) def test_radioless_non_p4_variant_rejected(monkeypatch) -> None: @@ -56,15 +56,15 @@ def test_p4_without_esp32_hosted_rejected(monkeypatch) -> None: def test_p4_with_esp32_hosted_passes(monkeypatch) -> None: - """The P4 with esp32_hosted present validates; config passes through.""" + """The P4 with esp32_hosted present validates.""" config = {"id": "espnow"} - assert _run(monkeypatch, VARIANT_ESP32P4, {"esp32_hosted": {}}, config) is config + _run(monkeypatch, VARIANT_ESP32P4, {"esp32_hosted": {}}, config) def test_esp8266_skips_variant_check(monkeypatch) -> None: """The ESP8266 has one Wi-Fi radio and no variants, so the check does not run.""" config = {"id": "espnow"} - assert _run(monkeypatch, "", {}, config, platform=PLATFORM_ESP8266) is config + _run(monkeypatch, "", {}, config, platform=PLATFORM_ESP8266) def _esp8266_arduino(monkeypatch) -> None: diff --git a/tests/unit_tests/components/test_usb_host.py b/tests/unit_tests/components/test_usb_host.py index 8d572dba968..ff28aeebf5c 100644 --- a/tests/unit_tests/components/test_usb_host.py +++ b/tests/unit_tests/components/test_usb_host.py @@ -114,13 +114,11 @@ def test_every_pair_is_compared_not_just_neighbours() -> None: validate_usb_clients(configs) -def _run_final_validate( - devices: list[ConfigType], uarts: list[ConfigType] -) -> ConfigType: +def _run_final_validate(devices: list[ConfigType], uarts: list[ConfigType]) -> None: config = {"id": "usb_host", "devices": devices} token = fv.full_config.set({"usb_host": config, "usb_uart": uarts}) try: - return _final_validate(config) + _final_validate(config) finally: fv.full_config.reset(token)