Using KTL keywords

Keyword instances are the primary kPyQt resource that most applications will interact with. The principal design goal objective of the Keyword is to properly sanitize KTL broadcast events for consumption by other PyQt widgets through the use of signals and slots. With few exceptions, other interaction with ktl.Keyword instances is best done directly rather than rely on wrapped methods in Keyword.

Instantiating Keyword instances

kPyQt.Keyword.factory(keyword, new_class=<class 'kPyQt.Keyword.Keyword'>, *args)

The keyword argument should be a ktl.Keyword instance; the remainder of the arguments passed to this function will be passed to the new_class Keyword type. All Keyword instances created by this method will be cached indefinitely and will not be deallocated; if a cached instance is available it will be returned instead of creating a new instance. Keyword instances can always be created directly instead of using this factory function, but care should be taken to save a reference to any created instances, otherwise they’ll get garbage collected and any connected signals won’t fire any more.

For convenience this method can be referenced via kPyQt.kFactory().

The base Keyword class

class kPyQt.Keyword.Keyword(*args, **kwargs)

The first set of methods are application-facing and have utility for GUI code interacting with KTL keywords.

getEnumerators()

Retrieve the enumerators for the wrapped ktl.Keyword instance. An empty tuple will be returned if no enumerators are available. This method is particularly useful for populating widgets like drop-down menus.

primeCallback()

Manually send all signals connected to slots on this Keyword, using the current value of the wrapped ktl.Keyword instance. This often needs to be called when popup widgets get destroyed and recreated, or more generally, when Keyword instances get reused and signals are connected to new slots.

read()

Return the current cached ascii value of the wrapped ktl.Keyword instance. This wrapper is not intended to be a full replacement for using a ktl.Keyword directly. Note this method may block to retrieve a value if one is not already cached.

setFormat(format)

Define the printf-style format that will be used by the formatValue() before re-emitting any KTL broadcasts as string callbacks.

setKeyword(keyword)

Define the ktl.Keyword instance that will be wrapped by this Keyword instance. This method will also establish callbacks and initiate monitoring of the ktl.Keyword instance.

write(value, wait=False)

Perform a non-blocking write of the provided ascii value to the wrapped ktl.Keyword instance. This wrapper is not intended to be a full replacement for using a ktl.Keyword directly.

Note

Use of non-blocking writes will cause problems for some KTL client library implementations that only properly work with blocking writes, which includes the EPICS CAke client library. Normally a GUI would never want to use a blocking write for this purpose, but it is required for stable use of some keywords.

The second set of methods are of interest for subclasses of Keyword, and may need to be overridden for proper handling of custom functionality.

formatValue(value)

Internal method used to re-format raw broadcast values before further handling takes place. See setFormat().

emitIntegerCallback(value)

Generate the signal for any PyQt widgets connected to our integer callback slot. This method is called by receiveCallback().

emitStringCallback(value)

Generate the signal for any PyQt widgets connected to our string callback slot. This method is called by receiveCallback().

receiveCallback(keyword)

Receive a broadcast value from a ktl.Keyword instance; format the broadcast for the emitStringCallback() and emitIntegerCallback() methods, and signal any Qt widgets connected to slots on this Keyword.

Subclasses of Keyword

The basic classes don’t add much (if anything) beyond the base Keyword.

class kPyQt.Keyword.Float(*args)

Unchanged from the base Keyword, except the default ascii formatting is as a floating point number (%f).

class kPyQt.Keyword.Integer(*args)

Unchanged from the base Keyword, except the default ascii formatting is as an integer (%d).

class kPyQt.Keyword.String(*args, **kwargs)

Unchanged from the base Keyword.

Additional subclasses included here were used regularly in multiple applications, and were generic enough to warrant providing as part of kPyQt.

class kPyQt.Keyword.DynamicEnumeration(*args)

The DynamicEnumeration class uses a KTL keyword to define the mapping between individual positions and some other value, in much the same way that an enumeration is a mapping between pre-defined integer and string values. An example might be filter names and numbered slots on a filter wheel, where the filters could change depending on the instrument configuration. Another example might be slitmask names and numbered slots in an exchange mechanism.

To use an example from galildisp, the caller might invoke setKeyword() with the NAM keyword for a stage, and setMappingKeyword() on the RON keyword. Calling getEnumerators() would return the list of available NAM values, which allows for easy population of drop-down menus.

getEnumerators()

Use the cached dynamic mapping to return a tuple of valid values.

setMappingKeyword(keyword, fields, interest=None)

A mapping keyword is a delimited mapping between positions and position names, similar to the PEN or RON keywords implemented by galildisp. fields is the number of different data types in the mapping keyword, and is generally 2 or 3. interest specifies the column number (starting at zero) containing the named positions, and defaults to (fields - 1).

An example RON value might be:

' 0 0 Home 500 1 Slot_1 1000 2 Slot_2'

The first character is the delimiter; the first field is an encoder value, the second field is an ordinal position, and the third field is the name for that position. A DynamicEnumeration user generally cares about the names, so in this case the appropriate arguments are fields=3, and interest does not need to be specified because the default value of 2 is correct. If the order was instead:

' 0 Home 0 500 Slot_1 1 1000 Slot_2 2'

…then the appropriate arguments would be fields=3 and interest=1, assuming the caller wants the position names. This would also be appropriate for the original value if the caller wanted the dynamic enumeration to return ordinal position numbers instead of position names.

setSort(function)

How to sort the enumerators returned from getEnumerators(). ‘function’ is a standard sorting key function, like you would pass to list.sort(). If True is passed instead of a function the default sort will be applied. If False or None is passed no sorting will be performed.

class kPyQt.Keyword.Percentage(*args, **kwargs)

Receive a numberic keyword and emit a percentage as an integer. The simplest translation (none!) occurs when the base keyword is itself a percentage; both the minimum and maximum values can be updated dynamically and the percentage will scale accordingly. For example, if a KTL service has a relative move value and a relative move target, the maximum can be set to the target and the keyword provided to setKeyword() should be the one reporting the current relative motion for the command. To be more specific, for a galildisp dispatcher the caller should invoke setKeyword() with the REL keyword, and setMaximumKeyword() with the TRL keyword. Using setMinimumKeyword() is only necessary if the caller needs to establish a non-zero value to subtract from the other keyword values.

setMinimumKeyword(keyword)

Define the ktl.Keyword that will dynamically determine what corresponds to 0%.

setMaximumKeyword(keyword)

Define the ktl.Keyword that will dynamically determine what corresponds to 100%.

setRange(minimum, maximum)

Set fixed minimum+maximum values for the “progress” keyword. The default values are 0 and 100; if the “progress” keyword is a floating point value that scales between 0 and 1, those limits need to be set here in order for the output percentage to scale properly. Note this is a one-time adjustment, any values set here will be overridden if setMinimumKeyword() or setMaximumKeyword() is used.