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
): 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"
),
),
}

View File

@ -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:

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}, (), ()),
({"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):