Example #1
0
 def load(self, cfg, compositeLookup):
     """
     load graph from config dictionary (inverse operation of save(...))
     :param cfg: dictionary loaded from json file
     :return: None
     """
     # apply subconfig gui state
     if "_guiState" in cfg and len(cfg["_guiState"]) > 0:
         guistateCC = self._propertyCollection.getChildCollection(
             "_guiState")
         for k in cfg["_guiState"]:
             PropertyCollectionImpl(k, guistateCC, cfg["_guiState"][k])
     for n in cfg["nodes"]:
         if not n["library"].startswith("composite://"):
             p = PropertyCollectionImpl(n["name"], self._propertyCollection,
                                        n["properties"])
             # apply node gui state
             nextP = PropertyCollectionImpl("_nexxT", p,
                                            {"thread": n["thread"]})
             logger.debug("loading: subconfig %s / node %s -> thread: %s",
                          self._name, n["name"], n["thread"])
             tmp = self._graph.addNode(n["library"],
                                       n["factoryFunction"],
                                       suggestedName=n["name"])
             if tmp != n["name"]:
                 raise NexTInternalError(
                     "addNode(...) has set unexpected name for node.")
         else:
             # composite node handling
             if n["library"] == "composite://port":
                 # the special nodes are already there, nothing to do here
                 pass
             elif n["library"] == "composite://ref":
                 name = n["factoryFunction"]
                 cf = compositeLookup(name)
                 tmp = self._graph.addNode(cf,
                                           "compositeNode",
                                           suggestedName=n["name"])
                 if tmp != n["name"]:
                     raise NexTInternalError(
                         "addNode(...) has set unexpected name for node.")
         for dip in n["dynamicInputPorts"]:
             self._graph.addDynamicInputPort(n["name"], dip)
         for dop in n["dynamicOutputPorts"]:
             self._graph.addDynamicOutputPort(n["name"], dop)
         # make sure that the filter is instantiated and the port information is updated immediately
         self._graph.getMockup(n["name"]).createFilterAndUpdate()
     for c in cfg["connections"]:
         contuple = self.connectionStringToTuple(c)
         self._graph.addConnection(*contuple)
Example #2
0
 def __init__(self, name):
     """
     Creates a NexTThread instance with a name. If this is not the main thread, create a corresponding
     QThread and start it (i.e., the event loop).
     :param name: name of the thread
     """
     super().__init__()
     self._filters = {}
     self._filter2name = {}
     self._mockups = {}
     self._name = name
     try:
         self._profsrv = Services.getService("Profiling")
         if hasattr(self._profsrv, "data") and self._profsrv.data() is None:
             self._profsrv = None
     except KeyError:
         self._profsrv = None
     if not self.thread() is QCoreApplication.instance().thread():
         raise NexTInternalError("unexpected thread")
     if name == "main":
         self._qthread = QCoreApplication.instance().thread()
         self._qthread.setObjectName(name)
     else:
         self._qthread = self.ThreadWithCoverage(parent=self)
         self._qthread.setObjectName(name)
         self._qthread.start()
     self.moveToThread(self._qthread)
     self.cleanUpCalled = False
Example #3
0
 def preStateTransition(self, operation):
     """
     State transitions might be explicitely set all filters to the operation state before executing the
     operation on the filters. This method makes sure that the state transitions are sane.
     :param operation: The FilterState operation.
     :return: None
     """
     logger.internal("Performing pre-state transition: %s", FilterState.state2str(operation))
     self._assertMyThread()
     if self.getPlugin() is None or (useCImpl and self.getPlugin().data() is None):
         raise NexTInternalError("Cannot perform state transitions on uninitialized plugin")
     operations = {
         FilterState.CONSTRUCTING: (None, FilterState.CONSTRUCTED, None),
         FilterState.INITIALIZING: (FilterState.CONSTRUCTED, FilterState.INITIALIZED, self.getPlugin().onInit),
         FilterState.OPENING: (FilterState.INITIALIZED, FilterState.OPENED, self.getPlugin().onOpen),
         FilterState.STARTING: (FilterState.OPENED, FilterState.ACTIVE, self.getPlugin().onStart),
         FilterState.STOPPING: (FilterState.ACTIVE, FilterState.OPENED, self.getPlugin().onStop),
         FilterState.CLOSING: (FilterState.OPENED, FilterState.INITIALIZED, self.getPlugin().onClose),
         FilterState.DEINITIALIZING: (FilterState.INITIALIZED, FilterState.CONSTRUCTED, self.getPlugin().onDeinit),
         FilterState.DESTRUCTING: (FilterState.CONSTRUCTED, None, None),
     }
     fromState, toState, function = operations[operation]
     if self._state != fromState:
         raise FilterStateMachineError(self._state, operation)
     self._state = operation
Example #4
0
def assertMainThread():
    """
    assert that function is called in main thread, otherwise, a NexTInternalError is raised
    :return: None
    """
    if not isMainThread():
        raise NexTInternalError("Non thread-safe function is called in unexpected thread.")
