CPython3 Icollection interpretation

Anyone got a clue why the following code would work in old IronPython2 but would not work in CPython3?

selelemz=uidoc.Selection.GetElementIds()
elements=FilteredElementCollector(doc,selelemz).WherePasses(framingfilt).WhereElementIsNotElementType().ToElements()

The error message is:

Warning: TypeError : No constructor matches given arguments: (<class ‘Autodesk.Revit.DB.Document’>, <class ‘list’>) [’ File “”, line 70, in \n’]

where line 70 is the “elements=FilteredElementCollector” line.

my guess is that the filtered element collector somehow is seeing the uidoc.Selection.GetElementIds() as just a list instead of as an ICollection of ElementIds as it used to in IronPython. Anyone got a clue how to make that work?

FilteredElementCollector Constructor (Document, ICollection(ElementId))

Try importing the inspect module, and then use OUT = inspect.getmembers(selelemz) to see what the variable you have is, and more importantly what you can do with it in the context of the current Python implementation.

Well - here’s the result of that - no clue what any of it means - though I see it thinks it is of class ‘list’. This to me seems like it is the issue in that the filtered element collector needs an Icollection.
image

I literally can switch the interpreter to ironPython2 and the script works fine. Is this just a limitation of CPython (seemingly a pretty major one if some of the Revit API methods dont easily work nice with it - and 90% of Dynamo users are primarily Revit-based…)

Somewhere in that list is _doc_ - what does that indicate?

Hello @Ben_Osborne
CPython3 engine uses PythonNet and .NET collections and arrays are automatically converted to Python collections.

Currently, you must cast your variables (collections) if you want to use the Revit API .Net with CPython3/PythonNet engine

example

from System.Collections.Generic import List
# some imports
selelemz=List[ElementId](uidoc.Selection.GetElementIds())
elements=FilteredElementCollector(doc,selelemz).WhereElementIsNotElementType().ToElements()

For information there are big changes on the next update of the PythonNet package (version 3), in particular on object conversions, so a List<T> should be to remain a List<T>

1 Like

ummm - that sounds like a major pain for anyone who’s been using Dynamo +Revit for years and has thousands of lines of code to go thru and cast every single variable (because some might work and some might not)…

I say “some” because this error was part of a much larger script (375 lines) that runs fine as long as i have it invoke the collector for Elements Visible in View instead of Selected Elements. it really makes me wary of moving to CPython if the conversion is going to mean going thru and casting every single Revit API variable ive ever used…

1 Like

Personally, I’d be sticking to IronPython until Autodesk sorts out a Python plan. It would be nice if they a) had a plan. b) would use some industry standards.
If there is some CPython3 you want to use, I’d import and reference that on an as need basis.
_ doc _ indicates an IronPython reference. (and that’s two underscores.) pyRevit has some documentation you can look at.

#pyRevit - I use this when I expect to posrt my Python outside of Dyanmo. Works fine inside Dynamo as well.
#doc = __revit__.ActiveUIDocument.Document
#app = __revit__.Application
#uidoc = __revit__.ActiveUIDocument
#uiapp = __revit__.CurrentUIApplication 

#Dynamo
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = uiapp.ActiveUIDocument

You will need to reference the correct Python engine of course.

#sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
sys.path.append('C:\Program Files\Autodesk\Revit 2020\AddIns\DynamoForRevit\IronPython.StdLib.2.7.8')
sys.path.append('C:\Program Files\pyRevit-Master\pyrevitlib')
sys.path.append('C:\Program Files\Autodesk\Revit 2020\AddIns\DynamoForRevit')
1 Like

https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwij69Ti3rvzAhXPk2oFHfS8BRUQFnoECCcQAQ&url=https%3A%2F%2Fwww.autodesk.com%2Fautodesk-university%2Fclass%2FUntangling-Python-Crash-Course-Dynamos-Python-Node-2017&usg=AOvVaw14WvH2UeUMFXAAWWI4K_2i

image

Yeah - I’d prefer to stick with IronPython (…if it ain’t broke, don’t fix it) but some of the way the Cpython change was talked about made me suspect it would be dropped sooner rather than later (much like the UseForgeId change from DisplayUnits had a one year grace period in the API). I am just now starting to get into trying out CPythons and thus far am not loving the idea.

2 Likes

There certainly is a plan, and it is keeping up with industry standards (meaning no more Iron Python). This is the industry standard is to move away from the Iron Python implementation as that code base is built on Python 2.7, which is no longer receiving any updates, including security updates.

As with any update, graph authors should take the Python version migration into account in updating their work. Form a plan of action, migrate the easy code first, and move into the more complex code over time. Keeping your Python code contained in a package is as always advisable, as this will allow easier systematic updates for end users, who can of course continue to use the Iron Python implementation or the C Python implementation as the code updates propagate and are pushed out to users.

Good.
I’m sure there a lot like me - that are moving away from nodes and just going with straight python. (a shout out for pyRevit, of course) The whole custom node thing is a pita in a small (or mid-size) office. We can’t have people downloading and maintaining nodes - so I want my code to run off whatever is OOTB as possible. Even my dyn use nothing but the provided nodes and raw python API.

I’ve spent too much time using visual studio to build applications. Python lets me make incremental improvements to apps within the daily time I might have (lunch), without the overhead of dlls and add-ins.

1 Like

To clarify: The custom nodes I was referring to were the DYFs, which just become containers for your Python, such as in the Clockwork and Genius Loci package. Package those up, copy them to the user’s local disc at log in, and you’re good to go. This is much easier than managing the Python in graph directly as you have to find all the DYNs and edit each as needed.

PyRevit is certainly a great tool. Do you know how it is handling the Python 2 to Python 3 migration?

We’ll said Aaron - better than I could have explained my opinions.
I’m also a “small/mid” company kind of guy and of the “no packages - use python + OOTB nodes (where possible)” school of thought. Once the python gets dumped into a custom node - the users just report “the node turned yellow and didn’t work” instead of being able to tell me what line the error occurred at (plus running more in just python script tends to be faster).

A lot of my work tends to need re-invention/tweaking fairly regularly because we work with modes from a lot of varied sources (not internally authored and coming to Revit from Tekla or SDS/2 via IFC) so being able to troubleshoot a script and tweak it for the specific model issues is quite common.

1 Like

Add some trace back exception reporting into the output Incase of failure. Feedback from users gets much easier in either custom node or Python node format.

…too busy fending off “why can’t I see my thing?” questions.

Ya. No
We had a outside threat that took down our whole network a while back
Coping that stuff to everyone’s workstation now takes forever and a day with new security procedures.

For pyRevt - I update the *.py on the server and everyone has the latest and greatest stuff each time they start Revit.
Zero install.
Zero updates.

1 Like