Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions packages/reflex-base/news/6747.performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`@var_operation` operands no longer pay the f-string tag round-trip (hash + permanent `_global_vars` registration + regex decode), cutting ~30-40% of var-operation construction cost and stopping internal operations from growing the never-evicting `_global_vars` dict.
33 changes: 32 additions & 1 deletion packages/reflex-base/src/reflex_base/vars/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,13 @@ def __format__(self, format_spec: str) -> str:
Returns:
The formatted var.
"""
# Operands of a running ``var_operation`` body interpolate as their
# raw JS expression: their VarData flows through the operation's
# ``_args``, so the tag round-trip (and its permanent ``_global_vars``
# entry) is pure overhead there. See ``var_operation``.
if self.__dict__.get("_format_without_tagging"):
return self._js_expr
Comment on lines +847 to +848

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Nested Operation Expression Disappears

When an operation result is used as another operation's operand, such as (a + b) * c, the operand is a CustomVarOperation whose _js_expr is empty and whose __str__ renders the actual expression. This branch returns the empty field directly, so the outer operation can emit incomplete JavaScript instead of the nested expression.

Suggested change
if self.__dict__.get("_format_without_tagging"):
return self._js_expr
if self.__dict__.get("_format_without_tagging"):
return str(self)

Comment on lines +847 to +848

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve tags when operands feed string Var builders

Because this flag is checked by every Var.__format__ call while a custom var_operation body runs, operands no longer produce the tagged f-string form that LiteralStringVar.create/Var.create depend on to turn f"prefix {value}" into a JS string concat. In that scenario the operand now formats as raw state.name, so the string builder compiles a literal like "prefix state.name" instead of a value depending on state.name; the _args merge only preserves VarData, not the string-concat semantics. Consider limiting the bypass to the var_operation_return JS-expression path rather than the whole body.

Useful? React with 👍 / 👎.


hashed_var = hash(self)

_global_vars[hashed_var] = self
Expand Down Expand Up @@ -1856,10 +1863,34 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> Var[T]:
for key, value in kwargs.items()
}

operands = [*args_vars.values(), *kwargs_vars.values()]
# Suppress f-string tagging for the operands while the body runs:
# their VarData reaches the operation through ``_args`` below, so the
# tag round-trip (hash + permanent ``_global_vars`` entry + regex
# decode of the return expression) is pure overhead. The suppression
# is ref-counted so a nested operation on the same var cannot clear
# an outer suppression early; vars created inside the body still tag
# normally and keep contributing VarData via the return expression.
for operand in operands:
operand_dict = operand.__dict__
operand_dict["_format_without_tagging"] = (
operand_dict.get("_format_without_tagging", 0) + 1
)
Comment on lines +1874 to +1878

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Shared Suppression Leaks Across Calls

The suppression counter is stored on the shared operand instance. If the same Var is formatted concurrently while an operation body is running, that unrelated formatting also skips tagging, so its enclosing expression can lose the operand's VarData, including required imports or hooks.

try:
return_var = func(*args_vars.values(), **kwargs_vars) # pyright: ignore [reportCallIssue]
finally:
for operand in operands:
operand_dict = operand.__dict__
remaining = operand_dict["_format_without_tagging"] - 1
if remaining:
operand_dict["_format_without_tagging"] = remaining
else:
del operand_dict["_format_without_tagging"]

return CustomVarOperation.create(
name=func.__name__,
args=tuple(list(args_vars.items()) + list(kwargs_vars.items())),
return_var=func(*args_vars.values(), **kwargs_vars), # pyright: ignore [reportCallIssue, reportReturnType]
return_var=return_var, # pyright: ignore [reportArgumentType]
).guess_type()

return wrapper
Expand Down
69 changes: 68 additions & 1 deletion tests/units/vars/test_base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
from collections.abc import Mapping, Sequence

import pytest
from reflex_base.vars.base import computed_var, figure_out_type
from reflex_base.utils.imports import ImportVar
from reflex_base.vars.base import (
Var,
VarData,
_global_vars,
computed_var,
figure_out_type,
var_operation,
var_operation_return,
)

from reflex.state import State

Expand Down Expand Up @@ -42,6 +51,64 @@ def test_figure_out_type(value, expected):
assert figure_out_type(value) == expected


def test_var_operation_does_not_register_global_vars() -> None:
"""Internal var operations bypass the f-string tag round-trip.

Regression: each operand interpolation hashed the var and permanently
registered it in the module-global ``_global_vars`` (a memory leak,
worst under hot-reload), then the return expression regex-decoded the
tag back out. Operand VarData already flows through
``CustomVarOperation._args``.
"""
lhs = Var(
_js_expr="tag_bypass_lhs",
_var_data=VarData(imports={"op-lib": [ImportVar(tag="thing")]}),
).to(int)

before = len(_global_vars)
result = lhs + 1
assert len(_global_vars) == before

# The suppression flag does not persist on the operand after the op.
assert "_format_without_tagging" not in lhs.__dict__

# Operand VarData still reaches the merged operation VarData via _args.
var_data = result._get_all_var_data()
assert var_data is not None
assert dict(var_data.imports)["op-lib"] == (ImportVar(tag="thing"),)
assert str(result) == "(tag_bypass_lhs + 1)"

# Formatting outside an operation still registers (and tags) as before.
formatted = f"{lhs}"
assert len(_global_vars) == before + 1
assert formatted != str(lhs)


def test_var_operation_body_created_vars_keep_var_data() -> None:
"""Vars created inside an operation body still contribute their VarData.

Only the operands bypass tagging; a var constructed inside the body is
not carried by ``_args``, so it must keep flowing through the tagged
return expression.
"""
from reflex_base.vars.number import NumberVar

@var_operation
def op_with_derived(value: NumberVar):
derived = Var(
_js_expr="derivedHelper",
_var_data=VarData(imports={"derived-lib": [ImportVar(tag="helper")]}),
)
return var_operation_return(f"({value} + {derived})", var_type=int)

result = op_with_derived(Var(_js_expr="a").to(int))

var_data = result._get_all_var_data()
assert var_data is not None
assert dict(var_data.imports)["derived-lib"] == (ImportVar(tag="helper"),)
assert str(result) == "(a + derivedHelper)"


def test_computed_var_replace() -> None:
class StateTest(State):
@computed_var(cache=True)
Expand Down
Loading