Skip to content

CodeExecute StubGeneration

Truong Giang Vu edited this page Feb 17, 2026 · 6 revisions

46: Python.NET Type Stubs - High-Reliability Stub Generation

RevitDevTool includes PythonNetStubGenerator - generates Python type hints directly from .NET assemblies instead of relying on outdated community stubs.

Python Stubs


The Problem

Without stubs:

from Autodesk.Revit import DB

# IDE doesn't know what DB.Wall is
# No autocomplete
# No type hints
# No error detection
wall = DB.Wall  # What methods does Wall have?

Old approach: Use community stubs

  • Often outdated
  • Incomplete coverage
  • Mismatches with current Revit versions
  • Manual updates needed

The Solution: Generate Stubs from Actual DLLs

RevitDevTool's generator reads .NET assemblies directly and creates accurate Python type stubs:

RevitAPI.dll + RevitAPIUI.dll
    ↓
PythonNetStubGenerator
    β”œβ”€ Reflection (read all types, methods, properties)
    β”œβ”€ XML docs (method descriptions)
    └─ Symbol resolution
    ↓
py.typed stub files (.pyi)
    ↓
IDE (PyCharm, VSCode)
    β”œβ”€ Autocomplete βœ…
    β”œβ”€ Type hints βœ…
    β”œβ”€ Error detection βœ…

Generated Stubs Enable

1. Autocomplete in IDE

from Autodesk.Revit import DB

collector = DB.FilteredElementCollector(doc)
# IDE shows: OfClass, OfCategory, WherePasses, ToElements, etc.
walls = collector.OfClass(DB.Wall).ToElements()
#       βœ… Autocomplete works

2. Type Hints (IntelliSense)

def process_walls(walls: list[DB.Wall]) -> int:
    #                             ↑ IDE knows this is Wall class
    count = 0
    for wall in walls:
        # IDE knows wall has: GetName(), GetType(), LevelId, etc.
        name = wall.Name
    return count

3. Error Detection

wall = collector.OfClass(DB.Wall).First()
# IDE knows First() doesn't exist on this type
# Error: "⚠️ Method not found" highlighted immediately

How It Works

Source: .NET Reflection

Generator reads assembly metadata:

  • All public types (classes, interfaces, enums)
  • All methods and properties
  • Parameter types and return types
  • XML documentation from DLL

Output: Python Stubs

Generates .pyi files (stub files):

# Generated: Autodesk/Revit/DB/__init__.pyi

class Wall:
    """Represents a wall element in Revit."""
    def get_name(self) -> str: ...
    def get_type(self) -> str: ...
    @property
    def Name(self) -> str: ...
    @property
    def LevelId(self) -> ElementId: ...
    def get_dependent_elements(self, relationship_type: RelationshipType) -> list[ElementId]: ...

class FilteredElementCollector:
    def __init__(self, document: Document) -> None: ...
    def of_class(self, class_type: Type) -> FilteredElementCollector: ...
    def where_passes(self, filter: ElementFilter) -> FilteredElementCollector: ...
    def to_elements(self) -> list[Element]: ...
    def first(self) -> Element: ...

Why High Reliability?

1. Direct from Source

  • Not third-party maintained stubs
  • Not outdated documentation
  • Real assembly metadata

2. Always Current

  • Regenerate anytime Revit updates
  • No waiting for community updates
  • Match your Revit version exactly

3. Complete Coverage

  • Every public type included
  • Every method documented
  • Every property typed

4. XML Documentation Integrated

  • Method descriptions from DLL XML docs
  • Docstrings in generated stubs
  • IDE shows full documentation

Generator Features

Symbol Resolution

  • Handles nested types
  • Resolves generic types
  • Cross-assembly references

Method Comparison

  • Removes duplicate signatures
  • Handles overloads correctly
  • Special methods (operators, special names)

Doc Comments

  • Extracts XML documentation
  • Converts to Python docstrings
  • Includes parameter descriptions

Usage in RevitDevTool

Stubs are generated during build and included in the project, enabling:

In your IDE:

  • Open script
  • Type: from Autodesk.Revit import DB
  • Press Ctrl+Space β†’ See all DB classes
  • Hover over method β†’ See documentation
  • Type: collector. β†’ Autocomplete shows all methods

Zero setup required - just use RevitDevTool and get full IDE support.


Configuration & IDE Setup

VSCode/Cursor IDE Configuration

RevitDevTool default output path for generated stubs is %APPDATA%\RevitDevTool\{RevitVersion}\Stubs.

⚠️ Important: If you choose a custom output path during stub generation, update the paths below accordingly.

Method 1: Global Stubs (Recommended)

Point to AppData location - stubs work across all projects:

