Skip to content

Scripting API

Transaction

from ArtisanPlugin.Scripting import Transaction

A script that moves forty stones should be one press of Ctrl+Z, not forty. Transaction is the undo primitive the rest of the scripting API is built on: it opens a Rhino undo record, everything done inside it collapses into that one entry, and closing it hands the user a single, named step in their history.

This matters more than it sounds. Without it, every Create, Move, SetCaratWeight and Delete lands as its own undo entry and fires its own redraw, so a bench jeweller who dislikes the result has to undo the script one operation at a time — through a history that no longer says anything about what happened.

Usage

with Transaction.Begin("Move all gems"):
    for g in gem.All():
        g.Move(Vector3d(0, 0, 1))
ParameterDefaultMeaning
descriptionThe name the undo step gets in Rhino’s history. Write it for the user: “Halo on 6 stones”, not “script”

Begin returns a disposable scope. The undo record opens when it is created and closes when it is disposed.

Always use the with form

Python’s with block is not a nicety here. It guarantees the scope is disposed — and therefore the undo record closed — on every exit path, including an exception thrown halfway through the script. That is the case that matters: a leaked undo record is not a tidy-history problem, it corrupts the document’s undo stack for the rest of the session, and the user has to restart Rhino to get it back. Scripts fail — a gem is missing, a plane is invalid, a licence check trips — and the with form is what makes those failures harmless.

Keep the whole run of mutations inside one block rather than opening a transaction per operation; nesting or reopening per call defeats the point.

What it groups

Everything the document records while the scope is open. That means Artisan calls — GemApi.Create, the handle mutations, the gemset facades, ToiEtMoiApi.Createand plain Rhino calls alike, rhinoscriptsyntax and RhinoDoc operations included. It is Rhino’s own undo record, not an Artisan-private mechanism, so a script that mixes the two APIs still undoes as one step:

import rhinoscriptsyntax as rs
from ArtisanPlugin.Scripting import GemApi as gem, Transaction
from Rhino.Geometry import Plane

with Transaction.Begin("Stone and marker"):
    g = gem.Create("ROUND", "Diamond", 0.50, Plane.WorldXY)
    rs.AddTextDot("centre", g.Position)

When you do not need one

Read-only scripts need no transaction at all. Nothing in GemApi.All, Find, Count, Selected, ByLayer, ByMaterial, Collisions, Shapes or Materials changes the document, none of them writes an undo entry, and Select(on) on a handle only toggles viewport selection. A script that reports, measures or checks for collisions can skip Transaction entirely.

The rule is simply: if the script changes the document, wrap it; if it only reads, do not bother.

Errors

Begin calls the licence check before it opens anything, so an unlicensed session raises ScriptingNotLicensedException at the with statement rather than at the first mutation inside it. With no document open the scope is still created and still valid to use — it just has no undo record to manage. Disposal is idempotent: leaving the block twice, or disposing a scope by hand and then letting the block end, closes the record exactly once.