AttributeError: 'List[object]' object has no attribute 'Id'

Hi I am trying to rotate the linked revit model with reference to its project base point as center of rotation using python taken it from How do you rotate around a specified center of rotation?

But I am unable to execute the code as I am getting the error like the following.

image

The script goes like this.

import clr

clr.AddReference(‘RevitAPI’)
from Autodesk.Revit.DB import *

from System.Collections.Generic import *
import math

clr.AddReference(‘RevitNodes’)
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)

clr.AddReference(‘RevitServices’)
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

#Preparing input from dynamo to revit
element = UnwrapElement(IN[0])
axis = IN[1].ToRevitType(True)
angle = (IN[2]*math.pi)/180
#Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
ElementTransformUtils.RotateElement(doc, element.Id, axis, angle)
#TransactionManager.Instance.TransactionTaskDone()
OUT = element

Please help me out as I am stucked in the mid.

import clr

clr.AddReference(‘RevitAPI’)
from Autodesk.Revit.DB import *

from System.Collections.Generic import *
import math

clr.AddReference(‘RevitNodes’)
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)

clr.AddReference(‘RevitServices’)
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

#Preparing input from dynamo to revit
element = UnwrapElement(IN[0])
axis = IN[1].ToRevitType(True)
angle = (IN[2]*math.pi)/180
#Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
ElementTransformUtils.RotateElement(doc, element.Id, axis, angle)
TransactionManager.Instance.TransactionTaskDone()
OUT = element



I just notice the hashtag# at the end.
Can load every library? to have the correct template:

https://primer.dynamobim.org/10_Custom-Nodes/10-6_Python-Templates.html

Hi @Draxl_Andreas I am still getting the same error.


Id is also avaible for Linked Modells…

i checked with dir(UnwrapElement(IN[0]))

if I use that then I will get only this much.

Hay I am using Revit 2020 and Dynamo 2.3.0.7 ! Which version of dynamo and revit are you using ?

you have to unwrap your elements

element = dir(UnwrapElement(IN[0]))

@Draxl_Andreas after this the same error.

dir is just to list all posible functions and answers! you are not using it in the script!

Okay then still I am getting the same error as you suggested I have made changes. Please let me know where I am doing wrong

Whats your input?

maybe it is not getting the right opject or wrong objecttype

@Draxl_Andreas These are my inputs

just say element!

you call just variables! just get rid of id

1 Like

If I do that then the error will be different like

and If I remove element.Id then the error will be

You need to handle your inputs. As a rule, when in python, I always assume inputs are lists of objects, and as a rule always ensure that they are by converting them to a list with a to_list function or having a mapping function. This way I can iterate over the objects (even if only one object given) and it will work.

In your case, you are providing a list of elements to rotate, so the element is actually a list object and obviously does not have an Id property, you need to iterate through the list of elements with a for loop to access the element itself (or list item if you will) and then you can access the Id property.

Also, you must to pass the ElementId into the rotate element method, it’s not optional.

https://www.revitapidocs.com/2020/3968f4e8-759c-f975-6c1f-7de42be633ed.htm

2 Likes

you mean like create a variable and work with that:

link = list(element)

https://www.revitapidocs.com/2020/44f3f7b1-3229-3404-93c9-dc5e70337dd6.htm

or just write ElementId

1 Like

Hello!

Try look into Synthesize package. Node name is “Rotate By Custom Point”.

Hi @shashank.baganeACM ,

Note that in the example in the thread you are refering to, it is a single element that is rotated.
Thus the ElementTransformUtils.RotateElement() method is used. Note that it’s singular (Link).

To handle a list of elements, its actually a different method you need to use:
ElementTransformUtils.RotateElements(). (Link)

The method takes an ICollection of elementId’s.

I usually handle these inputs as follows:

elements = UnwrapElement(IN[0])

#Create the .NET list
iCol = List[ElementId]()
#Iterate the elements and add the id's to the list
for i in elements:
    iCol.Add(i.Id)

Then you’ll be able to proceed with the rotation call, with the iCol list as one of the inputs:
Example:

Python from the example:

import clr
import System
import sys
import math

#Import the Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

#Import generic collections
clr.AddReference('System')
from System.Collections.Generic import *

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

#Import ToDSType(bool) extensions method
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

#Reference the active Document and application
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

#---###Start scripting here:###---#
elements = UnwrapElement(IN[0])

axis = IN[1].ToRevitType(True)
angle = (30*math.pi)/180

iCol = List[ElementId]()
for i in elements:
	iCol.Add(i.Id)

TransactionManager.Instance.EnsureInTransaction(doc)
ElementTransformUtils.RotateElements(doc, iCol, axis, angle)
TransactionManager.Instance.TransactionTaskDone()

OUT = iCol
2 Likes

@Draxl_Andreas ,

Sort of, but by checking if the input is a list, then if not then ensure it is a list so you have a consistent input. The purpose of the code below is to show how you might handle and validate your inputs. Note how I am ensuring inputs are as I need them. Firstly, I am ensuring elements are a list of elements so I can loop through them, then I am ensuring that it is just one line and one angle by converting to list and getting first item (you can do your own handling depending on the scenario, say if you want an axis and angle per element), then I validate the inputs and raise informative exceptions if they do not pass…

import clr

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

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument
app = DocumentManager.Instance.CurrentUIApplication.Application

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

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

import math

"""
Ensure object is a List of objects. If not a list, then it will wrap in a list.
"""
def to_list(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

# The Elements to rotate. Ensuring these are in a list as we will loop through them...
elems = to_list(UnwrapElement(IN[0]))

# The Axis as a DesignScript.Line. We are only handling a single line, so convert to list and get first ensuring there is only one line. If you want to add some more handling for multiple lines then you could test for length equality of elements and axis lines...
axis = to_list(IN[1])[0]

# The angle in degrees. We are only handling a single angle, so convert to list and get first ensuring there is only one angle. If you want to add some more handling for multiple angles then you could test for length equality of elements, axis lines and angles...
angle = to_list(IN[2])[0]


# Validating inputs. You can add more validation depending on your requirements...

if IN[0] == None or len(elems) == 0:
	raise Exception("Element(s) cannot be null or empty")

if IN[1] == None or not axis.GetType() == geom.Line:
	raise Exception("Axis is either null or is not of Type DS.Line")

if IN[2] == None:
	raise Exception("Angle cannot be null")

# The output from this node...
outlist = []

# Main code...

TransactionManager.Instance.EnsureInTransaction(doc)

# Loop through the list of Elements. We know this is always a list even if it is only one Element...
for e in elems:
	# Try/Except should be used sparingly and you should really handle expetions properly, but is beyond the scope of this example... 
	try:
		# Transform the Element. Make sure you convert to Radians and also ToRevitType for the DS.Line...
		ElementTransformUtils.RotateElement(doc, e.Id, axis.ToRevitType(True), math.radians(angle))
		outlist.append("Success")
	except Exception, ex:
		outlist.append("Failed: " + ex.message)

TransactionManager.Instance.TransactionTaskDone()

OUT = outlist

Like I said, this is just an example, how you handle your inputs is up to you. You can also do some clever mapping depending on your inputs, similar to how the node lacing works, but this is a little more advanced.

Hope this helps. :slight_smile:

4 Likes