nexxT.interface package

This __init__.py generates shortcuts for exported classes

class nexxT.interface.DataSample(content, datatype, timestamp)[source]

Bases: object

Note

Import this class with from nexxT.interface import DataSample.

This class is used for storing a data sample of the nexxT framework. For most generic usage, a QByteArray is used for the storage. This means that deserialization has to be performed on every usage and data generators need to serialize the data. Assumes that serializing / deserializing are efficient operations.

DataSample instances additionally have a type, which is a string and it should uniquely define the serialization method. Last but not least, an integer timestamp is stored for all DataSample instances.

Note

Usually, nexxT is using the wrapped C++ class instead of the python version. In python there are no differences between the wrapped C++ class and this python class. The C++ interface is defined in nexxT::DataSample

TIMESTAMP_RES = 1e-06

the resolution of the timestamps

__init__(content, datatype, timestamp)[source]

Create a new data sample instance.

Parameters:
  • content – A QByteArray instance containing the (serialized) content

  • datatype – A string instance which uniquely defines the serialized content

  • timestamp – An integer representing the sample’s time stamp [µs]

static copy(src)[source]

Create a copy of this DataSample instance

Parameters:

src – the instance to be copied

Returns:

the cloned data sample

static currentTime()[source]

Returns the current system time suitable for data sample timestamps. Note: The python implementation uses time.time_ns, which unfortunately has limited accuracy under windows (16 ms).

Returns:

an integer instance

getContent()[source]

Get the contents of this sample as a QByteArray. Note that this is an efficient operation due to the copy on write semantics of QByteArray. It also asserts that the original contents cannot be modified.

In C++, make sure to keep an instance of the QByteArray until done with processing. Moreover, consider to use QByteArray::constData() for a pointer-to-memory access rather than QByteArray::data(), since the latter will eventually make an unnecessary deep copy of the encapsulated data.

Returns:

QByteArray instance copy

getDatatype()[source]

Return the data type.

Returns:

data type string

getTimestamp()[source]

Return the timestamp associated to the data.

Returns:

integer timestamp

class nexxT.interface.Filter(dynInPortsSupported, dynOutPortsSupported, environment)[source]

Bases: QObject

Note

Import this class with from nexxT.interface import Filter.

This class is the base class for defining a nexxT filter. A minimal nexxT filter class looks like this:

class SimpleStaticFilter(Filter):

    def __init__(self, environment):
        super().__init__(False, False, environment)
        pc = self.propertyCollection()
        self.sample_property = pc.getProperty("sample_property", 0.1, "a property for demonstration purpose")
        self.inPort = self.addStaticInputPort("inPort")
        self.outPort = self.addStaticOutputPort("outPort")

    def onPortDataChanged(self, inputPort):
        dataSample = inputPort.getData()
        newSample = DataSample.copy(dataSample)
        self.outPort.transmit(dataSample)

The constructor of classes derived from nexxT.interface.Filter must have a single argument environment which is passed through to this base class. It configures dynamic port usage with the two boolean flags. In the constructor, the filter can define and query properties and create static ports.

The onPortDataChanged is called whenever new data arrives on an input port. In the example above, a copy of the original data sample is returned.

Note

Usually, nexxT is using the wrapped C++ class instead of the python version. In python there are no differences between the wrapped C++ class and this python class. The C++ interface is defined in nexxT::Filter

__init__(dynInPortsSupported, dynOutPortsSupported, environment)[source]

Filter Constructor.

Parameters:
  • dynInPortsSupported – Flag whether this filter supports dynamic input ports

  • dynOutPortsSupported – Flag whether this filter supports dynamic output ports

  • environment – FilterEnvironment instance which shall be passed through from the filter constructor.

addStaticInputPort(name, queueSizeSamples=1, queueSizeSeconds=None)[source]

Shortcut for generating a static input port and adding it to the filter. See also nexxT.interface.Ports.InputPort()

Parameters:
  • name – The name of the input port

  • queueSizeSamples – The size of the input queue in samples

  • queueSizeSeconds – The size of the input queue in seconds

Returns:

the new port instance

addStaticOutputPort(name)[source]

