Batch Detatch & SaveAsCentral (Non-Editable Worksets)

I´m building a python node on top of Batch Upgader (Detach From Central) to open a number of files as detached, then SaveAsCentral with another name.

The issue from the original code I want to overcome is: all workset become editable with myself as owner.
fd

To overrcome the issue I´m trying to:

  1. use a collector to get the list of worksets
  2. convert the python list into an icollection of WorksetID
  3. finally make use of WorksharingUtils.CheckoutWorksets and toggle the workset editability
  4. all of the above in the loop that opens, detaches, renames, saves, closes.

Despite the script running without errors, worksets are still editable and owened by me.

Posting my code below (apologies for formatting…first time here). What am I doing wrong?

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

>#import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

>doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

>#Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

>clr.AddReference("System")
from System.Collections.Generic import List

>#collect inputs
if isinstance(IN[0], list):
	files = IN[0]
else:
	files = [IN[0]]

>pDir = IN[1]
nPrefix = IN[2]
Originator = IN[3]

>#define originator split
splitPath = 1 + len(pDir)
splitA = splitPath + nPrefix
splitB = splitA + len(Originator)

>#save&worksharing options
options = OpenOptions()
options.DetachFromCentralOption = DetachFromCentralOption.DetachAndPreserveWorksets

>worksharingOptions = WorksharingSaveAsOptions()
worksharingOptions.SaveAsCentral = True

>SaveOptions = SaveAsOptions()
SaveOptions.SetWorksharingOptions(worksharingOptions)

>allPaths=[]

>#run through all files
for file in files:
	
	#Detatch
	modelpath = FilePath(file)
	newdoc = app.OpenDocumentFile(modelpath,options)
	
	#CloseWorksets
	collector = FilteredWorksetCollector(newdoc).OfKind(WorksetKind.UserWorkset)
	
	iDs = [c.Id for c in collector] #python list
	wsIds = List[WorksetId](iDs) #convert to icollection
	wsClose = WorksharingUtils.CheckoutWorksets(newdoc,wsIds)
	
	#Rename
	newfile = file[:splitA] + Originator + file[splitB:]  
				
	#SaveAsCentral
	newdoc.SaveAs(newfile,SaveOptions)
	
	newdoc.Close(False)
	allPaths.append(newfile)

OUT = allPaths

If you were to do this manually, you would have to sync after saving to relinquish the worksets. This is because you have to own each workset on initial creation in a central file. Just because you’re doing this programmatically doesn’t mean that Revit will perform things differently.

Try adding a Sync after saving, and note that you will need to set the options for relinquishing ownership as you do so.

A breadcrumb: SynchronizeWithCentralOptions Members

very much helpful Jacob, thanks!

As I do not know the “theory” behind, are you pointing out to relinquish all attributes - correct? or is it just the UserWorkset?

sth like

tOptions = TransactWithCentralOptions()

rOptions = RelinquishOptions(False)
rOptions.StandardWorksets = True
rOptions.ViewWorksets = True
rOptions.FamilyWorksets = True
rOptions.UserWorksets = True
rOptions.CheckedOutElements = True

sOptions = SynchronizeWithCentralOptions()
sOptions.SetRelinquishOptions(rOptions)
sOptions.Compact = True
sOptions.SaveLocalBefore = True
sOptions.SaveLocalAfter = True

to then parse this line right before the close, as you say?

newdoc.SynchronizeWithCentral(tOptions,sOptions)

I think it would require relinquish all to be set to ‘true’. You don’t want to own anything when you’re done after all. :slight_smile:

2 Likes

amazing @JacobSmall ! sync after save with relinquish all just did the trick

attached final script (with rationalized inputs)

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

clr.AddReference("System")
from System.Collections.Generic import List

# collect inputs
if isinstance(IN[0], list):
	files = IN[0]
	filenames = IN[2]
else:
	files = [IN[0]]
	filenames = [IN[2]]

newPath = IN[1]


#shortings and options
options = OpenOptions()
options.DetachFromCentralOption = DetachFromCentralOption.DetachAndPreserveWorksets

worksharingOptions = WorksharingSaveAsOptions()
worksharingOptions.SaveAsCentral = True

SaveOptions = SaveAsOptions()
SaveOptions.SetWorksharingOptions(worksharingOptions)

tOptions = TransactWithCentralOptions()

rOptions = RelinquishOptions(False)
rOptions.StandardWorksets = True
rOptions.ViewWorksets = True
rOptions.FamilyWorksets = True
rOptions.UserWorksets = True
rOptions.CheckedOutElements = True

sOptions = SynchronizeWithCentralOptions()
sOptions.SetRelinquishOptions(rOptions)
sOptions.Compact = True
sOptions.SaveLocalBefore = True
sOptions.SaveLocalAfter = True

allPaths=[]

#run through all files
for file,filename in zip(files,filenames):
	
	#Detatch
	modelpath = FilePath(file)
	newdoc = app.OpenDocumentFile(modelpath,options)
	
	#CloseWorksets
	collector = FilteredWorksetCollector(newdoc).OfKind(WorksetKind.UserWorkset)
	
	#iDs = []	
	iDs = [c.Id for c in collector] #python list
	wsIds = List[WorksetId](iDs) #convert to icollection
	wsClose = WorksharingUtils.CheckoutWorksets(newdoc,wsIds)
	
	#Rename
	newfile = newPath +"\\"+ filename
				# + version + ".rvt"
				
	#SaveAsCentral
	newdoc.SaveAs(newfile,SaveOptions)
	newdoc.SynchronizeWithCentral(tOptions,sOptions)
	newdoc.Close(False)
	allPaths.append(newfile)

OUT =  allPaths

Kudos to @stillgotme and @brunocassol as the breadcrumb lead me to the excellent opening&closing of multiple models in background while completeing a set of tasks

2 Likes