Style props with Callable Values (#1751)
This commit is contained in:
parent
77edb01e74
commit
06a110a07d
7
reflex/utils/exceptions.py
Normal file
7
reflex/utils/exceptions.py
Normal file
@ -0,0 +1,7 @@
|
||||
"""Custom Exceptions."""
|
||||
|
||||
|
||||
class InvalidStylePropError(TypeError):
|
||||
"""Custom Type Error when style props have invalid values."""
|
||||
|
||||
pass
|
@ -9,14 +9,15 @@ import os
|
||||
import os.path as op
|
||||
import re
|
||||
import sys
|
||||
from typing import TYPE_CHECKING, Any, Type, Union
|
||||
import types as builtin_types
|
||||
from typing import TYPE_CHECKING, Any, Callable, Type, Union
|
||||
|
||||
import plotly.graph_objects as go
|
||||
from plotly.graph_objects import Figure
|
||||
from plotly.io import to_json
|
||||
|
||||
from reflex import constants
|
||||
from reflex.utils import types
|
||||
from reflex.utils import exceptions, types
|
||||
from reflex.vars import Var
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -288,7 +289,8 @@ def format_prop(
|
||||
The formatted prop to display within a tag.
|
||||
|
||||
Raises:
|
||||
TypeError: If the prop is not a valid type.
|
||||
exceptions.InvalidStylePropError: If the style prop value is not a valid type.
|
||||
TypeError: If the prop is not valid.
|
||||
"""
|
||||
# import here to avoid circular import.
|
||||
from reflex.event import EVENT_ARG, EventChain
|
||||
@ -324,6 +326,8 @@ def format_prop(
|
||||
else:
|
||||
# Dump the prop as JSON.
|
||||
prop = json_dumps(prop)
|
||||
except exceptions.InvalidStylePropError:
|
||||
raise
|
||||
except TypeError as e:
|
||||
raise TypeError(f"Could not format prop: {prop} of type {type(prop)}") from e
|
||||
|
||||
@ -584,15 +588,28 @@ def format_dict(prop: ComponentStyle) -> str:
|
||||
|
||||
Returns:
|
||||
The formatted dict.
|
||||
|
||||
Raises:
|
||||
InvalidStylePropError: If a style prop has a callable value
|
||||
"""
|
||||
# Import here to avoid circular imports.
|
||||
from reflex.event import EventHandler
|
||||
from reflex.vars import Var
|
||||
|
||||
prop_dict = {}
|
||||
|
||||
# Convert any var keys to strings.
|
||||
prop = {key: str(val) if isinstance(val, Var) else val for key, val in prop.items()}
|
||||
for key, value in prop.items():
|
||||
if issubclass(type(value), Callable):
|
||||
raise exceptions.InvalidStylePropError(
|
||||
f"The style prop `{to_snake_case(key)}` cannot have " # type: ignore
|
||||
f"`{value.fn.__qualname__ if isinstance(value, EventHandler) else value.__qualname__ if isinstance(value, builtin_types.FunctionType) else value}`, "
|
||||
f"an event handler or callable as its value"
|
||||
)
|
||||
prop_dict[key] = str(value) if isinstance(value, Var) else value
|
||||
|
||||
# Dump the dict to a string.
|
||||
fprop = json_dumps(prop)
|
||||
fprop = json_dumps(prop_dict)
|
||||
|
||||
def unescape_double_quotes_in_var(m: re.Match) -> str:
|
||||
# Since the outer quotes are removed, the inner escaped quotes must be unescaped.
|
||||
|
@ -11,6 +11,7 @@ from reflex import constants
|
||||
from reflex.base import Base
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.event import EVENT_ARG, EventChain, EventHandler, EventSpec
|
||||
from reflex.state import State
|
||||
from reflex.style import Style
|
||||
from reflex.utils import (
|
||||
build,
|
||||
@ -45,6 +46,18 @@ V056 = version.parse("0.5.6")
|
||||
VMAXPLUS1 = version.parse(get_above_max_version())
|
||||
|
||||
|
||||
class ExampleTestState(State):
|
||||
"""Test state class."""
|
||||
|
||||
def test_event_handler(self):
|
||||
"""Test event handler."""
|
||||
pass
|
||||
|
||||
|
||||
def test_func():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input,output",
|
||||
[
|
||||
@ -744,3 +757,24 @@ def test_output_system_info(mocker):
|
||||
"""
|
||||
mocker.patch("reflex.utils.console.LOG_LEVEL", constants.LogLevel.DEBUG)
|
||||
utils_exec.output_system_info()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"callable", [ExampleTestState.test_event_handler, test_func, lambda x: x]
|
||||
)
|
||||
def test_style_prop_with_event_handler_value(callable):
|
||||
"""Test that a type error is thrown when a style prop has a
|
||||
callable as value.
|
||||
|
||||
Args:
|
||||
callable: The callable function or event handler.
|
||||
|
||||
"""
|
||||
style = {
|
||||
"color": EventHandler(fn=callable)
|
||||
if type(callable) != EventHandler
|
||||
else callable
|
||||
}
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
format.format_dict(style) # type: ignore
|
||||
|
Loading…
Reference in New Issue
Block a user