Shortcut for generating a static output port and adding it to the filter. See also nexxT.interface.Ports.OutputPort()

Parameters:

name – The name of the output port

Returns:

the new port instance

addStaticPort(port)[source]

Register a static port for this filter. Only possible in CONSTRUCTING state.

Parameters:

port – InputPort or OutputPort instance

Returns:

None

environment()[source]

Returns the environment associated with this filter.

Returns:

a FilterEnvironment instance

getDynamicInputPorts()[source]

Get dynamic input ports of this filter. Only possible in and after INITIALIZING state.

Returns:

list of dynamic input ports

getDynamicOutputPorts()[source]

Get dynamic output ports of this filter. Only possible in and after INITIALIZING state.

Returns:

list of dynamic output ports

guiState()[source]

Return the gui state associated with this filter. Note: the gui state shall not be used for properties which are important for data transport, for these cases the propertyCollection() shall be used. Typical gui state variables are: the geometry of a user-managed window, the last directory path used in a file dialog, etc. The gui state might not be initialized during mockup-phase.

Returns:

PropertyCollection instance

onClose()[source]

This function can be overwritten for general de-initialization tasks (e.g. release resources needed to run the filter, close files, etc.). It is the opoosite to onOpen(…).

Returns:

None

onDeinit()[source]

This function can be overwritten for performing de-initialization tasks related to dynamic ports. It is the opposite to onInit(…)

Returns:

None

onInit()[source]

This function can be overwritten for performing initialization tasks related to dynamic ports.

Returns:

None

onOpen()[source]

This function can be overwritten for general initialization tasks (e.g. acquire resources needed to run the filter, open files, connecting to services etc.).

Returns:

onPortDataChanged(inputPort)[source]

This function can be overwritten to be notified when new data samples arrive at input ports. For each data sample arrived this function will be called exactly once.

Parameters:

inputPort – the port where the data arrived

Returns:

None

onStart()[source]

This function can be overwritten to reset internal filter state. It is called before loading a new sequence.

Returns:

None

onStop()[source]

Opposite of onStart.

Returns:

None

onSuggestDynamicPorts()[source]

Shall return the suggested dynamic ports of this filter. Prominent example is to return the streams contained in a HDF5 file. Note that it is safe to assume that the instance lives in the GUI thread, when this function is called from the nexxT framework.

Returns:

listOfInputPortNames, listOfOutputPortNames

propertyCollection()[source]

Return the property collection associated with this filter.

Returns:

PropertyCollection instance

removeStaticPort(port)[source]

Remove a static port of this filter. Only possible in CONSTRUCTING state.

Parameters:

port – InputPort or OutputPort instance

Returns:

None

staticMetaObject = PySide6.QtCore.QMetaObject("Filter" inherits "QObject": )
class nexxT.interface.FilterState[source]

Bases: object

Note

Import this class with from nexxT.interface import FilterState.

This class defines an enum for the filter states. For reference, the filter’s lifecycle state diagram is shown here:

../_images/nexxT-filterstates.svg
static state2str(state)[source]

converts a state integer to the corresponding string

Parameters:

state – the state integer

Returns:

string

class nexxT.interface.FilterSurrogate(dllUrls, name)[source]

Bases: object

Note

Import this class with from nexxT.interface import FilterSurrogate.

This class acts as a surrogate to reference a filter from a DLL/shared object plugin from within python. It’s main purpose is the ability to announce these filters using python entry points. For this, create an instance of this class in one of your modules and refer to it by a ‘nexxT.filters’ entry point. Example:

from distutils.core import setup
setup( # ...
    'nexxT.filters' : [
         'examples.framework.CameraGrabber = nexxT.examples:CameraGrabber',
    ])

The surrogate creation of CameraGrabber is performed in nexxT.examples:

# SPDX-License-Identifier: Apache-2.0
# Copyright (C) 2020 ifm electronic gmbh
#
# THE PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
#

"""
define FilterSurrogates for binary filters.
"""

from pathlib import Path
import os
from nexxT.interface import FilterSurrogate
if os.environ.get("READTHEDOCS", None) is None:
    from nexxT.Qt import QtMultimedia # needed to load corresponding DLL before loading the nexxT plugin

