Fix empty selector validation (#151340)

pull/151510/head
Artur Pragacz 2025-09-01 16:22:41 +02:00 committed by GitHub
parent 5e22533fc0
commit d7e6f84d28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 92 additions and 22 deletions

View File

@ -50,7 +50,7 @@ def validate_selector(config: Any) -> dict:
# Selectors can be empty
if config[selector_type] is None:
return {selector_type: {}}
config = {selector_type: {}}
return {
selector_type: cast(dict, selector_class.CONFIG_SCHEMA(config[selector_type]))

View File

@ -20,6 +20,7 @@
'required': True,
'selector': dict({
'object': dict({
'multiple': False,
}),
}),
}),
@ -74,6 +75,8 @@
'name': 'Name',
'selector': dict({
'text': dict({
'multiline': False,
'multiple': False,
}),
}),
}),
@ -84,6 +87,8 @@
'required': True,
'selector': dict({
'text': dict({
'multiline': False,
'multiple': False,
}),
}),
}),

View File

@ -146,7 +146,9 @@ async def test_fetch_blueprint_from_github_url(
assert imported_blueprint.blueprint.domain == "automation"
assert imported_blueprint.blueprint.inputs == {
"service_to_call": None,
"trigger_event": {"selector": {"text": {}}},
"trigger_event": {
"selector": {"text": {"multiline": False, "multiple": False}}
},
"a_number": {"selector": {"number": {"mode": "box", "step": 1.0}}},
}
assert imported_blueprint.suggested_filename == "balloob/motion_light"

View File

@ -58,7 +58,9 @@ async def test_list_blueprints(
"domain": "automation",
"input": {
"service_to_call": None,
"trigger_event": {"selector": {"text": {}}},
"trigger_event": {
"selector": {"text": {"multiline": False, "multiple": False}}
},
"a_number": {"selector": {"number": {"mode": "box", "step": 1.0}}},
},
"name": "Call service based on event",
@ -69,7 +71,9 @@ async def test_list_blueprints(
"domain": "automation",
"input": {
"service_to_call": None,
"trigger_event": {"selector": {"text": {}}},
"trigger_event": {
"selector": {"text": {"multiline": False, "multiple": False}}
},
"a_number": {"selector": {"number": {"mode": "box", "step": 1.0}}},
},
"name": "Call service based on event",
@ -133,7 +137,9 @@ async def test_import_blueprint(
"domain": "automation",
"input": {
"service_to_call": None,
"trigger_event": {"selector": {"text": {}}},
"trigger_event": {
"selector": {"text": {"multiline": False, "multiple": False}}
},
"a_number": {"selector": {"number": {"mode": "box", "step": 1.0}}},
},
"name": "Call service based on event",
@ -219,21 +225,51 @@ async def test_save_blueprint(
output_yaml = write_mock.call_args[0][0]
assert output_yaml in (
# pure python dumper will quote the value after !input
"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 a_number:\n selector:\n number:\n "
" mode: box\n step: 1.0\n source_url:"
" https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml\ntriggers:\n"
" trigger: event\n event_type: !input 'trigger_event'\nactions:\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"
" multiline: false\n"
" multiple: false\n"
" service_to_call:\n"
" a_number:\n"
" selector:\n"
" number:\n"
" mode: box\n"
" step: 1.0\n"
" source_url: https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml\n"
"triggers:\n"
" trigger: event\n"
" event_type: !input 'trigger_event'\n"
"actions:\n"
" service: !input 'service_to_call'\n"
" entity_id: light.kitchen\n",
# c dumper will not quote the value after !input
"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 a_number:\n selector:\n number:\n "
" mode: box\n step: 1.0\n source_url:"
" https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml\ntriggers:\n"
" trigger: event\n event_type: !input trigger_event\nactions:\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"
" multiline: false\n"
" multiple: false\n"
" service_to_call:\n"
" a_number:\n"
" selector:\n"
" number:\n"
" mode: box\n"
" step: 1.0\n"
" source_url: https://github.com/balloob/home-assistant-config/blob/main/blueprints/automation/motion_light.yaml\n"
"triggers:\n"
" trigger: event\n"
" event_type: !input trigger_event\n"
"actions:\n"
" service: !input service_to_call\n"
" entity_id: light.kitchen\n",
)
# Make sure ita parsable and does not raise
assert len(parse_yaml(output_yaml)) > 1

View File

@ -17,6 +17,7 @@
'required': True,
'selector': dict({
'object': dict({
'multiple': False,
}),
}),
}),
@ -71,6 +72,8 @@
'name': 'Name',
'selector': dict({
'text': dict({
'multiline': False,
'multiple': False,
}),
}),
}),
@ -81,6 +84,8 @@
'required': True,
'selector': dict({
'text': dict({
'multiline': False,
'multiple': False,
}),
}),
}),

View File

@ -1160,6 +1160,7 @@ def test_constant_selector_schema(schema, valid_selections, invalid_selections)
@pytest.mark.parametrize(
"schema",
[
None, # Value is mandatory
{}, # Value is mandatory
{"value": []}, # Value must be str, int or bool
{"value": 123, "label": 123}, # Label must be str

View File

@ -987,7 +987,16 @@ async def test_async_get_all_descriptions_dot_keys(hass: HomeAssistant) -> None:
"test_domain": {
"test_service": {
"description": "",
"fields": {"test": {"selector": {"text": {}}}},
"fields": {
"test": {
"selector": {
"text": {
"multiline": False,
"multiple": False,
}
}
}
},
"name": "",
}
}
@ -1079,7 +1088,12 @@ async def test_async_get_all_descriptions_filter(hass: HomeAssistant) -> None:
"attribute": {"supported_color_modes": ["color_temp"]},
"supported_features": [1],
},
"selector": {"number": {}},
"selector": {
"number": {
"mode": "box",
"step": 1.0,
}
},
},
"entity": {
"selector": {
@ -1102,7 +1116,12 @@ async def test_async_get_all_descriptions_filter(hass: HomeAssistant) -> None:
"attribute": {"supported_color_modes": ["color_temp"]},
"supported_features": [1],
},
"selector": {"number": {}},
"selector": {
"number": {
"mode": "box",
"step": 1.0,
}
},
},
"entity": {
"selector": {

View File

@ -5,6 +5,8 @@ blueprint:
trigger_event:
selector:
text:
multiline: false
multiple: false
service_to_call:
a_number:
selector: