Object-oriented KTL Python

The object-oriented approach in KTL Python can greatly simplify a client application’s overall use of the module. When using the procedural approach, values must be cached, callbacks are more complicated to establish, and a lot of client-side metadata must be stored to correctly handle exceptional circumstances, such as an inability to monitor a given KTL keyword.

The Service and Keyword classes address these repetitive needs internally as much as possible in order to streamline the use of KTL Python.

Service objects

class ktl.Service(name, populate=False)

A complete representation of a single KTL service. name is a case-sensitive string representing the KTL service name. If populate is set to True, the Service instance will immediately instantiate all Keyword instances as part of its initialization. The default behavior is to do just-in-time instantiation of Keyword instances.

When accessing Keyword instances within a Service instance, the Service can be treated like a dictionary. See the basic use section of the Example usage document.

has_key(keyword)

Alias for Service.has_keyword().

has_keyword(keyword)

keyword can be either a Keyword instance, or a case-insensitive string.

heartbeat(keyword, period=5)

Identify keyword (either a keyword name, or a Keyword instance) as a heartbeat keyword for this Service. A heartbeat keyword should broadcast regularly to indicate that the KTL service is functional. period should be set to the maximum expected interval (in seconds) between heartbeat broadcasts.

All hearbeats are monitored by a background FirstResponder thread that wakes up according to the most imminent expiration of any heartbeat’s set period. If the heartbeat does not update within period seconds, an external check will be made to see whether the service is responding. If it is, and local broadcasts have not resumed, all Service instances corresponding to the affected KTL service will be resuscitated. See the FirstResponder class and Paramedic.resuscitate() for details.

Multiple heartbeats may be specified for a single Service instance. This is desirable if distinct dispatchers provide subsets of the keywords within a single KTL service. The failure of any heartbeat will trigger a full resuscitate operation; no attempt is made to distinguish between Keyword instances serviced by distinct dispatchers.

keywords()

List all keywords available in this Service instance.

list()

Alias for Service.keywords().

monitor(start=True, prime=True, wait=True)

Start or stop monitoring of all Keyword instances within this Service. A typical client application is only interested in monitoring a subset of the available keywords; in that case, use Keyword.monitor() instead. Refer to Keyword.monitor() for a description of the parameters.

monitored()

Return a sequence of keyword names that are presently monitored in this Service.

populated()

Returns a list of all keywords (as keyword names) that are instantiated as Keyword instances within this Service instance. A Keyword instance is not created until it is used by the client application.

read(keyword, binary=False, both=False, wait=True, timeout=None)

Perform a ktl_read() operation and return the most current value for the designated keyword. Refer to Keyword.read() for a description of the other arguments.

subscribe(start=True, prime=True)

Alias for Service.monitor().

wait(timeout=None, keywords=None, expression=None, reset=False, action=None, case=False)

Wait for any monitored Keyword instance in this Service to receive a new value. If expression is set, Service.wait() effectively acts as a wrapper to Service.waitFor(). If keywords is set to an iterable list of keywords (specified as either strings or Keyword instances), Service.wait() will act as if a parallel series of Keyword.wait() calls were invoked, with the first broadcast activity releasing Service.wait(). If reset is set to True, the notification flag will be cleared before waiting against it– this is dangerous, as this introduces a race condition between the arrival of the event itself, and the invocation of Service.wait(). If the event occurs first, the caller may wind up waiting indefinitely. If timeout (in whole or partial seconds) is set, Service.wait() will return False if no update occurs before the timeout expires. Otherwise, Service.wait() returns True to indicate that the wait completed successfully.

waitFor(expression, timeout=None, case=False)

Thin wrapper to waitfor(), using this Service instance as the default service.

waitfor(expression, timeout=None)

Alias for Service.waitFor().

write(keyword, value, wait=True, binary=False, timeout=None)

Perform a ktl_write() operation to assign the designated value to the designated keyword. Refer to Keyword.write() for a description of the other parameters.

Keyword objects

class ktl.Keyword(service, name, ktlc_instance)

A complete representation of a KTL keyword. It is not expected that users will instantiate Keyword instances directly: Keyword instances should always be acquired from a Service instance.

See also the basic use section of the Example usage document.