AviReader = FilterSurrogate(
    "binary://" + str((Path(__file__).parent.parent / "tests" /
                       "binary" / "${NEXXT_PLATFORM}" / "${NEXXT_VARIANT}" / "test_plugins").absolute()),
    "VideoPlaybackDevice"
)
"""
Filter surrogate for the VideoPlaybackDevice class which is defined in a packaged shared object "test_plugins".
"""

CameraGrabber = FilterSurrogate(
    "binary://" + str((Path(__file__).parent.parent / "tests" /
                       "binary" / "${NEXXT_PLATFORM}" / "${NEXXT_VARIANT}" / "test_plugins").absolute()),
    "CameraGrabber"
)
"""
Filter surrogate for the CameraGrabber class which is defined in a packaged shared object "test_plugins".
"""
__init__(dllUrls, name)[source]

Create a FilterSurrogate instance.

Parameters:
  • dllUrls – might be (1) a dictionary mapping variant names to URLs, variant names are usually “nonopt” and “release” or (2) a url string which will be mapped to the release variant Note that URLs for binary libraries (DLL’s or shared objects) are of the form “binary://<absolute-path-to-dll>”. The absolute path might contain variables like ${NEXXT_PLATFORM} or ${NEXXT_VARIANT}.

  • name – the name of the filter class or factory function

dllUrl(variant)[source]

returns the absolute path of the optimzed dll/shared object

Parameters:

variant – the variant for which the filter is needed, given as a string.

name()[source]

returns the name of the filter class

nexxT.interface.InputPort

alias of InputPortImpl

class nexxT.interface.InputPortInterface(dynamic, name, environment)[source]

Bases: Port

This abstract class defines the interface of an input port of a filter. In addition to the normal port attributes, there are two new attributes related to automatic buffering of input data samples. queueSizeSamples sets the maximum number of samples buffered (it can be None, if queueSizeSeconds is not None) queueSizeSeconds sets the maximum time of samples buffered (it can be None, if queueSizeSamples is not None) If both attributes are set, they are and-combined.

..note::

Usually nexxT is using a wrapped C++ class instead of this pure python version. In python there are no differences between the wrapped C++ class and this python class. The C++ interface is defined in nexxT::InputPortInterface

clone(newEnvironment)[source]

Return a copy of this port attached to a new environment.

Parameters:

newEnvironment – the new FilterEnvironment instance

Returns:

a new Port instance

getData(delaySamples=0, delaySeconds=None)[source]

Return a data sample stored in the queue (called by the filter).

Parameters:
  • delaySamples – 0 related the most actual sample, numbers > 0 relates to historic samples (None can be given if delaySeconds is not None)

  • delaySeconds – if not None, a delay of 0.0 is related to the current sample, positive numbers are related to historic samples (TODO specify the exact semantics of delaySeconds)

Returns:

DataSample instance

interthreadDynamicQueue()[source]

Return the interthread dynamic queue setting.

Returns:

a boolean

queueSizeSamples()[source]

return the current queueSize in samples

Returns:

an integer

queueSizeSeconds()[source]

return the current queueSize in seconds

Returns:

an integer

receiveAsync(dataSample, semaphore)[source]

Called from framework only and implements the asynchronous receive mechanism using a semaphore.

Parameters:
  • dataSample – the transmitted DataSample instance

  • semaphore – a QSemaphore instance

Returns:

None

receiveSync(dataSample)[source]

Called from framework only and implements the synchronous receive mechanism. TODO implement

Parameters:

dataSample – the transmitted DataSample instance

Returns:

None

setInterthreadDynamicQueue(enabled)[source]

If enabled is True, inter thread connections to this input port are dynamically queued for non-blocking behaviour.

This setting does not affect connections from within the same thread. This method can be called only during constructor or the onInit() method of a filter. The main use case is a recording filter where the QT signal/slot is allowed to buffer as many samples as allowed in the input port’s queue to prevent unwanted blocking behaviour.

Enabling this might cause a larger delay and might also consume a lot of memory.

Parameters:

enabled – whether the dynamic queuing feature is enabled or not.

Returns:

