Source code for ryvencore.Session
import importlib
import glob
from typing import List, Dict
from .Base import Base, Event
from .Flow import Flow
from .InfoMsgs import InfoMsgs
from .utils import pkg_path, load_from_file
from .Node import Node
[docs]class Session(Base):
"""
The Session is the top level interface to your project. It mainly manages flows, nodes, and add-ons and
provides methods for serialization and deserialization of the project.
"""
def __init__(
self,
gui: bool = False,
):
Base.__init__(self)
# events
self.new_flow_created = Event(Flow)
self.flow_renamed = Event(Flow)
self.flow_deleted = Event(Flow)
# ATTRIBUTES
self.addons = {}
self.flows: [Flow] = []
self.nodes = set() # list of node CLASSES
self.invisible_nodes = set()
self.gui: bool = gui
self.init_data = None
self.load_addons(pkg_path('addons/default/'))
self.load_addons(pkg_path('addons/'))
[docs] def load_addons(self, location: str):
"""
Loads all addons from the given location. ``location`` can be an absolute path to any readable directory.
See ``ryvencore.AddOn``.
"""
# discover all top-level modules in the given location
addons = filter(lambda p: not p.endswith('__init__.py'), glob.glob(location + '/*.py'))
for path in addons:
# extract 'addon' object from module
addon, = load_from_file(path, ['addon'])
if addon is None:
continue
# register addon
modname = path.split('/')[-1][:-3]
self.addons[modname] = addon
addon.register(self)
setattr(Node, addon.name, addon)
[docs] def register_nodes(self, node_classes: List):
"""
Registers a list of Nodes which then become available in the flows.
Do not attempt to place nodes in flows that haven't been registered in the session before.
"""
for n in node_classes:
self.register_node(n)
[docs] def register_node(self, node_class):
"""
Registers a single node.
"""
# build node class identifier
node_class._build_identifier()
self.nodes.add(node_class)
[docs] def unregister_node(self, node_class):
"""
Unregisters a node which will then be removed from the available list.
Existing instances won't be affected.
"""
self.nodes.remove(node_class)
[docs] def all_node_objects(self) -> List:
"""
Returns a list of all node objects instantiated in any flow.
"""
nodes = []
for s in self.flows:
for n in s.flow.nodes:
nodes.append(n)
return nodes
[docs] def create_flow(self, title: str = None, data: Dict = None) -> Flow:
"""
Creates and returns a new flow.
If data is provided the title parameter will be ignored.
"""
flow = Flow(session=self, title=title)
self.flows.append(flow)
if data:
flow.load(data)
self.new_flow_created.emit(flow)
return flow
[docs] def rename_flow(self, flow: Flow, title: str) -> bool:
"""
Renames an existing flow and returns success boolean.
"""
success = False
if self.flow_title_valid(title):
flow.title = title
success = True
self.flow_renamed.emit(flow)
return success
[docs] def flow_title_valid(self, title: str) -> bool:
"""
Checks whether a considered title for a new flow is valid (unique) or not.
"""
if len(title) == 0:
return False
for s in self.flows:
if s.title == title:
return False
return True
[docs] def delete_flow(self, flow: Flow):
"""
Deletes an existing flow.
"""
self.flows.remove(flow)
self.flow_deleted.emit(flow)
def _info_messenger(self):
"""
Returns a reference to InfoMsgs to print info data.
"""
return InfoMsgs
[docs] def load(self, data: Dict) -> List[Flow]:
"""
Loads a project and raises an exception if required nodes are missing (not registered).
"""
super().load(data)
self.init_data = data
# load flows
new_flows = []
# backward compatibility
if 'scripts' in data:
flows_data = {
title: script_data['flow']
for title, script_data in data['scripts'].items()
}
else:
flows_data = data['flows']
for fd in flows_data:
new_flows.append(self.create_flow(data=fd))
# load addons
for name, addon_data in data['addons'].items():
if name in self.addons:
self.addons[name].set_state(addon_data)
else:
print(f'found missing addon: {name}; attempting to load anyway')
return new_flows
[docs] def serialize(self):
"""Returns the project as JSON compatible dict to be saved and loaded again using load()"""
return self.complete_data(self.data())
[docs] def data(self) -> dict:
"""
Serializes the whole project into a JSON compatible dict. Pass to ``load()`` in a new session to restore.
"""
d = super().data()
d.update({
'flows': [
s.data() for s in self.flows
],
'addons': {
name: addon.get_state() for name, addon in self.addons.items()
}
})
return d