From 40fafc4d2f60b43f249615d83f75a19f085acb5c Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Tue, 7 Apr 2015 19:38:48 +0300 Subject: [PATCH 01/27] Add debugging benchmarks to plateGrid_json --- .../OmeroWeb/omeroweb/webgateway/views.py | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/views.py b/components/tools/OmeroWeb/omeroweb/webgateway/views.py index 31e872236aa..ddec29eb522 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/views.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/views.py @@ -15,6 +15,7 @@ import re import json +from datetime import datetime import omero import omero.clients @@ -1328,7 +1329,11 @@ def urlprefix(iid): def plateGrid_json(request, pid, field=0, conn=None, **kwargs): """ """ + t0 = datetime.now() plate = conn.getObject('plate', long(pid)) + t1 = datetime.now() + logger.debug('time to get plate: %s' % (t1 - t0)) + t0 = t1 try: field = long(field or 0) except ValueError: @@ -1345,23 +1350,47 @@ def urlprefix(iid): xtra = {'thumbUrlPrefix': kwargs.get('urlprefix', urlprefix)} server_id = kwargs['server_id'] + t1 = datetime.now() + logger.debug('time to get thumbnail URL prefix: %s' % (t1 - t0)) + t0 = t1 + rv = webgateway_cache.getJson(request, server_id, plate, 'plategrid-%d-%d' % (field, thumbsize)) if rv is None: + t1 = datetime.now() + logger.debug('time to check cache miss: %s' % (t1 - t0)) + t0 = t1 + plate.setGridSizeConstraints(8, 12) - for row in plate.getWellGrid(field): + t1 = datetime.now() + logger.debug('time to set grid constraints: %s' % (t1 - t0)) + t0 = t1 + t0 = t1 + wellGrid = plate.getWellGrid(field) + t1 = datetime.now() + logger.debug('time to get well grid: %s' % (t1 - t0)) + for row in wellGrid: tr = [] for e in row: if e: i = e.getImage() + t2 = datetime.now() + logger.warn('time to get image: %s' % (t2 - t1)) + t1 = t2 if i: t = i.simpleMarshal(xtra=xtra) t['wellId'] = e.getId() t['field'] = field tr.append(t) + t2 = datetime.now() + logger.debug('time to marshal image: %s' % (t2 - t1)) + t1 = t2 continue tr.append(None) grid.append(tr) + t1 = datetime.now() + logger.debug('time to get wells in grid: %s' % (t1 - t0)) + t0 = t1 rv = {'grid': grid, 'collabels': plate.getColumnLabels(), 'rowlabels': plate.getRowLabels()} From bff4f45bbd83046b0f1790c8607ac1079336059f Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Tue, 7 Apr 2015 19:44:07 +0300 Subject: [PATCH 02/27] Add a full-stack integration test for plateGrid_json This test goes through the full Django stack. Further tests will be more focused. --- .../test/integration/test_plate_grid.py | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 components/tools/OmeroWeb/test/integration/test_plate_grid.py diff --git a/components/tools/OmeroWeb/test/integration/test_plate_grid.py b/components/tools/OmeroWeb/test/integration/test_plate_grid.py new file mode 100644 index 00000000000..5247ba9555c --- /dev/null +++ b/components/tools/OmeroWeb/test/integration/test_plate_grid.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2015 Glencoe Software, Inc. +# All rights reserved. +# +# Use is subject to license terms supplied in LICENSE.txt + +""" + Integration tests for the "plategrid" module. +""" + +import pytest +import test.integration.library as lib + +from omero.model import PlateI, WellI, WellSampleI +from omero.rtypes import rint, rstring +from omero.gateway import BlitzGateway + +from django.test import Client +from django.core.urlresolvers import reverse +import json + + +@pytest.fixture(scope='function') +def itest(request): + """ + Returns a new L{test.integration.library.ITest} instance. With attached + finalizer so that pytest will clean it up. + """ + o = lib.ITest() + o.setup_method(None) + + def finalizer(): + o.teardown_method(None) + request.addfinalizer(finalizer) + return o + + +@pytest.fixture(scope='function') +def client(request, itest): + """Returns a new user client.""" + return itest.new_client() + + +@pytest.fixture(scope='function') +def conn(request, client): + """Returns a new OMERO gateway.""" + return BlitzGateway(client_obj=client) + + +@pytest.fixture(scope='function') +def update_service(request, client): + """Returns a new OMERO update service.""" + return client.getSession().getUpdateService() + + +@pytest.fixture(scope='function') +def plate_wells(request, itest, update_service): + """ + Returns a new OMERO Plate, linked Wells, linked WellSamples, and linked + Images populated by an L{test.integration.library.ITest} instance. + """ + plate = PlateI() + plate.name = rstring(itest.uuid()) + # Well A10 (will have two WellSamples) + well_a = WellI() + well_a.row = rint(0) + well_a.column = rint(9) + # Well A11 (will not have a WellSample) + well_b = WellI() + well_b.row = rint(0) + well_b.column = rint(10) + # Well D3 (will have one WellSample) + well_c = WellI() + well_c.row = rint(3) + well_c.column = rint(2) + ws_a = WellSampleI() + image_a = itest.new_image(name=itest.uuid()) + ws_a.image = image_a + ws_b = WellSampleI() + image_b = itest.new_image(name=itest.uuid()) + ws_b.image = image_b + ws_c = WellSampleI() + image_c = itest.new_image(name=itest.uuid()) + ws_c.image = image_c + well_a.addWellSample(ws_a) + well_a.addWellSample(ws_b) + well_c.addWellSample(ws_c) + plate.addWell(well_a) + plate.addWell(well_b) + plate.addWell(well_c) + return update_service.saveAndReturnObject(plate) + + +@pytest.fixture(scope='function') +def django_client(request, client): + """Returns a logged in Django test client.""" + django_client = Client() + login_url = reverse('weblogin') + + response = django_client.get(login_url) + assert response.status_code == 200 + + data = { + 'server': 1, + 'username': client.getProperty('omero.user'), + 'password': client.getProperty('omero.pass'), + } + response = django_client.post(login_url, data) + assert response.status_code == 302 + + def finalizer(): + logout_url = reverse('weblogout') + response = django_client.post(logout_url, data=data) + assert response.status_code == 302 + request.addfinalizer(finalizer) + return django_client + + +class TestPlateGrid(object): + """ + Tests to ensure that the OMERO.web "plategrid" functionality works as + expected. + """ + + def test_get_plate_grid_metadata(self, django_client, plate_wells, conn): + """ + Do a simple GET request to retrieve the metadata for a plate in JSON + form + """ + for field in range(2): + request_url = reverse('webgateway_plategrid_json', + args=(plate_wells.id.val, field)) + + response = django_client.get(request_url) + assert response.status_code == 200 + + plate_metadata = json.loads(response.content) + assert len(plate_metadata['rowlabels']) == 8 + assert len(plate_metadata['collabels']) == 12 + + grid = plate_metadata['grid'] + for well in plate_wells.copyWells(): + well_metadata = grid[well.row.val][well.column.val] + well_samples = well.copyWellSamples() + if len(well_samples) > field: + assert well_metadata['name'] ==\ + well_samples[field].getImage().name.val From d71736f1b2fc83cdb17651499cd657f410e71cfd Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Wed, 8 Apr 2015 11:01:53 +0300 Subject: [PATCH 03/27] Use optimized query for `getGridSize` --- .../tools/OmeroPy/src/omero/gateway/__init__.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 102ed7c2070..f55b806b2b1 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -5603,10 +5603,15 @@ def getGridSize(self): :rtype: dict of {'rows': rSize, 'columns':cSize} """ if self._gridSize is None: - r, c = 0, 0 - for child in self._listChildren(): - r, c = max(child.row.val, r), max(child.column.val, c) - self._gridSize = {'rows': r+1, 'columns': c+1} + q = self._conn.getQueryService() + params = omero.sys.Parameters() + params.map = {} + params.map['pid'] = omero_type(self.getId()) + query = "select max(row), max(column) from Well"\ + "where plate.id = :pid" + res = q.projection(query, params, self._conn.SERVICE_OPTS) + (row, col) = res[0] + self._gridSize = {'rows': row.val+1, 'columns': col.val+1} return self._gridSize def getWellGrid(self, index=0): From 19b8440f410ad18a91ce140336ff7d4a8b5540ab Mon Sep 17 00:00:00 2001 From: Chris Allan Date: Wed, 8 Apr 2015 01:58:50 -0700 Subject: [PATCH 04/27] Add specific integration test package for the plate wrapper --- .../gatewaytest/test_plate_wrapper.py | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py diff --git a/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py b/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py new file mode 100644 index 00000000000..b1f166907df --- /dev/null +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# +# Copyright (C) 2013 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 - Testing the gateway plate wrapper + + pytest fixtures used as defined in conftest.py: + - gatewaywrapper + +""" + +import pytest + +from omero.model import PlateI, WellI, WellSampleI, ImageI +from omero.rtypes import rstring, rint, rtime +from uuid import uuid4 + + +def uuid(): + return str(uuid4()) + + +@pytest.fixture() +def plate(request, gatewaywrapper): + """Creates a Plate.""" + gatewaywrapper.loginAsAuthor() + gw = gatewaywrapper.gateway + update_service = gw.getUpdateService() + plate = PlateI() + plate.name = rstring(uuid()) + for well_index in range(3): + well = WellI() + well.row = rint(well_index**2) + well.column = rint(well_index**3) + for well_sample_index in range(2): + well_sample = WellSampleI() + image = ImageI() + image.name = rstring('%s_%d' % (uuid(), well_sample_index)) + image.acquisitionDate = rtime(0) + well_sample.image = image + well.addWellSample(well_sample) + plate.addWell(well) + plate_id, = update_service.saveAndReturnIds([plate]) + return gw.getObject('Plate', plate_id) + + +class TestPlateWrapper(object): + + def testGetGridSize(self, gatewaywrapper, plate): + assert plate.getGridSize() == {'rows': 5L, 'columns': 9L} From 898a044ee4ff0c00d9e34d49d9ce00a4777e1051 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Fri, 10 Apr 2015 17:33:54 +0300 Subject: [PATCH 05/27] Split plate grid metadata into a separate class --- .../OmeroPy/src/omero/gateway/__init__.py | 2 +- .../OmeroWeb/omeroweb/webgateway/plategrid.py | 73 +++++++++++++++++++ .../OmeroWeb/omeroweb/webgateway/views.py | 56 ++------------ 3 files changed, 81 insertions(+), 50 deletions(-) create mode 100644 components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index f55b806b2b1..7ba63fa87aa 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -5607,7 +5607,7 @@ def getGridSize(self): params = omero.sys.Parameters() params.map = {} params.map['pid'] = omero_type(self.getId()) - query = "select max(row), max(column) from Well"\ + query = "select max(row), max(column) from Well "\ "where plate.id = :pid" res = q.projection(query, params, self._conn.SERVICE_OPTS) (row, col) = res[0] diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py new file mode 100644 index 00000000000..a123c18c8a8 --- /dev/null +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2015 Glencoe Software, Inc. +# All rights reserved. +# +# Use is subject to license terms supplied in LICENSE.txt + +""" + Module to encapsulate operations concerned with displaying the contents of a + plate as a grid. +""" + +import logging +from datetime import datetime + +logger = logging.getLogger(__name__) + + +class PlateGrid(object): + """ + A PlateGrid object encapsulates a PlateI reference and provides a number of + methods useful for displaying the contents of the plate as a grid. + """ + + def __init__(self, conn, pid, fid, xtra): + t0 = datetime.now() + self.plate = conn.getObject('plate', long(pid)) + t1 = datetime.now() + logger.debug('time to get plate: %s' % (t1 - t0)) + self.field = fid + self.xtra = xtra + self._metadata = None + + @property + def metadata(self): + if self._metadata is None: + t0 = datetime.now() + self.plate.setGridSizeConstraints(8, 12) + t1 = datetime.now() + logger.debug('time to set grid constraints: %s' % (t1 - t0)) + t0 = t1 + + grid = [] + wellGrid = self.plate.getWellGrid(self.field) + t1 = datetime.now() + logger.debug('time to get well grid: %s' % (t1 - t0)) + t0 = t1 + for row in wellGrid: + tr = [] + for e in row: + if e: + i = e.getImage() + t2 = datetime.now() + logger.warn('time to get image: %s' % (t2 - t1)) + t1 = t2 + if i: + t = i.simpleMarshal(xtra=self.xtra) + t['wellId'] = e.getId() + t['field'] = self.field + tr.append(t) + t2 = datetime.now() + logger.debug( + 'time to marshal image: %s' % (t2 - t1)) + t1 = t2 + continue + tr.append(None) + grid.append(tr) + t1 = datetime.now() + logger.debug('time to get wells in grid: %s' % (t1 - t0)) + self._metadata = {'grid': grid, + 'collabels': self.plate.getColumnLabels(), + 'rowlabels': self.plate.getRowLabels()} + return self._metadata diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/views.py b/components/tools/OmeroWeb/omeroweb/webgateway/views.py index ddec29eb522..e5917091274 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/views.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/views.py @@ -29,6 +29,7 @@ from django.core.servers.basehttp import FileWrapper from omero.rtypes import rlong, unwrap from omero.constants.namespaces import NSBULKANNOTATIONS +from omeroweb.webgateway.plategrid import PlateGrid from omero_version import build_year from marshal import imageMarshal, shapeMarshal @@ -1329,71 +1330,28 @@ def urlprefix(iid): def plateGrid_json(request, pid, field=0, conn=None, **kwargs): """ """ - t0 = datetime.now() - plate = conn.getObject('plate', long(pid)) - t1 = datetime.now() - logger.debug('time to get plate: %s' % (t1 - t0)) - t0 = t1 try: field = long(field or 0) except ValueError: field = 0 - if plate is None: - return HttpJavascriptResponseServerError('""') - grid = [] prefix = kwargs.get('thumbprefix', 'webgateway.views.render_thumbnail') thumbsize = int(request.REQUEST.get('size', 64)) logger.debug(thumbsize) + server_id = kwargs['server_id'] def urlprefix(iid): return reverse(prefix, args=(iid, thumbsize)) xtra = {'thumbUrlPrefix': kwargs.get('urlprefix', urlprefix)} - server_id = kwargs['server_id'] - t1 = datetime.now() - logger.debug('time to get thumbnail URL prefix: %s' % (t1 - t0)) - t0 = t1 + plateGrid = PlateGrid(conn, pid, field, xtra) + plate = plateGrid.plate + if plate is None: + return Http404 rv = webgateway_cache.getJson(request, server_id, plate, 'plategrid-%d-%d' % (field, thumbsize)) if rv is None: - t1 = datetime.now() - logger.debug('time to check cache miss: %s' % (t1 - t0)) - t0 = t1 - - plate.setGridSizeConstraints(8, 12) - t1 = datetime.now() - logger.debug('time to set grid constraints: %s' % (t1 - t0)) - t0 = t1 - t0 = t1 - wellGrid = plate.getWellGrid(field) - t1 = datetime.now() - logger.debug('time to get well grid: %s' % (t1 - t0)) - for row in wellGrid: - tr = [] - for e in row: - if e: - i = e.getImage() - t2 = datetime.now() - logger.warn('time to get image: %s' % (t2 - t1)) - t1 = t2 - if i: - t = i.simpleMarshal(xtra=xtra) - t['wellId'] = e.getId() - t['field'] = field - tr.append(t) - t2 = datetime.now() - logger.debug('time to marshal image: %s' % (t2 - t1)) - t1 = t2 - continue - tr.append(None) - grid.append(tr) - t1 = datetime.now() - logger.debug('time to get wells in grid: %s' % (t1 - t0)) - t0 = t1 - rv = {'grid': grid, - 'collabels': plate.getColumnLabels(), - 'rowlabels': plate.getRowLabels()} + rv = plateGrid.metadata webgateway_cache.setJson(request, server_id, plate, json.dumps(rv), 'plategrid-%d-%d' % (field, thumbsize)) else: From 1d81804eeac3c5811d26c14e616f2bc45347ce69 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Tue, 14 Apr 2015 08:56:18 +0300 Subject: [PATCH 06/27] Additional tests for PlateGrid helper --- .../{test_plate_grid.py => test_plategrid.py} | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) rename components/tools/OmeroWeb/test/integration/{test_plate_grid.py => test_plategrid.py} (76%) diff --git a/components/tools/OmeroWeb/test/integration/test_plate_grid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py similarity index 76% rename from components/tools/OmeroWeb/test/integration/test_plate_grid.py rename to components/tools/OmeroWeb/test/integration/test_plategrid.py index 5247ba9555c..4421eae48ca 100644 --- a/components/tools/OmeroWeb/test/integration/test_plate_grid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -15,6 +15,7 @@ from omero.model import PlateI, WellI, WellSampleI from omero.rtypes import rint, rstring from omero.gateway import BlitzGateway +from omeroweb.webgateway.plategrid import PlateGrid from django.test import Client from django.core.urlresolvers import reverse @@ -146,3 +147,35 @@ def test_get_plate_grid_metadata(self, django_client, plate_wells, conn): if len(well_samples) > field: assert well_metadata['name'] ==\ well_samples[field].getImage().name.val + + def test_instantiation(self, plate_wells, conn): + """ + Check that the helper object can be created + """ + xtra = {'key': 'value'} + plateGrid = PlateGrid(conn, plate_wells.id.val, 0, xtra) + assert plateGrid + assert plateGrid.plate.id == plate_wells.id.val + assert plateGrid.field == 0 + assert plateGrid.xtra == xtra + + def test_metadata_grid_size(self, plate_wells, conn): + """ + Check that the grid represented in the metadata is the correct size + """ + plateGrid = PlateGrid(conn, plate_wells.id.val, 0, {}) + assert len(plateGrid.metadata['grid']) == 8 + assert len(plateGrid.metadata['grid'][0]) == 12 + + def test_metadata_thumbnail_url(self, plate_wells, conn): + """ + Check that extra elements of the thumbnail URL passed in the `xtra` + dictionary are properly prepended + """ + xtra = {'thumbUrlPrefix': 'foo/bar/'} + plateGrid = PlateGrid(conn, plate_wells.id.val, 0, xtra) + metadata = plateGrid.metadata + for well in plate_wells.copyWells(): + well_metadata = metadata['grid'][well.row.val][well.column.val] + if well_metadata: + assert well_metadata['thumb_url'].startswith('foo/bar/') From 75a294799758365b90bf77fb328b2cc6fe555e31 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Tue, 14 Apr 2015 18:50:38 +0300 Subject: [PATCH 07/27] No need for a dict when there's only one value to pass --- components/tools/OmeroWeb/omeroweb/webgateway/views.py | 5 ++--- .../tools/OmeroWeb/test/integration/test_plategrid.py | 9 +++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/views.py b/components/tools/OmeroWeb/omeroweb/webgateway/views.py index e5917091274..330537c6972 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/views.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/views.py @@ -1341,9 +1341,8 @@ def plateGrid_json(request, pid, field=0, conn=None, **kwargs): def urlprefix(iid): return reverse(prefix, args=(iid, thumbsize)) - xtra = {'thumbUrlPrefix': kwargs.get('urlprefix', urlprefix)} - - plateGrid = PlateGrid(conn, pid, field, xtra) + plateGrid = PlateGrid(conn, pid, field, + kwargs.get('urlprefix', urlprefix)) plate = plateGrid.plate if plate is None: return Http404 diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index 4421eae48ca..3445fd7087a 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -152,18 +152,16 @@ def test_instantiation(self, plate_wells, conn): """ Check that the helper object can be created """ - xtra = {'key': 'value'} - plateGrid = PlateGrid(conn, plate_wells.id.val, 0, xtra) + plateGrid = PlateGrid(conn, plate_wells.id.val, 0) assert plateGrid assert plateGrid.plate.id == plate_wells.id.val assert plateGrid.field == 0 - assert plateGrid.xtra == xtra def test_metadata_grid_size(self, plate_wells, conn): """ Check that the grid represented in the metadata is the correct size """ - plateGrid = PlateGrid(conn, plate_wells.id.val, 0, {}) + plateGrid = PlateGrid(conn, plate_wells.id.val, 0) assert len(plateGrid.metadata['grid']) == 8 assert len(plateGrid.metadata['grid'][0]) == 12 @@ -172,8 +170,7 @@ def test_metadata_thumbnail_url(self, plate_wells, conn): Check that extra elements of the thumbnail URL passed in the `xtra` dictionary are properly prepended """ - xtra = {'thumbUrlPrefix': 'foo/bar/'} - plateGrid = PlateGrid(conn, plate_wells.id.val, 0, xtra) + plateGrid = PlateGrid(conn, plate_wells.id.val, 0, 'foo/bar/') metadata = plateGrid.metadata for well in plate_wells.copyWells(): well_metadata = metadata['grid'][well.row.val][well.column.val] From 3f90a425774c2887fa340f8fc10400177c68e0c1 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Tue, 14 Apr 2015 18:51:21 +0300 Subject: [PATCH 08/27] Optimize metadata retrieval with a query --- .../OmeroWeb/omeroweb/webgateway/plategrid.py | 88 ++++++++++++------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index a123c18c8a8..27a205005c2 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -11,7 +11,11 @@ """ import logging -from datetime import datetime +from datetime import datetime as dt +import time + +import omero.sys +from omero.rtypes import rint, rlong logger = logging.getLogger(__name__) @@ -22,50 +26,72 @@ class PlateGrid(object): methods useful for displaying the contents of the plate as a grid. """ - def __init__(self, conn, pid, fid, xtra): - t0 = datetime.now() + def __init__(self, conn, pid, fid, thumbprefix=''): + t0 = dt.now() self.plate = conn.getObject('plate', long(pid)) - t1 = datetime.now() + t1 = dt.now() logger.debug('time to get plate: %s' % (t1 - t0)) + self._conn = conn self.field = fid - self.xtra = xtra + self._thumbprefix = thumbprefix self._metadata = None @property def metadata(self): if self._metadata is None: - t0 = datetime.now() + t0 = dt.now() self.plate.setGridSizeConstraints(8, 12) - t1 = datetime.now() + t1 = dt.now() logger.debug('time to set grid constraints: %s' % (t1 - t0)) t0 = t1 - grid = [] - wellGrid = self.plate.getWellGrid(self.field) - t1 = datetime.now() + size = self.plate.getGridSize() + grid = [[None] * size['columns']] * size['rows'] + + q = self._conn.getQueryService() + params = omero.sys.Parameters() + params.map = {'pid': rlong(self.plate.id), + 'wsidx': rint(self.field)} + query = ' '.join([ + "select well.row, well.column,", # Grid index + "img.id,", # 'id' + "img.name,", # 'name' + "img.details.owner.firstName||' '", + "||img.details.owner.lastName,", # 'author' + "well.id,", # 'wellId' + "img.acquisitionDate", # 'date' + "from Well well", + "join well.wellSamples ws", + "join ws.image img", + "where well.plate.id = :pid", # plate ID + "and index(ws) = :wsidx" # field + ]) + + wellGrid = q.projection(query, params, self._conn.SERVICE_OPTS) + t1 = dt.now() logger.debug('time to get well grid: %s' % (t1 - t0)) t0 = t1 - for row in wellGrid: - tr = [] - for e in row: - if e: - i = e.getImage() - t2 = datetime.now() - logger.warn('time to get image: %s' % (t2 - t1)) - t1 = t2 - if i: - t = i.simpleMarshal(xtra=self.xtra) - t['wellId'] = e.getId() - t['field'] = self.field - tr.append(t) - t2 = datetime.now() - logger.debug( - 'time to marshal image: %s' % (t2 - t1)) - t1 = t2 - continue - tr.append(None) - grid.append(tr) - t1 = datetime.now() + maxplanesize = self._conn.getMaxPlaneSize() + tiledsize = maxplanesize[0] * maxplanesize[1] + for w in wellGrid: + gridRow = w[0].val + gridCol = w[1].val + wellmeta = {'type': 'Image', + 'id': w[2].val, + 'name': w[3].val, + 'author': w[4].val, + 'wellId': w[5].val, + 'field': self.field} + + date = dt.fromtimestamp(w[6].val / 1000) + wellmeta['date'] = time.mktime(date.timetuple()) + if callable(self._thumbprefix): + wellmeta['thumb_url'] = self._thumbprefix(str(w[2].val)) + else: + wellmeta['thumb_url'] = self._thumbprefix + str(w[2].val) + + grid[gridRow][gridCol] = wellmeta + t1 = dt.now() logger.debug('time to get wells in grid: %s' % (t1 - t0)) self._metadata = {'grid': grid, 'collabels': self.plate.getColumnLabels(), From edfd52515ab22f69f5b5828872b6d04d96506ad8 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Tue, 14 Apr 2015 19:11:21 +0300 Subject: [PATCH 09/27] Remove debugging logs --- .../OmeroWeb/omeroweb/webgateway/plategrid.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index 27a205005c2..423d2bae5c3 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -27,10 +27,7 @@ class PlateGrid(object): """ def __init__(self, conn, pid, fid, thumbprefix=''): - t0 = dt.now() self.plate = conn.getObject('plate', long(pid)) - t1 = dt.now() - logger.debug('time to get plate: %s' % (t1 - t0)) self._conn = conn self.field = fid self._thumbprefix = thumbprefix @@ -39,12 +36,7 @@ def __init__(self, conn, pid, fid, thumbprefix=''): @property def metadata(self): if self._metadata is None: - t0 = dt.now() self.plate.setGridSizeConstraints(8, 12) - t1 = dt.now() - logger.debug('time to set grid constraints: %s' % (t1 - t0)) - t0 = t1 - size = self.plate.getGridSize() grid = [[None] * size['columns']] * size['rows'] @@ -68,11 +60,6 @@ def metadata(self): ]) wellGrid = q.projection(query, params, self._conn.SERVICE_OPTS) - t1 = dt.now() - logger.debug('time to get well grid: %s' % (t1 - t0)) - t0 = t1 - maxplanesize = self._conn.getMaxPlaneSize() - tiledsize = maxplanesize[0] * maxplanesize[1] for w in wellGrid: gridRow = w[0].val gridCol = w[1].val @@ -91,8 +78,7 @@ def metadata(self): wellmeta['thumb_url'] = self._thumbprefix + str(w[2].val) grid[gridRow][gridCol] = wellmeta - t1 = dt.now() - logger.debug('time to get wells in grid: %s' % (t1 - t0)) + self._metadata = {'grid': grid, 'collabels': self.plate.getColumnLabels(), 'rowlabels': self.plate.getRowLabels()} From ec3fd14034ade83694be216b9e9afa4b85a14885 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Wed, 15 Apr 2015 18:48:12 +0300 Subject: [PATCH 10/27] Fix for repeated grid entries Using `*` to create the 2-D list results in shared references to the lists within the list, causing subsequent writes to conflict. Using a list comprehension instead ensures that each 2nd level list is unique. --- components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index 423d2bae5c3..46836fd1a51 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -38,7 +38,7 @@ def metadata(self): if self._metadata is None: self.plate.setGridSizeConstraints(8, 12) size = self.plate.getGridSize() - grid = [[None] * size['columns']] * size['rows'] + grid = [[None] * size['columns'] for _ in range(size['rows'])] q = self._conn.getQueryService() params = omero.sys.Parameters() From ab0921df91ea4d334ce3d78e6b81ed28a2af7a80 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Thu, 16 Apr 2015 09:20:08 +0300 Subject: [PATCH 11/27] Update copyright date --- .../OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py b/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py index b1f166907df..b0f7e3133aa 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2013 University of Dundee & Open Microscopy Environment. +# Copyright (C) 2013-2015 University of Dundee & Open Microscopy Environment. # All rights reserved. # # This program is free software; you can redistribute it and/or modify From 6b819b5c10f913d8a275dde47a96c4b36aaca157 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Thu, 16 Apr 2015 12:13:23 +0300 Subject: [PATCH 12/27] Use string concatenation instead of joining an array --- .../OmeroWeb/omeroweb/webgateway/plategrid.py | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index 46836fd1a51..e48cb72e038 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -44,20 +44,15 @@ def metadata(self): params = omero.sys.Parameters() params.map = {'pid': rlong(self.plate.id), 'wsidx': rint(self.field)} - query = ' '.join([ - "select well.row, well.column,", # Grid index - "img.id,", # 'id' - "img.name,", # 'name' - "img.details.owner.firstName||' '", - "||img.details.owner.lastName,", # 'author' - "well.id,", # 'wellId' - "img.acquisitionDate", # 'date' - "from Well well", - "join well.wellSamples ws", - "join ws.image img", - "where well.plate.id = :pid", # plate ID - "and index(ws) = :wsidx" # field - ]) + query = "select well.row, well.column, img.id, img.name, "\ + "author.firstName||' '||author.lastName, "\ + "well.id, img.acquisitionDate "\ + "from Well well "\ + "join well.wellSamples ws "\ + "join ws.image img "\ + "join img.details.owner author "\ + "where well.plate.id = :id "\ + "and index(ws) = :wsidx" wellGrid = q.projection(query, params, self._conn.SERVICE_OPTS) for w in wellGrid: From f67bb7bb90ae0a5785016610657328e4c835bfdc Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Thu, 16 Apr 2015 12:14:04 +0300 Subject: [PATCH 13/27] Use `omero.sys.ParametersI` for queries --- components/tools/OmeroPy/src/omero/gateway/__init__.py | 7 +++---- .../tools/OmeroWeb/omeroweb/webgateway/plategrid.py | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/components/tools/OmeroPy/src/omero/gateway/__init__.py b/components/tools/OmeroPy/src/omero/gateway/__init__.py index 7ba63fa87aa..b91d46dc7b6 100644 --- a/components/tools/OmeroPy/src/omero/gateway/__init__.py +++ b/components/tools/OmeroPy/src/omero/gateway/__init__.py @@ -5604,11 +5604,10 @@ def getGridSize(self): """ if self._gridSize is None: q = self._conn.getQueryService() - params = omero.sys.Parameters() - params.map = {} - params.map['pid'] = omero_type(self.getId()) + params = omero.sys.ParametersI() + params.addId(self.getId()) query = "select max(row), max(column) from Well "\ - "where plate.id = :pid" + "where plate.id = :id" res = q.projection(query, params, self._conn.SERVICE_OPTS) (row, col) = res[0] self._gridSize = {'rows': row.val+1, 'columns': col.val+1} diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index e48cb72e038..b2e3e37116f 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -15,7 +15,7 @@ import time import omero.sys -from omero.rtypes import rint, rlong +from omero.rtypes import rint logger = logging.getLogger(__name__) @@ -41,9 +41,9 @@ def metadata(self): grid = [[None] * size['columns'] for _ in range(size['rows'])] q = self._conn.getQueryService() - params = omero.sys.Parameters() - params.map = {'pid': rlong(self.plate.id), - 'wsidx': rint(self.field)} + params = omero.sys.ParametersI() + params.addId(self.plate.id) + params.add('wsidx', rint(self.field)) query = "select well.row, well.column, img.id, img.name, "\ "author.firstName||' '||author.lastName, "\ "well.id, img.acquisitionDate "\ From b3b64e49ee7d0461b4ed2f2389350e5925f795af Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Thu, 16 Apr 2015 13:48:30 +0300 Subject: [PATCH 14/27] Destructure row at a time for grid --- .../OmeroWeb/omeroweb/webgateway/plategrid.py | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index b2e3e37116f..7619e4ff5b8 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -54,25 +54,22 @@ def metadata(self): "where well.plate.id = :id "\ "and index(ws) = :wsidx" - wellGrid = q.projection(query, params, self._conn.SERVICE_OPTS) - for w in wellGrid: - gridRow = w[0].val - gridCol = w[1].val + for res in q.projection(query, params, self._conn.SERVICE_OPTS): + row, col, img_id, img_name, author, well_id, time = res wellmeta = {'type': 'Image', - 'id': w[2].val, - 'name': w[3].val, - 'author': w[4].val, - 'wellId': w[5].val, + 'id': img_id.val, + 'name': img_name.val, + 'author': author.val, + 'date': time.val / 1000, + 'wellId': well_id.val, 'field': self.field} - date = dt.fromtimestamp(w[6].val / 1000) - wellmeta['date'] = time.mktime(date.timetuple()) if callable(self._thumbprefix): - wellmeta['thumb_url'] = self._thumbprefix(str(w[2].val)) + wellmeta['thumb_url'] = self._thumbprefix(str(img_id.val)) else: - wellmeta['thumb_url'] = self._thumbprefix + str(w[2].val) + wellmeta['thumb_url'] = self._thumbprefix + str(img_id.val) - grid[gridRow][gridCol] = wellmeta + grid[row.val][col.val] = wellmeta self._metadata = {'grid': grid, 'collabels': self.plate.getColumnLabels(), From 87b0deaccc4de9bfff3031fdcedfc450291fceae Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Thu, 16 Apr 2015 13:55:37 +0300 Subject: [PATCH 15/27] Use relative import --- components/tools/OmeroWeb/omeroweb/webgateway/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/views.py b/components/tools/OmeroWeb/omeroweb/webgateway/views.py index 330537c6972..9e750fc610a 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/views.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/views.py @@ -29,7 +29,7 @@ from django.core.servers.basehttp import FileWrapper from omero.rtypes import rlong, unwrap from omero.constants.namespaces import NSBULKANNOTATIONS -from omeroweb.webgateway.plategrid import PlateGrid +from plategrid import PlateGrid from omero_version import build_year from marshal import imageMarshal, shapeMarshal From b5bbe7753bf7bbd06722010c6622381423be4327 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Mon, 20 Apr 2015 09:17:38 +0300 Subject: [PATCH 16/27] Add test for a full plate grid --- .../test/integration/test_plategrid.py | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index 3445fd7087a..b86d54573a0 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -93,6 +93,28 @@ def plate_wells(request, itest, update_service): return update_service.saveAndReturnObject(plate) +@pytest.fixture(scope='function') +def full_plate_wells(request, itest, update_service): + """ + Returns a full OMERO Plate, linked Wells, linked WellSamples, and linked + Images populated by an L{test.integration.library.ITest} instance. + """ + lett = map(chr, range(ord('A'), ord('Z')+1)) + plate = PlateI() + plate.name = rstring(itest.uuid()) + for row in range(8): + for column in range(12): + well = WellI() + well.row = rint(row) + well.column = rint(column) + ws = WellSampleI() + image = itest.new_image(name=lett[row]+str(column)) + ws.image = image + well.addWellSample(ws) + plate.addWell(well) + return update_service.saveAndReturnObject(plate) + + @pytest.fixture(scope='function') def django_client(request, client): """Returns a logged in Django test client.""" @@ -152,27 +174,40 @@ def test_instantiation(self, plate_wells, conn): """ Check that the helper object can be created """ - plateGrid = PlateGrid(conn, plate_wells.id.val, 0) - assert plateGrid - assert plateGrid.plate.id == plate_wells.id.val - assert plateGrid.field == 0 + plate_grid = PlateGrid(conn, plate_wells.id.val, 0) + assert plate_grid + assert plate_grid.plate.id == plate_wells.id.val + assert plate_grid.field == 0 def test_metadata_grid_size(self, plate_wells, conn): """ Check that the grid represented in the metadata is the correct size """ - plateGrid = PlateGrid(conn, plate_wells.id.val, 0) - assert len(plateGrid.metadata['grid']) == 8 - assert len(plateGrid.metadata['grid'][0]) == 12 + plate_grid = PlateGrid(conn, plate_wells.id.val, 0) + assert len(plate_grid.metadata['grid']) == 8 + assert len(plate_grid.metadata['grid'][0]) == 12 def test_metadata_thumbnail_url(self, plate_wells, conn): """ Check that extra elements of the thumbnail URL passed in the `xtra` dictionary are properly prepended """ - plateGrid = PlateGrid(conn, plate_wells.id.val, 0, 'foo/bar/') - metadata = plateGrid.metadata + plate_grid = PlateGrid(conn, plate_wells.id.val, 0, 'foo/bar/') + metadata = plate_grid.metadata for well in plate_wells.copyWells(): well_metadata = metadata['grid'][well.row.val][well.column.val] if well_metadata: assert well_metadata['thumb_url'].startswith('foo/bar/') + + def test_full_grid(self, full_plate_wells, conn): + """ + Check that all wells are assigned correctly even if the entire plate of + wells is full + """ + lett = map(chr, range(ord('A'), ord('Z')+1)) + plate_grid = PlateGrid(conn, full_plate_wells.id.val, 0) + metadata = plate_grid.metadata + for row in range(8): + for column in range(12): + assert metadata['grid'][row][column]['name'] ==\ + lett[row]+str(column) From e303e0b40627f9ffc554fa79f43188334f4bf90b Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Thu, 23 Apr 2015 18:11:38 +0300 Subject: [PATCH 17/27] Refactor tests This introduces factory methods for well samples, wells, and well grids to clean up some of the bigger fixtures. --- .../test/integration/test_plategrid.py | 80 +++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index b86d54573a0..f46134382bd 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -38,63 +38,79 @@ def finalizer(): @pytest.fixture(scope='function') -def client(request, itest): +def client(itest): """Returns a new user client.""" return itest.new_client() @pytest.fixture(scope='function') -def conn(request, client): +def conn(client): """Returns a new OMERO gateway.""" return BlitzGateway(client_obj=client) @pytest.fixture(scope='function') -def update_service(request, client): +def update_service(client): """Returns a new OMERO update service.""" return client.getSession().getUpdateService() @pytest.fixture(scope='function') -def plate_wells(request, itest, update_service): +def well_sample_factory(itest): + + def make_well_sample(): + ws = WellSampleI() + image = itest.new_image(name=itest.uuid()) + ws.image = image + return ws + return make_well_sample + + +@pytest.fixture(scope='function') +def well_factory(well_sample_factory): + + def make_well(ws_count=0): + well = WellI() + for _ in range(ws_count): + well.addWellSample(well_sample_factory()) + return well + return make_well + + +@pytest.fixture(scope='function') +def well_grid_factory(well_factory): + + def make_well_grid(grid_layout={}): + wells = [] + for row, column in grid_layout: + ws_count = grid_layout[(row, column)] + well = well_factory(ws_count) + well.row = rint(row) + well.column = rint(column) + wells.append(well) + return wells + return make_well_grid + + +@pytest.fixture(scope='function') +def plate_wells(itest, well_grid_factory, update_service): """ Returns a new OMERO Plate, linked Wells, linked WellSamples, and linked Images populated by an L{test.integration.library.ITest} instance. """ plate = PlateI() plate.name = rstring(itest.uuid()) - # Well A10 (will have two WellSamples) - well_a = WellI() - well_a.row = rint(0) - well_a.column = rint(9) - # Well A11 (will not have a WellSample) - well_b = WellI() - well_b.row = rint(0) - well_b.column = rint(10) - # Well D3 (will have one WellSample) - well_c = WellI() - well_c.row = rint(3) - well_c.column = rint(2) - ws_a = WellSampleI() - image_a = itest.new_image(name=itest.uuid()) - ws_a.image = image_a - ws_b = WellSampleI() - image_b = itest.new_image(name=itest.uuid()) - ws_b.image = image_b - ws_c = WellSampleI() - image_c = itest.new_image(name=itest.uuid()) - ws_c.image = image_c - well_a.addWellSample(ws_a) - well_a.addWellSample(ws_b) - well_c.addWellSample(ws_c) - plate.addWell(well_a) - plate.addWell(well_b) - plate.addWell(well_c) + # Well A10 has two WellSamples + # Well A11 has no WellSamples + # Well D3 has one WellSample + wells = well_grid_factory({(0, 9): 2, (0, 10): 0, (3, 2): 1}) + for well in wells: + plate.addWell(well) return update_service.saveAndReturnObject(plate) @pytest.fixture(scope='function') -def full_plate_wells(request, itest, update_service): +def full_plate_wells(itest, update_service): """ Returns a full OMERO Plate, linked Wells, linked WellSamples, and linked Images populated by an L{test.integration.library.ITest} instance. From 15b61d981503d26c122624e9b0c76c92c946d7a8 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Thu, 23 Apr 2015 18:14:43 +0300 Subject: [PATCH 18/27] Add logic to fall back to image creationEvent date This adds logic that will use the time of an image's creationEvent if the acquisition date of the image is either not set or set to an invalid value (e.g. 0). --- .../OmeroWeb/omeroweb/webgateway/plategrid.py | 15 +++-- .../test/integration/test_plategrid.py | 63 ++++++++++++++++++- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index 7619e4ff5b8..55f4dd200a9 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -11,7 +11,6 @@ """ import logging -from datetime import datetime as dt import time import omero.sys @@ -46,7 +45,8 @@ def metadata(self): params.add('wsidx', rint(self.field)) query = "select well.row, well.column, img.id, img.name, "\ "author.firstName||' '||author.lastName, "\ - "well.id, img.acquisitionDate "\ + "well.id, img.acquisitionDate, "\ + "img.details.creationEvent.time "\ "from Well well "\ "join well.wellSamples ws "\ "join ws.image img "\ @@ -55,12 +55,19 @@ def metadata(self): "and index(ws) = :wsidx" for res in q.projection(query, params, self._conn.SERVICE_OPTS): - row, col, img_id, img_name, author, well_id, time = res + row, col, img_id, img_name, author, well_id, acq_date, \ + create_date = res + + if acq_date.val is not None and acq_date.val > 0: + date = acq_date.val / 1000 + else: + date = create_date.val / 1000 + wellmeta = {'type': 'Image', 'id': img_id.val, 'name': img_name.val, 'author': author.val, - 'date': time.val / 1000, + 'date': date, 'wellId': well_id.val, 'field': self.field} diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index f46134382bd..ba21691cccd 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -13,13 +13,14 @@ import test.integration.library as lib from omero.model import PlateI, WellI, WellSampleI -from omero.rtypes import rint, rstring +from omero.rtypes import rint, rstring, rtime from omero.gateway import BlitzGateway from omeroweb.webgateway.plategrid import PlateGrid from django.test import Client from django.core.urlresolvers import reverse import json +import time @pytest.fixture(scope='function') @@ -131,6 +132,44 @@ def full_plate_wells(itest, update_service): return update_service.saveAndReturnObject(plate) +@pytest.fixture(scope='function') +def plate_wells_with_acq_date(itest, well_grid_factory, update_service): + """ + Creates a plate with a single well containing an image with both an + acquisition date set as well as a creation event with a date. Returns the + plate and the acquisition date in a map. + """ + acq_date = (time.time() - 60 * 60 * 24) * 1000 + plate = PlateI() + plate.name = rstring(itest.uuid()) + # Simple grid: one well with one image + [well] = well_grid_factory({(0, 0): 1}) + well.copyWellSamples()[0].image.acquisitionDate = rtime(int(acq_date)) + plate.addWell(well) + plate = update_service.saveAndReturnObject(plate) + return {'plate': plate, + 'acq_date': int(acq_date / 1000)} + + +@pytest.fixture(scope='function') +def plate_wells_with_no_acq_date(itest, well_grid_factory, update_service, + conn): + """ + Creates a plate with a single well containing an image with no acquisition + date set. Returns the plate and the time from the creation event in a map. + """ + plate = PlateI() + plate.name = rstring(itest.uuid()) + # Simple grid: one well with one image + [well] = well_grid_factory({(0, 0): 1}) + plate.addWell(well) + well = update_service.saveAndReturnObject(well) + creation_date = well.copyWellSamples()[0].image.details.creationEvent.time + plate = update_service.saveAndReturnObject(plate) + return {'plate': plate, + 'creation_date': creation_date.val / 1000} + + @pytest.fixture(scope='function') def django_client(request, client): """Returns a logged in Django test client.""" @@ -227,3 +266,25 @@ def test_full_grid(self, full_plate_wells, conn): for column in range(12): assert metadata['grid'][row][column]['name'] ==\ lett[row]+str(column) + + def test_acquisition_date(self, plate_wells_with_acq_date, conn): + """ + Check that acquisition date is used for an image in the plate if it is + specified + """ + plate = plate_wells_with_acq_date['plate'] + acq_date = plate_wells_with_acq_date['acq_date'] + plate_grid = PlateGrid(conn, plate.id.val, 0) + metadata = plate_grid.metadata + assert metadata['grid'][0][0]['date'] == acq_date + + def test_creation_date(self, plate_wells_with_no_acq_date, conn): + """ + Check that plate grid metadata falls back to using creation event time + if an image has no (or an invalid) acquistion date + """ + plate = plate_wells_with_no_acq_date['plate'] + creation_date = plate_wells_with_no_acq_date['creation_date'] + plate_grid = PlateGrid(conn, plate.id.val, 0) + metadata = plate_grid.metadata + assert metadata['grid'][0][0]['date'] == creation_date From 17ae494eb4a71ffb74503a268db91014cf4101ee Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Mon, 27 Apr 2015 15:49:45 +0300 Subject: [PATCH 19/27] Add handling of Image description --- .../OmeroWeb/omeroweb/webgateway/plategrid.py | 7 +++-- .../test/integration/test_plategrid.py | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index 55f4dd200a9..698fb367da7 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -46,7 +46,8 @@ def metadata(self): query = "select well.row, well.column, img.id, img.name, "\ "author.firstName||' '||author.lastName, "\ "well.id, img.acquisitionDate, "\ - "img.details.creationEvent.time "\ + "img.details.creationEvent.time, "\ + "img.description "\ "from Well well "\ "join well.wellSamples ws "\ "join ws.image img "\ @@ -56,16 +57,18 @@ def metadata(self): for res in q.projection(query, params, self._conn.SERVICE_OPTS): row, col, img_id, img_name, author, well_id, acq_date, \ - create_date = res + create_date, description = res if acq_date.val is not None and acq_date.val > 0: date = acq_date.val / 1000 else: date = create_date.val / 1000 + description = (description and description.val) or '' wellmeta = {'type': 'Image', 'id': img_id.val, 'name': img_name.val, + 'description': description, 'author': author.val, 'date': date, 'wellId': well_id.val, diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index ba21691cccd..53210b54ab3 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -170,6 +170,24 @@ def plate_wells_with_no_acq_date(itest, well_grid_factory, update_service, 'creation_date': creation_date.val / 1000} +@pytest.fixture(scope='function') +def plate_wells_with_description(itest, well_grid_factory, update_service): + """ + Creates a plate with a single well containing an image with a description. + Returns the plate and the description in a map. + """ + description = "test description" + plate = PlateI() + plate.name = rstring(itest.uuid()) + # Simple grid: one well with one image + [well] = well_grid_factory({(0, 0): 1}) + well.copyWellSamples()[0].image.description = rstring(description) + plate.addWell(well) + plate = update_service.saveAndReturnObject(plate) + return {'plate': plate, + 'description': description} + + @pytest.fixture(scope='function') def django_client(request, client): """Returns a logged in Django test client.""" @@ -266,6 +284,7 @@ def test_full_grid(self, full_plate_wells, conn): for column in range(12): assert metadata['grid'][row][column]['name'] ==\ lett[row]+str(column) + assert metadata['grid'][row][column]['description'] == '' def test_acquisition_date(self, plate_wells_with_acq_date, conn): """ @@ -288,3 +307,13 @@ def test_creation_date(self, plate_wells_with_no_acq_date, conn): plate_grid = PlateGrid(conn, plate.id.val, 0) metadata = plate_grid.metadata assert metadata['grid'][0][0]['date'] == creation_date + + def test_description(self, plate_wells_with_description, conn): + """ + Check that an images description is included with the grid metadata + """ + plate = plate_wells_with_description['plate'] + description = plate_wells_with_description['description'] + plate_grid = PlateGrid(conn, plate.id.val, 0) + metadata = plate_grid.metadata + assert metadata['grid'][0][0]['description'] == description From cd0c370866221308dfcaec3352d948a126a88e32 Mon Sep 17 00:00:00 2001 From: Chris Allan Date: Tue, 28 Apr 2015 14:08:12 +0100 Subject: [PATCH 20/27] Add specific integration test package for the image wrapper --- .../gatewaytest/test_image_wrapper.py | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py diff --git a/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py b/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py new file mode 100644 index 00000000000..8d74cf360a8 --- /dev/null +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# +# Copyright (C) 2013-2015 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 - Testing the gateway image wrapper + + pytest fixtures used as defined in conftest.py: + - gatewaywrapper + +""" + +import pytest + +from omero.model import ImageI +from omero.rtypes import rstring, rint, rtime +from datetime import datetime +from uuid import uuid4 + + +@pytest.fixture() +def image(request, gatewaywrapper): + """Creates an Image.""" + gatewaywrapper.loginAsAuthor() + gw = gatewaywrapper.gateway + update_service = gw.getUpdateService() + image = ImageI() + image.name = rstring('an image') + # 2015-04-21 01:15:00 + image.acquisitionDate = rtime(1429578900000L) + image_id, = update_service.saveAndReturnIds([image]) + return gw.getObject('Image', image_id) + + +@pytest.fixture() +def image_no_acquisition_date(request, gatewaywrapper): + """Creates an Image.""" + gatewaywrapper.loginAsAuthor() + gw = gatewaywrapper.gateway + update_service = gw.getUpdateService() + image = ImageI() + image.name = rstring('an image') + image.acquisitionDate = rtime(0L) + image_id, = update_service.saveAndReturnIds([image]) + return gw.getObject('Image', image_id) + + +class TestImageWrapper(object): + + def testGetDate(self, gatewaywrapper, image): + date = image.getDate() + assert date == datetime.fromtimestamp(1429578900L) + + def testGetDateNoAcquisitionDate( + self, gatewaywrapper, image_no_acquisition_date): + date = image_no_acquisition_date.getDate() + creation_event_date = image_no_acquisition_date.creationEventDate() + assert date == creation_event_date + + + def testSimpleMarshal(self, gatewaywrapper, image): + marshalled = image.simpleMarshal() + assert marshalled == { + 'description': '', + 'author': 'Author ', + 'date': 1429578900.0, + 'type': 'Image', + 'id': image.getId(), + 'name': 'an image' + } From e5c7bc1859956a927879aad5426c2e3951952636 Mon Sep 17 00:00:00 2001 From: Josh Ballanco Date: Wed, 29 Apr 2015 15:16:22 +0300 Subject: [PATCH 21/27] Include Glencoe copyright header --- .../gatewaytest/test_image_wrapper.py | 18 ++---------------- .../gatewaytest/test_plate_wrapper.py | 18 ++---------------- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py b/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py index 8d74cf360a8..13959e2744e 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py @@ -1,23 +1,9 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- -# -# Copyright (C) 2013-2015 University of Dundee & Open Microscopy Environment. +# Copyright (C) 2015 Glencoe Software, Inc. # 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. +# Use is subject to license terms supplied in LICENSE.txt """ gateway tests - Testing the gateway image wrapper diff --git a/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py b/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py index b0f7e3133aa..8e7d288d50d 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_plate_wrapper.py @@ -1,23 +1,9 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- -# -# Copyright (C) 2013-2015 University of Dundee & Open Microscopy Environment. +# Copyright (C) 2015 Glencoe Software, Inc. # 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. +# Use is subject to license terms supplied in LICENSE.txt """ gateway tests - Testing the gateway plate wrapper From 93fc5adf5d7f29e2d19162a1c7117c857c441046 Mon Sep 17 00:00:00 2001 From: Chris Allan Date: Thu, 30 Apr 2015 03:20:41 -0700 Subject: [PATCH 22/27] Fix flake8 errors --- .../test/integration/gatewaytest/test_image_wrapper.py | 4 +--- components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py | 1 - components/tools/OmeroWeb/omeroweb/webgateway/views.py | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py b/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py index 13959e2744e..083ae988a6c 100644 --- a/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py +++ b/components/tools/OmeroPy/test/integration/gatewaytest/test_image_wrapper.py @@ -16,9 +16,8 @@ import pytest from omero.model import ImageI -from omero.rtypes import rstring, rint, rtime +from omero.rtypes import rstring, rtime from datetime import datetime -from uuid import uuid4 @pytest.fixture() @@ -60,7 +59,6 @@ def testGetDateNoAcquisitionDate( creation_event_date = image_no_acquisition_date.creationEventDate() assert date == creation_event_date - def testSimpleMarshal(self, gatewaywrapper, image): marshalled = image.simpleMarshal() assert marshalled == { diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index 698fb367da7..6ea298f32f8 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -11,7 +11,6 @@ """ import logging -import time import omero.sys from omero.rtypes import rint diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/views.py b/components/tools/OmeroWeb/omeroweb/webgateway/views.py index 9e750fc610a..3e40d38e257 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/views.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/views.py @@ -15,7 +15,6 @@ import re import json -from datetime import datetime import omero import omero.clients From a1c4ea45bdc8191b3ab622dd2947ad4009d964fd Mon Sep 17 00:00:00 2001 From: Chris Allan Date: Fri, 1 May 2015 04:32:51 -0700 Subject: [PATCH 23/27] Port to OMERO 5.1.x testing semantics --- .../OmeroWeb/test/integration/test_plategrid.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index 53210b54ab3..0326d4c0823 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -10,7 +10,7 @@ """ import pytest -import test.integration.library as lib +from weblibrary import IWebTest from omero.model import PlateI, WellI, WellSampleI from omero.rtypes import rint, rstring, rtime @@ -26,16 +26,15 @@ @pytest.fixture(scope='function') def itest(request): """ - Returns a new L{test.integration.library.ITest} instance. With attached + Returns a new L{weblibrary.IWebTest} instance. With attached finalizer so that pytest will clean it up. """ - o = lib.ITest() - o.setup_method(None) + IWebTest.setup_class() def finalizer(): - o.teardown_method(None) + IWebTest.teardown_class() request.addfinalizer(finalizer) - return o + return IWebTest() @pytest.fixture(scope='function') @@ -97,7 +96,7 @@ def make_well_grid(grid_layout={}): def plate_wells(itest, well_grid_factory, update_service): """ Returns a new OMERO Plate, linked Wells, linked WellSamples, and linked - Images populated by an L{test.integration.library.ITest} instance. + Images populated by an L{weblibrary.IWebTest} instance. """ plate = PlateI() plate.name = rstring(itest.uuid()) @@ -114,7 +113,7 @@ def plate_wells(itest, well_grid_factory, update_service): def full_plate_wells(itest, update_service): """ Returns a full OMERO Plate, linked Wells, linked WellSamples, and linked - Images populated by an L{test.integration.library.ITest} instance. + Images populated by an L{weblibrary.IWebTest} instance. """ lett = map(chr, range(ord('A'), ord('Z')+1)) plate = PlateI() From 6a0af16f83d9fb2d05cb0e68aed8a7c0fa1d2387 Mon Sep 17 00:00:00 2001 From: Chris Allan Date: Fri, 1 May 2015 06:28:19 -0700 Subject: [PATCH 24/27] Adjust integration test to handle `acquisitionDate` nullability --- components/tools/OmeroWeb/test/integration/test_plategrid.py | 1 + 1 file changed, 1 insertion(+) diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index 0326d4c0823..648862d9be3 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -162,6 +162,7 @@ def plate_wells_with_no_acq_date(itest, well_grid_factory, update_service, # Simple grid: one well with one image [well] = well_grid_factory({(0, 0): 1}) plate.addWell(well) + well.copyWellSamples()[0].image.acquisitionDate = None well = update_service.saveAndReturnObject(well) creation_date = well.copyWellSamples()[0].image.details.creationEvent.time plate = update_service.saveAndReturnObject(plate) From 8715c200f53bb233321f403fc2f6598df765b5aa Mon Sep 17 00:00:00 2001 From: Chris Allan Date: Fri, 1 May 2015 06:30:06 -0700 Subject: [PATCH 25/27] Fix handling of `acquisitionDate` nullability --- components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py index 6ea298f32f8..98d7ec26dda 100644 --- a/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py +++ b/components/tools/OmeroWeb/omeroweb/webgateway/plategrid.py @@ -58,7 +58,7 @@ def metadata(self): row, col, img_id, img_name, author, well_id, acq_date, \ create_date, description = res - if acq_date.val is not None and acq_date.val > 0: + if acq_date is not None and acq_date.val > 0: date = acq_date.val / 1000 else: date = create_date.val / 1000 From d812fdb783d4505ec6c218f6d7e870124bb64866 Mon Sep 17 00:00:00 2001 From: Chris Allan Date: Fri, 1 May 2015 06:40:19 -0700 Subject: [PATCH 26/27] Emulate py.test scoping semantics when using xunit style --- .../tools/OmeroWeb/test/integration/test_plategrid.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index 648862d9be3..db8acf078ec 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -29,7 +29,13 @@ def itest(request): Returns a new L{weblibrary.IWebTest} instance. With attached finalizer so that pytest will clean it up. """ - IWebTest.setup_class() + class PlateGridIWebTest(IWebTest): + """ + This class emulates py.test scoping semantics when the xunit style + is in use. + """ + pass + PlateGridIWebTest.setup_class() def finalizer(): IWebTest.teardown_class() From a56dc7677c47fc2c9f3c1587020206c3741b793c Mon Sep 17 00:00:00 2001 From: Chris Allan Date: Fri, 1 May 2015 06:41:00 -0700 Subject: [PATCH 27/27] Relax scoping to make tests run quicker --- .../test/integration/test_plategrid.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_plategrid.py b/components/tools/OmeroWeb/test/integration/test_plategrid.py index db8acf078ec..8f71cff1d97 100644 --- a/components/tools/OmeroWeb/test/integration/test_plategrid.py +++ b/components/tools/OmeroWeb/test/integration/test_plategrid.py @@ -23,7 +23,7 @@ import time -@pytest.fixture(scope='function') +@pytest.fixture(scope='module') def itest(request): """ Returns a new L{weblibrary.IWebTest} instance. With attached @@ -38,30 +38,30 @@ class PlateGridIWebTest(IWebTest): PlateGridIWebTest.setup_class() def finalizer(): - IWebTest.teardown_class() + PlateGridIWebTest.teardown_class() request.addfinalizer(finalizer) - return IWebTest() + return PlateGridIWebTest() -@pytest.fixture(scope='function') +@pytest.fixture() def client(itest): """Returns a new user client.""" return itest.new_client() -@pytest.fixture(scope='function') +@pytest.fixture() def conn(client): """Returns a new OMERO gateway.""" return BlitzGateway(client_obj=client) -@pytest.fixture(scope='function') +@pytest.fixture() def update_service(client): """Returns a new OMERO update service.""" return client.getSession().getUpdateService() -@pytest.fixture(scope='function') +@pytest.fixture() def well_sample_factory(itest): def make_well_sample(): @@ -72,7 +72,7 @@ def make_well_sample(): return make_well_sample -@pytest.fixture(scope='function') +@pytest.fixture() def well_factory(well_sample_factory): def make_well(ws_count=0): @@ -83,7 +83,7 @@ def make_well(ws_count=0): return make_well -@pytest.fixture(scope='function') +@pytest.fixture() def well_grid_factory(well_factory): def make_well_grid(grid_layout={}): @@ -98,7 +98,7 @@ def make_well_grid(grid_layout={}): return make_well_grid -@pytest.fixture(scope='function') +@pytest.fixture() def plate_wells(itest, well_grid_factory, update_service): """ Returns a new OMERO Plate, linked Wells, linked WellSamples, and linked @@ -115,7 +115,7 @@ def plate_wells(itest, well_grid_factory, update_service): return update_service.saveAndReturnObject(plate) -@pytest.fixture(scope='function') +@pytest.fixture() def full_plate_wells(itest, update_service): """ Returns a full OMERO Plate, linked Wells, linked WellSamples, and linked @@ -137,7 +137,7 @@ def full_plate_wells(itest, update_service): return update_service.saveAndReturnObject(plate) -@pytest.fixture(scope='function') +@pytest.fixture() def plate_wells_with_acq_date(itest, well_grid_factory, update_service): """ Creates a plate with a single well containing an image with both an @@ -156,7 +156,7 @@ def plate_wells_with_acq_date(itest, well_grid_factory, update_service): 'acq_date': int(acq_date / 1000)} -@pytest.fixture(scope='function') +@pytest.fixture() def plate_wells_with_no_acq_date(itest, well_grid_factory, update_service, conn): """ @@ -176,7 +176,7 @@ def plate_wells_with_no_acq_date(itest, well_grid_factory, update_service, 'creation_date': creation_date.val / 1000} -@pytest.fixture(scope='function') +@pytest.fixture() def plate_wells_with_description(itest, well_grid_factory, update_service): """ Creates a plate with a single well containing an image with a description. @@ -194,7 +194,7 @@ def plate_wells_with_description(itest, well_grid_factory, update_service): 'description': description} -@pytest.fixture(scope='function') +@pytest.fixture() def django_client(request, client): """Returns a logged in Django test client.""" django_client = Client()