FreeCAD Scripting: How to Rollback Transactions

This article explains how to safely discard modifications made by Python scripts in FreeCAD using built-in transaction methods. When automating parametric modeling, scripts can encounter unexpected runtime exceptions or invalid geometries. By wrapping your code in a document transaction, you can ensure that any failing operation cleanly reverts the document to its original state rather than leaving behind orphaned or broken objects.

Understanding FreeCAD Transactions

FreeCAD's Application interface (FreeCAD or App) provides a transaction mechanism through the active document. Transactions group multiple modeling commands into an atomic operation. If the script finishes successfully, the transaction is committed; if an error occurs, the transaction can be aborted, effectively rolling back all modifications made since the transaction was opened.

The primary methods used on the document object are:

  • openTransaction(name): Starts recording changes under a specified transaction name.
  • commitTransaction(): Finalizes and saves all changes made during the open transaction.
  • abortTransaction(): Discards all changes made during the open transaction and restores the previous state.

Implementation Pattern

The most reliable way to implement transaction rollbacks is with a standard Python try...except block. This ensures that any unhandled exception triggers an immediate rollback.

import FreeCAD as App
import Part

doc = App.activeDocument()

if doc is None:
    doc = App.newDocument("TransactionDemo")

# 1. Open the transaction
transaction_name = "CreateParametricShape"
doc.openTransaction(transaction_name)

try:
    # 2. Perform document operations
    box = doc.addObject("Part::Box", "TempBox")
    box.Length = 10.0
    box.Width = 10.0
    box.Height = 10.0
    doc.recompute()

    # Simulate an error condition
    raise RuntimeError("An unexpected error occurred during processing.")

    # 3. Commit if everything succeeds
    doc.commitTransaction()
    print("Transaction committed successfully.")

except Exception as error:
    # 4. Abort and rollback on failure
    doc.abortTransaction()
    print(f"Error encountered: {error}")
    print("Transaction aborted. Changes have been rolled back.")

# Ensure document status is updated
doc.recompute()

Rolling Back Already Committed Changes

If a transaction has already been committed using commitTransaction(), calling abortTransaction() will no longer affect it. To undo changes after committing, use the document's undo() method:

# Reverses the last committed transaction
doc.undo()
doc.recompute()

Key Considerations

  • Nested Transactions: FreeCAD does not natively support nested transactions. Always ensure that an open transaction is either committed or aborted before opening a new one.
  • Recompute Timing: Changes aborted with abortTransaction() instantly remove temporary objects from the internal tree, but calling doc.recompute() afterward ensures the 3D view and tree view are fully synchronized with the rolled-back state.