A Primer for Dynamo For Revit Python Imports

So the other day on Twitter someone who is both really cool and smart said they didn’t understand what happens with all the import stuff in the Dynamo Python environment.

And so in an attempt to provide some insight to the masses I decided to share out my annotated Python code for the imports I use in the context of for Dynamo for Revit. Each line is annotated to explain it’s purpose, and at least give enough bread crumbs on what to each for if you want to learn more.

The imports
########################################
### Configure the Python environment ###
########################################
### standard imports ###
import sys #add the sys class to the Python environment so we can work with the sys objects
import clr #add the CLR (common language runtime) class to the Python environment so we can work with .net libraries

### Dynamo Revit imports ###
clr.AddReference("RevitNodes") #add Dynamo's Revit nodes library to the clr
import Revit #import Dynamo's Revit node class
clr.ImportExtensions(Revit.Elements) #add the element conversion methods to the CLR
clr.ImportExtensions(Revit.GeometryConversion) #add the geometry conversion methods to the CLR
clr.AddReference("RevitServices") #add the Revit services library to the CLR
import RevitServices #import the Revit services class to the Python environment
from RevitServices.Persistence import DocumentManager #import the document manager class to the Python environment 
from RevitServices.Transactions import TransactionManager #import the transaction manager class to the Python environment 

### Revit API imports ###
clr.AddReference("RevitAPI") #add the Revit API to the CLR
import Autodesk #add the Autodesk class to the Python environment 
from Autodesk.Revit.DB import * #import every class in the DB section of the Revit API to the Python environment. 
#The full list can be seen here: https://www.revitapidocs.com/2024/87546ba7-461b-c646-cbb1-2cb8f5bff8b2.htm 
### trade specific Revit imports ###
from Autodesk.Revit.DB.Architecture import * #import every class of the Revit architecture API to the Python environment
from Autodesk.Revit.DB.Structure import * #import every class of the Revit Structure API to the Python environment
from Autodesk.Revit.DB.Plumbing import * #import every class of the Revit plumbing API to the Python environment
from Autodesk.Revit.DB.Electrical import * #import every class of the Revit electrical API to the Python environment
from Autodesk.Revit.DB.Mechanical import * #import every class of the Revit mechanical API to the Python environment

### .net imports ###
clr.AddReference("System") #add the .net System library to the CLR
from System.Collections.Generic import List as NetList #imports the .net list module to the Python environment as the alias NetList
#elementIds = NetList[ClassHere](ListOfObjectsHere) #how to build a .net list from a python list of objects
7 Likes

I appreciate the post! (Being the person who mentioned it on twitter, and still not knowing anything about it).

I think i saw in the link you posted last night (to the python primer) that it explains WHY each line might get added, yeah? Thats where it gets confusing. I took an API coding class (back in 2012), and the teacher was like “Here is what i put at the top of my code, you can copy it in and use it in the future.” Trouble is, that meant i didnt learn WHY any of that had to be there.

BTW, TOTALLY not asking you to explain every line. Thats not your job. Just expanding on the confusion i mentioned from last nights Tweets.

For instance:

from RevitServices.Persistence import DocumentManager #import the document manager class to the Python environment
from RevitServices.Transactions import TransactionManager #import the transaction manager class to the Python environment

What i need to work on learning is: How do i know if/when i need either of these things?

1 Like

I like a “subtractive” template for code rather than an additive. My process is more or less “load in my full template” which contains all of that, the basic transaction calls, document and application variables, unwrapping and ‘to list’ methods. Can’t post that at the moment (wrong PC), but it is basically what is in the Dynamo Python primer and the Dynamo Developer primer.

So starting from that full template, my process is as follows:

Stage 1: I write v0.1.1 of my code, starting in the oldest build I am going to support (currently 2022 for me as there isn’t enough runway for me to get ROI on 2021 stuff, and 2020 is unsupported). The goal is to 'get the result with a minimal dataset - two inputs. At this stage I don’t use any definitions yet as while they are better long term they are harder to debug up front. I also avoid try statements - they are a last resort once i see the error happen. I omit any UI, additional version issues, or edge cases at this stage.

Step 2: I write v0.1.1 of my code. This adds the UI and addresses any versioning issues between my oldest and newest supported version, and addresses any simple edge cases i can find.

Step 3: I prep to ship v0.1.2. This cleans up the imports to reduce loading. I typically comment out lines I don’t need, confirm it still runs in oldest and newest build, and then eventually delete them after confirmation. I also add the code properties and such.

Step 4: I hand off the code and wait for additional edge cases and testing feedback.

So in the case of the lines you mentioned:

from RevitServices.Persistence import DocumentManager #import the document manager class to the Python environment
from RevitServices.Transactions import TransactionManager #import the transaction manager class to the Python environment

These would be in the python node until step 3 was complete. At which point they’d go away if I didn’t use TransactionManger or DocumentManager at any point after the imports.

1 Like

Nice one!

If it helps anyone too this is my typical Python boilerplate for noding. Subtractive is definitely the way to go, I’d never remeber these off the top of my head.

1 Like