mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 03:16:37 +00:00
[core] Replace voluptuous with probatio for config validation
This commit is contained in:
@@ -1460,7 +1460,7 @@ def test_only_with_framework_suggestion_without_docs_path() -> None:
|
||||
|
||||
|
||||
def test_has_at_least_one_key_not_dict() -> None:
|
||||
with pytest.raises(Invalid, match="expected dictionary"):
|
||||
with pytest.raises(Invalid, match="expected a dictionary"):
|
||||
cv.has_at_least_one_key("a", "b")([])
|
||||
|
||||
|
||||
@@ -1475,17 +1475,17 @@ def test_has_at_least_one_key_ok() -> None:
|
||||
|
||||
|
||||
def test_has_exactly_one_key_not_dict() -> None:
|
||||
with pytest.raises(Invalid, match="expected dictionary"):
|
||||
with pytest.raises(Invalid, match="expected a dictionary"):
|
||||
cv.has_exactly_one_key("a", "b")("notdict")
|
||||
|
||||
|
||||
def test_has_exactly_one_key_too_many() -> None:
|
||||
with pytest.raises(Invalid, match="Cannot specify more than one"):
|
||||
with pytest.raises(Invalid, match="exactly one of"):
|
||||
cv.has_exactly_one_key("a", "b")({"a": 1, "b": 2})
|
||||
|
||||
|
||||
def test_has_exactly_one_key_too_few() -> None:
|
||||
with pytest.raises(Invalid, match="Must contain exactly one"):
|
||||
with pytest.raises(Invalid, match="exactly one of"):
|
||||
cv.has_exactly_one_key("a", "b")({"c": 1})
|
||||
|
||||
|
||||
@@ -1495,12 +1495,12 @@ def test_has_exactly_one_key_ok() -> None:
|
||||
|
||||
|
||||
def test_has_at_most_one_key_not_dict() -> None:
|
||||
with pytest.raises(Invalid, match="expected dictionary"):
|
||||
with pytest.raises(Invalid, match="expected a dictionary"):
|
||||
cv.has_at_most_one_key("a", "b")(5)
|
||||
|
||||
|
||||
def test_has_at_most_one_key_too_many() -> None:
|
||||
with pytest.raises(vol.MultipleInvalid, match="Cannot specify more than one"):
|
||||
with pytest.raises(vol.MultipleInvalid, match="at most one of"):
|
||||
cv.has_at_most_one_key("a", "b")({"a": 1, "b": 2})
|
||||
|
||||
|
||||
@@ -1510,7 +1510,7 @@ def test_has_at_most_one_key_ok() -> None:
|
||||
|
||||
|
||||
def test_has_none_or_all_keys_not_dict() -> None:
|
||||
with pytest.raises(Invalid, match="expected dictionary"):
|
||||
with pytest.raises(Invalid, match="expected a dictionary"):
|
||||
cv.has_none_or_all_keys("a", "b")(5)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
"""The voluptuous compatibility shim for third-party (external) components.
|
||||
|
||||
External components import ``voluptuous`` directly. ESPHome installs probatio's
|
||||
shim at package import (``esphome/__init__.py``), so those imports resolve to
|
||||
probatio without the components needing any change. These tests pin that contract.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import probatio
|
||||
|
||||
import esphome # noqa: F401 (importing installs the shim)
|
||||
|
||||
|
||||
def test_voluptuous_resolves_to_probatio_shim() -> None:
|
||||
"""``import voluptuous`` resolves to probatio's shim, not a real voluptuous."""
|
||||
voluptuous = sys.modules.get("voluptuous")
|
||||
assert voluptuous is not None
|
||||
assert voluptuous.__name__ == "probatio._vol_shim"
|
||||
# Submodules dependencies reach into are aliased too.
|
||||
assert "voluptuous.schema_builder" in sys.modules
|
||||
assert hasattr(sys.modules["voluptuous.schema_builder"], "_compile_scalar")
|
||||
|
||||
|
||||
def test_external_component_style_schema_validates() -> None:
|
||||
"""A schema built the way a third-party component would, through voluptuous."""
|
||||
import voluptuous as vol # noqa: PLC0415 (mimics an external component)
|
||||
|
||||
# Markers imported from voluptuous are probatio markers via the shim.
|
||||
assert issubclass(vol.Required, probatio.Marker)
|
||||
|
||||
schema = vol.Schema(
|
||||
{
|
||||
vol.Required("name"): str,
|
||||
vol.Optional("count", default=1): int,
|
||||
}
|
||||
)
|
||||
assert schema({"name": "x"}) == {"name": "x", "count": 1}
|
||||
|
||||
|
||||
def test_shim_extra_key_is_probatio_error() -> None:
|
||||
"""An extra key raises probatio's MultipleInvalid through the shim."""
|
||||
import voluptuous as vol # noqa: PLC0415
|
||||
|
||||
schema = vol.Schema({vol.Required("name"): str})
|
||||
try:
|
||||
schema({"name": "x", "bogus": 1})
|
||||
except vol.MultipleInvalid as err:
|
||||
assert isinstance(err, probatio.MultipleInvalid)
|
||||
else:
|
||||
raise AssertionError("expected MultipleInvalid for an extra key")
|
||||
@@ -1,9 +1,9 @@
|
||||
"""Tests for voluptuous_schema.py."""
|
||||
|
||||
import probatio as vol
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
from esphome.voluptuous_schema import _Schema
|
||||
from esphome.voluptuous_schema import ExtraKeysInvalid, _Schema
|
||||
|
||||
|
||||
class TestIdKeyDropping:
|
||||
@@ -38,8 +38,11 @@ class TestIdKeyDropping:
|
||||
vol.Required("name"): str,
|
||||
}
|
||||
)
|
||||
with pytest.raises(vol.MultipleInvalid, match="extra keys not allowed"):
|
||||
with pytest.raises(vol.MultipleInvalid) as exc_info:
|
||||
schema({"name": "test", "unknown_key": "value"})
|
||||
# The extra key is reported as an ExtraKeysInvalid (probatio carries the
|
||||
# close-match candidates on it); assert the type, not the exact wording.
|
||||
assert any(isinstance(err, ExtraKeysInvalid) for err in exc_info.value.errors)
|
||||
|
||||
def test_id_key_not_dropped_when_in_schema(self):
|
||||
"""When 'id' is declared in the schema, it should be validated normally."""
|
||||
|
||||
Reference in New Issue
Block a user