Merge remote-tracking branch 'upstream/ci/import-time-check' into ci/lazy-import-offenders

# Conflicts:
#	esphome/loader.py
This commit is contained in:
J. Nick Koston
2026-04-28 08:51:00 -05:00
194 changed files with 5430 additions and 982 deletions
+44 -2
View File
@@ -511,6 +511,40 @@ def lint_no_std_string_view(fname, match):
)
@lint_re_check(
r"(?:"
# `from esphome.components.const import ...`
r"from\s+esphome\.components\.const\s+import"
r"|"
# `import esphome.components.const` (with optional `as` alias)
r"import\s+esphome\.components\.const\b"
r"|"
# `from esphome.components import [(] ... const ... [)]`
# Handles parenthesized + multiline import lists by allowing newlines inside
# the parens via [^)]*. Single-line form falls back to the [^#\n]* branch.
r"from\s+esphome\.components\s+import\s*"
r"(?:\([^)]*\bconst\b[^)]*\)|(?:[^#\n]*[\s,])?\bconst\b)"
r")",
include=["*.py"],
exclude=[
"esphome/components/*",
"tests/*",
"script/ci-custom.py",
],
)
def lint_no_components_const_outside_components(fname, match):
return (
f"Constants in {highlight('esphome/components/const/__init__.py')} are intended "
f"to be shared only between components in {highlight('esphome/components/')}. "
f"Code outside this folder must not import from "
f"{highlight('esphome.components.const')}.\n"
f"For core code (used outside {highlight('esphome/components/')}), define the "
f"constant in {highlight('esphome/const.py')} instead. When adding a new "
f"{highlight('CONF_')} constant there, bump {highlight('CONST_PY_MAX_CONF')} "
f"in this file accordingly (see {highlight('lint_const_py_frozen')})."
)
@lint_post_check
def lint_constants_usage():
errs = []
@@ -837,7 +871,16 @@ def lint_no_std_to_string(fname, match):
f"{highlight('std::to_string()')} (including unqualified {highlight('to_string()')}) "
f"allocates heap memory. On long-running embedded devices, repeated heap allocations "
f"fragment memory over time.\n"
f"Please use {highlight('snprintf()')} with a stack buffer instead.\n"
f"\n"
f"For plain integer formatting, prefer the dedicated helpers in helpers.h over "
f"{highlight('snprintf()')} — they avoid pulling in printf formatting code and are "
f"smaller and faster:\n"
f" int8_t: {highlight('int8_to_str(buf, val)')} (buf >= 5 bytes)\n"
f" uint8_t/uint16_t/uint32_t: {highlight('uint32_to_str(buf, val)')} (buf = UINT32_MAX_STR_SIZE; smaller types auto-widen)\n"
f"Example: {highlight('char buf[UINT32_MAX_STR_SIZE]; uint32_to_str(buf, value);')}\n"
f"For sensor values, use {highlight('value_accuracy_to_buf()')} from helpers.h.\n"
f"\n"
f"Otherwise use {highlight('snprintf()')} with a stack buffer.\n"
f"\n"
f"Buffer sizes and format specifiers (sizes include sign and null terminator):\n"
f" uint8_t: 4 chars - %u (or PRIu8)\n"
@@ -851,7 +894,6 @@ def lint_no_std_to_string(fname, match):
f" float/double: 24 chars - %.8g (15 digits + sign + decimal + e+XXX)\n"
f" 317 chars - %f (for DBL_MAX: 309 int digits + decimal + 6 frac + sign)\n"
f"\n"
f"For sensor values, use value_accuracy_to_buf() from helpers.h.\n"
f'Example: char buf[11]; snprintf(buf, sizeof(buf), "%" PRIu32, value);\n'
f"(If strictly necessary, add `{highlight('// NOLINT')}` to the end of the line)"
)
+9 -2
View File
@@ -438,8 +438,11 @@ def should_run_benchmarks(branch: str | None = None) -> bool:
Benchmarks run when any of the following conditions are met:
1. Core C++ files changed (esphome/core/*)
2. A directly changed component has benchmark files (no dependency expansion)
3. Benchmark infrastructure changed (tests/benchmarks/*, script/cpp_benchmark.py,
2. The host platform changed (esphome/components/host/*) — benchmarks
are built and run on the host platform, so its implementations of
``millis()``/``micros()``/etc. affect every benchmark
3. A directly changed component has benchmark files (no dependency expansion)
4. Benchmark infrastructure changed (tests/benchmarks/*, script/cpp_benchmark.py,
script/build_helpers.py, script/setup_codspeed_lib.py)
Unlike unit tests, benchmarks do NOT expand to dependent components.
@@ -456,6 +459,10 @@ def should_run_benchmarks(branch: str | None = None) -> bool:
if core_changed(files):
return True
# Host platform supplies the runtime that benchmarks execute on
if any(f.startswith("esphome/components/host/") for f in files):
return True
# Check if benchmark infrastructure changed
if any(
f.startswith("tests/benchmarks/") or f in BENCHMARK_INFRASTRUCTURE_FILES