Writing a python script node for getting Type Name of elements of all possible kinds of categories

Hello everyone, I am a newbie to Dynamo and Python. I am trying to create a python script node as captioned.

After days long researching and with help by POE, I finally killed all the errors messages, but can obtain nothing for the output as shown here:

And here are the python script I used:


# Import the required modules and references
import clr

# Add the Revit API assemblies to the system path
clr.AddReference("RevitAPI")
clr.AddReference("RevitServices")

# Import Revit API classes
from Autodesk.Revit.DB import Document, BuiltInCategory
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Import additional RevitNodes module for category retrieval
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

# Retrieve the active Revit document
doc = DocumentManager.Instance.CurrentDBDocument

# The input to this code snippet will be stored as a list in the IN variable.
elements = IN[0]  # Single element or list of elements

# Create empty lists to store the element types and type names
type_names = [ ]

# Function to get the category of an element
def GetCategory(item):
    if not item:
        return None, None
    objtype = item.GetType().ToString()
    if objtype == "Autodesk.Revit.DB.ParameterFilterElement":
        return [GetCategoryObjects(x) for x in item.GetCategories()]
    elif objtype == "Autodesk.Revit.DB.ViewSchedule":
        return GetCategoryObjects(item.Definition.CategoryId)
    elif objtype == "Autodesk.Revit.DB.Family":
        return GetCategoryObjects(item.FamilyCategoryId)
    elif objtype == "Autodesk.Revit.DB.GraphicsStyle":
        return GetCategoryObjects(item.GraphicsStyleCategory.Id)
    elif objtype == "Revit.Application.Document":
        if item.IsFamilyDocument:
            clr.AddReference("RevitServices")
            import RevitServices
            from RevitServices.Persistence import DocumentManager
            return GetCategoryObjects(DocumentManager.Instance.CurrentDBDocument.OwnerFamily.FamilyCategoryId)
        else:
            return None, None
    elif objtype == "Autodesk.Revit.DB.Category":
        if item.Parent:
            return GetCategoryObjects(item.Parent.Id)
        else:
            return None, None
    elif hasattr(item, "Category"):
        if item.Category:
            return GetCategoryObjects(item.Category.Id)
        else:
            return None, None
    else:
        return None, None

# Function to get the category objects
def GetCategoryObjects(catID):
    if not catID:
        return None, None
    returnBic = System.Enum.ToObject(BuiltInCategory, catID.IntegerValue)
    try:
        returnCat =  Revit.Elements.Category.ById(catID.IntegerValue)
    except:
        returnCat = None
    return returnCat, returnBic

#Iterate through the elements
for element in elements:
    if isinstance(element, list):  # Handling list inputs
        element = element[0]

    # Get the category and built-in category of the element
    category, built_in_category = GetCategory(element)

    if built_in_category == BuiltInCategory.OST_Walls:  # Example for walls
        # Retrieve the wall type using the "Wall.WallType" property
        wall_type = doc.GetElement(element.GetTypeId()).WallType
        if wall_type is not None:
            type_names.append(wall_type.Name)
        else:
            type_names.append("Unknown Type")
    elif category is not None:
        # Retrieve the element type using the category object
        element_type = doc.GetElement(element.GetTypeId())
        if element_type is not None:
            type_names.append(element_type.Name)
        else:
            type_names.append("Unknown Type")
    else:
        type_names.append("Unknown Type")

# Assign the output to the OUT variable
OUT = type_names

I know this issue may not be necessarily resolved by python. Welcome for any kind of solutions. Please help.

Thanks in advance.

Backgrounds, if you were interested:
I am processing a task requiring a processing of type name of selected elements. However, it is found that types of some categories are not accessible by Element.ElementType, such as walls.

I have tried to make use of package nodes like Walls.WallType to get the type of walls. But, by this approach there will be very bulky process with bunch of if nodes to filter out categories such as walls, floors and structural categories.

Finally, my team leader always suggests us not to use nodes in package.

That’s why I tried to create a python script node.

Please help. Appreciate your help!

Hello @19Ko and welcome to the dynamo forum :smiley:

First, there can nothing be processed if you don´t Unwrap the Revit elements!

UnwrapElement(IN[0])

Keep that in mind for all future code! Very important!

