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:
parent
30702bdcd2
commit
84a812ad05
3 changed files with 19 additions and 9 deletions
|
@ -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"
|
||||
),
|
||||
),
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Add table
Reference in a new issue