[core] Drop the duplicate ESPHome version parser (#18065)

This commit is contained in:
J. Nick Koston
2026-08-04 14:48:39 -05:00
committed by GitHub
parent d344fd74d1
commit 79a305d69a
3 changed files with 58 additions and 13 deletions
+22 -6
View File
@@ -99,7 +99,6 @@ from esphome.schema_extractors import (
schema_extractor_registry,
schema_extractor_typed,
)
from esphome.util import parse_esphome_version
from esphome.voluptuous_schema import _Schema
from esphome.yaml_util import SensitiveStr, make_data_base
@@ -2612,13 +2611,30 @@ def require_framework_version(
return validator
def require_esphome_version(year, month, patch):
def require_esphome_version(
year: Version | int, month: int | None = None, patch: int | None = None
):
"""Validator requiring at least the given ESPHome version.
Accepts a single ``Version`` like the sibling
``require_framework_version``, or the legacy ``(year, month, patch)``
ints external components already pass.
"""
if isinstance(year, Version):
required = year
elif month is None or patch is None:
raise ValueError(
"require_esphome_version needs a Version or (year, month, patch)"
)
else:
required = Version(year, month, patch)
def validator(value):
esphome_version = parse_esphome_version()
if esphome_version < (year, month, patch):
requires_version = f"{year}.{month}.{patch}"
# A dev or beta build of the required version still satisfies it,
# matching the old tuple comparison that dropped the suffix.
if Version.parse(ESPHOME_VERSION) < required:
raise Invalid(
f"This component requires at least ESPHome version {requires_version}"
f"This component requires at least ESPHome version {required}"
)
return value
-7
View File
@@ -329,13 +329,6 @@ def is_dev_esphome_version():
return "dev" in const.__version__
def parse_esphome_version() -> tuple[int, int, int]:
match = re.match(r"^(\d+).(\d+).(\d+)(-dev\d*|b\d*)?$", const.__version__)
if match is None:
raise ValueError(f"Failed to parse ESPHome version '{const.__version__}'")
return int(match.group(1)), int(match.group(2)), int(match.group(3))
# Custom OrderedDict with nicer repr method for debugging
class OrderedDict(collections.OrderedDict):
def __repr__(self):
@@ -2,6 +2,7 @@ import json
import logging
from pathlib import Path
import string
from unittest.mock import patch
from hypothesis import example, given, settings
from hypothesis.strategies import builds, integers, ip_addresses, one_of, text
@@ -2926,11 +2927,46 @@ def test_require_esphome_version_ok() -> None:
assert cv.require_esphome_version(1, 0, 0)("test") == "test"
def test_require_esphome_version_accepts_version_object() -> None:
"""The Version form matches require_framework_version's style."""
assert cv.require_esphome_version(cv.Version(1, 0, 0))("test") == "test"
with pytest.raises(Invalid, match="at least ESPHome version 9999.0.0"):
cv.require_esphome_version(cv.Version(9999, 0, 0))("test")
def test_require_esphome_version_partial_ints_fail_at_call_site() -> None:
"""Missing ints raise immediately instead of a TypeError inside the validator."""
with pytest.raises(ValueError, match="needs a Version or"):
cv.require_esphome_version(2026, 8)
with pytest.raises(ValueError, match="needs a Version or"):
cv.require_esphome_version(2026)
def test_require_esphome_version_too_old() -> None:
with pytest.raises(Invalid, match="at least ESPHome version 9999.0.0"):
cv.require_esphome_version(9999, 0, 0)("test")
@pytest.mark.parametrize("current", ["2026.8.0", "2026.8.0b1", "2026.8.0-dev20260801"])
def test_require_esphome_version_prerelease_of_required_passes(current: str) -> None:
"""A dev or beta build of the required version satisfies it.
Pins the behavior of the old tuple comparison that dropped the
suffix, now expressed through Version ordering where the extra field
only breaks ties upward.
"""
with patch.object(cv, "ESPHOME_VERSION", current):
assert cv.require_esphome_version(2026, 8, 0)("test") == "test"
def test_require_esphome_version_older_prerelease_fails() -> None:
with (
patch.object(cv, "ESPHOME_VERSION", "2026.7.0-dev20260701"),
pytest.raises(Invalid, match="at least ESPHome version 2026.8.0"),
):
cv.require_esphome_version(2026, 8, 0)("test")
# ---------------------------------------------------------------------------
# suppress_invalid / validate_source_shorthand / rename_key
# ---------------------------------------------------------------------------