Python Bound API

class karabo.bound.PythonDevice(configuration: <MagicMock name='mock.Hash.__or__()' id='140105519408128'>)

The PythonDevice class is the basis for all karabo.bound devices

Devices implemented in the karabo.bound API should derive from this class. It provides an interface to the distributed system and holds properties that represent the state of a device. Commands may be exposed through it using so-called slots.

Devices can optionally either use a full finite state machine, deriving from the FSM class, or use a simplified approach (NoFSM), where state updates are explicitly called from the device logic. The latter is the default if a device class just inherits from this PythonDevice. Otherwise the device class has to also inherit from a concrete FSM implementation that inherits from BaseFsm.

Devices run in a separate process, but internally use an event loop with multiple threads to serve requests from the distributed system.

KARABO_ON_DATA(channelName, handlerPerData)

Registers a data handler function

This function will be called if data is received on an input channel identified by channelName. The handler function should have the signature:

def onData(data, metaData):
pass

where data and metaData are both Hashes.

KARABO_ON_EOS(channelName, handler)

Registers an end-of-stream handler

Registers a handler to be called if input channel identified by channelName is signaled end-of-stream.

The handler function should have the signature

def onEos(input):
pass

where input is a reference to the input channel.

KARABO_ON_INPUT(channelName, handlerPerInput)

Registers an input handler function

Registers a handler to be called if data is available on the input channel identified by channelName. It is up to the device developer to read data (in contrast to the KARABO_ON_DATA registration).

def onInput(input):
for i in range(input.size()):
data, metaData = input.read(i)

Here input is a reference to the input channel.

KARABO_SLOT(slot, slotName=None, numArgs=None)

Register a slot in the distributed system.

:param slot is the callable to register :param slotname is used to call the slot, ‘None’ means slot.__name__,

note that a ‘_’ can also be called as ‘.’ as needed for nested slots in the Schema like ‘node.slotInNode’
:param numArgs number of arguments that the slot has,
‘None’ means to (try to) deduce from ‘slot’

Note that a slot is only connected with a SLOT_ELEMENT if the key of the SLOT_ELEMENT matches the slot name provided to this function.

SLOT_ELEMENT(expected).key(“slotDoSomething”)

self.KARABO_SLOT(slotDoSomething)

def slotDoSomething(self):
pass

For slots under a node, the method name needs to replace ‘.’ by ‘_’.

SLOT_ELEMENT(expected).key(“node.slotOther”)

self.KARABO_SLOT(node_slotOther)

def node_slotOther(self):
pass
aliasHasKey(alias)

Check if a key for a given alias exists

allowLock()

Overwrite this function for service devices that cannot be locked :return:

appendSchema(schema)

Append to the existing device schema

If a property is being reinjected, and of the same type, then it will keep its current value. If it does not fit within range, an error will be raised. Likewise, if the type changes, and the value cannot be cast, an error will be raised.

Input and output channels will be created if injected. An output channel is also recreated if its schema changes, to make the other end aware. Note that for newly created input channels there are no data, input and end-of-stream handlers registered. This has to be done via the corresponding self.KARABO_ON_[DATA|INPUT|EOS] methods. If an InputChannel is re-injected, its handlers are kept.

Parameters:schema – to append to current full schema
appendSchemaMaxSize(path, value, emitFlag=True)

Append Schema to change/set maximum size information for path. If paths does not exist, raise KeyError.

This is similar to the more general appendSchema, but dedicated to a common use case.

:param path indicates the parameter which should be a
Vector- or TableElement

:param value is the new maximum size of the element :param emitFlag indicates if others should be informed about this

Schema update. If this method is called for a bunch of paths, it is recommended to set this to True only for the last call.
call(instanceId, slotName, *args)

Call a remote slot with arguments

Parameters:
  • instanceId – instance of the remote device to call slot on
  • slotName – name of the slot to call on instanceId
  • args – list of arguments to call slot with, maximum length is 4
