Supercharging Autodesk Revit with Python
Arrow keys to navigate · S speaker notes · F fullscreen
Software Engineer & BIM Developer
Background, architecture, and why it matters.
Rapid Application Development
for Autodesk Revit
Created by Ehsan Iran-Nejad
in Portland, Oregon
Traditional Revit customisation requires a .NET add-in:
.dllpyrevitlib)AEC firms, BIM Managers, and a growing open-source community sharing extensions via GitHub.
script.py| Concept | What it is | Analogy |
|---|---|---|
Extension |
A folder that defines a ribbon tab with panels & buttons | VS Code extension |
Button (pushbutton) |
A .pushbutton folder containing script.py |
npm script |
Hook |
Python file that fires on a Revit event (open, save, sync…) | git hook |
Library |
A .lib extension that exposes shared Python modules |
shared package |
Two paths: GUI installer or CLI.
Latest release: v6.1.0
# Install via Chocolatey
choco install pyrevit-cli
# Clone & attach to Revit
pyrevit clone default
pyrevit attach default 2024
# Verify
pyrevit clones
Ideal for CI/CD & team deployments.
What ships in the box.
The default extension ships 200+ tools organised into panels:
Batch Sheet Maker, Rename Selected Sheets, Rename Selected Views, Keynotes
Color Splasher, Lines Per View Counter, Preflight Checks, Find Monitored Links
Set Workset, Match, Flip, ReNumber, Tag All in All Views
%APPDATA%\pyRevit-Master\extensions\pyRevitTools.extension
Install any Git-hosted extension with one command:
# Install a community library extension
pyrevit extend lib MyTools https://github.com/yourorg/my-pyrevit-tools.git
# List all installed extensions
pyrevit extensions
# Update all extensions
pyrevit update
From folder structure to shipping.
MyTools.extension/
├── MyTools.tab/ ← Ribbon tab
│ └── Sheets.panel/ ← Ribbon panel
│ ├── RenameSheets.pushbutton/
│ │ ├── script.py ← Main script
│ │ ├── icon.png ← 32×32 button icon (optional)
│ │ └── bundle.yaml ← Metadata (optional)
│ └── SheetIndex.pushbutton/
│ └── script.py
└── lib/ ← Shared Python modules
└── myutils.py
pyrevit extend ui MyTools /path/to/MyTools.extension
Every button in the ribbon is a bundle — a folder with a specific suffix:
| Suffix | Type |
|---|---|
.pushbutton |
Single command button |
.pulldown |
Dropdown menu |
.splitbutton |
Split button (default + dropdown) |
.stack |
Stacked small buttons (2–3) |
.panel |
Ribbon panel group |
.tab |
Ribbon tab |
# bundle.yaml
title: Rename Sheets
tooltip: >
Batch rename sheets by
find & replace pattern
author: Roman Golev
highlight: new
context: zero-doc
engines:
- iron-python-27
- cpython-385
bundle.yaml controls tooltip, author, engine, and button behavior.
import clr
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory, BuiltInParameter
doc = __revit__.ActiveUIDocument.Document
walls = FilteredElementCollector(doc) \
.OfCategory(BuiltInCategory.OST_Walls) \
.WhereElementIsNotElementType() \
.ToElements()
for wall in walls:
vol_param = wall.get_Parameter(BuiltInParameter.HOST_VOLUME_COMPUTED)
if vol_param:
vol_ft3 = vol_param.AsDouble()
vol_m3 = vol_ft3 * 0.0283168
print("{0}: {1:.3f} m3".format(
wall.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM).AsValueString(),
vol_m3
))
forms ModuleRich UI dialogs without writing WPF / XAML:
from pyrevit import forms
# Simple alert
forms.alert("Operation complete!")
# Yes / No confirmation
if forms.alert("Delete elements?",
yes=True, no=True):
# proceed with deletion
pass
# Text input
text = forms.ask_for_string(
prompt="Enter prefix:",
default="XX-"
)
from pyrevit import forms, revit, DB
# Select from a list
selected = forms.SelectFromList.show(
["Option A", "Option B", "Option C"],
title="Choose option",
multiselect=True
)
# Select Revit elements
doc = revit.doc
sheets = DB.FilteredElementCollector(doc)\
.OfClass(DB.ViewSheet).ToElements()
picked = forms.SelectFromList.show(
sorted(sheets, key=lambda s: s.SheetNumber),
title="Pick sheets",
multiselect=True,
name_attr="Name"
)
Standard transaction
from pyrevit import revit, DB
with revit.Transaction("Set Parameter"):
elem.LookupParameter("Comments") \
.Set("Reviewed")
Auto-commits on success; rolls back on any exception.
Transaction Group
from pyrevit import revit
with revit.TransactionGroup("Batch Ops"):
with revit.Transaction("Step 1"):
wall.get_Parameter(
DB.BuiltInParameter.ALL_MODEL_MARK
).Set("A")
with revit.Transaction("Step 2"):
wall.get_Parameter(
DB.BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS
).Set("Updated")
Groups multiple transactions into one undo operation in Revit.
Scaffold extensions visually — download ready-to-use folder structures.
Use AI to generate scripts — provide context for better results:
## Task
Write a pyRevit script that calculates and prints the volume
of all walls in the active Revit document.
## Environment
- Autodesk Revit 2025
- pyRevit (latest)
- IronPython 2.7 (IPY27)
## Requirements
- Calculate the total volume of all walls in the project
- Print the result as a single sum in both cubic meters and cubic feet
Agent: OpenCode or any AI coding assistant
Hold modifier keys when clicking any pyRevit button:
| Modifier | Action |
|---|---|
| Shift + Click | Alternate / Config Script |
| Alt + Click | Show script in Explorer |
| Ctrl + Click | Debug Mode |
| Ctrl + Alt + Shift + Click | Reload Engine |
| Win + Shift + Click | Button Context Menu |
forms module eliminates WPF boilerplate for 80 % of UI needspyRevit is a free, open-source project driven by community contributions. Whether it's code, documentation, bug reports, or financial support — every contribution helps keep the project alive and growing.
github.com/pyrevitlabs/pyRevit
Slides built with Reveal.js 5 & Bun · Dark theme & code blocks: JetBrains Mono + Monokai