From a0dcb6a5f5b14d438876d9aee240dc571f248c6c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 25 Aug 2026 08:37:33 -0500 Subject: [PATCH] Demote bulk stack-word decode misses to debug, count built components per pattern --- esphome/components/esp8266/__init__.py | 14 +++++++++----- script/test_build_components.py | 12 +++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index d672e03ab0..124655ea53 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -644,7 +644,10 @@ def _warn_decode_problem(key: str, message: str, *args) -> bool: return True -def _decode_pc(config: ConfigType, addr: str) -> None: +def _decode_pc(config: ConfigType, addr: str, *, bulk: bool = False) -> None: + """Decode one crash address. ``bulk``: the caller is scanning every + 8-hex stack word, most of which are not code addresses -- unmappable + ones log at debug so real frames are not buried.""" if (native_toolchain := native_toolchain_module()) is not None: addr2line = native_toolchain.get_addr2line_path() elf = native_toolchain.get_elf_path() @@ -686,9 +689,10 @@ def _decode_pc(config: ConfigType, addr: str) -> None: return if "?? ??:0" in translation: - # A stale or mismatched ELF: mark it, or the frame silently reads - # as merely unmappable - _LOGGER.warning("Not decoded %s (address not in %s)", addr, elf) + # A named register that fails to decode is confusing silence; a + # bulk stack word failing is the expected common case + log = _LOGGER.debug if bulk else _LOGGER.warning + log("Not decoded %s (address not in %s)", addr, elf) return translation = translation.replace(" at ??:?", "").replace(":?", "") _LOGGER.warning("Decoded %s", translation) @@ -758,6 +762,6 @@ def process_stacktrace(config: ConfigType, line: str, backtrace_state: bool) -> if backtrace_state: for addr in re.finditer(STACKTRACE_ESP8266_BACKTRACE_PC_RE, line): - _decode_pc(config, addr.group()) + _decode_pc(config, addr.group(), bulk=True) return backtrace_state diff --git a/script/test_build_components.py b/script/test_build_components.py index d167d7850e..95e9cd839f 100755 --- a/script/test_build_components.py +++ b/script/test_build_components.py @@ -1062,10 +1062,10 @@ def test_components( # toolchain build. include_validate = esphome_command != "compile" - # Find all component tests; remember which patterns (wildcards - # included) matched anything, for the deferred no-tests accounting + # Find all component tests; remember which components each pattern + # (wildcards included) matched, for the deferred no-tests accounting all_tests = {} - pattern_hits: dict[str, bool] = {} + pattern_components: dict[str, set[str]] = {} for pattern in component_patterns: # Skip empty patterns (happens when components list is empty string) if not pattern: @@ -1073,7 +1073,7 @@ def test_components( found = find_component_tests( tests_dir, pattern, base_only, include_validate=include_validate ) - pattern_hits[pattern] = bool(found) + pattern_components[pattern] = set(found) all_tests.update(found) # The flag's contract is "no test matched fails": a fully blank pattern @@ -1203,10 +1203,12 @@ def test_components( # legitimately match nothing. Failing is deferred past the summary # so a real failure's reproduce commands still print. built = {c for r in test_results for c in r.components} + # A pattern is silent when it matched no fixture, or when none of + # its matched components produced a build (wildcards included) silent = [ p for p in component_patterns - if p and (not pattern_hits.get(p) or ("*" not in p and p not in built)) + if p and not (pattern_components.get(p, set()) & built) ] if silent: print(f"No tests ran for requested pattern(s): {', '.join(silent)}")