[core] Read the mqtt IP discovery flag without importing the mqtt component (#18066)

This commit is contained in:
J. Nick Koston
2026-08-04 15:12:57 -05:00
committed by GitHub
parent 79a305d69a
commit d47acf5d0b
6 changed files with 46 additions and 4 deletions
+1 -2
View File
@@ -29,6 +29,7 @@ from esphome.const import (
CONF_BROKER,
CONF_DEASSERT_RTS_DTR,
CONF_DISABLED,
CONF_DISCOVER_IP,
CONF_ESPHOME,
CONF_LEVEL,
CONF_LOG_TOPIC,
@@ -486,8 +487,6 @@ def has_web_server_ota() -> bool:
def has_mqtt_ip_lookup() -> bool:
"""Check if MQTT is available and IP lookup is supported."""
from esphome.components.mqtt import CONF_DISCOVER_IP
if CONF_MQTT not in CORE.config:
return False
# Default Enabled
+1 -1
View File
@@ -21,6 +21,7 @@ from esphome.const import (
CONF_CLIENT_ID,
CONF_COMMAND_RETAIN,
CONF_COMMAND_TOPIC,
CONF_DISCOVER_IP,
CONF_DISCOVERY,
CONF_DISCOVERY_OBJECT_ID_GENERATOR,
CONF_DISCOVERY_PREFIX,
@@ -74,7 +75,6 @@ def AUTO_LOAD():
return ["json"]
CONF_DISCOVER_IP = "discover_ip"
CONF_IDF_SEND_ASYNC = "idf_send_async"
CONF_WAIT_FOR_CONNECTION = "wait_for_connection"
+1
View File
@@ -347,6 +347,7 @@ CONF_DISABLE_CRC = "disable_crc"
CONF_DISABLED = "disabled"
CONF_DISABLED_BY_DEFAULT = "disabled_by_default"
CONF_DISCONNECT_DELAY = "disconnect_delay"
CONF_DISCOVER_IP = "discover_ip"
CONF_DISCOVERY = "discovery"
CONF_DISCOVERY_OBJECT_ID_GENERATOR = "discovery_object_id_generator"
CONF_DISCOVERY_PREFIX = "discovery_prefix"
+1 -1
View File
@@ -557,7 +557,7 @@ def lint_constants_usage():
# Maximum allowed CONF_ constants in esphome/const.py.
# This file is frozen — new constants go in esphome/components/const/__init__.py.
# Decrease this number when constants are moved out of const.py.
CONST_PY_MAX_CONF = 1016
CONST_PY_MAX_CONF = 1017
@lint_content_check(include=["esphome/const.py"])
+34
View File
@@ -158,3 +158,37 @@ def test_espidf_toolchain_does_not_import_heavy_modules() -> None:
"The upload fast path skips validation; importing the validation "
"stack anyway defeats the validated-config cache."
)
def test_has_mqtt_ip_lookup_does_not_import_mqtt() -> None:
"""``has_mqtt_ip_lookup`` runs on the upload/logs fast path for mqtt
configs; reading ``CONF_DISCOVER_IP`` must not drag in the mqtt
component and, with it, the validation stack.
Runs in a subprocess because this session's other tests import the
mqtt component; the fast path itself must not.
"""
check = (
"import sys; from esphome.__main__ import has_mqtt_ip_lookup; "
"from esphome.core import CORE; from esphome.const import CONF_MQTT; "
"CORE.config = {CONF_MQTT: {}}; "
"assert has_mqtt_ip_lookup() is True, 'mqtt IP lookup default broke'; "
f"leaked = [m for m in {HEAVY_MODULES!r} if m in sys.modules]; "
"leaked += [m for m in sys.modules if m.startswith('esphome.components.')]; "
"print(','.join(leaked))"
)
# check=False keeps the child's stderr (its assertion message or an
# import traceback) visible on failure.
result = subprocess.run(
[sys.executable, "-c", check],
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 0, result.stderr
leaked = result.stdout.strip()
assert not leaked, (
f"has_mqtt_ip_lookup pulls in heavy modules: {leaked}. "
"The upload/logs fast path skips validation; importing the "
"validation stack anyway defeats the validated-config cache."
)
+8
View File
@@ -3257,6 +3257,14 @@ def test_get_port_type() -> None:
assert get_port_type("BOOTSEL") == "BOOTSEL"
def test_mqtt_reexports_discover_ip() -> None:
"""The old import path must keep working for external code."""
from esphome.components import mqtt
from esphome.const import CONF_DISCOVER_IP
assert mqtt.CONF_DISCOVER_IP is CONF_DISCOVER_IP
def test_has_mqtt_ip_lookup() -> None:
"""Test has_mqtt_ip_lookup function."""