Page 1 of 1

Image getDataset()

PostPosted: Thu Mar 20, 2014 3:13 pm
by a.herbert
I have an image that is in two datasets. When I call getDataset() on my image object through the python API I receive an error:

Code: Select all
img = conn.getObject('Image',23228)
img.getDataset()


serverExceptionClass = ome.conditions.ApiUsageException
message = Query named:


select ds from Image i join i.datasetLinks dl join dl.parent ds
where i.id = 23228


has returned more than one Object
findBy methods must return a single value.
Please try findAllBy methods for queries which return Lists.


This happens because the image is in two datasets. However my code did not expect an error from the API. It just wanted to know the dataset so a new result image could be placed in the same dataset as the parent image.

However what is the expected behaviour of the method in this case? Should it error or return the first valid dataset from a list? Should it be changed to return a list or should there be a getDatasets() method to return a list.

We are using OMERO.server-4.4.10-ice34-b112.

Thanks,

Alex

Re: Image getDataset()

PostPosted: Fri Mar 21, 2014 2:23 pm
by wmoore
Hi Alex,

Just checked the current code for getDataset() and I see

Code: Select all
    def getDataset(self):
        """
        XXX: Deprecated since 4.3.2, use listParents(). (See #6660)
        Gets the Dataset that image is in, or None.
        Returns None if Image is in more than one Dataset.
       
        @return:    Dataset
        @rtype:     L{DatasetWrapper}
        """
       
        try:
            q = """
            select ds from Image i join i.datasetLinks dl join dl.parent ds
            where i.id = %i
            """ % self._obj.id.val
            query = self._conn.getQueryService()
            ds = query.findAllByQuery(q, None, self._conn.SERVICE_OPTS)
            if ds and len(ds) == 1:
                return DatasetWrapper(self._conn, ds[0])
        except: #pragma: no cover
            logger.debug('on getDataset')
            logger.debug(traceback.format_exc())
            return None


This shouldn't throw any exceptions if the image has multiple Datasets.
I notice that the 4.4. code uses

Code: Select all
ds = query.findByQuery(q,None, self._conn.SERVICE_OPTS)


which matches your exception, but this is still within a try / except, so I would have expected that to catch it and simply return None.

https://github.com/openmicroscopy/openm ... _.py#L6087

You can use listParents() to get all the Datasets, or simply getParent() which will return just one of them.

Cheers,

Will.

Re: Image getDataset()

PostPosted: Fri Mar 21, 2014 5:14 pm
by a.herbert
Hi Will,

I checked my error file and the error I saw was just a debug output from the API. The method did return None. My code then failed on the None object.

I have switched to using getParent() and that returns a dataset I can use.

Now I have an issue when I have created an image in the dataset and I would like to update the logical channels on the new image. I am setting the emission wavelengths and names so that they match the old image.

Code: Select all
if newImg._prepareRenderingEngine():
        renderingEngine = newImg._re

        pixels = renderingEngine.getPixels()
       
        for i, c in enumerate(pixels.iterateChannels()):
            lc = c.getLogicalChannel()
            lc.setEmissionWave(rint( ... ))
            lc.setExcitationWave(rint( ... ))
            lc.setName(rstring( ... ))
            updateService.saveObject(lc)


This throws an error on getLogicalChannel() if the Blitz connection context is in a different group from the one that contained the original image.

The scenario is that the user is a member of many groups. An image from the non-default group is selected for processing. At the end of processing a script connects to OMERO using the python API, identifies the parent dataset from the image ID and creates the new image in the same dataset. However since the dataset is not in the same group as the default group I get an ome.conditions.SecurityViolation when trying to set properties on the logical channels. If I set the Blitz connection group to the correct group then it all works fine:

Code: Select all
# Default group = 'Group1'
# Original image in a dataset in 'Group2'

conn = BlitzGateway( ... )
# Create image in original Dataset = Group2
# conn.getGroupFromContext().getName() != [group name of new image]
# When setting logical channels => Error

conn = BlitzGateway( ... )
conn.setGroupNameForSession('Group2')
# Create image in original Dataset = Group2
# When setting logical channels => All OK


Is there a method to find out the group name for an image? I believe that in the current OMERO an image can still only be a member of one group so this should be a single group ID.

Alex

Re: Image getDataset()

PostPosted: Sat Mar 22, 2014 11:30 pm
by wmoore
Hi Alex,

There is a way of creating a new Image in OMERO using all the channel metadata from an existing Image.

Code: Select all
conn.createImageFromNumpySeq()
now includes a parameter: sourceImageId - see:

https://github.com/openmicroscopy/openm ... _.py#L2784


We don't use the conn.setGroupNameForSession() now (that should really be deprecated). Instead, we simply set the group context in conn with:

Code: Select all
conn.SERVICE_OPTS.setOmeroGroup(<groupId>)


The SERVICE_OPTS dict is passed to all the OMERO API calls made by the Blitz Gateway.

You can use groupId of '-1' for cross-group queries, but for save operations you'll want to set it to the appropriate group.
Often we start off with '-1' for finding an object by it's ID (without needing to know which group it's in) and then switch group to save changes.

You can get the ID of any object via

Code: Select all
object.getDetails().group.id.val


If you want to use a different 'context' in a particular API call, without changing the existing context of the conn.SERVICE_OPTS, you can do something like

Code: Select all
ctx = conn.SERVICE_OPTS.copy()
ctx.setOmeroGroup(image.getDetails().group.id.val)
conn.getUpdateService().saveObject(obj, ctx)


E.g. see https://github.com/openmicroscopy/openm ... _.py#L5903

Will.

Re: Image getDataset()

PostPosted: Mon Mar 24, 2014 12:32 pm
by a.herbert
Hi Will,

Thanks for the help. Upon further reading of my script I noticed that I was already getting the group Id from the object.getDetails() method and setting the ID into the conn.SERVICE_OPTS property in a calling method. So my bug was something else.

I had a look at how the createImageFromNumpySeq() method created the image object and then updated some of the properties. I used this to alter my method of setting the new image channel details:

Code: Select all
# img is the original image.
# newImg is the new image.
# The new image has different ZCT dimensions so set the channels individually.
# emWaves, exWaves and cNames contain the wavelengths and names of the
# channels we have created.

groupId = img.getDetails().group.id.val
conn.SERVICE_OPTS.setOmeroGroup(groupId)

# Get the image again to refresh state
newImg = conn.getObject("Image", newImg.getId())
for i, c in enumerate(newImg.getChannels()):
    lc = c.getLogicalChannel()
    lc.setEmissionWave(rint(emWaves[i]))
    lc.setExcitationWave(rint(exWaves[i]))
    lc.setName(rstring(cNames[i]))
    updateService.saveObject(lc._obj, conn.SERVICE_OPTS)


If I use the same code but do not pass the SERVICE_OPTS to the saveObject method I get my security error. So this may have been the original problem. Explicitly passing in the desired group through the SERVICE_OPTS to the updateService.saveObject method solves my issue with non-default group images.

Note that I only do this when the new image does not have the same ZCT dimensions as the original image. In that case I just use the sourceImageId property in the createImageFromNumpySeq method. Very useful.

Thanks,

Alex