Decorator to validate rx.color
prop fields (#2553)
This commit is contained in:
parent
a4ee985509
commit
64a90fa6eb
@ -199,7 +199,6 @@ class Component(BaseComponent, ABC):
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
TypeError: If an invalid prop is passed.
|
TypeError: If an invalid prop is passed.
|
||||||
ValueError: If a prop value is invalid.
|
|
||||||
"""
|
"""
|
||||||
# Set the id and children initially.
|
# Set the id and children initially.
|
||||||
children = kwargs.get("children", [])
|
children = kwargs.get("children", [])
|
||||||
@ -249,17 +248,10 @@ class Component(BaseComponent, ABC):
|
|||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
expected_type = fields[key].outer_type_.__args__[0]
|
expected_type = fields[key].outer_type_.__args__[0]
|
||||||
|
# validate literal fields.
|
||||||
if (
|
types.validate_literal(
|
||||||
types.is_literal(expected_type)
|
key, value, expected_type, type(self).__name__
|
||||||
and value not in expected_type.__args__
|
)
|
||||||
):
|
|
||||||
allowed_values = expected_type.__args__
|
|
||||||
if value not in allowed_values:
|
|
||||||
raise ValueError(
|
|
||||||
f"prop value for {key} of the `{type(self).__name__}` component should be one of the following: {','.join(allowed_values)}. Got '{value}' instead"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Get the passed type and the var type.
|
# Get the passed type and the var type.
|
||||||
passed_type = kwargs[key]._var_type
|
passed_type = kwargs[key]._var_type
|
||||||
expected_type = (
|
expected_type = (
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
"""The colors used in Reflex are a wrapper around https://www.radix-ui.com/colors."""
|
"""The colors used in Reflex are a wrapper around https://www.radix-ui.com/colors."""
|
||||||
|
|
||||||
from reflex.constants.colors import Color, ColorType, ShadeType
|
from reflex.constants.colors import Color, ColorType, ShadeType
|
||||||
|
from reflex.utils.types import validate_parameter_literals
|
||||||
|
|
||||||
|
|
||||||
def color(
|
@validate_parameter_literals
|
||||||
color: ColorType,
|
def color(color: ColorType, shade: ShadeType = 7, alpha: bool = False) -> Color:
|
||||||
shade: ShadeType = 7,
|
|
||||||
alpha: bool = False,
|
|
||||||
) -> Color:
|
|
||||||
"""Create a color object.
|
"""Create a color object.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import inspect
|
||||||
import types
|
import types
|
||||||
|
from functools import wraps
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
@ -330,6 +332,69 @@ def check_prop_in_allowed_types(prop: Any, allowed_types: Iterable) -> bool:
|
|||||||
return type_ in allowed_types
|
return type_ in allowed_types
|
||||||
|
|
||||||
|
|
||||||
|
def validate_literal(key: str, value: Any, expected_type: Type, comp_name: str):
|
||||||
|
"""Check that a value is a valid literal.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key: The prop name.
|
||||||
|
value: The prop value to validate.
|
||||||
|
expected_type: The expected type(literal type).
|
||||||
|
comp_name: Name of the component.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: When the value is not a valid literal.
|
||||||
|
"""
|
||||||
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
if (
|
||||||
|
is_literal(expected_type)
|
||||||
|
and not isinstance(value, Var) # validating vars is not supported yet.
|
||||||
|
and value not in expected_type.__args__
|
||||||
|
):
|
||||||
|
allowed_values = expected_type.__args__
|
||||||
|
if value not in allowed_values:
|
||||||
|
value_str = ",".join(
|
||||||
|
[str(v) if not isinstance(v, str) else f"'{v}'" for v in allowed_values]
|
||||||
|
)
|
||||||
|
raise ValueError(
|
||||||
|
f"prop value for {str(key)} of the `{comp_name}` component should be one of the following: {value_str}. Got '{value}' instead"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_parameter_literals(func):
|
||||||
|
"""Decorator to check that the arguments passed to a function
|
||||||
|
correspond to the correct function parameter if it (the parameter)
|
||||||
|
is a literal type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
func: The function to validate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The wrapper function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
func_params = list(inspect.signature(func).parameters.items())
|
||||||
|
annotations = {param[0]: param[1].annotation for param in func_params}
|
||||||
|
|
||||||
|
# validate args
|
||||||
|
for param, arg in zip(annotations.keys(), args):
|
||||||
|
if annotations[param] is inspect.Parameter.empty:
|
||||||
|
continue
|
||||||
|
validate_literal(param, arg, annotations[param], func.__name__)
|
||||||
|
|
||||||
|
# validate kwargs.
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
annotation = annotations.get(key)
|
||||||
|
if not annotation or annotation is inspect.Parameter.empty:
|
||||||
|
continue
|
||||||
|
validate_literal(key, value, annotation, func.__name__)
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
# Store this here for performance.
|
# Store this here for performance.
|
||||||
StateBases = get_base_class(StateVar)
|
StateBases = get_base_class(StateVar)
|
||||||
StateIterBases = get_base_class(StateIterVar)
|
StateIterBases = get_base_class(StateIterVar)
|
||||||
|
Loading…
Reference in New Issue
Block a user