From 1ae9fffdc1db698681c84715fc16aee16be71c30 Mon Sep 17 00:00:00 2001 From: William Moore Date: Fri, 9 Dec 2016 16:24:15 +0000 Subject: [PATCH 01/11] Blitz static _getQueryString() --- .../OmeroPy/src/omero/gateway/__init__.py | 235 ++++++++---------- 1 file changed, 103 insertions(+), 132 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index c1d750ba5fb..671baac9178 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -270,7 +270,8 @@ def _unwrapunits(self, obj, units=None): return obj return obj.getValue() - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("Project"). @@ -292,13 +293,13 @@ def _getQueryString(self, opts=None): child_count = False if opts is not None and 'child_count' in opts: child_count = opts['child_count'] - if child_count and self.LINK_CLASS is not None: + if child_count and klass.LINK_CLASS is not None: extra_select = """, (select count(id) from %s chl - where chl.parent=obj.id)""" % self.LINK_CLASS + where chl.parent=obj.id)""" % klass.LINK_CLASS query = ("select obj %s from %s obj " "join fetch obj.details.owner as owner " "join fetch obj.details.creationEvent" % - (extra_select, self.OMERO_CLASS)) + (extra_select, klass.OMERO_CLASS)) params = omero.sys.ParametersI() clauses = [] @@ -2610,8 +2611,7 @@ def listOrphans(self, obj_type, eid=None, params=None, loadPixels=False): params = omero.sys.ParametersI() wrapper = KNOWN_WRAPPERS.get(obj_type.lower(), None) - query = wrapper()._getQueryString() - query = wrapper()._getQueryString()[0] + query = wrapper._getQueryString()[0] if loadPixels and obj_type == 'Image': # left outer join so we don't exclude @@ -3125,6 +3125,9 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None, # get the base query from the instantiated object itself. E.g "select # obj Project as obj" + # NB: _getQueryString() is a classmethod BUT we still need to + # call wrapper() to instantiate the base Wrapper Classes that have + # the OMERO_CLASS defined query, clauses, baseParams = wrapper()._getQueryString(opts) # Handle dict of parameters -> convert to ParametersI() @@ -4580,7 +4583,8 @@ def __eq__(self, a): self.getValue() == a.getValue() and self.getNs() == a.getNs()) - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("Annotation") @@ -4745,7 +4749,8 @@ def __init__(self, *args, **kwargs): _attrs = ('file|OriginalFileWrapper',) - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("FileAnnotation"). @@ -4852,8 +4857,7 @@ class _OriginalFileWrapper (BlitzObjectWrapper, OmeroRestrictionWrapper): omero_model_OriginalFileI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'OriginalFile' + OMERO_CLASS = 'OriginalFile' def getFileInChunks(self, buf=2621440): """ @@ -4892,7 +4896,8 @@ class TimestampAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = TimestampAnnotationI - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("TimestampAnnotation"). @@ -4946,7 +4951,8 @@ class BooleanAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = BooleanAnnotationI - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("BooleanAnnotation"). @@ -5037,7 +5043,8 @@ def listParents(self, withlinks=True): self._conn, l.parent, l)) return rv - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("TagAnnotation"). @@ -5084,7 +5091,8 @@ class CommentAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = CommentAnnotationI - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("CommentAnnotation"). @@ -5129,7 +5137,8 @@ class LongAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = LongAnnotationI - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("LongAnnotation"). @@ -5175,7 +5184,8 @@ class DoubleAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = DoubleAnnotationI - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("DoubleAnnotation"). @@ -5222,7 +5232,8 @@ class TermAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = TermAnnotationI - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("TermAnnotation"). @@ -5326,11 +5337,10 @@ class _ExperimenterWrapper (BlitzObjectWrapper): omero_model_ExperimenterI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'Experimenter' - self.LINK_CLASS = "GroupExperimenterMap" - self.CHILD_WRAPPER_CLASS = None - self.PARENT_WRAPPER_CLASS = 'ExperimenterGroupWrapper' + OMERO_CLASS = 'Experimenter' + LINK_CLASS = "GroupExperimenterMap" + CHILD_WRAPPER_CLASS = None + PARENT_WRAPPER_CLASS = 'ExperimenterGroupWrapper' def simpleMarshal(self, xtra=None, parents=False): rv = super(_ExperimenterWrapper, self).simpleMarshal( @@ -5346,7 +5356,8 @@ def simpleMarshal(self, xtra=None, parents=False): 'isAdmin': isAdmin, }) return rv - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Returns string for building queries, loading Experimenters only. @@ -5575,13 +5586,13 @@ class _ExperimenterGroupWrapper (BlitzObjectWrapper): omero_model_ExperimenterGroupI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'ExperimenterGroup' - self.LINK_CLASS = "GroupExperimenterMap" - self.CHILD_WRAPPER_CLASS = 'ExperimenterWrapper' - self.PARENT_WRAPPER_CLASS = None + OMERO_CLASS = 'ExperimenterGroup' + LINK_CLASS = "GroupExperimenterMap" + CHILD_WRAPPER_CLASS = 'ExperimenterWrapper' + PARENT_WRAPPER_CLASS = None - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Returns string for building queries, loading Experimenters for each group. @@ -5673,13 +5684,13 @@ class _DatasetWrapper (BlitzObjectWrapper): omero_model_DatasetI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'Dataset' - self.LINK_CLASS = "DatasetImageLink" - self.CHILD_WRAPPER_CLASS = 'ImageWrapper' - self.PARENT_WRAPPER_CLASS = 'ProjectWrapper' + OMERO_CLASS = 'Dataset' + LINK_CLASS = "DatasetImageLink" + CHILD_WRAPPER_CLASS = 'ImageWrapper' + PARENT_WRAPPER_CLASS = 'ProjectWrapper' - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Extend base query to handle filtering of Datasets by Projects. Returns a tuple of (query, clauses, params). @@ -5689,7 +5700,7 @@ def _getQueryString(self, opts=None): :return: Tuple of string, list, ParametersI """ query, clauses, params = super( - _DatasetWrapper, self)._getQueryString(opts) + _DatasetWrapper, klass)._getQueryString(opts) if opts is not None and 'project' in opts: query += ' join obj.projectLinks plink' clauses.append('plink.parent.id = :pid') @@ -5718,11 +5729,10 @@ class _ProjectWrapper (BlitzObjectWrapper): omero_model_ProjectI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'Project' - self.LINK_CLASS = "ProjectDatasetLink" - self.CHILD_WRAPPER_CLASS = 'DatasetWrapper' - self.PARENT_WRAPPER_CLASS = None + OMERO_CLASS = 'Project' + LINK_CLASS = "ProjectDatasetLink" + CHILD_WRAPPER_CLASS = 'DatasetWrapper' + PARENT_WRAPPER_CLASS = None ProjectWrapper = _ProjectWrapper @@ -5732,11 +5742,10 @@ class _ScreenWrapper (BlitzObjectWrapper): omero_model_ScreenI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'Screen' - self.LINK_CLASS = "ScreenPlateLink" - self.CHILD_WRAPPER_CLASS = 'PlateWrapper' - self.PARENT_WRAPPER_CLASS = None + OMERO_CLASS = 'Screen' + LINK_CLASS = "ScreenPlateLink" + CHILD_WRAPPER_CLASS = 'PlateWrapper' + PARENT_WRAPPER_CLASS = None ScreenWrapper = _ScreenWrapper @@ -5757,11 +5766,10 @@ class _PlateWrapper (BlitzObjectWrapper, OmeroRestrictionWrapper): omero_model_PlateI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'Plate' - self.LINK_CLASS = None - self.CHILD_WRAPPER_CLASS = 'WellWrapper' - self.PARENT_WRAPPER_CLASS = 'ScreenWrapper' + OMERO_CLASS = 'Plate' + LINK_CLASS = None + CHILD_WRAPPER_CLASS = 'WellWrapper' + PARENT_WRAPPER_CLASS = 'ScreenWrapper' def __prepare__(self): self.__reset__() @@ -5948,7 +5956,8 @@ def exportOmeTiff(self): """ return None - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Returns a query string for constructing custom queries, loading the screen for each plate. @@ -5970,8 +5979,7 @@ def _getQueryString(self, opts=None): class _PlateAcquisitionWrapper (BlitzObjectWrapper): - def __bstrap__(self): - self.OMERO_CLASS = 'PlateAcquisition' + OMERO_CLASS = 'PlateAcquisition' def getName(self): name = super(_PlateAcquisitionWrapper, self).getName() @@ -6003,11 +6011,10 @@ class _WellWrapper (BlitzObjectWrapper, OmeroRestrictionWrapper): omero_model_WellI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'Well' - self.LINK_CLASS = None - self.CHILD_WRAPPER_CLASS = 'WellSampleWrapper' - self.PARENT_WRAPPER_CLASS = 'PlateWrapper' + OMERO_CLASS = 'Well' + LINK_CLASS = None + CHILD_WRAPPER_CLASS = 'WellSampleWrapper' + PARENT_WRAPPER_CLASS = 'PlateWrapper' def __prepare__(self, **kwargs): try: @@ -6198,13 +6205,12 @@ class _WellSampleWrapper (BlitzObjectWrapper): omero_model_WellSampleI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'WellSample' - self.CHILD_WRAPPER_CLASS = 'ImageWrapper' - self.PARENT_WRAPPER_CLASS = 'WellWrapper' - self.LINK_CLASS = 'WellSample' - self.LINK_PARENT = lambda x: x - self.LINK_CHILD = 'image' + OMERO_CLASS = 'WellSample' + CHILD_WRAPPER_CLASS = 'ImageWrapper' + PARENT_WRAPPER_CLASS = 'WellWrapper' + LINK_CLASS = 'WellSample' + LINK_PARENT = lambda x: x + LINK_CHILD = 'image' def listParents(self, withlinks=False): """ @@ -6256,17 +6262,6 @@ def getPlateAcquisition(self): WellSampleWrapper = _WellSampleWrapper -# class CategoryWrapper (BlitzObjectWrapper): -# def __bstrap__ (self): -# self.LINK_CLASS = "CategoryImageLink" -# self.CHILD_WRAPPER_CLASS = ImageWrapper -# self.PARENT_WRAPPER_CLASS= 'CategoryGroupWrapper' -# -# class CategoryGroupWrapper (BlitzObjectWrapper): -# def __bstrap__ (self): -# self.LINK_CLASS = "CategoryGroupCategoryLink" -# self.CHILD_WRAPPER_CLASS = CategoryWrapper -# self.PARENT_WRAPPER_CLASS = None # IMAGE # @@ -6495,8 +6490,7 @@ class _LightPathWrapper (BlitzObjectWrapper): '()emissionFilters|', '()excitationFilters|') - def __bstrap__(self): - self.OMERO_CLASS = 'LightPath' + OMERO_CLASS = 'LightPath' def getExcitationFilters(self): """ Returns list of excitation :class:`FilterWrapper`. Ordered @@ -6518,8 +6512,7 @@ class _PlaneInfoWrapper (BlitzObjectWrapper): omero_model_PlaneInfo class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = "PlaneInfo" + OMERO_CLASS = "PlaneInfo" def getDeltaT(self, units=None): """ @@ -6555,8 +6548,7 @@ class _PixelsWrapper (BlitzObjectWrapper): omero_model_PixelsI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'Pixels' + OMERO_CLASS = 'Pixels' def _prepareRawPixelsStore(self): """ @@ -6718,10 +6710,10 @@ class _FilesetWrapper (BlitzObjectWrapper): omero_model_FilesetI class wrapper extends BlitzObjectWrapper """ - def __bstrap__(self): - self.OMERO_CLASS = 'Fileset' + OMERO_CLASS = 'Fileset' - def _getQueryString(self, opts=None): + @classmethod + def _getQueryString(klass, opts=None): """ Used for building queries in generic methods such as getObjects("Fileset"). @@ -6768,8 +6760,7 @@ class _ChannelWrapper (BlitzObjectWrapper): (RED_MIN, RED_MAX, ColorHolder('Red')), ) - def __bstrap__(self): - self.OMERO_CLASS = 'Channel' + OMERO_CLASS = 'Channel' def __prepare__(self, idx=-1, re=None, img=None): """ @@ -7111,12 +7102,11 @@ def fromPixelsId(self, conn, pid): return None return ImageWrapper(conn, p.image) - def __bstrap__(self): - self.OMERO_CLASS = 'Image' - self.LINK_CLASS = None - self.CHILD_WRAPPER_CLASS = None - self.PARENT_WRAPPER_CLASS = ['DatasetWrapper', 'WellSampleWrapper'] - self._thumbInProgress = False + OMERO_CLASS = 'Image' + LINK_CLASS = None + CHILD_WRAPPER_CLASS = None + PARENT_WRAPPER_CLASS = ['DatasetWrapper', 'WellSampleWrapper'] + _thumbInProgress = False def __del__(self): self._re and self._re.untaint() @@ -9399,8 +9389,7 @@ class _ImagingEnviromentWrapper (BlitzObjectWrapper): 'co2percent', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'ImagingEnvironment' + OMERO_CLASS = 'ImagingEnvironment' ImagingEnviromentWrapper = _ImagingEnviromentWrapper @@ -9416,8 +9405,7 @@ class _TransmittanceRangeWrapper (BlitzObjectWrapper): 'transmittance', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'TransmittanceRange' + OMERO_CLASS = 'TransmittanceRange' TransmittanceRangeWrapper = _TransmittanceRangeWrapper @@ -9434,8 +9422,7 @@ class _DetectorSettingsWrapper (BlitzObjectWrapper): 'detector|DetectorWrapper', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'DetectorSettings' + OMERO_CLASS = 'DetectorSettings' DetectorSettingsWrapper = _DetectorSettingsWrapper @@ -9445,8 +9432,7 @@ class _BinningWrapper (BlitzObjectWrapper): omero_model_BinningI class wrapper extends BlitzObjectWrapper. """ - def __bstrap__(self): - self.OMERO_CLASS = 'Binning' + OMERO_CLASS = 'Binning' BinningWrapper = _BinningWrapper @@ -9466,8 +9452,7 @@ class _DetectorWrapper (BlitzObjectWrapper): '#type;detectorType', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'Detector' + OMERO_CLASS = 'Detector' def getDetectorType(self): """ @@ -9503,8 +9488,7 @@ class _ObjectiveWrapper (BlitzObjectWrapper): 'iris', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'Objective' + OMERO_CLASS = 'Objective' def getImmersion(self): """ @@ -9564,8 +9548,7 @@ class _ObjectiveSettingsWrapper (BlitzObjectWrapper): 'objective|ObjectiveWrapper', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'ObjectiveSettings' + OMERO_CLASS = 'ObjectiveSettings' def getObjective(self): """ @@ -9612,8 +9595,7 @@ class _FilterWrapper (BlitzObjectWrapper): 'transmittanceRange|TransmittanceRangeWrapper', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'Filter' + OMERO_CLASS = 'Filter' def getFilterType(self): """ @@ -9642,8 +9624,7 @@ class _DichroicWrapper (BlitzObjectWrapper): 'lotNumber', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'Dichroic' + OMERO_CLASS = 'Dichroic' DichroicWrapper = _DichroicWrapper @@ -9658,8 +9639,7 @@ class _FilterSetWrapper (BlitzObjectWrapper): 'dichroic|DichroicWrapper', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'FilterSet' + OMERO_CLASS = 'FilterSet' def copyEmissionFilters(self): """ TODO: not implemented """ @@ -9685,8 +9665,7 @@ class _OTFWrapper (BlitzObjectWrapper): 'objective|ObjectiveWrapper', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'OTF' + OMERO_CLASS = 'OTF' OTFWrapper = _OTFWrapper @@ -9701,8 +9680,7 @@ class _LightSettingsWrapper (BlitzObjectWrapper): 'microbeamManipulation', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'LightSettings' + OMERO_CLASS = 'LightSettings' def getLightSource(self): if self._obj.lightSource is None: @@ -9774,9 +9752,7 @@ class _FilamentWrapper (_LightSourceWrapper): omero_model_FilamentI class wrapper extends LightSourceWrapper. """ - def __bstrap__(self): - super(_FilamentWrapper, self).__bstrap__() - self.OMERO_CLASS = 'Filament' + OMERO_CLASS = 'Filament' FilamentWrapper = _FilamentWrapper _LightSourceClasses[omero.model.FilamentI] = 'FilamentWrapper' @@ -9787,9 +9763,7 @@ class _ArcWrapper (_FilamentWrapper): omero_model_ArcI class wrapper extends FilamentWrapper. """ - def __bstrap__(self): - super(_ArcWrapper, self).__bstrap__() - self.OMERO_CLASS = 'Arc' + OMERO_CLASS = 'Arc' ArcWrapper = _ArcWrapper _LightSourceClasses[omero.model.ArcI] = 'ArcWrapper' @@ -9800,9 +9774,10 @@ class _LaserWrapper (_LightSourceWrapper): omero_model_LaserI class wrapper extends LightSourceWrapper. """ + OMERO_CLASS = 'Laser' + def __bstrap__(self): super(_LaserWrapper, self).__bstrap__() - self.OMERO_CLASS = 'Laser' self._attrs += ( '#laserMedium', 'frequencyMultiplication', @@ -9848,9 +9823,7 @@ class _LightEmittingDiodeWrapper (_LightSourceWrapper): omero_model_LightEmittingDiodeI class wrapper extends LightSourceWrapper. """ - def __bstrap__(self): - super(_LightEmittingDiodeWrapper, self).__bstrap__() - self.OMERO_CLASS = 'LightEmittingDiode' + OMERO_CLASS = 'LightEmittingDiode' LightEmittingDiodeWrapper = _LightEmittingDiodeWrapper _LightSourceClasses[ @@ -9867,8 +9840,7 @@ class _MicroscopeWrapper (BlitzObjectWrapper): '#type;microscopeType', 'version') - def __bstrap__(self): - self.OMERO_CLASS = 'Microscope' + OMERO_CLASS = 'Microscope' def getMicroscopeType(self): """ @@ -9897,8 +9869,7 @@ class _InstrumentWrapper (BlitzObjectWrapper): _attrs = ('microscope|MicroscopeWrapper',) - def __bstrap__(self): - self.OMERO_CLASS = 'Instrument' + OMERO_CLASS = 'Instrument' def getMicroscope(self): """ From 9b2f18ad3ba1ec921d5fb7178814b1cd8b580ef1 Mon Sep 17 00:00:00 2001 From: William Moore Date: Fri, 9 Dec 2016 16:24:45 +0000 Subject: [PATCH 02/11] test_build_query checks 'None' not in query --- .../tools/OmeroPy/test/unit/gatewaytest/test_build_query.py | 1 + 1 file changed, 1 insertion(+) diff --git a/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py b/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py index 29e7aee6bf5..a0d6cd1e00c 100644 --- a/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py +++ b/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py @@ -46,6 +46,7 @@ def test_no_clauses(self, gateway, dtype): assert isinstance(wrapper(), BlitzObjectWrapper) assert query.startswith("select ") assert "where" not in query + assert 'None' not in query @pytest.mark.parametrize("dtype", KNOWN_WRAPPERS.keys()) def test_filter_by_owner(self, gateway, dtype): From ab9eba9b97986f65a972699567ee7cc7dd4f075a Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 12 Dec 2016 10:28:26 +0000 Subject: [PATCH 03/11] Use klass._getQueryString() instead of wrapper() --- .../tools/OmeroPy/src/omero/gateway/__init__.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 671baac9178..12034648830 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -3123,12 +3123,14 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None, offset = None limit = None - # get the base query from the instantiated object itself. E.g "select - # obj Project as obj" - # NB: _getQueryString() is a classmethod BUT we still need to - # call wrapper() to instantiate the base Wrapper Classes that have - # the OMERO_CLASS defined - query, clauses, baseParams = wrapper()._getQueryString(opts) + # We get the query from the ObjectWrapper class: + if wrapper.__name__ == "_wrap": + # If wrapper is the AnnotationWrapper._wrap class method, we + # need to get the underlying AnnotationWrapper class + klass = wrapper() + else: + klass = wrapper + query, clauses, baseParams = klass._getQueryString(opts) # Handle dict of parameters -> convert to ParametersI() if opts is not None: From 1920da210fb1c821cb5d46da0ecab99dd4f62175 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 12 Dec 2016 14:48:45 +0000 Subject: [PATCH 04/11] @staticmethod def LINK_PARENT(link) for WellSampleWrapper --- components/tools/OmeroPy/src/omero/gateway/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 12034648830..422e3f7066c 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -6211,8 +6211,12 @@ class _WellSampleWrapper (BlitzObjectWrapper): CHILD_WRAPPER_CLASS = 'ImageWrapper' PARENT_WRAPPER_CLASS = 'WellWrapper' LINK_CLASS = 'WellSample' - LINK_PARENT = lambda x: x LINK_CHILD = 'image' + + @staticmethod + def LINK_PARENT(link): + """Direct parent is Well. No Link between Well and WellSample.""" + return link def listParents(self, withlinks=False): """ From c16183c9cb207a2d9587bc3086ac7d45aefc3203 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 12 Dec 2016 14:50:07 +0000 Subject: [PATCH 05/11] Remove commented-out code in blitz _getParentWrappers() --- components/tools/OmeroPy/src/omero/gateway/__init__.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 422e3f7066c..6706f93e7d9 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -354,14 +354,7 @@ def _getParentWrappers(self): raise NotImplementedError pwc[i] = g[pwc[i]] - # if type(self.PARENT_WRAPPER_CLASS) is type(''): - # # resolve class - # g = globals() - # if not g.has_key(self.PARENT_WRAPPER_CLASS): #pragma: no cover - # raise NotImplementedError - # self.__class__.PARENT_WRAPPER_CLASS \ - # = self.PARENT_WRAPPER_CLASS = g[self.PARENT_WRAPPER_CLASS] - # return self.PARENT_WRAPPER_CLASS + # Cache this so we don't need to resolve classes again if (pwc != self.PARENT_WRAPPER_CLASS or pwc != self.__class__.PARENT_WRAPPER_CLASS): self.__class__.PARENT_WRAPPER_CLASS \ From 16ca0e7ec3d26570e393f406c4a58fa164e311e1 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 12 Dec 2016 14:51:28 +0000 Subject: [PATCH 06/11] Remove unused image.getParent() in metadata_general.html This was only found because it was causing an error See https://github.com/openmicroscopy/openmicroscopy/pull/4993#issuecomment-266382166 --- .../templates/webclient/annotations/metadata_general.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/webclient/templates/webclient/annotations/metadata_general.html b/components/tools/OmeroWeb/omeroweb/webclient/templates/webclient/annotations/metadata_general.html index 988841c69f4..430e6734eb5 100644 --- a/components/tools/OmeroWeb/omeroweb/webclient/templates/webclient/annotations/metadata_general.html +++ b/components/tools/OmeroWeb/omeroweb/webclient/templates/webclient/annotations/metadata_general.html @@ -503,7 +503,7 @@