.vscode/settings.json: (example configuration)

{
    "python.autoComplete.extraPaths": [
        "~/AppData/Roaming/RevitDevTool/2025/Stubs",
        "~/AppData/Roaming/pyRevit-Master/pyrevitlib",
        "~/AppData/Roaming/pyRevit-Master/site-packages"
    ],
    "python.analysis.extraPaths": [
        "~/AppData/Roaming/RevitDevTool/2025/Stubs",
        "~/AppData/Roaming/pyRevit-Master/pyrevitlib",
        "~/AppData/Roaming/pyRevit-Master/site-packages"
    ]
}

Note: Replace 2025 with your Revit version (2024, 2026, etc.)

Benefits:

  • βœ… Stubs available in all projects without copying
  • βœ… Update once (generate in RevitDevTool), all projects get new stubs
  • βœ… Works with pyRevit libraries side-by-side
  • βœ… No workspace-specific paths to maintain

Method 2: Workspace-Relative Stubs

Copy stubs to project folder for portable projects:

{
    "python.analysis.extraPaths": [
        "${workspaceFolder}/stubs/Revit2025"
    ],
    "python.analysis.stubPath": "${workspaceFolder}/stubs"
}

When to use:

  • Project shared across teams
  • Different machines need identical structure
  • No external dependencies preferred

Multiple Language Servers Support

For Cursor, Basedpyright, or other Pylance alternatives, configure all:

{
    "python.analysis.extraPaths": [
        "~/AppData/Roaming/RevitDevTool/2025/Stubs"
    ],
    "cursorpyright.analysis.extraPaths": [
        "~/AppData/Roaming/RevitDevTool/2025/Stubs"
    ],
    "basedpyright.analysis.extraPaths": [
        "~/AppData/Roaming/RevitDevTool/2025/Stubs"
    ],
    "basedpyright.importStrategy": "useBundled"
}

Note: ~ expands to user home directory (C:\Users\{username})

Instant Apply Workflow

  1. Generate in Revit: Click "Generate Stubs" button in RevitDevTool UI
  2. Stubs written to:
    • Default: %APPDATA%\RevitDevTool\{RevitVersion}\Stubs
    • Custom: If you selected a different output path, stubs go there instead
  3. Update IDE configuration: If using custom path, edit .vscode/settings.json to point to your chosen location
  4. IDE picks up: Restart language server (Ctrl+Shift+P β†’ "Reload Window") or restart IDE
  5. Autocomplete ready: Type from Autodesk.Revit import DB and see instant IntelliSense

No manual copying required - IDE reads directly from configured location.

Verifying Configuration

Test stub integration is working:

from Autodesk.Revit import DB

# Type this and press Ctrl+Space:
collector = DB.FilteredElementCollector(doc).
#                                            ↑ cursor here
# Should show: OfClass, OfCategory, WherePasses, ToElements, etc.

If autocomplete doesn't work:

  1. Check extraPaths points to correct directory
  2. Verify stubs exist: %APPDATA%\RevitDevTool\2025\Stubs\Autodesk\Revit\DB\__init__.pyi
  3. Restart IDE or reload language server
  4. Check Output panel β†’ Python Language Server for errors

Comparison: Community Stubs vs Generated

Aspect Community Stubs Generated Stubs
Currency Often outdated Always current (regenerate anytime)
Completeness Partial (volunteer-maintained) 100% (from assembly)
Maintenance Delayed (need PR approval) Automated (run generator)
Accuracy May contain errors Exact (from metadata)
Version matching Mismatches possible Exact match with your Revit DLLs
Documentation Manual Extracted from DLL XML docs

Real Example

Without Stubs (Community or None)

from Autodesk.Revit import DB

# What methods does FilteredElementCollector have?
# Need to:
# 1. Check external documentation
# 2. Rely on memory
# 3. Runtime errors if wrong
collector = DB.FilteredElementCollector(doc)
result = collector.where_passes_filter(filter)  # IDE doesn't warn
                                      ↑ This method doesn't exist
# Runtime error discovered

With Generated Stubs

from Autodesk.Revit import DB

collector = DB.FilteredElementCollector(doc)
result = collector.where_passes_filter(filter)
         ↑ IDE immediately shows error:
           "Method 'where_passes_filter' not found.
            Did you mean: 'WherePasses'?"

Benefits for Development

  1. Faster coding - Autocomplete instead of memorizing
  2. Fewer bugs - Type checking catches errors early
  3. Better IDE support - Full IntelliSense
  4. Documentation inline - Hover to see docs
  5. Confidence - Know exactly what's available
  6. Team alignment - Everyone has same signatures

See Also:

Clone this wiki locally