Merge remote-tracking branch 'origin/main' into reflex-0.4.0
This commit is contained in:
commit
58b5e2f5bd
@ -204,6 +204,20 @@ async def test_client_side_state(
|
||||
set_sub_state_button = driver.find_element(By.ID, "set_sub_state")
|
||||
set_sub_sub_state_button = driver.find_element(By.ID, "set_sub_sub_state")
|
||||
|
||||
def set_sub(var: str, value: str):
|
||||
AppHarness._poll_for(lambda: state_var_input.get_attribute("value") == "")
|
||||
AppHarness._poll_for(lambda: input_value_input.get_attribute("value") == "")
|
||||
state_var_input.send_keys(var)
|
||||
input_value_input.send_keys(value)
|
||||
set_sub_state_button.click()
|
||||
|
||||
def set_sub_sub(var: str, value: str):
|
||||
AppHarness._poll_for(lambda: state_var_input.get_attribute("value") == "")
|
||||
AppHarness._poll_for(lambda: input_value_input.get_attribute("value") == "")
|
||||
state_var_input.send_keys(var)
|
||||
input_value_input.send_keys(value)
|
||||
set_sub_sub_state_button.click()
|
||||
|
||||
# get a reference to all cookie and local storage elements
|
||||
c1 = driver.find_element(By.ID, "c1")
|
||||
c2 = driver.find_element(By.ID, "c2")
|
||||
@ -241,45 +255,19 @@ async def test_client_side_state(
|
||||
assert not local_storage_items
|
||||
|
||||
# set some cookies and local storage values
|
||||
state_var_input.send_keys("c1")
|
||||
input_value_input.send_keys("c1 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("c2")
|
||||
input_value_input.send_keys("c2 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("c4")
|
||||
input_value_input.send_keys("c4 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("c5")
|
||||
input_value_input.send_keys("c5 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("c6")
|
||||
input_value_input.send_keys("c6 throwaway value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("c6")
|
||||
input_value_input.send_keys("c6 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("c7")
|
||||
input_value_input.send_keys("c7 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("l1")
|
||||
input_value_input.send_keys("l1 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("l2")
|
||||
input_value_input.send_keys("l2 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("l3")
|
||||
input_value_input.send_keys("l3 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("l4")
|
||||
input_value_input.send_keys("l4 value")
|
||||
set_sub_state_button.click()
|
||||
state_var_input.send_keys("c1s")
|
||||
input_value_input.send_keys("c1s value")
|
||||
set_sub_sub_state_button.click()
|
||||
state_var_input.send_keys("l1s")
|
||||
input_value_input.send_keys("l1s value")
|
||||
set_sub_sub_state_button.click()
|
||||
set_sub("c1", "c1 value")
|
||||
set_sub("c2", "c2 value")
|
||||
set_sub("c4", "c4 value")
|
||||
set_sub("c5", "c5 value")
|
||||
set_sub("c6", "c6 throwaway value")
|
||||
set_sub("c6", "c6 value")
|
||||
set_sub("c7", "c7 value")
|
||||
set_sub("l1", "l1 value")
|
||||
set_sub("l2", "l2 value")
|
||||
set_sub("l3", "l3 value")
|
||||
set_sub("l4", "l4 value")
|
||||
set_sub_sub("c1s", "c1s value")
|
||||
set_sub_sub("l1s", "l1s value")
|
||||
|
||||
exp_cookies = {
|
||||
"state.client_side_state.client_side_sub_state.c1": {
|
||||
@ -347,9 +335,7 @@ async def test_client_side_state(
|
||||
assert not cookies
|
||||
|
||||
# Test cookie with expiry by itself to avoid timing flakiness
|
||||
state_var_input.send_keys("c3")
|
||||
input_value_input.send_keys("c3 value")
|
||||
set_sub_state_button.click()
|
||||
set_sub("c3", "c3 value")
|
||||
AppHarness._poll_for(
|
||||
lambda: "state.client_side_state.client_side_sub_state.c3"
|
||||
in cookie_info_map(driver)
|
||||
|
1023
poetry.lock
generated
1023
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -40,10 +40,7 @@ redis = "^4.3.5"
|
||||
rich = "^13.0.0"
|
||||
sqlmodel = "^0.0.14"
|
||||
typer = ">=0.4.2,<1"
|
||||
uvicorn = [
|
||||
{version = "^0.24.0", python = ">=3.12"},
|
||||
{version = "^0.20.0", python = "<3.12"},
|
||||
]
|
||||
uvicorn = "^0.27.0"
|
||||
watchdog = "^2.3.1"
|
||||
watchfiles = "^0.19.0"
|
||||
starlette-admin = "^0.9.0"
|
||||
|
@ -1,13 +1,21 @@
|
||||
"""Shims the real reflex app module for running backend server (uvicorn or gunicorn).
|
||||
Only the app attribute is explicitly exposed.
|
||||
"""
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from reflex import constants
|
||||
from reflex.utils.prerequisites import get_compiled_app
|
||||
from reflex.utils.prerequisites import get_app, get_compiled_app
|
||||
|
||||
if "app" != constants.CompileVars.APP:
|
||||
raise AssertionError("unexpected variable name for 'app'")
|
||||
app = getattr(get_compiled_app(), constants.CompileVars.APP)
|
||||
|
||||
app_module = get_app(reload=False)
|
||||
app = getattr(app_module, constants.CompileVars.APP)
|
||||
ThreadPoolExecutor(max_workers=1).submit(app.compile_)
|
||||
|
||||
# ensure only "app" is exposed.
|
||||
del app_module
|
||||
del get_app
|
||||
del get_compiled_app
|
||||
del constants
|
||||
del ThreadPoolExecutor
|
||||
|
@ -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)
|
||||
|
@ -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.style import LIGHT_COLOR_MODE, color_mode
|
||||
from reflex.utils import format, imports
|
||||
from reflex.vars import BaseVar, Var, VarData
|
||||
@ -168,6 +169,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(
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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>"
|
||||
|
@ -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__
|
||||
|
@ -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.
|
||||
):
|
||||
|
@ -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})",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user