Skip to content

Commit

Permalink
Merge pull request #60 from ifm/develop
Browse files Browse the repository at this point in the history
Release 1.1.0
  • Loading branch information
cwiede authored Mar 21, 2024
2 parents 27b6908 + ce142f2 commit 615fe62
Show file tree
Hide file tree
Showing 46 changed files with 3,674 additions and 232 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ __pycache__/
*.dll
binary/

# installed include files
include/

# scons
.sconsign.dblite
workspace/build
Expand Down
26 changes: 22 additions & 4 deletions nexxT/core/ActiveApplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from nexxT.core.CompositeFilter import CompositeFilter
from nexxT.core.Utils import Barrier, assertMainThread, mainThread, MethodInvoker
from nexxT.core.Thread import NexTThread
from nexxT.core.PropertyCollectionImpl import PropertyCollectionProxy
from nexxT.core.Variables import Variables

logger = logging.getLogger(__name__) # pylint: disable=invalid-name

Expand All @@ -28,6 +30,8 @@ class ActiveApplication(QObject):
stateChanged = Signal(int) # Signal is emitted after the state of the graph has been changed
aboutToClose = Signal() # Signal is emitted before stop operation takes place

singleThreaded = False

def __init__(self, graph):
super().__init__()
assertMainThread()
Expand Down Expand Up @@ -59,29 +63,43 @@ def getApplication(self):
"""
return self._graph.getSubConfig()

def _traverseAndSetup(self, graph, namePrefix=""):
def _traverseAndSetup(self, graph, namePrefix="", variables=None):
"""
Recursively create threads and add the filter mockups to them
"""
if variables is None:
variables = graph.getSubConfig().getConfiguration().propertyCollection().getVariables()
for basename in graph.allNodes():
filtername = namePrefix + "/" + basename
mockup = graph.getMockup(basename)
if issubclass(mockup.getPluginClass(), CompositeFilter.CompositeNode):
with mockup.createFilter() as cf:
self._composite2graphs[filtername] = cf.getPlugin().getGraph()
self._traverseAndSetup(cf.getPlugin().getGraph(), filtername)
compositeVars = mockup.getPropertyCollectionImpl().getVariables().copyAndReparent(variables)
self._traverseAndSetup(cf.getPlugin().getGraph(), filtername, compositeVars)
elif issubclass(mockup.getPluginClass(), CompositeFilter.CompositeInputNode):
pass
elif issubclass(mockup.getPluginClass(), CompositeFilter.CompositeOutputNode):
pass
else:
props = mockup.getPropertyCollectionImpl()
filterVars = Variables(parent=variables if variables is not None else props.getVariables())
filterVars.setObjectName("proxy:" + filtername)
filterVars["COMPOSITENAME"] = namePrefix if namePrefix != "" else "<root>"
filterVars["FILTERNAME"] = basename
filterVars["FULLQUALIFIEDFILTERNAME"] = filtername
filterVars["APPNAME"] = self._graph.getSubConfig().getName()
filterVars.setReadonly(["COMPOSITENAME", "FILTERNAME", "FULLQUALIFIEDFILTERNAME", "APPNAME"])
props = PropertyCollectionProxy(props, filterVars)
nexTprops = props.getChildCollection("_nexxT")
threadName = nexTprops.getProperty("thread")
if not threadName in self._threads:
threadName = props.getVariables().subst(threadName)
if self.singleThreaded:
threadName = "main"
if threadName not in self._threads:
# create threads as needed
self._threads[threadName] = NexTThread(threadName)
self._threads[threadName].addMockup(filtername, mockup)
self._threads[threadName].addMockup(filtername, mockup, props)
self._filters2threads[filtername] = threadName

def __del__(self):
Expand Down
37 changes: 29 additions & 8 deletions nexxT/core/AppConsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from nexxT.core.ConfigFiles import ConfigFileLoader
from nexxT.core.Configuration import Configuration
from nexxT.core.Application import Application
from nexxT.core.ActiveApplication import ActiveApplication
from nexxT.core.PluginManager import PythonLibrary
# this import is needed for initializing the nexxT qt resources
import nexxT.core.qrc_resources # pylint: disable=unused-import
from nexxT.interface import Services, FilterState
Expand All @@ -30,7 +32,7 @@
from nexxT.services.SrvConfiguration import MVCConfigurationBase
from nexxT.services.SrvPlaybackControl import PlaybackControlConsole
from nexxT.services.SrvRecordingControl import MVCRecordingControlBase
from nexxT.services.SrvProfiling import ProfilingService
from nexxT.services.SrvProfiling import ProfilingServiceDummy
from nexxT.services.gui.GuiLogger import GuiLogger
from nexxT.services.gui.MainWindow import MainWindow
from nexxT.services.gui.Configuration import MVCConfigurationGUI
Expand All @@ -50,8 +52,9 @@ def setupConsoleServices(config):
Services.addService("PlaybackControl", PlaybackControlConsole(config))
Services.addService("RecordingControl", MVCRecordingControlBase(config))
Services.addService("Configuration", MVCConfigurationBase(config))
Services.addService("Profiling", ProfilingServiceDummy())

def setupGuiServices(config):
def setupGuiServices(config, disableProfiling=False):
"""
Adds services available in console mode.
:param config: a nexxT.core.Configuration instance
Expand All @@ -63,9 +66,13 @@ def setupGuiServices(config):
Services.addService("PlaybackControl", MVCPlaybackControlGUI(config))
Services.addService("RecordingControl", MVCRecordingControlGUI(config))
Services.addService("Configuration", MVCConfigurationGUI(config))
Services.addService("Profiling", Profiling())
if not disableProfiling:
Services.addService("Profiling", Profiling())
else:
Services.addService("Profiling", ProfilingServiceDummy())

