Expressions in KTL Python

Expression instances are used in KTL Python to satisfy waitFor() conditions. All of Python’s logical and mathematical operators are supported, and KTL keywords can be used as operands for all valid operations; not all keyword types support all operations, just as some Python types cannot be used with specific operators. The Python documentation on built-in types describes the range of available operations for the various native Python types. When an Expression is evaluated, the rich-comparison functions of the Keyword class are used. The behavior of these functions mimics the behavior of native Python types.

Inline function calls are not supported by the Expression class, though support may be added in the future.

Basic expressions

Though there is no real incentive to do so, one can create Expression instances that do not contain KTL keywords. Here are a few examples demonstrating simple syntax; the following expressions all evaluate to True:

3 < 4
3 + 4 == 7
3 + 4 >= 6
(3 + 4) * 5 == 35
foobar + cat == foobarcat
foo * 3 == foofoofoo

Quoting in Expressions

Any Python quoting syntax is valid for values within an Expression. If multiple levels of quoting are present, only the first level of quoting will be ‘stripped’, same as if one were creating Python strings. As in the simple examples above, there is no requirement that a string be quoted when used in an Expression unless it contains whitespace, begins with a $ character, or matches a valid mathematical or logical operator. All non-quoted whitespace in an Expression is removed by the parser.

Consider the following examples, which all evaluate to True:

foo == foo
foo == 'foo'
foo != 'foo   '
foo != '$foo'
foo != "'foo'"
foo == '''foo'''
foo == """foo"""
foo != """'foo'"""

KTL keywords in expressions

Any readable KTL keyword can be used as part of an Expression regardless of whether the KTL service is already open elsewhere in the program, or whether a given KTL keyword is already being monitored.

The specific syntax for using keywords will vary according to how the Expression is initialized, but all such declarations are prefixed with a single $ character. Consistent with other usage in KTL Python, service names are case sensitive, and keyword names are case insensitive.

If a default service is specified (as implied when using Service.waitFor()), the service name does not need to be specified. Otherwise, the service name must be included as part of the KTL keyword declaration. KTL Python adopts the established convention that service and keyword names are joined with a single . character.

The following examples use the keyword BAR from the service foo. If the keyword has the value 5, these expressions will evaluate to True:

$foo.BAR == 5
$foo.bar < 10
$Bar >= 5
$BAR * 5 == 25

There is no limit to the number of keywords that may be used in an Expression. Consider this moderately complex example:

($foo.BAR < 55) or ($foo.BAZ > 215) or ($foo.STATUS != Ready)

If any of those sub-conditions evaluates to True, the whole Expression will evaluate to True.

How Expressions work

When an Expression instance is intantiated, it will parse the expression string for any embedded KTL keywords. If a KTL service is not opened, it will be opened; if a keyword is not monitored, it will be monitored. Services opened in this fashion will not be closed, and keyword monitoring will not be disabled, regardless of whether the specific Expression instance is still in use.

Upon creation, the Expression.evaluate() method can be invoked at any time to fully evaluate itself. Expression.wait() may be used to block waiting for an Expression to evaluate to True.

The Expression class

class ktl.Expression(expression, services=None, default=None, keywords=None, case=False, wait=True)

Parse a string into clauses using a shunting-yard algorithm. Expressions may contain a mixture of mathematical and logical operators, and can be evaluated at any time.

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

Register (or unregister if remove is set to True) a callback function with all identified Keyword instances that are part of this Expression instance.

evaluate(final=False)

Determine the current value of the Expression instance. If a Keyword in an Expression has no value (as might occur if its initial broadcast is still pending), Expression.evaluate() will return None. If final is False, the Expression will be fully evaluated for each individual keyword broadcast; if final is True, only a single evaluation will be performed, using only the most recent broadcast for each keyword.

wait(timeout=None)

Wait for this Expression to evaluate to True. timeout is specified in seconds; if a timeout is provided and it expires, wait() will return False.