Second, its a little tricky to get the wall type name, you can`t get it from the type but from the wall itselfe, weird^^ See here:
python - Get Name of WallType in PyRevit - Stack Overflow.

Also imports were missing and the processing of element/list input was not correct.

Here you are :slight_smile:

# Import the required modules and references
import clr
import System

# Add the Revit API assemblies to the system path
clr.AddReference("RevitAPI")
clr.AddReference("RevitServices")

# Import Revit API classes
from Autodesk.Revit.DB import Document, BuiltInCategory, Element
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Import additional RevitNodes module for category retrieval
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

# Retrieve the active Revit document
doc = DocumentManager.Instance.CurrentDBDocument

# Check if the input is a list, if not, wrap it in a list
if not isinstance(IN[0], list):
    elements = [UnwrapElement(IN[0])]
else:
    elements = UnwrapElement(IN[0])

# Create empty lists to store the element types and type names
type_names = []

# Function to get the category of an element
def GetCategory(item):
    if not item:
        return None, None
    objtype = item.GetType().ToString()
    if objtype == "Autodesk.Revit.DB.ParameterFilterElement":
        return [GetCategoryObjects(x) for x in item.GetCategories()]
    elif objtype == "Autodesk.Revit.DB.ViewSchedule":
        return GetCategoryObjects(item.Definition.CategoryId)
    elif objtype == "Autodesk.Revit.DB.Family":
        return GetCategoryObjects(item.FamilyCategoryId)
    elif objtype == "Autodesk.Revit.DB.GraphicsStyle":
        return GetCategoryObjects(item.GraphicsStyleCategory.Id)
    elif objtype == "Revit.Application.Document":
        if item.IsFamilyDocument:
            clr.AddReference("RevitServices")
            import RevitServices
            from RevitServices.Persistence import DocumentManager
            return GetCategoryObjects(DocumentManager.Instance.CurrentDBDocument.OwnerFamily.FamilyCategoryId)
        else:
            return None, None
    elif objtype == "Autodesk.Revit.DB.Category":
        if item.Parent:
            return GetCategoryObjects(item.Parent.Id)
        else:
            return None, None
    elif hasattr(item, "Category"):
        if item.Category:
            return GetCategoryObjects(item.Category.Id)
        else:
            return None, None
    else:
        return None, None

# Function to get the category objects
def GetCategoryObjects(catID):
    if not catID:
        return None, None
    returnBic = System.Enum.ToObject(BuiltInCategory, catID.IntegerValue)
    try:
        returnCat = Revit.Elements.Category.ById(catID.IntegerValue)
    except:
        returnCat = None
    return returnCat, returnBic

# Iterate through the elements
for element in elements:
    # Get the category and built-in category of the element
    category, built_in_category = GetCategory(element)

    if built_in_category == BuiltInCategory.OST_Walls:  # Example for walls
        type_names.append(Element.Name.GetValue(element))

    elif category is not None:
        # Retrieve the element type using the category object
        element_type = doc.GetElement(element.GetTypeId())
        if element_type is not None:
            type_names.append(element_type.Name)
        else:
            type_names.append("Unknown Type")
    else:
        type_names.append("Unknown Type")

# Assign the output to the OUT variable
OUT = type_names

1 Like

Hello @gerhard.p Thank you very much for your quick reply!! :hand_with_index_finger_and_thumb_crossed:
Very comprehensive and useful advices!
But I still have one question that is about the list level.

How to deal with the list with more list levels?

I have tried the method in this post:
Apply function to list regardless of levels in python - Lists-Logic - Dynamo (dynamobim.com)

# Import the required modules and references
import clr
import System

# Add the Revit API assemblies to the system path
clr.AddReference("RevitAPI")
clr.AddReference("RevitServices")

# Import Revit API classes
from Autodesk.Revit.DB import Document, BuiltInCategory, Element
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Import additional RevitNodes module for category retrieval
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

# Retrieve the active Revit document
doc = DocumentManager.Instance.CurrentDBDocument

# The input to this code snippet will be stored as a list in the IN variable.
#elements = UnwrapElement(IN[0])  # Single element or list of elements
#Function to handle any list structure
ProcessLists = lambda function, lists: [ProcessLists(function, item) if isinstance(item, list) else function(item) for item in lists]
ApplyFunction = lambda func, objs: ProcessLists(func, objs) if isinstance(objs, list) else [func(objs)]
#Funtion to unwrap
def Unwrap(item):
    return UnwrapElement(item)
# Check if the input is a list, if not, wrap it in a list
if not isinstance(IN[0], list):
    elements = ProcessLists(Unwrap, IN[0])
else:
    elements = Unwrap(IN[0])
# Create empty lists to store the element types and type names
type_names = []

# Function to get the category of an element
def GetCategory(item):
    if not item:
        return None, None
    objtype = item.GetType().ToString()
    if objtype == "Autodesk.Revit.DB.ParameterFilterElement":
        return [GetCategoryObjects(x) for x in item.GetCategories()]
    elif objtype == "Autodesk.Revit.DB.ViewSchedule":
        return GetCategoryObjects(item.Definition.CategoryId)
    elif objtype == "Autodesk.Revit.DB.Family":
        return GetCategoryObjects(item.FamilyCategoryId)
    elif objtype == "Autodesk.Revit.DB.GraphicsStyle":
        return GetCategoryObjects(item.GraphicsStyleCategory.Id)
    elif objtype == "Revit.Application.Document":
        if item.IsFamilyDocument:
            clr.AddReference("RevitServices")
            import RevitServices
            from RevitServices.Persistence import DocumentManager
            return GetCategoryObjects(DocumentManager.Instance.CurrentDBDocument.OwnerFamily.FamilyCategoryId)
        else:
            return None, None
    elif objtype == "Autodesk.Revit.DB.Category":
        if item.Parent:
            return GetCategoryObjects(item.Parent.Id)
        else:
            return None, None
    elif hasattr(item, "Category"):
        if item.Category:
            return GetCategoryObjects(item.Category.Id)
        else:
            return None, None
    else:
        return None, None

# Function to get the category objects
def GetCategoryObjects(catID):
    if not catID:
        return None, None
    returnBic = System.Enum.ToObject(BuiltInCategory, catID.IntegerValue)
    try:
        returnCat =  Revit.Elements.Category.ById(catID.IntegerValue)
    except:
        returnCat = None
    return returnCat, returnBic

# Iterate through the elements
for element in elements:
    if isinstance(element, list):  # Handling list inputs
        element = element[0]

    # Get the category and built-in category of the element
    category, built_in_category = GetCategory(element)

    if built_in_category == BuiltInCategory.OST_Walls:  # Example for walls
        # Retrieve the wall type using the "Wall.WallType" property
        type_names.append(Element.Name.GetValue(element))

    elif category is not None:
        # Retrieve the element type using the category object
        element_type = doc.GetElement(element.GetTypeId())
        if element_type is not None:
            type_names.append(element.Name)
        else:
            type_names.append("Unknown Type")
    else:
        type_names.append("Unknown Type")

# Assign the output to the OUT variable
OUT = ApplyFunction(lambda x: type_names, elements)

Then I have this error in result
image

for clearer information:

So, are there something wrong when I deal with the list?