Take lock, fetch all linked states, and patch them into the current state tree. If previous_dirty_vars is NOT provided, then any dirty vars after exiting the context will be applied to all other clients linked to this state's linked token. Args: previous
(
self, previous_dirty_vars: dict[str, set[str]] | None = None
)
| 373 | |
| 374 | @contextlib.asynccontextmanager |
| 375 | async def _modify_linked_states( |
| 376 | self, previous_dirty_vars: dict[str, set[str]] | None = None |
| 377 | ) -> AsyncIterator[None]: |
| 378 | """Take lock, fetch all linked states, and patch them into the current state tree. |
| 379 | |
| 380 | If previous_dirty_vars is NOT provided, then any dirty vars after |
| 381 | exiting the context will be applied to all other clients linked to this |
| 382 | state's linked token. |
| 383 | |
| 384 | Args: |
| 385 | previous_dirty_vars: When apply linked state changes to other |
| 386 | tokens, provide mapping of state full_name to set of dirty vars. |
| 387 | |
| 388 | Yields: |
| 389 | None. |
| 390 | """ |
| 391 | if self._exit_stack is not None: |
| 392 | msg = "Cannot nest _modify_linked_states contexts." |
| 393 | raise ReflexRuntimeError(msg) |
| 394 | if self._reflex_internal_links is None: |
| 395 | msg = "No linked states to modify." |
| 396 | raise ReflexRuntimeError(msg) |
| 397 | self._exit_stack = contextlib.AsyncExitStack() |
| 398 | self._held_locks = {} |
| 399 | current_dirty_vars: dict[str, set[str]] = {} |
| 400 | affected_tokens: set[str] = set() |
| 401 | try: |
| 402 | # Go through all linked states and patch them in if they are present in the tree |
| 403 | for linked_state_name, linked_token in self._reflex_internal_links.items(): |
| 404 | linked_state_cls: type[SharedState] = ( |
| 405 | self.get_root_state().get_class_substate( # pyright: ignore[reportAssignmentType] |
| 406 | linked_state_name |
| 407 | ) |
| 408 | ) |
| 409 | try: |
| 410 | original_state = self._get_state_from_cache(linked_state_cls) |
| 411 | except ValueError: |
| 412 | # This state wasn't required for processing the event. |
| 413 | continue |
| 414 | linked_state = await original_state._internal_patch_linked_state( |
| 415 | linked_token |
| 416 | ) |
| 417 | if ( |
| 418 | previous_dirty_vars |
| 419 | and (dv := previous_dirty_vars.get(linked_state_name)) is not None |
| 420 | ): |
| 421 | linked_state.dirty_vars.update(dv) |
| 422 | linked_state._mark_dirty() |
| 423 | async with self._exit_stack: |
| 424 | yield None |
| 425 | # Collect dirty vars and other affected clients that need to be updated. |
| 426 | for linked_state in self._held_locks_linked_states(): |
| 427 | if linked_state._previous_dirty_vars is not None: |
| 428 | current_dirty_vars[linked_state.get_full_name()] = set( |
| 429 | linked_state._previous_dirty_vars |
| 430 | ) |
| 431 | if ( |
| 432 | linked_state._get_was_touched() |
no test coverage detected