system.tag.getConfiguration and system.tag.configure

I am having a hard time understanding how getConfiguration / configure are supposed to work together in Ignition 8. For example, why does the following code fail for the simple case where I want to disable the UDT instance tag ‘T1/T2/Finst’?

(Yes I understand that I could do this directly in this simple case with something like nodes[0][‘enabled’] = False but I’m trying to build more general tools and want to have Python lists/dictionaries for the more general case)

import pprint
nodes = system.tag.getConfiguration('T1/T2/Finst', False)
print 'before = %s' % pprint.pformat(nodes)
rawInfo = {}
for key, value in nodes[0].iteritems():
	rawInfo[key] = value
rawInfo['enabled'] = False
nodes = [rawInfo]
print 'after = %s' % pprint.pformat(nodes)
system.tag.configure('T1/T2', nodes)

The result is:

before = [{u'enabled': True,
  u'name': u'Finst',
  u'parameters': {u'P1': {datatype=Integer, value=53},
                  u'P2': {datatype=Integer, value=null}},
  u'path': [default]T1/T2/Finst,
  u'tagType': UdtInstance,
  u'typeId': u'YokagawaUDTsDMWebb/FFF'}]
after = [{u'enabled': False,
  u'name': u'Finst',
  u'parameters': {u'P1': {datatype=Integer, value=53},
                  u'P2': {datatype=Integer, value=null}},
  u'path': [default]T1/T2/Finst,
  u'tagType': UdtInstance,
  u'typeId': u'YokagawaUDTsDMWebb/FFF'}]
18:18:31.717 [AWT-EventQueue-0] ERROR Scripting[util_tag] - Error converting PyTagDictionary to tag edit: 
java.lang.ClassCastException: Cannot coerce value '{
    "pathParts": [
        "T1",
        "T2",
        "Finst"
    ],
    "source": "default"
}' into type: interface com.inductiveautomation.ignition.common.tags.model.TagPath
	at com.inductiveautomation.ignition.common.TypeUtilities.coerce(TypeUtilities.java:1493)
	at com.inductiveautomation.ignition.common.TypeUtilities.coerceNullSafe(TypeUtilities.java:838)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserializePropertySafe(TagGson.java:670)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserializeProperty(TagGson.java:684)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserializeJsonObject(TagGson.java:642)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserialize(TagGson.java:566)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserialize(TagGson.java:515)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:927)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:994)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:967)
	at com.inductiveautomation.ignition.common.tags.TagUtilities.toTagConfiguration(TagUtilities.java:128)
	at com.inductiveautomation.ignition.common.script.builtin.AbstractTagUtilities.dictToTagEdits(AbstractTagUtilities.java:223)
	at com.inductiveautomation.ignition.common.script.builtin.AbstractTagUtilities.lambda$configure$0(AbstractTagUtilities.java:163)
	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:170)
	at jdk.internal.reflect.GeneratedMethodAccessor105.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:190)
	at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:541)
	at org.python.core.PyObject.__call__(PyObject.java:477)
	at org.python.core.PyObject.__call__(PyObject.java:481)
	at org.python.pycode._pyx175.f$0(<event:actionPerformed>:10)
	at org.python.pycode._pyx175.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1687)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:788)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:206)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:297)
	at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:57)
	at com.sun.proxy.$Proxy58.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)

Another case. It seems like when using system.tag.configure() to set UDT Instance data type parameters, only the Integer type is supported. The code below was run in a button, and the comments describe the result of print statements or system.tag.configure() calls.

nodes = system.tag.getConfiguration('T1/T2/Finst', False)
params = nodes[0]['parameters']
p1 = params['P1']
config = {}
config['name'] = 'Finst'
config['parameters'] = params

# Case 1: Change value of P1 to 12
p1.setValue(12)
print 'Config 1: %s' % config
# Config 1: {'name': 'Finst', 'parameters': {u'P1': {datatype=Integer, value=12}, u'P2': {datatype=Integer, value=null}}}
r = system.tag.configure('T1/T2', [config], 'm')
# Result: Works as expected, changes value of parameter P1 to 12

# Case 2: Change dataType of P1 to String
import com.inductiveautomation.ignition.common.sqltags.model.types.DataTypeClass as DataTypeClass
dataType = DataTypeClass.valueOf('String')
p1.setDatatype(dataType)
print 'Config 2: %s' % config
# Config 2: {'name': 'Finst', 'parameters': {u'P1': {datatype=String, value=12}, u'P2': {datatype=Integer, value=null}}}
r = system.tag.configure('T1/T2', [config], 'm')
# Result: Silently ignored, datatype for P1 is still Integer even though the value of r shows Good.

Finally, an attempt to set the datatype of P1 to String using the Tag Browser GUI, then use code to set the value to a string.

# Case 3: Change value of P1 to 'abc'
# [Change configuration of P1 to be String type using GUI before running this.]
p1.setValue('abc')
print 'Config 3: %s' % config
# Config 3: {'name': 'Finst', 'parameters': {u'P1': {datatype=String, value=abc}, u'P2': {datatype=Integer, value=null}}}
r = system.tag.configure('T1/T2', [config], 'm')
# Result: Exception:
16:16:57.475 [AWT-EventQueue-0] ERROR tags.json - Error parsing value. Data type: Integer, value: "abc"
java.lang.NumberFormatException: For input string: "abc"
	at java.base/java.lang.NumberFormatException.forInputString(Unknown Source)
	at java.base/java.lang.Long.parseLong(Unknown Source)
	at java.base/java.lang.Long.parseLong(Unknown Source)
	at com.inductiveautomation.ignition.common.gson.JsonPrimitive.getAsLong(JsonPrimitive.java:242)
	at com.inductiveautomation.ignition.common.tags.config.TagGson.deserializeValue(TagGson.java:825)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$ParameterValueTypeAdapter.deserialize(TagGson.java:234)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$ParameterValueTypeAdapter.deserialize(TagGson.java:212)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:927)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:994)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.deserialize(TreeTypeAdapter.java:162)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$ParameterTypeAdapter.deserialize(TagGson.java:189)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$ParameterTypeAdapter.deserialize(TagGson.java:155)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:927)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:994)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.deserialize(TreeTypeAdapter.java:162)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserializeProperty(TagGson.java:682)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserializeJsonObject(TagGson.java:642)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserialize(TagGson.java:566)
	at com.inductiveautomation.ignition.common.tags.config.TagGson$PropertySetTypeAdapter.deserialize(TagGson.java:515)
	at com.inductiveautomation.ignition.common.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:927)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:994)
	at com.inductiveautomation.ignition.common.gson.Gson.fromJson(Gson.java:967)
	at com.inductiveautomation.ignition.common.tags.TagUtilities.toTagConfiguration(TagUtilities.java:128)
	at com.inductiveautomation.ignition.common.script.builtin.AbstractTagUtilities.dictToTagEdits(AbstractTagUtilities.java:223)
	at com.inductiveautomation.ignition.common.script.builtin.AbstractTagUtilities.lambda$configure$0(AbstractTagUtilities.java:163)
	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:170)
	at jdk.internal.reflect.GeneratedMethodAccessor69.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:190)
	at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:541)
	at org.python.core.PyObject.__call__(PyObject.java:494)
	at org.python.core.PyObject.__call__(PyObject.java:498)
	at org.python.pycode._pyx295.f$0(<event:actionPerformed>:26)
	at org.python.pycode._pyx295.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1687)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:788)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:206)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:297)
	at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:57)
	at com.sun.proxy.$Proxy58.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)