From 7eddb732137e43a203fa1eb7edb4211fd5d12c16 Mon Sep 17 00:00:00 2001 From: Juan-Pablo Scaletti Date: Tue, 13 Jun 2023 18:48:01 -0500 Subject: [PATCH] Replace LazyString implementation with a modified collection.UserString --- src/jinjax/html_attrs.py | 24 +++++++------ tests/test_html_attrs.py | 77 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/src/jinjax/html_attrs.py b/src/jinjax/html_attrs.py index bc26fa3..5dae1c0 100644 --- a/src/jinjax/html_attrs.py +++ b/src/jinjax/html_attrs.py @@ -1,6 +1,9 @@ import re +from collections import UserString +from functools import cached_property from typing import Any + CLASS_KEY = "class" CLASS_ALT_KEY = "classes" CLASS_KEYS = (CLASS_KEY, CLASS_ALT_KEY) @@ -21,24 +24,23 @@ def quote(text: str) -> str: return f'"{text}"' -class LazyString: - """The string representation of an object, but lazily casted to str.""" +class LazyString(UserString): + """Behave like regular strings, but the actual casting of the initial value + is deferred until the value is actually required.""" - def __init__(self, value: Any) -> None: - self.value = value + __slots__ = ("_seq",) - def __str__(self) -> str: - if not hasattr(self, "_value_str"): - self._value_str = str(self.value) - return self._value_str + def __init__(self, seq): + self._seq = seq - def __eq__(self, other: Any) -> bool: - return str(self) == other + @cached_property + def data(self): + return str(self._seq) class HTMLAttrs: def __init__(self, attrs) -> None: - attributes: "dict[str, str]" = {} + attributes: "dict[str, str|LazyString]" = {} properties: "set[str]" = set() class_names = split(" ".join([ diff --git a/tests/test_html_attrs.py b/tests/test_html_attrs.py index 1b2a299..a0c9ef3 100644 --- a/tests/test_html_attrs.py +++ b/tests/test_html_attrs.py @@ -168,3 +168,80 @@ def __str__(self): with pytest.raises(RuntimeError): attrs.render() + + +def test_additional_attributes_lazily_evaluated_has_string_methods(): + class TestObject: + def __str__(self): + return 'test' + + attrs = HTMLAttrs({"some_object": TestObject()}) + + assert attrs["some_object"].__str__ + assert attrs["some_object"].__repr__ + assert attrs["some_object"].__int__ + assert attrs["some_object"].__float__ + assert attrs["some_object"].__complex__ + assert attrs["some_object"].__hash__ + assert attrs["some_object"].__eq__ + assert attrs["some_object"].__lt__ + assert attrs["some_object"].__le__ + assert attrs["some_object"].__gt__ + assert attrs["some_object"].__ge__ + assert attrs["some_object"].__contains__ + assert attrs["some_object"].__len__ + assert attrs["some_object"].__getitem__ + assert attrs["some_object"].__add__ + assert attrs["some_object"].__radd__ + assert attrs["some_object"].__mul__ + assert attrs["some_object"].__mod__ + assert attrs["some_object"].__rmod__ + assert attrs["some_object"].capitalize + assert attrs["some_object"].casefold + assert attrs["some_object"].center + assert attrs["some_object"].count + assert attrs["some_object"].removeprefix + assert attrs["some_object"].removesuffix + assert attrs["some_object"].encode + assert attrs["some_object"].endswith + assert attrs["some_object"].expandtabs + assert attrs["some_object"].find + assert attrs["some_object"].format + assert attrs["some_object"].format_map + assert attrs["some_object"].index + assert attrs["some_object"].isalpha + assert attrs["some_object"].isalnum + assert attrs["some_object"].isascii + assert attrs["some_object"].isdecimal + assert attrs["some_object"].isdigit + assert attrs["some_object"].isidentifier + assert attrs["some_object"].islower + assert attrs["some_object"].isnumeric + assert attrs["some_object"].isprintable + assert attrs["some_object"].isspace + assert attrs["some_object"].istitle + assert attrs["some_object"].isupper + assert attrs["some_object"].join + assert attrs["some_object"].ljust + assert attrs["some_object"].lower + assert attrs["some_object"].lstrip + assert attrs["some_object"].partition + assert attrs["some_object"].replace + assert attrs["some_object"].rfind + assert attrs["some_object"].rindex + assert attrs["some_object"].rjust + assert attrs["some_object"].rpartition + assert attrs["some_object"].rstrip + assert attrs["some_object"].split + assert attrs["some_object"].rsplit + assert attrs["some_object"].splitlines + assert attrs["some_object"].startswith + assert attrs["some_object"].strip + assert attrs["some_object"].swapcase + assert attrs["some_object"].title + assert attrs["some_object"].translate + assert attrs["some_object"].upper + assert attrs["some_object"].zfill + + assert attrs["some_object"].upper() == 'TEST' + assert attrs["some_object"].title() == 'Test'