Cannot use .update() to change key value pairs in ObjectWrapper type

Ignition Version 8.1.17

I have a Tree component in perspective that I'm using to allow users to modify what items are available in dropdowns in another interface. Each item in the tree has an 'ItemData' dictionary in the 'data' key of the item.

I'm able to add to the tree item's 'items' key utilizing .append(), however I am unable to modify the dictionary that is present in the item's 'data' key using .update().

Searching the forums yielded this post, but it appears they were trying to modify an object wrapper in a different way.

Message handler to append item to tree at selected level:

	logger = system.util.getLogger('OEE Management - Gen Management')
	
	itemType = payload['Type']
	itemIsSecondaryType = payload['Secondary']
	logger.info(str(itemType))
	
		
	treeStructure = self.view.custom.Data.ModifiedTree
	selection = self.getChild("FlexContainer_Body").getChild("FlexContainer_Selection").getChild("Tree").props.selection[0]
	self.addToTree(treeStructure, selection, itemType, itemIsSecondaryType)

calls this custom method:

	
	tmpDict = treeStructureData
	iconPath = ''
	
	path = path.split("/")
	
	# If we are adding from selecting a list node we need to be in the items of the list node
	if itemType in ['Downtime List', 'Part List'] or itemIsSecondaryType:
		pathing = path
	else:
		pathing = path[:-1]
	
	# If we are adding from selecting a list node, adjust the node type
	if itemType == 'Part List':
		itemTypeToAdd = 'Part'
	elif itemType == 'Downtime List':
		itemTypeToAdd = 'Downtime'
	else:
		itemTypeToAdd = itemType
	
	itemData = {'Type':itemTypeToAdd}
	items = []
	
	# Set icons, additional data for specific items
	if itemTypeToAdd == 'Campus':
		iconPath = 'material/apartment'
		itemData.update({'ExpectedItemTypes':['Cell']})
		
	elif itemTypeToAdd == 'Cell':
		itemData.update({'ExpectedItemTypes':['Machine']})
		
	elif itemTypeToAdd == 'Machine':
		itemData.update({'ExpectedItemTypes': ['Part List', 'Downtime List']})
		items = [{'label':'Parts',
					'data':{'Type': 'Part List', 'ExpectedItemTypes':['Part']},
					'icon':{'path':'material/memory', 'color': '#869DB1', 'style':{}},
					'items':[]},
				{'label': 'Downtime',
					'data':{'Type': 'Downtime List', 'ExpectedItemTypes':['Downtime']},
					'icon':{'path':'material/new_releases', 'color': '#869DB1', 'style':{}},
					'items':[]}]
		
	elif itemTypeToAdd == 'Part':
		iconPath = 'material/memory'
		itemData.update({'ExpectedItemTypes':['Scrap']})
		
	elif itemTypeToAdd == 'Scrap':
		iconPath = 'material/assignment_late'
		itemData.update({'ExpectedItemTypes':None})
		
	elif itemTypeToAdd == 'Downtime':
		iconPath = 'material/assignment_late'
		itemData.update({'ExpectedItemTypes':None})
	
	iconData = {'path':iconPath, 'color': '#869DB1', 'style':{}}
	
	for i in pathing:
		tmpDict['expanded'] = True
		tmpDict = tmpDict['items'][int(i)]
	
	tmpDict['expanded'] = True
	tmpDict['items'].append({'label': 'New {0}'.format(str(itemTypeToAdd)),
							'expanded': False,
							'data': itemData,
							'icon':iconData,
							'items':items})

The above code works, the new tree item is added at the expected level with no issues.

The message handler to update selected tree item:

	logger = system.util.getLogger("OEE Management - Update Tree")
	itemType = payload["Type"]
	path = payload["Path"]
	field = payload["Field"]
	value = payload["Value"]
	
	treeStructureData = self.view.custom.Data.ModifiedTree
	self.updateTree(treeStructureData, path, field, value)

Which calls this custom method:

	logger = system.util.getLogger("OEE Management - Update Tree")
	
	path = path.split("/")
	tmpDict = treeStructureData

	for i in path:
		tmpDict["expanded"] = True
		tmpDict = tmpDict["items"][int(i)]
	
	#tmpDict["expanded"] = True	
	logger.info(str(tmpDict["data"]["ItemData"]))
	logger.info(str({field:value}))
	dict(tmpDict["data"]["ItemData"]).update({field:value})
	logger.info(str(tmpDict["data"]["ItemData"]))

logger output before attempting to modify:

<ObjectWrapper>: {u'ScrapCode': u'Other', u'ScrapDesc': u'General Scrap', u'ScrapShortDesc': u'Not implemented'}

Logger output showing the dictionary made from the payload for the handler:

{u'ScrapDesc': u'General Scr'}

Logger output after the .update() call:

<ObjectWrapper>: {u'ScrapCode': u'Other', u'ScrapDesc': u'General Scrap', u'ScrapShortDesc': u'Not implemented'}

Something does appear to happen on the first call of the message handler as the tree flashes, collapses, then reopens to the selected item. After the first call though, nothing else happens to the tree. I can see the log on the gateway updating with the information from each call.

I have a markdown component on the side that shows the 'data' key of the selected tree item so I can see if data is being updated. The data shown in this component does not change for the selected item, even after the handler is called.

The tree's items property is bound to a custom property on the view. This custom property is what I'm modifying with the custom methods on the root container.

This is likely just a different manifestation of the same underlying bug.
I would try refactoring your custom method so that it's a "pure" function - it takes a data structure as input and returns a modified data structure. Then assign the modified data structure back to the right component property. You may want to deep-copy the structure to "plain" Python types when it comes into your function; there's some different approaches for that floating around the forums.

You could also attempt to boil down this issue and send it in to support, which will help us get it fixed first-party.

I ended up using the sanitize tree function from this post, which seems to allow me to modify the dictionary as I was intending to.

However, the tree's 'selectionData' property doesn't seem to update after the modified data has been applied to the tree. I have to click to a different item and then back to the modified item to see the changes. Is there a way to force the tree component to refresh that property?

In regards to boiling down the issue to send to support, what would I need to do? Make a view with a tree and a button that executes a simple script to change a dictionary in the first level of the tree data?

Bumped into this today. v8.1.28.