fully migrate vars into new system
This commit is contained in:
parent
ad14f38329
commit
de1fbdbe5b
@ -15,6 +15,8 @@ def VarOperations():
|
|||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
|
from reflex.ivars.sequence import ArrayVar
|
||||||
|
|
||||||
class VarOperationState(rx.State):
|
class VarOperationState(rx.State):
|
||||||
int_var1: int = 10
|
int_var1: int = 10
|
||||||
@ -29,8 +31,8 @@ def VarOperations():
|
|||||||
str_var2: str = "second"
|
str_var2: str = "second"
|
||||||
str_var3: str = "ThIrD"
|
str_var3: str = "ThIrD"
|
||||||
str_var4: str = "a long string"
|
str_var4: str = "a long string"
|
||||||
dict1: Dict = {1: 2}
|
dict1: Dict[int, int] = {1: 2}
|
||||||
dict2: Dict = {3: 4}
|
dict2: Dict[int, int] = {3: 4}
|
||||||
html_str: str = "<div>hello</div>"
|
html_str: str = "<div>hello</div>"
|
||||||
|
|
||||||
app = rx.App(state=rx.State)
|
app = rx.App(state=rx.State)
|
||||||
@ -547,29 +549,29 @@ def VarOperations():
|
|||||||
"second",
|
"second",
|
||||||
query=[VarOperationState.str_var2],
|
query=[VarOperationState.str_var2],
|
||||||
),
|
),
|
||||||
rx.text(rx.Var.range(2, 5).join(","), id="list_join_range1"),
|
rx.text(ArrayVar.range(2, 5).join(","), id="list_join_range1"),
|
||||||
rx.text(rx.Var.range(2, 10, 2).join(","), id="list_join_range2"),
|
rx.text(ArrayVar.range(2, 10, 2).join(","), id="list_join_range2"),
|
||||||
rx.text(rx.Var.range(5, 0, -1).join(","), id="list_join_range3"),
|
rx.text(ArrayVar.range(5, 0, -1).join(","), id="list_join_range3"),
|
||||||
rx.text(rx.Var.range(0, 3).join(","), id="list_join_range4"),
|
rx.text(ArrayVar.range(0, 3).join(","), id="list_join_range4"),
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.foreach(
|
rx.foreach(
|
||||||
rx.Var.range(0, 2),
|
ArrayVar.range(0, 2),
|
||||||
lambda x: rx.text(VarOperationState.list1[x], as_="p"),
|
lambda x: rx.text(VarOperationState.list1[x], as_="p"),
|
||||||
),
|
),
|
||||||
id="foreach_list_arg",
|
id="foreach_list_arg",
|
||||||
),
|
),
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.foreach(
|
rx.foreach(
|
||||||
rx.Var.range(0, 2),
|
ArrayVar.range(0, 2),
|
||||||
lambda x, ix: rx.text(VarOperationState.list1[ix], as_="p"),
|
lambda x, ix: rx.text(VarOperationState.list1[ix], as_="p"),
|
||||||
),
|
),
|
||||||
id="foreach_list_ix",
|
id="foreach_list_ix",
|
||||||
),
|
),
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.foreach(
|
rx.foreach(
|
||||||
rx.Var.create_safe(list(range(0, 3))).to(List[int]),
|
LiteralVar.create(list(range(0, 3))).to(ArrayVar, List[int]),
|
||||||
lambda x: rx.foreach(
|
lambda x: rx.foreach(
|
||||||
rx.Var.range(x),
|
ArrayVar.range(x),
|
||||||
lambda y: rx.text(VarOperationState.list1[y], as_="p"),
|
lambda y: rx.text(VarOperationState.list1[y], as_="p"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -783,6 +785,7 @@ def test_var_operations(driver, var_operations: AppHarness):
|
|||||||
]
|
]
|
||||||
|
|
||||||
for tag, expected in tests:
|
for tag, expected in tests:
|
||||||
|
print(tag)
|
||||||
assert driver.find_element(By.ID, tag).text == expected
|
assert driver.find_element(By.ID, tag).text == expected
|
||||||
|
|
||||||
# Highlight component with var query (does not plumb ID)
|
# Highlight component with var query (does not plumb ID)
|
||||||
|
@ -338,6 +338,7 @@ _SUBMODULES: set[str] = {
|
|||||||
"testing",
|
"testing",
|
||||||
"utils",
|
"utils",
|
||||||
"vars",
|
"vars",
|
||||||
|
"ivars",
|
||||||
"config",
|
"config",
|
||||||
"compiler",
|
"compiler",
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ from . import compiler as compiler
|
|||||||
from . import components as components
|
from . import components as components
|
||||||
from . import config as config
|
from . import config as config
|
||||||
from . import event as event
|
from . import event as event
|
||||||
|
from . import ivars as ivars
|
||||||
from . import model as model
|
from . import model as model
|
||||||
from . import style as style
|
from . import style as style
|
||||||
from . import testing as testing
|
from . import testing as testing
|
||||||
|
@ -527,9 +527,10 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
|||||||
self._enable_state()
|
self._enable_state()
|
||||||
else:
|
else:
|
||||||
for var in component._get_vars(include_children=True):
|
for var in component._get_vars(include_children=True):
|
||||||
if not var._var_data:
|
var_data = var._get_all_var_data()
|
||||||
|
if not var_data:
|
||||||
continue
|
continue
|
||||||
if not var._var_data.state:
|
if not var_data.state:
|
||||||
continue
|
continue
|
||||||
self._enable_state()
|
self._enable_state()
|
||||||
break
|
break
|
||||||
|
@ -17,6 +17,7 @@ from reflex.components.component import (
|
|||||||
StatefulComponent,
|
StatefulComponent,
|
||||||
)
|
)
|
||||||
from reflex.config import get_config
|
from reflex.config import get_config
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.state import BaseState
|
from reflex.state import BaseState
|
||||||
from reflex.style import SYSTEM_COLOR_MODE
|
from reflex.style import SYSTEM_COLOR_MODE
|
||||||
from reflex.utils.exec import is_prod_mode
|
from reflex.utils.exec import is_prod_mode
|
||||||
@ -80,7 +81,7 @@ def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None)
|
|||||||
The compiled context file.
|
The compiled context file.
|
||||||
"""
|
"""
|
||||||
appearance = getattr(theme, "appearance", None)
|
appearance = getattr(theme, "appearance", None)
|
||||||
if appearance is None or Var.create_safe(appearance)._var_name == "inherit":
|
if appearance is None or str(ImmutableVar.create_safe(appearance)) == "inherit":
|
||||||
appearance = SYSTEM_COLOR_MODE
|
appearance = SYSTEM_COLOR_MODE
|
||||||
|
|
||||||
last_compiled_time = str(datetime.now())
|
last_compiled_time = str(datetime.now())
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from reflex.components.base.fragment import Fragment
|
from reflex.components.base.fragment import Fragment
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.vars import Var
|
from reflex.ivars.base import ImmutableVar
|
||||||
|
|
||||||
|
|
||||||
class AppWrap(Fragment):
|
class AppWrap(Fragment):
|
||||||
@ -15,6 +15,4 @@ class AppWrap(Fragment):
|
|||||||
Returns:
|
Returns:
|
||||||
A new AppWrap component containing {children}.
|
A new AppWrap component containing {children}.
|
||||||
"""
|
"""
|
||||||
return super().create(
|
return super().create(ImmutableVar.create("children"))
|
||||||
Var.create("{children}", _var_is_local=False, _var_is_string=False)
|
|
||||||
)
|
|
||||||
|
@ -7,13 +7,14 @@ from typing import Any, Iterator
|
|||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.components.tags import Tag
|
from reflex.components.tags import Tag
|
||||||
from reflex.components.tags.tagless import Tagless
|
from reflex.components.tags.tagless import Tagless
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
|
||||||
class Bare(Component):
|
class Bare(Component):
|
||||||
"""A component with no tag."""
|
"""A component with no tag."""
|
||||||
|
|
||||||
contents: Var[str]
|
contents: Var[Any]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, contents: Any) -> Component:
|
def create(cls, contents: Any) -> Component:
|
||||||
@ -25,6 +26,8 @@ class Bare(Component):
|
|||||||
Returns:
|
Returns:
|
||||||
The component.
|
The component.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(contents, ImmutableVar):
|
||||||
|
return cls(contents=contents)
|
||||||
if isinstance(contents, Var) and contents._var_data:
|
if isinstance(contents, Var) and contents._var_data:
|
||||||
contents = contents.to(str)
|
contents = contents.to(str)
|
||||||
else:
|
else:
|
||||||
@ -32,6 +35,8 @@ class Bare(Component):
|
|||||||
return cls(contents=contents) # type: ignore
|
return cls(contents=contents) # type: ignore
|
||||||
|
|
||||||
def _render(self) -> Tag:
|
def _render(self) -> Tag:
|
||||||
|
if isinstance(self.contents, ImmutableVar):
|
||||||
|
return Tagless(contents=f"{{{str(self.contents)}}}")
|
||||||
return Tagless(contents=str(self.contents))
|
return Tagless(contents=str(self.contents))
|
||||||
|
|
||||||
def _get_vars(self, include_children: bool = False) -> Iterator[Var]:
|
def _get_vars(self, include_children: bool = False) -> Iterator[Var]:
|
||||||
|
@ -9,6 +9,8 @@ from reflex.components.component import Component
|
|||||||
from reflex.components.el import div, p
|
from reflex.components.el import div, p
|
||||||
from reflex.constants import Hooks, Imports
|
from reflex.constants import Hooks, Imports
|
||||||
from reflex.event import EventChain, EventHandler
|
from reflex.event import EventChain, EventHandler
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
|
from reflex.ivars.function import FunctionVar
|
||||||
from reflex.utils.imports import ImportVar
|
from reflex.utils.imports import ImportVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
@ -20,14 +22,14 @@ class ErrorBoundary(Component):
|
|||||||
tag = "ErrorBoundary"
|
tag = "ErrorBoundary"
|
||||||
|
|
||||||
# Fired when the boundary catches an error.
|
# Fired when the boundary catches an error.
|
||||||
on_error: EventHandler[lambda error, info: [error, info]] = Var.create_safe( # type: ignore
|
on_error: EventHandler[lambda error, info: [error, info]] = ImmutableVar( # type: ignore
|
||||||
"logFrontendError", _var_is_string=False, _var_is_local=False
|
"logFrontendError"
|
||||||
).to(EventChain)
|
).to(FunctionVar, EventChain)
|
||||||
|
|
||||||
# Rendered instead of the children when an error is caught.
|
# Rendered instead of the children when an error is caught.
|
||||||
Fallback_component: Var[Component] = Var.create_safe(
|
Fallback_component: Var[Component] = ImmutableVar.create_safe("Fallback")._replace(
|
||||||
"Fallback", _var_is_string=False, _var_is_local=False
|
_var_type=Component
|
||||||
).to(Component)
|
)
|
||||||
|
|
||||||
def add_imports(self) -> dict[str, list[ImportVar]]:
|
def add_imports(self) -> dict[str, list[ImportVar]]:
|
||||||
"""Add imports for the component.
|
"""Add imports for the component.
|
||||||
@ -56,7 +58,7 @@ class ErrorBoundary(Component):
|
|||||||
fallback_container = div(
|
fallback_container = div(
|
||||||
p("Ooops...Unknown Reflex error has occured:"),
|
p("Ooops...Unknown Reflex error has occured:"),
|
||||||
p(
|
p(
|
||||||
Var.create("error.message", _var_is_local=False, _var_is_string=False),
|
ImmutableVar.create("error.message"),
|
||||||
color="red",
|
color="red",
|
||||||
),
|
),
|
||||||
p("Please contact the support."),
|
p("Please contact the support."),
|
||||||
|
@ -9,6 +9,7 @@ from typing import Literal
|
|||||||
|
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ class Script(Component):
|
|||||||
|
|
||||||
# When the script will execute: afterInteractive (defer-like behavior) | beforeInteractive | lazyOnload (async-like behavior)
|
# When the script will execute: afterInteractive (defer-like behavior) | beforeInteractive | lazyOnload (async-like behavior)
|
||||||
strategy: Var[Literal["afterInteractive", "beforeInteractive", "lazyOnload"]] = (
|
strategy: Var[Literal["afterInteractive", "beforeInteractive", "lazyOnload"]] = (
|
||||||
Var.create_safe("afterInteractive", _var_is_string=True)
|
LiteralVar.create("afterInteractive")
|
||||||
)
|
)
|
||||||
|
|
||||||
# Triggered when the script is loading
|
# Triggered when the script is loading
|
||||||
|
@ -6,6 +6,7 @@ from functools import lru_cache
|
|||||||
from typing import List, Literal
|
from typing import List, Literal
|
||||||
|
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
@ -66,9 +67,7 @@ class ChakraProvider(ChakraComponent):
|
|||||||
A new ChakraProvider component.
|
A new ChakraProvider component.
|
||||||
"""
|
"""
|
||||||
return super().create(
|
return super().create(
|
||||||
theme=Var.create(
|
theme=ImmutableVar.create("extendTheme(theme)"),
|
||||||
"extendTheme(theme)", _var_is_local=False, _var_is_string=False
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_imports(self) -> ImportDict:
|
def add_imports(self) -> ImportDict:
|
||||||
|
@ -8,6 +8,7 @@ from reflex.components.chakra import (
|
|||||||
LiteralTagSize,
|
LiteralTagSize,
|
||||||
)
|
)
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ class Checkbox(ChakraComponent):
|
|||||||
name: Var[str]
|
name: Var[str]
|
||||||
|
|
||||||
# The value of the input field when checked (use is_checked prop for a bool)
|
# The value of the input field when checked (use is_checked prop for a bool)
|
||||||
value: Var[str] = Var.create("true", _var_is_string=True) # type: ignore
|
value: Var[str] = LiteralVar.create("true")
|
||||||
|
|
||||||
# The spacing between the checkbox and its label text (0.5rem)
|
# The spacing between the checkbox and its label text (0.5rem)
|
||||||
spacing: Var[str]
|
spacing: Var[str]
|
||||||
|
@ -7,6 +7,7 @@ from typing import Any, Optional
|
|||||||
from reflex.components.chakra import ChakraComponent, LiteralImageLoading
|
from reflex.components.chakra import ChakraComponent, LiteralImageLoading
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
|
||||||
@ -70,5 +71,5 @@ class Image(ChakraComponent):
|
|||||||
"""
|
"""
|
||||||
src = props.get("src", None)
|
src = props.get("src", None)
|
||||||
if src is not None and not isinstance(src, (Var)):
|
if src is not None and not isinstance(src, (Var)):
|
||||||
props["src"] = Var.create(value=src, _var_is_string=True)
|
props["src"] = LiteralVar.create(value=src)
|
||||||
return super().create(*children, **props)
|
return super().create(*children, **props)
|
||||||
|
@ -43,11 +43,12 @@ from reflex.event import (
|
|||||||
call_event_handler,
|
call_event_handler,
|
||||||
get_handler_args,
|
get_handler_args,
|
||||||
)
|
)
|
||||||
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
from reflex.style import Style, format_as_emotion
|
from reflex.style import Style, format_as_emotion
|
||||||
from reflex.utils import console, format, imports, types
|
from reflex.utils import console, format, imports, types
|
||||||
from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports
|
from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports
|
||||||
from reflex.utils.serializers import serializer
|
from reflex.utils.serializers import serializer
|
||||||
from reflex.vars import BaseVar, Var, VarData
|
from reflex.vars import BaseVar, ImmutableVarData, Var, VarData
|
||||||
|
|
||||||
|
|
||||||
class BaseComponent(Base, ABC):
|
class BaseComponent(Base, ABC):
|
||||||
@ -320,9 +321,8 @@ class Component(BaseComponent, ABC):
|
|||||||
# Set default values for any props.
|
# Set default values for any props.
|
||||||
if types._issubclass(field.type_, Var):
|
if types._issubclass(field.type_, Var):
|
||||||
field.required = False
|
field.required = False
|
||||||
field.default = Var.create(
|
if field.default is not None:
|
||||||
field.default, _var_is_string=isinstance(field.default, str)
|
field.default = LiteralVar.create(field.default)
|
||||||
)
|
|
||||||
elif types._issubclass(field.type_, EventHandler):
|
elif types._issubclass(field.type_, EventHandler):
|
||||||
field.required = False
|
field.required = False
|
||||||
|
|
||||||
@ -351,10 +351,7 @@ class Component(BaseComponent, ABC):
|
|||||||
"id": kwargs.get("id"),
|
"id": kwargs.get("id"),
|
||||||
"children": children,
|
"children": children,
|
||||||
**{
|
**{
|
||||||
prop: Var.create(
|
prop: LiteralVar.create(kwargs[prop])
|
||||||
kwargs[prop],
|
|
||||||
_var_is_string=False if isinstance(kwargs[prop], str) else None,
|
|
||||||
)
|
|
||||||
for prop in self.get_initial_props()
|
for prop in self.get_initial_props()
|
||||||
if prop in kwargs
|
if prop in kwargs
|
||||||
},
|
},
|
||||||
@ -401,10 +398,10 @@ class Component(BaseComponent, ABC):
|
|||||||
passed_types = None
|
passed_types = None
|
||||||
try:
|
try:
|
||||||
# Try to create a var from the value.
|
# Try to create a var from the value.
|
||||||
kwargs[key] = Var.create(
|
if isinstance(value, Var):
|
||||||
value,
|
kwargs[key] = value
|
||||||
_var_is_string=False if isinstance(value, str) else None,
|
else:
|
||||||
)
|
kwargs[key] = LiteralVar.create(value)
|
||||||
|
|
||||||
# Check that the var type is not None.
|
# Check that the var type is not None.
|
||||||
if kwargs[key] is None:
|
if kwargs[key] is None:
|
||||||
@ -448,7 +445,6 @@ class Component(BaseComponent, ABC):
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
f"Invalid var passed for prop {type(self).__name__}.{key}, expected type {expected_type}, got value {value_name} of type {passed_types or passed_type}."
|
f"Invalid var passed for prop {type(self).__name__}.{key}, expected type {expected_type}, got value {value_name} of type {passed_types or passed_type}."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if the key is an event trigger.
|
# Check if the key is an event trigger.
|
||||||
if key in component_specific_triggers:
|
if key in component_specific_triggers:
|
||||||
# Temporarily disable full control for event triggers.
|
# Temporarily disable full control for event triggers.
|
||||||
@ -692,9 +688,7 @@ class Component(BaseComponent, ABC):
|
|||||||
# Add ref to element if `id` is not None.
|
# Add ref to element if `id` is not None.
|
||||||
ref = self.get_ref()
|
ref = self.get_ref()
|
||||||
if ref is not None:
|
if ref is not None:
|
||||||
props["ref"] = Var.create(
|
props["ref"] = ImmutableVar.create(ref)
|
||||||
ref, _var_is_local=False, _var_is_string=False
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
props = props.copy()
|
props = props.copy()
|
||||||
|
|
||||||
@ -809,7 +803,7 @@ class Component(BaseComponent, ABC):
|
|||||||
else (
|
else (
|
||||||
Fragment.create(*child)
|
Fragment.create(*child)
|
||||||
if isinstance(child, tuple)
|
if isinstance(child, tuple)
|
||||||
else Bare.create(contents=Var.create(child, _var_is_string=True))
|
else Bare.create(contents=LiteralVar.create(child))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for child in children
|
for child in children
|
||||||
@ -936,7 +930,12 @@ class Component(BaseComponent, ABC):
|
|||||||
"""
|
"""
|
||||||
if isinstance(self.style, Var):
|
if isinstance(self.style, Var):
|
||||||
return {"css": self.style}
|
return {"css": self.style}
|
||||||
return {"css": Var.create(format_as_emotion(self.style))}
|
emotion_style = format_as_emotion(self.style)
|
||||||
|
return (
|
||||||
|
{"css": LiteralVar.create(emotion_style)}
|
||||||
|
if emotion_style is not None
|
||||||
|
else {}
|
||||||
|
)
|
||||||
|
|
||||||
def render(self) -> Dict:
|
def render(self) -> Dict:
|
||||||
"""Render the component.
|
"""Render the component.
|
||||||
@ -1091,10 +1090,10 @@ class Component(BaseComponent, ABC):
|
|||||||
# Style keeps track of its own VarData instance, so embed in a temp Var that is yielded.
|
# Style keeps track of its own VarData instance, so embed in a temp Var that is yielded.
|
||||||
if isinstance(self.style, dict) and self.style or isinstance(self.style, Var):
|
if isinstance(self.style, dict) and self.style or isinstance(self.style, Var):
|
||||||
vars.append(
|
vars.append(
|
||||||
BaseVar(
|
ImmutableVar(
|
||||||
_var_name="style",
|
_var_name="style",
|
||||||
_var_type=str,
|
_var_type=str,
|
||||||
_var_data=self.style._var_data,
|
_var_data=ImmutableVarData.merge(self.style._var_data),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1113,10 +1112,8 @@ class Component(BaseComponent, ABC):
|
|||||||
vars.append(comp_prop)
|
vars.append(comp_prop)
|
||||||
elif isinstance(comp_prop, str):
|
elif isinstance(comp_prop, str):
|
||||||
# Collapse VarData encoded in f-strings.
|
# Collapse VarData encoded in f-strings.
|
||||||
var = Var.create_safe(
|
var = LiteralVar.create(comp_prop)
|
||||||
comp_prop, _var_is_string=isinstance(comp_prop, str)
|
if var._get_all_var_data() is not None:
|
||||||
)
|
|
||||||
if var._var_data is not None:
|
|
||||||
vars.append(var)
|
vars.append(var)
|
||||||
|
|
||||||
# Get Vars associated with children.
|
# Get Vars associated with children.
|
||||||
@ -1358,8 +1355,9 @@ class Component(BaseComponent, ABC):
|
|||||||
event_imports = Imports.EVENTS if self.event_triggers else {}
|
event_imports = Imports.EVENTS if self.event_triggers else {}
|
||||||
|
|
||||||
# Collect imports from Vars used directly by this component.
|
# Collect imports from Vars used directly by this component.
|
||||||
|
var_datas = [var._get_all_var_data() for var in self._get_vars()]
|
||||||
var_imports = [
|
var_imports = [
|
||||||
var._var_data.imports for var in self._get_vars() if var._var_data
|
var_data.imports for var_data in var_datas if var_data is not None
|
||||||
]
|
]
|
||||||
|
|
||||||
added_import_dicts: list[ParsedImportDict] = []
|
added_import_dicts: list[ParsedImportDict] = []
|
||||||
@ -1427,7 +1425,7 @@ class Component(BaseComponent, ABC):
|
|||||||
"""
|
"""
|
||||||
ref = self.get_ref()
|
ref = self.get_ref()
|
||||||
if ref is not None:
|
if ref is not None:
|
||||||
return f"const {ref} = useRef(null); {str(Var.create_safe(ref, _var_is_string=False).as_ref())} = {ref};"
|
return f"const {ref} = useRef(null); {str(ImmutableVar.create_safe(ref).as_ref())} = {ref};"
|
||||||
|
|
||||||
def _get_vars_hooks(self) -> dict[str, None]:
|
def _get_vars_hooks(self) -> dict[str, None]:
|
||||||
"""Get the hooks required by vars referenced in this component.
|
"""Get the hooks required by vars referenced in this component.
|
||||||
@ -1437,8 +1435,13 @@ class Component(BaseComponent, ABC):
|
|||||||
"""
|
"""
|
||||||
vars_hooks = {}
|
vars_hooks = {}
|
||||||
for var in self._get_vars():
|
for var in self._get_vars():
|
||||||
if var._var_data:
|
var_data = var._get_all_var_data()
|
||||||
vars_hooks.update(var._var_data.hooks)
|
if var_data is not None:
|
||||||
|
vars_hooks.update(
|
||||||
|
var_data.hooks
|
||||||
|
if isinstance(var_data.hooks, dict)
|
||||||
|
else {k: None for k in var_data.hooks}
|
||||||
|
)
|
||||||
return vars_hooks
|
return vars_hooks
|
||||||
|
|
||||||
def _get_events_hooks(self) -> dict[str, None]:
|
def _get_events_hooks(self) -> dict[str, None]:
|
||||||
@ -1487,11 +1490,12 @@ class Component(BaseComponent, ABC):
|
|||||||
|
|
||||||
def extract_var_hooks(hook: Var):
|
def extract_var_hooks(hook: Var):
|
||||||
_imports = {}
|
_imports = {}
|
||||||
if hook._var_data is not None:
|
var_data = VarData.merge(hook._get_all_var_data())
|
||||||
for sub_hook in hook._var_data.hooks:
|
if var_data is not None:
|
||||||
|
for sub_hook in var_data.hooks:
|
||||||
code[sub_hook] = {}
|
code[sub_hook] = {}
|
||||||
if hook._var_data.imports:
|
if var_data.imports:
|
||||||
_imports = hook._var_data.imports
|
_imports = var_data.imports
|
||||||
if str(hook) in code:
|
if str(hook) in code:
|
||||||
code[str(hook)] = imports.merge_imports(code[str(hook)], _imports)
|
code[str(hook)] = imports.merge_imports(code[str(hook)], _imports)
|
||||||
else:
|
else:
|
||||||
@ -1505,6 +1509,7 @@ class Component(BaseComponent, ABC):
|
|||||||
extract_var_hooks(hook)
|
extract_var_hooks(hook)
|
||||||
else:
|
else:
|
||||||
code[hook] = {}
|
code[hook] = {}
|
||||||
|
|
||||||
return code
|
return code
|
||||||
|
|
||||||
def _get_hooks(self) -> str | None:
|
def _get_hooks(self) -> str | None:
|
||||||
@ -1561,7 +1566,7 @@ class Component(BaseComponent, ABC):
|
|||||||
The ref name.
|
The ref name.
|
||||||
"""
|
"""
|
||||||
# do not create a ref if the id is dynamic or unspecified
|
# do not create a ref if the id is dynamic or unspecified
|
||||||
if self.id is None or isinstance(self.id, BaseVar):
|
if self.id is None or isinstance(self.id, (BaseVar, ImmutableVar)):
|
||||||
return None
|
return None
|
||||||
return format.format_ref(self.id)
|
return format.format_ref(self.id)
|
||||||
|
|
||||||
@ -1707,7 +1712,7 @@ class CustomComponent(Component):
|
|||||||
|
|
||||||
# Handle subclasses of Base.
|
# Handle subclasses of Base.
|
||||||
if isinstance(value, Base):
|
if isinstance(value, Base):
|
||||||
base_value = Var.create(value)
|
base_value = LiteralVar.create(value)
|
||||||
|
|
||||||
# Track hooks and imports associated with Component instances.
|
# Track hooks and imports associated with Component instances.
|
||||||
if base_value is not None and isinstance(value, Component):
|
if base_value is not None and isinstance(value, Component):
|
||||||
@ -1721,7 +1726,7 @@ class CustomComponent(Component):
|
|||||||
else:
|
else:
|
||||||
value = base_value
|
value = base_value
|
||||||
else:
|
else:
|
||||||
value = Var.create(value, _var_is_string=isinstance(value, str))
|
value = LiteralVar.create(value)
|
||||||
|
|
||||||
# Set the prop.
|
# Set the prop.
|
||||||
self.props[format.to_camel_case(key)] = value
|
self.props[format.to_camel_case(key)] = value
|
||||||
@ -1800,19 +1805,19 @@ class CustomComponent(Component):
|
|||||||
"""
|
"""
|
||||||
return super()._render(props=self.props)
|
return super()._render(props=self.props)
|
||||||
|
|
||||||
def get_prop_vars(self) -> List[BaseVar]:
|
def get_prop_vars(self) -> List[ImmutableVar]:
|
||||||
"""Get the prop vars.
|
"""Get the prop vars.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The prop vars.
|
The prop vars.
|
||||||
"""
|
"""
|
||||||
return [
|
return [
|
||||||
BaseVar(
|
ImmutableVar(
|
||||||
_var_name=name,
|
_var_name=name,
|
||||||
_var_type=(
|
_var_type=(
|
||||||
prop._var_type if types._isinstance(prop, Var) else type(prop)
|
prop._var_type if types._isinstance(prop, Var) else type(prop)
|
||||||
),
|
),
|
||||||
)
|
).guess_type()
|
||||||
for name, prop in self.props.items()
|
for name, prop in self.props.items()
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1981,7 +1986,7 @@ class StatefulComponent(BaseComponent):
|
|||||||
if not should_memoize:
|
if not should_memoize:
|
||||||
# Determine if any Vars have associated data.
|
# Determine if any Vars have associated data.
|
||||||
for prop_var in component._get_vars():
|
for prop_var in component._get_vars():
|
||||||
if prop_var._var_data:
|
if prop_var._get_all_var_data():
|
||||||
should_memoize = True
|
should_memoize = True
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -1996,7 +2001,7 @@ class StatefulComponent(BaseComponent):
|
|||||||
should_memoize = True
|
should_memoize = True
|
||||||
break
|
break
|
||||||
child = cls._child_var(child)
|
child = cls._child_var(child)
|
||||||
if isinstance(child, Var) and child._var_data:
|
if isinstance(child, Var) and child._get_all_var_data():
|
||||||
should_memoize = True
|
should_memoize = True
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -2187,12 +2192,12 @@ class StatefulComponent(BaseComponent):
|
|||||||
# Calculate Var dependencies accessed by the handler for useCallback dep array.
|
# Calculate Var dependencies accessed by the handler for useCallback dep array.
|
||||||
var_deps = ["addEvents", "Event"]
|
var_deps = ["addEvents", "Event"]
|
||||||
for arg in event_args:
|
for arg in event_args:
|
||||||
if arg._var_data is None:
|
if arg._get_all_var_data() is None:
|
||||||
continue
|
continue
|
||||||
for hook in arg._var_data.hooks:
|
for hook in arg._get_all_var_data().hooks:
|
||||||
var_deps.extend(cls._get_hook_deps(hook))
|
var_deps.extend(cls._get_hook_deps(hook))
|
||||||
memo_var_data = VarData.merge(
|
memo_var_data = VarData.merge(
|
||||||
*[var._var_data for var in event_args],
|
*[var._get_all_var_data() for var in event_args],
|
||||||
VarData(
|
VarData(
|
||||||
imports={"react": [ImportVar(tag="useCallback")]},
|
imports={"react": [ImportVar(tag="useCallback")]},
|
||||||
),
|
),
|
||||||
@ -2200,7 +2205,7 @@ class StatefulComponent(BaseComponent):
|
|||||||
|
|
||||||
# Store the memoized function name and hook code for this event trigger.
|
# Store the memoized function name and hook code for this event trigger.
|
||||||
trigger_memo[event_trigger] = (
|
trigger_memo[event_trigger] = (
|
||||||
Var.create_safe(memo_name, _var_is_string=False)._replace(
|
ImmutableVar.create_safe(memo_name)._replace(
|
||||||
_var_type=EventChain, merge_var_data=memo_var_data
|
_var_type=EventChain, merge_var_data=memo_var_data
|
||||||
),
|
),
|
||||||
f"const {memo_name} = useCallback({rendered_chain}, [{', '.join(var_deps)}])",
|
f"const {memo_name} = useCallback({rendered_chain}, [{', '.join(var_deps)}])",
|
||||||
|
@ -19,47 +19,42 @@ from reflex.components.radix.themes.typography.text import Text
|
|||||||
from reflex.components.sonner.toast import Toaster, ToastProps
|
from reflex.components.sonner.toast import Toaster, ToastProps
|
||||||
from reflex.constants import Dirs, Hooks, Imports
|
from reflex.constants import Dirs, Hooks, Imports
|
||||||
from reflex.constants.compiler import CompileVars
|
from reflex.constants.compiler import CompileVars
|
||||||
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
|
from reflex.ivars.function import FunctionStringVar
|
||||||
|
from reflex.ivars.number import BooleanVar
|
||||||
|
from reflex.ivars.sequence import LiteralArrayVar
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.utils.serializers import serialize
|
from reflex.vars import ImmutableVarData, Var, VarData
|
||||||
from reflex.vars import Var, VarData
|
|
||||||
|
|
||||||
connect_error_var_data: VarData = VarData( # type: ignore
|
connect_error_var_data: VarData = VarData( # type: ignore
|
||||||
imports=Imports.EVENTS,
|
imports=Imports.EVENTS,
|
||||||
hooks={Hooks.EVENTS: None},
|
hooks={Hooks.EVENTS: None},
|
||||||
)
|
)
|
||||||
|
|
||||||
connect_errors: Var = Var.create_safe(
|
connect_errors: Var = ImmutableVar.create_safe(
|
||||||
value=CompileVars.CONNECT_ERROR,
|
value=CompileVars.CONNECT_ERROR,
|
||||||
_var_is_local=True,
|
|
||||||
_var_is_string=False,
|
|
||||||
_var_data=connect_error_var_data,
|
_var_data=connect_error_var_data,
|
||||||
)
|
)
|
||||||
|
|
||||||
connection_error: Var = Var.create_safe(
|
connection_error: Var = ImmutableVar.create_safe(
|
||||||
value="(connectErrors.length > 0) ? connectErrors[connectErrors.length - 1].message : ''",
|
value="((connectErrors.length > 0) ? connectErrors[connectErrors.length - 1].message : '')",
|
||||||
_var_is_local=False,
|
|
||||||
_var_is_string=False,
|
|
||||||
_var_data=connect_error_var_data,
|
_var_data=connect_error_var_data,
|
||||||
)
|
)
|
||||||
|
|
||||||
connection_errors_count: Var = Var.create_safe(
|
connection_errors_count: Var = ImmutableVar.create_safe(
|
||||||
value="connectErrors.length",
|
value="connectErrors.length",
|
||||||
_var_is_string=False,
|
|
||||||
_var_is_local=False,
|
|
||||||
_var_data=connect_error_var_data,
|
_var_data=connect_error_var_data,
|
||||||
)
|
)
|
||||||
|
|
||||||
has_connection_errors: Var = Var.create_safe(
|
has_connection_errors: Var = ImmutableVar.create_safe(
|
||||||
value="connectErrors.length > 0",
|
value="(connectErrors.length > 0)",
|
||||||
_var_is_string=False,
|
|
||||||
_var_data=connect_error_var_data,
|
_var_data=connect_error_var_data,
|
||||||
).to(bool)
|
).to(BooleanVar)
|
||||||
|
|
||||||
has_too_many_connection_errors: Var = Var.create_safe(
|
has_too_many_connection_errors: Var = ImmutableVar.create_safe(
|
||||||
value="connectErrors.length >= 2",
|
value="(connectErrors.length >= 2)",
|
||||||
_var_is_string=False,
|
|
||||||
_var_data=connect_error_var_data,
|
_var_data=connect_error_var_data,
|
||||||
).to(bool)
|
).to(BooleanVar)
|
||||||
|
|
||||||
|
|
||||||
class WebsocketTargetURL(Bare):
|
class WebsocketTargetURL(Bare):
|
||||||
@ -77,13 +72,21 @@ class WebsocketTargetURL(Bare):
|
|||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls) -> Component:
|
def create(cls) -> ImmutableVar:
|
||||||
"""Create a websocket target URL component.
|
"""Create a websocket target URL component.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The websocket target URL component.
|
The websocket target URL component.
|
||||||
"""
|
"""
|
||||||
return super().create(contents="{getBackendURL(env.EVENT).href}")
|
return ImmutableVar(
|
||||||
|
_var_name="getBackendURL(env.EVENT).href",
|
||||||
|
_var_data=ImmutableVarData(
|
||||||
|
imports={
|
||||||
|
"/env.json": [ImportVar(tag="env", is_default=True)],
|
||||||
|
f"/{Dirs.STATE_PATH}": [ImportVar(tag="getBackendURL")],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def default_connection_error() -> list[str | Var | Component]:
|
def default_connection_error() -> list[str | Var | Component]:
|
||||||
@ -112,24 +115,34 @@ class ConnectionToaster(Toaster):
|
|||||||
toast_id = "websocket-error"
|
toast_id = "websocket-error"
|
||||||
target_url = WebsocketTargetURL.create()
|
target_url = WebsocketTargetURL.create()
|
||||||
props = ToastProps( # type: ignore
|
props = ToastProps( # type: ignore
|
||||||
description=Var.create(
|
description=LiteralVar.create(
|
||||||
f"`Check if server is reachable at ${target_url}`",
|
f"Check if server is reachable at {target_url}",
|
||||||
_var_is_string=False,
|
|
||||||
_var_is_local=False,
|
|
||||||
),
|
),
|
||||||
close_button=True,
|
close_button=True,
|
||||||
duration=120000,
|
duration=120000,
|
||||||
id=toast_id,
|
id=toast_id,
|
||||||
)
|
)
|
||||||
hook = Var.create_safe(
|
|
||||||
|
individual_hooks = [
|
||||||
|
f"const toast_props = {str(LiteralVar.create(props))};",
|
||||||
|
f"const [userDismissed, setUserDismissed] = useState(false);",
|
||||||
|
FunctionStringVar(
|
||||||
|
"useEffect",
|
||||||
|
_var_data=VarData(
|
||||||
|
imports={
|
||||||
|
"react": ["useEffect", "useState"],
|
||||||
|
**dict(target_url._get_all_var_data().imports), # type: ignore
|
||||||
|
}
|
||||||
|
),
|
||||||
|
).call(
|
||||||
|
# TODO: This breaks the assumption that Vars are JS expressions
|
||||||
|
ImmutableVar.create_safe(
|
||||||
f"""
|
f"""
|
||||||
const toast_props = {serialize(props)};
|
() => {{
|
||||||
const [userDismissed, setUserDismissed] = useState(false);
|
if ({str(has_too_many_connection_errors)}) {{
|
||||||
useEffect(() => {{
|
|
||||||
if ({has_too_many_connection_errors}) {{
|
|
||||||
if (!userDismissed) {{
|
if (!userDismissed) {{
|
||||||
toast.error(
|
toast.error(
|
||||||
`Cannot connect to server: {connection_error}.`,
|
`Cannot connect to server: ${{{connection_error}}}.`,
|
||||||
{{...toast_props, onDismiss: () => setUserDismissed(true)}},
|
{{...toast_props, onDismiss: () => setUserDismissed(true)}},
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
@ -137,20 +150,16 @@ useEffect(() => {{
|
|||||||
toast.dismiss("{toast_id}");
|
toast.dismiss("{toast_id}");
|
||||||
setUserDismissed(false); // after reconnection reset dismissed state
|
setUserDismissed(false); // after reconnection reset dismissed state
|
||||||
}}
|
}}
|
||||||
}}, [{connect_errors}]);""",
|
}}
|
||||||
_var_is_string=False,
|
"""
|
||||||
)
|
),
|
||||||
imports: ImportDict = {
|
LiteralArrayVar([connect_errors]),
|
||||||
"react": ["useEffect", "useState"],
|
),
|
||||||
**target_url._get_imports(), # type: ignore
|
]
|
||||||
}
|
|
||||||
hook._var_data = VarData.merge(
|
|
||||||
connect_errors._var_data,
|
|
||||||
VarData(imports=imports),
|
|
||||||
)
|
|
||||||
return [
|
return [
|
||||||
Hooks.EVENTS,
|
Hooks.EVENTS,
|
||||||
hook,
|
*individual_hooks,
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -240,6 +249,7 @@ class WifiOffPulse(Icon):
|
|||||||
Returns:
|
Returns:
|
||||||
The icon component with default props applied.
|
The icon component with default props applied.
|
||||||
"""
|
"""
|
||||||
|
pulse_var = ImmutableVar.create("pulse")
|
||||||
return super().create(
|
return super().create(
|
||||||
"wifi_off",
|
"wifi_off",
|
||||||
color=props.pop("color", "crimson"),
|
color=props.pop("color", "crimson"),
|
||||||
@ -248,7 +258,7 @@ class WifiOffPulse(Icon):
|
|||||||
position=props.pop("position", "fixed"),
|
position=props.pop("position", "fixed"),
|
||||||
bottom=props.pop("botton", "33px"),
|
bottom=props.pop("botton", "33px"),
|
||||||
right=props.pop("right", "33px"),
|
right=props.pop("right", "33px"),
|
||||||
animation=Var.create(f"${{pulse}} 1s infinite", _var_is_string=True),
|
animation=LiteralVar.create(f"{pulse_var} 1s infinite"),
|
||||||
**props,
|
**props,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, Dict, Optional, Union, overload
|
from typing import Any, Dict, Optional, overload
|
||||||
|
|
||||||
from reflex.components.base.fragment import Fragment
|
from reflex.components.base.fragment import Fragment
|
||||||
from reflex.components.component import BaseComponent, Component, MemoizationLeaf
|
from reflex.components.component import BaseComponent, Component, MemoizationLeaf
|
||||||
from reflex.components.tags import CondTag, Tag
|
from reflex.components.tags import CondTag, Tag
|
||||||
from reflex.constants import Dirs
|
from reflex.constants import Dirs
|
||||||
from reflex.constants.colors import Color
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
|
from reflex.ivars.number import TernaryOperator
|
||||||
from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode
|
from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode
|
||||||
from reflex.utils import format
|
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.vars import BaseVar, Var, VarData
|
from reflex.vars import Var, VarData
|
||||||
|
|
||||||
_IS_TRUE_IMPORT: ImportDict = {
|
_IS_TRUE_IMPORT: ImportDict = {
|
||||||
f"/{Dirs.STATE_PATH}": [ImportVar(tag="isTrue")],
|
f"/{Dirs.STATE_PATH}": [ImportVar(tag="isTrue")],
|
||||||
@ -118,10 +118,10 @@ def cond(condition: Any, c1: Component) -> Component: ...
|
|||||||
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def cond(condition: Any, c1: Any, c2: Any) -> BaseVar: ...
|
def cond(condition: Any, c1: Any, c2: Any) -> ImmutableVar: ...
|
||||||
|
|
||||||
|
|
||||||
def cond(condition: Any, c1: Any, c2: Any = None):
|
def cond(condition: Any, c1: Any, c2: Any = None) -> Component | ImmutableVar:
|
||||||
"""Create a conditional component or Prop.
|
"""Create a conditional component or Prop.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -135,14 +135,8 @@ def cond(condition: Any, c1: Any, c2: Any = None):
|
|||||||
Raises:
|
Raises:
|
||||||
ValueError: If the arguments are invalid.
|
ValueError: If the arguments are invalid.
|
||||||
"""
|
"""
|
||||||
var_datas: list[VarData | None] = [
|
|
||||||
VarData( # type: ignore
|
|
||||||
imports=_IS_TRUE_IMPORT,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Convert the condition to a Var.
|
# Convert the condition to a Var.
|
||||||
cond_var = Var.create(condition)
|
cond_var = LiteralVar.create(condition)
|
||||||
assert cond_var is not None, "The condition must be set."
|
assert cond_var is not None, "The condition must be set."
|
||||||
|
|
||||||
# If the first component is a component, create a Cond component.
|
# If the first component is a component, create a Cond component.
|
||||||
@ -151,8 +145,6 @@ def cond(condition: Any, c1: Any, c2: Any = None):
|
|||||||
c2, BaseComponent
|
c2, BaseComponent
|
||||||
), "Both arguments must be components."
|
), "Both arguments must be components."
|
||||||
return Cond.create(cond_var, c1, c2)
|
return Cond.create(cond_var, c1, c2)
|
||||||
if isinstance(c1, Var):
|
|
||||||
var_datas.append(c1._var_data)
|
|
||||||
|
|
||||||
# Otherwise, create a conditional Var.
|
# Otherwise, create a conditional Var.
|
||||||
# Check that the second argument is valid.
|
# Check that the second argument is valid.
|
||||||
@ -160,37 +152,20 @@ def cond(condition: Any, c1: Any, c2: Any = None):
|
|||||||
raise ValueError("Both arguments must be props.")
|
raise ValueError("Both arguments must be props.")
|
||||||
if c2 is None:
|
if c2 is None:
|
||||||
raise ValueError("For conditional vars, the second argument must be set.")
|
raise ValueError("For conditional vars, the second argument must be set.")
|
||||||
if isinstance(c2, Var):
|
|
||||||
var_datas.append(c2._var_data)
|
|
||||||
|
|
||||||
def create_var(cond_part):
|
def create_var(cond_part):
|
||||||
return Var.create_safe(
|
return LiteralVar.create_safe(cond_part)
|
||||||
cond_part,
|
|
||||||
_var_is_string=isinstance(cond_part, (str, Color)),
|
|
||||||
)
|
|
||||||
|
|
||||||
# convert the truth and false cond parts into vars so the _var_data can be obtained.
|
# convert the truth and false cond parts into vars so the _var_data can be obtained.
|
||||||
c1 = create_var(c1)
|
c1 = create_var(c1)
|
||||||
c2 = create_var(c2)
|
c2 = create_var(c2)
|
||||||
var_datas.extend([c1._var_data, c2._var_data])
|
|
||||||
|
|
||||||
c1_type = c1._var_type if isinstance(c1, Var) else type(c1)
|
|
||||||
c2_type = c2._var_type if isinstance(c2, Var) else type(c2)
|
|
||||||
|
|
||||||
var_type = c1_type if c1_type == c2_type else Union[c1_type, c2_type]
|
|
||||||
|
|
||||||
# Create the conditional var.
|
# Create the conditional var.
|
||||||
return cond_var._replace(
|
return TernaryOperator(
|
||||||
_var_name=format.format_cond(
|
condition=cond_var,
|
||||||
cond=cond_var._var_full_name,
|
if_true=c1,
|
||||||
true_value=c1,
|
if_false=c2,
|
||||||
false_value=c2,
|
_var_data=VarData(imports=_IS_TRUE_IMPORT),
|
||||||
is_prop=True,
|
|
||||||
),
|
|
||||||
_var_type=var_type,
|
|
||||||
_var_is_local=False,
|
|
||||||
_var_full_name_needs_state_prefix=False,
|
|
||||||
merge_var_data=VarData.merge(*var_datas),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -205,7 +180,7 @@ def color_mode_cond(light: Any, dark: Any = None) -> Var | Component:
|
|||||||
The conditional component or prop.
|
The conditional component or prop.
|
||||||
"""
|
"""
|
||||||
return cond(
|
return cond(
|
||||||
resolved_color_mode == Var.create(LIGHT_COLOR_MODE, _var_is_string=True),
|
resolved_color_mode == LiteralVar.create(LIGHT_COLOR_MODE),
|
||||||
light,
|
light,
|
||||||
dark,
|
dark,
|
||||||
)
|
)
|
||||||
|
@ -9,6 +9,7 @@ from reflex.components.base.fragment import Fragment
|
|||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.components.tags import IterTag
|
from reflex.components.tags import IterTag
|
||||||
from reflex.constants import MemoizationMode
|
from reflex.constants import MemoizationMode
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.state import ComponentState
|
from reflex.state import ComponentState
|
||||||
from reflex.utils import console
|
from reflex.utils import console
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
@ -61,7 +62,7 @@ class Foreach(Component):
|
|||||||
deprecation_version="0.5.0",
|
deprecation_version="0.5.0",
|
||||||
removal_version="0.6.0",
|
removal_version="0.6.0",
|
||||||
)
|
)
|
||||||
iterable = Var.create_safe(iterable, _var_is_string=False)
|
iterable = ImmutableVar.create_safe(iterable)
|
||||||
if iterable._var_type == Any:
|
if iterable._var_type == Any:
|
||||||
raise ForeachVarError(
|
raise ForeachVarError(
|
||||||
f"Could not foreach over var `{iterable._var_full_name}` of type Any. "
|
f"Could not foreach over var `{iterable._var_full_name}` of type Any. "
|
||||||
|
@ -5,8 +5,8 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
|||||||
|
|
||||||
from reflex.components.base import Fragment
|
from reflex.components.base import Fragment
|
||||||
from reflex.components.component import BaseComponent, Component, MemoizationLeaf
|
from reflex.components.component import BaseComponent, Component, MemoizationLeaf
|
||||||
from reflex.components.core.colors import Color
|
|
||||||
from reflex.components.tags import MatchTag, Tag
|
from reflex.components.tags import MatchTag, Tag
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
from reflex.utils import format, types
|
from reflex.utils import format, types
|
||||||
from reflex.utils.exceptions import MatchTypeError
|
from reflex.utils.exceptions import MatchTypeError
|
||||||
@ -68,7 +68,7 @@ class Match(MemoizationLeaf):
|
|||||||
Raises:
|
Raises:
|
||||||
ValueError: If the condition is not provided.
|
ValueError: If the condition is not provided.
|
||||||
"""
|
"""
|
||||||
match_cond_var = Var.create(cond, _var_is_string=isinstance(cond, str))
|
match_cond_var = LiteralVar.create(cond)
|
||||||
|
|
||||||
if match_cond_var is None:
|
if match_cond_var is None:
|
||||||
raise ValueError("The condition must be set")
|
raise ValueError("The condition must be set")
|
||||||
@ -118,12 +118,11 @@ class Match(MemoizationLeaf):
|
|||||||
The case element Var.
|
The case element Var.
|
||||||
"""
|
"""
|
||||||
_var_data = case_element._var_data if isinstance(case_element, Style) else None # type: ignore
|
_var_data = case_element._var_data if isinstance(case_element, Style) else None # type: ignore
|
||||||
case_element = Var.create(
|
case_element = LiteralVar.create(case_element)
|
||||||
case_element,
|
|
||||||
_var_is_string=isinstance(case_element, (str, Color)),
|
|
||||||
)
|
|
||||||
if _var_data is not None:
|
if _var_data is not None:
|
||||||
case_element._var_data = VarData.merge(case_element._var_data, _var_data) # type: ignore
|
case_element._var_data = VarData.merge(
|
||||||
|
case_element._get_all_var_data(), _var_data
|
||||||
|
) # type: ignore
|
||||||
return case_element
|
return case_element
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -12,6 +12,7 @@ from reflex.components.radix.themes.components.button import Button
|
|||||||
from reflex.components.radix.themes.layout.box import Box
|
from reflex.components.radix.themes.layout.box import Box
|
||||||
from reflex.constants.colors import Color
|
from reflex.constants.colors import Color
|
||||||
from reflex.event import set_clipboard
|
from reflex.event import set_clipboard
|
||||||
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
@ -484,7 +485,7 @@ class CodeBlock(Component):
|
|||||||
if children:
|
if children:
|
||||||
props["code"] = children[0]
|
props["code"] = children[0]
|
||||||
if not isinstance(props["code"], Var):
|
if not isinstance(props["code"], Var):
|
||||||
props["code"] = Var.create(props["code"], _var_is_string=True)
|
props["code"] = LiteralVar.create(props["code"])
|
||||||
|
|
||||||
# Create the component.
|
# Create the component.
|
||||||
code_block = super().create(
|
code_block = super().create(
|
||||||
@ -505,10 +506,8 @@ class CodeBlock(Component):
|
|||||||
out = super()._render()
|
out = super()._render()
|
||||||
predicate, qmark, value = self.theme._var_name.partition("?")
|
predicate, qmark, value = self.theme._var_name.partition("?")
|
||||||
out.add_props(
|
out.add_props(
|
||||||
style=Var.create(
|
style=ImmutableVar.create(
|
||||||
format.to_camel_case(f"{predicate}{qmark}{value.replace('`', '')}"),
|
format.to_camel_case(f"{predicate}{qmark}{value.replace('`', '')}"),
|
||||||
_var_is_local=False,
|
|
||||||
_var_is_string=False,
|
|
||||||
)
|
)
|
||||||
).remove_props("theme", "code")
|
).remove_props("theme", "code")
|
||||||
if self.code is not None:
|
if self.code is not None:
|
||||||
|
@ -9,6 +9,7 @@ from reflex.base import Base
|
|||||||
from reflex.components.component import Component, NoSSRComponent
|
from reflex.components.component import Component, NoSSRComponent
|
||||||
from reflex.components.literals import LiteralRowMarker
|
from reflex.components.literals import LiteralRowMarker
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.utils import console, format, types
|
from reflex.utils import console, format, types
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.utils.serializers import serializer
|
from reflex.utils.serializers import serializer
|
||||||
@ -293,9 +294,7 @@ class DataEditor(NoSSRComponent):
|
|||||||
|
|
||||||
# Define the name of the getData callback associated with this component and assign to get_cell_content.
|
# Define the name of the getData callback associated with this component and assign to get_cell_content.
|
||||||
data_callback = f"getData_{editor_id}"
|
data_callback = f"getData_{editor_id}"
|
||||||
self.get_cell_content = Var.create(
|
self.get_cell_content = ImmutableVar.create(data_callback) # type: ignore
|
||||||
data_callback, _var_is_local=False, _var_is_string=False
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
code = [f"function {data_callback}([col, row])" "{"]
|
code = [f"function {data_callback}([col, row])" "{"]
|
||||||
|
|
||||||
|
@ -11,13 +11,14 @@ from reflex.components.el.element import Element
|
|||||||
from reflex.components.tags.tag import Tag
|
from reflex.components.tags.tag import Tag
|
||||||
from reflex.constants import Dirs, EventTriggers
|
from reflex.constants import Dirs, EventTriggers
|
||||||
from reflex.event import EventChain, EventHandler
|
from reflex.event import EventChain, EventHandler
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.utils.format import format_event_chain
|
from reflex.utils.format import format_event_chain
|
||||||
from reflex.utils.imports import ImportDict
|
from reflex.utils.imports import ImportDict
|
||||||
from reflex.vars import BaseVar, Var
|
from reflex.vars import BaseVar, Var
|
||||||
|
|
||||||
from .base import BaseHTML
|
from .base import BaseHTML
|
||||||
|
|
||||||
FORM_DATA = Var.create("form_data", _var_is_string=False)
|
FORM_DATA = ImmutableVar.create("form_data")
|
||||||
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
||||||
"""
|
"""
|
||||||
const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {
|
const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {
|
||||||
|
@ -17,6 +17,7 @@ from reflex.components.radix.themes.typography.heading import Heading
|
|||||||
from reflex.components.radix.themes.typography.link import Link
|
from reflex.components.radix.themes.typography.link import Link
|
||||||
from reflex.components.radix.themes.typography.text import Text
|
from reflex.components.radix.themes.typography.text import Text
|
||||||
from reflex.components.tags.tag import Tag
|
from reflex.components.tags.tag import Tag
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.utils import types
|
from reflex.utils import types
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
@ -287,7 +288,7 @@ class Markdown(Component):
|
|||||||
function {self._get_component_map_name()} () {{
|
function {self._get_component_map_name()} () {{
|
||||||
{formatted_hooks}
|
{formatted_hooks}
|
||||||
return (
|
return (
|
||||||
{str(Var.create(self.format_component_map()))}
|
{str(LiteralVar.create(self.format_component_map()))}
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
from typing import Any, Literal, Optional, Union
|
from typing import Any, Literal, Optional, Union
|
||||||
|
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.utils import types
|
from reflex.utils import types
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
@ -104,6 +105,6 @@ class Image(NextComponent):
|
|||||||
|
|
||||||
src = props.get("src", None)
|
src = props.get("src", None)
|
||||||
if src is not None and not isinstance(src, (Var)):
|
if src is not None and not isinstance(src, (Var)):
|
||||||
props["src"] = Var.create(value=src, _var_is_string=True)
|
props["src"] = LiteralVar.create(src)
|
||||||
|
|
||||||
return super().create(*children, **props)
|
return super().create(*children, **props)
|
||||||
|
@ -11,6 +11,7 @@ from reflex.components.lucide.icon import Icon
|
|||||||
from reflex.components.radix.primitives.base import RadixPrimitiveComponent
|
from reflex.components.radix.primitives.base import RadixPrimitiveComponent
|
||||||
from reflex.components.radix.themes.base import LiteralAccentColor, LiteralRadius
|
from reflex.components.radix.themes.base import LiteralAccentColor, LiteralRadius
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
from reflex.vars import Var, get_uuid_string_var
|
from reflex.vars import Var, get_uuid_string_var
|
||||||
|
|
||||||
@ -464,14 +465,12 @@ to {
|
|||||||
Returns:
|
Returns:
|
||||||
The style of the component.
|
The style of the component.
|
||||||
"""
|
"""
|
||||||
slideDown = Var.create(
|
slideDown = LiteralVar.create(
|
||||||
f"${{slideDown}} var(--animation-duration) var(--animation-easing)",
|
f"${{slideDown}} var(--animation-duration) var(--animation-easing)",
|
||||||
_var_is_string=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
slideUp = Var.create(
|
slideUp = LiteralVar.create(
|
||||||
f"${{slideUp}} var(--animation-duration) var(--animation-easing)",
|
f"${{slideUp}} var(--animation-duration) var(--animation-easing)",
|
||||||
_var_is_string=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -7,6 +7,7 @@ from typing import Any, Dict, Literal
|
|||||||
from reflex.components import Component
|
from reflex.components import Component
|
||||||
from reflex.components.tags import Tag
|
from reflex.components.tags import Tag
|
||||||
from reflex.config import get_config
|
from reflex.config import get_config
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
@ -230,10 +231,8 @@ class Theme(RadixThemesComponent):
|
|||||||
def _render(self, props: dict[str, Any] | None = None) -> Tag:
|
def _render(self, props: dict[str, Any] | None = None) -> Tag:
|
||||||
tag = super()._render(props)
|
tag = super()._render(props)
|
||||||
tag.add_props(
|
tag.add_props(
|
||||||
css=Var.create(
|
css=ImmutableVar.create(
|
||||||
"{{...theme.styles.global[':root'], ...theme.styles.global.body}}",
|
f"{{...theme.styles.global[':root'], ...theme.styles.global.body}}"
|
||||||
_var_is_local=False,
|
|
||||||
_var_is_string=False,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return tag
|
return tag
|
||||||
|
@ -17,7 +17,6 @@ rx.text(
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import dataclasses
|
|
||||||
from typing import Literal, get_args
|
from typing import Literal, get_args
|
||||||
|
|
||||||
from reflex.components.component import BaseComponent
|
from reflex.components.component import BaseComponent
|
||||||
@ -25,6 +24,7 @@ from reflex.components.core.cond import Cond, color_mode_cond, cond
|
|||||||
from reflex.components.lucide.icon import Icon
|
from reflex.components.lucide.icon import Icon
|
||||||
from reflex.components.radix.themes.components.dropdown_menu import dropdown_menu
|
from reflex.components.radix.themes.components.dropdown_menu import dropdown_menu
|
||||||
from reflex.components.radix.themes.components.switch import Switch
|
from reflex.components.radix.themes.components.switch import Switch
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.style import (
|
from reflex.style import (
|
||||||
LIGHT_COLOR_MODE,
|
LIGHT_COLOR_MODE,
|
||||||
color_mode,
|
color_mode,
|
||||||
@ -33,7 +33,7 @@ from reflex.style import (
|
|||||||
toggle_color_mode,
|
toggle_color_mode,
|
||||||
)
|
)
|
||||||
from reflex.utils import console
|
from reflex.utils import console
|
||||||
from reflex.vars import BaseVar, Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
from .components.icon_button import IconButton
|
from .components.icon_button import IconButton
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ class ColorModeSwitch(Switch):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ColorModeNamespace(BaseVar):
|
class ColorModeNamespace(ImmutableVar):
|
||||||
"""Namespace for color mode components."""
|
"""Namespace for color mode components."""
|
||||||
|
|
||||||
icon = staticmethod(ColorModeIcon.create)
|
icon = staticmethod(ColorModeIcon.create)
|
||||||
@ -204,5 +204,7 @@ class ColorModeNamespace(BaseVar):
|
|||||||
|
|
||||||
|
|
||||||
color_mode = color_mode_var_and_namespace = ColorModeNamespace(
|
color_mode = color_mode_var_and_namespace = ColorModeNamespace(
|
||||||
**dataclasses.asdict(color_mode)
|
_var_name=color_mode._var_name,
|
||||||
|
_var_type=color_mode._var_type,
|
||||||
|
_var_data=color_mode._var_data,
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,8 @@ from reflex.components.core.breakpoints import Responsive
|
|||||||
from reflex.components.radix.themes.layout.flex import Flex
|
from reflex.components.radix.themes.layout.flex import Flex
|
||||||
from reflex.components.radix.themes.typography.text import Text
|
from reflex.components.radix.themes.typography.text import Text
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
|
from reflex.ivars.function import JSON_STRINGIFY
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
from ..base import (
|
from ..base import (
|
||||||
@ -147,28 +149,24 @@ class HighLevelRadioGroup(RadixThemesComponent):
|
|||||||
color_scheme = props.pop("color_scheme", None)
|
color_scheme = props.pop("color_scheme", None)
|
||||||
default_value = props.pop("default_value", "")
|
default_value = props.pop("default_value", "")
|
||||||
|
|
||||||
default_value = Var.create(default_value, _var_is_string=True)
|
default_value = LiteralVar.create(default_value)
|
||||||
|
|
||||||
# convert only non-strings to json(JSON.stringify) so quotes are not rendered
|
# convert only non-strings to json(JSON.stringify) so quotes are not rendered
|
||||||
# for string literal types.
|
# for string literal types.
|
||||||
if isinstance(default_value, str) or (
|
if isinstance(default_value, str) or (
|
||||||
isinstance(default_value, Var) and default_value._var_type is str
|
isinstance(default_value, Var) and default_value._var_type is str
|
||||||
):
|
):
|
||||||
default_value = Var.create(default_value, _var_is_string=True) # type: ignore
|
default_value = LiteralVar.create(default_value) # type: ignore
|
||||||
else:
|
else:
|
||||||
default_value = (
|
default_value = JSON_STRINGIFY.call(ImmutableVar.create(default_value))
|
||||||
Var.create(default_value, _var_is_string=False)
|
|
||||||
.to_string() # type: ignore
|
|
||||||
._replace(_var_is_local=False)
|
|
||||||
)
|
|
||||||
|
|
||||||
def radio_group_item(value: str | Var) -> Component:
|
def radio_group_item(value: str | Var) -> Component:
|
||||||
item_value = Var.create(value, _var_is_string=False) # type: ignore
|
item_value = Var.create(value, _var_is_string=False) # type: ignore
|
||||||
item_value = rx.cond(
|
item_value = rx.cond(
|
||||||
item_value._type() == str, # type: ignore
|
item_value._type() == str, # type: ignore
|
||||||
item_value,
|
item_value,
|
||||||
item_value.to_string()._replace(_var_is_local=False), # type: ignore
|
JSON_STRINGIFY.call(item_value), # type: ignore
|
||||||
)._replace(_var_type=str)
|
)
|
||||||
|
|
||||||
return Text.create(
|
return Text.create(
|
||||||
Flex.create(
|
Flex.create(
|
||||||
|
@ -6,7 +6,8 @@ import inspect
|
|||||||
from typing import TYPE_CHECKING, Any, Callable, List, Tuple, Type, Union, get_args
|
from typing import TYPE_CHECKING, Any, Callable, List, Tuple, Type, Union, get_args
|
||||||
|
|
||||||
from reflex.components.tags.tag import Tag
|
from reflex.components.tags.tag import Tag
|
||||||
from reflex.vars import BaseVar, Var
|
from reflex.ivars.base import ImmutableVar
|
||||||
|
from reflex.vars import Var
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
@ -53,10 +54,10 @@ class IterTag(Tag):
|
|||||||
Returns:
|
Returns:
|
||||||
The index var.
|
The index var.
|
||||||
"""
|
"""
|
||||||
return BaseVar(
|
return ImmutableVar(
|
||||||
_var_name=self.index_var_name,
|
_var_name=self.index_var_name,
|
||||||
_var_type=int,
|
_var_type=int,
|
||||||
)
|
).guess_type()
|
||||||
|
|
||||||
def get_arg_var(self) -> Var:
|
def get_arg_var(self) -> Var:
|
||||||
"""Get the arg var for the tag (with curly braces).
|
"""Get the arg var for the tag (with curly braces).
|
||||||
@ -66,10 +67,10 @@ class IterTag(Tag):
|
|||||||
Returns:
|
Returns:
|
||||||
The arg var.
|
The arg var.
|
||||||
"""
|
"""
|
||||||
return BaseVar(
|
return ImmutableVar(
|
||||||
_var_name=self.arg_var_name,
|
_var_name=self.arg_var_name,
|
||||||
_var_type=self.get_iterable_var_type(),
|
_var_type=self.get_iterable_var_type(),
|
||||||
)
|
).guess_type()
|
||||||
|
|
||||||
def get_index_var_arg(self) -> Var:
|
def get_index_var_arg(self) -> Var:
|
||||||
"""Get the index var for the tag (without curly braces).
|
"""Get the index var for the tag (without curly braces).
|
||||||
@ -79,11 +80,10 @@ class IterTag(Tag):
|
|||||||
Returns:
|
Returns:
|
||||||
The index var.
|
The index var.
|
||||||
"""
|
"""
|
||||||
return BaseVar(
|
return ImmutableVar(
|
||||||
_var_name=self.index_var_name,
|
_var_name=self.index_var_name,
|
||||||
_var_type=int,
|
_var_type=int,
|
||||||
_var_is_local=True,
|
).guess_type()
|
||||||
)
|
|
||||||
|
|
||||||
def get_arg_var_arg(self) -> Var:
|
def get_arg_var_arg(self) -> Var:
|
||||||
"""Get the arg var for the tag (without curly braces).
|
"""Get the arg var for the tag (without curly braces).
|
||||||
@ -93,11 +93,10 @@ class IterTag(Tag):
|
|||||||
Returns:
|
Returns:
|
||||||
The arg var.
|
The arg var.
|
||||||
"""
|
"""
|
||||||
return BaseVar(
|
return ImmutableVar(
|
||||||
_var_name=self.arg_var_name,
|
_var_name=self.arg_var_name,
|
||||||
_var_type=self.get_iterable_var_type(),
|
_var_type=self.get_iterable_var_type(),
|
||||||
_var_is_local=True,
|
).guess_type()
|
||||||
)
|
|
||||||
|
|
||||||
def render_component(self) -> Component:
|
def render_component(self) -> Component:
|
||||||
"""Render the component.
|
"""Render the component.
|
||||||
|
@ -6,6 +6,7 @@ from typing import Any, Dict, List, Optional, Set, Tuple, Union
|
|||||||
|
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.event import EventChain
|
from reflex.event import EventChain
|
||||||
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
from reflex.utils import format, types
|
from reflex.utils import format, types
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ class Tag(Base):
|
|||||||
# Convert any props to vars.
|
# Convert any props to vars.
|
||||||
if "props" in kwargs:
|
if "props" in kwargs:
|
||||||
kwargs["props"] = {
|
kwargs["props"] = {
|
||||||
name: Var.create(value, _var_is_string=False)
|
name: ImmutableVar.create(value)
|
||||||
for name, value in kwargs["props"].items()
|
for name, value in kwargs["props"].items()
|
||||||
}
|
}
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@ -63,14 +64,12 @@ class Tag(Base):
|
|||||||
Returns:
|
Returns:
|
||||||
The tag with the props added.
|
The tag with the props added.
|
||||||
"""
|
"""
|
||||||
from reflex.components.core.colors import Color
|
|
||||||
|
|
||||||
self.props.update(
|
self.props.update(
|
||||||
{
|
{
|
||||||
format.to_camel_case(name, allow_hyphens=True): prop
|
format.to_camel_case(name, allow_hyphens=True): (
|
||||||
|
prop
|
||||||
if types._isinstance(prop, Union[EventChain, dict])
|
if types._isinstance(prop, Union[EventChain, dict])
|
||||||
else Var.create(
|
else LiteralVar.create(prop)
|
||||||
prop, _var_is_string=isinstance(prop, Color)
|
|
||||||
) # rx.color is always a string
|
) # rx.color is always a string
|
||||||
for name, prop in kwargs.items()
|
for name, prop in kwargs.items()
|
||||||
if self.is_valid_prop(prop)
|
if self.is_valid_prop(prop)
|
||||||
|
@ -18,9 +18,12 @@ from typing import (
|
|||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
|
from reflex.ivars.function import FunctionStringVar, FunctionVar
|
||||||
|
from reflex.ivars.object import ObjectVar
|
||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
from reflex.utils.types import ArgsSpec
|
from reflex.utils.types import ArgsSpec
|
||||||
from reflex.vars import BaseVar, Var
|
from reflex.vars import ImmutableVarData, Var
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
@ -186,7 +189,7 @@ class EventHandler(EventActionsMixin):
|
|||||||
|
|
||||||
# Get the function args.
|
# Get the function args.
|
||||||
fn_args = inspect.getfullargspec(self.fn).args[1:]
|
fn_args = inspect.getfullargspec(self.fn).args[1:]
|
||||||
fn_args = (Var.create_safe(arg, _var_is_string=False) for arg in fn_args)
|
fn_args = (ImmutableVar.create_safe(arg) for arg in fn_args)
|
||||||
|
|
||||||
# Construct the payload.
|
# Construct the payload.
|
||||||
values = []
|
values = []
|
||||||
@ -197,7 +200,7 @@ class EventHandler(EventActionsMixin):
|
|||||||
|
|
||||||
# Otherwise, convert to JSON.
|
# Otherwise, convert to JSON.
|
||||||
try:
|
try:
|
||||||
values.append(Var.create(arg, _var_is_string=isinstance(arg, str)))
|
values.append(LiteralVar.create(arg))
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
raise EventHandlerTypeError(
|
raise EventHandlerTypeError(
|
||||||
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
||||||
@ -264,13 +267,13 @@ class EventSpec(EventActionsMixin):
|
|||||||
|
|
||||||
# Get the remaining unfilled function args.
|
# Get the remaining unfilled function args.
|
||||||
fn_args = inspect.getfullargspec(self.handler.fn).args[1 + len(self.args) :]
|
fn_args = inspect.getfullargspec(self.handler.fn).args[1 + len(self.args) :]
|
||||||
fn_args = (Var.create_safe(arg, _var_is_string=False) for arg in fn_args)
|
fn_args = (ImmutableVar.create_safe(arg) for arg in fn_args)
|
||||||
|
|
||||||
# Construct the payload.
|
# Construct the payload.
|
||||||
values = []
|
values = []
|
||||||
for arg in args:
|
for arg in args:
|
||||||
try:
|
try:
|
||||||
values.append(Var.create(arg, _var_is_string=isinstance(arg, str)))
|
values.append(LiteralVar.create(arg))
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
raise EventHandlerTypeError(
|
raise EventHandlerTypeError(
|
||||||
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
||||||
@ -388,15 +391,16 @@ class FileUpload(Base):
|
|||||||
upload_id = self.upload_id or DEFAULT_UPLOAD_ID
|
upload_id = self.upload_id or DEFAULT_UPLOAD_ID
|
||||||
spec_args = [
|
spec_args = [
|
||||||
(
|
(
|
||||||
Var.create_safe("files", _var_is_string=False),
|
ImmutableVar.create_safe("files"),
|
||||||
Var.create_safe(
|
ImmutableVar(
|
||||||
f"filesById[{Var.create_safe(upload_id, _var_is_string=True)._var_name_unwrapped}]",
|
_var_name="filesById",
|
||||||
_var_is_string=False,
|
_var_type=dict[str, Any],
|
||||||
)._replace(_var_data=upload_files_context_var_data),
|
_var_data=ImmutableVarData.merge(upload_files_context_var_data),
|
||||||
|
).to(ObjectVar)[LiteralVar.create_safe(upload_id)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Var.create_safe("upload_id", _var_is_string=False),
|
ImmutableVar.create_safe("upload_id"),
|
||||||
Var.create_safe(upload_id, _var_is_string=True),
|
LiteralVar.create_safe(upload_id),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
if self.on_upload_progress is not None:
|
if self.on_upload_progress is not None:
|
||||||
@ -424,11 +428,10 @@ class FileUpload(Base):
|
|||||||
formatted_chain = str(format.format_prop(on_upload_progress_chain))
|
formatted_chain = str(format.format_prop(on_upload_progress_chain))
|
||||||
spec_args.append(
|
spec_args.append(
|
||||||
(
|
(
|
||||||
Var.create_safe("on_upload_progress", _var_is_string=False),
|
ImmutableVar.create_safe("on_upload_progress"),
|
||||||
BaseVar(
|
FunctionStringVar(
|
||||||
_var_name=formatted_chain.strip("{}"),
|
formatted_chain.strip("{}"),
|
||||||
_var_type=EventChain,
|
).to(FunctionVar, EventChain),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return EventSpec(
|
return EventSpec(
|
||||||
@ -465,8 +468,8 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
|
|||||||
handler=EventHandler(fn=fn),
|
handler=EventHandler(fn=fn),
|
||||||
args=tuple(
|
args=tuple(
|
||||||
(
|
(
|
||||||
Var.create_safe(k, _var_is_string=False),
|
ImmutableVar.create_safe(k),
|
||||||
Var.create_safe(v, _var_is_string=isinstance(v, str)),
|
LiteralVar.create(v),
|
||||||
)
|
)
|
||||||
for k, v in kwargs.items()
|
for k, v in kwargs.items()
|
||||||
),
|
),
|
||||||
@ -542,7 +545,7 @@ def set_focus(ref: str) -> EventSpec:
|
|||||||
return server_side(
|
return server_side(
|
||||||
"_set_focus",
|
"_set_focus",
|
||||||
get_fn_signature(set_focus),
|
get_fn_signature(set_focus),
|
||||||
ref=Var.create_safe(format.format_ref(ref), _var_is_string=True),
|
ref=ImmutableVar.create_safe(format.format_ref(ref)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -573,7 +576,7 @@ def set_value(ref: str, value: Any) -> EventSpec:
|
|||||||
return server_side(
|
return server_side(
|
||||||
"_set_value",
|
"_set_value",
|
||||||
get_fn_signature(set_value),
|
get_fn_signature(set_value),
|
||||||
ref=Var.create_safe(format.format_ref(ref), _var_is_string=True),
|
ref=ImmutableVar.create_safe(format.format_ref(ref)),
|
||||||
value=value,
|
value=value,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -757,11 +760,13 @@ def _callback_arg_spec(eval_result):
|
|||||||
|
|
||||||
def call_script(
|
def call_script(
|
||||||
javascript_code: str | Var[str],
|
javascript_code: str | Var[str],
|
||||||
callback: EventSpec
|
callback: (
|
||||||
|
EventSpec
|
||||||
| EventHandler
|
| EventHandler
|
||||||
| Callable
|
| Callable
|
||||||
| List[EventSpec | EventHandler | Callable]
|
| List[EventSpec | EventHandler | Callable]
|
||||||
| None = None,
|
| None
|
||||||
|
) = None,
|
||||||
) -> EventSpec:
|
) -> EventSpec:
|
||||||
"""Create an event handler that executes arbitrary javascript code.
|
"""Create an event handler that executes arbitrary javascript code.
|
||||||
|
|
||||||
@ -865,10 +870,8 @@ def parse_args_spec(arg_spec: ArgsSpec):
|
|||||||
annotations = get_type_hints(arg_spec)
|
annotations = get_type_hints(arg_spec)
|
||||||
return arg_spec(
|
return arg_spec(
|
||||||
*[
|
*[
|
||||||
BaseVar(
|
ImmutableVar(f"_{l_arg}").to(
|
||||||
_var_name=f"_{l_arg}",
|
ObjectVar, annotations.get(l_arg, FrontendEvent)
|
||||||
_var_type=annotations.get(l_arg, FrontendEvent),
|
|
||||||
_var_is_local=True,
|
|
||||||
)
|
)
|
||||||
for l_arg in spec.args
|
for l_arg in spec.args
|
||||||
]
|
]
|
||||||
|
@ -8,7 +8,6 @@ from reflex.components.sonner.toast import toast as toast
|
|||||||
|
|
||||||
from ..utils.console import warn
|
from ..utils.console import warn
|
||||||
from . import hooks as hooks
|
from . import hooks as hooks
|
||||||
from . import vars as vars
|
|
||||||
from .assets import asset as asset
|
from .assets import asset as asset
|
||||||
from .client_state import ClientStateVar as ClientStateVar
|
from .client_state import ClientStateVar as ClientStateVar
|
||||||
from .layout import layout as layout
|
from .layout import layout as layout
|
||||||
@ -43,7 +42,6 @@ _x = ExperimentalNamespace(
|
|||||||
asset=asset,
|
asset=asset,
|
||||||
client_state=ClientStateVar.create,
|
client_state=ClientStateVar.create,
|
||||||
hooks=hooks,
|
hooks=hooks,
|
||||||
vars=vars,
|
|
||||||
layout=layout,
|
layout=layout,
|
||||||
progress=progress,
|
progress=progress,
|
||||||
PropsBase=PropsBase,
|
PropsBase=PropsBase,
|
||||||
|
@ -6,6 +6,7 @@ import dataclasses
|
|||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import sys
|
import sys
|
||||||
|
import traceback
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
@ -13,12 +14,14 @@ from typing import (
|
|||||||
Dict,
|
Dict,
|
||||||
Generic,
|
Generic,
|
||||||
List,
|
List,
|
||||||
|
Literal,
|
||||||
Optional,
|
Optional,
|
||||||
Set,
|
Set,
|
||||||
Tuple,
|
Tuple,
|
||||||
Type,
|
Type,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Union,
|
Union,
|
||||||
|
get_args,
|
||||||
overload,
|
overload,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,7 +29,7 @@ from typing_extensions import ParamSpec, get_origin
|
|||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.utils import serializers, types
|
from reflex.utils import console, imports, serializers, types
|
||||||
from reflex.utils.exceptions import VarTypeError
|
from reflex.utils.exceptions import VarTypeError
|
||||||
from reflex.vars import (
|
from reflex.vars import (
|
||||||
ImmutableVarData,
|
ImmutableVarData,
|
||||||
@ -44,9 +47,16 @@ if TYPE_CHECKING:
|
|||||||
NumberVar,
|
NumberVar,
|
||||||
ToBooleanVarOperation,
|
ToBooleanVarOperation,
|
||||||
ToNumberVarOperation,
|
ToNumberVarOperation,
|
||||||
|
EqualOperation,
|
||||||
|
GreaterThanOperation,
|
||||||
|
GreaterThanOrEqualOperation,
|
||||||
|
LessThanOperation,
|
||||||
|
LessThanOrEqualOperation,
|
||||||
)
|
)
|
||||||
from .object import ObjectVar, ToObjectOperation
|
from .object import ObjectVar, ToObjectOperation
|
||||||
from .sequence import ArrayVar, StringVar, ToArrayOperation, ToStringOperation
|
from .sequence import ArrayVar, StringVar, ToArrayOperation, ToStringOperation
|
||||||
|
from reflex.state import BaseState
|
||||||
|
|
||||||
|
|
||||||
VAR_TYPE = TypeVar("VAR_TYPE")
|
VAR_TYPE = TypeVar("VAR_TYPE")
|
||||||
|
|
||||||
@ -376,10 +386,10 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|||||||
from .function import FunctionVar, ToFunctionOperation
|
from .function import FunctionVar, ToFunctionOperation
|
||||||
|
|
||||||
if issubclass(output, FunctionVar):
|
if issubclass(output, FunctionVar):
|
||||||
if fixed_type is not None and not issubclass(fixed_type, Callable):
|
# if fixed_type is not None and not issubclass(fixed_type, Callable):
|
||||||
raise TypeError(
|
# raise TypeError(
|
||||||
f"Unsupported type {var_type} for FunctionVar. Must be Callable."
|
# f"Unsupported type {var_type} for FunctionVar. Must be Callable."
|
||||||
)
|
# )
|
||||||
return ToFunctionOperation(self, var_type or Callable)
|
return ToFunctionOperation(self, var_type or Callable)
|
||||||
|
|
||||||
return output(
|
return output(
|
||||||
@ -405,6 +415,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|||||||
|
|
||||||
fixed_type = var_type if inspect.isclass(var_type) else get_origin(var_type)
|
fixed_type = var_type if inspect.isclass(var_type) else get_origin(var_type)
|
||||||
|
|
||||||
|
if fixed_type is Union:
|
||||||
|
return self
|
||||||
|
|
||||||
if issubclass(fixed_type, (int, float)):
|
if issubclass(fixed_type, (int, float)):
|
||||||
return self.to(NumberVar, var_type)
|
return self.to(NumberVar, var_type)
|
||||||
if issubclass(fixed_type, dict):
|
if issubclass(fixed_type, dict):
|
||||||
@ -417,6 +430,276 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|||||||
return self.to(ObjectVar, var_type)
|
return self.to(ObjectVar, var_type)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def get_default_value(self) -> Any:
|
||||||
|
"""Get the default value of the var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The default value of the var.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ImportError: If the var is a dataframe and pandas is not installed.
|
||||||
|
"""
|
||||||
|
if types.is_optional(self._var_type):
|
||||||
|
return None
|
||||||
|
|
||||||
|
type_ = (
|
||||||
|
get_origin(self._var_type)
|
||||||
|
if types.is_generic_alias(self._var_type)
|
||||||
|
else self._var_type
|
||||||
|
)
|
||||||
|
if type_ is Literal:
|
||||||
|
args = get_args(self._var_type)
|
||||||
|
return args[0] if args else None
|
||||||
|
if issubclass(type_, str):
|
||||||
|
return ""
|
||||||
|
if issubclass(type_, types.get_args(Union[int, float])):
|
||||||
|
return 0
|
||||||
|
if issubclass(type_, bool):
|
||||||
|
return False
|
||||||
|
if issubclass(type_, list):
|
||||||
|
return []
|
||||||
|
if issubclass(type_, dict):
|
||||||
|
return {}
|
||||||
|
if issubclass(type_, tuple):
|
||||||
|
return ()
|
||||||
|
if types.is_dataframe(type_):
|
||||||
|
try:
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
return pd.DataFrame()
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(
|
||||||
|
"Please install pandas to use dataframes in your app."
|
||||||
|
) from e
|
||||||
|
return set() if issubclass(type_, set) else None
|
||||||
|
|
||||||
|
def get_setter_name(self, include_state: bool = True) -> str:
|
||||||
|
"""Get the name of the var's generated setter function.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
include_state: Whether to include the state name in the setter name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The name of the setter function.
|
||||||
|
"""
|
||||||
|
setter = constants.SETTER_PREFIX + self._var_name
|
||||||
|
if self._var_data is None:
|
||||||
|
return setter
|
||||||
|
if not include_state or self._var_data.state == "":
|
||||||
|
return setter
|
||||||
|
print("get_setter_name", self._var_data.state, setter)
|
||||||
|
return ".".join((self._var_data.state, setter))
|
||||||
|
|
||||||
|
def get_setter(self) -> Callable[[BaseState, Any], None]:
|
||||||
|
"""Get the var's setter function.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A function that that creates a setter for the var.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setter(state: BaseState, value: Any):
|
||||||
|
"""Get the setter for the var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state: The state within which we add the setter function.
|
||||||
|
value: The value to set.
|
||||||
|
"""
|
||||||
|
if self._var_type in [int, float]:
|
||||||
|
try:
|
||||||
|
value = self._var_type(value)
|
||||||
|
setattr(state, self._var_name, value)
|
||||||
|
except ValueError:
|
||||||
|
console.debug(
|
||||||
|
f"{type(state).__name__}.{self._var_name}: Failed conversion of {value} to '{self._var_type.__name__}'. Value not set.",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
setattr(state, self._var_name, value)
|
||||||
|
|
||||||
|
setter.__qualname__ = self.get_setter_name()
|
||||||
|
|
||||||
|
return setter
|
||||||
|
|
||||||
|
def __eq__(self, other: Var | Any) -> BooleanVar:
|
||||||
|
"""
|
||||||
|
Check if the current variable is equal to the given variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other (Var | Any): The variable to compare with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BooleanVar: A BooleanVar object representing the result of the equality check.
|
||||||
|
"""
|
||||||
|
from .number import EqualOperation
|
||||||
|
|
||||||
|
return EqualOperation(self, other)
|
||||||
|
|
||||||
|
def __ne__(self, other: Var | Any) -> BooleanVar:
|
||||||
|
"""
|
||||||
|
Check if the current object is not equal to the given object.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
other (Var | Any): The object to compare with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BooleanVar: A BooleanVar object representing the result of the comparison.
|
||||||
|
"""
|
||||||
|
from .number import EqualOperation
|
||||||
|
|
||||||
|
return ~EqualOperation(self, other)
|
||||||
|
|
||||||
|
def __gt__(self, other: Var | Any) -> BooleanVar:
|
||||||
|
"""
|
||||||
|
Compare the current instance with another variable and return a BooleanVar representing the result of the greater than operation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other (Var | Any): The variable to compare with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BooleanVar: A BooleanVar representing the result of the greater than operation.
|
||||||
|
"""
|
||||||
|
from .number import GreaterThanOperation
|
||||||
|
|
||||||
|
return GreaterThanOperation(self, other)
|
||||||
|
|
||||||
|
def __ge__(self, other: Var | Any) -> BooleanVar:
|
||||||
|
"""
|
||||||
|
Check if the value of this variable is greater than or equal to the value of another variable or object.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other (Var | Any): The variable or object to compare with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BooleanVar: A BooleanVar object representing the result of the comparison.
|
||||||
|
"""
|
||||||
|
from .number import GreaterThanOrEqualOperation
|
||||||
|
|
||||||
|
return GreaterThanOrEqualOperation(self, other)
|
||||||
|
|
||||||
|
def __lt__(self, other: Var | Any) -> BooleanVar:
|
||||||
|
"""
|
||||||
|
Compare the current instance with another variable using the less than (<) operator.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other: The variable to compare with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A `BooleanVar` object representing the result of the comparison.
|
||||||
|
"""
|
||||||
|
from .number import LessThanOperation
|
||||||
|
|
||||||
|
return LessThanOperation(self, other)
|
||||||
|
|
||||||
|
def __le__(self, other: Var | Any) -> BooleanVar:
|
||||||
|
"""
|
||||||
|
Compare if the current instance is less than or equal to the given value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other: The value to compare with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A BooleanVar object representing the result of the comparison.
|
||||||
|
"""
|
||||||
|
from .number import LessThanOrEqualOperation
|
||||||
|
|
||||||
|
return LessThanOrEqualOperation(self, other)
|
||||||
|
|
||||||
|
def bool(self) -> BooleanVar:
|
||||||
|
"""Convert the var to a boolean.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The boolean var.
|
||||||
|
"""
|
||||||
|
from .number import ToBooleanVarOperation
|
||||||
|
|
||||||
|
return ToBooleanVarOperation(self)
|
||||||
|
|
||||||
|
def __and__(self, other: Var | Any) -> ImmutableVar:
|
||||||
|
"""Perform a logical AND operation on the current instance and another variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other: The variable to perform the logical AND operation with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A `BooleanVar` object representing the result of the logical AND operation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return AndOperation(self, other)
|
||||||
|
|
||||||
|
def __rand__(self, other: Var | Any) -> ImmutableVar:
|
||||||
|
"""Perform a logical AND operation on the current instance and another variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other: The variable to perform the logical AND operation with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A `BooleanVar` object representing the result of the logical AND operation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return AndOperation(other, self)
|
||||||
|
|
||||||
|
def __or__(self, other: Var | Any) -> ImmutableVar:
|
||||||
|
"""Perform a logical OR operation on the current instance and another variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other: The variable to perform the logical OR operation with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A `BooleanVar` object representing the result of the logical OR operation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return OrOperation(self, other)
|
||||||
|
|
||||||
|
def __ror__(self, other: Var | Any) -> ImmutableVar:
|
||||||
|
"""Perform a logical OR operation on the current instance and another variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other: The variable to perform the logical OR operation with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A `BooleanVar` object representing the result of the logical OR operation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return OrOperation(other, self)
|
||||||
|
|
||||||
|
def __invert__(self) -> BooleanVar:
|
||||||
|
"""Perform a logical NOT operation on the current instance.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A `BooleanVar` object representing the result of the logical NOT operation.
|
||||||
|
"""
|
||||||
|
from .number import BooleanNotOperation
|
||||||
|
|
||||||
|
return BooleanNotOperation(self.bool())
|
||||||
|
|
||||||
|
def to_string(self) -> ImmutableVar:
|
||||||
|
"""Convert the var to a string.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The string var.
|
||||||
|
"""
|
||||||
|
from .function import JSON_STRINGIFY
|
||||||
|
|
||||||
|
return JSON_STRINGIFY.call(self)
|
||||||
|
|
||||||
|
def as_ref(self) -> ImmutableVar:
|
||||||
|
"""Get a reference to the var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The reference to the var.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .object import ObjectVar
|
||||||
|
|
||||||
|
refs = ImmutableVar(
|
||||||
|
_var_name="refs",
|
||||||
|
_var_data=ImmutableVarData(
|
||||||
|
imports={
|
||||||
|
f"/{constants.Dirs.STATE_PATH}": [imports.ImportVar(tag="refs")]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
).to(ObjectVar)
|
||||||
|
return refs[self]
|
||||||
|
|
||||||
|
|
||||||
OUTPUT = TypeVar("OUTPUT", bound=ImmutableVar)
|
OUTPUT = TypeVar("OUTPUT", bound=ImmutableVar)
|
||||||
|
|
||||||
@ -457,6 +740,9 @@ class LiteralVar(ImmutableVar):
|
|||||||
value.dict(), _var_type=type(value), _var_data=_var_data
|
value.dict(), _var_type=type(value), _var_data=_var_data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return LiteralObjectVar(value, _var_data=_var_data)
|
||||||
|
|
||||||
from .number import LiteralBooleanVar, LiteralNumberVar
|
from .number import LiteralBooleanVar, LiteralNumberVar
|
||||||
from .sequence import LiteralArrayVar, LiteralStringVar
|
from .sequence import LiteralArrayVar, LiteralStringVar
|
||||||
|
|
||||||
@ -467,7 +753,6 @@ class LiteralVar(ImmutableVar):
|
|||||||
int: LiteralNumberVar,
|
int: LiteralNumberVar,
|
||||||
float: LiteralNumberVar,
|
float: LiteralNumberVar,
|
||||||
bool: LiteralBooleanVar,
|
bool: LiteralBooleanVar,
|
||||||
dict: LiteralObjectVar,
|
|
||||||
list: LiteralArrayVar,
|
list: LiteralArrayVar,
|
||||||
tuple: LiteralArrayVar,
|
tuple: LiteralArrayVar,
|
||||||
set: LiteralArrayVar,
|
set: LiteralArrayVar,
|
||||||
@ -581,3 +866,165 @@ def figure_out_type(value: Any) -> Type:
|
|||||||
unionize(*(figure_out_type(v) for v in value.values())),
|
unionize(*(figure_out_type(v) for v in value.values())),
|
||||||
]
|
]
|
||||||
return type(value)
|
return type(value)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
eq=False,
|
||||||
|
frozen=True,
|
||||||
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
||||||
|
)
|
||||||
|
class AndOperation(ImmutableVar):
|
||||||
|
"""Class for the logical AND operation."""
|
||||||
|
|
||||||
|
# The first var.
|
||||||
|
_var1: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
|
||||||
|
|
||||||
|
# The second var.
|
||||||
|
_var2: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, var1: Var | Any, var2: Var | Any, _var_data: VarData | None = None
|
||||||
|
):
|
||||||
|
"""Initialize the AndOperation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
var1: The first var.
|
||||||
|
var2: The second var.
|
||||||
|
_var_data: Additional hooks and imports associated with the Var.
|
||||||
|
"""
|
||||||
|
super(type(self), self).__init__(
|
||||||
|
_var_name="",
|
||||||
|
_var_type=Union[var1._var_type, var2._var_type],
|
||||||
|
_var_data=ImmutableVarData.merge(_var_data),
|
||||||
|
)
|
||||||
|
object.__setattr__(
|
||||||
|
self, "_var1", var1 if isinstance(var1, Var) else LiteralVar.create(var1)
|
||||||
|
)
|
||||||
|
object.__setattr__(
|
||||||
|
self, "_var2", var2 if isinstance(var2, Var) else LiteralVar.create(var2)
|
||||||
|
)
|
||||||
|
object.__delattr__(self, "_var_name")
|
||||||
|
|
||||||
|
@functools.cached_property
|
||||||
|
def _cached_var_name(self) -> str:
|
||||||
|
"""Get the cached var name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The cached var name.
|
||||||
|
"""
|
||||||
|
return f"({str(self._var1)} && {str(self._var2)})"
|
||||||
|
|
||||||
|
def __getattr__(self, name: str) -> Any:
|
||||||
|
"""Get an attribute of the var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the attribute.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The attribute.
|
||||||
|
"""
|
||||||
|
if name == "_var_name":
|
||||||
|
return self._cached_var_name
|
||||||
|
return getattr(super(type(self), self), name)
|
||||||
|
|
||||||
|
@functools.cached_property
|
||||||
|
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Get the cached VarData.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The cached VarData.
|
||||||
|
"""
|
||||||
|
return ImmutableVarData.merge(
|
||||||
|
self._var1._get_all_var_data(),
|
||||||
|
self._var2._get_all_var_data(),
|
||||||
|
self._var_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Get all VarData associated with the Var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The VarData of the components and all of its children.
|
||||||
|
"""
|
||||||
|
return self._cached_get_all_var_data
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
eq=False,
|
||||||
|
frozen=True,
|
||||||
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
||||||
|
)
|
||||||
|
class OrOperation(ImmutableVar):
|
||||||
|
"""Class for the logical OR operation."""
|
||||||
|
|
||||||
|
# The first var.
|
||||||
|
_var1: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
|
||||||
|
|
||||||
|
# The second var.
|
||||||
|
_var2: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, var1: Var | Any, var2: Var | Any, _var_data: VarData | None = None
|
||||||
|
):
|
||||||
|
"""Initialize the OrOperation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
var1: The first var.
|
||||||
|
var2: The second var.
|
||||||
|
_var_data: Additional hooks and imports associated with the Var.
|
||||||
|
"""
|
||||||
|
super(type(self), self).__init__(
|
||||||
|
_var_name="",
|
||||||
|
_var_type=Union[var1._var_type, var2._var_type],
|
||||||
|
_var_data=ImmutableVarData.merge(_var_data),
|
||||||
|
)
|
||||||
|
object.__setattr__(
|
||||||
|
self, "_var1", var1 if isinstance(var1, Var) else LiteralVar.create(var1)
|
||||||
|
)
|
||||||
|
object.__setattr__(
|
||||||
|
self, "_var2", var2 if isinstance(var2, Var) else LiteralVar.create(var2)
|
||||||
|
)
|
||||||
|
object.__delattr__(self, "_var_name")
|
||||||
|
|
||||||
|
@functools.cached_property
|
||||||
|
def _cached_var_name(self) -> str:
|
||||||
|
"""Get the cached var name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The cached var name.
|
||||||
|
"""
|
||||||
|
return f"({str(self._var1)} || {str(self._var2)})"
|
||||||
|
|
||||||
|
def __getattr__(self, name: str) -> Any:
|
||||||
|
"""Get an attribute of the var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the attribute.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The attribute.
|
||||||
|
"""
|
||||||
|
if name == "_var_name":
|
||||||
|
return self._cached_var_name
|
||||||
|
return getattr(super(type(self), self), name)
|
||||||
|
|
||||||
|
@functools.cached_property
|
||||||
|
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Get the cached VarData.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The cached VarData.
|
||||||
|
"""
|
||||||
|
return ImmutableVarData.merge(
|
||||||
|
self._var1._get_all_var_data(),
|
||||||
|
self._var2._get_all_var_data(),
|
||||||
|
self._var_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Get all VarData associated with the Var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The VarData of the components and all of its children.
|
||||||
|
"""
|
||||||
|
return self._cached_get_all_var_data
|
@ -7,7 +7,7 @@ import sys
|
|||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Any, Callable, Optional, Tuple, Type, Union
|
from typing import Any, Callable, Optional, Tuple, Type, Union
|
||||||
|
|
||||||
from reflex.experimental.vars.base import ImmutableVar, LiteralVar
|
from .base import ImmutableVar, LiteralVar
|
||||||
from reflex.vars import ImmutableVarData, Var, VarData
|
from reflex.vars import ImmutableVarData, Var, VarData
|
||||||
|
|
||||||
|
|
||||||
@ -288,3 +288,6 @@ class ToFunctionOperation(FunctionVar):
|
|||||||
The VarData of the components and all of its children.
|
The VarData of the components and all of its children.
|
||||||
"""
|
"""
|
||||||
return self._cached_get_all_var_data
|
return self._cached_get_all_var_data
|
||||||
|
|
||||||
|
|
||||||
|
JSON_STRINGIFY = FunctionStringVar("JSON.stringify")
|
@ -8,7 +8,9 @@ import sys
|
|||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
|
|
||||||
from reflex.experimental.vars.base import (
|
from reflex.utils.types import GenericType
|
||||||
|
|
||||||
|
from .base import (
|
||||||
ImmutableVar,
|
ImmutableVar,
|
||||||
LiteralVar,
|
LiteralVar,
|
||||||
)
|
)
|
||||||
@ -188,54 +190,6 @@ class NumberVar(ImmutableVar[Union[int, float]]):
|
|||||||
"""
|
"""
|
||||||
return NumberNegateOperation(self)
|
return NumberNegateOperation(self)
|
||||||
|
|
||||||
def __and__(self, other: number_types | boolean_types) -> BooleanAndOperation:
|
|
||||||
"""Boolean AND two numbers.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other number.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean AND operation.
|
|
||||||
"""
|
|
||||||
boolified_other = other.bool() if isinstance(other, Var) else bool(other)
|
|
||||||
return BooleanAndOperation(self.bool(), boolified_other)
|
|
||||||
|
|
||||||
def __rand__(self, other: number_types | boolean_types) -> BooleanAndOperation:
|
|
||||||
"""Boolean AND two numbers.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other number.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean AND operation.
|
|
||||||
"""
|
|
||||||
boolified_other = other.bool() if isinstance(other, Var) else bool(other)
|
|
||||||
return BooleanAndOperation(boolified_other, self.bool())
|
|
||||||
|
|
||||||
def __or__(self, other: number_types | boolean_types) -> BooleanOrOperation:
|
|
||||||
"""Boolean OR two numbers.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other number.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean OR operation.
|
|
||||||
"""
|
|
||||||
boolified_other = other.bool() if isinstance(other, Var) else bool(other)
|
|
||||||
return BooleanOrOperation(self.bool(), boolified_other)
|
|
||||||
|
|
||||||
def __ror__(self, other: number_types | boolean_types) -> BooleanOrOperation:
|
|
||||||
"""Boolean OR two numbers.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other number.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean OR operation.
|
|
||||||
"""
|
|
||||||
boolified_other = other.bool() if isinstance(other, Var) else bool(other)
|
|
||||||
return BooleanOrOperation(boolified_other, self.bool())
|
|
||||||
|
|
||||||
def __invert__(self) -> BooleanNotOperation:
|
def __invert__(self) -> BooleanNotOperation:
|
||||||
"""Boolean NOT the number.
|
"""Boolean NOT the number.
|
||||||
|
|
||||||
@ -284,7 +238,7 @@ class NumberVar(ImmutableVar[Union[int, float]]):
|
|||||||
"""
|
"""
|
||||||
return NumberTruncOperation(self)
|
return NumberTruncOperation(self)
|
||||||
|
|
||||||
def __lt__(self, other: number_types | boolean_types) -> LessThanOperation:
|
def __lt__(self, other: Any) -> LessThanOperation:
|
||||||
"""Less than comparison.
|
"""Less than comparison.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -293,9 +247,11 @@ class NumberVar(ImmutableVar[Union[int, float]]):
|
|||||||
Returns:
|
Returns:
|
||||||
The result of the comparison.
|
The result of the comparison.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(other, (NumberVar, BooleanVar, int, float, bool)):
|
||||||
return LessThanOperation(self, +other)
|
return LessThanOperation(self, +other)
|
||||||
|
return LessThanOperation(self, other)
|
||||||
|
|
||||||
def __le__(self, other: number_types | boolean_types) -> LessThanOrEqualOperation:
|
def __le__(self, other: Any) -> LessThanOrEqualOperation:
|
||||||
"""Less than or equal comparison.
|
"""Less than or equal comparison.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -304,9 +260,11 @@ class NumberVar(ImmutableVar[Union[int, float]]):
|
|||||||
Returns:
|
Returns:
|
||||||
The result of the comparison.
|
The result of the comparison.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(other, (NumberVar, BooleanVar, int, float, bool)):
|
||||||
return LessThanOrEqualOperation(self, +other)
|
return LessThanOrEqualOperation(self, +other)
|
||||||
|
return LessThanOrEqualOperation(self, other)
|
||||||
|
|
||||||
def __eq__(self, other: number_types | boolean_types) -> EqualOperation:
|
def __eq__(self, other: Any) -> EqualOperation:
|
||||||
"""Equal comparison.
|
"""Equal comparison.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -315,9 +273,11 @@ class NumberVar(ImmutableVar[Union[int, float]]):
|
|||||||
Returns:
|
Returns:
|
||||||
The result of the comparison.
|
The result of the comparison.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(other, (NumberVar, BooleanVar, int, float, bool)):
|
||||||
return EqualOperation(self, +other)
|
return EqualOperation(self, +other)
|
||||||
|
return EqualOperation(self, other)
|
||||||
|
|
||||||
def __ne__(self, other: number_types | boolean_types) -> NotEqualOperation:
|
def __ne__(self, other: Any) -> NotEqualOperation:
|
||||||
"""Not equal comparison.
|
"""Not equal comparison.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -326,9 +286,11 @@ class NumberVar(ImmutableVar[Union[int, float]]):
|
|||||||
Returns:
|
Returns:
|
||||||
The result of the comparison.
|
The result of the comparison.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(other, (NumberVar, BooleanVar, int, float, bool)):
|
||||||
return NotEqualOperation(self, +other)
|
return NotEqualOperation(self, +other)
|
||||||
|
return NotEqualOperation(self, other)
|
||||||
|
|
||||||
def __gt__(self, other: number_types | boolean_types) -> GreaterThanOperation:
|
def __gt__(self, other: Any) -> GreaterThanOperation:
|
||||||
"""Greater than comparison.
|
"""Greater than comparison.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -337,11 +299,11 @@ class NumberVar(ImmutableVar[Union[int, float]]):
|
|||||||
Returns:
|
Returns:
|
||||||
The result of the comparison.
|
The result of the comparison.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(other, (NumberVar, BooleanVar, int, float, bool)):
|
||||||
return GreaterThanOperation(self, +other)
|
return GreaterThanOperation(self, +other)
|
||||||
|
return GreaterThanOperation(self, other)
|
||||||
|
|
||||||
def __ge__(
|
def __ge__(self, other: Any) -> GreaterThanOrEqualOperation:
|
||||||
self, other: number_types | boolean_types
|
|
||||||
) -> GreaterThanOrEqualOperation:
|
|
||||||
"""Greater than or equal comparison.
|
"""Greater than or equal comparison.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -350,7 +312,9 @@ class NumberVar(ImmutableVar[Union[int, float]]):
|
|||||||
Returns:
|
Returns:
|
||||||
The result of the comparison.
|
The result of the comparison.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(other, (NumberVar, BooleanVar, int, float, bool)):
|
||||||
return GreaterThanOrEqualOperation(self, +other)
|
return GreaterThanOrEqualOperation(self, +other)
|
||||||
|
return GreaterThanOrEqualOperation(self, other)
|
||||||
|
|
||||||
def bool(self) -> NotEqualOperation:
|
def bool(self) -> NotEqualOperation:
|
||||||
"""Boolean conversion.
|
"""Boolean conversion.
|
||||||
@ -696,50 +660,6 @@ class NumberTruncOperation(UnaryNumberOperation):
|
|||||||
class BooleanVar(ImmutableVar[bool]):
|
class BooleanVar(ImmutableVar[bool]):
|
||||||
"""Base class for immutable boolean vars."""
|
"""Base class for immutable boolean vars."""
|
||||||
|
|
||||||
def __and__(self, other: bool) -> BooleanAndOperation:
|
|
||||||
"""AND two booleans.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other boolean.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean AND operation.
|
|
||||||
"""
|
|
||||||
return BooleanAndOperation(self, other)
|
|
||||||
|
|
||||||
def __rand__(self, other: bool) -> BooleanAndOperation:
|
|
||||||
"""AND two booleans.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other boolean.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean AND operation.
|
|
||||||
"""
|
|
||||||
return BooleanAndOperation(other, self)
|
|
||||||
|
|
||||||
def __or__(self, other: bool) -> BooleanOrOperation:
|
|
||||||
"""OR two booleans.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other boolean.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean OR operation.
|
|
||||||
"""
|
|
||||||
return BooleanOrOperation(self, other)
|
|
||||||
|
|
||||||
def __ror__(self, other: bool) -> BooleanOrOperation:
|
|
||||||
"""OR two booleans.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other boolean.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean OR operation.
|
|
||||||
"""
|
|
||||||
return BooleanOrOperation(other, self)
|
|
||||||
|
|
||||||
def __invert__(self) -> BooleanNotOperation:
|
def __invert__(self) -> BooleanNotOperation:
|
||||||
"""NOT the boolean.
|
"""NOT the boolean.
|
||||||
|
|
||||||
@ -913,16 +833,16 @@ class BooleanToIntOperation(NumberVar):
|
|||||||
frozen=True,
|
frozen=True,
|
||||||
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
||||||
)
|
)
|
||||||
class NumberComparisonOperation(BooleanVar):
|
class ComparisonOperation(BooleanVar):
|
||||||
"""Base class for immutable boolean vars that are the result of a comparison operation."""
|
"""Base class for immutable boolean vars that are the result of a comparison operation."""
|
||||||
|
|
||||||
a: number_types = dataclasses.field(default=0)
|
a: Var = dataclasses.field(default_factory=lambda: LiteralBooleanVar(True))
|
||||||
b: number_types = dataclasses.field(default=0)
|
b: Var = dataclasses.field(default_factory=lambda: LiteralBooleanVar(True))
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
a: number_types,
|
a: Var | Any,
|
||||||
b: number_types,
|
b: Var | Any,
|
||||||
_var_data: VarData | None = None,
|
_var_data: VarData | None = None,
|
||||||
):
|
):
|
||||||
"""Initialize the comparison operation var.
|
"""Initialize the comparison operation var.
|
||||||
@ -932,13 +852,13 @@ class NumberComparisonOperation(BooleanVar):
|
|||||||
b: The second value.
|
b: The second value.
|
||||||
_var_data: Additional hooks and imports associated with the Var.
|
_var_data: Additional hooks and imports associated with the Var.
|
||||||
"""
|
"""
|
||||||
super(NumberComparisonOperation, self).__init__(
|
super(ComparisonOperation, self).__init__(
|
||||||
_var_name="",
|
_var_name="",
|
||||||
_var_type=bool,
|
_var_type=bool,
|
||||||
_var_data=ImmutableVarData.merge(_var_data),
|
_var_data=ImmutableVarData.merge(_var_data),
|
||||||
)
|
)
|
||||||
object.__setattr__(self, "a", a)
|
object.__setattr__(self, "a", a if isinstance(a, Var) else LiteralVar.create(a))
|
||||||
object.__setattr__(self, "b", b)
|
object.__setattr__(self, "b", b if isinstance(b, Var) else LiteralVar.create(b))
|
||||||
object.__delattr__(self, "_var_name")
|
object.__delattr__(self, "_var_name")
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -961,7 +881,7 @@ class NumberComparisonOperation(BooleanVar):
|
|||||||
"""
|
"""
|
||||||
if name == "_var_name":
|
if name == "_var_name":
|
||||||
return self._cached_var_name
|
return self._cached_var_name
|
||||||
getattr(super(NumberComparisonOperation, self), name)
|
getattr(super(ComparisonOperation, self), name)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
@ -980,7 +900,7 @@ class NumberComparisonOperation(BooleanVar):
|
|||||||
return self._cached_get_all_var_data
|
return self._cached_get_all_var_data
|
||||||
|
|
||||||
|
|
||||||
class GreaterThanOperation(NumberComparisonOperation):
|
class GreaterThanOperation(ComparisonOperation):
|
||||||
"""Base class for immutable boolean vars that are the result of a greater than operation."""
|
"""Base class for immutable boolean vars that are the result of a greater than operation."""
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -995,7 +915,7 @@ class GreaterThanOperation(NumberComparisonOperation):
|
|||||||
return f"({str(first_value)} > {str(second_value)})"
|
return f"({str(first_value)} > {str(second_value)})"
|
||||||
|
|
||||||
|
|
||||||
class GreaterThanOrEqualOperation(NumberComparisonOperation):
|
class GreaterThanOrEqualOperation(ComparisonOperation):
|
||||||
"""Base class for immutable boolean vars that are the result of a greater than or equal operation."""
|
"""Base class for immutable boolean vars that are the result of a greater than or equal operation."""
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -1010,7 +930,7 @@ class GreaterThanOrEqualOperation(NumberComparisonOperation):
|
|||||||
return f"({str(first_value)} >= {str(second_value)})"
|
return f"({str(first_value)} >= {str(second_value)})"
|
||||||
|
|
||||||
|
|
||||||
class LessThanOperation(NumberComparisonOperation):
|
class LessThanOperation(ComparisonOperation):
|
||||||
"""Base class for immutable boolean vars that are the result of a less than operation."""
|
"""Base class for immutable boolean vars that are the result of a less than operation."""
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -1025,7 +945,7 @@ class LessThanOperation(NumberComparisonOperation):
|
|||||||
return f"({str(first_value)} < {str(second_value)})"
|
return f"({str(first_value)} < {str(second_value)})"
|
||||||
|
|
||||||
|
|
||||||
class LessThanOrEqualOperation(NumberComparisonOperation):
|
class LessThanOrEqualOperation(ComparisonOperation):
|
||||||
"""Base class for immutable boolean vars that are the result of a less than or equal operation."""
|
"""Base class for immutable boolean vars that are the result of a less than or equal operation."""
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -1040,7 +960,7 @@ class LessThanOrEqualOperation(NumberComparisonOperation):
|
|||||||
return f"({str(first_value)} <= {str(second_value)})"
|
return f"({str(first_value)} <= {str(second_value)})"
|
||||||
|
|
||||||
|
|
||||||
class EqualOperation(NumberComparisonOperation):
|
class EqualOperation(ComparisonOperation):
|
||||||
"""Base class for immutable boolean vars that are the result of an equal operation."""
|
"""Base class for immutable boolean vars that are the result of an equal operation."""
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -1052,10 +972,10 @@ class EqualOperation(NumberComparisonOperation):
|
|||||||
"""
|
"""
|
||||||
first_value = self.a if isinstance(self.a, Var) else LiteralVar.create(self.a)
|
first_value = self.a if isinstance(self.a, Var) else LiteralVar.create(self.a)
|
||||||
second_value = self.b if isinstance(self.b, Var) else LiteralVar.create(self.b)
|
second_value = self.b if isinstance(self.b, Var) else LiteralVar.create(self.b)
|
||||||
return f"({str(first_value)} == {str(second_value)})"
|
return f"({str(first_value)} === {str(second_value)})"
|
||||||
|
|
||||||
|
|
||||||
class NotEqualOperation(NumberComparisonOperation):
|
class NotEqualOperation(ComparisonOperation):
|
||||||
"""Base class for immutable boolean vars that are the result of a not equal operation."""
|
"""Base class for immutable boolean vars that are the result of a not equal operation."""
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -1139,36 +1059,6 @@ class LogicalOperation(BooleanVar):
|
|||||||
return self._cached_get_all_var_data
|
return self._cached_get_all_var_data
|
||||||
|
|
||||||
|
|
||||||
class BooleanAndOperation(LogicalOperation):
|
|
||||||
"""Base class for immutable boolean vars that are the result of a logical AND operation."""
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def _cached_var_name(self) -> str:
|
|
||||||
"""The name of the var.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The name of the var.
|
|
||||||
"""
|
|
||||||
first_value = self.a if isinstance(self.a, Var) else LiteralVar.create(self.a)
|
|
||||||
second_value = self.b if isinstance(self.b, Var) else LiteralVar.create(self.b)
|
|
||||||
return f"({str(first_value)} && {str(second_value)})"
|
|
||||||
|
|
||||||
|
|
||||||
class BooleanOrOperation(LogicalOperation):
|
|
||||||
"""Base class for immutable boolean vars that are the result of a logical OR operation."""
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def _cached_var_name(self) -> str:
|
|
||||||
"""The name of the var.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The name of the var.
|
|
||||||
"""
|
|
||||||
first_value = self.a if isinstance(self.a, Var) else LiteralVar.create(self.a)
|
|
||||||
second_value = self.b if isinstance(self.b, Var) else LiteralVar.create(self.b)
|
|
||||||
return f"({str(first_value)} || {str(second_value)})"
|
|
||||||
|
|
||||||
|
|
||||||
class BooleanNotOperation(BooleanVar):
|
class BooleanNotOperation(BooleanVar):
|
||||||
"""Base class for immutable boolean vars that are the result of a logical NOT operation."""
|
"""Base class for immutable boolean vars that are the result of a logical NOT operation."""
|
||||||
|
|
||||||
@ -1428,7 +1318,7 @@ class ToBooleanVarOperation(BooleanVar):
|
|||||||
Returns:
|
Returns:
|
||||||
The name of the var.
|
The name of the var.
|
||||||
"""
|
"""
|
||||||
return str(self._original_value)
|
return f"Boolean({str(self._original_value)})"
|
||||||
|
|
||||||
def __getattr__(self, name: str) -> Any:
|
def __getattr__(self, name: str) -> Any:
|
||||||
"""Get an attribute of the var.
|
"""Get an attribute of the var.
|
||||||
@ -1456,3 +1346,84 @@ class ToBooleanVarOperation(BooleanVar):
|
|||||||
|
|
||||||
def _get_all_var_data(self) -> ImmutableVarData | None:
|
def _get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
return self._cached_get_all_var_data
|
return self._cached_get_all_var_data
|
||||||
|
|
||||||
|
|
||||||
|
class TernaryOperator(ImmutableVar):
|
||||||
|
"""Base class for immutable vars that are the result of a ternary operation."""
|
||||||
|
|
||||||
|
condition: Var = dataclasses.field(default_factory=lambda: LiteralBooleanVar(False))
|
||||||
|
if_true: Var = dataclasses.field(default_factory=lambda: LiteralNumberVar(0))
|
||||||
|
if_false: Var = dataclasses.field(default_factory=lambda: LiteralNumberVar(0))
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
condition: Var | Any,
|
||||||
|
if_true: Var | Any,
|
||||||
|
if_false: Var | Any,
|
||||||
|
_var_type: GenericType | None = None,
|
||||||
|
_var_data: VarData | None = None,
|
||||||
|
):
|
||||||
|
"""Initialize the ternary operation var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
condition: The condition.
|
||||||
|
if_true: The value if the condition is true.
|
||||||
|
if_false: The value if the condition is false.
|
||||||
|
_var_data: Additional hooks and imports associated with the Var.
|
||||||
|
"""
|
||||||
|
condition = (
|
||||||
|
condition if isinstance(condition, Var) else LiteralVar.create(condition)
|
||||||
|
)
|
||||||
|
if_true = if_true if isinstance(if_true, Var) else LiteralVar.create(if_true)
|
||||||
|
if_false = (
|
||||||
|
if_false if isinstance(if_false, Var) else LiteralVar.create(if_false)
|
||||||
|
)
|
||||||
|
|
||||||
|
super(TernaryOperator, self).__init__(
|
||||||
|
_var_name="",
|
||||||
|
_var_type=_var_type or Union[if_true._var_type, if_false._var_type],
|
||||||
|
_var_data=ImmutableVarData.merge(_var_data),
|
||||||
|
)
|
||||||
|
object.__setattr__(self, "condition", condition)
|
||||||
|
object.__setattr__(self, "if_true", if_true)
|
||||||
|
object.__setattr__(self, "if_false", if_false)
|
||||||
|
object.__delattr__(self, "_var_name")
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _cached_var_name(self) -> str:
|
||||||
|
"""The name of the var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The name of the var.
|
||||||
|
"""
|
||||||
|
return f"({str(self.condition)} ? {str(self.if_true)} : {str(self.if_false)})"
|
||||||
|
|
||||||
|
def __getattr__(self, name: str) -> Any:
|
||||||
|
"""Get an attribute of the var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the attribute.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The attribute value.
|
||||||
|
"""
|
||||||
|
if name == "_var_name":
|
||||||
|
return self._cached_var_name
|
||||||
|
getattr(super(TernaryOperator, self), name)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Get all VarData associated with the Var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The VarData of the components and all of its children.
|
||||||
|
"""
|
||||||
|
return ImmutableVarData.merge(
|
||||||
|
self.condition._get_all_var_data(),
|
||||||
|
self.if_true._get_all_var_data(),
|
||||||
|
self.if_false._get_all_var_data(),
|
||||||
|
self._var_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
return self._cached_get_all_var_data
|
@ -22,13 +22,15 @@ from typing import (
|
|||||||
|
|
||||||
from typing_extensions import get_origin
|
from typing_extensions import get_origin
|
||||||
|
|
||||||
from reflex.experimental.vars.base import (
|
from reflex.utils import console
|
||||||
|
|
||||||
|
from .base import (
|
||||||
ImmutableVar,
|
ImmutableVar,
|
||||||
LiteralVar,
|
LiteralVar,
|
||||||
figure_out_type,
|
figure_out_type,
|
||||||
)
|
)
|
||||||
from reflex.experimental.vars.number import NumberVar
|
from .number import BooleanVar, NumberVar
|
||||||
from reflex.experimental.vars.sequence import ArrayVar, StringVar
|
from .sequence import ArrayVar, StringVar
|
||||||
from reflex.utils.exceptions import VarAttributeError
|
from reflex.utils.exceptions import VarAttributeError
|
||||||
from reflex.utils.types import GenericType, get_attribute_access_type
|
from reflex.utils.types import GenericType, get_attribute_access_type
|
||||||
from reflex.vars import ImmutableVarData, Var, VarData
|
from reflex.vars import ImmutableVarData, Var, VarData
|
||||||
@ -46,23 +48,13 @@ OTHER_KEY_TYPE = TypeVar("OTHER_KEY_TYPE")
|
|||||||
class ObjectVar(ImmutableVar[OBJECT_TYPE]):
|
class ObjectVar(ImmutableVar[OBJECT_TYPE]):
|
||||||
"""Base class for immutable object vars."""
|
"""Base class for immutable object vars."""
|
||||||
|
|
||||||
@overload
|
|
||||||
def _key_type(self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]]) -> KEY_TYPE: ...
|
|
||||||
|
|
||||||
@overload
|
|
||||||
def _key_type(self) -> Type: ...
|
|
||||||
|
|
||||||
def _key_type(self) -> Type:
|
def _key_type(self) -> Type:
|
||||||
"""Get the type of the keys of the object.
|
"""Get the type of the keys of the object.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The type of the keys of the object.
|
The type of the keys of the object.
|
||||||
"""
|
"""
|
||||||
fixed_type = (
|
return str
|
||||||
self._var_type if isclass(self._var_type) else get_origin(self._var_type)
|
|
||||||
)
|
|
||||||
args = get_args(self._var_type) if issubclass(fixed_type, dict) else ()
|
|
||||||
return args[0] if args else Any
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def _value_type(self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]]) -> VALUE_TYPE: ...
|
def _value_type(self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]]) -> VALUE_TYPE: ...
|
||||||
@ -82,15 +74,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
|
|||||||
args = get_args(self._var_type) if issubclass(fixed_type, dict) else ()
|
args = get_args(self._var_type) if issubclass(fixed_type, dict) else ()
|
||||||
return args[1] if args else Any
|
return args[1] if args else Any
|
||||||
|
|
||||||
@overload
|
def keys(self) -> ArrayVar[List[str]]:
|
||||||
def keys(
|
|
||||||
self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]],
|
|
||||||
) -> ArrayVar[List[KEY_TYPE]]: ...
|
|
||||||
|
|
||||||
@overload
|
|
||||||
def keys(self) -> ArrayVar: ...
|
|
||||||
|
|
||||||
def keys(self) -> ArrayVar:
|
|
||||||
"""Get the keys of the object.
|
"""Get the keys of the object.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -117,7 +101,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
|
|||||||
@overload
|
@overload
|
||||||
def entries(
|
def entries(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]],
|
self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]],
|
||||||
) -> ArrayVar[List[Tuple[KEY_TYPE, VALUE_TYPE]]]: ...
|
) -> ArrayVar[List[Tuple[str, VALUE_TYPE]]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def entries(self) -> ArrayVar: ...
|
def entries(self) -> ArrayVar: ...
|
||||||
@ -258,6 +242,8 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
|
|||||||
Returns:
|
Returns:
|
||||||
The attribute of the var.
|
The attribute of the var.
|
||||||
"""
|
"""
|
||||||
|
if name.startswith("__") and name.endswith("__"):
|
||||||
|
return getattr(super(type(self), self), name)
|
||||||
fixed_type = (
|
fixed_type = (
|
||||||
self._var_type if isclass(self._var_type) else get_origin(self._var_type)
|
self._var_type if isclass(self._var_type) else get_origin(self._var_type)
|
||||||
)
|
)
|
||||||
@ -272,6 +258,17 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
|
|||||||
else:
|
else:
|
||||||
return ObjectItemOperation(self, name).guess_type()
|
return ObjectItemOperation(self, name).guess_type()
|
||||||
|
|
||||||
|
def contains(self, key: Var | Any) -> BooleanVar:
|
||||||
|
"""Check if the object contains a key.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key: The key to check.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The result of the check.
|
||||||
|
"""
|
||||||
|
return ObjectHasOwnProperty(self, key)
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(
|
@dataclasses.dataclass(
|
||||||
eq=False,
|
eq=False,
|
||||||
@ -369,12 +366,12 @@ class LiteralObjectVar(LiteralVar, ObjectVar[OBJECT_TYPE]):
|
|||||||
return ImmutableVarData.merge(
|
return ImmutableVarData.merge(
|
||||||
*[
|
*[
|
||||||
value._get_all_var_data()
|
value._get_all_var_data()
|
||||||
for key, value in self._var_value
|
for value in self._var_value.values()
|
||||||
if isinstance(value, Var)
|
if isinstance(value, Var)
|
||||||
],
|
],
|
||||||
*[
|
*[
|
||||||
key._get_all_var_data()
|
key._get_all_var_data()
|
||||||
for key, value in self._var_value
|
for key in self._var_value.keys()
|
||||||
if isinstance(key, Var)
|
if isinstance(key, Var)
|
||||||
],
|
],
|
||||||
self._var_data,
|
self._var_data,
|
||||||
@ -802,3 +799,81 @@ class ToObjectOperation(ObjectVar):
|
|||||||
The VarData of the components and all of its children.
|
The VarData of the components and all of its children.
|
||||||
"""
|
"""
|
||||||
return self._cached_get_all_var_data
|
return self._cached_get_all_var_data
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
eq=False,
|
||||||
|
frozen=True,
|
||||||
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
||||||
|
)
|
||||||
|
class ObjectHasOwnProperty(BooleanVar):
|
||||||
|
"""Operation to check if an object has a property."""
|
||||||
|
|
||||||
|
value: ObjectVar = dataclasses.field(default_factory=lambda: LiteralObjectVar({}))
|
||||||
|
key: Var | Any = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
value: ObjectVar,
|
||||||
|
key: Var | Any,
|
||||||
|
_var_data: VarData | None = None,
|
||||||
|
):
|
||||||
|
"""Initialize the object has own property operation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The value of the operation.
|
||||||
|
key: The key to check.
|
||||||
|
_var_data: Additional hooks and imports associated with the operation.
|
||||||
|
"""
|
||||||
|
super(ObjectHasOwnProperty, self).__init__(
|
||||||
|
_var_name="",
|
||||||
|
_var_data=ImmutableVarData.merge(_var_data),
|
||||||
|
)
|
||||||
|
object.__setattr__(self, "value", value)
|
||||||
|
object.__setattr__(
|
||||||
|
self, "key", key if isinstance(key, Var) else LiteralVar.create(key)
|
||||||
|
)
|
||||||
|
object.__delattr__(self, "_var_name")
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _cached_var_name(self) -> str:
|
||||||
|
"""The name of the operation.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The name of the operation.
|
||||||
|
"""
|
||||||
|
return f"{str(self.value)}.hasOwnProperty({str(self.key)})"
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
"""Get an attribute of the operation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the attribute.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The attribute of the operation.
|
||||||
|
"""
|
||||||
|
if name == "_var_name":
|
||||||
|
return self._cached_var_name
|
||||||
|
return super(type(self), self).__getattr__(name)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Get all VarData associated with the operation.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The VarData of the components and all of its children.
|
||||||
|
"""
|
||||||
|
return ImmutableVarData.merge(
|
||||||
|
self.value._get_all_var_data(),
|
||||||
|
self.key._get_all_var_data(),
|
||||||
|
self._var_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Wrapper method for cached property.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The VarData of the components and all of its children.
|
||||||
|
"""
|
||||||
|
return self._cached_get_all_var_data
|
@ -27,13 +27,13 @@ from typing_extensions import get_origin
|
|||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.constants.base import REFLEX_VAR_OPENING_TAG
|
from reflex.constants.base import REFLEX_VAR_OPENING_TAG
|
||||||
from reflex.experimental.vars.base import (
|
from .base import (
|
||||||
ImmutableVar,
|
ImmutableVar,
|
||||||
LiteralVar,
|
LiteralVar,
|
||||||
figure_out_type,
|
figure_out_type,
|
||||||
unionize,
|
unionize,
|
||||||
)
|
)
|
||||||
from reflex.experimental.vars.number import (
|
from .number import (
|
||||||
BooleanVar,
|
BooleanVar,
|
||||||
LiteralNumberVar,
|
LiteralNumberVar,
|
||||||
NotEqualOperation,
|
NotEqualOperation,
|
||||||
@ -71,27 +71,29 @@ class StringVar(ImmutableVar[str]):
|
|||||||
"""
|
"""
|
||||||
return ConcatVarOperation(other, self)
|
return ConcatVarOperation(other, self)
|
||||||
|
|
||||||
def __mul__(self, other: int) -> ConcatVarOperation:
|
def __mul__(self, other: NumberVar | int) -> StringVar:
|
||||||
"""Concatenate two strings.
|
"""
|
||||||
|
Multiply the sequence by a number or an integer.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
other: The other string.
|
other (NumberVar | int): The number or integer to multiply the sequence by.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The string concatenation operation.
|
StringVar: The resulting sequence after multiplication.
|
||||||
"""
|
"""
|
||||||
return ConcatVarOperation(*[self for _ in range(other)])
|
return (self.split() * other).join()
|
||||||
|
|
||||||
def __rmul__(self, other: int) -> ConcatVarOperation:
|
def __rmul__(self, other: NumberVar | int) -> StringVar:
|
||||||
"""Concatenate two strings.
|
"""
|
||||||
|
Multiply the sequence by a number or an integer.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
other: The other string.
|
other (NumberVar | int): The number or integer to multiply the sequence by.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The string concatenation operation.
|
StringVar: The resulting sequence after multiplication.
|
||||||
"""
|
"""
|
||||||
return ConcatVarOperation(*[self for _ in range(other)])
|
return (self.split() * other).join()
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(self, i: slice) -> ArrayJoinOperation: ...
|
def __getitem__(self, i: slice) -> ArrayJoinOperation: ...
|
||||||
@ -596,10 +598,17 @@ class LiteralStringVar(LiteralVar, StringVar):
|
|||||||
var_data.interpolations = [
|
var_data.interpolations = [
|
||||||
(realstart, realstart + string_length)
|
(realstart, realstart + string_length)
|
||||||
]
|
]
|
||||||
|
var_content = value[end : (end + string_length)]
|
||||||
|
if (
|
||||||
|
var_content[0] == "{"
|
||||||
|
and var_content[-1] == "}"
|
||||||
|
and strings_and_vals
|
||||||
|
and strings_and_vals[-1][-1] == "$"
|
||||||
|
):
|
||||||
|
strings_and_vals[-1] = strings_and_vals[-1][:-1]
|
||||||
|
var_content = "(" + var_content[1:-1] + ")"
|
||||||
strings_and_vals.append(
|
strings_and_vals.append(
|
||||||
ImmutableVar.create_safe(
|
ImmutableVar.create_safe(var_content, _var_data=var_data)
|
||||||
value[end : (end + string_length)], _var_data=var_data
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
value = value[(end + string_length) :]
|
value = value[(end + string_length) :]
|
||||||
|
|
||||||
@ -728,8 +737,6 @@ VALUE_TYPE = TypeVar("VALUE_TYPE")
|
|||||||
class ArrayVar(ImmutableVar[ARRAY_VAR_TYPE]):
|
class ArrayVar(ImmutableVar[ARRAY_VAR_TYPE]):
|
||||||
"""Base class for immutable array vars."""
|
"""Base class for immutable array vars."""
|
||||||
|
|
||||||
from reflex.experimental.vars.sequence import StringVar
|
|
||||||
|
|
||||||
def join(self, sep: StringVar | str = "") -> ArrayJoinOperation:
|
def join(self, sep: StringVar | str = "") -> ArrayJoinOperation:
|
||||||
"""Join the elements of the array.
|
"""Join the elements of the array.
|
||||||
|
|
||||||
@ -739,7 +746,6 @@ class ArrayVar(ImmutableVar[ARRAY_VAR_TYPE]):
|
|||||||
Returns:
|
Returns:
|
||||||
The joined elements.
|
The joined elements.
|
||||||
"""
|
"""
|
||||||
from reflex.experimental.vars.sequence import ArrayJoinOperation
|
|
||||||
|
|
||||||
return ArrayJoinOperation(self, sep)
|
return ArrayJoinOperation(self, sep)
|
||||||
|
|
||||||
@ -751,6 +757,18 @@ class ArrayVar(ImmutableVar[ARRAY_VAR_TYPE]):
|
|||||||
"""
|
"""
|
||||||
return ArrayReverseOperation(self)
|
return ArrayReverseOperation(self)
|
||||||
|
|
||||||
|
def __add__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> ArrayConcatOperation:
|
||||||
|
"""
|
||||||
|
Concatenate two arrays.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
other (ArrayVar[ARRAY_VAR_TYPE]): The other array to concatenate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ArrayConcatOperation: The concatenation of the two arrays.
|
||||||
|
"""
|
||||||
|
return ArrayConcatOperation(self, other)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(self, i: slice) -> ArrayVar[ARRAY_VAR_TYPE]: ...
|
def __getitem__(self, i: slice) -> ArrayVar[ARRAY_VAR_TYPE]: ...
|
||||||
|
|
||||||
@ -915,6 +933,30 @@ class ArrayVar(ImmutableVar[ARRAY_VAR_TYPE]):
|
|||||||
"""
|
"""
|
||||||
return ArrayContainsOperation(self, other)
|
return ArrayContainsOperation(self, other)
|
||||||
|
|
||||||
|
def __mul__(self, other: NumberVar | int) -> ArrayVar[ARRAY_VAR_TYPE]:
|
||||||
|
"""
|
||||||
|
Multiply the sequence by a number or integer.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
other (NumberVar | int): The number or integer to multiply the sequence by.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ArrayVar[ARRAY_VAR_TYPE]: The result of multiplying the sequence by the given number or integer.
|
||||||
|
"""
|
||||||
|
return ArrayRepeatOperation(self, other)
|
||||||
|
|
||||||
|
def __rmul__(self, other: NumberVar | int) -> ArrayVar[ARRAY_VAR_TYPE]:
|
||||||
|
"""
|
||||||
|
Multiply the sequence by a number or integer.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
other (NumberVar | int): The number or integer to multiply the sequence by.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ArrayVar[ARRAY_VAR_TYPE]: The result of multiplying the sequence by the given number or integer.
|
||||||
|
"""
|
||||||
|
return ArrayRepeatOperation(self, other)
|
||||||
|
|
||||||
|
|
||||||
LIST_ELEMENT = TypeVar("LIST_ELEMENT")
|
LIST_ELEMENT = TypeVar("LIST_ELEMENT")
|
||||||
|
|
||||||
@ -1296,7 +1338,7 @@ class ArrayReverseOperation(ArrayToArrayOperation):
|
|||||||
Returns:
|
Returns:
|
||||||
The name of the var.
|
The name of the var.
|
||||||
"""
|
"""
|
||||||
return f"{str(self.a)}.reverse()"
|
return f"{str(self.a)}.slice().reverse()"
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(
|
@dataclasses.dataclass(
|
||||||
@ -1762,3 +1804,140 @@ class ToArrayOperation(ArrayVar):
|
|||||||
|
|
||||||
def _get_all_var_data(self) -> ImmutableVarData | None:
|
def _get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
return self._cached_get_all_var_data
|
return self._cached_get_all_var_data
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
eq=False,
|
||||||
|
frozen=True,
|
||||||
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
||||||
|
)
|
||||||
|
class ArrayRepeatOperation(ArrayVar):
|
||||||
|
"""Base class for immutable array vars that are the result of an array repeat operation."""
|
||||||
|
|
||||||
|
a: ArrayVar = dataclasses.field(default_factory=lambda: LiteralArrayVar([]))
|
||||||
|
n: NumberVar = dataclasses.field(default_factory=lambda: LiteralNumberVar(0))
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, a: ArrayVar, n: NumberVar | int, _var_data: VarData | None = None
|
||||||
|
):
|
||||||
|
"""Initialize the array repeat operation var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
a: The array.
|
||||||
|
n: The number of times to repeat the array.
|
||||||
|
_var_data: Additional hooks and imports associated with the Var.
|
||||||
|
"""
|
||||||
|
super(ArrayRepeatOperation, self).__init__(
|
||||||
|
_var_name="",
|
||||||
|
_var_type=a._var_type,
|
||||||
|
_var_data=ImmutableVarData.merge(_var_data),
|
||||||
|
)
|
||||||
|
object.__setattr__(self, "a", a)
|
||||||
|
object.__setattr__(
|
||||||
|
self,
|
||||||
|
"n",
|
||||||
|
n if isinstance(n, Var) else LiteralNumberVar(n),
|
||||||
|
)
|
||||||
|
object.__delattr__(self, "_var_name")
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _cached_var_name(self) -> str:
|
||||||
|
"""The name of the var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The name of the var.
|
||||||
|
"""
|
||||||
|
return f"Array.from({{ length: {str(self.n)} }}).flatMap(() => {str(self.a)})"
|
||||||
|
|
||||||
|
def __getattr__(self, name: str) -> Any:
|
||||||
|
"""Get an attribute of the var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the attribute.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The attribute value.
|
||||||
|
"""
|
||||||
|
if name == "_var_name":
|
||||||
|
return self._cached_var_name
|
||||||
|
getattr(super(ArrayRepeatOperation, self), name)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Get all VarData associated with the Var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The VarData of the components and all of its children.
|
||||||
|
"""
|
||||||
|
return ImmutableVarData.merge(
|
||||||
|
self.a._get_all_var_data(), self.n._get_all_var_data(), self._var_data
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
return self._cached_get_all_var_data
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
eq=False,
|
||||||
|
frozen=True,
|
||||||
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
||||||
|
)
|
||||||
|
class ArrayConcatOperation(ArrayVar):
|
||||||
|
"""Base class for immutable array vars that are the result of an array concat operation."""
|
||||||
|
|
||||||
|
a: ArrayVar = dataclasses.field(default_factory=lambda: LiteralArrayVar([]))
|
||||||
|
b: ArrayVar = dataclasses.field(default_factory=lambda: LiteralArrayVar([]))
|
||||||
|
|
||||||
|
def __init__(self, a: ArrayVar, b: ArrayVar, _var_data: VarData | None = None):
|
||||||
|
"""Initialize the array concat operation var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
a: The first array.
|
||||||
|
b: The second array.
|
||||||
|
_var_data: Additional hooks and imports associated with the Var.
|
||||||
|
"""
|
||||||
|
# TODO: Figure out how to merge the types of a and b
|
||||||
|
super(ArrayConcatOperation, self).__init__(
|
||||||
|
_var_name="",
|
||||||
|
_var_type=List[ARRAY_VAR_TYPE],
|
||||||
|
_var_data=ImmutableVarData.merge(_var_data),
|
||||||
|
)
|
||||||
|
object.__setattr__(self, "a", a)
|
||||||
|
object.__setattr__(self, "b", b)
|
||||||
|
object.__delattr__(self, "_var_name")
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _cached_var_name(self) -> str:
|
||||||
|
"""The name of the var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The name of the var.
|
||||||
|
"""
|
||||||
|
return f"[...{str(self.a)}, ...{str(self.b)}]"
|
||||||
|
|
||||||
|
def __getattr__(self, name: str) -> Any:
|
||||||
|
"""Get an attribute of the var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the attribute.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The attribute value.
|
||||||
|
"""
|
||||||
|
if name == "_var_name":
|
||||||
|
return self._cached_var_name
|
||||||
|
getattr(super(ArrayConcatOperation, self), name)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
"""Get all VarData associated with the Var.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The VarData of the components and all of its children.
|
||||||
|
"""
|
||||||
|
return ImmutableVarData.merge(
|
||||||
|
self.a._get_all_var_data(), self.b._get_all_var_data(), self._var_data
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_all_var_data(self) -> ImmutableVarData | None:
|
||||||
|
return self._cached_get_all_var_data
|
@ -32,6 +32,7 @@ import dill
|
|||||||
from sqlalchemy.orm import DeclarativeBase
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
|
||||||
from reflex.config import get_config
|
from reflex.config import get_config
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pydantic.v1 as pydantic
|
import pydantic.v1 as pydantic
|
||||||
@ -55,7 +56,12 @@ from reflex.utils import console, format, prerequisites, types
|
|||||||
from reflex.utils.exceptions import ImmutableStateError, LockExpiredError
|
from reflex.utils.exceptions import ImmutableStateError, LockExpiredError
|
||||||
from reflex.utils.exec import is_testing_env
|
from reflex.utils.exec import is_testing_env
|
||||||
from reflex.utils.serializers import SerializedType, serialize, serializer
|
from reflex.utils.serializers import SerializedType, serialize, serializer
|
||||||
from reflex.vars import BaseVar, ComputedVar, Var, computed_var
|
from reflex.vars import (
|
||||||
|
ComputedVar,
|
||||||
|
ImmutableVarData,
|
||||||
|
Var,
|
||||||
|
computed_var,
|
||||||
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
@ -298,7 +304,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
vars: ClassVar[Dict[str, Var]] = {}
|
vars: ClassVar[Dict[str, Var]] = {}
|
||||||
|
|
||||||
# The base vars of the class.
|
# The base vars of the class.
|
||||||
base_vars: ClassVar[Dict[str, BaseVar]] = {}
|
base_vars: ClassVar[Dict[str, ImmutableVar]] = {}
|
||||||
|
|
||||||
# The computed vars of the class.
|
# The computed vars of the class.
|
||||||
computed_vars: ClassVar[Dict[str, ComputedVar]] = {}
|
computed_vars: ClassVar[Dict[str, ComputedVar]] = {}
|
||||||
@ -520,9 +526,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
|
|
||||||
# Set the base and computed vars.
|
# Set the base and computed vars.
|
||||||
cls.base_vars = {
|
cls.base_vars = {
|
||||||
f.name: BaseVar(_var_name=f.name, _var_type=f.outer_type_)._var_set_state(
|
f.name: ImmutableVar(
|
||||||
cls
|
_var_name=format.format_state_name(cls.get_full_name()) + "." + f.name,
|
||||||
)
|
_var_type=f.outer_type_,
|
||||||
|
_var_data=ImmutableVarData.from_state(cls),
|
||||||
|
).guess_type()
|
||||||
for f in cls.get_fields().values()
|
for f in cls.get_fields().values()
|
||||||
if f.name not in cls.get_skip_vars()
|
if f.name not in cls.get_skip_vars()
|
||||||
}
|
}
|
||||||
@ -846,7 +854,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
return getattr(substate, name)
|
return getattr(substate, name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _init_var(cls, prop: BaseVar):
|
def _init_var(cls, prop: ImmutableVar):
|
||||||
"""Initialize a variable.
|
"""Initialize a variable.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -889,7 +897,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# create the variable based on name and type
|
# create the variable based on name and type
|
||||||
var = BaseVar(_var_name=name, _var_type=type_)
|
var = ImmutableVar(_var_name=name, _var_type=type_).guess_type()
|
||||||
var._var_set_state(cls)
|
var._var_set_state(cls)
|
||||||
|
|
||||||
# add the pydantic field dynamically (must be done before _init_var)
|
# add the pydantic field dynamically (must be done before _init_var)
|
||||||
@ -909,13 +917,18 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
cls._init_var_dependency_dicts()
|
cls._init_var_dependency_dicts()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _set_var(cls, prop: BaseVar):
|
def _set_var(cls, prop: ImmutableVar):
|
||||||
"""Set the var as a class member.
|
"""Set the var as a class member.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prop: The var instance to set.
|
prop: The var instance to set.
|
||||||
"""
|
"""
|
||||||
setattr(cls, prop._var_name, prop)
|
acutal_var_name = (
|
||||||
|
prop._var_name
|
||||||
|
if "." not in prop._var_name
|
||||||
|
else prop._var_name.split(".")[-1]
|
||||||
|
)
|
||||||
|
setattr(cls, acutal_var_name, prop)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _create_event_handler(cls, fn):
|
def _create_event_handler(cls, fn):
|
||||||
@ -935,7 +948,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
cls.setvar = cls.event_handlers["setvar"] = EventHandlerSetVar(state_cls=cls)
|
cls.setvar = cls.event_handlers["setvar"] = EventHandlerSetVar(state_cls=cls)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _create_setter(cls, prop: BaseVar):
|
def _create_setter(cls, prop: ImmutableVar):
|
||||||
"""Create a setter for the var.
|
"""Create a setter for the var.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -948,13 +961,16 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
setattr(cls, setter_name, event_handler)
|
setattr(cls, setter_name, event_handler)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _set_default_value(cls, prop: BaseVar):
|
def _set_default_value(cls, prop: ImmutableVar):
|
||||||
"""Set the default value for the var.
|
"""Set the default value for the var.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prop: The var to set the default value for.
|
prop: The var to set the default value for.
|
||||||
"""
|
"""
|
||||||
# Get the pydantic field for the var.
|
# Get the pydantic field for the var.
|
||||||
|
if "." in prop._var_name:
|
||||||
|
field = cls.get_fields()[prop._var_name.split(".")[-1]]
|
||||||
|
else:
|
||||||
field = cls.get_fields()[prop._var_name]
|
field = cls.get_fields()[prop._var_name]
|
||||||
if field.required:
|
if field.required:
|
||||||
default_value = prop.get_default_value()
|
default_value = prop.get_default_value()
|
||||||
|
@ -7,9 +7,11 @@ from typing import Any, Literal, Tuple, Type
|
|||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.components.core.breakpoints import Breakpoints, breakpoints_values
|
from reflex.components.core.breakpoints import Breakpoints, breakpoints_values
|
||||||
from reflex.event import EventChain
|
from reflex.event import EventChain
|
||||||
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
|
from reflex.ivars.function import FunctionVar
|
||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
from reflex.utils.imports import ImportVar
|
from reflex.utils.imports import ImportVar
|
||||||
from reflex.vars import BaseVar, CallableVar, Var, VarData
|
from reflex.vars import ImmutableVarData, Var, VarData
|
||||||
|
|
||||||
VarData.update_forward_refs() # Ensure all type definitions are resolved
|
VarData.update_forward_refs() # Ensure all type definitions are resolved
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ color_mode_imports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _color_mode_var(_var_name: str, _var_type: Type = str) -> BaseVar:
|
def _color_mode_var(_var_name: str, _var_type: Type = str) -> ImmutableVar:
|
||||||
"""Create a Var that destructs the _var_name from ColorModeContext.
|
"""Create a Var that destructs the _var_name from ColorModeContext.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -33,24 +35,22 @@ def _color_mode_var(_var_name: str, _var_type: Type = str) -> BaseVar:
|
|||||||
_var_type: The type of the Var.
|
_var_type: The type of the Var.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The BaseVar for accessing _var_name from ColorModeContext.
|
The Var that resolves to the color mode.
|
||||||
"""
|
"""
|
||||||
return BaseVar(
|
return ImmutableVar(
|
||||||
_var_name=_var_name,
|
_var_name=_var_name,
|
||||||
_var_type=_var_type,
|
_var_type=_var_type,
|
||||||
_var_is_local=False,
|
_var_data=ImmutableVarData(
|
||||||
_var_is_string=False,
|
|
||||||
_var_data=VarData(
|
|
||||||
imports=color_mode_imports,
|
imports=color_mode_imports,
|
||||||
hooks={f"const {{ {_var_name} }} = useContext(ColorModeContext)": None},
|
hooks={f"const {{ {_var_name} }} = useContext(ColorModeContext)": None},
|
||||||
),
|
),
|
||||||
)
|
).guess_type()
|
||||||
|
|
||||||
|
|
||||||
@CallableVar
|
# @CallableVar
|
||||||
def set_color_mode(
|
def set_color_mode(
|
||||||
new_color_mode: LiteralColorMode | Var[LiteralColorMode] | None = None,
|
new_color_mode: LiteralColorMode | Var[LiteralColorMode] | None = None,
|
||||||
) -> BaseVar[EventChain]:
|
) -> Var[EventChain]:
|
||||||
"""Create an EventChain Var that sets the color mode to a specific value.
|
"""Create an EventChain Var that sets the color mode to a specific value.
|
||||||
|
|
||||||
Note: `set_color_mode` is not a real event and cannot be triggered from a
|
Note: `set_color_mode` is not a real event and cannot be triggered from a
|
||||||
@ -70,11 +70,14 @@ def set_color_mode(
|
|||||||
return base_setter
|
return base_setter
|
||||||
|
|
||||||
if not isinstance(new_color_mode, Var):
|
if not isinstance(new_color_mode, Var):
|
||||||
new_color_mode = Var.create_safe(new_color_mode, _var_is_string=True)
|
new_color_mode = LiteralVar.create(new_color_mode)
|
||||||
return base_setter._replace(
|
|
||||||
_var_name=f"() => {base_setter._var_name}({new_color_mode._var_name_unwrapped})",
|
return ImmutableVar(
|
||||||
merge_var_data=new_color_mode._var_data,
|
f"() => {str(base_setter)}({str(new_color_mode)})",
|
||||||
)
|
_var_data=ImmutableVarData.merge(
|
||||||
|
base_setter._get_all_var_data(), new_color_mode._get_all_var_data()
|
||||||
|
),
|
||||||
|
).to(FunctionVar, EventChain)
|
||||||
|
|
||||||
|
|
||||||
# Var resolves to the current color mode for the app ("light", "dark" or "system")
|
# Var resolves to the current color mode for the app ("light", "dark" or "system")
|
||||||
@ -111,7 +114,9 @@ def media_query(breakpoint_expr: str):
|
|||||||
return f"@media screen and (min-width: {breakpoint_expr})"
|
return f"@media screen and (min-width: {breakpoint_expr})"
|
||||||
|
|
||||||
|
|
||||||
def convert_item(style_item: str | Var) -> tuple[str, VarData | None]:
|
def convert_item(
|
||||||
|
style_item: str | Var,
|
||||||
|
) -> tuple[str, VarData | ImmutableVarData | None]:
|
||||||
"""Format a single value in a style dictionary.
|
"""Format a single value in a style dictionary.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -122,13 +127,13 @@ def convert_item(style_item: str | Var) -> tuple[str, VarData | None]:
|
|||||||
"""
|
"""
|
||||||
if isinstance(style_item, Var):
|
if isinstance(style_item, Var):
|
||||||
# If the value is a Var, extract the var_data and cast as str.
|
# If the value is a Var, extract the var_data and cast as str.
|
||||||
return str(style_item), style_item._var_data
|
return str(style_item), style_item._get_all_var_data()
|
||||||
|
|
||||||
# Otherwise, convert to Var to collapse VarData encoded in f-string.
|
# Otherwise, convert to Var to collapse VarData encoded in f-string.
|
||||||
new_var = Var.create(style_item, _var_is_string=False)
|
new_var = ImmutableVar.create(style_item)
|
||||||
if new_var is not None and new_var._var_data:
|
if new_var is not None and new_var._var_data:
|
||||||
# The wrapped backtick is used to identify the Var for interpolation.
|
# The wrapped backtick is used to identify the Var for interpolation.
|
||||||
return f"`{str(new_var)}`", new_var._var_data
|
return f"`{str(new_var)}`", new_var._get_all_var_data()
|
||||||
|
|
||||||
return style_item, None
|
return style_item, None
|
||||||
|
|
||||||
@ -175,7 +180,11 @@ def convert(style_dict):
|
|||||||
|
|
||||||
for key, value in style_dict.items():
|
for key, value in style_dict.items():
|
||||||
keys = format_style_key(key)
|
keys = format_style_key(key)
|
||||||
if isinstance(value, dict):
|
if isinstance(value, Var):
|
||||||
|
return_val = value
|
||||||
|
new_var_data = value._get_all_var_data()
|
||||||
|
update_out_dict(return_val, keys)
|
||||||
|
elif isinstance(value, dict):
|
||||||
# Recursively format nested style dictionaries.
|
# Recursively format nested style dictionaries.
|
||||||
return_val, new_var_data = convert(value)
|
return_val, new_var_data = convert(value)
|
||||||
update_out_dict(return_val, keys)
|
update_out_dict(return_val, keys)
|
||||||
@ -254,7 +263,7 @@ class Style(dict):
|
|||||||
value: The value to set.
|
value: The value to set.
|
||||||
"""
|
"""
|
||||||
# Create a Var to collapse VarData encoded in f-string.
|
# Create a Var to collapse VarData encoded in f-string.
|
||||||
_var = Var.create(value, _var_is_string=False)
|
_var = ImmutableVar.create(value)
|
||||||
if _var is not None:
|
if _var is not None:
|
||||||
# Carry the imports/hooks when setting a Var as a value.
|
# Carry the imports/hooks when setting a Var as a value.
|
||||||
self._var_data = VarData.merge(self._var_data, _var._var_data)
|
self._var_data = VarData.merge(self._var_data, _var._var_data)
|
||||||
|
@ -9,6 +9,8 @@ import re
|
|||||||
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
|
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
|
from reflex.ivars.function import FunctionVar
|
||||||
from reflex.utils import exceptions, types
|
from reflex.utils import exceptions, types
|
||||||
from reflex.vars import BaseVar, Var
|
from reflex.vars import BaseVar, Var
|
||||||
|
|
||||||
@ -483,8 +485,14 @@ def format_props(*single_props, **key_value_props) -> list[str]:
|
|||||||
The formatted props list.
|
The formatted props list.
|
||||||
"""
|
"""
|
||||||
# Format all the props.
|
# Format all the props.
|
||||||
|
from reflex.ivars.base import ImmutableVar
|
||||||
|
|
||||||
return [
|
return [
|
||||||
f"{name}={format_prop(prop)}"
|
(
|
||||||
|
f"{name}={{{format_prop(prop)}}}"
|
||||||
|
if isinstance(prop, ImmutableVar)
|
||||||
|
else f"{name}={format_prop(prop)}"
|
||||||
|
)
|
||||||
for name, prop in sorted(key_value_props.items())
|
for name, prop in sorted(key_value_props.items())
|
||||||
if prop is not None
|
if prop is not None
|
||||||
] + [str(prop) for prop in single_props]
|
] + [str(prop) for prop in single_props]
|
||||||
@ -613,11 +621,13 @@ def format_event_chain(
|
|||||||
|
|
||||||
|
|
||||||
def format_queue_events(
|
def format_queue_events(
|
||||||
events: EventSpec
|
events: (
|
||||||
|
EventSpec
|
||||||
| EventHandler
|
| EventHandler
|
||||||
| Callable
|
| Callable
|
||||||
| List[EventSpec | EventHandler | Callable]
|
| List[EventSpec | EventHandler | Callable]
|
||||||
| None = None,
|
| None
|
||||||
|
) = None,
|
||||||
args_spec: Optional[ArgsSpec] = None,
|
args_spec: Optional[ArgsSpec] = None,
|
||||||
) -> Var[EventChain]:
|
) -> Var[EventChain]:
|
||||||
"""Format a list of event handler / event spec as a javascript callback.
|
"""Format a list of event handler / event spec as a javascript callback.
|
||||||
@ -647,9 +657,7 @@ def format_queue_events(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not events:
|
if not events:
|
||||||
return Var.create_safe(
|
return ImmutableVar("(() => null)").to(FunctionVar, EventChain)
|
||||||
"() => null", _var_is_string=False, _var_is_local=False
|
|
||||||
).to(EventChain)
|
|
||||||
|
|
||||||
# If no spec is provided, the function will take no arguments.
|
# If no spec is provided, the function will take no arguments.
|
||||||
def _default_args_spec():
|
def _default_args_spec():
|
||||||
@ -682,12 +690,10 @@ def format_queue_events(
|
|||||||
|
|
||||||
# Return the final code snippet, expecting queueEvents, processEvent, and socket to be in scope.
|
# Return the final code snippet, expecting queueEvents, processEvent, and socket to be in scope.
|
||||||
# Typically this snippet will _only_ run from within an rx.call_script eval context.
|
# Typically this snippet will _only_ run from within an rx.call_script eval context.
|
||||||
return Var.create_safe(
|
return ImmutableVar(
|
||||||
f"{arg_def} => {{queueEvents([{','.join(payloads)}], {constants.CompileVars.SOCKET}); "
|
f"{arg_def} => {{queueEvents([{','.join(payloads)}], {constants.CompileVars.SOCKET}); "
|
||||||
f"processEvent({constants.CompileVars.SOCKET})}}",
|
f"processEvent({constants.CompileVars.SOCKET})}}",
|
||||||
_var_is_string=False,
|
).to(FunctionVar, EventChain)
|
||||||
_var_is_local=False,
|
|
||||||
).to(EventChain)
|
|
||||||
|
|
||||||
|
|
||||||
def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
|
def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
|
||||||
@ -939,6 +945,6 @@ def format_data_editor_cell(cell: Any):
|
|||||||
The formatted cell.
|
The formatted cell.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
"kind": Var.create(value="GridCellKind.Text", _var_is_string=False),
|
"kind": ImmutableVar.create("GridCellKind.Text"),
|
||||||
"data": cell,
|
"data": cell,
|
||||||
}
|
}
|
||||||
|
@ -345,6 +345,33 @@ class ImmutableVarData:
|
|||||||
== imports.collapse_imports(other.imports)
|
== imports.collapse_imports(other.imports)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_state(cls, state: Type[BaseState] | str) -> ImmutableVarData:
|
||||||
|
"""Set the state of the var.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state: The state to set or the full name of the state.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The var with the set state.
|
||||||
|
"""
|
||||||
|
from reflex.utils import format
|
||||||
|
|
||||||
|
state_name = state if isinstance(state, str) else state.get_full_name()
|
||||||
|
new_var_data = ImmutableVarData(
|
||||||
|
state=state_name,
|
||||||
|
hooks={
|
||||||
|
"const {0} = useContext(StateContexts.{0})".format(
|
||||||
|
format.format_state_name(state_name)
|
||||||
|
): None
|
||||||
|
},
|
||||||
|
imports={
|
||||||
|
f"/{constants.Dirs.CONTEXTS_PATH}": [ImportVar(tag="StateContexts")],
|
||||||
|
"react": [ImportVar(tag="useContext")],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return new_var_data
|
||||||
|
|
||||||
|
|
||||||
def _decode_var_immutable(value: str) -> tuple[ImmutableVarData | None, str]:
|
def _decode_var_immutable(value: str) -> tuple[ImmutableVarData | None, str]:
|
||||||
"""Decode the state name from a formatted var.
|
"""Decode the state name from a formatted var.
|
||||||
@ -800,11 +827,19 @@ class Var:
|
|||||||
"""
|
"""
|
||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
|
|
||||||
out = (
|
if self._var_is_local:
|
||||||
self._var_full_name
|
console.deprecate(
|
||||||
if self._var_is_local
|
feature_name="Local Vars",
|
||||||
else format.wrap(self._var_full_name, "{")
|
reason=(
|
||||||
|
"Setting _var_is_local to True does not have any effect anymore. "
|
||||||
|
"Use the new ImmutableVar instead."
|
||||||
|
),
|
||||||
|
deprecation_version="0.5.9",
|
||||||
|
removal_version="0.6.0",
|
||||||
)
|
)
|
||||||
|
out = self._var_full_name
|
||||||
|
else:
|
||||||
|
out = format.wrap(self._var_full_name, "{")
|
||||||
if self._var_is_string:
|
if self._var_is_string:
|
||||||
out = format.format_string(out)
|
out = format.format_string(out)
|
||||||
return out
|
return out
|
||||||
|
@ -63,6 +63,8 @@ class ImmutableVarData:
|
|||||||
def merge(
|
def merge(
|
||||||
cls, *others: ImmutableVarData | VarData | None
|
cls, *others: ImmutableVarData | VarData | None
|
||||||
) -> ImmutableVarData | None: ...
|
) -> ImmutableVarData | None: ...
|
||||||
|
@classmethod
|
||||||
|
def from_state(cls, state: Type[BaseState] | str) -> ImmutableVarData: ...
|
||||||
|
|
||||||
def _decode_var_immutable(value: str) -> tuple[ImmutableVarData, str]: ...
|
def _decode_var_immutable(value: str) -> tuple[ImmutableVarData, str]: ...
|
||||||
|
|
||||||
@ -150,7 +152,7 @@ class Var:
|
|||||||
@property
|
@property
|
||||||
def _var_full_name(self) -> str: ...
|
def _var_full_name(self) -> str: ...
|
||||||
def _var_set_state(self, state: Type[BaseState] | str) -> Any: ...
|
def _var_set_state(self, state: Type[BaseState] | str) -> Any: ...
|
||||||
def _get_all_var_data(self) -> VarData: ...
|
def _get_all_var_data(self) -> VarData | ImmutableVarData: ...
|
||||||
def json(self) -> str: ...
|
def json(self) -> str: ...
|
||||||
|
|
||||||
@dataclass(eq=False)
|
@dataclass(eq=False)
|
||||||
|
@ -8,19 +8,19 @@ from pandas import DataFrame
|
|||||||
|
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.constants.base import REFLEX_VAR_CLOSING_TAG, REFLEX_VAR_OPENING_TAG
|
from reflex.constants.base import REFLEX_VAR_CLOSING_TAG, REFLEX_VAR_OPENING_TAG
|
||||||
from reflex.experimental.vars.base import (
|
from reflex.ivars.base import (
|
||||||
ImmutableVar,
|
ImmutableVar,
|
||||||
LiteralVar,
|
LiteralVar,
|
||||||
var_operation,
|
var_operation,
|
||||||
)
|
)
|
||||||
from reflex.experimental.vars.function import ArgsFunctionOperation, FunctionStringVar
|
from reflex.ivars.function import ArgsFunctionOperation, FunctionStringVar
|
||||||
from reflex.experimental.vars.number import (
|
from reflex.ivars.number import (
|
||||||
LiteralBooleanVar,
|
LiteralBooleanVar,
|
||||||
LiteralNumberVar,
|
LiteralNumberVar,
|
||||||
NumberVar,
|
NumberVar,
|
||||||
)
|
)
|
||||||
from reflex.experimental.vars.object import LiteralObjectVar
|
from reflex.ivars.object import LiteralObjectVar
|
||||||
from reflex.experimental.vars.sequence import (
|
from reflex.ivars.sequence import (
|
||||||
ArrayVar,
|
ArrayVar,
|
||||||
ConcatVarOperation,
|
ConcatVarOperation,
|
||||||
LiteralArrayVar,
|
LiteralArrayVar,
|
||||||
|
Loading…
Reference in New Issue
Block a user