From b8eb153831014dbd1afd66b90880a4dc851948e9 Mon Sep 17 00:00:00 2001 From: William Moore Date: Fri, 13 Jan 2017 09:53:32 +0000 Subject: [PATCH 01/23] add_data() in ObjectsView used to add urls in ProjectsView --- .../tools/OmeroWeb/omeroweb/api/views.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 51845b61fd9..90ec9507f65 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -198,13 +198,21 @@ def get_opts(self, request, **kwargs): } return opts + def add_data(self, marshalled, request, **kwargs): + """Post-process marshalled objects to add any extra data.""" + return marshalled + def get(self, request, conn=None, **kwargs): """GET a list of Projects, filtering by various request parameters.""" opts = self.get_opts(request, **kwargs) group = getIntOrDefault(request, 'group', -1) normalize = request.GET.get('normalize', False) == 'true' # Get the data - return query_objects(conn, self.OMERO_TYPE, group, opts, normalize) + marshalled = query_objects(conn, self.OMERO_TYPE, group, + opts, normalize) + for m in marshalled['data']: + self.add_data(m, request, **kwargs) + return marshalled class ProjectsView(ObjectsView): @@ -212,6 +220,18 @@ class ProjectsView(ObjectsView): OMERO_TYPE = 'Project' + def add_data(self, marshalled, request, **kwargs): + """Add urls to the marshalled Projects.""" + marshalled = super(ProjectsView, self).add_data( + marshalled, request, **kwargs) + project_id = marshalled['@id'] + v = kwargs['api_version'] + marshalled['datasets_url'] = build_url(request, 'api_project_datasets', + v, project_id=project_id) + marshalled['project_url'] = build_url(request, 'api_project', + v, pid=project_id) + return marshalled + class DatasetsView(ObjectsView): """Handles GET for /datasets/ to list available Datasets.""" From c17906256a4e81265d594cd0a5b60443ee75584a Mon Sep 17 00:00:00 2001 From: William Moore Date: Sat, 14 Jan 2017 22:05:55 +0000 Subject: [PATCH 02/23] Rename pid -> object_id for ObjectView --- components/tools/OmeroWeb/omeroweb/api/urls.py | 8 ++++---- components/tools/OmeroWeb/omeroweb/api/views.py | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index d2a833704fc..a1473618e82 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -75,7 +75,7 @@ """ api_project = url( - r'^v(?P%s)/m/projects/(?P[0-9]+)/$' % versions, + r'^v(?P%s)/m/projects/(?P[0-9]+)/$' % versions, views.ProjectView.as_view(), name='api_project') """ @@ -99,7 +99,7 @@ """ api_dataset = url( - r'^v(?P%s)/m/datasets/(?P[0-9]+)/$' % versions, + r'^v(?P%s)/m/datasets/(?P[0-9]+)/$' % versions, views.DatasetView.as_view(), name='api_dataset') """ @@ -107,7 +107,7 @@ """ api_screen = url( - r'^v(?P%s)/m/screens/(?P[0-9]+)/$' % versions, + r'^v(?P%s)/m/screens/(?P[0-9]+)/$' % versions, views.ScreenView.as_view(), name='api_screen') """ @@ -138,7 +138,7 @@ """ api_plate = url( - r'^v(?P%s)/m/plates/(?P[0-9]+)/$' % versions, + r'^v(?P%s)/m/plates/(?P[0-9]+)/$' % versions, views.PlateView.as_view(), name='api_plate') """ diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 90ec9507f65..b5562c32d48 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -119,25 +119,27 @@ def dispatch(self, *args, **kwargs): """Wrap other methods to add decorators.""" return super(ObjectView, self).dispatch(*args, **kwargs) - def get(self, request, pid, conn=None, **kwargs): + def get(self, request, object_id, conn=None, **kwargs): """Simply GET a single Object and marshal it or 404 if not found.""" - obj = conn.getObject(self.OMERO_TYPE, pid) + obj = conn.getObject(self.OMERO_TYPE, object_id) if obj is None: - raise NotFoundError('%s %s not found' % (self.OMERO_TYPE, pid)) + raise NotFoundError('%s %s not found' % (self.OMERO_TYPE, + object_id)) encoder = get_encoder(obj._obj.__class__) return encoder.encode(obj._obj) - def delete(self, request, pid, conn=None, **kwargs): + def delete(self, request, object_id, conn=None, **kwargs): """ Delete the Object and return marshal of deleted Object. Return 404 if not found. """ try: - obj = conn.getQueryService().get(self.OMERO_TYPE, long(pid), + obj = conn.getQueryService().get(self.OMERO_TYPE, long(object_id), conn.SERVICE_OPTS) except ValidationException: - raise NotFoundError('%s %s not found' % (self.OMERO_TYPE, pid)) + raise NotFoundError('%s %s not found' % (self.OMERO_TYPE, + object_id)) encoder = get_encoder(obj.__class__) json = encoder.encode(obj) conn.deleteObject(obj) From 10b331581325a9aa44130cf9199e29b1925c9846 Mon Sep 17 00:00:00 2001 From: William Moore Date: Sat, 14 Jan 2017 22:18:45 +0000 Subject: [PATCH 03/23] ObjectsView.add_data() uses subcleass.url = {} to add urls --- .../tools/OmeroWeb/omeroweb/api/views.py | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index b5562c32d48..432cdaa6938 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -173,6 +173,9 @@ class PlateView(ObjectView): class ObjectsView(View): """Base class for listing objects.""" + # urls extended by subclasses to add urls to marshalled objects + urls = {} + @method_decorator(login_required(useragent='OMERO.webapi')) @method_decorator(json_response()) def dispatch(self, *args, **kwargs): @@ -201,7 +204,24 @@ def get_opts(self, request, **kwargs): return opts def add_data(self, marshalled, request, **kwargs): - """Post-process marshalled objects to add any extra data.""" + """ + Post-process marshalled objects to add any extra data. + + Used to add urls to marshalled json. + Subclasses can configure self.urls to specify urls to add. + See ProjectsView urls as example + """ + object_id = marshalled['@id'] + version = kwargs['api_version'] + for key, args in self.urls.items(): + name = args['name'] + kwargs = args['kwargs'].copy() + # If kwargs has 'OBJECT_ID' placeholder, we replace with id + for k, v in kwargs.items(): + if v == 'OBJECT_ID': + kwargs[k] = object_id + url = build_url(request, name, version, **kwargs) + marshalled[key] = url return marshalled def get(self, request, conn=None, **kwargs): @@ -222,18 +242,16 @@ class ProjectsView(ObjectsView): OMERO_TYPE = 'Project' - def add_data(self, marshalled, request, **kwargs): - """Add urls to the marshalled Projects.""" - marshalled = super(ProjectsView, self).add_data( - marshalled, request, **kwargs) - project_id = marshalled['@id'] - v = kwargs['api_version'] - marshalled['datasets_url'] = build_url(request, 'api_project_datasets', - v, project_id=project_id) - marshalled['project_url'] = build_url(request, 'api_project', - v, pid=project_id) - return marshalled - + # To add a url to marshalled object add to this dict + # 'name' is url name, kwargs are passed to reverse() + # If any kwargs values are 'OBJECT_ID' then this placeholder will be + # filled with the actual project_id + urls = { + 'datasets_url': {'name': 'api_project_datasets', + 'kwargs': {'project_id': 'OBJECT_ID'}}, + 'project_url': {'name': 'api_project', + 'kwargs': {'object_id': 'OBJECT_ID'}} + } class DatasetsView(ObjectsView): """Handles GET for /datasets/ to list available Datasets.""" @@ -253,12 +271,26 @@ def get_opts(self, request, **kwargs): opts['project'] = project return opts + # Urls to add to marshalled object. See ProjectsView for more details + urls = { + 'dataset_url': {'name': 'api_dataset', + 'kwargs': {'object_id': 'OBJECT_ID'}} + } + class ScreensView(ObjectsView): """Handles GET for /screens/ to list available Screens.""" OMERO_TYPE = 'Screen' + # Urls to add to marshalled object. See ProjectsView for more details + urls = { + 'plates_url': {'name': 'api_screen_plates', + 'kwargs': {'screen_id': 'OBJECT_ID'}}, + 'screen_url': {'name': 'api_screen', + 'kwargs': {'object_id': 'OBJECT_ID'}} + } + class PlatesView(ObjectsView): """Handles GET for /plates/ to list available Plates.""" @@ -278,6 +310,12 @@ def get_opts(self, request, **kwargs): opts['screen'] = screen return opts + # Urls to add to marshalled object. See ProjectsView for more details + urls = { + 'plate_url': {'name': 'api_plate', + 'kwargs': {'object_id': 'OBJECT_ID'}} + } + class SaveView(View): """ From 3832b753a3e2ccac92c7089b29104c942a7eb433 Mon Sep 17 00:00:00 2001 From: William Moore Date: Sun, 15 Jan 2017 22:18:48 +0000 Subject: [PATCH 04/23] Adding urls to 'extra' in test_screens() --- .../OmeroWeb/test/integration/test_api_containers.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 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 584ee08a359..d439c583da1 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -268,4 +268,14 @@ def test_screens(self, user1, user_screens): # List ALL Screens rsp = _get_response_json(django_client, request_url, {}) - assert_objects(conn, rsp['data'], user_screens, dtype="Screen") + extra = [] + for screen in user_screens: + extra.append({ + 'screen_url': reverse('api_screen', kwargs={'api_version': version, + 'object_id': screen.id.val}), + 'plates_url': reverse('api_screen_plates', kwargs={'api_version': version, + 'screen_id': screen.id.val}) + }) + print extra + assert_objects(conn, rsp['data'], user_screens, + dtype="Screen", extra=extra) From 9cff702fea6d9aa43baf98ca0732684e4c41de75 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 16 Jan 2017 10:42:53 +0000 Subject: [PATCH 05/23] Work-around to add http://testserver/ to test urls --- .../test/integration/test_api_containers.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index d439c583da1..64395d35c3e 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -269,13 +269,19 @@ def test_screens(self, user1, user_screens): # List ALL Screens rsp = _get_response_json(django_client, request_url, {}) extra = [] + r = django_client.request() + webclint_url = r.url # http://testserver/webclient/ for screen in user_screens: + s_url = reverse('api_screen', kwargs={'api_version': version, + 'object_id': screen.id.val}) + p_url = reverse('api_screen_plates', + kwargs={'api_version': version, + 'screen_id': screen.id.val}) + s_url = webclint_url.replace('/webclient/', s_url) + p_url = webclint_url.replace('/webclient/', p_url) extra.append({ - 'screen_url': reverse('api_screen', kwargs={'api_version': version, - 'object_id': screen.id.val}), - 'plates_url': reverse('api_screen_plates', kwargs={'api_version': version, - 'screen_id': screen.id.val}) + 'screen_url': s_url, + 'plates_url': p_url }) - print extra assert_objects(conn, rsp['data'], user_screens, dtype="Screen", extra=extra) From 09a2e71b07b2d9b878bdf871efe6255f2b21f156 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 16 Jan 2017 22:10:23 +0000 Subject: [PATCH 06/23] Use request.build_absolute_uri() in test_screens --- .../OmeroWeb/test/integration/test_api_containers.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 64395d35c3e..48e739fbf43 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -23,6 +23,7 @@ _csrf_post_json, _csrf_put_json, _csrf_delete_response_json from django.core.urlresolvers import reverse from django.conf import settings +from django.http import HttpRequest import pytest from omero.gateway import BlitzGateway from omero_marshal import get_encoder @@ -269,16 +270,19 @@ def test_screens(self, user1, user_screens): # List ALL Screens rsp = _get_response_json(django_client, request_url, {}) extra = [] - r = django_client.request() - webclint_url = r.url # http://testserver/webclient/ + r = HttpRequest() + r.META = { + "SERVER_NAME": "testserver", + "SERVER_PORT": "80", + } for screen in user_screens: s_url = reverse('api_screen', kwargs={'api_version': version, 'object_id': screen.id.val}) p_url = reverse('api_screen_plates', kwargs={'api_version': version, 'screen_id': screen.id.val}) - s_url = webclint_url.replace('/webclient/', s_url) - p_url = webclint_url.replace('/webclient/', p_url) + s_url = r.build_absolute_uri(s_url) + p_url = r.build_absolute_uri(p_url) extra.append({ 'screen_url': s_url, 'plates_url': p_url From cdb5a5e242765f6080e49641f025c3507144e217 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 16 Jan 2017 22:32:15 +0000 Subject: [PATCH 07/23] Revert "Use request.build_absolute_uri() in test_screens" This reverts commit 09a2e71b07b2d9b878bdf871efe6255f2b21f156. --- .../OmeroWeb/test/integration/test_api_containers.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 48e739fbf43..64395d35c3e 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -23,7 +23,6 @@ _csrf_post_json, _csrf_put_json, _csrf_delete_response_json from django.core.urlresolvers import reverse from django.conf import settings -from django.http import HttpRequest import pytest from omero.gateway import BlitzGateway from omero_marshal import get_encoder @@ -270,19 +269,16 @@ def test_screens(self, user1, user_screens): # List ALL Screens rsp = _get_response_json(django_client, request_url, {}) extra = [] - r = HttpRequest() - r.META = { - "SERVER_NAME": "testserver", - "SERVER_PORT": "80", - } + r = django_client.request() + webclint_url = r.url # http://testserver/webclient/ for screen in user_screens: s_url = reverse('api_screen', kwargs={'api_version': version, 'object_id': screen.id.val}) p_url = reverse('api_screen_plates', kwargs={'api_version': version, 'screen_id': screen.id.val}) - s_url = r.build_absolute_uri(s_url) - p_url = r.build_absolute_uri(p_url) + s_url = webclint_url.replace('/webclient/', s_url) + p_url = webclint_url.replace('/webclient/', p_url) extra.append({ 'screen_url': s_url, 'plates_url': p_url From 7785e68ed13beca2920365ac8a576b27b1aa149a Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 16 Jan 2017 23:55:51 +0000 Subject: [PATCH 08/23] Added build_url() helper to test_api_containers --- .../test/integration/test_api_containers.py | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 64395d35c3e..1efd1047f5e 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -50,6 +50,16 @@ def cmp_name_insensitive(x, y): return cmp(unwrap(x.name).lower(), unwrap(y.name).lower()) +def build_url(client, url_name, url_kwargs): + """Build an absolute url using client response url""" + response = client.request() + # http://testserver/webclient/ + webclint_url = response.url + url = reverse(url_name, kwargs=url_kwargs) + url = webclint_url.replace('/webclient/', url) + return url + + def marshal_objects(objects): """Marshal objects using omero_marshal.""" expected = [] @@ -262,23 +272,20 @@ def test_screens(self, user1, user_screens): """Test listing of Screens.""" 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] request_url = reverse('api_screens', kwargs={'api_version': version}) # List ALL Screens - rsp = _get_response_json(django_client, request_url, {}) + rsp = _get_response_json(client, request_url, {}) extra = [] - r = django_client.request() - webclint_url = r.url # http://testserver/webclient/ for screen in user_screens: - s_url = reverse('api_screen', kwargs={'api_version': version, - 'object_id': screen.id.val}) - p_url = reverse('api_screen_plates', - kwargs={'api_version': version, - 'screen_id': screen.id.val}) - s_url = webclint_url.replace('/webclient/', s_url) - p_url = webclint_url.replace('/webclient/', p_url) + s_url = build_url(client, 'api_screen', + {'api_version': version, + 'object_id': screen.id.val}) + p_url = build_url(client, 'api_screen_plates', + {'api_version': version, + 'screen_id': screen.id.val}) extra.append({ 'screen_url': s_url, 'plates_url': p_url From 801ad6f2c2b97f8ffbe69a664ab9da2176316c99 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 16 Jan 2017 23:56:56 +0000 Subject: [PATCH 09/23] Remove '_url' values from json in test_api_projects * containers --- .../tools/OmeroWeb/test/integration/test_api_containers.py | 4 ++++ .../tools/OmeroWeb/test/integration/test_api_projects.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 1efd1047f5e..118e7b5e432 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -94,6 +94,10 @@ def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", for i, o1, o2 in zip(range(len(expected)), json_objects, expected): if extra is not None and i < len(extra): o2.update(extra[i]) + # remove any urls from json + for key in o1.keys(): + if key.endswith('_url') and key not in o2: + del(o1[key]) assert o1 == o2 diff --git a/components/tools/OmeroWeb/test/integration/test_api_projects.py b/components/tools/OmeroWeb/test/integration/test_api_projects.py index e44f8ee3499..e2bcb0c02fc 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_projects.py +++ b/components/tools/OmeroWeb/test/integration/test_api_projects.py @@ -174,6 +174,10 @@ def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", expected = marshal_objects(projects) assert len(json_objects) == len(expected) for o1, o2 in zip(json_objects, expected): + # remove any urls from json + for key in o1.keys(): + if key.endswith('_url'): + del(o1[key]) assert o1 == o2 From e0ff25e2212ddc01d2c6db4f135a53035f88def6 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 17 Jan 2017 11:19:35 +0000 Subject: [PATCH 10/23] Add 'images_url' to /datasets/ json --- components/tools/OmeroWeb/omeroweb/api/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index c825436608e..8d6fe962470 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -294,7 +294,9 @@ def get_opts(self, request, **kwargs): # Urls to add to marshalled object. See ProjectsView for more details urls = { 'dataset_url': {'name': 'api_dataset', - 'kwargs': {'object_id': 'OBJECT_ID'}} + 'kwargs': {'object_id': 'OBJECT_ID'}}, + 'images_url': {'name': 'api_dataset_images', + 'kwargs': {'dataset_id': 'OBJECT_ID'}}, } From d986da1f66d3a826864078f792386bf92e9afb2d Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 17 Jan 2017 11:48:33 +0000 Subject: [PATCH 11/23] New ApiView base class for ObjectsView and ObjectView --- .../tools/OmeroWeb/omeroweb/api/urls.py | 2 +- .../tools/OmeroWeb/omeroweb/api/views.py | 75 ++++++++++--------- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/urls.py b/components/tools/OmeroWeb/omeroweb/api/urls.py index 998f1aebae9..f2a77063fd3 100644 --- a/components/tools/OmeroWeb/omeroweb/api/urls.py +++ b/components/tools/OmeroWeb/omeroweb/api/urls.py @@ -123,7 +123,7 @@ """ api_image = url( - r'^v(?P%s)/m/images/(?P[0-9]+)/$' % versions, + r'^v(?P%s)/m/images/(?P[0-9]+)/$' % versions, views.ImageView.as_view(), name='api_image') """ diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 8d6fe962470..0fae406647b 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -111,14 +111,44 @@ def api_servers(request, api_version, **kwargs): return {'data': servers} -class ObjectView(View): - """Handle access to an individual Object to GET or DELETE it.""" +class ApiView(View): + """Base class extended by ObjectView and ObjectsView.""" + + # urls extended by subclasses to add urls to marshalled objects + urls = {} @method_decorator(login_required(useragent='OMERO.webapi')) @method_decorator(json_response()) def dispatch(self, *args, **kwargs): """Wrap other methods to add decorators.""" - return super(ObjectView, self).dispatch(*args, **kwargs) + return super(ApiView, self).dispatch(*args, **kwargs) + + def add_data(self, marshalled, request, **kwargs): + """ + Post-process marshalled object to add any extra data. + + Used to add urls to marshalled json. + Subclasses can configure self.urls to specify urls to add. + See ProjectsView urls as example + """ + # if self.urls is None: + # return marshalled + object_id = marshalled['@id'] + version = kwargs['api_version'] + for key, args in self.urls.items(): + name = args['name'] + kwargs = args['kwargs'].copy() + # If kwargs has 'OBJECT_ID' placeholder, we replace with id + for k, v in kwargs.items(): + if v == 'OBJECT_ID': + kwargs[k] = object_id + url = build_url(request, name, version, **kwargs) + marshalled[key] = url + return marshalled + + +class ObjectView(ApiView): + """Handle access to an individual Object to GET or DELETE it.""" def get_opts(self, request): """Return a dict for use in conn.getObjects() based on request.""" @@ -127,12 +157,14 @@ def get_opts(self, request): def get(self, request, object_id, conn=None, **kwargs): """Simply GET a single Object and marshal it or 404 if not found.""" opts = self.get_opts(request) - obj = conn.getObject(self.OMERO_TYPE, pid, opts=opts) + obj = conn.getObject(self.OMERO_TYPE, object_id, opts=opts) if obj is None: raise NotFoundError('%s %s not found' % (self.OMERO_TYPE, object_id)) encoder = get_encoder(obj._obj.__class__) - return encoder.encode(obj._obj) + marshalled = encoder.encode(obj._obj) + self.add_data(marshalled, request, **kwargs) + return marshalled def delete(self, request, object_id, conn=None, **kwargs): """ @@ -190,18 +222,9 @@ class PlateView(ObjectView): OMERO_TYPE = 'Plate' -class ObjectsView(View): +class ObjectsView(ApiView): """Base class for listing objects.""" - # urls extended by subclasses to add urls to marshalled objects - urls = {} - - @method_decorator(login_required(useragent='OMERO.webapi')) - @method_decorator(json_response()) - def dispatch(self, *args, **kwargs): - """Use dispatch to add decorators to class methods.""" - return super(ObjectsView, self).dispatch(*args, **kwargs) - def get_opts(self, request, **kwargs): """Return an options dict based on request parameters.""" try: @@ -223,27 +246,6 @@ def get_opts(self, request, **kwargs): } return opts - def add_data(self, marshalled, request, **kwargs): - """ - Post-process marshalled objects to add any extra data. - - Used to add urls to marshalled json. - Subclasses can configure self.urls to specify urls to add. - See ProjectsView urls as example - """ - object_id = marshalled['@id'] - version = kwargs['api_version'] - for key, args in self.urls.items(): - name = args['name'] - kwargs = args['kwargs'].copy() - # If kwargs has 'OBJECT_ID' placeholder, we replace with id - for k, v in kwargs.items(): - if v == 'OBJECT_ID': - kwargs[k] = object_id - url = build_url(request, name, version, **kwargs) - marshalled[key] = url - return marshalled - def get(self, request, conn=None, **kwargs): """GET a list of Projects, filtering by various request parameters.""" opts = self.get_opts(request, **kwargs) @@ -273,6 +275,7 @@ class ProjectsView(ObjectsView): 'kwargs': {'object_id': 'OBJECT_ID'}} } + class DatasetsView(ObjectsView): """Handles GET for /datasets/ to list available Datasets.""" From 3ce2708d585a08128c7657b307936eb8b32a49e5 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 17 Jan 2017 11:49:34 +0000 Subject: [PATCH 12/23] Add children_urls to Project, Dataset & Screen json --- .../tools/OmeroWeb/omeroweb/api/views.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 0fae406647b..e5447b17843 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -189,12 +189,24 @@ class ProjectView(ObjectView): OMERO_TYPE = 'Project' + # Urls to add to marshalled object. See ProjectsView for more details + urls = { + 'datasets_url': {'name': 'api_project_datasets', + 'kwargs': {'project_id': 'OBJECT_ID'}}, + } + class DatasetView(ObjectView): """Handle access to an individual Dataset to GET or DELETE it.""" OMERO_TYPE = 'Dataset' + # Urls to add to marshalled object. See ProjectsView for more details + urls = { + 'images_url': {'name': 'api_dataset_images', + 'kwargs': {'dataset_id': 'OBJECT_ID'}}, + } + class ImageView(ObjectView): """Handle access to an individual Image to GET or DELETE it.""" @@ -215,6 +227,12 @@ class ScreenView(ObjectView): OMERO_TYPE = 'Screen' + # Urls to add to marshalled object. See ProjectsView for more details + urls = { + 'plates_url': {'name': 'api_screen_plates', + 'kwargs': {'screen_id': 'OBJECT_ID'}}, + } + class PlateView(ObjectView): """Handle access to an individual Plate to GET or DELETE it.""" From fd287d30154fb479021580a1436d7c57a01e65fb Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 17 Jan 2017 12:00:58 +0000 Subject: [PATCH 13/23] Fix pid -> object_id rename in test_api_projects.py --- .../test/integration/test_api_projects.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_projects.py b/components/tools/OmeroWeb/test/integration/test_api_projects.py index e2bcb0c02fc..c70b0f06cca 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_projects.py +++ b/components/tools/OmeroWeb/test/integration/test_api_projects.py @@ -519,8 +519,9 @@ def test_project_create_other_group(self, user1, projects_user1_group2): new_project_id = rsp['@id'] assert rsp['omero:details']['group']['@id'] == group2_id # Read Project - project_url = reverse('api_project', kwargs={'api_version': version, - 'pid': new_project_id}) + project_url = reverse('api_project', + kwargs={'api_version': version, + 'object_id': new_project_id}) rsp = _get_response_json(django_client, project_url, {}) assert rsp['omero:details']['group']['@id'] == group2_id @@ -537,8 +538,9 @@ def test_project_update(self, user1): # Update Project in 2 ways... version = settings.API_VERSIONS[-1] - project_url = reverse('api_project', kwargs={'api_version': version, - 'pid': project.id.val}) + project_url = reverse('api_project', + kwargs={'api_version': version, + 'object_id': project.id.val}) save_url = reverse('api_save', kwargs={'api_version': version}) # 1) Get Project, update and save back project_json = _get_response_json(django_client, project_url, {}) @@ -577,8 +579,9 @@ def test_project_delete(self, user1): project.description = rstring('Test update') project = get_update_service(user1).saveAndReturnObject(project) version = settings.API_VERSIONS[-1] - project_url = reverse('api_project', kwargs={'api_version': version, - 'pid': project.id.val}) + project_url = reverse('api_project', + kwargs={'api_version': version, + 'object_id': project.id.val}) # Before delete, we can read pr_json = _get_response_json(django_client, project_url, {}) assert pr_json['Name'] == 'test_project_delete' From e0f93131a23fee1011eef698ea53a4346e471075 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 17 Jan 2017 16:12:20 +0000 Subject: [PATCH 14/23] Add new test_pdi_urls --- .../tools/OmeroWeb/omeroweb/api/views.py | 6 ++ .../test/integration/test_api_containers.py | 83 +++++++++++++++++-- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index e5447b17843..5f2e3492667 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -365,6 +365,12 @@ class ImagesView(ObjectsView): OMERO_TYPE = 'Image' + # Urls to add to marshalled object. See ProjectsView for more details + urls = { + 'image_url': {'name': 'api_image', + 'kwargs': {'object_id': 'OBJECT_ID'}}, + } + def get_opts(self, request, **kwargs): """Add filtering by 'dataset' and other params to the opts dict.""" opts = super(ImagesView, self).get_opts(request, **kwargs) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 118e7b5e432..8c3fef16da6 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -51,7 +51,7 @@ def cmp_name_insensitive(x, y): def build_url(client, url_name, url_kwargs): - """Build an absolute url using client response url""" + """Build an absolute url using client response url.""" response = client.request() # http://testserver/webclient/ webclint_url = response.url @@ -70,7 +70,7 @@ def marshal_objects(objects): def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", - group='-1', extra=None): + group='-1', extra=None, opts=None): """ Load objects from OMERO, via conn.getObjects(). @@ -87,7 +87,7 @@ def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", except TypeError: pids.append(p.id.val) conn.SERVICE_OPTS.setOmeroGroup(group) - objs = conn.getObjects(dtype, pids, respect_order=True) + objs = conn.getObjects(dtype, pids, respect_order=True, opts=opts) objs = [p._obj for p in objs] expected = marshal_objects(objs) assert len(json_objects) == len(expected) @@ -123,8 +123,10 @@ def project_datasets(self, user1): dataset1 = DatasetI() dataset1.name = rstring('Dataset%s' % d) for i in range(d): - image = ImageI() - image.name = rstring('Image%s' % i) + image = self.create_test_image(size_x=5, size_y=5, + session=user1[0].getSession(), + name="Image%s" % i) + image = ImageI(image.id.val, False) dataset1.linkImage(image) project.linkDataset(dataset1) @@ -296,3 +298,74 @@ def test_screens(self, user1, user_screens): }) assert_objects(conn, rsp['data'], user_screens, dtype="Screen", extra=extra) + + def test_pdi_urls(self, user1, project_datasets): + """Test browsing via urls in json /api/->PDI.""" + conn = get_connection(user1) + user_name = conn.getUser().getName() + client = self.new_django_client(user_name, user_name) + version = settings.API_VERSIONS[-1] + base_url = reverse('api_base', kwargs={'api_version': version}) + base_rsp = _get_response_json(client, base_url, {}) + + # List projects + project, dataset = project_datasets + projects_url = base_rsp['projects_url'] + rsp = _get_response_json(client, projects_url, {}) + projects_json = rsp['data'] + extra = [{ + 'project_url': build_url(client, 'api_project', + {'api_version': version, + 'object_id': project.id.val}), + 'datasets_url': build_url(client, 'api_project_datasets', + {'api_version': version, + 'project_id': project.id.val}) + }] + assert_objects(conn, projects_json, [project], extra=extra) + # View single Project + rsp = _get_response_json(client, projects_json[0]['project_url'], {}) + assert_objects(conn, [rsp], [project], + extra=[{'datasets_url': extra[0]['datasets_url']}]) + + # List datasets + datasets_url = projects_json[0]['datasets_url'] + datasets = project.linkedDatasetList() + datasets.sort(cmp_name_insensitive) + rsp = _get_response_json(client, datasets_url, {}) + datasets_json = rsp['data'] + extra = [] + for d in datasets: + extra.append({ + 'dataset_url': build_url(client, 'api_dataset', + {'api_version': version, + 'object_id': d.id.val}), + 'images_url': build_url(client, 'api_dataset_images', + {'api_version': version, + 'dataset_id': d.id.val}) + }) + assert_objects(conn, datasets_json, datasets, + dtype='Dataset', extra=extra) + # View single Dataset + rsp = _get_response_json(client, datasets_json[0]['dataset_url'], {}) + assert_objects(conn, [rsp], datasets[0:1], dtype='Dataset', + extra=[{'images_url': extra[0]['images_url']}]) + + # List images (from last Dataset) + images_url = datasets_json[-1]['images_url'] + images = datasets[-1].linkedImageList() + images.sort(cmp_name_insensitive) + rsp = _get_response_json(client, images_url, {}) + images_json = rsp['data'] + extra = [] + for i in images: + extra.append({ + 'image_url': build_url(client, 'api_image', + {'api_version': version, + 'object_id': i.id.val}), + }) + assert_objects(conn, images_json, images, + dtype='Image', extra=extra, opts={'load_pixels': True}) + # View single Image + rsp = _get_response_json(client, images_json[0]['image_url'], {}) + assert_objects(conn, [rsp], images[0:1], dtype='Image', + opts={'load_channels': True}) From 871b8033335b0d1e78ef8198c7c79c1f6a3cbf86 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 18 Jan 2017 13:57:24 +0000 Subject: [PATCH 15/23] Ignore urls in test_api_images assert_objects() --- components/tools/OmeroWeb/test/integration/test_api_images.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/tools/OmeroWeb/test/integration/test_api_images.py b/components/tools/OmeroWeb/test/integration/test_api_images.py index 1c66186c99c..190a7491a5f 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_images.py +++ b/components/tools/OmeroWeb/test/integration/test_api_images.py @@ -92,6 +92,10 @@ def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", # dumping to json and loading (same as test data) 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) + for key in o1.keys(): + if key.endswith('_url'): + del(o1[key]) assert o1 == o2 From af2614eb96c8d4161a06569baf72cb012ecb8cbe Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 18 Jan 2017 13:59:35 +0000 Subject: [PATCH 16/23] Fixes from #5035 for api/views.py --- components/tools/OmeroWeb/omeroweb/api/views.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index 5f2e3492667..fdbacd48653 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -131,8 +131,6 @@ def add_data(self, marshalled, request, **kwargs): Subclasses can configure self.urls to specify urls to add. See ProjectsView urls as example """ - # if self.urls is None: - # return marshalled object_id = marshalled['@id'] version = kwargs['api_version'] for key, args in self.urls.items(): @@ -314,10 +312,10 @@ def get_opts(self, request, **kwargs): # Urls to add to marshalled object. See ProjectsView for more details urls = { - 'dataset_url': {'name': 'api_dataset', - 'kwargs': {'object_id': 'OBJECT_ID'}}, 'images_url': {'name': 'api_dataset_images', 'kwargs': {'dataset_id': 'OBJECT_ID'}}, + 'dataset_url': {'name': 'api_dataset', + 'kwargs': {'object_id': 'OBJECT_ID'}}, } From 64c05a7f4004a168ccfb6920e40a3587dc0706d3 Mon Sep 17 00:00:00 2001 From: William Moore Date: Wed, 18 Jan 2017 23:54:55 +0000 Subject: [PATCH 17/23] Add test_spw_urls() --- .../test/integration/test_api_containers.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index 8c3fef16da6..c3b86769154 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -299,6 +299,53 @@ def test_screens(self, user1, user_screens): assert_objects(conn, rsp['data'], user_screens, dtype="Screen", extra=extra) + def test_spw_urls(self, user1, screen_plates): + """Test browsing via urls in json /api/->SPW.""" + conn = get_connection(user1) + user_name = conn.getUser().getName() + client = self.new_django_client(user_name, user_name) + version = settings.API_VERSIONS[-1] + base_url = reverse('api_base', kwargs={'api_version': version}) + base_rsp = _get_response_json(client, base_url, {}) + + # List screens + screen, plate = screen_plates + screens_url = base_rsp['screens_url'] + rsp = _get_response_json(client, screens_url, {}) + screens_json = rsp['data'] + extra = [{ + 'screen_url': build_url(client, 'api_screen', + {'api_version': version, + 'object_id': screen.id.val}), + 'plates_url': build_url(client, 'api_screen_plates', + {'api_version': version, + 'screen_id': screen.id.val}) + }] + assert_objects(conn, screens_json, [screen], dtype='Screen', + extra=extra) + # View single screen + rsp = _get_response_json(client, screens_json[0]['screen_url'], {}) + assert_objects(conn, [rsp], [screen], dtype='Screen', + extra=[{'plates_url': extra[0]['plates_url']}]) + + # List plates + plates_url = screens_json[0]['plates_url'] + plates = screen.linkedPlateList() + plates.sort(cmp_name_insensitive) + rsp = _get_response_json(client, plates_url, {}) + plates_json = rsp['data'] + extra = [] + for p in plates: + extra.append({ + 'plate_url': build_url(client, 'api_plate', + {'api_version': version, + 'object_id': p.id.val}), + }) + assert_objects(conn, plates_json, plates, dtype='Plate', extra=extra) + # View single plate + rsp = _get_response_json(client, plates_json[0]['plate_url'], {}) + assert_objects(conn, [rsp], plates[0:1], dtype='Plate') + def test_pdi_urls(self, user1, project_datasets): """Test browsing via urls in json /api/->PDI.""" conn = get_connection(user1) From 074876dbd041341b99ee78f0d7a45230052a2a8a Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 19 Jan 2017 11:33:04 +0000 Subject: [PATCH 18/23] Use url: prefix for urls in json --- .../tools/OmeroWeb/omeroweb/api/views.py | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/components/tools/OmeroWeb/omeroweb/api/views.py b/components/tools/OmeroWeb/omeroweb/api/views.py index fdbacd48653..b1b8bcae317 100644 --- a/components/tools/OmeroWeb/omeroweb/api/views.py +++ b/components/tools/OmeroWeb/omeroweb/api/views.py @@ -67,7 +67,7 @@ def api_versions(request, **kwargs): for v in settings.API_VERSIONS: versions.append({ 'version': v, - 'base_url': build_url(request, 'api_base', v) + 'url:base': build_url(request, 'api_base', v) }) return {'data': versions} @@ -76,16 +76,16 @@ def api_versions(request, **kwargs): def api_base(request, api_version=None, **kwargs): """Base url of the webgateway json api for a specified version.""" v = api_version - rv = {'projects_url': build_url(request, 'api_projects', v), - 'datasets_url': build_url(request, 'api_datasets', v), - 'images_url': build_url(request, 'api_images', v), - 'screens_url': build_url(request, 'api_screens', v), - 'plates_url': build_url(request, 'api_plates', v), - 'token_url': build_url(request, 'api_token', v), - 'servers_url': build_url(request, 'api_servers', v), - 'login_url': build_url(request, 'api_login', v), - 'save_url': build_url(request, 'api_save', v), - 'schema_url': OME_SCHEMA_URL} + rv = {'url:projects': build_url(request, 'api_projects', v), + 'url:datasets': build_url(request, 'api_datasets', v), + 'url:images': build_url(request, 'api_images', v), + 'url:screens': build_url(request, 'api_screens', v), + 'url:plates': build_url(request, 'api_plates', v), + 'url:token': build_url(request, 'api_token', v), + 'url:servers': build_url(request, 'api_servers', v), + 'url:login': build_url(request, 'api_login', v), + 'url:save': build_url(request, 'api_save', v), + 'url:schema': OME_SCHEMA_URL} return rv @@ -189,7 +189,7 @@ class ProjectView(ObjectView): # Urls to add to marshalled object. See ProjectsView for more details urls = { - 'datasets_url': {'name': 'api_project_datasets', + 'url:datasets': {'name': 'api_project_datasets', 'kwargs': {'project_id': 'OBJECT_ID'}}, } @@ -201,7 +201,7 @@ class DatasetView(ObjectView): # Urls to add to marshalled object. See ProjectsView for more details urls = { - 'images_url': {'name': 'api_dataset_images', + 'url:images': {'name': 'api_dataset_images', 'kwargs': {'dataset_id': 'OBJECT_ID'}}, } @@ -227,7 +227,7 @@ class ScreenView(ObjectView): # Urls to add to marshalled object. See ProjectsView for more details urls = { - 'plates_url': {'name': 'api_screen_plates', + 'url:plates': {'name': 'api_screen_plates', 'kwargs': {'screen_id': 'OBJECT_ID'}}, } @@ -285,9 +285,9 @@ class ProjectsView(ObjectsView): # If any kwargs values are 'OBJECT_ID' then this placeholder will be # filled with the actual project_id urls = { - 'datasets_url': {'name': 'api_project_datasets', + 'url:datasets': {'name': 'api_project_datasets', 'kwargs': {'project_id': 'OBJECT_ID'}}, - 'project_url': {'name': 'api_project', + 'url:project': {'name': 'api_project', 'kwargs': {'object_id': 'OBJECT_ID'}} } @@ -312,9 +312,9 @@ def get_opts(self, request, **kwargs): # Urls to add to marshalled object. See ProjectsView for more details urls = { - 'images_url': {'name': 'api_dataset_images', + 'url:images': {'name': 'api_dataset_images', 'kwargs': {'dataset_id': 'OBJECT_ID'}}, - 'dataset_url': {'name': 'api_dataset', + 'url:dataset': {'name': 'api_dataset', 'kwargs': {'object_id': 'OBJECT_ID'}}, } @@ -326,9 +326,9 @@ class ScreensView(ObjectsView): # Urls to add to marshalled object. See ProjectsView for more details urls = { - 'plates_url': {'name': 'api_screen_plates', + 'url:plates': {'name': 'api_screen_plates', 'kwargs': {'screen_id': 'OBJECT_ID'}}, - 'screen_url': {'name': 'api_screen', + 'url:screen': {'name': 'api_screen', 'kwargs': {'object_id': 'OBJECT_ID'}} } @@ -353,7 +353,7 @@ def get_opts(self, request, **kwargs): # Urls to add to marshalled object. See ProjectsView for more details urls = { - 'plate_url': {'name': 'api_plate', + 'url:plate': {'name': 'api_plate', 'kwargs': {'object_id': 'OBJECT_ID'}} } @@ -365,7 +365,7 @@ class ImagesView(ObjectsView): # Urls to add to marshalled object. See ProjectsView for more details urls = { - 'image_url': {'name': 'api_image', + 'url:image': {'name': 'api_image', 'kwargs': {'object_id': 'OBJECT_ID'}}, } From ddc2f232b987a5262e0586404e314f011b836a3e Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 19 Jan 2017 11:40:23 +0000 Subject: [PATCH 19/23] Update tests to use 'url:' prefix for urls --- .../test/integration/test_api_containers.py | 54 +++++++++---------- .../test/integration/test_api_images.py | 2 +- .../test/integration/test_api_projects.py | 2 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index c3b86769154..e8594383ea7 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -94,9 +94,9 @@ def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", for i, o1, o2 in zip(range(len(expected)), json_objects, expected): if extra is not None and i < len(extra): o2.update(extra[i]) - # remove any urls from json + # remove any urls from json, if not in both objects for key in o1.keys(): - if key.endswith('_url') and key not in o2: + if key.startswith('url:') and key not in o2: del(o1[key]) assert o1 == o2 @@ -187,9 +187,9 @@ def test_container_crud(self, dtype): # Need to get the Schema url to create @type base_url = reverse('api_base', kwargs={'api_version': version}) rsp = _get_response_json(django_client, base_url, {}) - schema_url = rsp['schema_url'] + schema_url = rsp['url:schema'] # specify group via query params - save_url = "%s?group=%s" % (rsp['save_url'], group) + save_url = "%s?group=%s" % (rsp['url:save'], group) project_name = 'test_container_create_read' payload = {'Name': project_name, '@type': '%s#%s' % (schema_url, dtype)} @@ -293,8 +293,8 @@ def test_screens(self, user1, user_screens): {'api_version': version, 'screen_id': screen.id.val}) extra.append({ - 'screen_url': s_url, - 'plates_url': p_url + 'url:screen': s_url, + 'url:plates': p_url }) assert_objects(conn, rsp['data'], user_screens, dtype="Screen", extra=extra) @@ -310,26 +310,26 @@ def test_spw_urls(self, user1, screen_plates): # List screens screen, plate = screen_plates - screens_url = base_rsp['screens_url'] + screens_url = base_rsp['url:screens'] rsp = _get_response_json(client, screens_url, {}) screens_json = rsp['data'] extra = [{ - 'screen_url': build_url(client, 'api_screen', + 'url:screen': build_url(client, 'api_screen', {'api_version': version, 'object_id': screen.id.val}), - 'plates_url': build_url(client, 'api_screen_plates', + 'url:plates': build_url(client, 'api_screen_plates', {'api_version': version, 'screen_id': screen.id.val}) }] assert_objects(conn, screens_json, [screen], dtype='Screen', extra=extra) # View single screen - rsp = _get_response_json(client, screens_json[0]['screen_url'], {}) + rsp = _get_response_json(client, screens_json[0]['url:screen'], {}) assert_objects(conn, [rsp], [screen], dtype='Screen', - extra=[{'plates_url': extra[0]['plates_url']}]) + extra=[{'url:plates': extra[0]['url:plates']}]) # List plates - plates_url = screens_json[0]['plates_url'] + plates_url = screens_json[0]['url:plates'] plates = screen.linkedPlateList() plates.sort(cmp_name_insensitive) rsp = _get_response_json(client, plates_url, {}) @@ -337,13 +337,13 @@ def test_spw_urls(self, user1, screen_plates): extra = [] for p in plates: extra.append({ - 'plate_url': build_url(client, 'api_plate', + 'url:plate': build_url(client, 'api_plate', {'api_version': version, 'object_id': p.id.val}), }) assert_objects(conn, plates_json, plates, dtype='Plate', extra=extra) # View single plate - rsp = _get_response_json(client, plates_json[0]['plate_url'], {}) + rsp = _get_response_json(client, plates_json[0]['url:plate'], {}) assert_objects(conn, [rsp], plates[0:1], dtype='Plate') def test_pdi_urls(self, user1, project_datasets): @@ -357,25 +357,25 @@ def test_pdi_urls(self, user1, project_datasets): # List projects project, dataset = project_datasets - projects_url = base_rsp['projects_url'] + projects_url = base_rsp['url:projects'] rsp = _get_response_json(client, projects_url, {}) projects_json = rsp['data'] extra = [{ - 'project_url': build_url(client, 'api_project', + 'url:project': build_url(client, 'api_project', {'api_version': version, 'object_id': project.id.val}), - 'datasets_url': build_url(client, 'api_project_datasets', + 'url:datasets': build_url(client, 'api_project_datasets', {'api_version': version, 'project_id': project.id.val}) }] assert_objects(conn, projects_json, [project], extra=extra) # View single Project - rsp = _get_response_json(client, projects_json[0]['project_url'], {}) + rsp = _get_response_json(client, projects_json[0]['url:project'], {}) assert_objects(conn, [rsp], [project], - extra=[{'datasets_url': extra[0]['datasets_url']}]) + extra=[{'url:datasets': extra[0]['url:datasets']}]) # List datasets - datasets_url = projects_json[0]['datasets_url'] + datasets_url = projects_json[0]['url:datasets'] datasets = project.linkedDatasetList() datasets.sort(cmp_name_insensitive) rsp = _get_response_json(client, datasets_url, {}) @@ -383,22 +383,22 @@ def test_pdi_urls(self, user1, project_datasets): extra = [] for d in datasets: extra.append({ - 'dataset_url': build_url(client, 'api_dataset', + 'url:dataset': build_url(client, 'api_dataset', {'api_version': version, 'object_id': d.id.val}), - 'images_url': build_url(client, 'api_dataset_images', + 'url:images': build_url(client, 'api_dataset_images', {'api_version': version, 'dataset_id': d.id.val}) }) assert_objects(conn, datasets_json, datasets, dtype='Dataset', extra=extra) # View single Dataset - rsp = _get_response_json(client, datasets_json[0]['dataset_url'], {}) + rsp = _get_response_json(client, datasets_json[0]['url:dataset'], {}) assert_objects(conn, [rsp], datasets[0:1], dtype='Dataset', - extra=[{'images_url': extra[0]['images_url']}]) + extra=[{'url:images': extra[0]['url:images']}]) # List images (from last Dataset) - images_url = datasets_json[-1]['images_url'] + images_url = datasets_json[-1]['url:images'] images = datasets[-1].linkedImageList() images.sort(cmp_name_insensitive) rsp = _get_response_json(client, images_url, {}) @@ -406,13 +406,13 @@ def test_pdi_urls(self, user1, project_datasets): extra = [] for i in images: extra.append({ - 'image_url': build_url(client, 'api_image', + 'url:image': build_url(client, 'api_image', {'api_version': version, 'object_id': i.id.val}), }) assert_objects(conn, images_json, images, dtype='Image', extra=extra, opts={'load_pixels': True}) # View single Image - rsp = _get_response_json(client, images_json[0]['image_url'], {}) + rsp = _get_response_json(client, images_json[0]['url:image'], {}) assert_objects(conn, [rsp], images[0:1], dtype='Image', opts={'load_channels': True}) diff --git a/components/tools/OmeroWeb/test/integration/test_api_images.py b/components/tools/OmeroWeb/test/integration/test_api_images.py index 190a7491a5f..e0fadf2a9d6 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_images.py +++ b/components/tools/OmeroWeb/test/integration/test_api_images.py @@ -94,7 +94,7 @@ def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", o2 = json.loads(json.dumps(o2)) # remove any urls from json (tested elsewhere) for key in o1.keys(): - if key.endswith('_url'): + if key.startswith('url:'): del(o1[key]) assert o1 == o2 diff --git a/components/tools/OmeroWeb/test/integration/test_api_projects.py b/components/tools/OmeroWeb/test/integration/test_api_projects.py index c70b0f06cca..28da0256fc4 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_projects.py +++ b/components/tools/OmeroWeb/test/integration/test_api_projects.py @@ -176,7 +176,7 @@ def assert_objects(conn, json_objects, omero_ids_objects, dtype="Project", for o1, o2 in zip(json_objects, expected): # remove any urls from json for key in o1.keys(): - if key.endswith('_url'): + if key.startswith('url:'): del(o1[key]) assert o1 == o2 From 981db6e6d61e1d1748b5a1cff0d2fa57bc04e6ae Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 19 Jan 2017 11:45:22 +0000 Subject: [PATCH 20/23] flake8 fix --- components/tools/OmeroWeb/test/integration/test_api_login.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_login.py b/components/tools/OmeroWeb/test/integration/test_api_login.py index b40e258b029..5785f6d4cc7 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_login.py +++ b/components/tools/OmeroWeb/test/integration/test_api_login.py @@ -22,8 +22,8 @@ """ import pytest -from omeroweb.testlib import IWebTest, _get_response_json, _post_response_json, \ - _csrf_post_response_json +from omeroweb.testlib import IWebTest, _get_response_json, \ + _post_response_json, _csrf_post_response_json from django.core.urlresolvers import reverse, NoReverseMatch from django.conf import settings from django.test import Client From a9b6ca0b07912254678f025f77cd5cddb76ba7e7 Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 19 Jan 2017 13:31:17 +0000 Subject: [PATCH 21/23] Update test_api_login.py to use 'url:' prefix --- .../test/integration/test_api_login.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_login.py b/components/tools/OmeroWeb/test/integration/test_api_login.py index 5785f6d4cc7..3250b09fc42 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_login.py +++ b/components/tools/OmeroWeb/test/integration/test_api_login.py @@ -57,15 +57,15 @@ def test_base_url(self): version = settings.API_VERSIONS[-1] request_url = reverse('api_base', kwargs={'api_version': version}) rsp = _get_response_json(django_client, request_url, {}) - assert 'servers_url' in rsp - assert 'login_url' in rsp - assert 'projects_url' in rsp - assert 'datasets_url' in rsp - assert 'images_url' in rsp - assert 'screens_url' in rsp - assert 'plates_url' in rsp - assert 'save_url' in rsp - assert rsp['schema_url'] == OME_SCHEMA_URL + assert 'url:servers' in rsp + assert 'url:login' in rsp + assert 'url:projects' in rsp + assert 'url:datasets' in rsp + assert 'url:images' in rsp + assert 'url:screens' in rsp + assert 'url:plates' in rsp + assert 'url:save' in rsp + assert rsp['url:schema'] == OME_SCHEMA_URL def test_base_url_versions_404(self): """ @@ -147,13 +147,13 @@ def test_login_example(self): rsp = _get_response_json(django_client, request_url, {}) # Pick the last version version = rsp['data'][-1] - base_url = version['base_url'] + base_url = version['url:base'] # Base url will give a bunch of other urls base_rsp = _get_response_json(django_client, base_url, {}) - login_url = base_rsp['login_url'] - servers_url = base_rsp['servers_url'] - login_url = base_rsp['login_url'] - token_url = base_rsp['token_url'] + login_url = base_rsp['url:login'] + servers_url = base_rsp['url:servers'] + login_url = base_rsp['url:login'] + token_url = base_rsp['url:token'] # See what servers we can log in to servers_rsp = _get_response_json(django_client, servers_url, {}) server_id = servers_rsp['data'][0]['id'] From ff95b03bcd1abadb97e72d03c783ab4630490f54 Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 19 Jan 2017 22:07:25 +0000 Subject: [PATCH 22/23] Fix typo webclint --- .../tools/OmeroWeb/test/integration/test_api_containers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_containers.py b/components/tools/OmeroWeb/test/integration/test_api_containers.py index e8594383ea7..eb4a19d73a9 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_containers.py +++ b/components/tools/OmeroWeb/test/integration/test_api_containers.py @@ -54,9 +54,9 @@ def build_url(client, url_name, url_kwargs): """Build an absolute url using client response url.""" response = client.request() # http://testserver/webclient/ - webclint_url = response.url + webclient_url = response.url url = reverse(url_name, kwargs=url_kwargs) - url = webclint_url.replace('/webclient/', url) + url = webclient_url.replace('/webclient/', url) return url From a364e39ed07c4b0dbfc9e623913f60a23b5fb059 Mon Sep 17 00:00:00 2001 From: William Moore Date: Fri, 20 Jan 2017 09:44:35 +0000 Subject: [PATCH 23/23] Fix missing '_url' -> 'url:' keys in test_api_projects.py --- .../tools/OmeroWeb/test/integration/test_api_projects.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/tools/OmeroWeb/test/integration/test_api_projects.py b/components/tools/OmeroWeb/test/integration/test_api_projects.py index 28da0256fc4..83a867dfc51 100644 --- a/components/tools/OmeroWeb/test/integration/test_api_projects.py +++ b/components/tools/OmeroWeb/test/integration/test_api_projects.py @@ -467,10 +467,10 @@ def test_project_create_read(self): # Need to get the Schema url to create @type base_url = reverse('api_base', kwargs={'api_version': version}) rsp = _get_response_json(django_client, base_url, {}) - schema_url = rsp['schema_url'] + schema_url = rsp['url:schema'] # specify group via query params - save_url = "%s?group=%s" % (rsp['save_url'], group) - projects_url = rsp['projects_url'] + save_url = "%s?group=%s" % (rsp['url:save'], group) + projects_url = rsp['url:projects'] project_name = 'test_api_projects' payload = {'Name': project_name, '@type': schema_url + '#Project'}