From 5f90abbc603e1a757b9023e6dbc431a87f1d6ca2 Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 17 Nov 2016 15:33:07 +0000 Subject: [PATCH 01/18] Blitz Gateway changes from PR #4945 --- .../OmeroPy/src/omero/gateway/__init__.py | 345 +++++++++++------- 1 file changed, 203 insertions(+), 142 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 27090109494..dda1ba5f3d1 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -13,7 +13,6 @@ # Set up the python include paths import os -THISPATH = os.path.dirname(os.path.abspath(__file__)) import warnings from collections import defaultdict @@ -44,7 +43,13 @@ from gettext import gettext as _ import logging +from math import sqrt + +from omero.rtypes import rstring, rint, rlong, rbool +from omero.rtypes import rtime, rlist, rdouble, unwrap + logger = logging.getLogger(__name__) +THISPATH = os.path.dirname(os.path.abspath(__file__)) try: from PIL import Image, ImageDraw, ImageFont # see ticket:2597 @@ -57,10 +62,6 @@ except: logger.error( 'No Pillow installed, line plots and split channel will fail!') -from math import sqrt - -from omero.rtypes import rstring, rint, rlong, rbool -from omero.rtypes import rtime, rlist, rdouble, unwrap def omero_type(val): @@ -211,9 +212,9 @@ def __eq__(self, a): :return: True if objects are same - see above :rtype: Boolean """ - return (type(a) == type(self) - and self._obj.id == a._obj.id - and self.getName() == a.getName()) + return (type(a) == type(self) and + self._obj.id == a._obj.id and + self.getName() == a.getName()) def __bstrap__(self): """ @@ -268,14 +269,26 @@ def _unwrapunits(self, obj, units=None): return obj return obj.getValue() - def _getQueryString(self): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("Project") """ - return ("select obj from %s obj join fetch obj.details.owner " - "as owner join fetch obj.details.group " - "join fetch obj.details.creationEvent" % self.OMERO_CLASS) + extra_select = "" + 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: + extra_select = """, (select count(id) from %s chl + where chl.parent=obj.id)""" % self.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)) + + params = omero.sys.ParametersI() + clauses = [] + return (query, clauses, params) def _getChildWrapper(self): """ @@ -334,8 +347,8 @@ def _getParentWrappers(self): # self.__class__.PARENT_WRAPPER_CLASS \ # = self.PARENT_WRAPPER_CLASS = g[self.PARENT_WRAPPER_CLASS] # return self.PARENT_WRAPPER_CLASS - if (pwc != self.PARENT_WRAPPER_CLASS - or pwc != self.__class__.PARENT_WRAPPER_CLASS): + if (pwc != self.PARENT_WRAPPER_CLASS or + pwc != self.__class__.PARENT_WRAPPER_CLASS): self.__class__.PARENT_WRAPPER_CLASS \ = self.PARENT_WRAPPER_CLASS = pwc return self.PARENT_WRAPPER_CLASS @@ -394,9 +407,9 @@ def findChildByName(self, name, description=None): """ for c in self.listChildren(): if c.getName() == name: - if (description is None - or omero_type(description) - == omero_type(c.getDescription())): + if (description is None or + omero_type(description) == + omero_type(c.getDescription())): return c return None @@ -422,8 +435,8 @@ def getDate(self): """ try: - if (self._obj.acquisitionDate.val is not None - and self._obj.acquisitionDate.val > 0): + if (self._obj.acquisitionDate.val is not None and + self._obj.acquisitionDate.val > 0): t = self._obj.acquisitionDate.val return datetime.fromtimestamp(t/1000) except: @@ -460,9 +473,9 @@ def saveAs(self, details): """ if self._conn.isAdmin(): d = self.getDetails() - if (d.getOwner() - and d.getOwner().omeName == details.getOwner().omeName - and d.getGroup().name == details.getGroup().name): + if (d.getOwner() and + d.getOwner().omeName == details.getOwner().omeName and + d.getGroup().name == details.getGroup().name): return self.save() else: newConn = self._conn.suConn( @@ -863,8 +876,8 @@ def _getAnnotationLinks(self, ns=None): rv = self.copyAnnotationLinks() if ns is not None: rv = filter( - lambda x: x.getChild().getNs() - and x.getChild().getNs().val == ns, rv) + lambda x: x.getChild().getNs() and + x.getChild().getNs().val == ns, rv) return rv def unlinkAnnotations(self, ns): @@ -1019,12 +1032,12 @@ def linkAnnotation(self, ann, sameOwner=False): if sameOwner: d = self.getDetails() ad = ann.getDetails() - if (self._conn.isAdmin() - and self._conn.getUserId() != d.getOwner().id): + if (self._conn.isAdmin() and + self._conn.getUserId() != d.getOwner().id): # Keep the annotation owner the same as the linked of object's - if (ad.getOwner() - and d.getOwner().omeName == ad.getOwner().omeName - and d.getGroup().name == ad.getGroup().name): + if (ad.getOwner() and + d.getOwner().omeName == ad.getOwner().omeName and + d.getGroup().name == ad.getGroup().name): newConn = ann._conn else: # p = omero.sys.Principal() @@ -1174,9 +1187,9 @@ def __getattr__(self, attr): # handle lookup of 'get' methods, using '_attrs' dict to define how we # wrap returned objects. - if (attr != 'get' - and attr.startswith('get') - and hasattr(self, '_attrs')): + if (attr != 'get' and + attr.startswith('get') and + hasattr(self, '_attrs')): tattr = attr[3].lower() + attr[4:] # 'getName' -> 'name' # find attr with 'name' attrs = filter(lambda x: tattr in x, self._attrs) @@ -1229,8 +1242,8 @@ def wrap(): # If this is a _unit, then we ignore val # since it's not an rtype to unwrap. if not hasattr(rv, "_unit"): - return (isinstance(rv.val, StringType) - and rv.val.decode('utf8') or rv.val) + return (isinstance(rv.val, StringType) and + rv.val.decode('utf8') or rv.val) return rv raise AttributeError( "'%s' object has no attribute '%s'" @@ -2055,8 +2068,8 @@ def connect(self, sUuid=None): return self.connect() else: # pragma: no cover logger.debug( - "BlitzGateway.connect().createSession(): " - + traceback.format_exc()) + "BlitzGateway.connect().createSession(): " + + traceback.format_exc()) logger.info( "first create session threw SecurityViolation, " "retry (but only once)") @@ -2078,8 +2091,8 @@ def connect(self, sUuid=None): except: logger.info("Failed to create session.") logger.debug( - "BlitzGateway.connect().createSession(): " - + traceback.format_exc()) + "BlitzGateway.connect().createSession(): " + + traceback.format_exc()) # time.sleep(10) self._createSession() @@ -2235,9 +2248,9 @@ def canWrite(self, obj): :return: Boolean """ - return (self.isAdmin() - or (self.getUserId() == obj.getDetails().getOwner().getId() - and obj.getDetails().getPermissions().isUserWrite())) + return (self.isAdmin() or + (self.getUserId() == obj.getDetails().getOwner().getId() and + obj.getDetails().getPermissions().isUserWrite())) def canOwnerWrite(self, obj): """ @@ -2285,8 +2298,8 @@ def setGroupForSession(self, groupid): """ if self.getEventContext().groupId == groupid: return None - if (groupid not in self._ctx.memberOfGroups - and 0 not in self._ctx.memberOfGroups): + if (groupid not in self._ctx.memberOfGroups and + 0 not in self._ctx.memberOfGroups): return False self._lastGroupId = self._ctx.groupId self._ctx = None @@ -2584,6 +2597,7 @@ def listOrphans(self, obj_type, eid=None, params=None, loadPixels=False): wrapper = KNOWN_WRAPPERS.get(obj_type.lower(), None) query = wrapper()._getQueryString() + query = wrapper()._getQueryString()[0] if loadPixels and obj_type == 'Image': # left outer join so we don't exclude @@ -2715,8 +2729,8 @@ def createGroup(self, name, owner_Ids=None, member_Ids=None, perms=None, group = omero.model.ExperimenterGroupI() group.name = rstring(str(name)) group.description = ( - (description != "" and description is not None) - and rstring(str(description)) or None) + (description != "" and description is not None) and + rstring(str(description)) or None) if perms is not None: group.details.permissions = omero.model.PermissionsI(perms) group.ldap = rbool(ldap) @@ -3035,8 +3049,11 @@ def getObjects(self, obj_type, ids=None, params=None, attributes=None, """ query, params, wrapper = self.buildQuery( obj_type, ids, params, attributes) - result = self.getQueryService().findAllByQuery( - query, params, self.SERVICE_OPTS) + qs = self.getQueryService() + # we do projection in case query has extra selects (E.g. child_count) + result = qs.projection(query, params, self.SERVICE_OPTS) + # unwrap projected objects + result = [unwrap(r[0]) for r in result] if respect_order and ids is not None: idMap = {} for r in result: @@ -3076,28 +3093,54 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None): "getObjects uses a string to define obj_type, E.g. " "'Image' not %r" % obj_type) - if params is None: - params = omero.sys.Parameters() - if params.map is None: - params.map = {} + owner = None + order_by = None + opts = None + inputParams = None + + if isinstance(params, dict): + opts = params + elif isinstance(params, omero.sys.Parameters): + inputParams = params # get the base query from the instantiated object itself. E.g "select # obj Project as obj" - query = wrapper()._getQueryString() + query, clauses, params = wrapper()._getQueryString(opts) + + # Handle dict of parameters -> convert to ParametersI() + if opts is not None: + # Parse opts dict to build params + if 'page' in opts and 'limit' in opts: + limit = opts['limit'] + params.page((opts['page']-1) * limit, limit) + if 'owner' in opts: + owner = rlong(opts['owner']) + if 'order_by' in opts: + order_by = opts['order_by'] + # Handle existing Parameters - need to retrieve owner filter + elif inputParams is not None: + if inputParams.theFilter: + if inputParams.theFilter.ownerId is not None: + owner = inputParams.theFilter.ownerId + # pagination + offset = inputParams.theFilter.offset + limit = inputParams.theFilter.limit + if limit is not None and offset is not None: + params.page(offset.val, limit.val) + # Other params args will be ignored unless we handle here - clauses = [] # getting object by ids if ids is not None: clauses.append("obj.id in (:ids)") params.map["ids"] = rlist([rlong(a) for a in ids]) # support filtering by owner (not for some object types) - if (params.theFilter - and params.theFilter.ownerId - and obj_type.lower() + if (owner is not None and + owner.val != -1 and + obj_type.lower() not in ["experimentergroup", "experimenter"]): clauses.append("owner.id = (:eid)") - params.map["eid"] = params.theFilter.ownerId + params.map["eid"] = owner # finding by attributes if attributes is not None: @@ -3107,6 +3150,10 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None): if clauses: query += " where " + (" and ".join(clauses)) + # Order by... + if order_by is not None: + query += " order by lower(obj.%s), obj.id" % order_by + return (query, params, wrapper) def listFileAnnotations(self, eid=None, toInclude=[], toExclude=[]): @@ -4155,9 +4202,9 @@ def parse_time(c, i): d_from = parse_time(created, 0) d_to = parse_time(created, 1) - d_type = (useAcquisitionDate - and "acquisitionDate" - or "details.creationEvent.time") + d_type = (useAcquisitionDate and + "acquisitionDate" or + "details.creationEvent.time") try: rv = [] @@ -4507,19 +4554,19 @@ def __eq__(self, a): :return: True if annotations are the same - see above :rtype: Boolean """ - return (type(a) == type(self) and self._obj.id == a._obj.id - and self.getValue() == a.getValue() - and self.getNs() == a.getNs()) + return (type(a) == type(self) and self._obj.id == a._obj.id and + self.getValue() == a.getValue() and + self.getNs() == a.getNs()) - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("Annotation") """ - return ("select obj from Annotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent") + query = ("select obj from Annotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent") + return query, [], omero.sys.ParametersI() @classmethod def _register(klass, regklass): @@ -4671,15 +4718,15 @@ def __init__(self, *args, **kwargs): _attrs = ('file|OriginalFileWrapper',) - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("FileAnnotation") """ - return ("select obj from FileAnnotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent join fetch obj.file") + query = ("select obj from FileAnnotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent join fetch obj.file") + return query, [], omero.sys.ParametersI() def getValue(self): """ Not implemented """ @@ -4718,11 +4765,11 @@ def isOriginalMetadata(self): """ try: - if (self._obj.ns is not None - and self._obj.ns.val - == omero.constants.namespaces.NSCOMPANIONFILE - and self.getFile().getName() - == omero.constants.annotation.file.ORIGINALMETADATA): + if (self._obj.ns is not None and + self._obj.ns.val == + omero.constants.namespaces.NSCOMPANIONFILE and + self.getFile().getName() == + omero.constants.annotation.file.ORIGINALMETADATA): return True except: logger.info(traceback.format_exc()) @@ -4813,15 +4860,15 @@ class TimestampAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = TimestampAnnotationI - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("TimestampAnnotation") """ - return ("select obj from TimestampAnnotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent") + query = ("select obj from TimestampAnnotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent") + return query, [], omero.sys.ParametersI() def getValue(self): """ @@ -4862,15 +4909,15 @@ class BooleanAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = BooleanAnnotationI - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("BooleanAnnotation") """ - return ("select obj from BooleanAnnotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent") + query = ("select obj from BooleanAnnotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent") + return query, [], omero.sys.ParametersI() def getValue(self): """ @@ -4948,15 +4995,15 @@ def listParents(self, withlinks=True): self._conn, l.parent, l)) return rv - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("TagAnnotation") """ - return ("select obj from TagAnnotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent") + query = ("select obj from TagAnnotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent") + return query, [], omero.sys.ParametersI() def getValue(self): """ @@ -4990,15 +5037,15 @@ class CommentAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = CommentAnnotationI - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("CommentAnnotation") """ - return ("select obj from CommentAnnotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent") + query = ("select obj from CommentAnnotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent") + return query, [], omero.sys.ParametersI() def getValue(self): """ @@ -5030,15 +5077,15 @@ class LongAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = LongAnnotationI - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("LongAnnotation") """ - return ("select obj from LongAnnotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent") + query = ("select obj from LongAnnotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent") + return query, [], omero.sys.ParametersI() def getValue(self): """ @@ -5071,15 +5118,15 @@ class DoubleAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = DoubleAnnotationI - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("DoubleAnnotation") """ - return ("select obj from DoubleAnnotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent") + query = ("select obj from DoubleAnnotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent") + return query, [], omero.sys.ParametersI() def getValue(self): """ @@ -5113,15 +5160,15 @@ class TermAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = TermAnnotationI - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("TermAnnotation") """ - return ("select obj from TermAnnotation obj " - "join fetch obj.details.owner as owner " - "join fetch obj.details.group " - "join fetch obj.details.creationEvent") + query = ("select obj from TermAnnotation obj " + "join fetch obj.details.owner as owner " + "join fetch obj.details.creationEvent") + return query, [], omero.sys.ParametersI() def getValue(self): """ @@ -5232,13 +5279,14 @@ def simpleMarshal(self, xtra=None, parents=False): 'isAdmin': isAdmin, }) return rv - def _getQueryString(self): + def _getQueryString(self, opts=None): """ Returns string for building queries, loading Experimenters only. """ - return ("select distinct obj from Experimenter as obj " - "left outer join fetch obj.groupExperimenterMap as map " - "left outer join fetch map.parent g") + query = ("select distinct obj from Experimenter as obj " + "left outer join fetch obj.groupExperimenterMap as map " + "left outer join fetch map.parent g") + return query, [], omero.sys.ParametersI() def getRawPreferences(self): """ @@ -5460,7 +5508,7 @@ def __bstrap__(self): self.CHILD_WRAPPER_CLASS = 'ExperimenterWrapper' self.PARENT_WRAPPER_CLASS = None - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Returns string for building queries, loading Experimenters for each group. @@ -5468,7 +5516,7 @@ def _getQueryString(self): query = ("select distinct obj from ExperimenterGroup as obj " "left outer join fetch obj.groupExperimenterMap as map " "left outer join fetch map.child e") - return query + return query, [], omero.sys.ParametersI() def groupSummary(self, exclude_self=False): """ @@ -5485,8 +5533,8 @@ def groupSummary(self, exclude_self=False): userId = self._conn.getUserId() colleagues = [] leaders = [] - if (not self.isPrivate() or self._conn.isLeader(self.id) - or self._conn.isAdmin()): + if (not self.isPrivate() or self._conn.isLeader(self.id) or + self._conn.isAdmin()): for d in self.copyGroupExperimenterMap(): if d is None or d.child.id.val == userId: continue @@ -5553,6 +5601,18 @@ def __bstrap__(self): self.CHILD_WRAPPER_CLASS = 'ImageWrapper' self.PARENT_WRAPPER_CLASS = 'ProjectWrapper' + def _getQueryString(self, opts): + """ + Extend base query to handle filtering by Projects + """ + query, clauses, params = super( + _DatasetWrapper, self)._getQueryString(opts) + if opts is not None and 'project' in opts: + query += ' join obj.projectLinks plink' + clauses.append('plink.parent.id = :pid') + params.add('pid', rlong(opts['project'])) + return (query, clauses, params) + def __loadedHotSwap__(self): """ In addition to loading the Dataset, this method also loads the Images @@ -5761,8 +5821,8 @@ def getColumnLabels(self): Returns a list of labels for the columns on this plate. E.g. [1, 2, 3...] or ['A', 'B', 'C'...] etc """ - if (self.columnNamingConvention - and self.columnNamingConvention.lower() == 'letter'): + if (self.columnNamingConvention and + self.columnNamingConvention.lower() == 'letter'): # this should simply be precalculated! return [_letterGridLabel(x) for x in range(self.getGridSize()['columns'])] @@ -5774,8 +5834,8 @@ def getRowLabels(self): Returns a list of labels for the rows on this plate. E.g. [1, 2, 3...] or ['A', 'B', 'C'...] etc """ - if (self.rowNamingConvention - and self.rowNamingConvention.lower() == 'number'): + if (self.rowNamingConvention and + self.rowNamingConvention.lower() == 'number'): return range(1, self.getGridSize()['rows']+1) else: # this should simply be precalculated! @@ -5805,18 +5865,17 @@ def exportOmeTiff(self): """ return None - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Returns a query string for constructing custom queries, loading the screen for each plate. """ query = ("select obj from Plate as obj " "join fetch obj.details.owner as owner " - "join fetch obj.details.group " "join fetch obj.details.creationEvent " "left outer join fetch obj.screenLinks spl " "left outer join fetch spl.parent sc") - return query + return query, [], omero.sys.ParametersI() PlateWrapper = _PlateWrapper @@ -6574,15 +6633,16 @@ class _FilesetWrapper (BlitzObjectWrapper): def __bstrap__(self): self.OMERO_CLASS = 'Fileset' - def _getQueryString(self): + def _getQueryString(self, child_count=False): """ Used for building queries in generic methods such as getObjects("Fileset") """ - return "select obj from Fileset obj "\ + query = "select obj from Fileset obj "\ "left outer join fetch obj.images as image "\ "left outer join fetch obj.usedFiles as usedFile " \ "join fetch usedFile.originalFile" + return query, [], omero.sys.ParametersI() def copyImages(self): """ Returns a list of :class:`ImageWrapper` linked to this Fileset """ @@ -7167,8 +7227,9 @@ def simpleMarshal(self, xtra=None, parents=False): 'height': self.getSizeY(), } if rv['size']['height'] and rv['size']['width']: - rv['tiled'] = ((rv['size']['height'] * rv['size']['width']) - > (maxplanesize[0] * maxplanesize[1])) + rv['tiled'] = ((rv['size']['height'] * + rv['size']['width']) > + (maxplanesize[0] * maxplanesize[1])) else: rv['tiled'] = False @@ -7724,9 +7785,9 @@ def setActiveChannels(self, channels, windows=None, colors=None, if (reverseMaps is not None and reverseMaps[idx] is not None): self.setReverseIntensity(c, reverseMaps[idx]) - if (windows is not None - and windows[idx][0] is not None - and windows[idx][1] is not None): + if (windows is not None and + windows[idx][0] is not None and + windows[idx][1] is not None): self._re.setChannelWindow( c, float(windows[idx][0]), float(windows[idx][1]), self._conn.SERVICE_OPTS) @@ -7865,11 +7926,11 @@ def getPixelLine(self, z, t, pos, axis, channels=None, range=None): (bw, rp.isFloat(), rp.isSigned()), None) if key is None: logger.error( - "Unknown data type: " - + str((bw, rp.isFloat(), rp.isSigned()))) - plot = array.array(key, (axis == 'h' - and rp.getRow(pos, z, c, t) - or rp.getCol(pos, z, c, t))) + "Unknown data type: " + + str((bw, rp.isFloat(), rp.isSigned()))) + plot = array.array(key, (axis == 'h' and + rp.getRow(pos, z, c, t) or + rp.getCol(pos, z, c, t))) plot.byteswap() # TODO: Assuming ours is a little endian # system now move data into the windowMin..windowMax range offset = -chw[c][0] @@ -8254,8 +8315,8 @@ def _wordwrap(self, width, text, font): while len(tokens) > 1: p1 = 0 p2 = 1 - while (p2 <= len(tokens) - and font.getsize(' '.join(tokens[p1:p2]))[0] < width): + while (p2 <= len(tokens) and + font.getsize(' '.join(tokens[p1:p2]))[0] < width): p2 += 1 rv.append(' '.join(tokens[p1:p2-1])) tokens = tokens[p2-1:] From 45d6aff289863461e97622c81e8e739048cba038 Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 17 Nov 2016 15:57:42 +0000 Subject: [PATCH 02/18] test_get_objects.py changes from PR #4945 --- .../gatewaytest/test_get_objects.py | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) 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 f15049756a4..786c2390fbb 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py @@ -321,6 +321,35 @@ def testListProjects(self, gatewaywrapper): for p in pros: assert p.getId() in projectIds + def testPagination(self, gatewaywrapper): + gatewaywrapper.loginAsAuthor() + params = omero.sys.ParametersI() + # Only 3 images available + limit = 2 + params.page(0, limit) + pros = list(gatewaywrapper.gateway.getObjects( + "Project", None, params)) + assert len(pros) == limit + + def testGetDatasetsByProject(self, gatewaywrapper): + gatewaywrapper.loginAsAuthor() + allDs = list(gatewaywrapper.gateway.getObjects("Dataset")) + + # Get Datasets by project.listChildren()... + project = gatewaywrapper.getTestProject() + dsIds = [d.id for d in project.listChildren()] + + # Get Datasets, filtering by project + p = {'project': project.id} + datasets = list(gatewaywrapper.gateway.getObjects("Dataset", params=p)) + + # Check that not all Datasets are in Project (or test is invalid) + assert len(allDs) > len(dsIds) + # Should get same result both methods + assert len(datasets) == len(dsIds) + for d in datasets: + assert d.id in dsIds + def testListExperimentersAndGroups(self, gatewaywrapper): gatewaywrapper.loginAsAuthor() # experimenters @@ -558,30 +587,25 @@ def testListOrphans(self, gatewaywrapper): gatewaywrapper.loginAsUser() eid = gatewaywrapper.gateway.getUserId() - imageList = list() + # Create 5 images for i in range(0, 5): - imageList.append(gatewaywrapper.createTestImage( - imageName=(str(uuid.uuid1()))).getName()) - - findImages = list(gatewaywrapper.gateway.listOrphans("Image")) - assert len(findImages) == 5, "Did not find orphaned images" - - for p in findImages: - assert not p._obj.pixelsLoaded - assert p.getName() in imageList, \ - "All images should have queried name" + gatewaywrapper.createTestImage(imageName=str(uuid.uuid1())) + # Pagination, loading pixels params = omero.sys.ParametersI() params.page(1, 3) findImagesInPage = list(gatewaywrapper.gateway.listOrphans( "Image", eid=eid, params=params, loadPixels=True)) assert len(findImagesInPage) == 3, \ "Did not find orphaned images in page" - for p in findImagesInPage: assert p._obj.pixelsLoaded + # All orphans, no pixels + findImages = list(gatewaywrapper.gateway.listOrphans("Image")) + orphanedCount = len(findImages) for p in findImages: + assert not p._obj.pixelsLoaded client = p._conn handle = client.deleteObjects( 'Image', [p.getId()], deleteAnns=True) @@ -590,6 +614,11 @@ def testListOrphans(self, gatewaywrapper): finally: handle.close() + # Check this AFTER delete + # If test fails with previously undeleted images, + # it should pass when re-run since images are deleted above + assert orphanedCount == 5, "Did not find orphaned images" + def testOrderById(self, gatewaywrapper): gatewaywrapper.loginAsUser() imageIds = list() From 0f945ff38ec7641279843cd0c684b2cf39f99d3e Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 17 Nov 2016 22:27:36 +0000 Subject: [PATCH 03/18] Add test for getObjects('Project', {'owner': 0}) --- .../gatewaytest/test_get_objects.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) 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 786c2390fbb..e3ce0115465 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py @@ -303,18 +303,23 @@ def testListProjects(self, gatewaywrapper): # params limit query by owner params = omero.sys.Parameters() params.theFilter = omero.sys.Filter() + conn = gatewaywrapper.gateway # should be no Projects owned by root (in the current group) params.theFilter.ownerId = omero.rtypes.rlong(0) # owned by 'root' - pros = gatewaywrapper.gateway.getObjects("Project", None, params) + pros = conn.getObjects("Project", None, params) + assert len(list(pros)) == 0, "Should be no Projects owned by root" + + # Also filter by owner using params dict + pros = conn.getObjects("Project", None, {'owner': 0}) assert len(list(pros)) == 0, "Should be no Projects owned by root" # filter by current user should get same as above. # owned by 'author' params.theFilter.ownerId = omero.rtypes.rlong( - gatewaywrapper.gateway.getEventContext().userId) - pros = list(gatewaywrapper.gateway.getObjects( + conn.getEventContext().userId) + pros = list(conn.getObjects( "Project", None, params)) - projects = list(gatewaywrapper.gateway.listProjects()) + projects = list(conn.listProjects()) # check unordered lists are the same length & ids assert len(pros) == len(projects) projectIds = [p.getId() for p in projects] @@ -331,6 +336,11 @@ def testPagination(self, gatewaywrapper): "Project", None, params)) assert len(pros) == limit + # Also using params dict + pros = list(gatewaywrapper.gateway.getObjects( + "Project", None, {'page': 0, 'limit': 2})) + assert len(pros) == limit + def testGetDatasetsByProject(self, gatewaywrapper): gatewaywrapper.loginAsAuthor() allDs = list(gatewaywrapper.gateway.getObjects("Dataset")) From 03909a09f06156ddb0f30e6fa273432d401a72d0 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 5 Dec 2016 15:39:34 +0000 Subject: [PATCH 04/18] Add test of conn.listOrphans(Dataset) --- .../OmeroPy/test/integration/gatewaytest/test_get_objects.py | 5 +++++ 1 file changed, 5 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 e3ce0115465..b9146065daa 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py @@ -629,6 +629,11 @@ def testListOrphans(self, gatewaywrapper): # it should pass when re-run since images are deleted above assert orphanedCount == 5, "Did not find orphaned images" + # Simply check this doesn't fail See https://github.com/ + # openmicroscopy/openmicroscopy/pull/4950#issuecomment-264142956 + datasets = list(gatewaywrapper.gateway.listOrphans("Dataset")) + + def testOrderById(self, gatewaywrapper): gatewaywrapper.loginAsUser() imageIds = list() From 1353f00e96f4f3903e2db4da2e2dec814cc6fca2 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 5 Dec 2016 14:49:33 +0000 Subject: [PATCH 05/18] Aligning parameters to _getQueryString(opts=None) --- .../OmeroPy/src/omero/gateway/__init__.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index dda1ba5f3d1..28365fb93a0 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -4558,7 +4558,7 @@ def __eq__(self, a): self.getValue() == a.getValue() and self.getNs() == a.getNs()) - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("Annotation") @@ -4718,7 +4718,7 @@ def __init__(self, *args, **kwargs): _attrs = ('file|OriginalFileWrapper',) - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("FileAnnotation") @@ -4860,7 +4860,7 @@ class TimestampAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = TimestampAnnotationI - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("TimestampAnnotation") @@ -4909,7 +4909,7 @@ class BooleanAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = BooleanAnnotationI - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("BooleanAnnotation") @@ -4995,7 +4995,7 @@ def listParents(self, withlinks=True): self._conn, l.parent, l)) return rv - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("TagAnnotation") @@ -5037,7 +5037,7 @@ class CommentAnnotationWrapper (AnnotationWrapper): OMERO_TYPE = CommentAnnotationI - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("CommentAnnotation") @@ -5077,7 +5077,7 @@ class LongAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = LongAnnotationI - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("LongAnnotation") @@ -5118,7 +5118,7 @@ class DoubleAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = DoubleAnnotationI - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("DoubleAnnotation") @@ -5160,7 +5160,7 @@ class TermAnnotationWrapper (AnnotationWrapper): """ OMERO_TYPE = TermAnnotationI - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("TermAnnotation") @@ -5508,7 +5508,7 @@ def __bstrap__(self): self.CHILD_WRAPPER_CLASS = 'ExperimenterWrapper' self.PARENT_WRAPPER_CLASS = None - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Returns string for building queries, loading Experimenters for each group. @@ -5601,7 +5601,7 @@ def __bstrap__(self): self.CHILD_WRAPPER_CLASS = 'ImageWrapper' self.PARENT_WRAPPER_CLASS = 'ProjectWrapper' - def _getQueryString(self, opts): + def _getQueryString(self, opts=None): """ Extend base query to handle filtering by Projects """ @@ -5865,7 +5865,7 @@ def exportOmeTiff(self): """ return None - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Returns a query string for constructing custom queries, loading the screen for each plate. @@ -6633,7 +6633,7 @@ class _FilesetWrapper (BlitzObjectWrapper): def __bstrap__(self): self.OMERO_CLASS = 'Fileset' - def _getQueryString(self, child_count=False): + def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("Fileset") From 727cbbec0c3e83b24ca6b48964c7fa7295564883 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 5 Dec 2016 21:31:25 +0000 Subject: [PATCH 06/18] Add docs to _getQueryString() --- .../OmeroPy/src/omero/gateway/__init__.py | 87 ++++++++++++++++--- 1 file changed, 76 insertions(+), 11 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 28365fb93a0..b66e456fb42 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -272,7 +272,15 @@ def _unwrapunits(self, obj, units=None): def _getQueryString(self, opts=None): """ Used for building queries in generic methods - such as getObjects("Project") + such as getObjects("Project"). + Returns a tuple of (query, clauses, params). + Overridden by sub-classes to specify loading of different + portions of the graph. + Different sub-classes may allow some control over what's loaded + and filtering of the query using various opts arguments. + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ extra_select = "" child_count = False @@ -4562,6 +4570,10 @@ def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as getObjects("Annotation") + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from Annotation obj " "join fetch obj.details.owner as owner " @@ -4721,7 +4733,11 @@ def __init__(self, *args, **kwargs): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("FileAnnotation") + getObjects("FileAnnotation"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from FileAnnotation obj " "join fetch obj.details.owner as owner " @@ -4863,7 +4879,11 @@ class TimestampAnnotationWrapper (AnnotationWrapper): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("TimestampAnnotation") + getObjects("TimestampAnnotation"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from TimestampAnnotation obj " "join fetch obj.details.owner as owner " @@ -4912,7 +4932,11 @@ class BooleanAnnotationWrapper (AnnotationWrapper): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("BooleanAnnotation") + getObjects("BooleanAnnotation"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from BooleanAnnotation obj " "join fetch obj.details.owner as owner " @@ -4998,7 +5022,11 @@ def listParents(self, withlinks=True): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("TagAnnotation") + getObjects("TagAnnotation"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from TagAnnotation obj " "join fetch obj.details.owner as owner " @@ -5040,7 +5068,11 @@ class CommentAnnotationWrapper (AnnotationWrapper): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("CommentAnnotation") + getObjects("CommentAnnotation"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from CommentAnnotation obj " "join fetch obj.details.owner as owner " @@ -5080,7 +5112,11 @@ class LongAnnotationWrapper (AnnotationWrapper): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("LongAnnotation") + getObjects("LongAnnotation"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from LongAnnotation obj " "join fetch obj.details.owner as owner " @@ -5121,7 +5157,11 @@ class DoubleAnnotationWrapper (AnnotationWrapper): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("DoubleAnnotation") + getObjects("DoubleAnnotation"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from DoubleAnnotation obj " "join fetch obj.details.owner as owner " @@ -5163,7 +5203,11 @@ class TermAnnotationWrapper (AnnotationWrapper): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("TermAnnotation") + getObjects("TermAnnotation"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from TermAnnotation obj " "join fetch obj.details.owner as owner " @@ -5282,6 +5326,11 @@ def simpleMarshal(self, xtra=None, parents=False): def _getQueryString(self, opts=None): """ Returns string for building queries, loading Experimenters only. + + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select distinct obj from Experimenter as obj " "left outer join fetch obj.groupExperimenterMap as map " @@ -5512,6 +5561,10 @@ def _getQueryString(self, opts=None): """ Returns string for building queries, loading Experimenters for each group. + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select distinct obj from ExperimenterGroup as obj " "left outer join fetch obj.groupExperimenterMap as map " @@ -5603,7 +5656,11 @@ def __bstrap__(self): def _getQueryString(self, opts=None): """ - Extend base query to handle filtering by Projects + Extend base query to handle filtering of Datasets by Projects. + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query, clauses, params = super( _DatasetWrapper, self)._getQueryString(opts) @@ -5869,6 +5926,10 @@ def _getQueryString(self, opts=None): """ Returns a query string for constructing custom queries, loading the screen for each plate. + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = ("select obj from Plate as obj " "join fetch obj.details.owner as owner " @@ -6636,7 +6697,11 @@ def __bstrap__(self): def _getQueryString(self, opts=None): """ Used for building queries in generic methods such as - getObjects("Fileset") + getObjects("Fileset"). + Returns a tuple of (query, clauses, params). + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI """ query = "select obj from Fileset obj "\ "left outer join fetch obj.images as image "\ From ab1ff19e0cdf4478fa10f1dde38c6c74b4aa7c5b Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 5 Dec 2016 22:36:59 +0000 Subject: [PATCH 07/18] flake8 fixes --- .../OmeroPy/test/integration/gatewaytest/test_get_objects.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 b9146065daa..3b06f05c2bc 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py @@ -631,8 +631,7 @@ def testListOrphans(self, gatewaywrapper): # Simply check this doesn't fail See https://github.com/ # openmicroscopy/openmicroscopy/pull/4950#issuecomment-264142956 - datasets = list(gatewaywrapper.gateway.listOrphans("Dataset")) - + list(gatewaywrapper.gateway.listOrphans("Dataset")) def testOrderById(self, gatewaywrapper): gatewaywrapper.loginAsUser() From 4ce3bb983b879dee774793ae5d93b8885a4ae3c1 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 6 Dec 2016 16:47:37 +0000 Subject: [PATCH 08/18] Add 'opts' param to conn.buildQuery() and conn.getObjects() --- .../OmeroPy/src/omero/gateway/__init__.py | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 6d0f62e795a..e3210bb23a6 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -3035,7 +3035,7 @@ def getObject(self, obj_type, oid=None, params=None, attributes=None): return wrapper(self, result) def getObjects(self, obj_type, ids=None, params=None, attributes=None, - respect_order=False): + respect_order=False, opts=None): """ Retrieve Objects by type E.g. "Image" Returns generator of appropriate :class:`BlitzObjectWrapper` type. @@ -3049,15 +3049,17 @@ def getObjects(self, obj_type, ids=None, params=None, attributes=None, :type ids: List of Long :param params: omero.sys.Parameters, can be used for pagination, filtering etc. - :param attributes: Map of key-value pairs to filter results by. + :param attributes: Dict of key-value pairs to filter results by. Key must be attribute of obj_type. E.g. 'name', 'ns' :param respect_order: Returned items will be ordered according to the order of ids + :param opts: Dict of additional options for filtering or + defining extra data to load. E.g. childCount :return: Generator of :class:`BlitzObjectWrapper` subclasses """ query, params, wrapper = self.buildQuery( - obj_type, ids, params, attributes) + obj_type, ids, params, attributes, opts) qs = self.getQueryService() # we do projection in case query has extra selects (E.g. child_count) result = qs.projection(query, params, self.SERVICE_OPTS) @@ -3072,7 +3074,8 @@ def getObjects(self, obj_type, ids=None, params=None, attributes=None, for r in result: yield wrapper(self, r) - def buildQuery(self, obj_type, ids=None, params=None, attributes=None): + def buildQuery(self, obj_type, ids=None, params=None, attributes=None, + opts=None): """ Prepares a query for iQuery. Also prepares params and determines appropriate wrapper for result Returns (query, params, wrapper) which @@ -3085,9 +3088,10 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None): :type ids: List of Long :param params: omero.sys.Parameters, can be used for pagination, filtering etc. - :param attributes: Map of key-value pairs to filter results by. + :param attributes: Dict of key-value pairs to filter results by. Key must be attribute of obj_type. E.g. 'name', 'ns' + :param opts: Dict of extra query options. :return: (query, params, wrapper) """ @@ -3104,58 +3108,58 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None): owner = None order_by = None - opts = None - inputParams = None - - if isinstance(params, dict): - opts = params - elif isinstance(params, omero.sys.Parameters): - inputParams = params + offset = None + limit = None # get the base query from the instantiated object itself. E.g "select # obj Project as obj" - query, clauses, params = wrapper()._getQueryString(opts) + query, clauses, baseParams = wrapper()._getQueryString(opts) # Handle dict of parameters -> convert to ParametersI() if opts is not None: # Parse opts dict to build params if 'page' in opts and 'limit' in opts: limit = opts['limit'] - params.page((opts['page']-1) * limit, limit) + offset = (opts['page']-1) * limit if 'owner' in opts: owner = rlong(opts['owner']) if 'order_by' in opts: order_by = opts['order_by'] - # Handle existing Parameters - need to retrieve owner filter - elif inputParams is not None: - if inputParams.theFilter: - if inputParams.theFilter.ownerId is not None: - owner = inputParams.theFilter.ownerId - # pagination - offset = inputParams.theFilter.offset - limit = inputParams.theFilter.limit - if limit is not None and offset is not None: - params.page(offset.val, limit.val) - # Other params args will be ignored unless we handle here + # Handle additional Parameters - need to retrieve owner filter + if params is not None and params.theFilter is not None: + if params.theFilter.ownerId is not None: + owner = params.theFilter.ownerId + # pagination + ofs = params.theFilter.offset + lmt = params.theFilter.limit + print ofs, lmt + if ofs is not None and lmt is not None: + offset = ofs.val + limit = lmt.val + # Other params args will be ignored unless we handle here + + + if limit is not None and offset is not None: + print "offset, limit", offset, limit + baseParams.page(offset, limit) # getting object by ids if ids is not None: clauses.append("obj.id in (:ids)") - params.map["ids"] = rlist([rlong(a) for a in ids]) + baseParams.map["ids"] = rlist([rlong(a) for a in ids]) # support filtering by owner (not for some object types) - if (params.theFilter and - params.theFilter.ownerId and + if (owner is not None and obj_type.lower() not in ["experimentergroup", "experimenter"]): clauses.append("owner.id = (:eid)") - params.map["eid"] = owner + baseParams.map["eid"] = owner # finding by attributes if attributes is not None: for k, v in attributes.items(): clauses.append('obj.%s=:%s' % (k, k)) - params.map[k] = omero_type(v) + baseParams.map[k] = omero_type(v) if clauses: query += " where " + (" and ".join(clauses)) @@ -3163,7 +3167,7 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None): if order_by is not None: query += " order by lower(obj.%s), obj.id" % order_by - return (query, params, wrapper) + return (query, baseParams, wrapper) def listFileAnnotations(self, eid=None, toInclude=[], toExclude=[]): """ From 412a0bfe7f8d2af5fa850b327d5b4e2a000cee24 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 6 Dec 2016 16:48:20 +0000 Subject: [PATCH 09/18] Update test_get_objects.py to use opts parameter --- .../test/integration/gatewaytest/test_get_objects.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 3b06f05c2bc..b719a280f1c 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py @@ -310,8 +310,8 @@ def testListProjects(self, gatewaywrapper): pros = conn.getObjects("Project", None, params) assert len(list(pros)) == 0, "Should be no Projects owned by root" - # Also filter by owner using params dict - pros = conn.getObjects("Project", None, {'owner': 0}) + # Also filter by owner using opts dict + pros = conn.getObjects("Project", None, opts={'owner': 0}) assert len(list(pros)) == 0, "Should be no Projects owned by root" # filter by current user should get same as above. # owned by 'author' @@ -336,9 +336,9 @@ def testPagination(self, gatewaywrapper): "Project", None, params)) assert len(pros) == limit - # Also using params dict + # Also using opts dict pros = list(gatewaywrapper.gateway.getObjects( - "Project", None, {'page': 0, 'limit': 2})) + "Project", None, opts={'page': 1, 'limit': 2})) assert len(pros) == limit def testGetDatasetsByProject(self, gatewaywrapper): @@ -351,7 +351,7 @@ def testGetDatasetsByProject(self, gatewaywrapper): # Get Datasets, filtering by project p = {'project': project.id} - datasets = list(gatewaywrapper.gateway.getObjects("Dataset", params=p)) + datasets = list(gatewaywrapper.gateway.getObjects("Dataset", opts=p)) # Check that not all Datasets are in Project (or test is invalid) assert len(allDs) > len(dsIds) From 48eb41c9138608b3464a99fdb2729c087b24336b Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 6 Dec 2016 23:24:34 +0000 Subject: [PATCH 10/18] flake8 fix --- components/tools/OmeroPy/src/omero/gateway/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index e3210bb23a6..7704b7f2e55 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -3138,7 +3138,6 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None, limit = lmt.val # Other params args will be ignored unless we handle here - if limit is not None and offset is not None: print "offset, limit", offset, limit baseParams.page(offset, limit) From 2cd70752282c2a60b22e0ce5258fbac85334adb7 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 7 Dec 2016 00:01:30 +0000 Subject: [PATCH 11/18] Improve 'opts' parameter documentation --- .../tools/OmeroPy/src/omero/gateway/__init__.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 7704b7f2e55..f26abeee07e 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -3048,14 +3048,17 @@ def getObjects(self, obj_type, ids=None, params=None, attributes=None, :param ids: object IDs :type ids: List of Long :param params: omero.sys.Parameters, can be used for pagination, - filtering etc. + & filtering by owner. Takes precedence over opts. :param attributes: Dict of key-value pairs to filter results by. Key must be attribute of obj_type. E.g. 'name', 'ns' :param respect_order: Returned items will be ordered according to the order of ids :param opts: Dict of additional options for filtering or - defining extra data to load. E.g. childCount + defining extra data to load. + offset, limit and owner for all objects. + Additional opts handled in wrapper._getQueryString() + E.g. 'childCount', or filter Dataset by 'project' :return: Generator of :class:`BlitzObjectWrapper` subclasses """ query, params, wrapper = self.buildQuery( @@ -3087,11 +3090,15 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None, :param ids: object IDs :type ids: List of Long :param params: omero.sys.Parameters, can be used for pagination, - filtering etc. + & filtering by owner. Takes precedence over opts. :param attributes: Dict of key-value pairs to filter results by. Key must be attribute of obj_type. E.g. 'name', 'ns' - :param opts: Dict of extra query options. + :param opts: Dict of additional options for filtering or + defining extra data to load. + offset, limit and owner for all objects. + Additional opts handled in wrapper._getQueryString() + E.g. 'childCount', or filter Dataset by 'project' :return: (query, params, wrapper) """ @@ -3132,14 +3139,12 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None, # pagination ofs = params.theFilter.offset lmt = params.theFilter.limit - print ofs, lmt if ofs is not None and lmt is not None: offset = ofs.val limit = lmt.val # Other params args will be ignored unless we handle here if limit is not None and offset is not None: - print "offset, limit", offset, limit baseParams.page(offset, limit) # getting object by ids From df0e0cb2f02c178c50fd4646274fa180f6aab261 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 7 Dec 2016 00:03:02 +0000 Subject: [PATCH 12/18] Use 'offset' for opts instead of 'page' --- components/tools/OmeroPy/src/omero/gateway/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index f26abeee07e..b8eab3e56ca 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -3125,9 +3125,9 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None, # Handle dict of parameters -> convert to ParametersI() if opts is not None: # Parse opts dict to build params - if 'page' in opts and 'limit' in opts: + if 'offset' in opts and 'limit' in opts: limit = opts['limit'] - offset = (opts['page']-1) * limit + offset = opts['offset'] if 'owner' in opts: owner = rlong(opts['owner']) if 'order_by' in opts: From 3a86763c4e0fb36015a528531e2d219458fefdd8 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 7 Dec 2016 00:03:35 +0000 Subject: [PATCH 13/18] Update test_get_objects.py to use opts['offset'] --- .../OmeroPy/test/integration/gatewaytest/test_get_objects.py | 2 +- 1 file changed, 1 insertion(+), 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 b719a280f1c..1c3a141fe77 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_get_objects.py @@ -338,7 +338,7 @@ def testPagination(self, gatewaywrapper): # Also using opts dict pros = list(gatewaywrapper.gateway.getObjects( - "Project", None, opts={'page': 1, 'limit': 2})) + "Project", None, opts={'offset': 0, 'limit': 2})) assert len(pros) == limit def testGetDatasetsByProject(self, gatewaywrapper): From 179e447e2db7c1267cf0dfb4de0308fbfc66f965 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 7 Dec 2016 00:23:38 +0000 Subject: [PATCH 14/18] flake8 fixes --- components/tools/OmeroPy/src/omero/gateway/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index b8eab3e56ca..9212051e9bd 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -3057,7 +3057,7 @@ def getObjects(self, obj_type, ids=None, params=None, attributes=None, :param opts: Dict of additional options for filtering or defining extra data to load. offset, limit and owner for all objects. - Additional opts handled in wrapper._getQueryString() + Additional opts handled by _getQueryString() E.g. 'childCount', or filter Dataset by 'project' :return: Generator of :class:`BlitzObjectWrapper` subclasses """ @@ -3097,7 +3097,7 @@ def buildQuery(self, obj_type, ids=None, params=None, attributes=None, :param opts: Dict of additional options for filtering or defining extra data to load. offset, limit and owner for all objects. - Additional opts handled in wrapper._getQueryString() + Additional opts handled by _getQueryString() E.g. 'childCount', or filter Dataset by 'project' :return: (query, params, wrapper) """ From a14c2d3881117465fb5a6468639b943c3d431fbe Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 7 Dec 2016 14:56:48 +0000 Subject: [PATCH 15/18] Unit tests for conn.buildQuery() --- .../test/unit/gatewaytest/test_build_query.py | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py diff --git a/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py b/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py new file mode 100644 index 00000000000..c3e641474f9 --- /dev/null +++ b/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# +# Copyright (C) 2016 University of Dundee & Open Microscopy Environment. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +"""Gateway tests - buildQuery() as used by conn.getObjects().""" + +from omero.gateway import _BlitzGateway, BlitzObjectWrapper, KNOWN_WRAPPERS +from omero.sys import Parameters, ParametersI, Filter +import pytest +from omero.rtypes import wrap + + +class TestBuildQuery(object): + + @classmethod + @pytest.fixture(autouse=True) + def setup_class(cls, tmpdir, monkeypatch): + ice_config = tmpdir / "ice.config" + ice_config.write("omero.host=localhost\nomero.port=4064") + monkeypatch.setenv("ICE_CONFIG", ice_config) + cls.g = _BlitzGateway() + + @pytest.mark.parametrize("dtype", KNOWN_WRAPPERS.keys()) + def test_no_clauses(self, dtype): + """Expect a query with no 'where' clauses.""" + result = self.g.buildQuery(dtype) + query, params, wrapper = result + assert isinstance(query, str) + assert isinstance(params, Parameters) + assert isinstance(wrapper(), BlitzObjectWrapper) + assert query.startswith("select ") + assert "where" not in query + + @pytest.mark.parametrize("dtype", KNOWN_WRAPPERS.keys()) + def test_filter_by_owner(self, dtype): + """Query should filter by owner.""" + p = ParametersI() + p.theFilter = Filter() + p.theFilter.ownerId = wrap(2) + # Test using 'params' argument + with_params = self.g.buildQuery(dtype, params=p) + # Test using 'opts' dictionary + with_opts = self.g.buildQuery(dtype, opts={'owner': 1}) + for result in [with_params, with_opts]: + query, params, wrapper = result + assert isinstance(query, str) + assert isinstance(params, Parameters) + assert isinstance(wrapper(), BlitzObjectWrapper) + if dtype not in ('experimenter', 'experimentergroup'): + assert "where owner" in query + else: + assert "where owner" not in query + + @pytest.mark.parametrize("dtype", KNOWN_WRAPPERS.keys()) + def test_pagination(self, dtype): + """Query should paginate.""" + offset = 1 + limit = 100 + p = ParametersI() + p.page(offset, limit) + # Test using 'params' argument + with_params = self.g.buildQuery(dtype, params=p) + # Test using 'opts' dictionary + opts = {'offset': offset, 'limit': limit} + with_opts = self.g.buildQuery(dtype, opts=opts) + for result in [with_params, with_opts]: + query, params, wrapper = result + assert isinstance(query, str) + assert isinstance(params, Parameters) + assert isinstance(wrapper(), BlitzObjectWrapper) + assert params.theFilter.offset.val == offset + assert params.theFilter.limit.val == limit From d8a547014abeea64d360115747434a03108f6bbb Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 7 Dec 2016 14:58:58 +0000 Subject: [PATCH 16/18] Add docstrings to test_build_query --- .../tools/OmeroPy/test/unit/gatewaytest/test_build_query.py | 2 ++ 1 file changed, 2 insertions(+) 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 c3e641474f9..c58459e3723 100644 --- a/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py +++ b/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py @@ -28,10 +28,12 @@ class TestBuildQuery(object): + """Test the conn.buildQuery() method for all Object Wrappers.""" @classmethod @pytest.fixture(autouse=True) def setup_class(cls, tmpdir, monkeypatch): + """Prepare BlitzGateway with ICE_CONFIG.""" ice_config = tmpdir / "ice.config" ice_config.write("omero.host=localhost\nomero.port=4064") monkeypatch.setenv("ICE_CONFIG", ice_config) From e65be91db3650a3424be467e16b106692e815cc8 Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 8 Dec 2016 12:08:54 +0000 Subject: [PATCH 17/18] More docs for 'opts' parameters --- .../OmeroPy/src/omero/gateway/__init__.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 9212051e9bd..c1d750ba5fb 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -279,6 +279,11 @@ def _getQueryString(self, opts=None): portions of the graph. Different sub-classes may allow some control over what's loaded and filtering of the query using various opts arguments. + Opts: + 'child_count': boolean If true, this will produce a 'projection' + query that also selects child_count for + objects that have a LINK_CLASS + See different sub-classes for additional opts. :param opts: Dictionary of optional parameters. :return: Tuple of string, list, ParametersI @@ -4582,6 +4587,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from Annotation obj " @@ -4746,6 +4752,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from FileAnnotation obj " @@ -4892,6 +4899,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from TimestampAnnotation obj " @@ -4945,6 +4953,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from BooleanAnnotation obj " @@ -5035,6 +5044,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from TagAnnotation obj " @@ -5081,6 +5091,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from CommentAnnotation obj " @@ -5125,6 +5136,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from LongAnnotation obj " @@ -5170,6 +5182,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from DoubleAnnotation obj " @@ -5216,6 +5229,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from TermAnnotation obj " @@ -5339,6 +5353,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select distinct obj from Experimenter as obj " @@ -5573,6 +5588,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select distinct obj from ExperimenterGroup as obj " @@ -5667,6 +5683,7 @@ def _getQueryString(self, opts=None): """ Extend base query to handle filtering of Datasets by Projects. Returns a tuple of (query, clauses, params). + Supported opts: 'project': to filter by Project :param opts: Dictionary of optional parameters. :return: Tuple of string, list, ParametersI @@ -5938,6 +5955,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = ("select obj from Plate as obj " @@ -6710,6 +6728,7 @@ def _getQueryString(self, opts=None): Returns a tuple of (query, clauses, params). :param opts: Dictionary of optional parameters. + NB: No options supported for this class. :return: Tuple of string, list, ParametersI """ query = "select obj from Fileset obj "\ From ca94e44ee6fd82c68691637fe4aa2732db73dc7b Mon Sep 17 00:00:00 2001 From: William Moore Date: Fri, 9 Dec 2016 13:59:57 +0000 Subject: [PATCH 18/18] remove unnecessary setup_class() from unit tests --- .../test/unit/gatewaytest/test_build_query.py | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) 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 c58459e3723..29e7aee6bf5 100644 --- a/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py +++ b/components/tools/OmeroPy/test/unit/gatewaytest/test_build_query.py @@ -27,22 +27,19 @@ from omero.rtypes import wrap +@pytest.fixture(scope='function') +def gateway(): + """Create a BlitzGateway object.""" + return _BlitzGateway() + + class TestBuildQuery(object): """Test the conn.buildQuery() method for all Object Wrappers.""" - @classmethod - @pytest.fixture(autouse=True) - def setup_class(cls, tmpdir, monkeypatch): - """Prepare BlitzGateway with ICE_CONFIG.""" - ice_config = tmpdir / "ice.config" - ice_config.write("omero.host=localhost\nomero.port=4064") - monkeypatch.setenv("ICE_CONFIG", ice_config) - cls.g = _BlitzGateway() - @pytest.mark.parametrize("dtype", KNOWN_WRAPPERS.keys()) - def test_no_clauses(self, dtype): + def test_no_clauses(self, gateway, dtype): """Expect a query with no 'where' clauses.""" - result = self.g.buildQuery(dtype) + result = gateway.buildQuery(dtype) query, params, wrapper = result assert isinstance(query, str) assert isinstance(params, Parameters) @@ -51,15 +48,15 @@ def test_no_clauses(self, dtype): assert "where" not in query @pytest.mark.parametrize("dtype", KNOWN_WRAPPERS.keys()) - def test_filter_by_owner(self, dtype): + def test_filter_by_owner(self, gateway, dtype): """Query should filter by owner.""" p = ParametersI() p.theFilter = Filter() p.theFilter.ownerId = wrap(2) # Test using 'params' argument - with_params = self.g.buildQuery(dtype, params=p) + with_params = gateway.buildQuery(dtype, params=p) # Test using 'opts' dictionary - with_opts = self.g.buildQuery(dtype, opts={'owner': 1}) + with_opts = gateway.buildQuery(dtype, opts={'owner': 1}) for result in [with_params, with_opts]: query, params, wrapper = result assert isinstance(query, str) @@ -71,17 +68,17 @@ def test_filter_by_owner(self, dtype): assert "where owner" not in query @pytest.mark.parametrize("dtype", KNOWN_WRAPPERS.keys()) - def test_pagination(self, dtype): + def test_pagination(self, gateway, dtype): """Query should paginate.""" offset = 1 limit = 100 p = ParametersI() p.page(offset, limit) # Test using 'params' argument - with_params = self.g.buildQuery(dtype, params=p) + with_params = gateway.buildQuery(dtype, params=p) # Test using 'opts' dictionary opts = {'offset': offset, 'limit': limit} - with_opts = self.g.buildQuery(dtype, opts=opts) + with_opts = gateway.buildQuery(dtype, opts=opts) for result in [with_params, with_opts]: query, params, wrapper = result assert isinstance(query, str)