Keyword instances can be used with all boolean, comparison, and arithmetic operations. The support for these operations has its caveats. For all such operations, the Keyword instance must have a value, either via a Keyword.read() call, or by enabling asynchronous updates via Keyword.monitor(). Note that in-place operations (+=, -=, etc.) will automatically invoke Keyword.monitor() if necessary. In-place operations also imply a blocking invocation of Keyword.write(). In order to support the use of Keyword instances as dictionary keys, comparison operations between two Keyword instances do not compare the values of the two keywords, such operations compare their names. The Expression class goes to some length to manage comparisons between two Keyword instances to defeat this behavior. Comparisons between Keyword instances and all other data types are intended to match the behavior of comparisons between standard Python types; for example, a boolean Keyword can meaningfully be compared against the integers 0 and 1, just like the standard Python bool type.

In addition its member functions, a Keyword also provides significant functionality via dictionary-like keys. Many of these keys trigger just-in-time acquisition of data, caching the result for future use. The following keys are supported:

Key Operation performed
ascii or asc Return the current ascii representation of the Keyword; if the Keyword has no value, a Keyword.read() operation will be performed. Will raise an exception if one is active for this Keyword instance.
binary or bin Same as ascii, but will return the binary representation.
broadcasts Return a boolean indicating whether this KTL keyword supports broadcasts.
dictionary or dict Same as ascii, but will return a dictionary representation of the current value, if and only if the KTL keyword is a numeric array type.
enumerators or enum For enumerated KTL keyword types (including booleans), return a tuple containing the enumerators for all available named positions.
error Return a string representation of the active exception associated with this Keyword, if any. The exception object itself is stored as Keyword.error.
history Return a tuple containing a small chronological set of the most recent HistorySlice instances for this Keyword. The most recent broadcast is at the end of the sequence.
keys For numeric KTL array types, return a tuple containing the key name for each individual array value.
name Return the name of the keyword. All keyword names are case-insensitive, and are handled internally in all upper-case.
monitor or monitored Return a boolean indicating whether this Keyword instance is currently subscribed to broadcasts.
notify_reads Return a boolean indicating whether this KTL keyword supports KTL_NOTIFY read operations.
notify_writes Return a boolean indicating whether this KTL keyword supports KTL_NOTIFY write operations.
populated Return a boolean indicating whether this Keyword instance has a value, either from an explicit Keyword.read() operation or from a broadcast.
range Return a dictionary containing the minimum and maximum values for this KTL keyword. If no range is set, return None. If either the minimum or maximum is not set, that specific value will be set to None. These values are expected to be the binary representation; a a nested ‘ascii’ dictionary will contain the same numeric values put through the keyword’s binary-to-ascii routine. For most keywords, there is no significant distinction between the two.
reads Return a boolean indicating whether this KTL keyword supports read operations.
servers Return a tuple containing the server names associated with this KTL keyword.
timestamp Return the floating point timestamp (in UNIX seconds) associated with the most recent update to the value of the Keyword. It is recommended that you work instead with the HistorySlice instances provided by the history key.
type Return the KTL type of this KTL keyword as a string. Use the top-level KTL_DATATYPE dictionary to map between string and integer representations of the KTL type.
units Return the ‘units’ associated with this KTL keyword, if any.
writes Return a boolean indicating whether this KTL keyword supports write operations.

a Keyword defines the following functions:

callback(function, remove=False, preferred=False)

Request that a callback function be invoked whenever a KTL broadcast is received for this keyword. The callback function should accept as its sole argument a Keyword instance. If remove is set to False, the designated function will be removed from the set of active callbacks. If preferred is set to True, this callback will be remembered as a preferred callback, which gets invoked before all other non-preferred callbacks.

Keyword.callback() is typically used in conjunction with Keyword.monitor(), or Keyword.poll() if the specific KTL keyword does not support broadcasts.

cast(value)

Cast the provided value to a native Python type appropriate for this keyword. For example, a numeric keyword type would cast the string ‘1.2’ to a floating point number; an integer keyword type would convert the same string to the number 1.

clone()

Return a copy of this Keyword instance with a frozen list of HistorySlice instances. Otherwise, all other internal references will refer back to the source Keyword instance. Note that if a clone’s Keyword.read() method is called, only the frozen values associated with the cloned instance will be returned.

convert(binary=None, ascii=None)

Request a translation for either a KTL binary representation to its KTL ascii representation, or the other way around. You cannot simultaneously specify both binary and ascii values. The return result is the translated value.

isAlive()

Check that the heartbeats associated with this keyword are themselves alive; if they are, return True, otherwise return False. If no heartbeats are associated with this Keyword instance, a NoHeartbeatsError exception will be raised.

lower()

Return the lower-case equivalent of the current ascii value of this Keyword instance. If there is no current ascii value, an AttributeError exception will be raised.

monitor(start=True, prime=True, wait=True)

