From 7c302c1511b1798c4821bcc18f1c16bb1c9a8794 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 31 Jan 2017 21:31:14 +0000 Subject: [PATCH 01/23] PlateView.add_data() uses api_query.get_wellsample_indices() --- .../tools/OmeroWeb/omeroweb/api/api_query.py | 21 ++++++++++++++ .../tools/OmeroWeb/omeroweb/api/views.py | 29 +++++++++++++------ 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/api_query.py b/components/tools/OmeroWeb/omeroweb/api/api_query.py index db15cc70147..d06dd29e7a8 100644 --- a/components/tools/OmeroWeb/omeroweb/api/api_query.py +++ b/components/tools/OmeroWeb/omeroweb/api/api_query.py @@ -24,6 +24,27 @@ from api_marshal import marshal_objects from copy import deepcopy +from omero.sys import ParametersI +from omero.rtypes import wrap + + +def get_wellsample_indices(conn, plate_id): + """ + Return min and max WellSample index for a Plate. + + @param conn: BlitzGateway + @param plate_id: Plate ID + @return A dict of parent_id: child_count + """ + ctx = deepcopy(conn.SERVICE_OPTS) + ctx.setOmeroGroup(-1) + params = ParametersI() + params.add('id', wrap(plate_id)) + query = "select minIndex(ws), maxIndex(ws) from Well well " \ + "join well.wellSamples ws where well.plate.id=:id" + result = conn.getQueryService().projection(query, params, ctx) + result = [r for r in unwrap(result)[0] if r is not None] + return result def query_objects(conn, object_type, diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index e2530f9555a..e24f79f54a0 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -28,7 +28,7 @@ import traceback import json -from api_query import query_objects +from api_query import query_objects, get_wellsample_indices from omero_marshal import get_encoder, get_decoder, OME_SCHEMA_URL from omero import ValidationException from omeroweb.connector import Server @@ -123,7 +123,7 @@ def dispatch(self, *args, **kwargs): """Wrap other methods to add decorators.""" return super(ApiView, self).dispatch(*args, **kwargs) - def add_data(self, marshalled, request, urls=None, **kwargs): + def add_data(self, marshalled, request, conn, urls=None, **kwargs): """ Post-process marshalled object to add any extra data. @@ -162,7 +162,7 @@ def get(self, request, object_id, conn=None, **kwargs): object_id)) encoder = get_encoder(obj._obj.__class__) marshalled = encoder.encode(obj._obj) - self.add_data(marshalled, request, self.urls, **kwargs) + self.add_data(marshalled, request, conn, self.urls, **kwargs) return marshalled def delete(self, request, object_id, conn=None, **kwargs): @@ -243,6 +243,15 @@ class PlateView(ObjectView): 'kwargs': {'plate_id': 'OBJECT_ID'}} } + def add_data(self, marshalled, request, conn, urls=None, **kwargs): + """Add min/max WellSampleIndex.""" + marshalled = super(PlateView, self).add_data(marshalled, request, conn, + urls=urls, **kwargs) + idx = get_wellsample_indices(conn, marshalled['@id']) + + marshalled['omero:wellsampleIndex'] = idx + return marshalled + class WellView(ObjectView): """Handle access to an individual Well to GET or DELETE it.""" @@ -256,9 +265,9 @@ def get_opts(self, request): opts['load_pixels'] = True return opts - def add_data(self, marshalled, request, urls=None, **kwargs): + def add_data(self, marshalled, request, conn, urls=None, **kwargs): """Add 'url:image' to any 'Image' in 'WellSamples'.""" - marshalled = super(WellView, self).add_data(marshalled, request, + marshalled = super(WellView, self).add_data(marshalled, request, conn, urls=urls, **kwargs) image_urls = { 'url:image': {'name': 'api_image', @@ -268,7 +277,8 @@ def add_data(self, marshalled, request, urls=None, **kwargs): # For each WellSample, add image urls to Image for ws in marshalled['WellSamples']: if 'Image' in ws: - self.add_data(ws['Image'], request, image_urls, **kwargs) + self.add_data(ws['Image'], request, conn, + image_urls, **kwargs) return marshalled @@ -304,7 +314,7 @@ def get(self, request, conn=None, **kwargs): marshalled = query_objects(conn, self.OMERO_TYPE, group, opts, normalize) for m in marshalled['data']: - self.add_data(m, request, self.urls, **kwargs) + self.add_data(m, request, conn, self.urls, **kwargs) return marshalled @@ -462,7 +472,7 @@ def get_opts(self, request, **kwargs): opts['load_images'] = True return opts - def add_data(self, marshalled, request, urls=None, **kwargs): + def add_data(self, marshalled, request, conn, urls=None, **kwargs): """Add 'url:image' to any 'Image' in 'WellSamples'.""" marshalled = super(WellsView, self).add_data(marshalled, request, urls=urls, **kwargs) @@ -474,7 +484,8 @@ def add_data(self, marshalled, request, urls=None, **kwargs): # For each WellSample, add image urls to Image for ws in marshalled['WellSamples']: if 'Image' in ws: - self.add_data(ws['Image'], request, image_urls, **kwargs) + self.add_data(ws['Image'], request, conn, + image_urls, **kwargs) return marshalled From a69833a888a2a3165783caaaa5be71584d64e8ba Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 31 Jan 2017 22:18:31 +0000 Subject: [PATCH 02/23] Blitz PlateAcquisition getQueryString() to filter by plate --- .../tools/OmeroPy/src/omero/gateway/__init__.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index ea682010700..680234fcb5d 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -6023,6 +6023,23 @@ class _PlateAcquisitionWrapper (BlitzObjectWrapper): OMERO_CLASS = 'PlateAcquisition' + @classmethod + def _getQueryString(cls, opts=None): + """ + Extend base query to handle filtering of PlateAcquisitions by Plate. + Returns a tuple of (query, clauses, params). + Supported opts: 'plate': to filter by Plate + + :param opts: Dictionary of optional parameters. + :return: Tuple of string, list, ParametersI + """ + query, clauses, params = super( + _PlateAcquisitionWrapper, cls)._getQueryString(opts) + if opts is not None and 'plate' in opts: + clauses.append('obj.plate.id = :pid') + params.add('pid', rlong(opts['plate'])) + return (query, clauses, params) + def getName(self): name = super(_PlateAcquisitionWrapper, self).getName() if name is None: From a0e0063467c7cda52ed7720c971bd08c7ca98ae0 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 31 Jan 2017 22:22:39 +0000 Subject: [PATCH 03/23] Support /plates/:id/plateacquisitions/ --- components/tools/OmeroWeb/omeroweb/api/urls.py | 10 ++++++++++ components/tools/OmeroWeb/omeroweb/api/views.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index f320700b2bd..2a9a5cf8d95 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -176,6 +176,15 @@ GET all wells, using omero-marshal to generate json """ +api_plate_plateacquisitions = url( + r'^v(?P%s)/m/plates/' + '(?P[0-9]+)/plateacquisitions/$' % versions, + views.PlateAcquisitionsView.as_view(), + name='api_plate_plateacquisitions') +""" +GET PlateAcquisitions in Plate, using omero-marshal to generate json +""" + api_plate_wells = url( r'^v(?P%s)/m/plates/' '(?P[0-9]+)/wells/$' % versions, @@ -215,6 +224,7 @@ api_screen_plates, api_plate, api_wells, + api_plate_plateacquisitions, api_plate_wells, api_well, ) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index e24f79f54a0..52a318701c6 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -445,6 +445,21 @@ def get_opts(self, request, **kwargs): return opts +class PlateAcquisitionsView(ObjectsView): + """Handles GET for /plates/:plate_id/plateacquisitions.""" + + OMERO_TYPE = 'PlateAcquisition' + + def get_opts(self, request, **kwargs): + """Add extra parameters to the opts dict.""" + opts = super(PlateAcquisitionsView, self).get_opts(request, **kwargs) + opts['order_by'] = 'lower(obj.name)' + # at /plates/:plate_id/plateacquisitions/ we have 'plate_id' in kwargs + if 'plate_id' in kwargs: + opts['plate'] = long(kwargs['plate_id']) + return opts + + class WellsView(ObjectsView): """Handles GET for /wells/ to list available Images.""" From 6b2d29f857f3cb26273dfc92655eeb35e2a51e35 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 1 Feb 2017 10:12:17 +0000 Subject: [PATCH 04/23] Blitz Well.getQueryString() supports filter by 'plateacquisition' --- .../OmeroPy/src/omero/gateway/__init__.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 680234fcb5d..78d3cb3b2c2 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -6101,16 +6101,18 @@ def _getQueryString(cls, opts=None): """ query, clauses, params = super( _WellWrapper, cls)._getQueryString(opts) - if opts is not None and 'plate' in opts: + if opts is None: + opts = {} + if 'plate' in opts: clauses.append('obj.plate.id = :pid') params.add('pid', rlong(opts['plate'])) - load_images = False - load_pixels = False - load_channels = False - if opts is not None: - load_images = opts.get('load_images') - load_pixels = opts.get('load_pixels') - load_channels = opts.get('load_channels') + load_images = opts.get('load_images') + load_pixels = opts.get('load_pixels') + load_channels = opts.get('load_channels') + if 'plateacquisition' in opts: + clauses.append('plateAcquisition.id = :plateAcq') + params.add('plateAcq', rlong(opts['plateacquisition'])) + load_images = True if load_images or load_pixels or load_channels: # NB: Using left outer join, we may get Wells with no Images query += " left outer join fetch obj.wellSamples as wellSamples"\ From 7c70b45037df8c377fd703fb504ee789e4330a00 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 1 Feb 2017 10:13:48 +0000 Subject: [PATCH 05/23] /plateacquisition/:id/wells/ filters Wells by plate_acquisition --- components/tools/OmeroWeb/omeroweb/api/urls.py | 10 ++++++++++ components/tools/OmeroWeb/omeroweb/api/views.py | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index 2a9a5cf8d95..fa44b0ef200 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -194,6 +194,15 @@ GET Wells in Plate, using omero-marshal to generate json """ +api_plateacquisition_wells = url( + r'^v(?P%s)/m/plateacquisitions/' + '(?P[0-9]+)/wells/$' % versions, + views.WellsView.as_view(), + name='api_plateacquisition_wells') +""" +GET Wells in Plate, using omero-marshal to generate json +""" + api_well = url( r'^v(?P%s)/m/wells/(?P[0-9]+)/$' % versions, views.WellView.as_view(), @@ -226,5 +235,6 @@ api_wells, api_plate_plateacquisitions, api_plate_wells, + api_plateacquisition_wells, api_well, ) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 52a318701c6..363e603a533 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -478,6 +478,8 @@ def get_opts(self, request, **kwargs): # at /plates/:plate_id/wells/ we have 'plate_id' in kwargs if 'plate_id' in kwargs: opts['plate'] = long(kwargs['plate_id']) + elif 'plateacquisition_id' in kwargs: + opts['plateacquisition'] = long(kwargs['plateacquisition_id']) else: # filter by query /wells/?plate=:id plate = getIntOrDefault(request, 'plate', None) @@ -489,7 +491,7 @@ def get_opts(self, request, **kwargs): def add_data(self, marshalled, request, conn, urls=None, **kwargs): """Add 'url:image' to any 'Image' in 'WellSamples'.""" - marshalled = super(WellsView, self).add_data(marshalled, request, + marshalled = super(WellsView, self).add_data(marshalled, request, conn, urls=urls, **kwargs) image_urls = { 'url:image': {'name': 'api_image', From 048adc0f90d4e57158e3531d7450e583cf1c86b8 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 8 Feb 2017 15:49:13 +0000 Subject: [PATCH 06/23] Add 'url:plateacquisitions' to plate json --- components/tools/OmeroWeb/omeroweb/api/views.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 363e603a533..fff24bb2807 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -240,7 +240,9 @@ class PlateView(ObjectView): # Urls to add to marshalled object. See ProjectsView for more details urls = { 'url:wells': {'name': 'api_plate_wells', - 'kwargs': {'plate_id': 'OBJECT_ID'}} + 'kwargs': {'plate_id': 'OBJECT_ID'}}, + 'url:plateacquisitions': {'name': 'api_plate_plateacquisitions', + 'kwargs': {'plate_id': 'OBJECT_ID'}}, } def add_data(self, marshalled, request, conn, urls=None, **kwargs): @@ -413,7 +415,9 @@ def get_opts(self, request, **kwargs): 'url:wells': {'name': 'api_plate_wells', 'kwargs': {'plate_id': 'OBJECT_ID'}}, 'url:plate': {'name': 'api_plate', - 'kwargs': {'object_id': 'OBJECT_ID'}} + 'kwargs': {'object_id': 'OBJECT_ID'}}, + 'url:plateacquisitions': {'name': 'api_plate_plateacquisitions', + 'kwargs': {'plate_id': 'OBJECT_ID'}}, } From edbb992b899f874aade6f48a5ff240246ffd33fe Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 8 Feb 2017 16:15:07 +0000 Subject: [PATCH 07/23] Support /plateacquistions/:id/ includes min/max wellsampleIndex --- .../tools/OmeroWeb/omeroweb/api/api_query.py | 14 ++++++--- .../tools/OmeroWeb/omeroweb/api/urls.py | 9 ++++++ .../tools/OmeroWeb/omeroweb/api/views.py | 30 +++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/api_query.py b/components/tools/OmeroWeb/omeroweb/api/api_query.py index d06dd29e7a8..844ebd75852 100644 --- a/components/tools/OmeroWeb/omeroweb/api/api_query.py +++ b/components/tools/OmeroWeb/omeroweb/api/api_query.py @@ -28,20 +28,26 @@ from omero.rtypes import wrap -def get_wellsample_indices(conn, plate_id): +def get_wellsample_indices(conn, plate_id=None, plateacquisition_id=None): """ - Return min and max WellSample index for a Plate. + Return min and max WellSample index for a Plate OR PlateAcquisition @param conn: BlitzGateway @param plate_id: Plate ID + @param plateacquisition_id: PlateAcquisition ID @return A dict of parent_id: child_count """ ctx = deepcopy(conn.SERVICE_OPTS) ctx.setOmeroGroup(-1) params = ParametersI() - params.add('id', wrap(plate_id)) query = "select minIndex(ws), maxIndex(ws) from Well well " \ - "join well.wellSamples ws where well.plate.id=:id" + "join well.wellSamples ws" + if plate_id is not None: + query += " where well.plate.id=:plate_id " + params.add('plate_id', wrap(plate_id)) + elif plateacquisition_id is not None: + query += " where ws.plateAcquisition.id=:plateacquisition_id" + params.add('plateacquisition_id', wrap(plateacquisition_id)) result = conn.getQueryService().projection(query, params, ctx) result = [r for r in unwrap(result)[0] if r is not None] return result diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index fa44b0ef200..9012eb8c3ae 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -185,6 +185,14 @@ GET PlateAcquisitions in Plate, using omero-marshal to generate json """ +api_plateacquisition = url( + r'^v(?P%s)/m/plateacquisitions/(?P[0-9]+)/$' % versions, + views.PlateAcquisitionView.as_view(), + name='api_plateacquisition') +""" +Well url to GET or DELETE a single Well +""" + api_plate_wells = url( r'^v(?P%s)/m/plates/' '(?P[0-9]+)/wells/$' % versions, @@ -234,6 +242,7 @@ api_plate, api_wells, api_plate_plateacquisitions, + api_plateacquisition, api_plate_wells, api_plateacquisition_wells, api_well, diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index fff24bb2807..a70bd79ad24 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -255,6 +255,21 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): return marshalled +class PlateAcquisitionView(ObjectView): + """Handles GET for /plates/:plate_id/plateacquisitions.""" + + OMERO_TYPE = 'PlateAcquisition' + + def add_data(self, marshalled, request, conn, urls=None, **kwargs): + """Add min/max WellSampleIndex.""" + marshalled = super(PlateAcquisitionView, self).add_data( + marshalled, request, conn, urls=urls, **kwargs) + idx = get_wellsample_indices(conn, + plateacquisition_id=marshalled['@id']) + marshalled['omero:wellsampleIndex'] = idx + return marshalled + + class WellView(ObjectView): """Handle access to an individual Well to GET or DELETE it.""" @@ -454,6 +469,12 @@ class PlateAcquisitionsView(ObjectsView): OMERO_TYPE = 'PlateAcquisition' + # Urls to add to marshalled object. See ProjectsView for more details + urls = { + 'url:plateacquisition': {'name': 'api_plateacquisition', + 'kwargs': {'object_id': 'OBJECT_ID'}}, + } + def get_opts(self, request, **kwargs): """Add extra parameters to the opts dict.""" opts = super(PlateAcquisitionsView, self).get_opts(request, **kwargs) @@ -463,6 +484,15 @@ def get_opts(self, request, **kwargs): opts['plate'] = long(kwargs['plate_id']) return opts + def add_data(self, marshalled, request, conn, urls=None, **kwargs): + """Add min/max WellSampleIndex.""" + marshalled = super(PlateAcquisitionsView, self).add_data( + marshalled, request, conn, urls=urls, **kwargs) + idx = get_wellsample_indices(conn, + plateacquisition_id=marshalled['@id']) + marshalled['omero:wellsampleIndex'] = idx + return marshalled + class WellsView(ObjectsView): """Handles GET for /wells/ to list available Images.""" From 1bfe9b8fd4c76ea7c346b36057922bb0d0feea88 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 8 Feb 2017 22:27:43 +0000 Subject: [PATCH 08/23] Add url 'plateacquisitions/:id/index/:idx/wells' to plate_acq json --- components/tools/OmeroWeb/omeroweb/api/urls.py | 14 +++++++++++++- components/tools/OmeroWeb/omeroweb/api/views.py | 10 ++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index 9012eb8c3ae..2eac5c0770f 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -186,13 +186,24 @@ """ api_plateacquisition = url( - r'^v(?P%s)/m/plateacquisitions/(?P[0-9]+)/$' % versions, + r'^v(?P%s)/m/plateacquisitions/' + '(?P[0-9]+)/$' % versions, views.PlateAcquisitionView.as_view(), name='api_plateacquisition') """ Well url to GET or DELETE a single Well """ +api_plateacquisition_index_wells = url( + r'^v(?P%s)/m/plateacquisitions/' + '(?P[0-9]+)/index/' + '(?P[0-9]+)/wells/$' % versions, + views.WellsView.as_view(), + name='api_plateacquisition_index_wells') +""" +GET PlateAcquisitions in Plate, using omero-marshal to generate json +""" + api_plate_wells = url( r'^v(?P%s)/m/plates/' '(?P[0-9]+)/wells/$' % versions, @@ -243,6 +254,7 @@ api_wells, api_plate_plateacquisitions, api_plateacquisition, + api_plateacquisition_index_wells, api_plate_wells, api_plateacquisition_wells, api_well, diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index a70bd79ad24..d47737398e5 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -491,6 +491,16 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): idx = get_wellsample_indices(conn, plateacquisition_id=marshalled['@id']) marshalled['omero:wellsampleIndex'] = idx + + # Add link to Wells for each WellSample index in this PlateAcquisition + for ws_index in range(idx[0], idx[1]+1): + version = kwargs['api_version'] + extra = {'plateacquisition_id': marshalled['@id'], + 'index': ws_index} + url = build_url(request, 'api_plateacquisition_index_wells', + version, **extra) + marshalled['url:index_%s' % ws_index] = url + return marshalled From 9253577329f52e73d4c0f38a42f2aeb52c347ff6 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 8 Feb 2017 23:11:15 +0000 Subject: [PATCH 09/23] Blitz Well getQueryString() supports filter by 'wellsample_index' --- components/tools/OmeroPy/src/omero/gateway/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 78d3cb3b2c2..2bb978cdebc 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -6113,6 +6113,9 @@ def _getQueryString(cls, opts=None): clauses.append('plateAcquisition.id = :plateAcq') params.add('plateAcq', rlong(opts['plateacquisition'])) load_images = True + if 'wellsample_index' in opts: + clauses.append('index(wellSamples) = :wellsample_index') + params.add('wellsample_index', rint(opts['wellsample_index'])) if load_images or load_pixels or load_channels: # NB: Using left outer join, we may get Wells with no Images query += " left outer join fetch obj.wellSamples as wellSamples"\ From 8e3e5d607058a8c06ed99bfe0f59e162d4958f63 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 8 Feb 2017 23:12:22 +0000 Subject: [PATCH 10/23] api WellsView handles 'index' to filter by wellsample_index --- components/tools/OmeroWeb/omeroweb/api/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index d47737398e5..d2453f3e864 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -524,6 +524,8 @@ def get_opts(self, request, **kwargs): opts['plate'] = long(kwargs['plate_id']) elif 'plateacquisition_id' in kwargs: opts['plateacquisition'] = long(kwargs['plateacquisition_id']) + if 'index' in kwargs: + opts['wellsample_index'] = int(kwargs['index']) else: # filter by query /wells/?plate=:id plate = getIntOrDefault(request, 'plate', None) From 84d177c826db40ac3843a82e4224e217aec96412 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 20 Feb 2017 13:21:26 +0000 Subject: [PATCH 11/23] Add support for /plates/id/index/0/wells/ --- components/tools/OmeroWeb/omeroweb/api/urls.py | 13 ++++++++++++- components/tools/OmeroWeb/omeroweb/api/views.py | 5 +++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index 2eac5c0770f..33ec4dfde79 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -201,7 +201,17 @@ views.WellsView.as_view(), name='api_plateacquisition_index_wells') """ -GET PlateAcquisitions in Plate, using omero-marshal to generate json +GET Wells from a single Index in PlateAcquisition +""" + +api_plate_index_wells = url( + r'^v(?P%s)/m/plates/' + '(?P[0-9]+)/index/' + '(?P[0-9]+)/wells/$' % versions, + views.WellsView.as_view(), + name='api_plate_index_wells') +""" +GET Wells from a single Index in Plate """ api_plate_wells = url( @@ -255,6 +265,7 @@ api_plate_plateacquisitions, api_plateacquisition, api_plateacquisition_index_wells, + api_plate_index_wells, api_plate_wells, api_plateacquisition_wells, api_well, diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 65d5dd6300a..8689e2993bd 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -550,13 +550,14 @@ def get_opts(self, request, **kwargs): opts['plate'] = long(kwargs['plate_id']) elif 'plateacquisition_id' in kwargs: opts['plateacquisition'] = long(kwargs['plateacquisition_id']) - if 'index' in kwargs: - opts['wellsample_index'] = int(kwargs['index']) else: # filter by query /wells/?plate=:id plate = getIntOrDefault(request, 'plate', None) if plate is not None: opts['plate'] = plate + # When filtering by plate or plateacquisition, can filter by ws index + if 'index' in kwargs: + opts['wellsample_index'] = int(kwargs['index']) # Listing Wells, load Images opts['load_images'] = True return opts From be3673864462d0ec210c0b12a8baf73b2438ad03 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 20 Feb 2017 14:13:35 +0000 Subject: [PATCH 12/23] Add 'urls:wellsampleindex_wells' to PlateAcquisition and Plate views --- .../tools/OmeroWeb/omeroweb/api/views.py | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 8689e2993bd..6327b92e021 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -274,8 +274,19 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): marshalled = super(PlateView, self).add_data(marshalled, request, conn, urls=urls, **kwargs) idx = get_wellsample_indices(conn, marshalled['@id']) - marshalled['omero:wellsampleIndex'] = idx + + # Add link to Wells for each WellSample index in this Plate + ws_urls = [] + for ws_index in range(idx[0], idx[1]+1): + version = kwargs['api_version'] + extra = {'plate_id': marshalled['@id'], + 'index': ws_index} + url = build_url(request, 'api_plate_index_wells', + version, **extra) + ws_urls.append(url) + marshalled['urls:wellsampleindex_wells'] = ws_urls + return marshalled @@ -291,6 +302,17 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): idx = get_wellsample_indices(conn, plateacquisition_id=marshalled['@id']) marshalled['omero:wellsampleIndex'] = idx + + # Add link to Wells for each WellSample index in this PlateAcquisition + ws_urls = [] + for ws_index in range(idx[0], idx[1]+1): + version = kwargs['api_version'] + extra = {'plateacquisition_id': marshalled['@id'], + 'index': ws_index} + url = build_url(request, 'api_plateacquisition_index_wells', + version, **extra) + ws_urls.append(url) + marshalled['urls:wellsampleindex_wells'] = ws_urls return marshalled @@ -519,13 +541,15 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): marshalled['omero:wellsampleIndex'] = idx # Add link to Wells for each WellSample index in this PlateAcquisition + ws_urls = [] for ws_index in range(idx[0], idx[1]+1): version = kwargs['api_version'] extra = {'plateacquisition_id': marshalled['@id'], 'index': ws_index} url = build_url(request, 'api_plateacquisition_index_wells', version, **extra) - marshalled['url:index_%s' % ws_index] = url + ws_urls.append(url) + marshalled['urls:wellsampleindex_wells'] = ws_urls return marshalled From 58b6c302474013b9740aa761639460c927063c3d Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 20 Feb 2017 23:07:31 +0000 Subject: [PATCH 13/23] Add tests for listing 'index' urls in plate/plate_acquisition --- .../tools/OmeroWeb/omeroweb/api/views.py | 15 +- .../test/integration/test_api_containers.py | 14 +- .../test/integration/test_api_wells.py | 147 ++++++++++++++---- 3 files changed, 140 insertions(+), 36 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 6327b92e021..0e4b7d5272c 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -278,13 +278,14 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): # Add link to Wells for each WellSample index in this Plate ws_urls = [] - for ws_index in range(idx[0], idx[1]+1): - version = kwargs['api_version'] - extra = {'plate_id': marshalled['@id'], - 'index': ws_index} - url = build_url(request, 'api_plate_index_wells', - version, **extra) - ws_urls.append(url) + if len(idx) == 2: + for ws_index in range(idx[0], idx[1]+1): + version = kwargs['api_version'] + extra = {'plate_id': marshalled['@id'], + 'index': ws_index} + url = build_url(request, 'api_plate_index_wells', + version, **extra) + ws_urls.append(url) marshalled['urls:wellsampleindex_wells'] = ws_urls return marshalled diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 90555ebffa5..87a1062698f 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -435,7 +435,19 @@ def test_spw_urls(self, user1, screen_plates): assert_objects(conn, plates_json, plates, dtype='Plate', extra=extra) # View single plate rsp = _get_response_json(client, plates_json[0]['url:plate'], {}) - assert_objects(conn, [rsp['data']], plates[0:1], dtype='Plate') + plate_json = rsp['data'] + minMaxIndex = [0, 0] + links = [] + for idx in range(minMaxIndex[0], minMaxIndex[1]+1): + l = build_url(client, 'api_plate_index_wells', + {'api_version': version, + 'plate_id': plate_json['@id'], + 'index': idx}) + links.append(l) + extra = [{'urls:wellsampleindex_wells': links, + 'omero:wellsampleIndex': minMaxIndex}] + assert_objects(conn, [plate_json], plates[0:1], dtype='Plate', + extra=extra) # List wells of first plate wells_url = plates_json[0]['url:wells'] diff --git a/components/tools/OmeroWeb/test/integration/test_api_wells.py b/components/tools/OmeroWeb/test/integration/test_api_wells.py index d746b2b0cc5..a2a0eeccde2 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_wells.py +++ b/components/tools/OmeroWeb/test/integration/test_api_wells.py @@ -24,7 +24,8 @@ from django.conf import settings import pytest from test_api_projects import get_update_service, \ - get_connection, marshal_objects + get_connection, marshal_objects, cmp_name_insensitive +from test_api_containers import build_url from omero.model import ImageI, \ LengthI, \ PlateAcquisitionI, \ @@ -49,10 +50,10 @@ def cmp_column_row(x, y): return sort_by_column -def remove_urls(marshalled): +def remove_urls(marshalled, keys=[]): """Traverse a dict (Well) removing 'url:' values.""" for key, val in marshalled.items(): - if key.startswith('url:'): + if key.startswith('url:') and key not in keys: del(marshalled[key]) # We only traverse paths where we know urls are elif key == 'Image': @@ -85,13 +86,15 @@ def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", expected = marshal_objects(objs) assert len(json_objects) == len(expected) for i, o1, o2 in zip(range(len(expected)), json_objects, expected): + dont_remove = [] if extra is not None and i < len(extra): o2.update(extra[i]) + dont_remove = extra[i].keys() # We dump to json and re-load (same as test data). This means that # unicode has been handled in same way, e.g. Pixel size symbols. o2 = json.loads(json.dumps(o2)) - # remove any urls from json (tested elsewhere) - remove_urls(o1) + # remove urls from json + remove_urls(o1, dont_remove) assert o1 == o2 @@ -105,25 +108,28 @@ def user1(self): group = self.new_group(perms='rwra--') return self.new_client_and_user(group=group) - def create_plate_wells(self, user1, rows, cols, with_plate_acq=True): + def create_plate_wells(self, user1, rows, cols, plateacquisitions=1): """Return Plate with Wells.""" updateService = get_update_service(user1) plate = PlateI() plate.name = rstring('plate') plate = updateService.saveAndReturnObject(plate) - # Single PlateAcquisition for plate - if with_plate_acq: + # PlateAcquisitions for plate + plate_acqs = [] + for p in range(plateacquisitions): plate_acq = PlateAcquisitionI() - plate_acq.name = rstring('plateacquisition') + plate_acq.name = rstring('plateacquisition_%s' % p) plate_acq.description = rstring('plateacquisition_description') plate_acq.maximumFieldCount = rint(3) plate_acq.startTime = rtime(1L) plate_acq.endTime = rtime(2L) plate_acq.plate = PlateI(plate.id.val, False) plate_acq = updateService.saveAndReturnObject(plate_acq) + plate_acqs.append(plate_acq) # Create Wells for plate + ref_frame = UnitsLength.REFERENCEFRAME for row in range(rows): for col in range(cols): # create Well @@ -133,19 +139,23 @@ def create_plate_wells(self, user1, rows, cols, with_plate_acq=True): well.plate = PlateI(plate.id.val, False) # Only wells in first Column have well-samples etc. if col == 0: - # Have 3 images/well-samples in these wells - for i in range(3): - image = self.create_test_image( - size_x=5, size_y=5, session=user1[0].getSession()) - ws = WellSampleI() - ws.image = ImageI(image.id, False) - ws.well = well - ws.posX = LengthI(i * 10, UnitsLength.REFERENCEFRAME) - ws.posY = LengthI(i, UnitsLength.REFERENCEFRAME) - if with_plate_acq: - ws.setPlateAcquisition( - PlateAcquisitionI(plate_acq.id.val, False)) - well.addWellSample(ws) + # Have 3 images/well-samples per plateacquisition + # (if no plateacquisitions, create 3 well-samples without) + for p in range(max(1, plateacquisitions)): + for i in range(3): + image = self.create_test_image( + size_x=5, size_y=5, + session=user1[0].getSession()) + ws = WellSampleI() + ws.image = ImageI(image.id, False) + ws.well = well + ws.posX = LengthI(i * 10, ref_frame) + ws.posY = LengthI(i, ref_frame) + if p < len(plate_acqs): + ws.setPlateAcquisition( + PlateAcquisitionI(plate_acqs[p].id.val, + False)) + well.addWellSample(ws) updateService.saveObject(well) return plate @@ -156,7 +166,7 @@ def small_plate(self, user1): Two wells are created, but only the first has any Images (3). """ - return self.create_plate_wells(user1, 1, 2, with_plate_acq=False) + return self.create_plate_wells(user1, 1, 2, 0) @pytest.fixture() def bigger_plate(self, user1): @@ -168,17 +178,27 @@ def bigger_plate(self, user1): """ return self.create_plate_wells(user1, 2, 3) + @pytest.fixture() + def multi_acquisition_plate(self, user1): + """ + Create a bigger plate with 2 plate_acquisitions. + + Six wells are created, but only wells in the first + column have any Images (3 fields in each of 2 Acquisitions). + """ + return self.create_plate_wells(user1, 2, 3, 2) + def test_plate_wells(self, user1, small_plate, bigger_plate): """Test listing of Wells in a Plate.""" conn = get_connection(user1) user_name = conn.getUser().getName() - django_client = self.new_django_client(user_name, user_name) + client = self.new_django_client(user_name, user_name) version = settings.API_VERSIONS[-1] wells_url = reverse('api_wells', kwargs={'api_version': version}) # List ALL Wells in both plates - rsp = _get_response_json(django_client, wells_url, {}) + rsp = _get_response_json(client, wells_url, {}) assert len(rsp['data']) == 8 # Filter Wells by Plate @@ -190,16 +210,87 @@ def test_plate_wells(self, user1, small_plate, bigger_plate): wells = [w._obj for w in plate_wrapper.listChildren()] wells.sort(cmp_column_row) payload = {'plate': plate.id.val} - rsp = _get_response_json(django_client, wells_url, payload) + rsp = _get_response_json(client, wells_url, payload) # Manual check that Images are loaded but Pixels are not assert len(rsp['data']) == well_count well_sample = rsp['data'][0]['WellSamples'][0] assert 'Image' in well_sample assert ('PlateAcquisition' in well_sample) == with_acq assert 'Pixels' not in well_sample['Image'] - + extra = [{'url:well': build_url(client, 'api_well', + {'object_id': w.id.val, + 'api_version': version})} + for w in wells] assert_objects(conn, rsp['data'], wells, dtype='Well', - opts={'load_images': True}) + opts={'load_images': True}, extra=extra) + + def test_plate_index_wells(self, user1, multi_acquisition_plate): + """ + Test filtering of Wells by Plate/Acquisition AND index. + + Browse urls Plate -> PlateAcquisitions -> Wells + OR Plate -> Wells (filtering by Index) + """ + conn = get_connection(user1) + user_name = conn.getUser().getName() + client = self.new_django_client(user_name, user_name) + version = settings.API_VERSIONS[-1] + + plate_id = multi_acquisition_plate.id.val + plate_url = reverse('api_plate', + kwargs={'object_id': plate_id, + 'api_version': version}) + + rsp = _get_response_json(client, plate_url, {}) + plate_json = rsp['data'] + + # Construct the urls we expect... + plate_acq_link = build_url(client, 'api_plate_plateacquisitions', + {'plate_id': plate_id, + 'api_version': version}) + well_link = build_url(client, 'api_plate_wells', + {'plate_id': plate_id, + 'api_version': version}) + index_links = [] + plate = conn.getObject('Plate', plate_id) + idx = plate.getNumberOfFields() + for i in range(idx[0], idx[1]+1): + l = build_url(client, 'api_plate_index_wells', + {'api_version': version, + 'plate_id': plate_id, + 'index': i}) + index_links.append(l) + # ...and compare plate json: + assert_objects(conn, [plate_json], [multi_acquisition_plate], + dtype='Plate', + extra=[{'url:plateacquisitions': plate_acq_link, + 'urls:wellsampleindex_wells': index_links, + 'url:wells': well_link, + 'omero:wellsampleIndex': list(idx)}]) + + # Browse to /plate/:id/plateacquisitions/ + rsp = _get_response_json(client, plate_acq_link, {}) + plate_acq_json = rsp['data'] + + # Construct data & urls we expect... + pas = list(plate.listPlateAcquisitions()) + pas.sort(cmp_name_insensitive) + paq_ids = [p.id for p in pas] + extra = [] + for p, plate_acq in enumerate(pas): + index_links = [] + for i in range(p * 3, (p + 1) * 3): + l = build_url(client, 'api_plateacquisition_index_wells', + {'api_version': version, + 'plateacquisition_id': plate_acq.id, + 'index': i}) + index_links.append(l) + extra.append({'urls:wellsampleindex_wells': index_links, + 'omero:wellsampleIndex': [p * 3, (p + 1) * 3 - 1]}) + # ...and compare + assert_objects(conn, plate_acq_json, paq_ids, + dtype="PlateAcquisition", + extra=extra) def test_well(self, user1, small_plate): """Test loading a single Well, with or without WellSamples.""" From fc3d2785e9979a105359ffb752465478145f52b3 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 20 Feb 2017 23:21:08 +0000 Subject: [PATCH 14/23] Remove duplicate imports --- components/tools/OmeroWeb/omeroweb/api/api_query.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/api_query.py b/components/tools/OmeroWeb/omeroweb/api/api_query.py index 920e2303f12..5bd427e4918 100644 --- a/components/tools/OmeroWeb/omeroweb/api/api_query.py +++ b/components/tools/OmeroWeb/omeroweb/api/api_query.py @@ -25,8 +25,6 @@ from api_marshal import marshal_objects from copy import deepcopy -from omero.sys import ParametersI -from omero.rtypes import wrap def get_wellsample_indices(conn, plate_id=None, plateacquisition_id=None): From c03093a4e84cf4650e1f570e1aed906d3edab589 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 21 Feb 2017 11:37:13 +0000 Subject: [PATCH 15/23] Use 'url:' prefix for url:wellsampleindex_wells. --- components/tools/OmeroWeb/omeroweb/api/views.py | 6 +++--- .../tools/OmeroWeb/test/integration/test_api_containers.py | 7 +++++-- .../tools/OmeroWeb/test/integration/test_api_wells.py | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 0e4b7d5272c..e4ff367ad97 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -286,7 +286,7 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): url = build_url(request, 'api_plate_index_wells', version, **extra) ws_urls.append(url) - marshalled['urls:wellsampleindex_wells'] = ws_urls + marshalled['url:wellsampleindex_wells'] = ws_urls return marshalled @@ -313,7 +313,7 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): url = build_url(request, 'api_plateacquisition_index_wells', version, **extra) ws_urls.append(url) - marshalled['urls:wellsampleindex_wells'] = ws_urls + marshalled['url:wellsampleindex_wells'] = ws_urls return marshalled @@ -550,7 +550,7 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): url = build_url(request, 'api_plateacquisition_index_wells', version, **extra) ws_urls.append(url) - marshalled['urls:wellsampleindex_wells'] = ws_urls + marshalled['url:wellsampleindex_wells'] = ws_urls return marshalled diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 87a1062698f..06e7bbe0d4f 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -341,6 +341,9 @@ def test_datasets_plates(self, user1, dtype, child_count, object_url = "%sm/%ss/%s/" % (base_url, dtype.lower(), children[0].id.val) rsp = _get_response_json(django_client, object_url, payload) + if dtype == 'Plate': + # When we get a single Plate, expect this (not when listing plates) + ds_or_pl_children= [{'omero:wellsampleIndex': [0, 0]}] assert_objects(conn, [rsp['data']], [children[0]], dtype=dtype, extra=ds_or_pl_children) @@ -351,13 +354,13 @@ def test_datasets_plates(self, user1, dtype, child_count, 'childCount': str(child_count).lower()} rsp = _get_response_json(django_client, request_url, payload) extra = None - if ds_or_pl_children is not None: + if ds_or_pl_children is not None and len(ds_or_pl_children) > 1: extra = ds_or_pl_children[0:limit] assert_objects(conn, rsp['data'], children[0:limit], dtype=dtype, extra=extra) payload['page'] = 2 rsp = _get_response_json(django_client, request_url, payload) - if ds_or_pl_children is not None: + if ds_or_pl_children is not None and len(ds_or_pl_children) > 1: extra = ds_or_pl_children[limit:limit * 2] assert_objects(conn, rsp['data'], children[limit:limit * 2], dtype=dtype, extra=extra) diff --git a/components/tools/OmeroWeb/test/integration/test_api_wells.py b/components/tools/OmeroWeb/test/integration/test_api_wells.py index a2a0eeccde2..429d44244b7 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_wells.py +++ b/components/tools/OmeroWeb/test/integration/test_api_wells.py @@ -264,7 +264,7 @@ def test_plate_index_wells(self, user1, multi_acquisition_plate): assert_objects(conn, [plate_json], [multi_acquisition_plate], dtype='Plate', extra=[{'url:plateacquisitions': plate_acq_link, - 'urls:wellsampleindex_wells': index_links, + 'url:wellsampleindex_wells': index_links, 'url:wells': well_link, 'omero:wellsampleIndex': list(idx)}]) @@ -285,7 +285,7 @@ def test_plate_index_wells(self, user1, multi_acquisition_plate): 'plateacquisition_id': plate_acq.id, 'index': i}) index_links.append(l) - extra.append({'urls:wellsampleindex_wells': index_links, + extra.append({'url:wellsampleindex_wells': index_links, 'omero:wellsampleIndex': [p * 3, (p + 1) * 3 - 1]}) # ...and compare assert_objects(conn, plate_acq_json, paq_ids, From 424ef1b802c86357dda8e5de5f2fee328d792ba4 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 21 Feb 2017 13:32:48 +0000 Subject: [PATCH 16/23] Fix merge conflict --- .../tools/OmeroWeb/test/integration/test_api_wells.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_wells.py b/components/tools/OmeroWeb/test/integration/test_api_wells.py index 429d44244b7..e1ce7ad34b4 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_wells.py +++ b/components/tools/OmeroWeb/test/integration/test_api_wells.py @@ -192,13 +192,13 @@ def test_plate_wells(self, user1, small_plate, bigger_plate): """Test listing of Wells in a Plate.""" conn = get_connection(user1) user_name = conn.getUser().getName() - client = self.new_django_client(user_name, user_name) + django_client = self.new_django_client(user_name, user_name) version = settings.API_VERSIONS[-1] wells_url = reverse('api_wells', kwargs={'api_version': version}) # List ALL Wells in both plates - rsp = _get_response_json(client, wells_url, {}) + rsp = _get_response_json(django_client, wells_url, {}) assert len(rsp['data']) == 8 # Filter Wells by Plate @@ -210,14 +210,14 @@ def test_plate_wells(self, user1, small_plate, bigger_plate): wells = [w._obj for w in plate_wrapper.listChildren()] wells.sort(cmp_column_row) payload = {'plate': plate.id.val} - rsp = _get_response_json(client, wells_url, payload) + rsp = _get_response_json(django_client, wells_url, payload) # Manual check that Images are loaded but Pixels are not assert len(rsp['data']) == well_count well_sample = rsp['data'][0]['WellSamples'][0] assert 'Image' in well_sample assert ('PlateAcquisition' in well_sample) == with_acq assert 'Pixels' not in well_sample['Image'] - extra = [{'url:well': build_url(client, 'api_well', + extra = [{'url:well': build_url(django_client, 'api_well', {'object_id': w.id.val, 'api_version': version})} for w in wells] From f17506b458bf037624ef217afcbe1535cfec9e35 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 21 Feb 2017 21:54:30 +0000 Subject: [PATCH 17/23] Tidy imports in test_api_wells.py --- .../tools/OmeroWeb/test/integration/test_api_containers.py | 2 +- .../tools/OmeroWeb/test/integration/test_api_wells.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 06e7bbe0d4f..1a2bc9f31b8 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -343,7 +343,7 @@ def test_datasets_plates(self, user1, dtype, child_count, rsp = _get_response_json(django_client, object_url, payload) if dtype == 'Plate': # When we get a single Plate, expect this (not when listing plates) - ds_or_pl_children= [{'omero:wellsampleIndex': [0, 0]}] + ds_or_pl_children = [{'omero:wellsampleIndex': [0, 0]}] assert_objects(conn, [rsp['data']], [children[0]], dtype=dtype, extra=ds_or_pl_children) diff --git a/components/tools/OmeroWeb/test/integration/test_api_wells.py b/components/tools/OmeroWeb/test/integration/test_api_wells.py index e1ce7ad34b4..0a913ae1a0f 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_wells.py +++ b/components/tools/OmeroWeb/test/integration/test_api_wells.py @@ -23,8 +23,10 @@ from django.core.urlresolvers import reverse from django.conf import settings import pytest -from test_api_projects import get_update_service, \ - get_connection, marshal_objects, cmp_name_insensitive +from test_api_projects import cmp_name_insensitive, \ + get_connection, \ + get_update_service, \ + marshal_objects from test_api_containers import build_url from omero.model import ImageI, \ LengthI, \ From 3a71a644f1a0ef982a5ad5fbd2297829ee25c93d Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 21 Feb 2017 22:02:18 +0000 Subject: [PATCH 18/23] Tiny fix in docstring --- components/tools/OmeroWeb/test/integration/test_api_wells.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_wells.py b/components/tools/OmeroWeb/test/integration/test_api_wells.py index 0a913ae1a0f..d39f85bfe0f 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_wells.py +++ b/components/tools/OmeroWeb/test/integration/test_api_wells.py @@ -228,7 +228,7 @@ def test_plate_wells(self, user1, small_plate, bigger_plate): def test_plate_index_wells(self, user1, multi_acquisition_plate): """ - Test filtering of Wells by Plate/Acquisition AND index. + Test filtering of Wells by Plate/PlateAcquisition AND index. Browse urls Plate -> PlateAcquisitions -> Wells OR Plate -> Wells (filtering by Index) From 1f6229eff1565a64468a12bebb9af836d2d3a3db Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 22 Feb 2017 23:52:13 +0000 Subject: [PATCH 19/23] Blitz helper add_plate_filter() used in getQueryString() --- .../tools/OmeroPy/src/omero/gateway/__init__.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index b16444ec455..39525262503 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -158,6 +158,13 @@ def getChannelsQuery(): ' left outer join fetch logicalChannel.contrastMethod') +def add_plate_filter(clauses, params, opts): + """Helper for adding 'plate' to filtering clauses and parameters.""" + if opts is not None and 'plate' in opts: + clauses.append('obj.plate.id = :pid') + params.add('pid', rlong(opts['plate'])) + + class OmeroRestrictionWrapper (object): def canDownload(self): @@ -6020,9 +6027,7 @@ def _getQueryString(cls, opts=None): """ query, clauses, params = super( _PlateAcquisitionWrapper, cls)._getQueryString(opts) - if opts is not None and 'plate' in opts: - clauses.append('obj.plate.id = :pid') - params.add('pid', rlong(opts['plate'])) + add_plate_filter(clauses, params, opts) return (query, clauses, params) def getName(self): @@ -6088,9 +6093,7 @@ def _getQueryString(cls, opts=None): _WellWrapper, cls)._getQueryString(opts) if opts is None: opts = {} - if 'plate' in opts: - clauses.append('obj.plate.id = :pid') - params.add('pid', rlong(opts['plate'])) + add_plate_filter(clauses, params, opts) load_images = opts.get('load_images') load_pixels = opts.get('load_pixels') load_channels = opts.get('load_channels') From 50efc29849177eb7da31f965a83c074e219a4cb8 Mon Sep 17 00:00:00 2001 From: William Moore Date: Fri, 24 Feb 2017 11:45:03 +0000 Subject: [PATCH 20/23] flake8 fix --- components/tools/OmeroWeb/test/integration/test_api_wells.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_wells.py b/components/tools/OmeroWeb/test/integration/test_api_wells.py index 54c9db23c99..8cbf94eac12 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_wells.py +++ b/components/tools/OmeroWeb/test/integration/test_api_wells.py @@ -237,7 +237,7 @@ def test_plate_index_wells(self, user1, multi_acquisition_plate): conn = get_connection(user1) user_name = conn.getUser().getName() client = self.new_django_client(user_name, user_name) - version = settings.API_VERSIONS[-1] + version = api_settings.API_VERSIONS[-1] plate_id = multi_acquisition_plate.id.val plate_url = reverse('api_plate', From 1320d393fc4077a8e5465b0f23e2b7c6f78d3b72 Mon Sep 17 00:00:00 2001 From: William Moore Date: Sun, 26 Feb 2017 22:22:20 +0000 Subject: [PATCH 21/23] Fix test_spw_urls --- .../tools/OmeroWeb/test/integration/test_api_containers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index ec294e35409..efd12927d2d 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -467,7 +467,7 @@ def test_spw_urls(self, user1, screen_plates): 'plate_id': plate_json['@id'], 'index': idx}) links.append(l) - extra = [{'urls:wellsampleindex_wells': links, + extra = [{'url:wellsampleindex_wells': links, 'omero:wellsampleIndex': minMaxIndex}] assert_objects(conn, [plate_json], plates[0:1], dtype='Plate', extra=extra) From 2b2a9b9e688f1322c30aec5d600357ad5ec91d4c Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 27 Feb 2017 15:08:42 +0000 Subject: [PATCH 22/23] Use 'wellsampleindex' in urls --- components/tools/OmeroWeb/omeroweb/api/urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index 348bd5dae2b..76baa347fb6 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -196,7 +196,7 @@ api_plateacquisition_index_wells = url( r'^v(?P%s)/m/plateacquisitions/' - '(?P[0-9]+)/index/' + '(?P[0-9]+)/wellsampleindex/' '(?P[0-9]+)/wells/$' % versions, views.WellsView.as_view(), name='api_plateacquisition_index_wells') @@ -206,7 +206,7 @@ api_plate_index_wells = url( r'^v(?P%s)/m/plates/' - '(?P[0-9]+)/index/' + '(?P[0-9]+)/wellsampleindex/' '(?P[0-9]+)/wells/$' % versions, views.WellsView.as_view(), name='api_plate_index_wells') From 2d94baf12352d711bb53cc677562cb84919c3b0e Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 27 Feb 2017 16:09:20 +0000 Subject: [PATCH 23/23] Update 'index' -> 'wellsampleindex' in url names --- components/tools/OmeroWeb/omeroweb/api/urls.py | 12 ++++++------ components/tools/OmeroWeb/omeroweb/api/views.py | 8 +++++--- .../OmeroWeb/test/integration/test_api_containers.py | 2 +- .../OmeroWeb/test/integration/test_api_wells.py | 5 +++-- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index 76baa347fb6..5261364e90f 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -194,22 +194,22 @@ Well url to GET or DELETE a single Well """ -api_plateacquisition_index_wells = url( +api_plateacquisition_wellsampleindex_wells = url( r'^v(?P%s)/m/plateacquisitions/' '(?P[0-9]+)/wellsampleindex/' '(?P[0-9]+)/wells/$' % versions, views.WellsView.as_view(), - name='api_plateacquisition_index_wells') + name='api_plateacquisition_wellsampleindex_wells') """ GET Wells from a single Index in PlateAcquisition """ -api_plate_index_wells = url( +api_plate_wellsampleindex_wells = url( r'^v(?P%s)/m/plates/' '(?P[0-9]+)/wellsampleindex/' '(?P[0-9]+)/wells/$' % versions, views.WellsView.as_view(), - name='api_plate_index_wells') + name='api_plate_wellsampleindex_wells') """ GET Wells from a single Index in Plate """ @@ -264,8 +264,8 @@ api_wells, api_plate_plateacquisitions, api_plateacquisition, - api_plateacquisition_index_wells, - api_plate_index_wells, + api_plateacquisition_wellsampleindex_wells, + api_plate_wellsampleindex_wells, api_plate_wells, api_plateacquisition_wells, api_well, diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 606a51387a8..faf8a265ec1 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -283,7 +283,7 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): version = kwargs['api_version'] extra = {'plate_id': marshalled['@id'], 'index': ws_index} - url = build_url(request, 'api_plate_index_wells', + url = build_url(request, 'api_plate_wellsampleindex_wells', version, **extra) ws_urls.append(url) marshalled['url:wellsampleindex_wells'] = ws_urls @@ -310,7 +310,8 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): version = kwargs['api_version'] extra = {'plateacquisition_id': marshalled['@id'], 'index': ws_index} - url = build_url(request, 'api_plateacquisition_index_wells', + url = build_url(request, + 'api_plateacquisition_wellsampleindex_wells', version, **extra) ws_urls.append(url) marshalled['url:wellsampleindex_wells'] = ws_urls @@ -547,7 +548,8 @@ def add_data(self, marshalled, request, conn, urls=None, **kwargs): version = kwargs['api_version'] extra = {'plateacquisition_id': marshalled['@id'], 'index': ws_index} - url = build_url(request, 'api_plateacquisition_index_wells', + url = build_url(request, + 'api_plateacquisition_wellsampleindex_wells', version, **extra) ws_urls.append(url) marshalled['url:wellsampleindex_wells'] = ws_urls diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index efd12927d2d..124c0ad0a7c 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -462,7 +462,7 @@ def test_spw_urls(self, user1, screen_plates): minMaxIndex = [0, 0] links = [] for idx in range(minMaxIndex[0], minMaxIndex[1]+1): - l = build_url(client, 'api_plate_index_wells', + l = build_url(client, 'api_plate_wellsampleindex_wells', {'api_version': version, 'plate_id': plate_json['@id'], 'index': idx}) diff --git a/components/tools/OmeroWeb/test/integration/test_api_wells.py b/components/tools/OmeroWeb/test/integration/test_api_wells.py index 8cbf94eac12..96292c7429c 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_wells.py +++ b/components/tools/OmeroWeb/test/integration/test_api_wells.py @@ -258,7 +258,7 @@ def test_plate_index_wells(self, user1, multi_acquisition_plate): plate = conn.getObject('Plate', plate_id) idx = plate.getNumberOfFields() for i in range(idx[0], idx[1]+1): - l = build_url(client, 'api_plate_index_wells', + l = build_url(client, 'api_plate_wellsampleindex_wells', {'api_version': version, 'plate_id': plate_id, 'index': i}) @@ -283,7 +283,8 @@ def test_plate_index_wells(self, user1, multi_acquisition_plate): for p, plate_acq in enumerate(pas): index_links = [] for i in range(p * 3, (p + 1) * 3): - l = build_url(client, 'api_plateacquisition_index_wells', + l = build_url(client, + 'api_plateacquisition_wellsampleindex_wells', {'api_version': version, 'plateacquisition_id': plate_acq.id, 'index': i})