Overview
Writing a script directly in the Maestro IDE gives you full control over what the tool does and how it interacts with Revit. This section covers the basic structure of a script, how to import the right libraries, how to reference the Revit API, and how to test and debug your work.
Code Structure
At a high level, most Maestro scripts should follow this pattern:
- Imports
- Maestro / MVAR definitions
- Helper functions
- Main execution logic
- Safe exit / error handling
Example skeleton:
# 1. Imports
import sys
from Autodesk.Revit.DB import *
# 2. Maestro variables (MVARs)
category_name = "Walls" # @mvar(type='string', display='Desired Category')
# 3. Helper functions
def get_elements_by_category(doc, category_name):
cat = getattr(BuiltInCategory, "OST_" + category_name)
return FilteredElementCollector(doc).OfCategory(cat).WhereElementIsNotElementType().ToElements()
# 4. Main execution logic
def main():
elements = get_elements_by_category(doc, category_name)
# do something with elements
return len(elements)
# 5. Entry point
main()
Use MVARs (marked with the # @mvar(<inputs>) comment) for anything a user should be able to change without editing code (categories, parameter names, thresholds, etc.).
Imports
Imports should be:
- Minimal: Only bring in what you actually use.
- Explicit: Prefer importing specific classes from
Autodesk.Revit.DBandAutodesk.Revit.UIinstead of*when possible. - Grouped: Keep standard Python imports, third-party imports, and Revit-specific imports separated.
Typical import grouping:
# Standard library
import math
import itertools
# Third-party (if applicable)
# import clr # only if required in your environment
# Revit API
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import TaskDialog
If the script relies on firm-specific helper modules, import them after the core dependencies and clearly comment what they provide.
Revit API References
Your script runs inside a Revit context with access to the current document and application. In most Maestro scripts you will interact with:
doc: The activeDocument(read/write access to the model).__revit__: TheApplicationobject (global settings, documents, options).
Maestro does not provide a default accessor for the ActiveUIDocument. This can be added using:
uidoc = __revit__.ActiveUIDocument
Typical patterns:
# Accessing selected elements
uidoc = __revit__.ActiveUIDocument
selection_ids = uidoc.Selection.GetElementIds()
selected_elements = [doc.GetElement(id) for id in selection_ids]
# Starting a transaction
t = Transaction(doc, "My Automation")
t.Start()
try:
# modify elements here
t.Commit()
except Exception as e:
t.RollBack()
raise
Key points:
- Always wrap write operations in a
Transaction. - Keep transactions as small as reasonable; do not span user prompts or long-running logic if you can avoid it.
- Be explicit about what you’re modifying (logically and in comments) so others can trust and maintain the script.
Testing and Debugging
Testing and debugging in the IDE should be incremental and intentional:
-
Start small
- Begin with a no-op script that just reads from the model and logs output.
- Add write operations only after you’ve confirmed you’re targeting the correct elements.
-
Use logging and messages
- Print to the console or use Revit dialogs for key checkpoints: counts of elements found, parameter values, etc.
-
Test on safe models
- Never test new logic for the first time on a production model. Use copies or sandbox projects.
- Validate behavior on multiple configurations (different templates, different parameter setups).
-
Iterate with small changes
- Change one thing at a time, run, observe, then proceed.
- When something breaks, narrow it down by temporarily commenting out sections and re-running.
A script is “ready” when:
- It runs without errors on representative test models.
- It handles empty selections, missing parameters, and edge cases gracefully.
- You can describe, in one sentence, what it does and under what conditions it should be used.