mirror of
https://github.com/esphome/esphome.git
synced 2026-08-22 22:26:21 +00:00
[core] Drop the duplicate ESPHome version parser (#18065)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user