diff --git a/packages/reflex-base/news/+format-prop-dict.bugfix.md b/packages/reflex-base/news/+format-prop-dict.bugfix.md new file mode 100644 index 00000000000..7fa0acaf0ef --- /dev/null +++ b/packages/reflex-base/news/+format-prop-dict.bugfix.md @@ -0,0 +1 @@ +Passing a plain `dict` to `format_prop` no longer raises `AttributeError`; the dict is JSON-encoded like any other literal. diff --git a/packages/reflex-base/src/reflex_base/utils/format.py b/packages/reflex-base/src/reflex_base/utils/format.py index 5cf3724f373..a71e34c875e 100644 --- a/packages/reflex-base/src/reflex_base/utils/format.py +++ b/packages/reflex-base/src/reflex_base/utils/format.py @@ -13,7 +13,6 @@ from rich.markup import escape as escape_markup from reflex_base import constants -from reflex_base.utils import exceptions from reflex_base.utils.types import is_non_string_sequence if TYPE_CHECKING: @@ -369,7 +368,7 @@ def format_match( def format_prop( prop: Var | EventChain | ComponentStyle | str, -) -> int | float | str: +) -> str: """Format a prop. Args: @@ -379,13 +378,10 @@ def format_prop( The formatted prop to display within a tag. Raises: - exceptions.InvalidStylePropError: If the style prop value is not a valid type. TypeError: If the prop is not valid. - ValueError: If the prop is not a string. """ # import here to avoid circular import. from reflex_base.event import EventChain - from reflex_base.utils import serializers from reflex_base.vars import Var try: @@ -403,23 +399,13 @@ def format_prop( return prop return json_dumps(prop) - # For dictionaries, convert any properties to strings. - if isinstance(prop, dict): - prop = serializers.serialize_dict(prop) # pyright: ignore [reportAttributeAccessIssue] - - else: - # Dump the prop as JSON. - prop = json_dumps(prop) - except exceptions.InvalidStylePropError: - raise + # Dump the prop as JSON. + prop = json_dumps(prop) except TypeError as e: msg = f"Could not format prop: {prop} of type {type(prop)}" raise TypeError(msg) from e # Wrap the variable in braces. - if not isinstance(prop, str): - msg = f"Invalid prop: {prop}. Expected a string." - raise ValueError(msg) return wrap(prop, "{", check_first=False) diff --git a/tests/units/utils/test_format.py b/tests/units/utils/test_format.py index f8ea505bfd3..3bfbbc13343 100644 --- a/tests/units/utils/test_format.py +++ b/tests/units/utils/test_format.py @@ -578,6 +578,25 @@ def test_format_prop(prop: Var, formatted: str): assert format.format_prop(LiteralVar.create(prop)) == formatted +@pytest.mark.parametrize( + ("prop", "formatted"), + [ + ({"a": 1}, '{{"a": 1}}'), + ({"nested": {"b": [1, 2]}}, '{{"nested": {"b": [1, 2]}}}'), + ({}, "{{}}"), + ({"d": datetime.date(2026, 1, 2)}, '{{"d": "2026-01-02"}}'), + ], +) +def test_format_prop_raw_dict(prop: dict, formatted: str): + """Test that a raw dict prop is JSON-dumped and wrapped in braces. + + Args: + prop: The dict prop to test. + formatted: The expected formatted value. + """ + assert format.format_prop(prop) == formatted + + @pytest.mark.parametrize( ("single_props", "key_value_props", "output"), [