Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9a7d317
don't use reserve words for variable names
adhami3310 May 2, 2025
4fe0fe0
use underscore suffix instead
adhami3310 May 2, 2025
9473762
fix various places that got the wrong name
adhami3310 May 2, 2025
4b5899d
fix the test
adhami3310 May 2, 2025
97d15b3
fix unit tests
adhami3310 May 2, 2025
449c00c
fix dynamic components
adhami3310 May 3, 2025
826c5d3
i don't know how to do inheritance
adhami3310 May 3, 2025
c3c4181
maybe
adhami3310 May 3, 2025
ac29df2
remove that suffix
adhami3310 May 3, 2025
bc8cc41
ok we can't do that
adhami3310 May 3, 2025
af74e9f
add something to update vars internal
adhami3310 May 3, 2025
db4aa45
fix dynamic route
adhami3310 May 3, 2025
02f60a5
Merge branch 'main' into khaleel/eng-5649-foreach-with-var-name-that-…
adhami3310 May 7, 2025
ec07336
fix unit tests
adhami3310 May 7, 2025
cf0cc12
fix is hydrated
adhami3310 May 7, 2025
89e418c
Merge remote-tracking branch 'origin/main' into khaleel/eng-5649-fore…
adhami3310 Jun 10, 2025
94baf77
solve post merge artifcats
adhami3310 Jun 10, 2025
edd5a12
simplify rx base
adhami3310 Jun 10, 2025
dc99619
fix a few more post merge artifacts
adhami3310 Jun 10, 2025
589c3f4
make all of those guys into a constant
adhami3310 Jun 10, 2025
9a23d48
Merge branch 'main' into khaleel/eng-5649-foreach-with-var-name-that-…
adhami3310 Jun 13, 2025
6cd1a42
it's ruff out there
adhami3310 Jun 13, 2025
f663a06
use field marker
adhami3310 Jun 14, 2025
2bf3046
Merge branch 'main' into khaleel/eng-5649-foreach-with-var-name-that-…
adhami3310 Jun 14, 2025
146d39a
add ignore field makrer
adhami3310 Jun 14, 2025
976934f
msg = msg replace
adhami3310 Jun 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions reflex/.templates/web/utils/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,10 @@ const applyClientStorageDelta = (client_storage, delta) => {
);
if (unqualified_states.length === 1) {
const main_state = delta[unqualified_states[0]];
if (main_state.is_hydrated !== undefined && !main_state.is_hydrated) {
if (
main_state.is_hydrated_rx_state_ !== undefined &&
!main_state.is_hydrated_rx_state_
) {
// skip if the state is not hydrated yet, since all client storage
// values are sent in the hydrate event
return;
Expand Down Expand Up @@ -1025,7 +1028,7 @@ export const useEventLoop = (
const change_start = () => {
const main_state_dispatch = dispatch["reflex___state____state"];
if (main_state_dispatch !== undefined) {
main_state_dispatch({ is_hydrated: false });
main_state_dispatch({ is_hydrated_rx_state_: false });
}
};
change_start();
Expand Down
2 changes: 1 addition & 1 deletion reflex/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,7 @@ def _validate_var_dependencies(self, state: type[BaseState] | None = None) -> No
)
for dep in dep_set:
if dep not in state_cls.vars and dep not in state_cls.backend_vars:
msg = f"ComputedVar {var._js_expr} on state {state.__name__} has an invalid dependency {state_name}.{dep}"
msg = f"ComputedVar {var._name} on state {state.__name__} has an invalid dependency {state_name}.{dep}"
raise exceptions.VarDependencyError(msg)

for substate in state.class_subclasses:
Expand Down
88 changes: 1 addition & 87 deletions reflex/base.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,6 @@
"""Define the base Reflex class."""

from __future__ import annotations

import os
from typing import TYPE_CHECKING, Any

import pydantic.v1.main as pydantic_main
from pydantic.v1 import BaseModel
from pydantic.v1.fields import ModelField


def validate_field_name(bases: list[type[BaseModel]], field_name: str) -> None:
"""Ensure that the field's name does not shadow an existing attribute of the model.

Args:
bases: List of base models to check for shadowed attrs.
field_name: name of attribute

Raises:
VarNameError: If state var field shadows another in its parent state
"""
from reflex.utils.exceptions import VarNameError

# can't use reflex.config.environment here cause of circular import
reload = os.getenv("__RELOAD_CONFIG", "").lower() == "true"
base = None
try:
for base in bases:
if not reload and getattr(base, field_name, None):
pass
except TypeError as te:
msg = (
f'State var "{field_name}" in {base} has been shadowed by a substate var; '
f'use a different field name instead".'
)
raise VarNameError(msg) from te


# monkeypatch pydantic validate_field_name method to skip validating
# shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPrivateImportUsage]

if TYPE_CHECKING:
from reflex.vars import Var


class Base(BaseModel):
Expand Down Expand Up @@ -75,7 +33,7 @@ def json(self) -> str:
default=serialize,
)

def set(self, **kwargs: Any):
def set(self, **kwargs: object):
"""Set multiple fields and return the object.

Args:
Expand All @@ -87,47 +45,3 @@ def set(self, **kwargs: Any):
for key, value in kwargs.items():
setattr(self, key, value)
return self

@classmethod
def get_fields(cls) -> dict[str, ModelField]:
"""Get the fields of the object.

Returns:
The fields of the object.
"""
return cls.__fields__

@classmethod
def add_field(cls, var: Var, default_value: Any):
"""Add a pydantic field after class definition.

Used by State.add_var() to correctly handle the new variable.

Args:
var: The variable to add a pydantic field for.
default_value: The default value of the field
"""
var_name = var._var_field_name
new_field = ModelField.infer(
name=var_name,
value=default_value,
annotation=var._var_type,
class_validators=None,
config=cls.__config__,
)
cls.__fields__.update({var_name: new_field})

def get_value(self, key: str) -> Any:
"""Get the value of a field.

Args:
key: The key of the field.

Returns:
The value of the field.
"""
if isinstance(key, str):
# Seems like this function signature was wrong all along?
# If the user wants a field that we know of, get it and pass it off to _get_value
return getattr(self, key)
return key
3 changes: 3 additions & 0 deletions reflex/compiler/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
)
from reflex.config import get_config
from reflex.constants.compiler import PageNames
from reflex.constants.state import FIELD_MARKER
from reflex.environment import environment
from reflex.state import BaseState
from reflex.style import SYSTEM_COLOR_MODE
Expand Down Expand Up @@ -694,6 +695,8 @@ def _modify_exception(e: Exception) -> None:
f"{msg[:state_index]}{module_path}.{actual_state_name}{msg[dot_index:]}"
)

msg = msg.replace(FIELD_MARKER, "")

e.args = (msg,)


Expand Down
3 changes: 2 additions & 1 deletion reflex/compiler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from reflex.components.el.elements.metadata import Head, Meta, Title
from reflex.components.el.elements.other import Html
from reflex.components.el.elements.sectioning import Body
from reflex.constants.state import FIELD_MARKER
from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
from reflex.state import BaseState, _resolve_delta
from reflex.style import Style
Expand Down Expand Up @@ -252,7 +253,7 @@ def _compile_client_storage_recursive(
if name in state.inherited_vars:
# only include vars defined in this state
continue
state_key = f"{state_name}.{name}"
state_key = f"{state_name}.{name}" + FIELD_MARKER
field_type, options = _compile_client_storage_field(field)
if field_type is Cookie:
cookies[state_key] = options
Expand Down
5 changes: 3 additions & 2 deletions reflex/components/core/foreach.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from reflex.components.core.cond import cond
from reflex.components.tags import IterTag
from reflex.constants import MemoizationMode
from reflex.constants.state import FIELD_MARKER
from reflex.state import ComponentState
from reflex.utils import types
from reflex.utils.exceptions import UntypedVarError
Expand Down Expand Up @@ -132,11 +133,11 @@ def _render(self) -> IterTag:

if len(params) >= 1:
# Determine the arg var name based on the params accepted by render_fn.
props["arg_var_name"] = params[0].name
props["arg_var_name"] = params[0].name + FIELD_MARKER

if len(params) == 2:
# Determine the index var name based on the params accepted by render_fn.
props["index_var_name"] = params[1].name
props["index_var_name"] = params[1].name + FIELD_MARKER
else:
render_fn = self.render_fn
# Otherwise, use a deterministic index, based on the render function bytecode.
Expand Down
2 changes: 2 additions & 0 deletions reflex/constants/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ class StateManagerMode(str, Enum):

# Used for things like console_log, etc.
FRONTEND_EVENT_STATE = "__reflex_internal_frontend_event_state"

FIELD_MARKER = "_rx_state_"
Loading