Source code for ryvencore.addons.default.Variables

from typing import Optional

from ryvencore import Node
from ryvencore.Base import Base, Event
from ryvencore.utils import serialize, deserialize
from ryvencore import AddOn



[docs]class Variable: """Implementation of flow variables""" def __init__(self, addon, flow, name='', val=None, data=None): self.addon = addon self.flow = flow self.name = name self.val = val if data and 'serialized' in data.keys(): self.val = deserialize(data['serialized'])
[docs] def get(self): """ Returns the value of the variable """ return self.val
[docs] def set(self, val): """ Sets the value of the variable """ self.val = val self.addon._var_updated(self.flow, self.name)
[docs] def serialize(self): return serialize(self.val)
[docs]class VarsAddon(AddOn): """ This addon provides a simple variable system. It provides an API to create Variable objects which can wrap any Python object. Nodes can subscribe to variable names with a callback that is executed once a variable with that name changes or is created. The callback must be a method of the node, so the subscription can be re-established on loading. This way nodes can react to changes of data and non-trivial data-flow is introduced, meaning that data dependencies are determined also by variable subscriptions and not purely by the edges in the graph anymore. This can be useful, but it can also prevent optimization. Variables are flow-local. >>> import ryvencore as rc >>> >>> class MyNode(rc.Node): ... init_outputs = [] ... ... def __init__(self, params): ... super().__init__(params) ... ... self.Vars = self.get_addon('Variables') ... self.var_val = None ... ... def place_event(self): ... self.Vars.subscribe(self, 'var1', self.var1_changed) ... self.var_val = self.Vars.var(self.flow, 'var1').get() ... ... def var1_changed(self, val): ... print('var1 changed!') ... self.var_val = val >>> >>> s = rc.Session() >>> s.register_node(MyNode) >>> f = s.create_flow('main') >>> >>> Vars = s.addons['Variables'] >>> v = Vars.create_var(f, 'var1', None) >>> >>> n1 = f.create_node(MyNode) >>> v.set(42) var1 changed! >>> print(n1.var_val) 42 """ name = 'Variables' version = '0.0.3' def __init__(self): AddOn.__init__(self) # { # Flow: { # 'variable name': { # 'var': Variable, # 'subscriptions': [Node method] # }, # } self.flow_variables = {}
[docs] def var_name_valid(self, flow, name: str) -> bool: """ Checks if ``name`` is a valid variable identifier and hasn't been take yet. """ return name.isidentifier() and not self._var_exists(flow, name)
[docs] def create_var(self, flow, name: str, val=None, data=None) -> Optional[Variable]: """ Creates and returns a new variable and None if the name isn't valid. """ if flow not in self.flow_variables: self.flow_variables[flow] = {} if self.var_name_valid(flow, name): v = Variable(self, flow, name, val, data) self.flow_variables[flow][name] = { 'var': v, 'subscriptions': [] } return v else: return None
[docs] def delete_var(self, flow, name: str): """ Deletes a variable and causes subscription update. Subscriptions are preserved. """ if not self._var_exists(flow, name): return del self.flow_variables[flow][name]['var']
def _var_exists(self, flow, name: str) -> bool: return flow in self.flow_variables and name in self.flow_variables[flow]
[docs] def var(self, flow, name: str): """ Returns the variable with the given name or None if it doesn't exist. """ if not self._var_exists(flow, name): return None return self.flow_variables[flow][name]['var']
def _var_updated(self, flow, name: str): """ Called when a Variable object changes or when the var is created or deleted. """ v = self.flow_variables[flow][name]['var'] for (node, cb) in self.flow_variables[flow][name]['subscriptions']: cb(v.val)
[docs] def subscribe(self, node: Node, name: str, callback): """ Subscribe to a variable. ``callback`` must be a method of the node. """ if not self._var_exists(node.flow, name): return self.flow_variables[node.flow][name]['subscriptions'].append((node, callback))
[docs] def unsubscribe(self, node, name: str, callback): """ Unsubscribe from a variable. """ if not self._var_exists(node.flow, name): return self.flow_variables[node.flow][name]['subscriptions'].remove((node, callback))
def _extend_node_data(self, node, data: dict): """ Extends the node data with the variable subscriptions. """ data['Variables'] = { 'subscriptions': { name: cb.__name__ for name, var in self.flow_variables[node.flow].items() for (n, cb) in var['subscriptions'] if node == n } } if data['Variables']['subscriptions'] == {}: del data['Variables'] def _on_node_created(self, flow, node): """ Reconstruction of subscriptions. """ if node.init_data and 'Variables' in node.init_data: for name, cb_name in node.init_data['Variables']['subscriptions'].items(): self.subscribe(node, name, getattr(node, cb_name))
[docs] def get_state(self) -> dict: return { f.GLOBAL_ID: { name: { 'serialized': var['var'].serialize() } for name, var in self.flow_variables[f].items() } for f in self.flow_variables.keys() }
[docs] def set_state(self, state: dict): for pref_flow_id, variables in state.items(): f = Base.obj_from_prev_id(pref_flow_id) # recreate variables for name, var in variables.items(): if self._var_exists(f, name): self.var(f, name).set(deserialize(var['serialized'])) else: self.create_var(f, name, data=var)
addon = VarsAddon()