def startNexT(cfgfile, active, execScripts, execCode, withGui):
def startNexT(cfgfile, active, execScripts, execCode, withGui, singleThreaded=False, disableUnloadHeuristic=False,
disableProfiling=False):
"""
Starts next with the given config file and activates the given application.
:param cfgfile: path to config file
Expand All @@ -75,18 +82,23 @@ def startNexT(cfgfile, active, execScripts, execCode, withGui):
logger.debug("Starting nexxT...")
config = Configuration()
QLocale.setDefault(QLocale.c())

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)
setupGuiServices(config, disableProfiling=disableProfiling)
else:
app = QCoreApplication() if QCoreApplication.instance() is None else QCoreApplication.instance()
app.setOrganizationName("nexxT")
app.setApplicationName("nexxT")
setupConsoleServices(config)

ActiveApplication.singleThreaded = singleThreaded
PythonLibrary.disableUnloadHeuristic = disableUnloadHeuristic


if cfgfile is not None:
ConfigFileLoader.load(config, cfgfile)
if withGui:
Expand Down Expand Up @@ -164,18 +176,25 @@ def main(withGui):
""")
parser.add_argument("cfg", nargs='?', help=".json configuration file of the project to be loaded.")
parser.add_argument("-a", "--active", default=None, type=str,
help="active application; default: first application in config file")
help="active application; default: first application in config file.")
parser.add_argument("-l", "--logfile", default=None, type=str,
help="log file location (.db extension will use sqlite).")
parser.add_argument("-v", "--verbosity", default="INFO",
choices=["INTERNAL", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "CRITICAL"],
help="sets the log verbosity")
parser.add_argument("-q", "--quiet", action="store_true", default=False, help="disble logging to stderr")
parser.add_argument("-q", "--quiet", action="store_true", default=False, help="disble logging to stderr.")
parser.add_argument("-e", "--execpython", action="append", default=[],
help="execute arbitrary python code given in a string before actually starting the "
"application.")
parser.add_argument("-s", "--execscript", action="append", default=[],
help="execute arbitrary python code given in a file before actually starting the application.")
parser.add_argument("-t", "--single-threaded", action="store_true", default=False,
help="force using only the main thread")
parser.add_argument("-u", "--disable-unload-heuristic", action="store_true", default=False,
help="disable unload heuristic for python modules.")
parser.add_argument("-np", "--no-profiling", action="store_true",
help="disable profiling support (only relevant for GUI).")

def str2bool(value):
if isinstance(value, bool):
return value
Expand Down Expand Up @@ -204,7 +223,9 @@ def str2bool(value):
handler = logging.FileHandler(args.logfile)
handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s"))
nexT_logger.addHandler(handler)
startNexT(args.cfg, args.active, args.execscript, args.execpython, withGui=args.gui)
startNexT(args.cfg, args.active, args.execscript, args.execpython, withGui=args.gui,
singleThreaded=args.single_threaded, disableUnloadHeuristic=args.disable_unload_heuristic,
disableProfiling=args.no_profiling)

def mainConsole():
"""
Expand Down
2 changes: 1 addition & 1 deletion nexxT/core/BaseGraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def renameNode(self, oldName, newName):
self._connections[i] = c
p = self._connectionProps[oldConn]
del self._connectionProps[oldConn]
self._connectionProps[c] = p
self._connectionProps[c] = p
self.nodeRenamed.emit(oldName, newName)
self.dirtyChanged.emit()

Expand Down
1 change: 1 addition & 0 deletions nexxT/core/CompositeFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def __init__(self, name, configuration):
def compositeNode(self, env):
"""
Factory function for creating a dummy filter instance (this one will never get active).
:param env: the FilterEnvironment instance
:return: a Filter instance
"""
Expand Down
32 changes: 30 additions & 2 deletions nexxT/core/ConfigFileSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,29 @@
"type": "object",
"propertyNames": { "$ref": "#/definitions/identifier" },
"patternProperties": {
"^.*$": {"type": ["string", "number", "boolean"]}
"^.*$": {
"anyOf": [
{"type": "string"}, {"type": "number"}, {"type": "boolean"},
{
"type": "object",
"additionalProperties": false,
"required": ["value", "subst"],
"properties": {
"value": {"anyOf": [{"type": "string"}, {"type": "number"}, {"type": "boolean"}]},
"subst": {"type": "boolean"}
}
}
]
}
}
},
"variables": {
"type": "object",
"propertyNames": {"$ref": "#/definitions/identifier"},
"patternProperties": {
"^.*$": {
"type": "string"
}
}
},
"sub_graph": {
Expand Down Expand Up @@ -58,7 +80,7 @@
"type": "string"
},
"thread": {
"$ref": "#/definitions/identifier",
"type": "string",
"default": "main"
},
"dynamicInputPorts": {
Expand All @@ -80,6 +102,9 @@
"properties": {
"$ref": "#/definitions/propertySection",
"default": {}
},
"variables": {
"$ref": "#/definitions/variables"
}
}
}
Expand Down Expand Up @@ -110,6 +135,9 @@
"$ref": "#/definitions/sub_graph"
}
},
"variables": {
"$ref": "#/definitions/variables"
},
"_guiState": {
"$ref": "#/definitions/propertySection",
"default": {}
Expand Down
Loading

0 comments on commit 615fe62

Please sign in to comment.