- {% with image=manager.image parent=manager.image.getParent %} + {% with image=manager.image %} {% include "webclient/annotations/includes/core_metadata.html" %} {% endwith %} From fa172298dd1d59a0834a70db1e4154fff3869517 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 12 Dec 2016 15:40:07 +0000 Subject: [PATCH 07/11] Add to TestListParents --- .../gatewaytest/test_get_objects.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py index 1c3a141fe77..30ce174ef8a 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py @@ -20,6 +20,9 @@ from omero.gateway.scripts import dbhelpers from omero.rtypes import wrap +from omero.testlib import ITest +from omero.gateway import BlitzGateway, KNOWN_WRAPPERS +from omero.model import ScreenI, PlateI, WellI, WellSampleI class TestDeleteObject (object): @@ -794,3 +797,100 @@ def testGroupSummaryAsMemberDeprecated(self, gatewaywrapper): assert len(summary["leaders"]) == 1 assert summary["leaders"][0].omeName == "group_owner" assert len(summary["colleagues"]) == 0 + + +class TestListParents(ITest): + + def testSupportedObjects(self): + """ + Check that we are testing all objects where listParents() is supported. + + If this test fails, need to update tested_wrappers and add + corresponding tests below + """ + tested_wrappers = ['plate', 'image', 'dataset', 'experimenter', 'well'] + for key, wrapper in KNOWN_WRAPPERS.items(): + if (hasattr(wrapper, 'PARENT_WRAPPER_CLASS') and + wrapper.PARENT_WRAPPER_CLASS is not None): + assert key in tested_wrappers + + + def testListParentsPDI(self): + """Test listParents() for Image in Dataset""" + + # Set up PDI + client, exp = self.new_client_and_user() + p = self.make_project(name="ListParents Test", client=client) + d = self.make_dataset(name="ListParents Test", client=client) + i = self.make_image(name="ListParents Test", client=client) + self.link(p, d, client=client) + self.link(d, i, client=client) + + conn = BlitzGateway(client_obj=client) + image = conn.getObject("Image", i.id.val) + + # Traverse from Image -> Project + dataset = image.listParents()[0] + assert dataset.id == d.id.val + + project = dataset.listParents()[0] + assert project.id == p.id.val + # Project has no parent + assert len(project.listParents()) == 0 + + def testListParentsSPW(self): + """Test listParents() for Image in WellSample""" + + client, exp = self.new_client_and_user() + conn = BlitzGateway(client_obj=client) + + # setup SPW-WS-Img... + s = ScreenI() + s.name = wrap('ScreenA') + p = PlateI() + p.name = wrap('PlateA') + s.linkPlate(p) + w = WellI() + w.column = wrap(0) + w.row = wrap(0) + p.addWell(w) + s = client.sf.getUpdateService().saveAndReturnObject(s) + p = s.linkedPlateList()[0] + w = p.copyWells()[0] + i = self.make_image(name="SPW listParents", client=client) + ws = WellSampleI() + ws.image = i + ws.well = WellI(w.id.val, False) + w.addWellSample(ws) + ws = client.sf.getUpdateService().saveAndReturnObject(ws) + + # Traverse from Image -> Screen + image = conn.getObject("Image", i.id.val) + wellSample = image.listParents()[0] + + well = wellSample.listParents()[0] + assert well.id == w.id.val + + plate = well.listParents()[0] + assert plate.id == p.id.val + + screen = plate.listParents()[0] + assert screen.id == s.id.val + # Screen has no parent + assert len(screen.listParents()) == 0 + + def testExperimenterListParents(self): + """Test listParents() for Experimenter in ExperimenterGroup.""" + + client, exp = self.new_client_and_user() + conn = BlitzGateway(client_obj=client) + + userGroupId = conn.getAdminService().getSecurityRoles().userGroupId + exp = conn.getUser() + groups = exp.listParents() + assert len(groups) == 2 + gIds = [g.id for g in groups] + assert userGroupId in gIds + + # ExperimenterGroup has no parent + assert len(groups[0].listParents()) == 0 From f26ccd4d762016dd6d4b0eb23fbf530554c3c18c Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 12 Dec 2016 15:55:12 +0000 Subject: [PATCH 08/11] test_get_objects flake8 fix --- .../OmeroPy/test/integration/gatewaytest/test_get_objects.py | 1 - 1 file changed, 1 deletion(-) diff --git a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py index 30ce174ef8a..023b3dffced 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py @@ -814,7 +814,6 @@ def testSupportedObjects(self): wrapper.PARENT_WRAPPER_CLASS is not None): assert key in tested_wrappers - def testListParentsPDI(self): """Test listParents() for Image in Dataset""" From d9ae4df51807fa1a418d8995f7526e04f94c7e3d Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 12 Dec 2016 15:55:57 +0000 Subject: [PATCH 09/11] Blitz flake8 fix --- components/tools/OmeroPy/src/omero/gateway/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 6706f93e7d9..a85765e7323 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -6205,7 +6205,7 @@ class _WellSampleWrapper (BlitzObjectWrapper): PARENT_WRAPPER_CLASS = 'WellWrapper' LINK_CLASS = 'WellSample' LINK_CHILD = 'image' - + @staticmethod def LINK_PARENT(link): """Direct parent is Well. No Link between Well and WellSample.""" From ac56ea2939ccaadc523163115166483e67f7f0ac Mon Sep 17 00:00:00 2001 From: William Moore Date: Fri, 6 Jan 2017 10:51:07 +0000 Subject: [PATCH 10/11] Fix klass -> cls for getQueryString() --- .../OmeroPy/src/omero/gateway/__init__.py | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index a85765e7323..e9bb80c78aa 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -271,7 +271,7 @@ def _unwrapunits(self, obj, units=None): return obj.getValue() @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("Project"). @@ -293,13 +293,13 @@ def _getQueryString(klass, opts=None): child_count = False if opts is not None and 'child_count' in opts: child_count = opts['child_count'] - if child_count and klass.LINK_CLASS is not None: + if child_count and cls.LINK_CLASS is not None: extra_select = """, (select count(id) from %s chl - where chl.parent=obj.id)""" % klass.LINK_CLASS + where chl.parent=obj.id)""" % cls.LINK_CLASS query = ("select obj %s from %s obj " "join fetch obj.details.owner as owner " "join fetch obj.details.creationEvent" % - (extra_select, klass.OMERO_CLASS)) + (extra_select, cls.OMERO_CLASS)) params = omero.sys.ParametersI() clauses = [] @@ -3120,10 +3120,10 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None, if wrapper.__name__ == "_wrap": # If wrapper is the AnnotationWrapper._wrap class method, we # need to get the underlying AnnotationWrapper class - klass = wrapper() + cls = wrapper() else: - klass = wrapper - query, clauses, baseParams = klass._getQueryString(opts) + cls = wrapper + query, clauses, baseParams = cls._getQueryString(opts) # Handle dict of parameters -> convert to ParametersI() if opts is not None: @@ -4579,7 +4579,7 @@ def __eq__(self, a): self.getNs() == a.getNs()) @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("Annotation") @@ -4745,7 +4745,7 @@ def __init__(self, *args, **kwargs): _attrs = ('file|OriginalFileWrapper',) @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("FileAnnotation"). @@ -4892,7 +4892,7 @@ class TimestampAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = TimestampAnnotationI @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("TimestampAnnotation"). @@ -4947,7 +4947,7 @@ class BooleanAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = BooleanAnnotationI @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("BooleanAnnotation"). @@ -5039,7 +5039,7 @@ def listParents(self, withlinks=True): return rv @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("TagAnnotation"). @@ -5087,7 +5087,7 @@ class CommentAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = CommentAnnotationI @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("CommentAnnotation"). @@ -5133,7 +5133,7 @@ class LongAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = LongAnnotationI @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("LongAnnotation"). @@ -5180,7 +5180,7 @@ class DoubleAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = DoubleAnnotationI @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("DoubleAnnotation"). @@ -5228,7 +5228,7 @@ class TermAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = TermAnnotationI @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("TermAnnotation"). @@ -5352,7 +5352,7 @@ def simpleMarshal(self, xtra=None, parents=False): return rv @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Returns string for building queries, loading Experimenters only. @@ -5587,7 +5587,7 @@ class _ExperimenterGroupWrapper (BlitzObjectWrapper): PARENT_WRAPPER_CLASS = None @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Returns string for building queries, loading Experimenters for each group. @@ -5685,7 +5685,7 @@ class _DatasetWrapper (BlitzObjectWrapper): PARENT_WRAPPER_CLASS = 'ProjectWrapper' @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Extend base query to handle filtering of Datasets by Projects. Returns a tuple of (query, clauses, params). @@ -5695,7 +5695,7 @@ def _getQueryString(klass, opts=None): :return: Tuple of string, list, ParametersI """ query, clauses, params = super( - _DatasetWrapper, klass)._getQueryString(opts) + _DatasetWrapper, cls)._getQueryString(opts) if opts is not None and 'project' in opts: query += ' join obj.projectLinks plink' clauses.append('plink.parent.id = :pid') @@ -5952,7 +5952,7 @@ def exportOmeTiff(self): return None @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Returns a query string for constructing custom queries, loading the screen for each plate. @@ -6712,7 +6712,7 @@ class _FilesetWrapper (BlitzObjectWrapper): OMERO_CLASS = 'Fileset' @classmethod - def _getQueryString(klass, opts=None): + def _getQueryString(cls, opts=None): """ Used for building queries in generic methods such as getObjects("Fileset"). From 16e4ac2d2f47b175e74f3b04cf5ca3d6212668d4 Mon Sep 17 00:00:00 2001 From: William Moore Date: Fri, 6 Jan 2017 11:03:30 +0000 Subject: [PATCH 11/11] Fix klass -> cls for other @classmethods --- .../OmeroPy/src/omero/gateway/__init__.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index e9bb80c78aa..772217ea5d1 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -4595,7 +4595,7 @@ def _getQueryString(cls, opts=None): return query, [], omero.sys.ParametersI() @classmethod - def _register(klass, regklass): + def _register(cls, regklass): """ Adds the AnnotationWrapper regklass to class registry @@ -4604,10 +4604,10 @@ def _register(klass, regklass): :type regklass: :class:`AnnotationWrapper` subclass """ - klass.registry[regklass.OMERO_TYPE] = regklass + cls.registry[regklass.OMERO_TYPE] = regklass @classmethod - def _wrap(klass, conn=None, obj=None, link=None): + def _wrap(cls, conn=None, obj=None, link=None): """ Class method for creating :class:`AnnotationWrapper` subclasses based on the type of annotation object, using previously registered mapping @@ -4626,17 +4626,17 @@ def _wrap(klass, conn=None, obj=None, link=None): """ if obj is None: return AnnotationWrapper() - if obj.__class__ in klass.registry: + if obj.__class__ in cls.registry: kwargs = dict() if link is not None: kwargs['link'] = BlitzObjectWrapper(conn, link) - return klass.registry[obj.__class__](conn, obj, **kwargs) + return cls.registry[obj.__class__](conn, obj, **kwargs) else: # pragma: no cover logger.error("Failed to _wrap() annotation: %s" % obj.__class__) return None @classmethod - def createAndLink(klass, target, ns, val=None, sameOwner=False): + def createAndLink(cls, target, ns, val=None, sameOwner=False): """ Class method for creating an instance of this AnnotationWrapper, setting ns and value and linking to the target. @@ -4648,7 +4648,7 @@ def createAndLink(klass, target, ns, val=None, sameOwner=False): :param val: Value of annotation. E.g Long, Text, Boolean etc. """ - this = klass() + this = cls() this.setNs(ns) if val is not None: this.setValue(val) @@ -6287,7 +6287,7 @@ def __init__(self, colorname=None): self._color[colorname.lower()] = 255 @classmethod - def fromRGBA(klass, r, g, b, a): + def fromRGBA(cls, r, g, b, a): """ Class method for creating a ColorHolder from r,g,b,a values @@ -6303,7 +6303,7 @@ def fromRGBA(klass, r, g, b, a): :rtype: :class:`ColorHolder` """ - rv = klass() + rv = cls() rv.setRed(r) rv.setGreen(g) rv.setBlue(b) @@ -7083,7 +7083,7 @@ class _ImageWrapper (BlitzObjectWrapper, OmeroRestrictionWrapper): PLANEDEF = omero.romio.XY @classmethod - def fromPixelsId(self, conn, pid): + def fromPixelsId(cls, conn, pid): """ Creates a new Image wrapper with the image specified by pixels ID @@ -7096,7 +7096,7 @@ def fromPixelsId(self, conn, pid): """ q = conn.getQueryService() - p = q.find('Pixels', pid, self._conn.SERVICE_OPTS) + p = q.find('Pixels', pid, conn.SERVICE_OPTS) if p is None: return None return ImageWrapper(conn, p.image)