Example #5
0
def waitForSignal(signal, callback=None, timeout=None):
    """
    Waits for the given signal. If a callback is given, it will be called with the signal's arguments until the
    return value of the callback evaluates to true. If a timeout is given (in seconds), a TimeoutError will be
    thrown after the time has elapsed.
    :param signal: a Qt signal to be waited for, suitable for slot connections.
    :param callback: a callable called
    :param timeout: an optional timeout in seconds.
    :return: None
    """
    _received = False
    _sigArgs = None
    def _slot(*args, **kw):
        nonlocal _received, _sigArgs
        _sigArgs = args
        if callback is None:
            _received = True
        else:
            if callback(*args, **kw):
                _received = True
    if not signal.connect(_slot, Qt.QueuedConnection):
        raise NexTInternalError("cannot connect the signal.")
    t0 = time.perf_counter()
    while not _received:
        QCoreApplication.processEvents()
        if timeout is not None and time.perf_counter() - t0 > timeout:
            signal.disconnect(_slot)
            raise TimeoutError()
    signal.disconnect(_slot)
    return _sigArgs
 def applyLoadedConfig(self, loadedFromConfig):
     """
     applies the loaded configuration after the instance has been already created. This is used for guiState items.
     :param loadedFromConfig: dictionary loaded from json file
     :return: None
     """
     if len(self._loadedFromConfig) > 0:
         raise NexTInternalError("Expected that no loaded config is present.")
     self._accessed = False
     self._loadedFromConfig = loadedFromConfig
 def __init__(self, name, parentPropColl, loadedFromConfig=None):
     PropertyCollection.__init__(self)
     assertMainThread()
     self._properties = {}
     self._accessed = False # if no access to properties has been made, we stick with configs from config file.
     self._loadedFromConfig = loadedFromConfig if loadedFromConfig is not None else {}
     self._propertyMutex = QMutex(QMutex.Recursive)
     if parentPropColl is not None:
         if not isinstance(parentPropColl, PropertyCollectionImpl):
             raise NexTInternalError("parentPropColl should always be a property collection instance but it isn't")
         parentPropColl.addChild(name, self)
Example #8
0
 def subConfigByNameAndTye(self, name, typeid):
     """
     Return the subconfiguration with the given name and type
     :param name: a string
     :param typeid: either CONFIG_TYPE_APPLICATION or CONFIG_TYPE_COMPOSITE
     :return: a SubConfiguration instance
     """
     if typeid == self.CONFIG_TYPE_APPLICATION:
         return self.applicationByName(name)
     if typeid == self.CONFIG_TYPE_COMPOSITE:
         return self.compositeFilterByName(name)
     raise NexTInternalError("unknown typeid %s" % typeid)
Example #9
0
 def applicationByName(self, name):
     """
     Search for the application with the given name
     :param name: a string
     :return: an Application instance
     """
     match = [app for app in self._applications if app.getName() == name]
     if len(match) == 1:
         return match[0]
     if len(match) == 0:
         raise NodeNotFoundError(name)
     raise NexTInternalError("non unique name %s" % name)
Example #10
0
 def compositeFilterByName(self, name):
     """
     Search for the composite filter with the given name
     :param name: a string
     :return: a CompositeFilter instance
     """
     match = [cf for cf in self._compositeFilters if cf.getName() == name]
     if len(match) == 1:
         return match[0]
     if len(match) == 0:
         raise NodeNotFoundError(name)
     raise NexTInternalError("non unique name %s" % name)
Example #11
0
 def _receiveSync(self, dataSample):
     """
     Called from framework only and implements the synchronous receive mechanism.
     :param dataSample: the transmitted DataSample instance
     :return: None
     """
     if not QThread.currentThread() is self.thread():
         raise NexTInternalError(
             "InputPort.receiveSync has been called from an unexpected thread."
         )
     self._addToQueue(dataSample)
     self._transmit()
Example #12
0
 def adaptLibAndFactory(lib, factory):
     if not isinstance(lib, str):
         if factory in ["CompositeInputNode", "CompositeOutputNode"]:
             ncfg["library"] = "composite://port"
             ncfg["factoryFunction"] = factory[:-len("Node")]
         elif factory in ["compositeNode"]:
             ncfg["library"] = "composite://ref"
             ncfg["factoryFunction"] = lib.getName()
         else:
             raise NexTInternalError("Unexpected factory function '%s'" % factory)
     else:
         ncfg["library"] = lib
         ncfg["factoryFunction"] = factory
     return lib, factory
