OMERO Python Language Bindings
Table of Contents
In addition to the auto-generated Python libraries of the core OMERO API, we have developed a more user-friendly 'Blitz Gateway' Python module that facilitates several aspects of working with the Python API, such as connection handling, object graph traversal and lazy loading.
The Python libraries are part of the server build and can be found under OMERO_HOME/lib/python. These include the core omero.model objects and services as well as the Blitz Gateway code.
Using the OmeroPy libraries
For Python beginners, or those who prefer more detailed instructions, see the PythonClientBeginners page.
To use OmeroPy, you'll need to download the libraries (E.g. as part of the server package) and setup your PYTHONPATH to include them:
OMERO_HOME=~/Desktop/OMERO.server-Beta-4.3.2 # for example PYTHONPATH=$OMERO_HOME/lib/python
Connect to OMERO
# These values will be imported by all the other training scripts. HOST = 'localhost' PORT = 4064 USERNAME = 'will' PASSWORD = 'ome'
from omero.gateway import BlitzGateway
if __name__ == '__main__':
"""
NB: This block is only run when calling this file directly
and not when imported.
"""
# Connect to the Python Blitz Gateway
# =============================================================
# Make a simple connection to OMERO, printing details of the
# connection. See OmeroPy/Gateway for more info
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT)
connected = conn.connect()
# Check if you are connected.
# =============================================================
if not connected:
import sys
sys.stderr.write("Error: Connection not available, please check your user name and password.\n")
sys.exit(1)
# Using secure connection.
# =============================================================
# By default, once we have logged in, data transfer is not encrypted (faster)
# To use a secure connection, call setSecure(True):
# conn.setSecure(True) # <--------- Uncomment this
# Current session details
# =============================================================
# By default, you will have logged into your 'current' group in OMERO. This
# can be changed by switching group in the OMERO insight or web clients.
user = conn.getUser()
print "Current user:"
print " ID:", user.getId()
print " Username:", user.getName()
print " Full Name:", user.getFullName()
print "Member of:"
for g in conn.getGroupsMemberOf():
print " ID:", g.getName(), " Name:", g.getId()
group = conn.getGroupFromContext()
print "Current group: ", group.getName()
print "Other Members of current group:"
for exp in conn.listColleagues():
print " ID:", exp.getId(), exp.getOmeName(), " Name:", exp.getFullName()
print "Owner of:"
for g in conn.listOwnedGroups():
print " ID:", g.getName(), " Name:", g.getId()
# The 'context' of our current session
ctx = conn.getEventContext()
# print ctx # for more info
# Close connection:
# =================================================================
# When you're done, close the session to free up server resources.
conn._closeSession()
Read Data
- Create a connection
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT) conn.connect()
- Configuration
imageId = 27544 datasetId = 2651 plateId = -1
def print_obj(obj, indent=0):
"""
Helper method to display info about OMERO objects.
Not all objects will have a "name" or owner field.
"""
print """%s%s:%s Name:"%s" (owner=%s)""" % (\
" " * indent,
obj.OMERO_CLASS,\
obj.getId(),\
obj.getName(),\
obj.getOwnerOmeName())
- List all Projects available to me, and their Datasets and Images:
# The only_owned=True parameter limits the Projects which are returned.
# If the parameter is omitted or the value is Fale, then all Projects
# visible in the current group are returned.
print "\nList Projects:"
print "=" * 50
for project in conn.listProjects(only_owned=True):
print_obj(project)
for dataset in project.listChildren():
print_obj(dataset, 2)
for image in dataset.listChildren():
print_obj(image, 4)
- Retrieve the datasets owned by the user currently logged in:
# Here we create an omero.sys.ParametersI instance which we # can use to filter the results that are returned. If we did # not pass the params argument to getObjects, then all Datasets # in the current group would be returned. print "\nList Datasets:" print "=" * 50
params = omero.sys.ParametersI() params.exp(conn.getUser().getId()) # only show current user's Datasets
datasets = conn.getObjects("Dataset", params=params)
for dataset in datasets:
print_obj(dataset)
- Retrieve the images contained in a dataset:
print "\nDataset:%s" % datasetId
print "=" * 50
dataset = conn.getObject("Dataset", datasetId)
print "\nImages in Dataset:", dataset.getName()
for image in dataset.listChildren():
print_obj(image)
- Retrieve an image by Image ID:
image = conn.getObject("Image", imageId)
print "\nImage:%s" % imageId
print "=" * 50
print image.getName(), image.getDescription()
# Retrieve information about an image.
print " X:", image.getSizeX()
print " Y:", image.getSizeY()
print " Z:", image.getSizeZ()
print " C:", image.getSizeC()
print " T:", image.getSizeT()
# render the first timepoint, mid Z section
z = image.getSizeZ() / 2
t = 0
renderedImage = image.renderImage(z, t)
#renderedImage.show() # popup (use for debug only)
#renderedImage.save("test.jpg") # save in the current folder
- Retrieve Screening data:
print "\nList Screens:"
print "=" * 50
for screen in conn.getObjects("Screen"):
print_obj(screen)
for plate in screen.listChildren():
print_obj(plate, 2)
plateId = plate.getId()
- Retrieve Wells and Images within a Plate:
if plateId >= 0:
print "\nPlate:%s" % plateId
print "=" * 50
plate = conn.getObject("Plate", plateId)
print "\nNumber of fields:", plate.getNumberOfFields()
print "\nGrid size:", plate.getGridSize()
print "\nWells in Plate:", plate.getName()
for well in plate.listChildren():
index = well.countWellSample()
print " Well: ", well.row, well.column, " Fields:", index
for index in xrange(0, index):
print " Image: ", \
well.getImage(index).getName(),\
well.getImage(index).getId()
- Close connection:
# When you're done, close the session to free up server resources. conn._closeSession()
Raw Data Access
- Create a connection
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT) conn.connect()
- Configuration
imageId = 27544
- Retrieve a given plane
# Use the pixelswrapper to retrieve the plane as
# a 2D numpy array. See [http://www.scipy.org/Tentative_NumPy_Tutorial]
#
# Numpy array can be used for various analysis routines
#
image = conn.getObject("Image", imageId)
sizeZ = image.getSizeZ()
sizeC = image.getSizeC()
sizeT = image.getSizeT()
z, t, c = 0, 0, 0 # first plane of the image
pixels = image.getPrimaryPixels()
plane = pixels.getPlane(z, c, t) # get a numpy array.
print "\nPlane at zct: ", z, c, t
print plane
print "shape: ", plane.shape
print "min:", plane.min(), " max:", plane.max(),\
"pixel type:", plane.dtype.name
- Retrieve a given stack
# Get a Z-stack of tiles. Using getTiles or getPlanes (see below) returns # a generator of data (not all the data in hand) The RawPixelsStore is # only opened once (not closed after each plane) Alternative is to use # getPlane() or getTile() multiple times - slightly slower. c, t = 0, 0 # First channel and timepoint tile = (50, 50, 10, 10) # x, y, width, height of tile
# list of [ (0,0,0,(x,y,w,h)), (1,0,0,(x,y,w,h)), (2,0,0,(x,y,w,h))....etc... ]
zctList = [(z, c, t, tile) for z in range(sizeZ)]
print "\nZ stack of tiles:"
planes = pixels.getTiles(zctList)
for i, p in enumerate(planes):
print "Tile:", zctList[i], " min:", p.min(),\
" max:", p.max(), " sum:", p.sum()
- Retrieve a given hypercube
zctList = []
for z in range(sizeZ / 2, sizeZ): # get the top half of the Z-stack
for c in range(sizeC): # all channels
for t in range(sizeT): # all time-points
zctList.append((z, c, t))
print "\nHyper stack of planes:"
planes = pixels.getPlanes(zctList)
for i, p in enumerate(planes):
print "plane zct:", zctList[i], " min:", p.min(), " max:", p.max()
- Close connection:
# When you're done, close the session to free up server resources. conn._closeSession()
Write Data
- Create a connection
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT) conn.connect()
- Configuration
projectId = 3109 #Specify a local file. E.g. could be result of some analysis fileToUpload = "fileToUpload.txt" # This file should already exist
- Create a new Dataset
datasetObj = omero.model.DatasetI()
datasetObj.setName(rstring("New Dataset"))
datasetObj = conn.getUpdateService().saveAndReturnObject(datasetObj)
datasetId = datasetObj.getId().getValue()
print "New dataset, Id:", datasetId
- Link to Project
project = conn.getObject("Project", projectId)
if project is None:
import sys
sys.stderr.write("Error: Object does not exist.\n")
sys.exit(1)
link = omero.model.ProjectDatasetLinkI()
link.setParent(omero.model.ProjectI(project.getId(), False))
link.setChild(datasetObj)
conn.getUpdateService().saveObject(link)
- How to create a file annotation and link to a Dataset
dataset = conn.getObject("Dataset", datasetId)
# create the original file and file annotation (uploads the file etc.)
namespace = "imperial.training.demo"
print "\nCreating an OriginalFile and FileAnnotation"
fileAnn = conn.createFileAnnfromLocalFile(fileToUpload, mimetype="text/plain", ns=namespace, desc=None)
print "Attaching FileAnnotation to Dataset: ", "File ID:", fileAnn.getId(), ",", fileAnn.getFile().getName(), "Size:", fileAnn.getFile().getSize()
dataset.linkAnnotation(fileAnn) # link it to dataset.
- Download a file annotation linked to a Dataset
# make a location to download the file. "download" folder.
path = os.path.join(os.path.dirname(__file__), "download")
if not os.path.exists(path):
os.makedirs(path)
# Go through all the annotations on the Dataset. Download any file annotations we find.
print "\nAnnotations on Dataset:", dataset.getName()
for ann in dataset.listAnnotations():
if isinstance(ann, omero.gateway.FileAnnotationWrapper):
print "File ID:", ann.getFile().getId(), ann.getFile().getName(), "Size:", ann.getFile().getSize()
file_path = os.path.join(path, ann.getFile().getName())
f = open(str(file_path), 'w')
print "\nDownloading file to", file_path, "..."
try:
for chunk in ann.getFileInChunks():
f.write(chunk)
finally:
f.close()
print "File downloaded!"
- Load all the file annotations with a given namespace
nsToInclude = [namespace]
nsToExclude = []
metadataService = conn.getMetadataService()
annotations = metadataService.loadSpecifiedAnnotations('omero.model.FileAnnotation', nsToInclude, nsToExclude, None)
for ann in annotations:
print ann.getId().getValue(), ann.file.name.val
- Get first annotation with specified namespace
ann = dataset.getAnnotation(namespace) print "Found Annotation with namespace: ", ann.getNs()
- Close connection:
# When you're done, close the session to free up server resources. conn._closeSession()
OMERO tables
- Create a connection
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT) conn.connect()
- Configuration
datasetId = 51
- Create a name for the Original File (should be unique)
from random import random tablename = "TablesDemo:%s" % str(random())
col1 = omero.grid.LongColumn('Uid', 'testLong', [])
col2 = omero.grid.StringColumn('MyStringColumnInit', '', 64, [])
columns = [col1, col2]
- Create and initialize a new table.
repositoryId = 1 table = conn.c.sf.sharedResources().newTable(repositoryId, tablename) table.initialize(columns)
- Add data to the table.
ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
strings = ["one", "two", "three", "four", "five",\
"six", "seven", "eight", "nine", "ten"]
data1 = omero.grid.LongColumn('Uid', 'test Long', ids)
data2 = omero.grid.StringColumn('MyStringColumn', '', 64, strings)
data = [data1, data2]
table.addData(data)
table.close() # when we're done, close.
- Get the table as an original file...
orig_file = table.getOriginalFile() orig_file_id = orig_file.id.val # ...so you can attach this data to an object. E.g. Dataset fileAnn = omero.model.FileAnnotationI() fileAnn.setFile(omero.model.OriginalFileI(orig_file_id, False)) # use unloaded OriginalFileI fileAnn = conn.getUpdateService().saveAndReturnObject(fileAnn) link = omero.model.DatasetAnnotationLinkI() link.setParent(omero.model.DatasetI(datasetId, False)) link.setChild(omero.model.FileAnnotationI(fileAnn.id.val, False)) conn.getUpdateService().saveAndReturnObject(link)
- Table API
# See: [http://hudson.openmicroscopy.org.uk/job/OMERO/javadoc/slice]2html/omero/grid/Table.html openTable = conn.c.sf.sharedResources().openTable(orig_file)
print "Table Columns:"
for col in openTable.getHeaders():
print " ", col.name
rowCount = openTable.getNumberOfRows() print "Row count:", rowCount
- Get data from every column of the specified rows
rowNumbers = [3, 5, 7]
print "\nGet All Data for rows: ", rowNumbers
data = openTable.readCoordinates(range(rowCount))
for col in data.columns:
print "Data for Column: ", col.name
for v in col.values:
print " ", v
- Get data from specified columns of specified rows
colNumbers = [1]
start = 3
stop = 7
print "\nGet Data for cols: ", colNumbers,\
" and between rows: ", start, "-", stop
data = openTable.read(colNumbers, start, stop)
for col in data.columns:
print "Data for Column: ", col.name
for v in col.values:
print " ", v
- Query the table for rows where the 'Uid' is in a particular range
queryRows = openTable.getWhereList("(Uid > 2) & (Uid <= 8)",\
variables={}, start=0, stop=rowCount, step=0)
data = openTable.readCoordinates(queryRows)
for col in data.columns:
print "Query Results for Column: ", col.name
for v in col.values:
print " ", v
openTable.close() # we're done
- In future, to get the table back from Original File
orig_table_file = conn.getObject("OriginalFile", attributes={'name': tablename}) # if name is unique
savedTable = conn.c.sf.sharedResources().openTable(orig_table_file._obj)
print "Opened table with row-count:", savedTable.getNumberOfRows()
- Close connection:
# When you're done, close the session to free up server resources. conn._closeSession()
ROIs
- Create a connection
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT) conn.connect() updateService = conn.getUpdateService()
- Configuration
imageId = 27544
- Create ROI.
# We are using the core Python API and omero.model objects here, since ROIs are
# not yet supported in the Python Blitz Gateway.
#
# In this example, we create an ROI with a rectangular shape and attach it to an
# image.
x = 50
y = 200
width = 100
height = 50
image = conn.getObject("Image", imageId)
theZ = image.getSizeZ() / 2
theT = 0
print "Adding a rectangle at theZ: %s, theT: %s, X: %s, Y: %s, width: %s, height: %s" % \
(theZ, theT, x, y, width, height)
# create an ROI, link it to Image roi = omero.model.RoiI() roi.setImage(image._obj) # use the omero.model.ImageI that underlies the 'image' wrapper
# create a rectangle shape and add to ROI
rect = omero.model.RectI()
rect.x = rdouble(x)
rect.y = rdouble(y)
rect.width = rdouble(width)
rect.height = rdouble(height)
rect.theZ = rint(theZ)
rect.theT = rint(theT)
rect.textValue = rstring("test-Rectangle")
roi.addShape(rect)
# create an Ellips shape and add to ROI
ellipse = omero.model.EllipseI()
ellipse.cx = rdouble(y)
ellipse.cy = rdouble(x)
ellipse.rx = rdouble(width)
ellipse.ry = rdouble(height)
ellipse.theZ = rint(theZ)
ellipse.theT = rint(theT)
ellipse.textValue = rstring("test-Ellipse")
roi.addShape(ellipse)
# Save the ROI (saves any linked shapes too) r = updateService.saveAndReturnObject(roi)
- Retrieve ROIs linked to an Image.
roiService = conn.getRoiService()
result = roiService.findByImage(imageId, None)
for roi in result.rois:
print "ROI: ID:", roi.getId().getValue()
for s in roi.copyShapes():
shape = {}
shape['id'] = s.getId().getValue()
shape['theT'] = s.getTheT().getValue()
shape['theZ'] = s.getTheZ().getValue()
if s.getTextValue():
shape['textValue'] = s.getTextValue().getValue()
if type(s) == omero.model.RectI:
shape['type'] = 'Rectangle'
shape['x'] = s.getX().getValue()
shape['y'] = s.getY().getValue()
shape['width'] = s.getWidth().getValue()
shape['height'] = s.getHeight().getValue()
elif type(s) == omero.model.EllipseI:
shape['type'] = 'Ellipse'
shape['cx'] = s.getCx().getValue()
shape['cy'] = s.getCy().getValue()
shape['rx'] = s.getRx().getValue()
shape['ry'] = s.getRy().getValue()
elif type(s) == omero.model.PointI:
shape['type'] = 'Point'
shape['cx'] = s.getCx().getValue()
shape['cy'] = s.getCy().getValue()
elif type(s) == omero.model.LineI:
shape['type'] = 'Line'
shape['x1'] = s.getX1().getValue()
shape['x2'] = s.getX2().getValue()
shape['y1'] = s.getY1().getValue()
shape['y2'] = s.getY2().getValue()
elif type(s) in (omero.model.MaskI, omero.model.LabelI, omero.model.PolygonI):
print type(s), " Not supported by this code"
# Do some processing here, or just print:
print " Shape:",
for key, value in shape.items():
print " ", key, value,
print ""
- Remove shape from ROI
result = roiService.findByImage(imageId, None)
for roi in result.rois:
for s in roi.copyShapes():
# Find and remove the Shape we added above
if s.getTextValue() and s.getTextValue().getValue() == "test-Ellipse":
print "Removing Shape from ROI..."
roi.removeShape(s)
roi = updateService.saveAndReturnObject(roi)
- Close connection:
# When you're done, close the session to free up server resources. conn._closeSession()
Delete Data
- Create a connection
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT) conn.connect()
- Configuration
projectId = 3110
- Load the Project
project = conn.getObject("Project", projectId)
if project is None:
import sys
sys.stderr.write("Error: Object does not exist.\n")
sys.exit(1)
print "\nProject:", project.getName()
- Delete Project
# You can delete a number of objects of the same type at the same
# time. In this case 'Project'. Use deleteChildren=True if you are
# deleting a Project and you want to delete Datasets and Images.
obj_ids = [projectId]
deleteChildren = False
handle = conn.deleteObjects("Project", obj_ids,\
deleteAnns=True, deleteChildren=deleteChildren)
- Retrieve callback and wait until delete completes
callback = omero.callbacks.DeleteCallbackI(conn.c, handle) print "Deleting, please wait." while callback.block(500) is not None: # ms. print "." print "Errors:", handle.errors() callback.close()
Retrieve callback from string
If you've stored the string representation of the callback, then you can load the handle proxy to see the state of the delete.
import Ice callback as string cbString = str(handle) try: post_handle = omero.api.delete.DeleteHandlePrx?.checkedCast(\ conn.c.ic.stringToProxy(cbString)) self.fail("exception Ice.ObjectNotExistException? was not thrown") except Ice.ObjectNotExistException?: pass
Close connection:
# When you're done, close the session to free up server resources. conn._closeSession()
Render Images
- Create a connection
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT) conn.connect()
- Configuration
imageId = 27544
- Get thumbnail
# Thumbnail is created using the current rendering settings on the image
image = conn.getObject("Image", imageId)
img_data = image.getThumbnail()
renderedThumb = Image.open(StringIO(img_data))
#renderedThumb.show() # shows a pop-up
renderedThumb.save("thumbnail.jpg")
- Get current settings
print "Channel rendering settings:"
for ch in image.getChannels():
print "Name: ", ch.getLabel() # if no name, get emission wavelength or index
print " Color:", ch.getColor().getHtml()
print " Active:", ch.isActive()
print " Levels:", ch.getWindowStart(), "-", ch.getWindowEnd()
print "isGreyscaleRenderingModel:", image.isGreyscaleRenderingModel()
- Render each channel as a separate greyscale image
image.setGreyscaleRenderingModel()
sizeC = image.getSizeC()
z = image.getSizeZ() / 2
t = 0
for c in range(1, sizeC + 1): # Channel index starts at 1
channels = [c] # Turn on a single channel at a time
image.setActiveChannels(channels)
renderedImage = image.renderImage(z, t)
#renderedImage.show() # popup (use for debug only)
renderedImage.save("channel%s.jpg" % c) # save in the current folder
- Turn 3 channels on, setting their colours
image.setColorRenderingModel()
channels = [1, 2, 3]
colorList = ['F00', None, 'FFFF00'] # don't change colour of 2nd channel
image.setActiveChannels(channels, colors=colorList)
image.setProjection('intmax') # max intensity projection 'intmean' for mean-intensity
renderedImage = image.renderImage(z, t) # z and t are ignored for projections
#renderedImage.show()
renderedImage.save("all_channels.jpg")
image.setProjection('normal') # turn off projection
- Turn 2 channels on, setting levels of the first one
channels = [1, 2]
rangeList = [(100.0, 120.2), (None, None)]
image.setActiveChannels(channels, windows=rangeList)
renderedImage = image.renderImage(z, t, compression=0.5) # default compression is 0.9
#renderedImage.show()
renderedImage.save("two_channels.jpg")
- Save the current rendering settings
image.saveDefaults()
- Close connection:
# When you're done, close the session to free up server resources. conn._closeSession()
Create Image
- Create a connection
conn = BlitzGateway(USERNAME, PASSWORD, host=HOST, port=PORT) conn.connect()
- Configuration
imageId = 27544 # This image must have at least 2 channels
- Create an image from scratch
# This example demonstrates the usage of the convenience method # createImageFromNumpySeq() Here we create a multi-dimensional image from a # hard-coded array of data. from numpy import array sizeX, sizeY, sizeZ, sizeC, sizeT = 5, 4, 1, 2, 1 plane1 = array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) plane2 = array([[5, 6, 7, 8, 9], [0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [0, 1, 2, 3, 4]]) planes = [plane1, plane2]
def planeGen():
"""generator will yield planes"""
for p in planes:
yield p
desc = "Image created from a hard-coded arrays"
i = conn.createImageFromNumpySeq(planeGen(), "numpy image",\
sizeZ, sizeC, sizeT, description=desc, dataset=None)
- Create an Image from an existing image
# We are going to create a new image by passing the method a 'generator' of 2D
# planes This will come from an existing image, by taking the average of 2 channels.
zctList = []
image = conn.getObject('Image', imageId)
sizeZ, sizeC, sizeT = image.getSizeZ(), image.getSizeC(), image.getSizeT()
dataset = image.getParent()
pixels = image.getPrimaryPixels()
newSizeC = 1
def planeGen():
"""
set up a generator of 2D numpy arrays.
The createImage method below expects planes in the order specified here (for
z.. for c.. for t..)
"""
for z in range(sizeZ): # all Z sections
for c in range(newSizeC): # Illustrative purposes only, since we only have 1 channel
for t in range(sizeT): # all time-points
channel0 = pixels.getPlane(z, 0, t)
channel1 = pixels.getPlane(z, 1, t)
# Here we can manipulate the data in many different ways. As an example we're doing "average"
newPlane = (channel0 + channel1) / 2 # average of 2 channels
print "newPlane for z,t:", z, t, newPlane.dtype, newPlane.min(), newPlane.max()
yield newPlane
desc = "Image created from Image ID: %s by averaging Channel 1 and Channel 2" % imageId
i = conn.createImageFromNumpySeq(planeGen(), "new image",\
sizeZ, newSizeC, sizeT, description=desc, dataset=dataset)
- Close connection:
# When you're done, close the session to free up server resources. conn._closeSession()
Python OMERO.scripts
- Script definition
Script name, description and 2 parameters are defined here. These parameters will be recognised by the Insight and web clients and populated with the currently selected Image(s)
dataTypes = [rstring('Image')] # this script only takes Images (not Datasets etc.)
client = scripts.client("Scripting_Service_Example.py",
"""Example script to use as a template for getting started with the scripting service.""",
# first parameter
scripts.String("Data_Type", optional=False, values=dataTypes, default="Image"),
# second parameter
scripts.List("IDs", optional=False).ofType(rlong(0)),
)
# we can now create our Blitz Gateway by wrapping the client object
conn = BlitzGateway(client_obj=client)
# get the 'IDs' parameter (which we have restricted to 'Image' IDs)
ids = unwrap(client.getInput("IDs"))
imageId = ids[0] # simply use the first ID for this example
# ** paste here **
# Replace the code block below. NB: we have established a connection "conn" and we have an "imageId"
image = conn.getObject("Image", imageId)
print image.getName()
- Return some value(s).
Here, we return anything useful the script has produced. NB: The Insight and web clients will display the "Message" output.
message = "Script ran with Image ID: %s, Name: %s" % (imageId, image.getName())
client.setOutput("Message", rstring(message))
client.closeSession()