From 84a812ad05e8f4763ff9c2429882174c742f09de Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Thu, 15 Sep 2022 08:29:46 +0200 Subject: [PATCH] Allow setting number selector step size to 'any' (#78265) * Allow setting number selector step size to 'any' * Improve test coverage --- homeassistant/components/threshold/config_flow.py | 6 +++--- homeassistant/helpers/selector.py | 15 +++++++++------ tests/helpers/test_selector.py | 7 +++++++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/threshold/config_flow.py b/homeassistant/components/threshold/config_flow.py index 45ccdcb4a5c..e3af2e9c567 100644 --- a/homeassistant/components/threshold/config_flow.py +++ b/homeassistant/components/threshold/config_flow.py @@ -31,17 +31,17 @@ OPTIONS_SCHEMA = vol.Schema( CONF_HYSTERESIS, default=DEFAULT_HYSTERESIS ): selector.NumberSelector( selector.NumberSelectorConfig( - mode=selector.NumberSelectorMode.BOX, step=1e-3 + mode=selector.NumberSelectorMode.BOX, step="any" ), ), vol.Optional(CONF_LOWER): selector.NumberSelector( selector.NumberSelectorConfig( - mode=selector.NumberSelectorMode.BOX, step=1e-3 + mode=selector.NumberSelectorMode.BOX, step="any" ), ), vol.Optional(CONF_UPPER): selector.NumberSelector( selector.NumberSelectorConfig( - mode=selector.NumberSelectorMode.BOX, step=1e-3 + mode=selector.NumberSelectorMode.BOX, step="any" ), ), } diff --git a/homeassistant/helpers/selector.py b/homeassistant/helpers/selector.py index e5fa493330e..bd6dff03858 100644 --- a/homeassistant/helpers/selector.py +++ b/homeassistant/helpers/selector.py @@ -2,7 +2,7 @@ from __future__ import annotations from collections.abc import Callable, Sequence -from typing import Any, TypedDict, cast +from typing import Any, Literal, TypedDict, cast from uuid import UUID import voluptuous as vol @@ -609,7 +609,7 @@ class NumberSelectorConfig(TypedDict, total=False): min: float max: float - step: float + step: float | Literal["any"] unit_of_measurement: str mode: NumberSelectorMode @@ -621,7 +621,7 @@ class NumberSelectorMode(StrEnum): SLIDER = "slider" -def has_min_max_if_slider(data: Any) -> Any: +def validate_slider(data: Any) -> Any: """Validate configuration.""" if data["mode"] == "box": return data @@ -629,6 +629,9 @@ def has_min_max_if_slider(data: Any) -> Any: if "min" not in data or "max" not in data: raise vol.Invalid("min and max are required in slider mode") + if "step" in data and data["step"] == "any": + raise vol.Invalid("step 'any' is not allowed in slider mode") + return data @@ -645,8 +648,8 @@ class NumberSelector(Selector): vol.Optional("max"): vol.Coerce(float), # Controls slider steps, and up/down keyboard binding for the box # user input is not rounded - vol.Optional("step", default=1): vol.All( - vol.Coerce(float), vol.Range(min=1e-3) + vol.Optional("step", default=1): vol.Any( + "any", vol.All(vol.Coerce(float), vol.Range(min=1e-3)) ), vol.Optional(CONF_UNIT_OF_MEASUREMENT): str, vol.Optional(CONF_MODE, default=NumberSelectorMode.SLIDER): vol.All( @@ -654,7 +657,7 @@ class NumberSelector(Selector): ), } ), - has_min_max_if_slider, + validate_slider, ) def __init__(self, config: NumberSelectorConfig | None = None) -> None: diff --git a/tests/helpers/test_selector.py b/tests/helpers/test_selector.py index 4c20a3b7906..4b4072bd06c 100644 --- a/tests/helpers/test_selector.py +++ b/tests/helpers/test_selector.py @@ -241,6 +241,7 @@ def test_area_selector_schema(schema, valid_selections, invalid_selections): ), ({"min": 10, "max": 1000, "mode": "slider", "step": 0.5}, (), ()), ({"mode": "box"}, (10,), ()), + ({"mode": "box", "step": "any"}, (), ()), ), ) def test_number_selector_schema(schema, valid_selections, invalid_selections): @@ -253,6 +254,12 @@ def test_number_selector_schema(schema, valid_selections, invalid_selections): ( {}, # Must have mandatory fields {"mode": "slider"}, # Must have min+max in slider mode + { + "mode": "slider", + "min": 0, + "max": 1, + "step": "any", # Can't combine slider with step any + }, ), ) def test_number_selector_schema_error(schema):