1
mirror of https://github.com/home-assistant/core synced 2024-10-04 07:58:43 +02:00

Fix importing blueprints (#71365)

Co-authored-by: Shay Levy <levyshay1@gmail.com>
This commit is contained in:
Paulus Schoutsen 2022-05-05 14:33:17 -07:00 committed by GitHub
parent aadfcc9a6e
commit 353cc0b8c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 12 deletions

View File

@ -5,11 +5,13 @@ from collections.abc import Callable, Sequence
from typing import Any, TypedDict, cast from typing import Any, TypedDict, cast
import voluptuous as vol import voluptuous as vol
import yaml
from homeassistant.backports.enum import StrEnum from homeassistant.backports.enum import StrEnum
from homeassistant.const import CONF_MODE, CONF_UNIT_OF_MEASUREMENT from homeassistant.const import CONF_MODE, CONF_UNIT_OF_MEASUREMENT
from homeassistant.core import split_entity_id, valid_entity_id from homeassistant.core import split_entity_id, valid_entity_id
from homeassistant.util import decorator from homeassistant.util import decorator
from homeassistant.util.yaml.dumper import represent_odict
from . import config_validation as cv from . import config_validation as cv
@ -71,7 +73,11 @@ class Selector:
def serialize(self) -> Any: def serialize(self) -> Any:
"""Serialize Selector for voluptuous_serialize.""" """Serialize Selector for voluptuous_serialize."""
return {"selector": {self.selector_type: self.config}} return {"selector": {self.selector_type: self.serialize_config()}}
def serialize_config(self) -> Any:
"""Serialize config."""
return self.config
SINGLE_ENTITY_SELECTOR_CONFIG_SCHEMA = vol.Schema( SINGLE_ENTITY_SELECTOR_CONFIG_SCHEMA = vol.Schema(
@ -623,6 +629,13 @@ class NumberSelector(Selector):
"""Instantiate a selector.""" """Instantiate a selector."""
super().__init__(config) super().__init__(config)
def serialize_config(self) -> Any:
"""Serialize the selector config."""
return {
**self.config,
"mode": self.config["mode"].value,
}
def __call__(self, data: Any) -> float: def __call__(self, data: Any) -> float:
"""Validate the passed selection.""" """Validate the passed selection."""
value: float = vol.Coerce(float)(data) value: float = vol.Coerce(float)(data)
@ -881,3 +894,11 @@ class TimeSelector(Selector):
"""Validate the passed selection.""" """Validate the passed selection."""
cv.time(data) cv.time(data)
return cast(str, data) return cast(str, data)
yaml.SafeDumper.add_representer(
Selector,
lambda dumper, value: represent_odict(
dumper, "tag:yaml.org,2002:map", value.serialize()
),
)

View File

@ -198,7 +198,7 @@ async def test_fetch_blueprint_from_github_url(hass, aioclient_mock, url):
assert imported_blueprint.blueprint.domain == "automation" assert imported_blueprint.blueprint.domain == "automation"
assert imported_blueprint.blueprint.inputs == { assert imported_blueprint.blueprint.inputs == {
"service_to_call": None, "service_to_call": None,
"trigger_event": None, "trigger_event": {"selector": {"text": {}}},
} }
assert imported_blueprint.suggested_filename == "balloob/motion_light" assert imported_blueprint.suggested_filename == "balloob/motion_light"
assert imported_blueprint.blueprint.metadata["source_url"] == url assert imported_blueprint.blueprint.metadata["source_url"] == url

View File

@ -30,7 +30,10 @@ async def test_list_blueprints(hass, hass_ws_client):
"test_event_service.yaml": { "test_event_service.yaml": {
"metadata": { "metadata": {
"domain": "automation", "domain": "automation",
"input": {"service_to_call": None, "trigger_event": None}, "input": {
"service_to_call": None,
"trigger_event": {"selector": {"text": {}}},
},
"name": "Call service based on event", "name": "Call service based on event",
}, },
}, },
@ -89,7 +92,10 @@ async def test_import_blueprint(hass, aioclient_mock, hass_ws_client):
"blueprint": { "blueprint": {
"metadata": { "metadata": {
"domain": "automation", "domain": "automation",
"input": {"service_to_call": None, "trigger_event": None}, "input": {
"service_to_call": None,
"trigger_event": {"selector": {"text": {}}},
},
"name": "Call service based on event", "name": "Call service based on event",
"source_url": "https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml", "source_url": "https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml",
}, },
@ -123,7 +129,7 @@ async def test_save_blueprint(hass, aioclient_mock, hass_ws_client):
assert msg["success"] assert msg["success"]
assert write_mock.mock_calls assert write_mock.mock_calls
assert write_mock.call_args[0] == ( assert write_mock.call_args[0] == (
"blueprint:\n name: Call service based on event\n domain: automation\n input:\n trigger_event:\n service_to_call:\n source_url: https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml\ntrigger:\n platform: event\n event_type: !input 'trigger_event'\naction:\n service: !input 'service_to_call'\n entity_id: light.kitchen\n", "blueprint:\n name: Call service based on event\n domain: automation\n input:\n trigger_event:\n selector:\n text: {}\n service_to_call:\n source_url: https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml\ntrigger:\n platform: event\n event_type: !input 'trigger_event'\naction:\n service: !input 'service_to_call'\n entity_id: light.kitchen\n",
) )

View File

@ -11,7 +11,7 @@ import pytest
import voluptuous as vol import voluptuous as vol
import homeassistant import homeassistant
from homeassistant.helpers import config_validation as cv, template from homeassistant.helpers import config_validation as cv, selector, template
def test_boolean(): def test_boolean():
@ -720,6 +720,17 @@ def test_string_in_serializer():
} }
def test_selector_in_serializer():
"""Test selector with custom_serializer."""
assert cv.custom_serializer(selector.selector({"text": {}})) == {
"selector": {
"text": {
"multiline": False,
}
}
}
def test_positive_time_period_dict_in_serializer(): def test_positive_time_period_dict_in_serializer():
"""Test positive_time_period_dict with custom_serializer.""" """Test positive_time_period_dict with custom_serializer."""
assert cv.custom_serializer(cv.positive_time_period_dict) == { assert cv.custom_serializer(cv.positive_time_period_dict) == {

View File

@ -2,7 +2,8 @@
import pytest import pytest
import voluptuous as vol import voluptuous as vol
from homeassistant.helpers import config_validation as cv, selector from homeassistant.helpers import selector
from homeassistant.util import yaml
FAKE_UUID = "a266a680b608c32770e6c45bfe6b8411" FAKE_UUID = "a266a680b608c32770e6c45bfe6b8411"
@ -48,10 +49,12 @@ def _test_selector(
converter = default_converter converter = default_converter
# Validate selector configuration # Validate selector configuration
selector.validate_selector({selector_type: schema}) config = {selector_type: schema}
selector.validate_selector(config)
selector_instance = selector.selector(config)
# Use selector in schema and validate # Use selector in schema and validate
vol_schema = vol.Schema({"selection": selector.selector({selector_type: schema})}) vol_schema = vol.Schema({"selection": selector_instance})
for selection in valid_selections: for selection in valid_selections:
assert vol_schema({"selection": selection}) == { assert vol_schema({"selection": selection}) == {
"selection": converter(selection) "selection": converter(selection)
@ -62,9 +65,12 @@ def _test_selector(
# Serialize selector # Serialize selector
selector_instance = selector.selector({selector_type: schema}) selector_instance = selector.selector({selector_type: schema})
assert cv.custom_serializer(selector_instance) == { assert (
"selector": {selector_type: selector_instance.config} selector.selector(selector_instance.serialize()["selector"]).config
} == selector_instance.config
)
# Test serialized selector can be dumped to YAML
yaml.dump(selector_instance.serialize())
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -3,6 +3,8 @@ blueprint:
domain: automation domain: automation
input: input:
trigger_event: trigger_event:
selector:
text:
service_to_call: service_to_call:
trigger: trigger:
platform: event platform: event