mirror of
https://github.com/home-assistant/core.git
synced 2025-06-25 07:27:08 +00:00
Add template function: shuffle (#140077)
This commit is contained in:
parent
b7094c12f7
commit
d4f205c366
@ -6,7 +6,7 @@ from ast import literal_eval
|
|||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import collections.abc
|
import collections.abc
|
||||||
from collections.abc import Callable, Generator, Iterable
|
from collections.abc import Callable, Generator, Iterable, MutableSequence
|
||||||
from contextlib import AbstractContextManager
|
from contextlib import AbstractContextManager
|
||||||
from contextvars import ContextVar
|
from contextvars import ContextVar
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
@ -2736,6 +2736,30 @@ def iif(
|
|||||||
return if_false
|
return if_false
|
||||||
|
|
||||||
|
|
||||||
|
def shuffle(*args: Any, seed: Any = None) -> MutableSequence[Any]:
|
||||||
|
"""Shuffle a list, either with a seed or without."""
|
||||||
|
if not args:
|
||||||
|
raise TypeError("shuffle expected at least 1 argument, got 0")
|
||||||
|
|
||||||
|
# If first argument is iterable and more than 1 argument provided
|
||||||
|
# but not a named seed, then use 2nd argument as seed.
|
||||||
|
if isinstance(args[0], Iterable):
|
||||||
|
items = list(args[0])
|
||||||
|
if len(args) > 1 and seed is None:
|
||||||
|
seed = args[1]
|
||||||
|
elif len(args) == 1:
|
||||||
|
raise TypeError(f"'{type(args[0]).__name__}' object is not iterable")
|
||||||
|
else:
|
||||||
|
items = list(args)
|
||||||
|
|
||||||
|
if seed:
|
||||||
|
r = random.Random(seed)
|
||||||
|
r.shuffle(items)
|
||||||
|
else:
|
||||||
|
random.shuffle(items)
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
class TemplateContextManager(AbstractContextManager):
|
class TemplateContextManager(AbstractContextManager):
|
||||||
"""Context manager to store template being parsed or rendered in a ContextVar."""
|
"""Context manager to store template being parsed or rendered in a ContextVar."""
|
||||||
|
|
||||||
@ -2936,6 +2960,7 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment):
|
|||||||
self.filters["bool"] = forgiving_boolean
|
self.filters["bool"] = forgiving_boolean
|
||||||
self.filters["version"] = version
|
self.filters["version"] = version
|
||||||
self.filters["contains"] = contains
|
self.filters["contains"] = contains
|
||||||
|
self.filters["shuffle"] = shuffle
|
||||||
self.globals["log"] = logarithm
|
self.globals["log"] = logarithm
|
||||||
self.globals["sin"] = sine
|
self.globals["sin"] = sine
|
||||||
self.globals["cos"] = cosine
|
self.globals["cos"] = cosine
|
||||||
@ -2973,6 +2998,7 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment):
|
|||||||
self.globals["bool"] = forgiving_boolean
|
self.globals["bool"] = forgiving_boolean
|
||||||
self.globals["version"] = version
|
self.globals["version"] = version
|
||||||
self.globals["zip"] = zip
|
self.globals["zip"] = zip
|
||||||
|
self.globals["shuffle"] = shuffle
|
||||||
self.tests["is_number"] = is_number
|
self.tests["is_number"] = is_number
|
||||||
self.tests["list"] = _is_list
|
self.tests["list"] = _is_list
|
||||||
self.tests["set"] = _is_set
|
self.tests["set"] = _is_set
|
||||||
|
@ -15,6 +15,7 @@ from unittest.mock import patch
|
|||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
import orjson
|
import orjson
|
||||||
import pytest
|
import pytest
|
||||||
|
from pytest_unordered import unordered
|
||||||
from syrupy import SnapshotAssertion
|
from syrupy import SnapshotAssertion
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -6672,3 +6673,54 @@ async def test_merge_response_not_mutate_original_object(
|
|||||||
|
|
||||||
tpl = template.Template(_template, hass)
|
tpl = template.Template(_template, hass)
|
||||||
assert tpl.async_render()
|
assert tpl.async_render()
|
||||||
|
|
||||||
|
|
||||||
|
def test_shuffle(hass: HomeAssistant) -> None:
|
||||||
|
"""Test the shuffle function and filter."""
|
||||||
|
assert list(
|
||||||
|
template.Template("{{ [1, 2, 3] | shuffle }}", hass).async_render()
|
||||||
|
) == unordered([1, 2, 3])
|
||||||
|
|
||||||
|
assert list(
|
||||||
|
template.Template("{{ shuffle([1, 2, 3]) }}", hass).async_render()
|
||||||
|
) == unordered([1, 2, 3])
|
||||||
|
|
||||||
|
assert list(
|
||||||
|
template.Template("{{ shuffle(1, 2, 3) }}", hass).async_render()
|
||||||
|
) == unordered([1, 2, 3])
|
||||||
|
|
||||||
|
assert list(template.Template("{{ shuffle([]) }}", hass).async_render()) == []
|
||||||
|
|
||||||
|
assert list(template.Template("{{ [] | shuffle }}", hass).async_render()) == []
|
||||||
|
|
||||||
|
# Testing using seed
|
||||||
|
assert list(
|
||||||
|
template.Template("{{ shuffle([1, 2, 3], 'seed') }}", hass).async_render()
|
||||||
|
) == [2, 3, 1]
|
||||||
|
|
||||||
|
assert list(
|
||||||
|
template.Template(
|
||||||
|
"{{ shuffle([1, 2, 3], seed='seed') }}",
|
||||||
|
hass,
|
||||||
|
).async_render()
|
||||||
|
) == [2, 3, 1]
|
||||||
|
|
||||||
|
assert list(
|
||||||
|
template.Template(
|
||||||
|
"{{ [1, 2, 3] | shuffle('seed') }}",
|
||||||
|
hass,
|
||||||
|
).async_render()
|
||||||
|
) == [2, 3, 1]
|
||||||
|
|
||||||
|
assert list(
|
||||||
|
template.Template(
|
||||||
|
"{{ [1, 2, 3] | shuffle(seed='seed') }}",
|
||||||
|
hass,
|
||||||
|
).async_render()
|
||||||
|
) == [2, 3, 1]
|
||||||
|
|
||||||
|
with pytest.raises(TemplateError):
|
||||||
|
template.Template("{{ 1 | shuffle }}", hass).async_render()
|
||||||
|
|
||||||
|
with pytest.raises(TemplateError):
|
||||||
|
template.Template("{{ shuffle() }}", hass).async_render()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user