connect(signalInstance, signalName, slotInstance, slotName)

Connect a signal with a slot

Parameters:
  • signalInstance – instance the signal is on, use “” for local
  • signalName – name of the signal to connect
  • slotInstance – instance the slot is on, use “” for local
  • slotName – name of the slot to be executed upon signal reception

:return whether connection could be established

classmethod create(*args)

The factory classmethod to create the instance of class with “classId” using input “configuration”. Example:

instance = Shape.create(“EditableCircle”,
Hash(“radius”, 12.345))

The factory classmethod to create instance according input “configuration”. The configuration should have “classId” of class to be created as a root element. Example:

configuration = Hash(“EditableCircle.radius”, 12.345) instance = Shape.create(configuration)
classmethod createChoice(choice, config)

The helper classmethod to create the instance using “choiceName” and input “configuration”.

classmethod createList(listname, configuration)

The helper method to create the list of instances using “listName” as a key to the list of configs in input “configuration”. The configurations will be validated.

classmethod createNode(nodename, classid, configuration)

The helper classmethod to create instance of class specified by “classId” using sub-configuration specified by “nodeName” which has to be a part of input “configuration”.

emit(signalName, *args)

Emit a signal to the remote system

Parameters:
  • signalName – name of the signal.
  • args – list of arguments signal is emitted with. Maximum 4
filterByTags(configuration, tags)

Filter a given configuration Hash by tags

Parameters:
  • configuration
  • tags – a string, with several entries separated by commas spaces or semicolons
Returns:

the filtered configuration Hash

fullSchema

DEPRECATED - use getFullSchema()

get(key)

Return a property of this device

Parameters:key – as defined in the expected parameter section
Returns:the value of the property
getActualTimestamp()

Returns the actual timestamp.

The Trainstamp part of Timestamp is extrapolated from the last values received via slotTimeTick (or zero if no time ticks received, i.e. timeServerId is empty). To receive time ticks, the server of the device has to be connected to a time server.

Returns:the actual timestamp
getAliasFromKey(key, aliasReferenceType)

Return the alias of a key :param key: to return the alias from :param aliasReferenceType: type the alias is of :return: an object of aliasReferenceType

getAvailableInstances()

Return available instances in the distributed system

getCurrentConfiguration(tags='')

Return the current configuration, optionally filtered by tags

Parameters:tags – a string, with several entries separated by commas spaces or semicolons. Set to an empty string if no filtering is to be applied.
Returns:a configuration Hash
getCurrentConfigurationSlice(paths)

Retrieves a slice of the current configuration.

Parameters:paths

of the configuration which should be returned (as declared in expectedParameters,

method throws if a non-existing path is given)
Returns:Hash with the current values and attributes (e.g. timestamp) of the selected configuration
getFullSchema()

Return the full schema describing this device

Returns:a karabo Schema object
getKeyFromAlias(alias)

Return the key mapping to a given alias

classmethod getSchema(classid, rules=None)

Use this classmethod to get schema for class with “classid” using assembly “rules” Example:

schema = Shape.getSchema(“Rectangle”)
or
schema = Shape.getSchema(“Rectangle”, AssemblyRules())
getServerId()

Return the id of the server hosting this devices

getTimestamp(epoch)

Returns the Timestamp for given Epochstamp.

The Trainstamp part of Timestamp is extrapolated forward or backward from the last values received via slotTimeTick (or zero if no time ticks received yet). To receive time ticks, the server of the device has to be connected to a time server.

Parameters:epoch – Epochstamp for that the time stamp is searched for
Returns:the matching Timestamp, consisting of epoch and the corresponding Trainstamp
getValueType(key)

Get the ValueType of a given key

Returns:The type in terms of karabo::util::ReferenceTypes
initChannels(topLevel='', schema=None)

Initialise Input-/OutputChannels :param schema to recurse for channels - if None, use self._fullSchema :param topLevel is path in schema hierarchy where to start recursion

keyHasAlias(key)

Check if a given key has an alias defined

