Batch process documents on Shift+Click

Following the discussion on how to process multiple models at once, this is my take: a python decorator that enables batch processing when you SHIFT+click on the button.

# -*- coding: utf-8 -*-
""" Reusable functions for batch processing. """

__author__ = "Andrea Ghensi"

from pyrevit import revit, forms, EXEC_PARAMS

def batch(function, *args, **kwargs):
    """
    Run a function on multiple Revit files.

    Function must accept a document as "doc" keyword argument.
    Positional and keyword arguments are passed to the function.

    Args:
        function (callable): function to run on each model.
        close (bool): if True (default), closes the document after the process.
        save (bool): if True (default), saves the document after the process.
    """
    file_ext = kwargs.pop("file_ext", "*.rvt")
    model_paths = forms.pick_file(file_ext=file_ext, multi_file=True)
    if not model_paths:
        return
    close = kwargs.pop("close", True)
    save = kwargs.pop("save", True)
    for model in model_paths:
        doc = revit.open_doc(model)
        function(doc=doc, *args, **kwargs)
        if save:
            doc.Save()
        if close:
            doc.Close(False)


def on_shiftclick(func, close=True, save=True):
    """
    Decorate a function to run it in batch mode if SHIFT+CLICKed.

    Example:
        >>> from pyrevit import revit
        >>> import batch
        >>>
        >>> @batch.on_shiftclick(save=False)
        >>> def my_function(doc=revit.doc)
        >>>     print(doc.title) # or something more useful
        >>>
        >>> my_function()

    Args:
        func (callable): function to batch; must accept the keyword arg `doc`.
        close (bool): if True (default), close the document after the process.
        save (bool): if True (default), save the document after the process.
    """
    def wrapper_on_shiftclick(*args, **kwargs):
        if EXEC_PARAMS.config_mode:
            # Shift+click: use batch mode
            kwargs["save"] = save
            kwargs["close"] = close
            batch(func, *args, **kwargs)
        else:
            # Normal click: work with current model
            kwargs["doc"] = revit.doc
            func(*args, **kwargs)
    return wrapper_on_shiftclick

you can put this script in the lib folder of your extension to make it available to every command.
Obviously your scripts need to be refactored to use at least a function with the doc argument and not use the __revit__.ActiveUIDocument.Document or pyrevit.revit.doc directly.

1 Like