Utilities
The following functions are useful in any context or scope, and do not fit within another category.
transform()
This function emulates the “expression transform” operations available in Perspective bindings in other binding contexts (expression tags, Vision component bindings, Identity Provider attribute mappings), though can be used in Perspective, too.
transform(valueExpr, transformExpr) returns Object
| valueExpr | Any expression. It is executed first, and its result is loaded into a thread-local stack, similar to the thread-locals used by the iteration functions. |
| transformExpr | Any expression. This is executed after the thread-local has been set
up, enabling this expression to use value() in multiple
places. The result of this expression is the result from the function
as a whole. |
You can treat this function as if the valueExpr was top half of an expression
binding that has an expression transform attached, and the transformExpr
was the bottom half. See the example below.
value()
This function must be nested in the transformExpr of a tranform()
function. It retrieves the saved “top half” value anywhere it is needed
within the “bottom half”, without needless re-execution of the “top half”
expression.
value([depth]) returns Object
| depth | Optional number of saved thread locals to skip before retrieving the
value, similar to the behavior of it() and idx()
when using nested iteration functions. Zero when omitted. |
A Perspective expression binding that has an expression transform
attached can be reimplemented in a single expression using transform()
and value(). Like this Perspective binding expression:
split({path.to.some.string}, '/')
with this transform:
{value}[len({value})-1, 0]
can be combined in a single expressions like so:
transform(
split({path.to.some.string}, '/'),
value()[len(value())-1, 0]
)
Note that the expression transform simply has {value} replaced with
value()–exactly the same number of characters.
This expression can also be deployed outside of Perspective.
jsonDecode()
This function offers the functionality of Ignition’s native system.util.jsonDecode()
scripting function in expressions. (It uses the scripting implemention exposed
in the SDK API directly.)
jsonDecode(source) returns Object
| source | String to be interpreted as JSON to produce and return and object tree. |
jsonEncode()
This function offers a robust alternative to Ignition’s native system.util.jsonEncode()
scripting function in expressions. Instead of using the buggy scripting implementation
exposed in the SDK API, it uses IA’s customized version of GSON that is shipped with
the platform. Unlike the scripting interface, this function always delivers a
“pretty printed” string.
jsonEncode(object) returns String
| object | Any object that can be JSONified by GSON, typically including all standard dictionary, list, string, and numeric types, whether from java or jython. |
ramp()
Given speed and acceleration limits, compute values on a trajectory from the current value to a target position. Supports separate forward and reverse speeds. Updates on a given poll rate in event driven contexts and scopes, like UI bindings, and at the scan class rate in expression tags.
ramp(pollRate, target, rampRate [, revRampRate [, accel]]) returns Double
| pollRate | Milliseconds between computations, or zero to short-circuit the target to the output. Polling will cease when the output reaches the target. |
| target | Number that is the final value the expression attempts to reach. |
| rampRate | The positive or forward ramp rate, in units per second. (Not units per poll). |
| revRampRate | Optional negative or reverse ramp rate, in units per second, expressed as a positive number. Same as the positive ramp rate if omitted. |
| accel | Optional maximum change in ramp rate, in units per second squared, or zero to disable acceleration limiting. Disabled if omitted. |
Any of these values may be changed on the fly.
tags()
This function provides an alternative to a script transform when values must be retrieved for a variable list of tag paths. When the tag paths are provided in a Dataset, the return value is a Dataset, with two columns: path and value. Otherwise the return value is a list of pairs of path and value. (Where relative paths are allowed, they are expanded for the return value.)
tags(tagPaths [, timing]) returns Dataset or List
| tagPaths | This argument provides the tagpaths whose values are to be retrieved. If a dataset, its first column supplies the paths. Other columns will be ignored. Otherwise, it must be a sequence or array whose elements are the tag path strings. |
| timing | This argument controls the subscription mode and timing. When zero, no subscription is made and the tags are read with the equivalent of system.tag.readBlocking(), but with a 1000ms timeout (not adjustable). Otherwise, this integer is clipped to the range of 5 to 1000 milliseconds, and each tag is subscribed. When the first subscription value arrives, the function waits this long for more values to arrive before signalling the expression to re-execute. In this mode, the first execution always yields nulls with quality "Good, Uncertain Initial Value". The default is five milliseconds. |
qvAt()
Enhanced subscript lookup for Dataset, Lists, and Arrays. The native
lookup using the square-bracket operator discards any quality
code associated with that value in the subject. This alternative
passes the item’s specific quality, if present, as the function’s
return quality. This permits the use of isGood(), isBad(), and
related functions on the subscripted value.
qvAt(subject [, row], col OR subject, index) returns Object with quality
| subject | A Dataset, a List, or an Array. |
| row | Zero-based integer row index, applicable only when subject is a Dataset. When omitted, a zero is used. |
| col | Zero-based integer column index, or String column name, applicable only when subject is a Dataset. |
| index | Zero-based integer subscript, applicable when subject is not a Dataset. |
toolkitCtx()
There are a number of scope-specific techniques available to retrieve
an instance of Ignition’s CommonContext for advanced (and
unsupported) scripting tasks. Integration Toolkit now exposes its own
scope-specific context to scripts.
system.util.toolkitCtx() returns CommonContext
The return value is a ModuleContext subclass that corresponds to the
scope, so it behaves as a GatewayContext in gateway scope, et cetera.
Use with care!
indirectAction()
It is not safe to attach jython listeners or consumer implementations to Ignition platform APIs, as the code in the listener will cause a significant memory leak when the scripting context that created the listener is restarted. This function produces an object that performs call-time lookup of a project library function to execute a listener/consumer action, and that has been coerced into the java type required by the API.
system.util.indirectAction(functionName, proxyFor, projectName={current}) returns Object
| functionName | A dot-delimited simple name of a function in a project library script. The function must accept the number of arguments expected by the java interface targeted. |
| proxyFor | A platform API interface that defines a single non-default method to be emulated by the specified function. (Not enforced. If an interface has multiple non-default methods, they will all be funneled to the given function for execution.) |
| projectName | The project that contains the desired library script function. When omitted, the current project name is looked up and used. Or the global scripting project is used, if called outside a project in gateway scope. |
The object returned by this function proxies the target function without holding any actual jython code. It will always call the latest code version as projects are edited, making it safe for use as a long-lived API listener.
When an object has already been created with precisely the same set of
arguments, the returned object is the same as returned by the prior
call, managed in a persistent registry. It is a good idea to record
in an instance from system.util.globalVarMap that a particular listener
has been attached to an API, as many APIs will not collapse identical
listeners into a single run-time call. (The .putIfAbsent()
method of the BindableVarMap is recommended, where only a non-null
return is then attached to the API.)
runPrepInsert()
The Ignition builtin scripting function system.db.runPrepUpdate has the
unfortunate limitation of only returning 32-bit integer keys when using its
getKey=True option.
This alternative performs the same basic function as runPrepUpdate, with
an implicit getKey=True, but returns the JDBC standard’s
.getGeneratedKeys() resultset directly, as a PyDataset. This can only be
used with databases whose JDBC driver implements this method, and the actual
behavior varies by implementation. Some notes:
-
Microsoft SQL Server returns identity columns after coercion to
Double. This meansbigintcolumns must not exceed 2^53 to avoid loss of the low-order bits. Also, the returned dataset provides just one column, namedGENERATED_KEYS. When a multi-row INSERT is performed, only the last row’s key is returned. When the primary key is a GUID column, the result is a jythonNone. -
PostgreSQL returns the entire row produced by the INSERT operation, or multiple entire rows when a multi-row INSERT is performed. The returned rows have the column names and types as defined for the table. This includes UUID columns where the default value is
gen_random_uuid().
If your application calls for UUID primary keys, or has a multi-column primary key with automatic defaults, consider using a database brand that has a competent JDBC driver in this regard.
system.db.runPrepInsert(query, args, [database], [tx]) returns PyDataset
| query | A string containing the SQL to prepare. It must be an INSERT operation.
Include ? substitutions as appropriate, as used with any of
Ignition's native "Prep" query scripting functions. |
| args | A list of actual value arguments corresponding to the ?
substitution placeholders, in order. Supply an empty list if no substitutions
are used. |
| database | The name of the database connection to use. In project contexts, this may be omitted, and the project default will be used. |
| tx | An optional string identifying an open transaction. Usage is identical to
that for the native system.db.runPrepUpdate. |
This function accepts all arguments in keyword form. The skipAudit argument
found in native functions is not implemented.
runInGateway()
Numerous operations in Ignition are only possible in Gateway Scope, and will fail if attempted from the designer Script Console or from a Vision Client.
A work-around is to set up a Gateway Message Handler that will perform the
desired operation and return the result. Designer and Vision Client scopes can
use system.util.sendRequest() to invoke the message handler to perform the
desired task. A message handler could even perform function lookups by name
to multiplex through a single message handler.
The above doesn’t scale, particularly when multiple requests are needed in parallel.
The subject function is a Jython decorator that eliminates the need for a custom message handler and also handles as many parallel requests as the gateway normally would accept from any other client.
When executed in Gateway Scope, the decorator examines its environment and the decorated function to ensure that it can later be called correctly. (It must be a top level function in a Project Library Script. Not in site packages, nor a method nor any kind of nested function.) But otherwise passes the function through to the module namespace.
When executed in the Designer or a Vision Client scope, the given function is validated as in gateway scope, but the implementation is altered to perform Gateway RPC with the function arguments instead of executing locally. The matching function in gateway scope is invoked and its result (or exception) is returned to the remote caller.
Be sure to save your project before calling any such function.
system.util.runInGateway(f) returns PyFunction
| f | A Jython Function definition. Typically supplied via decorator syntax. The function must be a top level function in a project library script. |
Example:
logger = system.util.getLogger(system.util.getProjectName() + '.' + system.reflect.getModulePath())
@system.util.runInGateway
def gwLogInfof(*args):
logger.infof(*args)
The above, called as someScript.gwLogInfof(...) within the same project will
perform the logging operation in gateway scope, no matter what scope initiates
it. Be aware that arguments to RPC functions must be serializable on the network.
Objects that are intimately tied to the running JVM in which they live cannot
be delivered via RPC.
runInClient()
The subject function is a Jython decorator that eliminates the need for
a client-scope message handler, and permits multiple simultaneous messages to
execute. This is the companion function to runInGateway() that ensures the
decorated function is executed in Vision Client and/or Designer scope. Similar
to using system.util.sendMessage(...., scope='C'), broadcasting to all sessions
that have the project open, but does not require a client message handler.
Unlike .sendMessage(), this function cannot target code in other projects,
nor will it filter by user, role, or other security attributes of client sessions.
It will pop the key clientSessionId from the keyword arguments supplied to
the decorated function, and then deliver only to that Client or Designer. (Must
still be the same project.)
Note that designer delivery is a critical difference from .sendMessage, and works
in both Design and Preview modes.
A background pool of four threads is used to execute the target function in
client scope.
Users must take care to redeliver on the foreground thread via
system.util.invokeLater() if the target function will manipulate UI windows or
components.
Users must also redeliver to a custom thread pool or via
system.util.invokeAsynchronous() if four threads are insufficient for the task.
When executed in the Designer or a Vision Client scope, the decorator examines its environment and the decorated function to ensure that it can later be called correctly. (It must be a top level function in a Project Library Script. Not in site packages, nor a method nor any kind of nested function.) The decorator otherwise passes the function through to the module namespace.
When executed in Gateway Scope, the given function is validated as in client scope, but the implementation is altered to perform Push Notifications with the function arguments, instead of executing locally. The matching function in client scope is invoked. No result is expected (as there is no mechanism for returns from Push Notifications). Unexpected return values, and any other exceptions, are logged in the client diagnostics.
system.util.runInClient(f) returns PyFunction
| f | A Jython Function definition. Typically supplied via decorator syntax. The function must be a top level function in a project library script. |
rex()
This function performs a regular expression search and returns detailed results.
The return value is a list of matching results with nested lists of details.
Each nested list has length N+2, where N is the number of capturing
subexpressions. The first element is the matcher’s integer .start() index
within the source, and the second element is the complete matched text,
corresponding to the matcher’s .group(0).
The remaining elements of the nested list are the captured
subexpressions, from .group(1) to .group(N).
Optional captures that did not participate will be null.
The outer result list will be empty if the pattern did not match at all.
rex(pattern, source) returns List<List>
| pattern | A regular expression string compatible with java.util.regex.Pattern . Use embedded pattern codes to activate special matching options. |
| source | Any string to search with a matcher's .find() method. |
linesOf()
This function efficiently splits a string into a list of separate lines, using
the .lines() method of java.lang.String.
A null or an empty string yields an empty list.
linesOf(source) returns List
| source | A string, possibly containing line endings. |
parseJTime()
This function uses
DateTimeFormatter
from the java.time family of modern timezone-aware and locale-aware classes
to convert strings into Date/Time values.
The return value will be either an implementation of
TemporalAccessor,
or a java.sql.Timestamp. The latter is used when the result is an
Instant, to maximize compatibility with the rest of Ignition. See
the DateTimeFormatter documentation for a discussion of the resolving
method, and how that directs the choice of result class.
The result, when not a java.sql.Timestamp, will typically be one of
LocalDate, LocalTime, LocalDateTime, OffsetDateTime,
OffsetTime, or ZonedDateTime.
Be aware that TemporalAccessor classes are generally not supported
by the rest of Ignition, and should be treated as temporary values
within a more complex expression, or handed off to scripting.
parseJTime(pattern, source [, zone [, locale]]) returns TemporalAccessor or Timestamp
The time zone and locale arguments are optional. Both should be supplied when parsing user input.
| pattern | A string containing the date/time parsing pattern, possibly with optional sections. |
| source | A date/time string representation compatible with the given pattern. |
| zone | A time zone ID to apply to or check against the supplied date/time. |
| locale | A language/country tag customizing the parsing and/or supplying the expected month and day names. |
formatJTime()
This function uses
DateTimeFormatter
from the java.time family of modern timezone-aware and locale-aware classes
to convert Date/Time values into strings with precise control. Source values
that are subclasses of java.util.Date will be converted to java.time.Instant
before formatting.
formatJTime(pattern, source [, zone [, locale]]) returns String
The time zone and locale arguments are optional.
| pattern | A string containing the date/time formatting pattern. |
| source | An instance or subclass of `java.util.Date`, or an implementation of `TemporalAccessor`. |
| zone | A time zone ID to apply to the supplied date/time. |
| locale | A language/country tag customizing the formatting and/or supplying the proper month and day names. |