Allow setting number selector step size to 'any' (#78265)

* Allow setting number selector step size to 'any'

* Improve test coverage
This commit is contained in:
Erik Montnemery 2022-09-15 08:29:46 +02:00 committed by GitHub
parent 30702bdcd2
commit 84a812ad05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 9 deletions

View File

@ -31,17 +31,17 @@ OPTIONS_SCHEMA = vol.Schema(
CONF_HYSTERESIS, default=DEFAULT_HYSTERESIS CONF_HYSTERESIS, default=DEFAULT_HYSTERESIS
): selector.NumberSelector( ): selector.NumberSelector(
selector.NumberSelectorConfig( selector.NumberSelectorConfig(
mode=selector.NumberSelectorMode.BOX, step=1e-3 mode=selector.NumberSelectorMode.BOX, step="any"
), ),
), ),
vol.Optional(CONF_LOWER): selector.NumberSelector( vol.Optional(CONF_LOWER): selector.NumberSelector(
selector.NumberSelectorConfig( selector.NumberSelectorConfig(
mode=selector.NumberSelectorMode.BOX, step=1e-3 mode=selector.NumberSelectorMode.BOX, step="any"
), ),
), ),
vol.Optional(CONF_UPPER): selector.NumberSelector( vol.Optional(CONF_UPPER): selector.NumberSelector(
selector.NumberSelectorConfig( selector.NumberSelectorConfig(
mode=selector.NumberSelectorMode.BOX, step=1e-3 mode=selector.NumberSelectorMode.BOX, step="any"
), ),
), ),
} }

View File

@ -2,7 +2,7 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable, Sequence from collections.abc import Callable, Sequence
from typing import Any, TypedDict, cast from typing import Any, Literal, TypedDict, cast
from uuid import UUID from uuid import UUID
import voluptuous as vol import voluptuous as vol
@ -609,7 +609,7 @@ class NumberSelectorConfig(TypedDict, total=False):
min: float min: float
max: float max: float
step: float step: float | Literal["any"]
unit_of_measurement: str unit_of_measurement: str
mode: NumberSelectorMode mode: NumberSelectorMode
@ -621,7 +621,7 @@ class NumberSelectorMode(StrEnum):
SLIDER = "slider" SLIDER = "slider"
def has_min_max_if_slider(data: Any) -> Any: def validate_slider(data: Any) -> Any:
"""Validate configuration.""" """Validate configuration."""
if data["mode"] == "box": if data["mode"] == "box":
return data 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: if "min" not in data or "max" not in data:
raise vol.Invalid("min and max are required in slider mode") 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 return data
@ -645,8 +648,8 @@ class NumberSelector(Selector):
vol.Optional("max"): vol.Coerce(float), vol.Optional("max"): vol.Coerce(float),
# Controls slider steps, and up/down keyboard binding for the box # Controls slider steps, and up/down keyboard binding for the box
# user input is not rounded # user input is not rounded
vol.Optional("step", default=1): vol.All( vol.Optional("step", default=1): vol.Any(
vol.Coerce(float), vol.Range(min=1e-3) "any", vol.All(vol.Coerce(float), vol.Range(min=1e-3))
), ),
vol.Optional(CONF_UNIT_OF_MEASUREMENT): str, vol.Optional(CONF_UNIT_OF_MEASUREMENT): str,
vol.Optional(CONF_MODE, default=NumberSelectorMode.SLIDER): vol.All( 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: def __init__(self, config: NumberSelectorConfig | None = None) -> None:

View File

@ -241,6 +241,7 @@ def test_area_selector_schema(schema, valid_selections, invalid_selections):
), ),
({"min": 10, "max": 1000, "mode": "slider", "step": 0.5}, (), ()), ({"min": 10, "max": 1000, "mode": "slider", "step": 0.5}, (), ()),
({"mode": "box"}, (10,), ()), ({"mode": "box"}, (10,), ()),
({"mode": "box", "step": "any"}, (), ()),
), ),
) )
def test_number_selector_schema(schema, valid_selections, invalid_selections): 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 {}, # Must have mandatory fields
{"mode": "slider"}, # Must have min+max in slider mode {"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): def test_number_selector_schema_error(schema):