FWIW, I recently forgot about this and inadvertently added property overrides to a large number of UDTInstance tags So I created a script to remove the prop overrides on tags part of UDT instances that were not included in a list of property names.
The script copies the tag json back into clipboard, so you can review it first before saving as a json and importing it back in.
Main Functions
def removePropOverrides(tags, retainProps=None, tagpath='', insideUDTInstance=False):
'''
This will remove property overrides set on tags that are within UDTInstances that are not
contained within the predefined retain set, or the retain set passed into the function.
Revision History
===========
Rev Date Author Comment
1.0 2022-10-20 Nick Minchin Original
Args
===========
tags: - tag json e.g. copied into the clipboard by using the "Copy JSON" context menu option from the Tag Browser
retainProps: - a set with a list of properties to retain, for example {'writePermissions'}
tagpath: - INTERNAL USE ONLY. Keeps track of the relative tag path used to print the properties removed along with the tags they were removed from.
insideUDTInstance: - INTERNAL USE ONLY. Keeps track of whether or not the current `tags` are within a UDT instance or not. This will determine if tag props
will be removed or not.
Return
===========
Returns the modified tags as a Py object of dicts and lists
'''
fn = 'removePropOverrides()'
this = removePropOverrides
if isinstance(tags, str) or isinstance(tags, unicode):
tags = system.util.jsonDecode(tags)
if retainProps is None:
retainProps = {}
if not isinstance(retainProps, set):
retainProps = set(retainProps)
# these props should always exist and should not be removed!
retainProps.add('name')
retainProps.add('tagType')
retainProps.add('tags')
retainProps.add('value')
retainProps.add('parameters')
retainProps.add('typeId')
# remove all props not in the retain list, if the tag is within a UDTInstance
if isinstance(tags, dict):
if insideUDTInstance:
removedKeys = []
for key in tags:
if key not in retainProps:
removedKeys.append(key)
del tags[key]
if len(removedKeys) > 0:
print 'Tag: "{}", Removed keys: {}'.format(tagpath, system.util.jsonEncode(removedKeys))
# check if the tags object has child tags and run the function over these as well
if 'tags' in tags:
for tag in tags['tags']:
insideUDTInstance_ = insideUDTInstance or 'typeId' in tag
this(tag, retainProps, tagpath + '/' + tag['name'], insideUDTInstance_)
return tags
def removePropOverridesFromClipboard(retainProps=None):
'''
This is a wrapper for removePropOverrides which passes in tag json stored in the clipboard.
'''
tag_json = shared.util.clipboard.readText()
tags = removePropOverrides(tag_json, retainProps)
return tags
tags=removePropOverridesFromClipboard({'writePermissions'})
shared.util.clipboard.writeText(system.util.jsonEncode(tags))
Clipboard Functions
from java.awt.datatransfer import StringSelection
from java.awt.datatransfer import Clipboard
from java.awt import Toolkit
def setup():
global toolkit, clipboard
toolkit = Toolkit.getDefaultToolkit()
clipboard = toolkit.getSystemClipboard()
def writeText(text):
setup()
clipboard.setContents(StringSelection(text), None)
def readText():
setup()
from java.awt.datatransfer import DataFlavor
contents = clipboard.getContents(None)
return contents.getTransferData(DataFlavor.stringFlavor)
For example, the output print statements will return something like below. If you don't get anything printed, then no tags are affected.
Example Print Statement Output
Tag: "/Folder 1/Instance/Sec", Removed keys: ["deadband","opcServer"]
Tag: "/Folder 1/Instance/Month", Removed keys: ["deadband","opcServer"]
Tag: "/Folder 1/Instance/Day", Removed keys: ["dataType","opcServer","valueSource"]
Tag: "/Folder 1/Instance/Year", Removed keys: ["deadband","opcServer"]
Tag: "/Folder 1/Folder 2/Instance/Day", Removed keys: ["dataType","opcServer","valueSource"]
Tag: "/Folder 2/Instance/Day", Removed keys: ["dataType","opcServer","valueSource"]
Tag: "/Folder 2/Folder 1/Instance/Month", Removed keys: ["deadband","opcServer"]
Tag: "/Folder 2/Folder 1/Instance/Day", Removed keys: ["dataType","opcServer","valueSource"]
Tag: "/Folder 2/Folder 1/Instance/Year", Removed keys: ["deadband","opcServer"]
Tag: "/Folder 2/Folder 1/Instance/Sec", Removed keys: ["deadband","opcServer"]
Tag: "/Folder 2/Folder 1/Folder 2/Instance/Day", Removed keys: ["dataType","opcServer","valueSource"]
And if not obvious, use at your own risk. Check the output before actually importing anything! (and take a backup of your tags in case you need to revert)