I tried to rename a list of assemblies of revit with python code, it should work fine but I noticed some of the assemblies have been renamed the same, which doesn’t follow my input list, therefore a revit window asks me to delete one of the repeated assemblies.
I wonder if that name that is duplicated had similar name before renaming with script and then skips the script? Or maybe i ran before the script and revit remember old assemblies name?
I don’t understand Revit behaviour but I want to force to rename the assemblies as the input list of names I provide.
I used transaction force close start and done as well as i saw in this forum by @c.poupin but this time is awful
Maybe someone had similar experience and know how to force Revit to do the task?
Incorporate a check by getting all assemblies (not just those checked), and pulling the names of each into a list early on the code (right after the imports). Then you can proceed with renaming, but as you iterate over the list check if your desired name is already in use, and if so append an integer to the end and check if that name is in the list. If so, increment it again and again until you get a valid and unique name. Consider a hard stop after 10 or so tests to prevent infinite looping issues, where if the increment hits 10 you just pass to the next name, appending an error message to the out list. Once you have the unique name you can just proceed with renaming.
I don’t use assemblies anymore, but a few years ago I used a Dynamo graph with the following steps. It is useful to mention here that I made an assembly for each individual product (not a group of products).
Select the products of which an assembly is to be made.
Filter this list by unique products (first of each sublist), and duplicate products (remainder of each sublist).
Create an assembly (Tool.CreateAssembly from Steamnodes) for each of the unique products.
Rename each of these assemblies as desired (Assembly.Modify.RenameAssemblyInstances from Steamnodes).
Create the desired assembly views for each of these assemblies (Tool.AssemblyViews from Steamnodes).
Use a wait node (on the list of duplicate products) to ensure that steps 3 to 5 are completed.
Create an assembly (Tool.CreateAssembly from Steamnodes) for each of the duplicate products.
The assemblies for the duplicate products automatically inherit the correct/same name as the unique products.
Can you post a .rvt with a few assemblies in it? I haven’t worked with them before so it’d be pretty time consuming to rebuild, and this would ensure we’re looking at the same version. Left to my own devices i’d develop for 2024 which may or may not work for older builds.
Get names of all potential duplicate name candidates (all assemblies in this case). Can be done after step 3 also technically if you want to ignore name clashes for renamed assemblies
Pre-rename them by adding their Id to the end, making them suredly unique
Try to rename them again with intended names, checking firstly if the name exists in the assembly names in the model. If it does, rename it with intended name and its element id for post review. If it doesnt, rename. As you go, build a list of rename outcomes to also check renaming against
All duplicates should end up with a unique name, and any duplicates can be reviewed if their id is on the name afterwards.
I realised the problem is not the code for rename assembly types, it works!, the problem is that one assembly type has 2 assembly instances and one of them cannot be renamed different than the other because the name is defined in the type and not in the instance.
Something weird that I do not understand is happening when creating the assemblies with script that I have to investigate. I was sure the script before renaming was creating one assembly type with one assembly instance!
This code will throw a warning and exit the Python environment if an assembly name is already in the document, or if one of the provided names is used twice. The python node will be in a warning state once executed when this happens, and no further processing will occur and as such the assemblies are not renamed. If both tests pass then the assemblies will be renamed. This prevents partial renaming, but will throw an error in automatic run mode (at least in 2024) as the names will be set and then the graph will attempt to re-run.
#####################################################
############# Configure the environment #############
#####################################################
import clr
from System.Collections.Generic import List as cList
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
#####################################################
############ global variables and inputs ############
#####################################################
doc = DocumentManager.Instance.CurrentDBDocument
all_AssemblyTypes = [ e for e in FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Assemblies).WhereElementIsElementType().ToElements() ] #get all the assembly types from the document
usedAssemblyNames = list(set([i.get_Name() for i in all_AssemblyTypes])) #get the unique assembly names from the list of assembly types
assemblies = UnwrapElement(IN[0]) #the list of assemblies to rename from the Dynamo environment
desiredNames = IN[1] #the list of names to try from the Dynamo environment
#####################################################
#### Test if the provided names are valid to use ####
############## in the current document ##############
#####################################################
namesProviedTest = len(desiredNames) == len(set(desiredNames)) #ensure the names provided are unique
if not namesProviedTest: sys.exit("\r\rThe provided names are not unique. Please rename and try again.\r\r") #throw a warning and exit the python environment if any name is reused
namesAlreadyUsed = [name for name in desiredNames if name in usedAssemblyNames] #get the list of names which are already in the document
if not len(namesAlreadyUsed) == 0: sys.exit("\r\rThe following names are already in use:\r\t{0}\r\r".format("\r\t".join(namesAlreadyUsed))) #throw a warning and exit the python environment if a name was already used.
#####################################################
############### rename the assemblies ###############
#####################################################
TransactionManager.Instance.EnsureInTransaction(doc) #start a transaction to modify the document
for assembly,name in zip(assemblies, desiredNames): #start a list of assemblies
assembly.AssemblyTypeName = name #set the assembly's name property to the given name
TransactionManager.Instance.TransactionTaskDone() #commit the transaction
OUT = [ [ assembly,assembly.AssemblyTypeName ]for assembly in assemblies]
If you are having issues with multiple assemblies of the same type, I recommend grouping the assemblies by the element id of their type first, then getting the first instance from each group and passing that into the code to rename.
thanks very much, I learnt from this response, but the script does not resolve the problem because it renames the assembly types and not the assembly instances, so I identified unfortunately the problem is that the script that I used did not create one assembly type with one assembly instance, it created less assembly types but more than one assembly instance by assembly type, so if one assembly type has 3 assembly instances, script is renaming the 3 assembly instances the same than the assembly type.
I do not understand the logic of Revit on this, I was expecting the script createas one assembly type by each sublist of IN[0], but I do not why I do not have one assembly type by each sublist of IN[0], but more than one assembly instance by assembly type created by the script!
This is the code I used, I believe it is a weird thing with the category id of the assembly type. I am testing on Revit 2019 and Revit 2020.
import clr
from System.Collections.Generic import *
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from System import Array
doc = DocumentManager.Instance.CurrentDBDocument
element_array = UnwrapElement(IN[0])
assembly_names = IN[1]
# get elements ids and assembly categories
ids = [[elem.Id for elem in arr] for arr in element_array]
# create list of element id lists
idlist = [List[ElementId](sublist) for sublist in ids]
# create assemblies for each sublist
assembly_list = []
TransactionManager.Instance.EnsureInTransaction(doc)
for i, sublist in enumerate(idlist):
category_id = doc.GetElement(sublist[0]).Category.Id
assembly_instance = AssemblyInstance.Create(doc, sublist, category_id)
assembly_list.append(assembly_instance)
TransactionManager.Instance.TransactionTaskDone()
OUT = assembly_list
It is the same principle as with Families.
For example, you loaded a list of Families into your project.
These Families each have one or more FamilyTypes.
You can place these FamilyTypes several times in your project, these are then the FamilyInstances. These FamilyInstances also inherit the host Family name and chosen FamilyType. If you change the name of one of the FamilyInstances, you will see that this also happens for the other FamilyInstances. In other words, you do not change the name of a FamilyInstances, but of the corresponding FamilyType.
If you still want to make a distinction, you will have to store unique sub-brands in instance parameters.
I know that, but he problem that I do not have created some Assembly Types that I was expecting the script will create, so my input names to rename makes no sense because some does not exist!
The error in the previous code is a separate question, so best to break it into a new topic so others might find this for renaming, and the new topic for creating.
As far as why two are identical, what happens if you make assemblies of these manually via the UI - do they share the same type? I don’t have a model to test on and I’m not an expert with assemblies so it’s hard for me to know one way or another.
For reference I just created 3 separate assemblies all of the same type by creating assemblies from a selection of walls. If the assembly is the same members with the same transforms and geometry then they share the same type, and you only have one to rename.
Because the assemblies themselves don’t have a name (but the types do) you can only rename the type. You could set another parameter to a unique value (ie: the mark), but name does not exist.
I saw the coincidence that where the assembly instances that are packed in same assembly type, they are composed by the same families with same orientation, but in other location of the project, so how to force to be each assembly instance to be in independent assembly type is the question. the codes shared for renaming work well so that was already resolved. I created new post to continue this: How to force Revit to create each assembly instance with separate assembly type