setQueueSize(queueSizeSamples, queueSizeSeconds)[source]

Set the queue size of this port.

Parameters:
  • queueSizeSamples – 0 related the most actual sample, numbers > 0 relates to historic samples (None can be given if delaySeconds is not None)

  • queueSizeSeconds – if not None, a delay of 0.0 is related to the current sample, positive numbers are related to historic samples

Returns:

staticMetaObject = PySide6.QtCore.QMetaObject("InputPortInterface" inherits "Port": )
nexxT.interface.OutputPort

alias of OutputPortImpl

class nexxT.interface.OutputPortInterface(dynamic, name, environment)[source]

Bases: Port

This abstract base class defines the interface of an output port of a filter.

..note::

Usually nexxT is using a wrapped C++ class instead of this pure python version. In python there are no differences between the wrapped C++ class and this python class. The C++ interface is defined in nexxT::OutputPortInterface

clone(newEnvironment)[source]

Return a copy of this port attached to a new environment.

Parameters:

newEnvironment – the new FilterEnvironment instance

Returns:

a new Port instance

setupDirectConnection(inputPort)

Setup a direct (intra-thread) connection between outputPort and inputPort Note: both instances must live in same thread!

Parameters:
  • outputPort – the output port instance to be connected

  • inputPort – the input port instance to be connected

Returns:

None

setupInterThreadConnection(inputPort, outputPortThread, width)

Setup an inter thread connection between outputPort and inputPort

Parameters:
  • outputPort – the output port instance to be connected

  • inputPort – the input port instance to be connected

  • outputPortThread – the QThread instance of the outputPort instance

  • width – the width of the connection in DataSamples (0: infinite)

Returns:

an InterThreadConnection instance which manages the connection (has to survive until connections is deleted)