Subscribe to broadcasts for this KTL keyword. If start is set to False, the subscription will be shut down. If prime is set to False, there will be no priming read of the keyword value; the default behavior is to perform a priming read. If wait is set to False, the priming read (if requested) will not block while waiting for the priming read to complete.

In order to avoid a race condition, priming reads are always performed as a distinct operation from the subscription request. Traditional KTL C usage combines the two in a single ktl_read() operation.

poll(period=1, start=True)

In circumstances when a KTL keyword cannot (or will not) reliably broadcast updates, polling can be established. If start is True, a non-blocking call to Keyword.read() will be invoked every period seconds; if start is False, polling for this keyword will be discontinued.

Polling keywords is inefficient, as it requires a discrete ktl_read() operation for each polling event for each keyword polled. Using monitor() is a far better choice if supported by the service’s KTL client library.

probe()

Use the Procedural.probe() method to open/read/close this KTL service and keyword to see if out-of-band communication succeeds. There is no return result, exceptions are raised upon failure. It is highly recommended to try calling Keyword.read() (possibly with a timeout) before calling this method; some services will restore themselves automatically without requiring a Service.reconnect() operation.

propagate()

Invoke any/all callbacks registered via Keyword.callback(). This is an internal function, invoked after a Keyword instance successfully completes a Keyword.read() call, or a KTL broadcast event occurs.

read(binary=False, both=False, wait=True, timeout=None)

Perform a ktl_read() operation for this keyword. The default behavior is to do a blocking read and return the ascii representation of the keyword value. If binary is set to True, only the binary representation will be returned; If both is set to True, both representations will be returned in a (binary, ascii) tuple. If wait is set to False, the KTL read operation will be performed in a background thread, and any resulting updates would trigger any callbacks registered via Keyword.callback(). If a timeout is specified (in seconds), and wait is set to True, Keyword.read() will raise a TimeoutException if the timeout expires before a response is received.

In order to avoid the possibility of a silent deadlock, the timeout argument is only respected if the service supports KTL_NOTIFY read operations.

subscribe(start=True, prime=True, wait=True)

Subscribe to broadcasts for this KTL keyword. If start is set to False, the subscription will be shut down. If prime is set to False, there will be no priming read of the keyword value; the default behavior is to perform a priming read. If wait is set to False, the priming read (if requested) will not block while waiting for the priming read to complete.

In order to avoid a race condition, priming reads are always performed as a distinct operation from the subscription request. Traditional KTL C usage combines the two in a single ktl_read() operation.

upper()

Return the upper-case equivalent of the current ascii value of this Keyword instance. If there is no current ascii value, an AttributeError exception will be raised.

wait(timeout=None, operator=None, value=None, sequence=None, reset=False, case=False)

Wait for the Keyword to receive a new value, or if sequence is set, wait for the designated write operation to complete. If value is set, with or without operator being set, Keyword.wait() effectively acts as a wrapper to Keyword.waitFor(). If reset is set to True, the notification flag will be cleared before waiting against it– this is dangerous, as this introduces a race condition between the arrival of the event itself, and the invocation of Keyword.wait(). If the event occurs first, the caller may wind up waiting indefinitely. If timeout (in whole or partial seconds) is set, Keyword.wait() will return False if no update occurs before the timeout expires. Otherwise, Keyword.wait() returns True to indicate that the wait completed successfully.

waitFor(expression, timeout=None, case=False)

Wait until this Keyword satisfies the provided expression. If timeout seconds elapse without success, Keyword.waitFor() will return False. This Keyword is always prefixed to the expression as the implied first argument.

See the documentation on Expressions in KTL Python for syntax details.

write(value, wait=True, binary=False, timeout=None)

Perform a KTL write for this keyword. value is the new value to write to the keyword. If binary is set to True, value will be interpreted as a binary representation; the default behavior is to interpret value as an ascii representation. The behavior of timeout is the same as for Keyword.read().

Keyword.write() does not update the Keyword instance with new values. A Keyword instance will only update its internal values as a result of a Keyword.read() call, or if the Keyword is subscribed to broadcasts via Keyword.monitor().

Other objects

class ktl.HistorySlice(keyword, binary, ascii, time)

A HistorySlice is effectively a named tuple, an object type available in Python 2.6 and later. A HistorySlice provides programmer-friendly access to the data resulting from a single KTL broadcast.

Available keys are as follows:

Key Value  
0 or time or timestamp UNIX timestamp for the broadcast
1 or bin or binary Binary representation of keyword
2 or asc or ascii Ascii representation of keyword
keyword or name Name of KTL keyword