Example #13
0
 def __init__(self, name, configuration):
     super().__init__(name, configuration)
     self._configuration = configuration
     _compositeInputNode = self._graph.addNode(CompositeFilter,
                                               "CompositeInputNode",
                                               "CompositeInput")
     _compositeOutputNode = self._graph.addNode(CompositeFilter,
                                                "CompositeOutputNode",
                                                "CompositeOutput")
     if _compositeInputNode != "CompositeInput" or _compositeOutputNode != "CompositeOutput":
         raise NexTInternalError("unexpected node names.")
     # prevent renaming and deletion of these special nodes
     self._graph.protect("CompositeInput")
     self._graph.protect("CompositeOutput")
     configuration.addComposite(self)
Example #14
0
 def shutdown(self):
     """
     Transfer graph to DESTRUCTED state.
     :return: None
     """
     assertMainThread()
     if self._state == FilterState.ACTIVE:
         self.stop()
     # while this is similar to code in FilterEnvironment, the lines here refer to applications
     # and the lines in FilterEnvironment refer to filters.
     if self._state == FilterState.OPENED:
         self.close()
     if self._state == FilterState.INITIALIZED:
         self.deinit()
     if self._state == FilterState.CONSTRUCTED:
         self.destruct()
     if not self._state == FilterState.DESTRUCTED:
         raise NexTInternalError("Unexpected state '%s' after shutdown." %
                                 FilterState.state2str(self._state))
Example #15
0
 def _stateTransition(self, operation):
     """
     Perform state transition according to operation.
     :param operation: The FilterState operation.
     :return: None
     """
     logger.internal("Performing state transition: %s", FilterState.state2str(operation))
     self._assertMyThread()
     if self.getPlugin() is None or (useCImpl and self.getPlugin().data() is None):
         raise NexTInternalError("Cannot perform state transitions on uninitialized plugin")
     operations = {
         FilterState.CONSTRUCTING: (None, FilterState.CONSTRUCTED, None),
         FilterState.INITIALIZING: (FilterState.CONSTRUCTED, FilterState.INITIALIZED, self.getPlugin().onInit),
         FilterState.OPENING: (FilterState.INITIALIZED, FilterState.OPENED, self.getPlugin().onOpen),
         FilterState.STARTING: (FilterState.OPENED, FilterState.ACTIVE, self.getPlugin().onStart),
         FilterState.STOPPING: (FilterState.ACTIVE, FilterState.OPENED, self.getPlugin().onStop),
         FilterState.CLOSING: (FilterState.OPENED, FilterState.INITIALIZED, self.getPlugin().onClose),
         FilterState.DEINITIALIZING: (FilterState.INITIALIZED, FilterState.CONSTRUCTED, self.getPlugin().onDeinit),
         FilterState.DESTRUCTING: (FilterState.CONSTRUCTED, None, None),
     }
     fromState, toState, function = operations[operation]
     # filters must be either in fromState or already in operation state (if preStateTransition has been used)
     if self._state not in (fromState, operation):
         raise FilterStateMachineError(self._state, operation)
     self._state = operation
     try:
         function()
     except Exception as e: # pylint: disable=broad-except
         # What should be done on errors?
         #    1. inhibit state transition to higher state
         #         pro: prevent activation of not properly intialized filter
         #         con: some actions of onInit might already be executed, we really want to call onDeinit for cleanup
         #    2. ignore the exception and perform state transition anyways
         #         pro/con is inverse to 1
         #    3. introduce an error state
         #         pro: filters in error state are clearly identifyable and prevented from being used
         #         con: higher complexity, cleanup issues, ...
         #    --> for now we use 2.
         self._state = fromState
         logger.exception("Exception while executing operation %s of filter %s",
                          FilterState.state2str(operation),
                          self.propertyCollection().objectName())
     self._state = toState
Example #16
0
 def _receiveAsync(self, dataSample, semaphore):
     """
     Called from framework only and implements the asynchronous receive mechanism using a semaphore.
     :param dataSample: the transmitted DataSample instance
     :param semaphore: a QSemaphore instance
     :return: None
     """
     if not QThread.currentThread() is self.thread():
         raise NexTInternalError(
             "InputPort.receiveAsync has been called from an unexpected thread."
         )
     self._addToQueue(dataSample)
     if not self._interthreadDynamicQueue:
         # usual behaviour
         semaphore.release(1)
         self._transmit()
     else:
         if semaphore not in self._semaphoreN:
             self._semaphoreN[semaphore] = 1
         delta = self._semaphoreN[semaphore] - len(self.queue)
         if delta <= 0:
             # the semaphore's N is too small
             semaphore.release(1 - delta)
             self._semaphoreN[semaphore] += -delta
             logger.internal("delta = %d: semaphoreN = %d", delta,
                             self._semaphoreN[semaphore])
             self._transmit()
         elif delta > 0:
             # first acquire is done by caller
             self._semaphoreN[semaphore] -= 1
             # the semaphore's N is too large, try acquires to reduce the size
             for i in range(1, delta):
                 if semaphore.tryAcquire(1):
                     self._semaphoreN[semaphore] -= 1
                 else:
                     break
             logger.internal("delta = %d: semaphoreN = %d", delta,
                             self._semaphoreN[semaphore])
             self._transmit()