staticMetaObject = PySide6.QtCore.QMetaObject("OutputPortInterface" inherits "Port": Methods:   #4 type=Signal, signature=transmitSample(PyObject), parameters=PyObject )
transmit(dataSample)[source]

transmit a data sample over this port

Parameters:

dataSample – sample to transmit

transmitSample
class nexxT.interface.Port(dynamic, name, environment)[source]

Bases: QObject

This class is the base class for ports. It is used mainly as structure, containing the 3 properties dynamic (boolean), name (str) and environment (a FilterEnvironment instance).

..note::

Usually nexxT is using a wrapped C++ class instead of this pure python version. In python there are no differences between the wrapped C++ class and this python class. The C++ interface is defined in nexxT::Port

INPUT_PORT = 0
OUTPUT_PORT = 1
__init__(dynamic, name, environment)[source]

Constructor.

Parameters:
  • dynamic – boolean whether this is a dynamic port or not

  • name – the port name, given as a string

  • environment – the corresponding FilterEnvironment instance

clone(newEnvironment)[source]

This function must be overwritten in inherited classes to create a clone of this port attached to a different environment.

Parameters:

newEnvironment – the new FilterEnvironment instance

Returns:

a new Port instance

dynamic()[source]

Returns whether this is a dynamic port

Returns:

a boolean

environment()[source]

Returns the environment instance managing this port

Returns:

FilterEnvironment instance

isInput()[source]

Returns true if this is an input port

Returns:

bool

isOutput()[source]

Returns true if this is an output port

Returns:

bool

name()[source]

Returns the port name

Returns:

a string

setName(name)[source]

Sets the port name

Parameters:

name – the port name given as a string

Returns:

None

staticMetaObject = PySide6.QtCore.QMetaObject("Port" inherits "QObject": )
class nexxT.interface.PropertyCollection[source]

Bases: QObject

Note

Import this class with from nexxT.interface import PropertyCollection.

This class represents a collection of properties. These collections are organized in a tree, such that there are parent/child relations. This is a generic base class, which is implemented in the core package. Access to properties throug the methods below is thread safe.

Properties are usually used in subclasses of nexxT.interface.Filters.Filter. They are presented in the GUI as editable entities and the settings are saved to the configuration file. They are defined during filter constructor and onInit(…), they can be used during the whole filter lifecycle. There is also the possibility to connect a callback function to the propertyChanged signal. Note that properties are automatically deleted from the config file if they disappear (e.g., due to code changes, changed dynamic ports, etc.).

Example:

class MyFilter(Filter):
    def __init__(self, env):
        super().__init__(False, False, env)
        pc = self.propertyCollection()
        pc.defineProperty("intProp", 1, "an unconstrained integer")
        pc.defineProperty("intPropMax", 1, "an max constrained integer", options=dict(max=10))
        pc.defineProperty("intPropBounded", 1, "a bounded integer", options=dict(min=-4, max=10))
        pc.defineProperty("floatProp", 1.0, "a floating point number", options=dict(min=-1e-4, max=10000))
        pc.defineProperty("boolProp", True, "a boolean")
        # it is also possible to connect a callback
        pc.propertyChanged.connect(self.onPropertyChanged)

    def onInit(self):
        pc = self.propertyCollection()
        pc.defineProperty("strProp", "Hello World", "a string")
        pc.defineProperty("enumProp", "Hello", "a string", options=dict(enum=["Hello", "World"]))

    def onStart(self):
        # queries the current value of the property
        pc = self.propertyCollection()
        intProp = pc.getProperty("intProp")
        # ...

    def onPropertyChanged(self, pc, name):
        logger.info("Property '%s' changed to %s", name, repr(pc.getProperty(name)))

In the above example, different editors will be created apropriate to the chosen values. For example, the enum property can be edited using a combo box while integer properties are edited with spin boxes. It is also possible to adapt this behaviour by passing custom propertyHandlers.

This class is an abstract base class.

Note

Usually, nexxT is using the wrapped C++ class instead of the python version. In python there are no differences between the wrapped C++ class and this python class. The C++ interface is defined in nexxT::PropertyCollection

defineProperty(name, defaultVal, helpstr, options=None, propertyHandler=None)[source]

Return the value of the given property, creating a new property if it doesn’t exist. If it does exist, the definition must be consistent, otherwise an error is raised.

Note that the parameters options and propertyHandler must not be present at the same time. That is because the options are already passed to the constructor of the propertyHandler.

Parameters:
  • name – the name of the property

  • defaultVal – the default value of the property. Note that this value will be used to determine the property’s type. Currently supported types are string, int and float

  • helpstr – a help string for the user (presented as a tool tip)

  • options – a dict mapping string to qvariant (common options: ‘min’, ‘max’, ‘enum’) all properties support the option ‘ignoreInconsistentOptions’ (default: False). If this option is True, then nexxT allows that the options change over time. Even if present, the option type and its default values are not allowed to change.

  • propertyHandler – a PropertyHandler instance, or None for automatic choice according to defaultVal

Returns:

the current value of this property

evalpath(path)[source]

Evaluates the string path. If it is an absolute path it is unchanged, otherwise it is converted to an absolute path relative to the config file path.

Parameters:

path – a string

Returns:

absolute path as string

getProperty(name)[source]

return the property identified by name

Parameters:

name – a string

Returns:

the current property value

propertyChanged

QT signal which is emitted after a property value of the collection has been changed by the user.

Parameters:
  • pc – the PropertyCollection instance (i.e., the same as self.sender())

  • propName – the name of the property which has been changed.

setProperty(name, value)[source]

Set the value of a named property.

Parameters:
  • name – property name

  • value – the value to be set

Returns:

None

staticMetaObject = PySide6.QtCore.QMetaObject("PropertyCollection" inherits "QObject": Methods:   #4 type=Signal, signature=propertyChanged(PyObject,QString), parameters=PyObject, QString   #5 type=Slot, signature=setProperty(QString,PyObject), parameters=QString, PyObject )
class nexxT.interface.PropertyHandler[source]

Bases: object

Note

Import this class with from nexxT.interface import PropertyHandler.

This class represents a property definition for a specific type. The type handles loading/saving from and to .json configs as well as providing editor widgets for modifying the property in a model/view framework.

It is an abstrct base class.

For illustration, the implementation of the IntHandler is given here as an example:

class IntHandler(PropertyHandler):
    """
    The property handler for integer properties; Supported options: min and max.
    """

    def __init__(self, options):
        """
        Constructor

        :param options: the options given to the defineProperty(...) function.
        """
        for k in options:
            if k in ["min", "max"]:
                if not isinstance(options[k], int):
                    raise PropertyParsingError(f"Unexpected type of option {k}; expected int.")
            else:
                raise PropertyParsingError(f"Unexpected option {k}; expected 'min' or 'max'.")
        self._options = options

    def options(self):
        """
        return this handler's options

        :return: a python dict with the actual options.
        """
        return self._options

    def fromConfig(self, value):
        """
        import value from config file and return the adapted version.

        :param value: an integer is expected
        :return: the validated integer
        """
        assert isinstance(value, (float, int, bool))
        return self.validate(value)

    def toConfig(self, value):
        """
        export value to config file and return the adapted version

        :param value: an integer is expected
        :return: the exported value
        """
        assert isinstance(value, int)
        return value

    def toViewValue(self, value):
        """
        create a view of this option value.

        :param value: the current option value
        :return: a string
        """
        assert isinstance(value, int)
        return str(value)

    def validate(self, value):
        """
        Validate an option value and return an adapted, valid value

        :param value: the value to be tested (an integer)
        :return: the adapted, valid value
        """
        if isinstance(value, str):
            try:
                value = int(value)
            except ValueError:
                logger.warning("Cannot interpret value '%s' as int. Using 0.", value)
                value = 0
        if "min" in self._options:
            if value < self._options["min"]:
                logger.warning("Adapted option value %d to minimum value %d.", value, self._options["min"])
                return self._options["min"]
        if "max" in self._options:
            if value > self._options["max"]:
                logger.warning("Adapted option value %d to maximum value %d.", value, self._options["max"])
                return self._options["max"]
        return int(value)

    def createEditor(self, parent):
        """
        Creates a QSpinBox instance for GUI editing of integer values

        :param parent: the parent of the widget
        :return: a QSpinBox instance
        """
        res = QSpinBox(parent)
        res.setFrame(False)
        if "min" in self._options:
            res.setMinimum(self._options["min"])
        else:
            res.setMinimum(-2147483648)
        if "max" in self._options:
            res.setMaximum(self._options["max"])
        else:
            res.setMaximum(2147483647)
        return res

    def setEditorData(self, editor, value):
        """
        set the value of the QSpinBox

        :param editor: the instance returned by createEditor
        :param value: the option value (an integer)
        :return: None
        """
        editor.setValue(value)

    def getEditorData(self, editor):
        """
        return the currently edited value

        :param editor: the instance returned by createEditor
        :return: the integer value
        """
        return self.validate(editor.value())

Note

Usually, nexxT is using the wrapped C++ class instead of the python version. In python there are no differences between the wrapped C++ class and this python class. The C++ interface is defined in nexxT::PropertyHandler

createEditor(parent)[source]

This is called in QStyledItemDelegate::createEditor; creates an editor widget instance.

Parameters:

parent – a QWidget instance

Returns:

a QWidget instance

fromConfig(value)[source]

Converts the value read from the json file into the native python format

Parameters:

value – a QVariant instance

Returns:

the native value (also a QVariant)

getEditorData(editor)[source]

This is called in QStyledItemDelegate::setModelData; converts the value from the editor back to native python value.

Parameters:

editor – the editor widget

Returns:

a QVariant, the new native property value

options()[source]

Returns the options set for this handler as a QVariantMap

Returns:

a QVariantMap instance

setEditorData(editor, value)[source]

This is called in QStyledItemDelegate::setEditorData; populates the editor widget with the actual data.

Parameters:
  • editor – the editor widget as rezurned by createEditor

  • value – the current property value, given as native python value

Returns:

None

toConfig(value)[source]

Converts the native python format into a value suitable for json files.

Parameters:

value – a QVariant instance (the native value)

Returns:

the json value (also a QVariant)

toViewValue(value)[source]

Converts the native python format into a value suitable for display in the Qt model/view framework.

Parameters:

value – a QVariant instance (the native value)

Returns:

a QVariant value (suitable value for display)

validate(value)[source]

Returns a validated version of value.

Parameters:

value – the value to be set

Returns:

a validated version of value

Submodules