loadLogger()

Load the distributed logger

Uses config in self._parameters[“Logger”] and PythonDevice._loggerCfg

noStateTransition(currentState, currentEvent)

This function is called if a requested state transition is not allowed in the current context. Usually, this means you have an error in your state machine.

onTimeUpdate(id, sec, frac, period)

Called when an update from the time server is received

Parameters:
  • id – train id
  • sec – seconds
  • frac – fractional seconds
  • period
Returns:

parameters

DEPRECATED * for full config use getCurrentConfiguration() * maybe what you want is just some key, then use get(some_key)

postReconfigure()

Use this hook to react on configuration changes after they have been validated and applied to the device, and have been notified to the distributed system.

preDestruction()

Use this hook if you need to perform clean-up actions before a device gets destroyed.

preReconfigure(incomingReconfiguration)

Use this hook to alter a configuration Hash before it gets applied to the device and the distributed system is notified of the change. :param incomingReconfiguration:

registerSignal(signalName, *args)

Register a signal to be handles in the remote system

:param signalName:name of the signal to be registered :param args: signature of the signal, e.g. str, Hash, str

remote()

Return a DeviceClient instance.

The DeviceClient will use this device’s SignalSlotable to interact with the distributed system :return:

reply(*args)

Place the reply of a slot being called

Reply content will not be sent immediately, but when the slot call ends. If called more than once, the last call defines the slot reply.

Parameters:args – list of arguments to reply, maximum length is 4
request(instanceId, slotName, *args)

Request a reply from a remote slot

Parameters:
  • instanceId – instance of the remote device to request from
  • slotName – name of the slot to request from on instanceId
  • args – list of arguments to call slot with, maximum length is 4
Returns:

a SignalSlotable.Requestor object handling the reply

requestNoWait(instanceId, slotName, replyInstance, replySlotName, *args)

Request a reply from a remote slot

Parameters:
  • instanceId – instance of the remote device to request from
  • slotName – name of the slot to request from on instanceId
  • replyInstance – instance on which to handle reply, use “” for local device.
  • replySlotName – slot to call with reply on replyInstance
  • args – list of arguments to call slot with, maximum length is 4
Returns:

a SignalSlotable.Requestor object handling the reply

set(*args, **kwargs)

Updates device properties and notifies any observers. Note that an update of the device “state” property must be done using updateState(..).

args: can be of length

  • one: expects a Hash, and uses current timestamp
  • two: expects a key, value pair and uses current timestamp or a
    Hash, timestamp pair
  • three: expects key, value and timestamp
kwargs: validate: specifies if validation of args should be performed
before notification. Skipping validation should not be used with State or AlarmCondition.

If a Hash is provided, its keys should be device properties and the values should have the proper types. A State or AlarmCondition inside a Hash should be given as a string.

setAlarmCondition(condition, **deprecated)

Set the global alarm condition

Parameters:condition – condition to set
Returns:None
setVectorUpdate(key, updates, updateType, timestamp=None)

Concurrency safe update of vector property (not for tables)

Parameters:
  • key – key of the vector property to update
  • updates – iterable of items to remove from property vector (starting at the front) or to add (at the end)
  • updateType – indicates update type, applied individually to all items in ‘updates’, one of “add”, “addIfNotIn”, “removeOne”, “removeAll”
  • timestamp – optional timestamp to assign to updated vector property, defaults to self.getActualTimestamp()
signalEndOfStream(channelName)

Signal an end-of-stream event

The channel is identified by channnelName

Note: The methods ‘writeChannel(..)’ and ‘signalEndOfStream(..)’ must not be called concurrently.

signalSlotable

Get SignalSlotable object embedded in PythonDevice instance.

slotClearLock()

Clear the lock on this device

slotGetTime(info)

Return the actual time information of this device

Parameters:info – An empty place holder hash

This slot returns a Hash with:

  • key time and the attributes provide an actual

