mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Allow float values in time periods (#38023)
This commit is contained in:
parent
4a5a09a0e9
commit
726d5fdd94
@ -86,7 +86,7 @@ import homeassistant.util.dt as dt_util
|
|||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
|
|
||||||
TIME_PERIOD_ERROR = "offset {} should be format 'HH:MM' or 'HH:MM:SS'"
|
TIME_PERIOD_ERROR = "offset {} should be format 'HH:MM', 'HH:MM:SS' or 'HH:MM:SS.F'"
|
||||||
|
|
||||||
# Home Assistant types
|
# Home Assistant types
|
||||||
byte = vol.All(vol.Coerce(int), vol.Range(min=0, max=255))
|
byte = vol.All(vol.Coerce(int), vol.Range(min=0, max=255))
|
||||||
@ -299,11 +299,11 @@ time_period_dict = vol.All(
|
|||||||
dict,
|
dict,
|
||||||
vol.Schema(
|
vol.Schema(
|
||||||
{
|
{
|
||||||
"days": vol.Coerce(int),
|
"days": vol.Coerce(float),
|
||||||
"hours": vol.Coerce(int),
|
"hours": vol.Coerce(float),
|
||||||
"minutes": vol.Coerce(int),
|
"minutes": vol.Coerce(float),
|
||||||
"seconds": vol.Coerce(int),
|
"seconds": vol.Coerce(float),
|
||||||
"milliseconds": vol.Coerce(int),
|
"milliseconds": vol.Coerce(float),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
has_at_least_one_key("days", "hours", "minutes", "seconds", "milliseconds"),
|
has_at_least_one_key("days", "hours", "minutes", "seconds", "milliseconds"),
|
||||||
@ -357,17 +357,17 @@ def time_period_str(value: str) -> timedelta:
|
|||||||
elif value.startswith("+"):
|
elif value.startswith("+"):
|
||||||
value = value[1:]
|
value = value[1:]
|
||||||
|
|
||||||
try:
|
parsed = value.split(":")
|
||||||
parsed = [int(x) for x in value.split(":")]
|
if len(parsed) not in (2, 3):
|
||||||
except ValueError:
|
|
||||||
raise vol.Invalid(TIME_PERIOD_ERROR.format(value))
|
raise vol.Invalid(TIME_PERIOD_ERROR.format(value))
|
||||||
|
try:
|
||||||
if len(parsed) == 2:
|
hour = int(parsed[0])
|
||||||
hour, minute = parsed
|
minute = int(parsed[1])
|
||||||
|
try:
|
||||||
|
second = float(parsed[2])
|
||||||
|
except IndexError:
|
||||||
second = 0
|
second = 0
|
||||||
elif len(parsed) == 3:
|
except ValueError:
|
||||||
hour, minute, second = parsed
|
|
||||||
else:
|
|
||||||
raise vol.Invalid(TIME_PERIOD_ERROR.format(value))
|
raise vol.Invalid(TIME_PERIOD_ERROR.format(value))
|
||||||
|
|
||||||
offset = timedelta(hours=hour, minutes=minute, seconds=second)
|
offset = timedelta(hours=hour, minutes=minute, seconds=second)
|
||||||
@ -378,10 +378,10 @@ def time_period_str(value: str) -> timedelta:
|
|||||||
return offset
|
return offset
|
||||||
|
|
||||||
|
|
||||||
def time_period_seconds(value: Union[int, str]) -> timedelta:
|
def time_period_seconds(value: Union[float, str]) -> timedelta:
|
||||||
"""Validate and transform seconds to a time offset."""
|
"""Validate and transform seconds to a time offset."""
|
||||||
try:
|
try:
|
||||||
return timedelta(seconds=int(value))
|
return timedelta(seconds=float(value))
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
raise vol.Invalid(f"Expected seconds, got {value}")
|
raise vol.Invalid(f"Expected seconds, got {value}")
|
||||||
|
|
||||||
|
@ -260,18 +260,49 @@ def test_time_period():
|
|||||||
"""Test time_period validation."""
|
"""Test time_period validation."""
|
||||||
schema = vol.Schema(cv.time_period)
|
schema = vol.Schema(cv.time_period)
|
||||||
|
|
||||||
options = (None, "", "hello:world", "12:", "12:34:56:78", {}, {"wrong_key": -10})
|
options = (
|
||||||
|
None,
|
||||||
|
"",
|
||||||
|
"hello:world",
|
||||||
|
"12:",
|
||||||
|
"12:34:56:78",
|
||||||
|
{},
|
||||||
|
{"wrong_key": -10},
|
||||||
|
"12.5:30",
|
||||||
|
"12:30.5",
|
||||||
|
"12.5:30:30",
|
||||||
|
"12:30.5:30",
|
||||||
|
)
|
||||||
for value in options:
|
for value in options:
|
||||||
with pytest.raises(vol.MultipleInvalid):
|
with pytest.raises(vol.MultipleInvalid):
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
||||||
options = ("8:20", "23:59", "-8:20", "-23:59:59", "-48:00", {"minutes": 5}, 1, "5")
|
options = (
|
||||||
for value in options:
|
("8:20", timedelta(hours=8, minutes=20)),
|
||||||
schema(value)
|
("23:59", timedelta(hours=23, minutes=59)),
|
||||||
|
("-8:20", -1 * timedelta(hours=8, minutes=20)),
|
||||||
assert timedelta(seconds=180) == schema("180")
|
("-1:15", -1 * timedelta(hours=1, minutes=15)),
|
||||||
assert timedelta(hours=23, minutes=59) == schema("23:59")
|
("-23:59:59", -1 * timedelta(hours=23, minutes=59, seconds=59)),
|
||||||
assert -1 * timedelta(hours=1, minutes=15) == schema("-1:15")
|
("-48:00", -1 * timedelta(days=2)),
|
||||||
|
({"minutes": 5}, timedelta(minutes=5)),
|
||||||
|
(1, timedelta(seconds=1)),
|
||||||
|
("5", timedelta(seconds=5)),
|
||||||
|
("180", timedelta(seconds=180)),
|
||||||
|
("00:08:20.5", timedelta(minutes=8, seconds=20, milliseconds=500)),
|
||||||
|
("00:23:59.999", timedelta(minutes=23, seconds=59, milliseconds=999)),
|
||||||
|
("-00:08:20.5", -1 * timedelta(minutes=8, seconds=20, milliseconds=500)),
|
||||||
|
(
|
||||||
|
"-12:59:59.999",
|
||||||
|
-1 * timedelta(hours=12, minutes=59, seconds=59, milliseconds=999),
|
||||||
|
),
|
||||||
|
({"milliseconds": 1.5}, timedelta(milliseconds=1, microseconds=500)),
|
||||||
|
({"seconds": "1.5"}, timedelta(seconds=1, milliseconds=500)),
|
||||||
|
({"minutes": "1.5"}, timedelta(minutes=1, seconds=30)),
|
||||||
|
({"hours": -1.5}, -1 * timedelta(hours=1, minutes=30)),
|
||||||
|
({"days": "-1.5"}, -1 * timedelta(days=1, hours=12)),
|
||||||
|
)
|
||||||
|
for value, result in options:
|
||||||
|
assert schema(value) == result
|
||||||
|
|
||||||
|
|
||||||
def test_remove_falsy():
|
def test_remove_falsy():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user