# Ignition Extensions - Convenience utilities for advanced users

**URL:** <https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615>\
**Category:** 3rd Party Modules\
**Created:** [September 28, 2022, 6:41pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615 "2022-09-28T18:41:11Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 28, 2022, 6:41pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/1 "2022-09-28T18:41:11Z")

</div>

> **[GitHub - IgnitionModuleDevelopmentCommunity/ignition-extensions](https://github.com/IgnitionModuleDevelopmentCommunity/ignition-extensions)**
>
> Contribute to IgnitionModuleDevelopmentCommunity/ignition-extensions development by creating an account on GitHub.

Introducing a hopefully community-engaged effort to build a useful repository of scripting and other Ignition utilities for everyone to benefit from.

Download the latest release from the [Releases](https://github.com/IgnitionModuleDevelopmentCommunity/ignition-extensions/releases) page and take advantage of the following functions:

* * *

# Scripting Functions

## system.util

### `system.util.getContext(): Context`

A convenience function to retrieve the local "context" object, useful as an entrypoint to other advanced scripting.

### `system.util.deepCopy(object): Object`

Converts a given Python object of any type into native Python data structures - lists, dictionaries, or "primitive" values (numbers, booleans, strings).

### `system.util.evalExpression(expression, **arguments): QualifiedValue`

Evaluates the supplied string `expression` as an expression. Additional keyword arguments to the function are provided as reference values inside the expression, e.g.  
`system.util.evalExpression("{one} + {two}", one=1, two=2)`  
Any other reference inside curly braces is assumed to be a tag path.  
Returns a QualifiedValue.

* * *

## system.dataset

### `system.dataset.print(dataset, output=sys.stdout, includeTypes=False)`

Pretty-prints an Ignition dataset to the supplied buffer (or, with no argument, the local JVM standard output buffer). If `includeTypes` is True, adds the simple name of the column's type to the header.

### `system.dataset.map(dataset, mapper, preserveColumnTypes=False): Dataset`

Runs `mapper` on every row of `dataset`. `mapper` will be invoked with keyword arguments, per column in `dataset`. Return the new values for each row as a list or other sequence. This function allows you to perform multiple updates to a dataset, per-row, as a single operation.

### `system.dataset.filter(dataset, filter): Dataset`

Runs `filter` on every row of `dataset`. `filter` will be invoked with keyword arguments, per column in `dataset`. The first argument will be the row index, as an int. Return `True` to keep the column in the output, or `False` to omit it.

### `system.dataset.fromExcel(input, headerRow=-1, sheetNumber=0, firstRow=-1, lastRow=-1, firstColumn=-1, lastColumn=-1): Dataset`

Attempts to read `input` as an Excel file (either from a filepath supplied as a string, or as a byte-array already read into memory). Looks on `sheetNumber` for a contiguous dataset. Provide `firstRow`, `lastRow`, `firstColumn`, and `lastColumn` to restrict the region of cells read (if not provided, the first/last cells with data will be used). Pass a value for `headerRow` to extract column names from a particular row (outside of your data region).

### `system.dataset.equals(dataset, dataset): Boolean`

Returns True if both input datasets have the same columns, with the same types, and the same values.

### `system.dataset.valuesEqual(dataset, dataset): Boolean`

Returns True if both input datasets have the same number of rows/columns, and those rows/columns have the same values in the same places.

### `system.dataset.columnsEqual(dataset, dataset, ignoreCase=False, includeTypes=True): Boolean`

Returns True if both input datasets have the same column definitions. Use the optional keyword arguments to make the behavior more lenient.

### `system.dataset.builder(**columns): DatasetBuilder`

Returns a wrapped DatasetBuilder. Provided keyword arguments (if any) are used as column names; the values should be Java or Python types, or the 'short codes' accepted by system.dataset.fromCSV:

| alias | class |
| --- | --- |
| "byt" | byte.class |
| "s" | short.class |
| "i" | int.class |
| "l" | long.class |
| "f" | float.class |
| "d" | double.class |
| "b" | bool.class |
| "Byt" | Byte.class |
| "S" | Short.class |
| "I" | Integer.class |
| "L" | Long.class |
| "F" | Float.class |
| "D" | Double.class |
| "B" | Boolean.class |
| "O" | Object.class |
| "clr" | Color.class |
| "date" | Date.class |
| "cur" | Cursor.class |
| "dim" | Dimension.class |
| "rect" | Rectangle.class |
| "pt" | Point.class |
| "str" | String.class |
| "border" | Border.class |

In addition, the `colTypes` function can now be called with the same short codes, or common Python types (e.g. `str` instead of `java.lang.String`).

* * *

## system.project

### `system.project.getProject(): Project`

Returns the internal project object appropriate to your local scope. On the gateway and the client, this is a [`RuntimeProject`](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.21/com/inductiveautomation/ignition/common/project/RuntimeProject.html); in the designer, this will be a [`DesignableProject`](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.21/com/inductiveautomation/ignition/designer/project/DesignableProject.html) that can be directly mutated.  
Also, on the gateway, `getProject()` can be called with a single string argument to retrieve a project by name.

### `system.project.save()`

In the Designer, essentially programmatically pushes the save button.

### `system.project.update()`

In the Designer, programmatically invokes the 'Update Project' action, which pulls in changes to the local project from the gateway.

* * *

# Expression Functions

## Logic

### `isAvailable(value)`

Returns true if the provided value (i.e. a tag reference) has a quality _other than_ `Bad_Disabled` or `Bad_NotFound`.

### `anyOf(args...)`, `allOf(args...)`, `noneOf(args...)`

Logical predicates across the input arguments, interpreted as booleans. Beware [vacuous truth](https://en.wikipedia.org/wiki/Vacuous_truth#In_computer_programming) on empty lists of arguments.

* * *

# ⚠ Experimental ⚠

## system.tag

### `system.tag.getLocalConfiguration(basePath, recursive=False)`

Retrieves only the local configuration for the given tags under path, per the same browsing behavior as system.tag.getConfiguration; i.e., omits any content inherited from parent UDT(s).

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 29, 2022, 12:46am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/2 "2022-09-29T00:46:20Z")

</div>

Releases are now signed automatically, making things a lot more palatable for actual use.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [September 30, 2022, 11:33am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/3 "2022-09-30T11:33:49Z")

</div>

That sounds awesome, Paul! Super cool initiative! (same with Kindling)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 30, 2022, 7:28pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/4 "2022-09-30T19:28:30Z")

</div>

0.3.0 out now, adds `system.project` extensions.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 10, 2022, 10:53pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/5 "2022-10-10T22:53:31Z")

</div>

I already implemented it, so I might just drop it in anyways, but I just pushed a PR for an idea that someone asked for literally years ago: `system.util.evalExpression`. I'm not sure if anyone would actually find this useful, so I figure I'll ask if anyone has strong opinions.

> <https://github.com/IgnitionModuleDevelopmentCommunity/ignition-extensions/pull/7>
>
> Maybe a very silly idea. Want to see if anyone would find this useful as more th…an a curiosity before inclusion.

Usage is pretty simple; provide your expression as the first argument, and any known variables as keyword arguments; your expression can refer to them inside curly braces. Anything in curly braces that isn't a provided variable will be parsed as a tagpath.  
E.G:

```python
system.util.evalExpression("123 + {fourFiveSix} + {Realistic0}", fourFiveSix=456)

```

```auto
>>> 
[678.6929315736934, Good, Mon Oct 10 15:52:39 PDT 2022 (1665442359536)]

```

I figure this could be useful to someone trying to do testing, maybe? I think the original request I saw was something related to tag import/export.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 10, 2022, 11:05pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/6 "2022-10-10T23:05:38Z")

</div>

Will that run in a Vision Client? (I vaguely recall discovering the scaffolding was designer & gateway only.)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 10, 2022, 11:07pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/7 "2022-10-10T23:07:41Z")

</div>

This is the lower-level evaluation/parsing mechanism used throughout, so should work fine in all scopes; even in a very silly example:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/4/b47f71cc93ac33d4dd7a37cac1854fd4d76d3f0b.png)

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [October 11, 2022, 3:05am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/8 "2022-10-11T03:05:55Z")

</div>

> [@paul-griffith](#):
>
> I'm not sure if anyone would actually find this useful

I could see this being useful for building custom in-UI dataset filters.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [October 11, 2022, 12:14pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/9 "2022-10-11T12:14:59Z")

</div>

You think this would play with your simulation aids view function nicely?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 11, 2022, 12:21pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/10 "2022-10-11T12:21:50Z")

</div>

Probably.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [October 12, 2022, 11:20pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/11 "2022-10-12T23:20:20Z")

</div>

Is it possible to add a colour picker component? 🙂

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 12, 2022, 11:31pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/12 "2022-10-12T23:31:31Z")

</div>

Rejected: Insufficient specification 😉

Perspective, or Vision? What's the end goal?

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [October 12, 2022, 11:33pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/13 "2022-10-12T23:33:59Z")

</div>

Haha good answer!

Perspective  
Current use case is a css theme manager ([Style Classes using CSS properties not in Designer GUI - #14 by rbabcock](https://forum.inductiveautomation.com/t/style-classes-using-css-properties-not-in-designer-gui/64543/14) ) so I can pick a colour and copy the hex or hsla code. Thinking an hsl/rgb picker

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [October 13, 2022, 2:04am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/14 "2022-10-13T02:04:48Z")

</div>

I love this idea, however a robust perspective component is significantly more complicated than the other items in this module (because of the weird nuances of perspective). I think the best person to build this, if the time permits, is @ynejati

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 13, 2022, 2:40pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/15 "2022-10-13T14:40:56Z")

</div>

I have another idea for Perspective components, I can't remember if we talked about it at ICC; a module that does all the gateway level scaffolding, and allow you to just upload an arbitrary JS component bundle that you create however you feel like.

Unrelated idea:

> [@Best Practices for SVN/GIT on projects](https://forum.inductiveautomation.com/t/best-practices-for-svn-git-on-projects/30218/16):
>
> You are taking your chances with `system.util.execute`. I don't think it waits for the process to run, so those three commands could execute out of order. Use java's `ProcessBuilder` to ensure things are sequential (and you can check for success).

`system.util.launch`, as a wrapper around `ProcessBuilder`? Perhaps a context manager, so `with system.util.launch() as process:` works?  
Would need some input on what folks expect to be able to do with a launched process; capture stdout and stderr, certainly, but also to be able to inject arbitrary data to stdin?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 13, 2022, 2:48pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/16 "2022-10-13T14:48:25Z")

</div>

> [@paul-griffith](#):
>
> upload an arbitrary JS component

That would be neat.

> [@paul-griffith](#):
>
> `system.util.launch`, as a wrapper around `ProcessBuilder`? Perhaps a context manager

Good idea. Probably not a context manager. Definitely include pipe conveniences. Maybe an analog of python's `.communicate()` that returned a `CompletableFuture`. That would enable use of `.whenComplete()` to run asynchronously. (Satisfies my aversion to waiting in any thread.)

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [October 13, 2022, 3:10pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/17 "2022-10-13T15:10:56Z")

</div>

> [@paul-griffith](#):
>
> a module that does all the gateway level scaffolding, and allow you to just upload an arbitrary JS component bundle that you create however you feel like.

Yes we did talk about this at ICC and I think it would be very well received. The scaffolding of perspective is by far the hardest part of adding those components

---

<div class="post-metadata">

**Author:** ![ynejati](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ynejati/32/6093_2.png) [@ynejati](https://forum.inductiveautomation.com/u/ynejati)\
**Post date:** [October 14, 2022, 3:23pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/18 "2022-10-14T15:23:35Z")

</div>

😄

What am I building? A color picker? Sorry, I lost the thread.

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [October 14, 2022, 3:34pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/19 "2022-10-14T15:34:20Z")

</div>

Whatever you feel like man! However the specific item someone requested was a color picker.

I just knew that you were the expert on perspective components so I threw you under the bus! Lol

---

<div class="post-metadata">

**Author:** ![ynejati](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ynejati/32/6093_2.png) [@ynejati](https://forum.inductiveautomation.com/u/ynejati)\
**Post date:** [October 14, 2022, 3:48pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/20 "2022-10-14T15:48:44Z")

</div>

Ha! I'm flattered.

If that's what we are talking about, we have a ticket for this, as a standalone thing. I'm glad you guys brought it up though, since we have some new devs starting this month, and this could be a good one to start them off with.

Also, when the new Form component is implemented (next component in queue), you will be able to select a color picker as an input type when you build out your forms. So, it will be available there as well.

It would be super easy to build one yourself if you wanted to, since its part of the HTML spec, and is implemented by most if not all browsers (I think).

> **[\- HTML: HyperText Markup Language | MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/color)**
>
> elements of type color provide a user interface element that lets a user specify a color, either by using a visual color picker interface or by entering the color into a text field in #rrggbb hexadecimal format.

We'll take this component into consideration. Thanks for the suggestion!

[Next page](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615.md?page=2)