timestamp with train Id information - key timeServerId to show the configured time server - key reference and the attributes provide the latest received timestamp information from the timeserver

slotLoggerContent(info)

Slot call to receive logger content from the print logger

This slot is similar to slotLoggerContent for servers except that the serverId key is substituted with key deviceId.

look in the device_server module for detailed informations

updateSchema(schema)

Updates the existing device schema It merges the schema in argument to the static schema defined in expectedParameters, removing any previous schema injections.

If a property is being reinjected, and of the same type, then it will keep its current value. If it does not fit within range, an error will be raised. Likewise, if the type changes, and the value cannot be cast, an error will be raised.

Input and output channels will be created if injected and removed again in case updateSchema is called again without them. An output channel is also recreated if its schema changes. Note that for newly created input channels there are no data, input and end-of-stream handlers registered. This has to be done via the corresponding self.KARABO_ON_[DATA|INPUT|EOS] methods. If an InputChannel is re-injected, its handlers are kept.

Parameters:schema – to be merged with the static schema
updateState(newState, propertyUpdates=None, timestamp=None)

Update the state property of the device to a new state.

This should be used for NoFSM devices and should not be used if you have an underlying FSM. :param newState: the state to set the device to :propertyUpdates: a Hash with further properties to update (or None) :timestamp: timestamp to be assigned to the update,

if None, use self.getActualTimestamp()
Returns:
writeChannel(channelName, data, timestamp=None, safeNDArray=False)

Write data to an output channel.

Parameters:
  • channelName – name given to an OUTPUT_CHANNEL in expectedParameters
  • data – a Hash with keys as described in the Schema of the channel
  • timestamp – optional timestamp; if none is given, the current timestamp is used
  • safeNDArray – Boolean that should be set to ‘True’ if ‘data’ contains any ‘NDArray’ and their data is not changed after this ‘writeChannel’. Otherwise, data will be copied if needed, i.e. when the output channel has to queue or serves inner-process receivers.

Example for an output channel sending an image (key: “image”) and a frame number (key: “frame”):

imgArray = numpy.array(…) self.writeChannel(“output”, Hash(“image”, ImageData(imgArray),

“frame”, frameNumber))

Note: The methods ‘writeChannel(..)’ and ‘signalEndOfStream(..)’ must not be called concurrently.

class karabo.bound.DeviceServer(config)

Device server serves as a launcher of python devices.

It scans ‘plugins’ directory for new plugins (python scripts) available and communicates its findings to master device server. It communicates XSD form of schema of user devices and starts such devices as separate process if user push “Initiate” button in GUI

classmethod create(*args)

The factory classmethod to create the instance of class with “classId” using input “configuration”. Example:

instance = Shape.create(“EditableCircle”,
Hash(“radius”, 12.345))

The factory classmethod to create instance according input “configuration”. The configuration should have “classId” of class to be created as a root element. Example:

configuration = Hash(“EditableCircle.radius”, 12.345) instance = Shape.create(configuration)
classmethod createChoice(choice, config)

The helper classmethod to create the instance using “choiceName” and input “configuration”.

classmethod createList(listname, configuration)

The helper method to create the list of instances using “listName” as a key to the list of configs in input “configuration”. The configurations will be validated.

classmethod createNode(nodename, classid, configuration)

The helper classmethod to create instance of class specified by “classId” using sub-configuration specified by “nodeName” which has to be a part of input “configuration”.

classmethod getSchema(classid, rules=None)

Use this classmethod to get schema for class with “classid” using assembly “rules” Example:

schema = Shape.getSchema(“Rectangle”)
or
schema = Shape.getSchema(“Rectangle”, AssemblyRules())
onStateUpdate(currentState)

This function is DEPRECATED and will be removed.

scanPlugins(pluginNamespace)

Scan for available device classes

Returns Hash with keys “deviceClasses” and “visibilities” to be merged into instance info and a list of log messages to be send. Inside the list there are tuples of two string: log level (e.g. “INFO”) and message. Also fills self.availableDevices dictionary.

