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 os.path as op
|
||||||
import re
|
import re
|
||||||
import sys
|
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
|
import plotly.graph_objects as go
|
||||||
from plotly.graph_objects import Figure
|
from plotly.graph_objects import Figure
|
||||||
from plotly.io import to_json
|
from plotly.io import to_json
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.utils import types
|
from reflex.utils import exceptions, types
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -288,7 +289,8 @@ def format_prop(
|
|||||||
The formatted prop to display within a tag.
|
The formatted prop to display within a tag.
|
||||||
|
|
||||||
Raises:
|
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.
|
# import here to avoid circular import.
|
||||||
from reflex.event import EVENT_ARG, EventChain
|
from reflex.event import EVENT_ARG, EventChain
|
||||||
@ -324,6 +326,8 @@ def format_prop(
|
|||||||
else:
|
else:
|
||||||
# Dump the prop as JSON.
|
# Dump the prop as JSON.
|
||||||
prop = json_dumps(prop)
|
prop = json_dumps(prop)
|
||||||
|
except exceptions.InvalidStylePropError:
|
||||||
|
raise
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
raise TypeError(f"Could not format prop: {prop} of type {type(prop)}") from 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:
|
Returns:
|
||||||
The formatted dict.
|
The formatted dict.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidStylePropError: If a style prop has a callable value
|
||||||
"""
|
"""
|
||||||
# Import here to avoid circular imports.
|
# Import here to avoid circular imports.
|
||||||
|
from reflex.event import EventHandler
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
prop_dict = {}
|
||||||
|
|
||||||
# Convert any var keys to strings.
|
# 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.
|
# 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:
|
def unescape_double_quotes_in_var(m: re.Match) -> str:
|
||||||
# Since the outer quotes are removed, the inner escaped quotes must be unescaped.
|
# 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.base import Base
|
||||||
from reflex.components.tags import Tag
|
from reflex.components.tags import Tag
|
||||||
from reflex.event import EVENT_ARG, EventChain, EventHandler, EventSpec
|
from reflex.event import EVENT_ARG, EventChain, EventHandler, EventSpec
|
||||||
|
from reflex.state import State
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
from reflex.utils import (
|
from reflex.utils import (
|
||||||
build,
|
build,
|
||||||
@ -45,6 +46,18 @@ V056 = version.parse("0.5.6")
|
|||||||
VMAXPLUS1 = version.parse(get_above_max_version())
|
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(
|
@pytest.mark.parametrize(
|
||||||
"input,output",
|
"input,output",
|
||||||
[
|
[
|
||||||
@ -744,3 +757,24 @@ def test_output_system_info(mocker):
|
|||||||
"""
|
"""
|
||||||
mocker.patch("reflex.utils.console.LOG_LEVEL", constants.LogLevel.DEBUG)
|
mocker.patch("reflex.utils.console.LOG_LEVEL", constants.LogLevel.DEBUG)
|
||||||
utils_exec.output_system_info()
|
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