def restoreState(self, state): """ Restore the state of this flowchart from a previous call to `saveState()`. """ self.blockSignals(True) try: if 'source_configuration' in state: src_cfg = state['source_configuration'] self.widget().sourceConfigure.restoreState(src_cfg) if src_cfg['files']: self.widget().sourceConfigure.applyClicked() if 'library' in state: lib_cfg = state['library'] self.widget().libraryEditor.restoreState(lib_cfg) self.widget().libraryEditor.applyClicked() if 'viewbox' in state: self.viewBox.restoreState(state['viewbox']) nodes = state['nodes'] nodes.sort(key=lambda a: a['state']['pos'][0]) for n in nodes: if n['class'] == 'SourceNode': try: ttype = eval(n['state']['terminals']['Out']['ttype']) n['state']['terminals']['Out']['ttype'] = ttype node = SourceNode(name=n['name'], terminals=n['state']['terminals']) self.addNode(node=node) except Exception: printExc( "Error creating node %s: (continuing anyway)" % n['name']) else: try: node = self.createNode(n['class'], name=n['name']) except Exception: printExc( "Error creating node %s: (continuing anyway)" % n['name']) node.restoreState(n['state']) if hasattr(node, "display"): node.display(topics=None, terms=None, addr=None, win=None) if hasattr(node.widget, 'restoreState') and 'widget' in n['state']: node.widget.restoreState(n['state']['widget']) connections = {} with tempfile.NamedTemporaryFile(mode='w') as type_file: type_file.write("from mypy_extensions import TypedDict\n") type_file.write("from typing import *\n") type_file.write("import numbers\n") type_file.write("import amitypes\n") type_file.write("T = TypeVar('T')\n\n") nodes = self.nodes(data='node') for n1, t1, n2, t2 in state['connects']: try: node1 = nodes[n1] term1 = node1[t1] node2 = nodes[n2] term2 = node2[t2] self.connectTerminals(term1, term2, type_file) if term1.isInput() or term1.isCondition: in_name = node1.name() + '_' + term1.name() in_name = in_name.replace('.', '_') out_name = node2.name() + '_' + term2.name() out_name = out_name.replace('.', '_') else: in_name = node2.name() + '_' + term2.name() in_name = in_name.replace('.', '_') out_name = node1.name() + '_' + term1.name() out_name = out_name.replace('.', '_') connections[(in_name, out_name)] = (term1, term2) except Exception: print(node1.terminals) print(node2.terminals) printExc("Error connecting terminals %s.%s - %s.%s:" % (n1, t1, n2, t2)) type_file.flush() status = subprocess.run( ["mypy", "--follow-imports", "silent", type_file.name], capture_output=True, text=True) if status.returncode != 0: lines = status.stdout.split('\n')[:-1] for line in lines: m = re.search(r"\"+(\w+)\"+", line) if m: m = m.group().replace('"', '') for i in connections: if i[0] == m: term1, term2 = connections[i] term1.disconnectFrom(term2) break elif i[1] == m: term1, term2 = connections[i] term1.disconnectFrom(term2) break finally: self.blockSignals(False) for name, node in self.nodes(data='node'): self.sigNodeChanged.emit(node)
class NodeProcess(QtCore.QObject): def __init__(self, msg, broker_addr="", graphmgr_addr="", checkpoint_addr="", loop=None, library_paths=None, hutch=''): super().__init__() if loop is None: self.app = QtGui.QApplication([]) loop = QEventLoop(self.app) asyncio.set_event_loop(loop) self.win = NodeWindow(self) self.win.resize(800, 800) if msg.node_type == "SourceNode": self.node = SourceNode(name=msg.name) else: if library_paths: dirs = set(map(os.path.dirname, library_paths)) sys.path.extend(dirs) for mod in library_paths: mod = os.path.basename(mod) mod = os.path.splitext(mod)[0] mod = importlib.import_module(mod) nodes = [ getattr(mod, name) for name in dir(mod) if isNodeClass(getattr(mod, name)) ] for node in nodes: LIBRARY.addNodeType(node, [(mod.__name__, )]) self.node = LIBRARY.getNodeType(msg.node_type)(msg.name) self.node.restoreState(msg.state) self.graphmgr_addr = graphmgr_addr self.ctx = zmq.asyncio.Context() self.broker = self.ctx.socket(zmq.SUB) self.broker.connect(broker_addr) self.broker.setsockopt_string(zmq.SUBSCRIBE, msg.name + ZMQ_TOPIC_DELIM) self.checkpoint = self.ctx.socket(zmq.PUB) self.checkpoint.connect(checkpoint_addr) self.ctrlWidget = self.node.ctrlWidget(self.win) self.widget = None title = msg.name if hutch: title += f' hutch: {hutch}' self.win.setWindowTitle(title) with loop: loop.run_until_complete(self.process()) async def process(self): while True: await self.broker.recv_string() msg = await self.broker.recv_pyobj() if isinstance(msg, fcMsgs.DisplayNode): self.display(msg) elif isinstance(msg, fcMsgs.ReloadLibrary): self.reloadLibrary(msg) elif isinstance(msg, fcMsgs.CloseNode): return def display(self, msg): if self.node.viewed and msg.redisplay: self.node.close() self.widget = None if msg.geometry: self.win.restoreGeometry(msg.geometry) if self.widget is None: self.widget = self.node.display(msg.topics, msg.terms, self.graphmgr_addr, self.win, units=msg.units) if self.ctrlWidget and self.widget: splitter = QtWidgets.QSplitter(parent=self.win) splitter.addWidget(self.ctrlWidget) splitter.addWidget(self.widget) splitter.setStretchFactor(1, 10) self.win.setCentralWidget(splitter) self.ctrlWidget.setParent(splitter) self.widget.setParent(splitter) elif self.ctrlWidget: scrollarea = QtWidgets.QScrollArea(parent=self.win) scrollarea.setWidget(self.ctrlWidget) self.ctrlWidget.setParent(scrollarea) self.win.setCentralWidget(scrollarea) elif self.widget: scrollarea = QtWidgets.QScrollArea(parent=self.win) scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.widget) self.widget.setParent(scrollarea) self.win.setCentralWidget(scrollarea) if msg.state and hasattr(self.widget, 'restoreState'): self.widget.restoreState(msg.state) self.node.sigStateChanged.connect(self.send_checkpoint) self.win.show() if self.node.viewed: self.win.activateWindow() self.node.viewed = True def reloadLibrary(self, msg): for mod in msg.mods: mod = sys.modules[mod] pg.reload.reload(mod) @asyncSlot(object) async def send_checkpoint(self, node): state = node.saveState() msg = fcMsgs.NodeCheckpoint(node.name(), state=state) await self.checkpoint.send_string(node.name() + ZMQ_TOPIC_DELIM, zmq.SNDMORE) await self.checkpoint.send_pyobj(msg)
class NodeProcess(QtCore.QObject): def __init__(self, msg, broker_addr="", graphmgr_addr="", checkpoint_addr="", loop=None, library_paths=None): super().__init__() if loop is None: self.app = QtGui.QApplication([]) loop = QEventLoop(self.app) asyncio.set_event_loop(loop) self.win = NodeWindow(self) self.win.resize(800, 800) if msg.node_type == "SourceNode": self.node = SourceNode(name=msg.name) else: if library_paths: dirs = set(map(os.path.dirname, library_paths)) sys.path.extend(dirs) for mod in library_paths: mod = os.path.basename(mod) mod = os.path.splitext(mod)[0] mod = importlib.import_module(mod) nodes = [getattr(mod, name) for name in dir(mod) if isNodeClass(getattr(mod, name))] for node in nodes: LIBRARY.addNodeType(node, [(mod.__name__, )]) self.node = LIBRARY.getNodeType(msg.node_type)(msg.name) self.node.restoreState(msg.state) self.graphmgr_addr = graphmgr_addr self.ctx = zmq.asyncio.Context() self.broker = self.ctx.socket(zmq.SUB) self.broker.connect(broker_addr) self.broker.setsockopt_string(zmq.SUBSCRIBE, msg.name) self.checkpoint = self.ctx.socket(zmq.PUB) self.checkpoint.connect(checkpoint_addr) self.ctrlWidget = self.node.ctrlWidget(self.win) self.widget = None self.win.setWindowTitle(msg.name) with loop: loop.run_until_complete(asyncio.gather(self.process(), self.monitor_node_task())) async def monitor_node_task(self): if hasattr(self.node, 'task'): while self.node.task is None: await asyncio.sleep(0.1) # await the node task so we can see any exceptions it raised try: await self.node.task except asyncio.CancelledError: # ignore cancelled errors just means the window was closed pass async def process(self): while True: await self.broker.recv_string() msg = await self.broker.recv_pyobj() if isinstance(msg, fcMsgs.DisplayNode): self.display(msg) elif isinstance(msg, fcMsgs.ReloadLibrary): self.reloadLibrary(msg) elif isinstance(msg, fcMsgs.CloseNode): return def display(self, msg): if self.node.viewed and msg.redisplay: self.node.close() self.widget = None if msg.geometry: self.win.restoreGeometry(msg.geometry) if self.widget is None: self.widget = self.node.display(msg.topics, msg.terms, self.graphmgr_addr, self.win, units=msg.units) if self.ctrlWidget and self.widget: cw = QtGui.QWidget() self.win.setCentralWidget(cw) layout = QtGui.QGridLayout() cw.setLayout(layout) layout.addWidget(self.ctrlWidget, 0, 0, -1, 1) layout.addWidget(self.widget, 0, 1, -1, -1) layout.setColumnStretch(1, 10) elif self.ctrlWidget: scrollarea = QtWidgets.QScrollArea() scrollarea.setWidget(self.ctrlWidget) self.win.setCentralWidget(scrollarea) elif self.widget: scrollarea = QtWidgets.QScrollArea() scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.widget) self.win.setCentralWidget(scrollarea) if msg.state and hasattr(self.widget, 'restoreState'): self.widget.restoreState(msg.state) self.node.sigStateChanged.connect(self.send_checkpoint) self.win.show() if self.node.viewed: self.win.activateWindow() self.node.viewed = True def reloadLibrary(self, msg): for mod in msg.mods: mod = sys.modules[mod] pg.reload.reload(mod) @asyncSlot(object) async def send_checkpoint(self, node): state = node.saveState() msg = fcMsgs.NodeCheckpoint(node.name(), state=state) await self.checkpoint.send_string(node.name(), zmq.SNDMORE) await self.checkpoint.send_pyobj(msg)