setupFsm()

Description of DeviceServer state machine

slotDeviceUp(instanceId, success, reason)

Slot for device to tell us whether it managed to get alive

slotLoggerContent(info)

Slot call to receive logger content from the CacheLogger

replies with a Hash containing a key, serverId and a content containing a vector of hashes formatted in the same way the broker based logging uses. For details: src/karabo/log/CacheLogger.cc

Parameters:info – input Hash containing an optional logs integer defining the maximum number of lines returned
karabo.bound.DeviceClient
class karabo.bound.worker.QueueWorker(callback)
class karabo.bound.worker.Worker(callback=None, timeout=-1, repetition=-1, daemon=True)
run()

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

start()

Start the thread’s activity.

It must be called at most once per thread object. It arranges for the object’s run() method to be invoked in a separate thread of control.

This method will raise a RuntimeError if called more than once on the same thread object.

karabo.bound.decorators.KARABO_CLASSINFO(classid, version)

This decorator should be placed just before class definition. It adds some variables used in KARABO configuration infrastructure. It has two parameters: “classId” and “version” similar to corresponding C++ macro: Example:

@KARABO_CLASSINFO(“Shape”,”1.0”) class Shape(object):

karabo.bound.decorators.KARABO_CONFIGURATION_BASE_CLASS(theClass)

This decorator should be placed just before “KARABO_CLASSINFO” decorator. It registers the class as the base configurable class and adds the following classmethods: “create”, “createNode”, “createChoice”, “createList”, “getSchema” and “getRegisteredClasses”. It has no parameters. Example:

@KARABO_CONFIGURATION_BASE_CLASS @KARABO_CLASSINFO(“Shape”,”1.0”) class Shape(object):

class karabo.bound.Configurator(classid)

Provides factorized configuration

Configurator is the singleton class that keeps methods for registration and creation other classes that are configurable classes

create(*args)

The factory method to create the instance of class with “classId” that inherits from base class given to constructor using “input” configuration. The last argument is a flag to determine if the input configuration should be validated.

Example:

instance = Configurator(Shape).create(“EditableCircle”,
Hash(“radius”, 12.345))

The factory method to create instance of class that inherits from base class given to constructor using input “configuration”. The configuration should have “classId” of class to be created as a root element. The last argument is a flag to determine if the input “configuration” should be validated.

Example:

configuration = Hash(“EditableCircle.radius”, 12.345) instance = Configurator(Shape).create(configuration)
Parameters:args – thus can have an arity of one to three: - class id string - config with classId as root key - class id string, config - config with classId as root key, validation flag - class id string, config, validation flag
createChoice(choicename, configuration, validation=True)

The helper method to create the instance of class derived from base class given to constructor using “choiceName” and input “configuration”. The last argument is a flag to determine if the input configuration should be validated.

createList(listname, input, validation=True)

The helper method to create the list of instances of classes derived from base class given to constructor using “listName” used as a key to the list and “input” configuration. The last argument is a flag to determine if the input configuration should be validated.

createNode(nodename, classid, configuration, validation=True)

The helper method to create instance of class specified by “classId” and derived from class given to constructor using sub-configuration specified by “nodeName” which has to be a part of input “configuration”.

The last argument is a flag to determine if the input “configuration” should be validated.

static getRegisteredBaseClasses()

Returns all classid’s of base classes registered in Configurator.

getRegisteredClasses()

Returns list of “classid“‘s for all registered classes derived from base class given to constructor.

getSchema(classid, rules=<MagicMock name='mock.AssemblyRules()' id='140105518627616'>)

Get schema for class with “classid” derived from base class given to constructor using assembly “rules”. Example:

schema = Configurator(Shape).getSchema(“Rectangle”)
static registerAsBaseClass(theClass)

Register a class as a base class in the configurator

Parameters:theClass – to be registered
registerClass(derived)

Register a derived class, i.e. a class deriving from a registered base class in the configuration system. :param derived: :return: