# 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:** 3

<div class="post-metadata">

**Author:** ![nader.chinichian](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nader.chinichian/32/9261_2.png) [@nader.chinichian](https://forum.inductiveautomation.com/u/nader.chinichian)\
**Post date:** [November 7, 2022, 8:23am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/41 "2022-11-07T08:23:14Z")

</div>

Hi Paul,

Can you also add simple web socket server in the extensions?  
You can use system.util.getGlobals() to pass data to perspective.

---

<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:** [November 7, 2022, 5:38pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/42 "2022-11-07T17:38:18Z")

</div>

Probably not as part of Ignition Extensions, but I might put up a standalone example module to do that at some point in the future.

---

<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:** [November 9, 2022, 8:41pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/43 "2022-11-09T20:41:22Z")

</div>

> [@bkarabinchak.psi](#):
>
> `newDs = sytem.dataset.buildDS(['colName1','colName2',..],[int,str,...])` where the python typing of `int` maps to `java.lang.Integer`, str to `java.lang.String` etc

How about:

```python
system.dataset.builder(colName1=int, colName2=str).addRow(1, 'abc').build()

```

Too 'cute' to embed column names as keyword arguments?  
One downside is embedding column names with spaces:

```python
from collections import OrderedDict
columns = OrderedDict()
columns["Column 1"] = int
columns["Column 2"] = str
system.dataset.builder(**columns).addRow(1, 'abc').build()

```

I suppose you could call `builder()`, and then I could add setters for column names and column types to the builder object; that way you can get the terser syntax if you don't need exotic column names, but it's available if you do.

---

<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:** [November 9, 2022, 9:08pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/44 "2022-11-09T21:08:45Z")

</div>

Meh. DatasetBuilder gives you total control in a very terse package. Maybe just expose it in `system.` so we don't have to import it. (With the java class names suited to datasets for use with its colTypes method.) Its methods are chainable so one-liners are easy.

---

<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:** [November 10, 2022, 12:10am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/45 "2022-11-10T00:10:52Z")

</div>

> <https://github.com/IgnitionModuleDevelopmentCommunity/ignition-extensions/pull/16>
>
> Fixes #13 
> 
> Adds \`system.dataset.builder()\` that optionally accepts keyword ar…guments (ultimately, just exposing the Ignition builtin DatasetBuilder class more readily). Keyword arguments will be used to define the expected column names and types; Python types will be accepted, e.g. \`system.dataset.builder(a=int, b=str, c=bool).addRow(1, '2', False).build()\`.

The keyword args are optional, so you can either use `system.dataset.builder().colNames("colName").colTypes(colType)` or `system.dataset.builder(colName=colType)`.

> [@pturmel](#):
>
> With the java class names suited to datasets for use with its colTypes method.

Hmm. Are you suggesting exposing e.g. `system.dataset.String`, `system.dataset.Integer`? Or something else?

---

<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:** [November 10, 2022, 12:40am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/46 "2022-11-10T00:40:50Z")

</div>

> [@paul-griffith](#):
>
> Are you suggesting exposing e.g. `system.dataset.String`, `system.dataset.Integer`? Or something else?

Those, or the abbreviations used in CSV files. Or both. But limited to the classes in the dataset tag whitelist.

---

<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:** [November 10, 2022, 12:43am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/47 "2022-11-10T00:43:31Z")

</div>

Or maybe re-implement `.colTypes` to _ **also** _ accept strings of the simple class names or the abbreviations.

---

<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:** [November 22, 2022, 11:56pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/48 "2022-11-22T23:56:10Z")

</div>

0.6.0 available now:

> **[Release 0.6.0 · IgnitionModuleDevelopmentCommunity/ignition-extensions](https://github.com/IgnitionModuleDevelopmentCommunity/ignition-extensions/releases/tag/0.6.0)**
>
> Commits
> 
> 8cf83ca: Add dataset equality functions (fixes #14) (Paul Griffith) #15
> c483479: Expose DatasetBuilder and add kwargs for convenient instantiation (#16) (Paul Griffith) #16

Adds:

- `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:

---

<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:** [November 23, 2022, 1:05pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/49 "2022-11-23T13:05:12Z")

</div>

Great stuff @paul-griffith . The string for column types is better than my original suggestion and more consistent with what Ignition already uses.

One question re: `system.dataset.equals` vs `system.dataset.valueEquals` - first one is same columns/types/values, and the second is same rows/columns, but not type. Is it possible then for two datasets of differing row numbers to return true from `system.dataset.equals`? Just trying to understand a situation where `system.dataset.equals` would return true but `system.dataset.valueEquals` would return false and vice versa.

---

<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:** [November 23, 2022, 4:13pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/50 "2022-11-23T16:13:53Z")

</div>

The implementation of equals is literally: `return ds1 === ds2 || (columnsEqual(ds1, ds2) && valuesEqual(ds1, ds2))`

So, the only way you'd have `equals` return false but `valuesEqual` return true is if the second dataset had the same column types, rows, data, but different column _names_. I figure that's unlikely, but potentially useful.

---

<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:** [November 28, 2022, 8:06pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/51 "2022-11-28T20:06:07Z")

</div>

> [@nminchin](#):
>
> I'm sure I had an idea somewhere, but my suggestion was to add an argument into the `system.tag.getConfiguration` function to return only the config stored on the tags themselves, not from parent settings such as non-defaults configured in the UDT definition.

This was the idea I was talking about. Is it possible to add this change into the extensions module? Or at least another function to return just the non-default config on the UDT instance and not in the definition? This is a big issue when trying to script tag changes

> [@\[FEATURE\] Add option to system.tag.getConfiguration to match output of tag browser \`copy JSON\`](https://forum.inductiveautomation.com/t/feature-add-option-to-system-tag-getconfiguration-to-match-output-of-tag-browser-copy-json/62807):
>
> When you use system.tag.getConfiguration to get the configuration of UDt instances, it retrieves all non-default configuration of the UDT definition’s tags by deep recursively searching. If you compare this to the Tag Browser’s copy JSON functionality, this only copies the properties of the UDT definition tags that are overridden at face value, as well as of the name and tagType. When using getConfiguration with configure, the output from copy JSON is required otherwise you will essentially be…

---

<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:** [November 28, 2022, 8:36pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/52 "2022-11-28T20:36:58Z")

</div>

I could probably add something like `system.tag.getLocalConfiguration`? Assuming I'm understanding what you're asking for properly.

---

<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:** [November 28, 2022, 8:48pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/53 "2022-11-28T20:48:34Z")

</div>

Basically need a function to get the json exactly as the 'copy json' in the tag browser returns it. Local config sounds about right! That'd be great to have 🙂

---

<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:** [November 28, 2022, 8:49pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/54 "2022-11-28T20:49:58Z")

</div>

> <https://github.com/IgnitionModuleDevelopmentCommunity/ignition-extensions/issues/17>
>
> List of paths? Always a single path? Recursive arg? TBD
> 
> https://docs.inductiv…eautomation.com/display/DOC81/system.tag.getConfiguration

Alright, it's on the list - feel free to add any input you might have.

---

<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:** [November 28, 2022, 8:55pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/55 "2022-11-28T20:55:16Z")

</div>

Sounds good!

Coincidentally, why does the getConfiguration doco say "will _ **attempt** _ to retrieve all the tags" instead of just "will retrieve all the tags"? When would this fail?

 ![Screenshot_20221129-072332_Chrome](https://us1.discourse-cdn.com/inductiveautomation/original/3X/7/9/7929ba34b932426bbb05cb9081902319ac2ca50e.jpeg)

---

<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:** [November 28, 2022, 9:00pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/56 "2022-11-28T21:00:10Z")

</div>

Most likely, it's a verbatim transcription of what a developer sent when initially explaining the feature when 8.0.X launched that no one's ever amended.

---

<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:** [December 9, 2022, 1:22pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/57 "2022-12-09T13:22:19Z")

</div>

Recently I had to convert something to an iso format. Currnetly you would have to do it manually `system.date.format` but other date libraries (like datetime for instance) have a function `.isoformat()` since ISO is so common. So maybe that as an additional date function? Something like `system.date.isoFormat(someDate)`?

I know it's simple and only saves a handful of lines of code but we are talking about convenience functions. Just a thought. I don't know how others feel about this one.

---

<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:** [December 13, 2022, 2:05pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/58 "2022-12-13T14:05:03Z")

</div>

Sorry for the sin of double posting but I ran into a dataset one that I would love to have.

I am trying to write tests now and I have to refer to datasets that come in and get referred in my functions. In my test function I don't want to have to have to go out to the window and grab a dataset. This I guess falls under meta programming but it would be nice if we could reverse engineer any dataset into a script that creates the dataset? For example say I have a dataset

```auto
id name
=======================
1 Test1
2 Test2
3 Name1

```

Then running something like `system.datset.getScript(ds)`  
would produce

```auto
cols = ['id','name']
rows = [[1, 'Test1'], [2,'Test2'],[3,'Test3']]
ds = system.dataset.toDataSet(cols, rows)

```

so that I could then copy and paste this in to my unit test scripts.

Perhaps this is too easy to do in jython already though so maybe it's not worth it. Just throwing it out there in case others also think it would be useful.

---

<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:** [December 13, 2022, 2:37pm UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/59 "2022-12-13T14:37:15Z")

</div>

To be reliable, it would need to use DatasetBuilder. With that, python's `repr()` is your friend. I don't think you need java for this.

---

<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:** [December 14, 2022, 12:43am UTC](https://forum.inductiveautomation.com/t/ignition-extensions-convenience-utilities-for-advanced-users/64615/60 "2022-12-14T00:43:28Z")

</div>

> [@bkarabinchak.psi](#):
>
> Recently I had to convert something to an iso format

This is the _only_ datetime format I use, since it's the most logical (sorry you US folk 😆) and importantly, it's also inherently sortable 🙂 (e.g. filenames)

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

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