Skip to content

Commit 3702d23

Browse files
riebecjclaudemasenf
authored
Return the true value of an AsyncComputedVar when called via get_var_value() (#6391)
* Actually return the value of an AsyncComputedVar * Actually return the value of an AsyncComputedVar * Fix linting * Fixing newline error * Fixing local state var case * test(state): add regression test for get_var_value with async computed vars Reproduces the bug fixed in #6391 where get_var_value returned the un-awaited coroutine for an async computed var instead of the underlying value. https://claude.ai/code/session_01PLGmhJG9HNUzobmBRXQUnc * Extend test case for slow path * Handle ValueError in _run_lifespan_tasks helper Fix rare regression failure during app startup. --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Masen Furer <m_github@0x26.net>
1 parent c47f2ed commit 3702d23

2 files changed

Lines changed: 48 additions & 2 deletions

File tree

reflex/state.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,13 +1753,19 @@ async def get_var_value(self, var: Var[VAR_TYPE]) -> VAR_TYPE:
17531753
raise UnretrievableVarValueError(msg)
17541754
# Fastish case: this var belongs to this state
17551755
if var_data.state == self.get_full_name():
1756-
return getattr(self, var_data.field_name)
1756+
value = getattr(self, var_data.field_name)
1757+
if inspect.isawaitable(value):
1758+
return await value
1759+
return value
17571760

17581761
# Slow case: this var belongs to another state
17591762
other_state = await self.get_state(
17601763
self._get_root_state().get_class_substate(var_data.state)
17611764
)
1762-
return getattr(other_state, var_data.field_name)
1765+
value = getattr(other_state, var_data.field_name)
1766+
if inspect.isawaitable(value):
1767+
return await value
1768+
return value
17631769

17641770
def _mark_dirty_computed_vars(self) -> None:
17651771
"""Mark ComputedVars that need to be recalculated based on dirty_vars."""

tests/units/test_state.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4396,6 +4396,46 @@ async def test_get_var_value(
43964396
}
43974397

43984398

4399+
@pytest.mark.asyncio
4400+
async def test_get_var_value_async_computed_var(
4401+
token: str, attached_mock_event_context: EventContext
4402+
):
4403+
"""Test that get_var_value awaits async computed vars and returns their value.
4404+
4405+
Regression test for https://github.com/reflex-dev/reflex/pull/6391: previously
4406+
get_var_value returned the un-awaited coroutine for async computed vars rather
4407+
than the underlying value.
4408+
4409+
Args:
4410+
token: A token.
4411+
attached_mock_event_context: An event context that will be attached to the app's state manager.
4412+
"""
4413+
4414+
class StateWithAsyncCV(BaseState):
4415+
"""A state with an async computed var."""
4416+
4417+
base: int = 5
4418+
4419+
@rx.var(cache=True)
4420+
async def doubled(self) -> int:
4421+
return self.base * 2
4422+
4423+
class Substate(StateWithAsyncCV):
4424+
"""A substate to test get_var_value across states."""
4425+
4426+
state_manager = attached_mock_event_context.state_manager
4427+
state = await state_manager.get_state(
4428+
BaseStateToken(ident=token, cls=StateWithAsyncCV)
4429+
)
4430+
4431+
# Fast path
4432+
assert await state.get_var_value(StateWithAsyncCV.doubled) == 10
4433+
4434+
# Slow path
4435+
substate = await state.get_state(Substate)
4436+
assert await substate.get_var_value(StateWithAsyncCV.doubled) == 10
4437+
4438+
43994439
@pytest.mark.asyncio
44004440
async def test_async_computed_var_get_state(
44014441
token: str, attached_mock_event_context: EventContext

0 commit comments

Comments
 (0)