Overwrite tag folder using system.tag.configure

I am trying to, by script, delete many tags on my production gateway (>500 tags). While I’m doing this I’d like to leave a few (<10 tags) in place because their history is being plotted, and I don’t want to lose it.

I’ve gone through and deleted all the tags I don’t want on my development gateway, leaving only the tags I want to be preserved. I copied the JSON representation of the top-level folder to a file. I thought the following script would remove all the tags I don’t want (that aren’t present in the JSON string). It isn’t. Can anyone help me understand why?

asdf = [
	['','%pathWhereISavedTheJsonString%']
]

def configTags(params):	
	tagExport = system.file.readFileAsString(params[1])
	system.tag.configure(
		params[0],
		tagExport,
		'o'
	)
for i in asdf:
	configTags(i)

The script will add tags that are missing, but it won’t remove the extra tags like I thought the Override collision policy would.

Veering slightly off-topic: I could delete the whole folder then re-import my configuration which I’m pretty confident would leave me with only the tags I want, but I’m concerned that I would lose the history when I delete the tags. Does anyone know if this is true?

Ignition V8.1.17

Perhaps try using system.tag.deleteTags? You could get a list of the 10ish tag paths that you want left, then browse all the tags and delete any tag whose tag path isn’t on the list.

Simply deleting the root and importing the config would be the easiest option, but I’m not completely sure whether that messes with the id columns in the historian. I’d imagine it would be fine because the tag path would stay the same…

For the future:
I still don’t know why the overwrite collision policy doesn’t delete tags that aren’t present in the provided configuration, but this script accomplished my goal. I’m sure this could be improved in any number of ways, but it may serve as a starting point for someone else.

If you’re going to use this for anything, please test it thoroughly.

def findTagsToDelete(configuration, preserveTagPaths, pathRoot='', currentDepth=0):
	tagsToDeleteSoFar=[]
	# Need to keep track of the whole path of the tag.
	if pathRoot!='':
		concatChar = '/'
	else:
		concatChar = ''
	pathRoot=str(pathRoot)+concatChar+str(configuration['path'])
	# Recursion scares me so I like to put checks in place.
	# If you've got more than 15 levels of nested folders you may need to change this
	maxDepth = 15
	if currentDepth>maxDepth:
		print 'Maxiumum Depth Reached'
		raise
	# If tag is a folder, and it has tags, recurse for each child tag.
	# If tag is a folder and it has not tags, delete the folder.
	if str(configuration['tagType'])=='Folder':
		try:
			tagsConfig=configuration['tags']
		except KeyError:
			tagsToDeleteSoFar.append(pathRoot)
			return tagsToDeleteSoFar
		if len(tagsConfig)>0:
			currentDepth+=1
			for i in configuration['tags']:
				moreTagsToDelete = findTagsToDelete(i,preserveTagPaths,pathRoot,currentDepth)
				tagsToDeleteSoFar.extend(moreTagsToDelete)
		else:
			tagstoDeleteSoFar.append(pathRoot)
			return tagsToDeleteSoFar
	# If tag is not a folder, determine if it it in the list of tags to be preserved.
	# If not in the preserve list, add it to the delete list.
	else:
		if pathRoot not in preserveTagPaths:
			tagsToDeleteSoFar.append(pathRoot)
			return tagsToDeleteSoFar
	return tagsToDeleteSoFar
# tags I want to preserve.
preserveTags = [
	'[default]tagFolder/tagToSave1',
	'[default]tagFolder/tagToSave2',
	'[default]tagFolder/tagToSave3'
]
# perform multiple passes because deleting this many tags will create empty folders
# these folders will be deleted on subsequent passes. There is definitely a more elegant
# way to accomplish this, but it's wicked fast and serves my need today.
passes=0
while True:
	passes+=1
	if passes>100:
		break
	dcsVibmonTags = system.tag.getConfiguration('folderToOverwrite',1)[0]
	asdf = findTagsToDelete(dcsVibmonTags, preserveTags)
	if len(asdf)<1:
		break
	system.tag.deleteTags(asdf)
1 Like

Disclaimer: I'm not an expert on the tag system

I think this is because the collision policies are considered with individual tags, rather than being defined by particular folders. Folders are basically created implicitly (by virtue of tag(s) being defined with a parent path), rather than being explicit nodes to have their own collision rules. So the collision policy you choose just doesn't really affect things here.

1 Like

Couldn’t you just copy/paste your development tags to the prod ? Or import ?

Maybe. The tags already exist in production and I want to remove most of them. Someone went a little crazy dragging folders in from the OPC browser, and we don’t use most of the tags that are in the tree, so I’m house-cleaning (to the tune of 1500 tags all subscribed at 1 second).

Of the tags I’m keeping, some are tracked by the historian, and I don’t want those tags to be retired in the historian system because I want the trends to continue uninterrupted. Maybe I could have deleted all the tags and imported the ones I want to keep, but I wasn’t sure how that would impact historian continuity. I assume that trying to import tags would have encountered the same problem as system.tag.configure (you can add but not delete tags), but I admit I didn’t try it.