Get rx.color working with fstrings (#2562)

* fix for rx.color working with fstrings

* Fix fstrings issues
This commit is contained in:
Elijah Ahianyo 2024-02-10 01:06:55 +00:00 committed by GitHub
parent fe2778379d
commit ccc9c32c95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 70 additions and 11 deletions

View File

@ -2,11 +2,10 @@
from reflex.constants.colors import Color, ColorType, ShadeType
from reflex.utils.types import validate_parameter_literals
from reflex.vars import Var
@validate_parameter_literals
def color(color: ColorType, shade: ShadeType = 7, alpha: bool = False) -> Var:
def color(color: ColorType, shade: ShadeType = 7, alpha: bool = False) -> Color:
"""Create a color object.
Args:
@ -17,4 +16,4 @@ def color(color: ColorType, shade: ShadeType = 7, alpha: bool = False) -> Var:
Returns:
The color object.
"""
return Var.create(Color(color, shade, alpha))._replace(_var_is_string=True) # type: ignore
return Color(color, shade, alpha)

View File

@ -7,6 +7,7 @@ from reflex.components.base.fragment import Fragment
from reflex.components.component import BaseComponent, Component, MemoizationLeaf
from reflex.components.tags import CondTag, Tag
from reflex.constants import Dirs
from reflex.constants.colors import Color
from reflex.utils import format, imports
from reflex.vars import BaseVar, Var, VarData
@ -167,6 +168,17 @@ def cond(condition: Any, c1: Any, c2: Any = None):
if isinstance(c2, Var):
var_datas.append(c2._var_data)
def create_var(cond_part):
return Var.create_safe(
cond_part,
_var_is_string=type(cond_part) is str or isinstance(cond_part, Color),
)
# convert the truth and false cond parts into vars so the _var_data can be obtained.
c1 = create_var(c1)
c2 = create_var(c2)
var_datas.extend([c1._var_data, c2._var_data])
# Create the conditional var.
return cond_var._replace(
_var_name=format.format_cond(

View File

@ -4,6 +4,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
from reflex.components.base import Fragment
from reflex.components.component import BaseComponent, Component, MemoizationLeaf
from reflex.components.core.colors import Color
from reflex.components.tags import MatchTag, Tag
from reflex.style import Style
from reflex.utils import format, imports, types
@ -116,7 +117,8 @@ class Match(MemoizationLeaf):
"""
_var_data = case_element._var_data if isinstance(case_element, Style) else None # type: ignore
case_element = Var.create(
case_element, _var_is_string=type(case_element) is str
case_element,
_var_is_string=type(case_element) is str or isinstance(case_element, Color),
)
if _var_data is not None:
case_element._var_data = VarData.merge(case_element._var_data, _var_data) # type: ignore

View File

@ -6,6 +6,8 @@ from .base import (
LOCAL_STORAGE,
POLLING_MAX_HTTP_BUFFER_SIZE,
PYTEST_CURRENT_TEST,
REFLEX_VAR_CLOSING_TAG,
REFLEX_VAR_OPENING_TAG,
RELOAD_CONFIG,
SKIP_COMPILE_ENV_VAR,
ColorMode,
@ -73,6 +75,8 @@ __ALL__ = [
Expiration,
Ext,
Fnm,
REFLEX_VAR_CLOSING_TAG,
REFLEX_VAR_OPENING_TAG,
GitIgnore,
Hooks,
Imports,

View File

@ -187,3 +187,6 @@ SKIP_COMPILE_ENV_VAR = "__REFLEX_SKIP_COMPILE"
# Testing os env set by pytest when running a test case.
PYTEST_CURRENT_TEST = "PYTEST_CURRENT_TEST"
RELOAD_CONFIG = "__REFLEX_RELOAD_CONFIG"
REFLEX_VAR_OPENING_TAG = "<reflex.Var>"
REFLEX_VAR_CLOSING_TAG = "</reflex.Var>"

View File

@ -25,6 +25,7 @@ from pydantic.fields import ModelField
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import DeclarativeBase, Mapped, QueryableAttribute, Relationship
from reflex import constants
from reflex.base import Base
from reflex.utils import serializers
@ -332,6 +333,18 @@ def check_prop_in_allowed_types(prop: Any, allowed_types: Iterable) -> bool:
return type_ in allowed_types
def is_encoded_fstring(value) -> bool:
"""Check if a value is an encoded Var f-string.
Args:
value: The value string to check.
Returns:
Whether the value is an f-string
"""
return isinstance(value, str) and constants.REFLEX_VAR_OPENING_TAG in value
def validate_literal(key: str, value: Any, expected_type: Type, comp_name: str):
"""Check that a value is a valid literal.
@ -349,6 +362,7 @@ def validate_literal(key: str, value: Any, expected_type: Type, comp_name: str):
if (
is_literal(expected_type)
and not isinstance(value, Var) # validating vars is not supported yet.
and not is_encoded_fstring(value) # f-strings are not supported.
and value not in expected_type.__args__
):
allowed_values = expected_type.__args__

View File

@ -202,7 +202,10 @@ def _encode_var(value: Var) -> str:
The encoded var.
"""
if value._var_data:
return f"<reflex.Var>{value._var_data.json()}</reflex.Var>" + str(value)
return (
f"{constants.REFLEX_VAR_OPENING_TAG}{value._var_data.json()}{constants.REFLEX_VAR_CLOSING_TAG}"
+ str(value)
)
return str(value)
@ -219,7 +222,7 @@ def _decode_var(value: str) -> tuple[VarData | None, str]:
if isinstance(value, str):
# Extract the state name from a formatted var
while m := re.match(
pattern=r"(.*)<reflex.Var>(.*)</reflex.Var>(.*)",
pattern=rf"(.*){constants.REFLEX_VAR_OPENING_TAG}(.*){constants.REFLEX_VAR_CLOSING_TAG}(.*)",
string=value,
flags=re.DOTALL, # Ensure . matches newline characters.
):

View File

@ -1,24 +1,46 @@
import pytest
import reflex as rx
from reflex.vars import Var
class ColorState(rx.State):
"""Test color state."""
color: str = "mint"
color_part: str = "tom"
shade: int = 4
def create_color_var(color):
return Var.create(color)
@pytest.mark.parametrize(
"color, expected",
[
(rx.color("mint"), "{`var(--mint-7)`}"),
(rx.color("mint", 3), "{`var(--mint-3)`}"),
(rx.color("mint", 3, True), "{`var(--mint-a3)`}"),
(create_color_var(rx.color("mint")), "var(--mint-7)"),
(create_color_var(rx.color("mint", 3)), "var(--mint-3)"),
(create_color_var(rx.color("mint", 3, True)), "var(--mint-a3)"),
(
rx.color(ColorState.color, ColorState.shade), # type: ignore
"{`var(--${state__color_state.color}-${state__color_state.shade})`}",
create_color_var(rx.color(ColorState.color, ColorState.shade)), # type: ignore
"var(--${state__color_state.color}-${state__color_state.shade})",
),
(
create_color_var(rx.color(f"{ColorState.color}", f"{ColorState.shade}")), # type: ignore
"var(--${state__color_state.color}-${state__color_state.shade})",
),
(
create_color_var(rx.color(f"{ColorState.color_part}ato", f"{ColorState.shade}")), # type: ignore
"var(--${state__color_state.color_part}ato-${state__color_state.shade})",
),
(
create_color_var(f'{rx.color(ColorState.color, f"{ColorState.shade}")}'), # type: ignore
"var(--${state__color_state.color}-${state__color_state.shade})",
),
(
create_color_var(f'{rx.color(f"{ColorState.color}", f"{ColorState.shade}")}'), # type: ignore
"var(--${state__color_state.color}-${state__color_state.shade})",
),
],
)