def setData(self, index, value, role): # pylint: disable=too-many-return-statements,too-many-branches,unused-argument """ Generic data modification (see QAbstractItemModel for details) :param index: a QModelIndex instance :param value: the new value :param role: the role to be changed :return: """ if not index.isValid(): return False item = index.internalPointer().content if isinstance(item, str): return False if isinstance(item, self.SubConfigContent): subConfig = item.subConfig if value == subConfig.getName(): return False config = self.root.content if Configuration.configType( subConfig) == Configuration.CONFIG_TYPE_APPLICATION: try: if subConfig.getName() == self.activeApp: self.activeApp = value config.renameApp(subConfig.getName(), value) except NexTRuntimeError: return False self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole]) return True if Configuration.configType( subConfig) == Configuration.CONFIG_TYPE_COMPOSITE: try: config.renameComposite(subConfig.getName(), value) except NexTRuntimeError: return False self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole]) return True if isinstance(item, self.NodeContent): if item.name == value: return False subConfig = index.parent().internalPointer().content.subConfig graph = subConfig.getGraph() try: graph.renameNode(item.name, value) except NexTRuntimeError: return False self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole]) return True if isinstance(item, self.PropertyContent): try: item.property.setProperty(item.name, value) except NexTRuntimeError: return False self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole]) return True return False
def test_recursion(): config = Configuration() cf_inner = CompositeFilter("cf_inner", config) cg_inner = cf_inner.getGraph() f1 = cg_inner.addNode("pyfile://" + os.path.dirname(__file__) + "/../interface/SimpleStaticFilter.py", "SimpleStaticFilter") cf = CompositeFilter("cf", config) cg = cf.getGraph() f1 = cg.addNode("pyfile://" + os.path.dirname(__file__) + "/../interface/SimpleStaticFilter.py", "SimpleStaticFilter") f2 = cg.addNode(cf_inner, "compositeNode") # add composite node to itself cg_oldNodes = set(cg.allNodes()) cg_inner_oldNodes = set(cg_inner.allNodes()) expect_exception(CompositeRecursion, cg.addNode, cf, "compositeNode") assert cg_oldNodes == set(cg.allNodes()) # add composite node to an inner node expect_exception(CompositeRecursion, cg_inner.addNode, cf, "compositeNode") assert cg_inner_oldNodes == set(cg_inner.allNodes()) # double dependency cf1 = CompositeFilter("cf1", config) cf2 = CompositeFilter("cf2", config) cf1.getGraph().addNode(cf2, "compositeNode") expect_exception(CompositeRecursion, cf2.getGraph().addNode, cf1, "compositeNode")
def indexOfSubConfigParent(self, subConfig): """ Returns the index of the given subConfig's parent :param subConfig: a SubConfiguration instance :return: a QModelIndex instance. """ sctype = Configuration.configType(subConfig) if sctype is Configuration.CONFIG_TYPE_APPLICATION: parent = self.index(1, 0, QModelIndex()) elif sctype is Configuration.CONFIG_TYPE_COMPOSITE: parent = self.index(0, 0, QModelIndex()) else: raise NexTRuntimeError("Unexpected subconfig type") return parent
def exception_setup(python, thread, where, activeTime_s): logging.getLogger(__name__).info("------------------------------------------------------") logging.getLogger(__name__).info("Starting exception_setup %d %s %s %f", python, thread, where, activeTime_s) from nexxT.services.ConsoleLogger import ConsoleLogger logger = ConsoleLogger() Services.addService("Logging", logger) class LogCollector(logging.StreamHandler): def __init__(self): super().__init__() self.logs = [] def emit(self, record): self.logs.append(record) # avoid warning flood about service profiling not found Services.addService("Profiling", None) collector = LogCollector() logging.getLogger().addHandler(collector) try: t = QTimer() t.setSingleShot(True) # timeout if test case hangs t2 = QTimer() t2.start((activeTime_s + 3)*1000) try: test_json = Path(__file__).parent / "test_except_constr.json" with test_json.open("r", encoding='utf-8') as fp: cfg = json.load(fp) if nexxT.useCImpl and not python: cfg["composite_filters"][0]["nodes"][2]["library"] = "binary://../binary/${NEXXT_PLATFORM}/${NEXXT_VARIANT}/test_plugins" cfg["composite_filters"][0]["nodes"][2]["thread"] = thread cfg["composite_filters"][0]["nodes"][2]["properties"]["whereToThrow"] = where mod_json = Path(__file__).parent / "test_except_constr_tmp.json" with mod_json.open("w", encoding="utf-8") as fp: json.dump(cfg, fp) config = Configuration() ConfigFileLoader.load(config, mod_json) config.activate("testApp") app.processEvents() aa = Application.activeApplication init = True def timeout(): nonlocal init if init: init = False aa.stop() aa.close() aa.deinit() else: app.exit(0) def timeout2(): print("Application timeout hit!") nonlocal init if init: init = False aa.stop() aa.close() aa.deinit() else: print("application exit!") app.exit(1) t2.timeout.connect(timeout2) t.timeout.connect(timeout) def state_changed(state): if state == FilterState.ACTIVE: t.setSingleShot(True) t.start(activeTime_s*1000) elif not init and state == FilterState.CONSTRUCTED: t.start(1000) aa.stateChanged.connect(state_changed) aa.init() aa.open() aa.start() app.exec_() finally: del t del t2 finally: logging.getLogger().removeHandler(collector) Services.removeAll() return collector.logs
def data(self, index, role): # pylint: disable=too-many-return-statements,too-many-branches """ Generic data query :param index: a QModelIndex instance :param role: the data role (see QAbstractItemModel) :return: """ if not index.isValid(): return None item = index.internalPointer().content if role == Qt.DisplayRole: if isinstance(item, str): return item if index.column() == 0 else None if isinstance(item, self.SubConfigContent): return item.subConfig.getName() if index.column( ) == 0 else None if isinstance(item, self.NodeContent): return item.name if index.column() == 0 else None if isinstance(item, self.PropertyContent): if index.column() == 0: return item.name p = item.property.getPropertyDetails(item.name) return p.handler.toViewValue( item.property.getProperty(item.name)) logger.warning("Unknown item %s", repr(item)) if role == Qt.DecorationRole: if index.column() != 0: return None if isinstance(item, str): if not index.parent().isValid(): return QIcon.fromTheme( "drive-harddisk", QApplication.style().standardIcon( QStyle.SP_DriveHDIcon)) if isinstance(item, self.SubConfigContent): if Configuration.configType( item.subConfig) == Configuration.CONFIG_TYPE_COMPOSITE: return QIcon.fromTheme( "repository", QApplication.style().standardIcon( QStyle.SP_DirLinkIcon)) if Configuration.configType( item.subConfig ) == Configuration.CONFIG_TYPE_APPLICATION: return QIcon.fromTheme( "folder", QApplication.style().standardIcon(QStyle.SP_DirIcon)) if isinstance(item, self.NodeContent): return QIcon.fromTheme( "unknown", QApplication.style().standardIcon(QStyle.SP_FileIcon)) if isinstance(item, self.PropertyContent): return None logger.warning("Unknown item %s", repr(item)) if role == Qt.FontRole: if index.column() != 0: return None if isinstance(item, self.SubConfigContent): if index.parent().row() == 1: font = QFont() if item.subConfig.getName() == self.activeApp: font.setBold(True) return font if role == Qt.ToolTipRole: if isinstance(item, self.PropertyContent): p = item.property.getPropertyDetails(item.name) return p.helpstr if role == ITEM_ROLE: return item return None
def startNexT(cfgfile, active, execScripts, execCode, withGui): """ Starts next with the given config file and activates the given application. :param cfgfile: path to config file :param active: active application (if None, the first application in the config will be used) :return: None """ logger.debug("Starting nexxT...") config = Configuration() lcl = QLocale.system() lcl.setNumberOptions(QLocale.c().numberOptions()) QLocale.setDefault(lcl) if withGui: app = QApplication() if QApplication.instance() is None else QApplication.instance() app.setWindowIcon(QIcon(":icons/nexxT.svg")) app.setOrganizationName("nexxT") app.setApplicationName("nexxT") setupGuiServices(config) else: app = QCoreApplication() if QCoreApplication.instance() is None else QCoreApplication.instance() app.setOrganizationName("nexxT") app.setApplicationName("nexxT") setupConsoleServices(config) if cfgfile is not None: ConfigFileLoader.load(config, cfgfile) if withGui: mainWindow = Services.getService("MainWindow") mainWindow.restoreState() mainWindow.show() # the reference will still be held by the service, but here we don't need it anymore del mainWindow if active is not None: config.activate(active) # pylint: disable=unused-variable # need to hold the reference of this until the method is called i2 = MethodInvoker(dict(object=Application, method="initialize", thread=app.thread()), MethodInvoker.IDLE_TASK) # pylint: disable=unused-variable waitForSignal(config.appActivated) if Application.activeApplication.getState() != FilterState.ACTIVE: waitForSignal(Application.activeApplication.stateChanged, lambda s: s == FilterState.ACTIVE) logger.info("done") def cleanup(): logger.debug("cleaning up loaded services") Services.removeAll() logger.debug("cleaning up loaded plugins") for v in ("last_traceback", "last_type", "last_value"): if hasattr(sys, v): del sys.__dict__[v] #PluginManager.singleton().unloadAll() logger.debug("cleaning up complete") code_globals = {} for c in execCode: logger.info("Executing code '%s'", c) # note that exec is used intentionally here to provide the user with scripting posibilities exec(compile(c, "<string>", 'exec'), code_globals) # pylint: disable=exec-used logger.debug("Executing code done") for s in execScripts: logger.info("Executing script '%s'", s) with open(s) as fscript: # note that exec is used intentionally here to provide the user with scripting possibilities exec(compile(fscript.read(), s, 'exec'), code_globals) # pylint: disable=exec-used logger.debug("Executing script done") res = app.exec_() logger.debug("closing config") config.close() cleanup() logger.internal("app.exec_ returned") return res
def simple_setup(sourceFreq, activeTime_s): t = QTimer() t.setSingleShot(True) # timeout if test case hangs t2 = QTimer() t2.start((activeTime_s + 3)*1000) try: config = Configuration() cf_inner = CompositeFilter("cf_inner", config) cg_inner = cf_inner.getGraph() f1 = cg_inner.addNode("pyfile://" + os.path.dirname(__file__) + "/../interface/SimpleStaticFilter.py", "SimpleStaticFilter") cg_inner.addDynamicOutputPort("CompositeInput", "compositeIn") cg_inner.addDynamicInputPort("CompositeOutput", "compositeOut") app.processEvents() cg_inner.addConnection("CompositeInput", "compositeIn", f1, "inPort") cg_inner.addConnection(f1, "outPort", "CompositeOutput", "compositeOut") cf = CompositeFilter("cf", config) cg = cf.getGraph() f1 = cg.addNode("pyfile://" + os.path.dirname(__file__) + "/../interface/SimpleStaticFilter.py", "SimpleStaticFilter") f2 = cg.addNode(cf_inner, "compositeNode") app.processEvents() cg.addDynamicOutputPort("CompositeInput", "compositeIn") cg.addDynamicInputPort("CompositeOutput", "compositeOut") app.processEvents() cg.addConnection("CompositeInput", "compositeIn", f1, "inPort") cg.addConnection(f1, "outPort", f2, "compositeIn") cg.addConnection(f2, "compositeOut", "CompositeOutput", "compositeOut") expect_exception(CompositeRecursion, cg.addNode, cf, "compositeNode") expect_exception(CompositeRecursion, cg_inner.addNode, cf, "compositeNode") a = Application("app", config) ag = a.getGraph() cn = ag.addNode(cf, "compositeNode") app.processEvents() app.processEvents() cn_ip = [p.name() for p in ag.getMockup(cn).getAllInputPorts()] cn_op = [p.name() for p in ag.getMockup(cn).getAllOutputPorts()] assert cn_ip == ["compositeIn"] assert cn_op == ["compositeOut"] sn = ag.addNode("pyfile://" + os.path.dirname(__file__) + "/../interface/SimpleStaticFilter.py", "SimpleSource") p = ag.getMockup(sn).propertyCollection() p.setProperty("frequency", sourceFreq) ag.addConnection(sn, "outPort", cn, "compositeIn") fn = ag.addNode("pyfile://" + os.path.dirname(__file__) + "/../interface/SimpleStaticFilter.py", "SimpleStaticFilter") ag.addConnection(cn, "compositeOut", fn, "inPort") cg.renameDynamicInputPort("CompositeOutput", "compositeOut", "renamedOut") app.processEvents() cg.renameDynamicOutputPort("CompositeInput", "compositeIn", "renamedIn") app.processEvents() aa = ActiveApplication(ag) init = True def timeout(): nonlocal init if init: init = False aa.stop() aa.close() aa.deinit() else: app.exit(0) def timeout2(): print("Application timeout hit!") nonlocal init if init: init = False aa.stop() aa.close() aa.deinit() else: app.exit(1) t2.timeout.connect(timeout2) t.timeout.connect(timeout) events = [] def logger(object, function, datasample): nonlocal events events.append(dict(object=object, function=function, datasample=datasample, time=time.time())) def state_changed(state): if state == FilterState.ACTIVE: t.setSingleShot(True) t.start(activeTime_s*1000) elif not init and state == FilterState.CONSTRUCTED: t.start(1000) aa.stateChanged.connect(state_changed) t1 = aa._filters2threads["/SimpleSource"] f1 = aa._threads[t1]._filters["/SimpleSource"].getPlugin() f1.beforeTransmit = lambda ds: logger(object="SimpleSource", function="beforeTransmit", datasample=ds) f1.afterTransmit = lambda: logger(object="SimpleSource", function="afterTransmit", datasample=None) t2 = aa._filters2threads["/SimpleStaticFilter"] f2 = aa._threads[t2]._filters["/SimpleStaticFilter"].getPlugin() f2.afterReceive = lambda ds: logger(object="SimpleStaticFilter", function="afterReceive", datasample=ds) f2.beforeTransmit = lambda ds: logger(object="SimpleStaticFilter", function="beforeTransmit", datasample=ds) f2.afterTransmit = lambda: logger(object="SimpleStaticFilter", function="afterTransmit", datasample=None) aa.init() aa.open() aa.start() app.exec_() return events finally: del t del t2
def simple_setup(activeTime_s): t = QTimer() t.setSingleShot(True) # timeout if test case hangs t2 = QTimer() t2.start((activeTime_s + 3) * 1000) try: if nexxT.useCImpl: test_json = Path(__file__).parent / "test2.json" else: test_json = Path(__file__).parent / "test1.json" config = Configuration() ConfigFileLoader.load(config, test_json) # we don't have a save as feature yet, so this function is throwing an exception atm expect_exception(ConfigFileLoader.save, config, test_json.parent / "test1.saved.json") config.activate("testApp") app.processEvents() aa = Application.activeApplication init = True def timeout(): nonlocal init if init: init = False aa.stop() aa.close() aa.deinit() else: app.exit(0) #logging.INTERNAL = INTERNAL def timeout2(): print("Application timeout hit!") nonlocal init if init: init = False aa.stop() aa.close() aa.deinit() else: app.exit(1) t2.timeout.connect(timeout2) t.timeout.connect(timeout) def state_changed(state): if state == FilterState.ACTIVE: t.setSingleShot(True) t.start(activeTime_s * 1000) elif not init and state == FilterState.CONSTRUCTED: t.start(1000) aa.stateChanged.connect(state_changed) aa.init() aa.open() aa.start() app.exec_() finally: del t del t2