Source code for pantra.components.reactdict

from __future__ import annotations
import typing
from collections import defaultdict

from ..common import typename
from .controllers import process_call

if typing.TYPE_CHECKING:
    from .render.render_node import RenderNode
    from .context import ReactNode

[docs] class ReactDict(dict): """Extended dictionary with reactions the changes Attributes: react_vars (dict[str, set[RenderNode]]): variable to nodes registered connections react_nodes (set[RenderNode]): set of all reactive nodes for fast search """ __slots__ = ('react_vars', 'react_nodes') def __init__(self): super().__init__() self.react_vars: dict[str, set[RenderNode]] = defaultdict(set) self.react_nodes: set[RenderNode] = set()
[docs] def call(self, func_name, *args, **kwargs): """get function by name and call with args""" return self[func_name](*args, **kwargs)
[docs] def register_reactions(self, var_names: set[str], node: RenderNode): """register variable to nodes reaction""" for var_name in var_names: self.react_vars[var_name].add(node) self.react_nodes.add(node)
[docs] def remove_reactions_to(self, node: RenderNode): """remove all reactions from node""" if node in self.react_nodes: self.react_nodes.remove(node) for v in self.react_vars.values(): v.discard(node)
[docs] def has_reactions_to(self, node: RenderNode) -> bool: """check if node has registered reactions""" return node in self.react_nodes
def __setitem__(self, key, value): if key not in self: dict.__setitem__(self, key, value) return old_value = self[key] dict.__setitem__(self, key, value) if (nodes:=self.react_vars.get(key, None)) is not None and value != old_value: for node in list(nodes): # type: RenderNode | ReactNode # WARNING: `nodes` list is dynamically changed by updates, but we need to avoid new nodes # as well as deleted ones if typename(node) == 'ReactNode': node.value = value node.update_tree() if isinstance(node.action, str): process_call(node.context.session, node.context, node.action, node) else: node.update(True)
[docs] def set_quietly(self, key, value): """set variable without effects""" super().__setitem__(key, value)
def __str__(self): return ', '.join(self.keys())