Assembly Creation/Renaming

Hello, I’m trying to create a script with Pyrevit where I select several elements to create an Assembly (more specifically a column, rebar, and concrete corbels - which are families of structural framing).

When I create the assembly manually, the type name is required along with the naming category, and it is done correctly [image]. However, with my code, the assembly is generated correctly, but when I try to rename it with AssemblyTypeName, I get the following error: Exception: No valid type for the assembly instance.

Does anyone know what I can do to solve this? Here’s my code.

# -*- coding: utf-8 -*-

from Autodesk.Revit.DB import *
from System.Collections.Generic import List
from Autodesk.Revit.UI.Selection import *
from pyrevit import script, DB

doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument
output = script.get_output()

# seleção de elementos da montagem

elements_ids = List[ElementId]()

references = uidoc.Selection.PickObjects(ObjectType.Element)

for reference in references:
    element = doc.GetElement(reference)
    elements_ids.Add(element.Id)

pillar_id = None

for id in elements_ids:
    element = doc.GetElement(id)
    if element.Category and element.Category.Id.IntegerValue == int(
        BuiltInCategory.OST_StructuralColumns
    ):
        pillar_id = id
        break

pillar = doc.GetElement(pillar_id)

with Transaction(doc, "Criar montagem") as t:
    t.Start()
    assembly = AssemblyInstance.Create(doc, elements_ids, pillar.Category.Id)
    assembly.AssemblyTypeName = "Novo nome"
    t.Commit()

Hi, after some testing, I discovered what was causing the error.

Apparently, when initializing a transaction like the one I was doing, Revit doesn’t create the entity immediately, but rather provisionally. This can be determined by doing “assembly.GetTypeId()” inside the transaction, which will return “-1”, because the API doesn’t yet have a “type” associated with the newly created element. The solution is basically to isolate a transaction for each action (a bit obvious), to ensure that the manipulated elements actually exist in the project.

I’ll keep the post open in case anyone else has problems with transactions, since it’s common to use only one transaction throughout the script, even though it’s bad practice in many contexts.

2 Likes

You might also look at subtransactions to manage this. They let you better control the rollback and undo.

1 Like

pyRevit has a lot of wrappers and utility functions, that help you keep the code more readable and maintainable. Like so (untested!)

# -*- coding: utf-8 -*-

from pyrevit import script, revit, DB
from pyrevit.compat import get_elementid_value_func

get_elementid_value = get_elementid_value_func()  # in case you want to use it in Revit > 2024

doc = revit.doc
output = script.get_output()

# seleção de elementos da montagem

pillar_id = None

elements = revit.pick_elements()

for element in elements:
    if element.Category and get_elementid_value(element.Category.Id) == int(
        DB.BuiltInCategory.OST_StructuralColumns
    ):
        pillar_id = id
        break

pillar = doc.GetElement(pillar_id)

with revit.Transaction("Criar montagem"):
    assembly = DB.AssemblyInstance.Create(doc, elements, pillar.Category.Id)
    assembly.AssemblyTypeName = "Novo nome"

1 Like