System.tag.configure with dataset tag

Hi,

I have a script that tries to get the configuration from a dataset memory tag with system.tag.getConfiguration(), then modify the configuration and then write the changes back to the tag with system.tag.configure().

However I get an [Error_Configuration] when trying to write the modified configuration back to the dataset tag.
I even get an [Error_Configuration] when trying to write an unmodified configuration back to the tag?

Is there some limitation with system.tag.getConfiguration()/system.tag.configure() when it comes to dataset tags?

Thanks

I dont know of any limitations.
https://docs.inductiveautomation.com/display/DOC81/system.tag.configure

Have you tried running it in the script console? might help you debug it. Show us the full error message and code?

I am running it in the script console. You can easily make the same test.

c1 = system.tag.getConfiguration('[Provider]Folder/Tag')
print system.tag.configure('[Provider]Folder/',c1,'o')

The output console just says ‘[Error_Configuration]’?

If I do the same test with a tag that isn’t a dataset tag the operation succeeds with ‘[Good]’ in the output console.

Hm that works for me tho, are you sure the path’s to the tags are correct?

Ah it seems if there is data in the dataset i get the error too let me check
yeah so running

c1 = system.tag.getConfiguration('[default]Project/New Folder/Dataset', True)
del c1[0]['value']
print system.tag.configure('[default]Project/New Folder/',c1,'o')

works but then you lose the dataset so you will have to add it back after i guess… weird

c1 = system.tag.getConfiguration('[default]Project/New Folder/Dataset', True)
print (c1[0]['value'])
value = c1[0]['value']
del c1[0]['value']
print system.tag.configure('[default]Project/New Folder/',c1,'o')
system.tag.write('[default]Project/New Folder/Dataset',value)

I’m pretty sure we bumped into the same thing in Ignition 8.1.7. I whittled it down to a simple test case.

If I have a dataset stored in a tag at [default]sandbox/testds, this code will work:

src_path = '[default]sandbox/testds'
dst_path = '[default]sandbox'
dst_name = 'goodds'
src_config = system.tag.getConfiguration(src_path, False)[0]
dst_config = dict()
dst_config['valueSource'] = src_config['valueSource']
dst_config['dataType'] = src_config['dataType']
dst_config['name'] = dst_name
dst_config['value'] = src_config['value']
dst_config['tagType'] = src_config['tagType']
system.tag.configure(dst_path, [dst_config], 'a')

But this code will fail:

src_path = '[default]sandbox/testds'
dst_path = '[default]sandbox'
dst_name = 'badds'
src_config = system.tag.getConfiguration(src_path, False)[0]
for x in src_config:
  if x not in ['valueSource', 'dataType', 'name', 'value', 'tagType']:
    src_config.pop(x)
src_config['name'] = dst_name
system.tag.configure(dst_path, [src_config], 'a')

The error is the same as others have shown:

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: java.lang.Boolean. Forgot to register a type adapter?
	at com.inductiveautomation.ignition.common.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:73)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:69)
	at com.inductiveautomation.ignition.common.gson.TypeAdapter$1.write(TypeAdapter.java:191)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
	at com.inductiveautomation.ignition.common.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97)
	at com.inductiveautomation.ignition.common.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
	at com.inductiveautomation.ignition.common.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127)
	at com.inductiveautomation.ignition.common.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245)
	at com.inductiveautomation.ignition.common.gson.internal.bind.ObjectTypeAdapter.write(ObjectTypeAdapter.java:107)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
	at com.inductiveautomation.ignition.common.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:208)
	at com.inductiveautomation.ignition.common.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:145)
	at com.inductiveautomation.ignition.common.gson.Gson.toJson(Gson.java:704)
	at com.inductiveautomation.ignition.common.gson.Gson.toJson(Gson.java:683)
	at com.inductiveautomation.ignition.common.gson.Gson.toJson(Gson.java:638)
	at com.inductiveautomation.ignition.common.gson.Gson.toJson(Gson.java:618)
	at com.inductiveautomation.ignition.common.config.PyTagDictionary.toTagConfiguration(PyTagDictionary.java:122)
	at com.inductiveautomation.ignition.common.config.PyTagDictionary.toTagConfiguration(PyTagDictionary.java:163)
	at com.inductiveautomation.ignition.common.script.builtin.AbstractTagUtilities.dictToTagEdits(AbstractTagUtilities.java:191)
	at com.inductiveautomation.ignition.common.script.builtin.AbstractTagUtilities.lambda$configure$0(AbstractTagUtilities.java:154)
	at java.base/java.util.stream.ReferencePipeline$7$1.accept(Unknown Source)
	at java.base/java.util.Iterator.forEachRemaining(Unknown Source)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
	at java.base/java.util.stream.ReferencePipeline.collect(Unknown Source)
	at com.inductiveautomation.ignition.common.script.builtin.AbstractTagUtilities.configure(AbstractTagUtilities.java:154)
	at jdk.internal.reflect.GeneratedMethodAccessor58.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:188)
	at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:539)
	at org.python.core.PyObject.__call__(PyObject.java:515)
	at org.python.core.PyObject.__call__(PyObject.java:519)
	at org.python.pycode._pyx168.f$0(<input>:18)
	at org.python.pycode._pyx168.call_function(<input>)
	at org.python.core.PyTableCode.call(PyTableCode.java:171)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1614)
	at org.python.core.Py.exec(Py.java:1658)
	at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:276)
	at org.python.util.InteractiveInterpreter.runcode(InteractiveInterpreter.java:131)
	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:605)
	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:593)
	at java.desktop/javax.swing.SwingWorker$1.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.desktop/javax.swing.SwingWorker.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)

I’m confused as to what is different between the bad sample versus the good sample.

EDIT: And this one will work:

src_path = '[default]sandbox/testds'
dst_path = '[default]sandbox'
dst_name = 'newds'
src_config = system.tag.getConfiguration(src_path, False)[0]
dst_config = dict(src_config)
for x in dst_config:
  if x not in ['valueSource', 'dataType', 'name', 'value', 'tagType']:
    dst_config.pop(x)
dst_config['name'] = dst_name
system.tag.configure(dst_path, [dst_config], 'a')
1 Like

Looks like the magic combination is to make a new dict to hold the config and to drop the path entry from the dict when copying it, although I prefer to drop all the fields I don’t expect/need.

But why?

2 Likes