top of page

ESAPI Programming with Python

I'm used to programming in C# when creating Eclipse scripts with ESAPI. But there's a lot of ceremony in that—opening Visual Studio, creating a new solution and project, referencing the ESAPI assemblies, creating a new program class, etc. That's all fine if I'm creating a script that will be used by others.


But sometimes I just want to quickly get some information about a patient or patients and be done. It turns out that one can use Python to do this. Python is a general-purpose scripting language that's easy to learn and use. Python was added to the family of .NET languages as IronPython. This is good because, as you may know, ESAPI is based on the .NET framework and therefore requires a .NET language to use it.


To get started, download and install IronPython. You can also install additional tools to integrate Python into Visual Studio, but I haven't tried that yet. I'm just going to use a plain text editor.


Here's the basic template of an ESAPI script in Python:


import sys
import clr
import System

# Add Varian's path when referencing assemblies
sys.path.append(r"C:\Program Files (x86)\Varian\Vision\13.6\Bin64")

# Reference the Varian API assemblies
clr.AddReferenceToFile("VMS.TPS.Common.Model.API.dll")
clr.AddReferenceToFile("VMS.TPS.Common.Model.Types.dll")

from VMS.TPS.Common.Model.API import *
from VMS.TPS.Common.Model.Types import *

app = Application.CreateApplication("username", "password")

# Your code here

app.Dispose()

First, you tell it where the ESAPI assemblies are, and then you reference the required assemblies. You then create the application object (passing it your username and password). After your code, you dispose of the application object. (If you don't dispose of it, you'll get an annoying error before the program exists.)


Let's use this template in an example. I'd like to output the multileaf collimator (MLC) leaf positions of all control points in a beam for a patient. Each output line will contain the control point index, the control point's meterset weight, the jaw positions, and the positions of a leaf pair. Here's the code:


patient = app.OpenPatientById("1234567890")
course = next(c for c in patient.Courses if c.Id == "COURSE")
plan = next(p for p in course.PlanSetups if p.Id == "PLAN")
beam = next(b for b in plan.Beams if b.Id == "BEAM")
for cpIndex in range(beam.ControlPoints.Count):
    cp = beam.ControlPoints[cpIndex]
    for leafPairIx in range(cp.LeafPositions.GetLength(1)):
        print cpIndex + 1, \
              cp.MetersetWeight, \
              cp.JawPositions.X1, \
              cp.JawPositions.X2, \
              cp.JawPositions.Y1, \
              cp.JawPositions.Y2, \
              cp.LeafPositions[0, leafPairIndex], \
              cp.LeafPositions[1, leafPairIndex]
app.ClosePatient()

As another example, I'd like to output the plan sums that contain plans with different structure set images. Here's the code:


for ps in app.PatientSummaries:
    try:
        patient = app.OpenPatientById(ps.Id)
        if patient.Courses == None:
            continue
        for course in patient.Courses:
            if course.PlanSums == None:
                continue
            for pls in course.PlanSums:
                if pls.PlanSetups == None:
                    continue
                plans = list(pls.PlanSetups)
                if len(plans) < 2:
                    continue
                if plans[0].StructureSet == None or \
                   plans[1].StructureSet == None:
                    continue
                if plans[0].StructureSet.Image.FOR != \
                   plans[1].StructureSet.Image.FOR:
                    print patient.Id, course.Id, pls.Id
    except:
        print "Error with patient " + ps.Id
    finally:
        app.ClosePatient()

Each of these examples were coded in a single file—no need for solutions, projects, classes, etc. The code itself is also fairly easy to read because the language is streamlined and devoid of unnecessary syntax.


The IronPython Documentation website contains several useful links, including the Python language documentation and a reference on how IronPython integrates with the .NET framework.

Related Posts

See All

ESAPI Essentials 1.1 and 2.0

A few months ago, I introduced ESAPI Essentials—a toolkit for working with ESAPI (available via NuGet). I've recently added one major feature: asynchronous access to ESAPI for binary plugin scripts. Y

Announcement: ESAPI Subreddit

A few months ago, Matt Schmidt started the ESAPI subreddit. It's another useful resource for finding and discussing ESAPI-related topics. According to the description, This community is to post and di

Dump All Patient Data from ESAPI

If, for whatever reason, you need to dump out all of the data for a patient from ESAPI, there's a quick and dirty way to do it. Well, there are probably several ways to do it, but here's one I've foun

bottom of page