From 0dd6d9f8aee5e92b4638474a103f024141904325 Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Tue, 6 Oct 2020 13:09:19 +0000 Subject: [PATCH 01/18] Basic page for entities fitting result list --- weblab/entities/tests/test_views.py | 192 ++++++++++++++++++ weblab/entities/urls.py | 6 + weblab/entities/views.py | 44 +++- weblab/fitting/urls.py | 7 +- .../templates/entities/compare_fittings.html | 60 ++++++ 5 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 weblab/templates/entities/compare_fittings.html diff --git a/weblab/entities/tests/test_views.py b/weblab/entities/tests/test_views.py index fbb97ce27..0a7cd833e 100644 --- a/weblab/entities/tests/test_views.py +++ b/weblab/entities/tests/test_views.py @@ -652,6 +652,198 @@ def test_returns_404_if_commit_not_found(self, client, logged_in_user): assert response.status_code == 404 +@pytest.mark.django_db +class TestModelEntityCompareFittingResultsView: + def test_shows_related_fittings(self, client, logged_in_user, fittingresult_version): + fit = fittingresult_version.fittingresult + fit.model.set_version_visibility('latest', 'public') + fit.author = logged_in_user + fit.save() + + sha = fit.model.repo.latest_commit.sha + recipes.fittingresult_version.make( + fittingresult__author=logged_in_user + ).fittingresult # should not be included, as it uses a different model + + response = client.get( + '/entities/models/%d/versions/%s/fittings' % (fit.model.pk, sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [(fit.dataset, [fit])] + + +@pytest.mark.django_db +class TestEntityCompareFittingResultsView: + def test_shows_fittings_related_to_model_version(self, client, fittingresult_version): + fit = fittingresult_version.fittingresult + + # should not be included, as it uses a different model and version + recipes.fittingresult_version.make() + + # should not be included, as it uses a different version of this model + recipes.fittingresult_version.make(fittingresult__model=fit.model) + + response = client.get( + '/entities/models/%d/versions/%s/fittings' % (fit.model.pk, fit.model_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [(fit.dataset, [fit])] + + def test_groups_by_dataset_for_model(self, client, public_model): + model_version = public_model.repocache.latest_version + dataset1 = recipes.dataset.make(visibility='public') + dataset2 = recipes.dataset.make(visibility='public') + + # Create publicly visible fitting result versions + ds1fit1 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset1, + fittingresult__model=public_model, + fittingresult__model_version=model_version, + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + ) + + ds1fit2 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset1, + fittingresult__model=public_model, + fittingresult__model_version=model_version, + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + ) + + ds2fit1 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset2, + fittingresult__model=public_model, + fittingresult__model_version=model_version, + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + ) + + response = client.get( + '/entities/models/%d/versions/%s/fittings' % (public_model.id, model_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (dataset1, [ds1fit1.fittingresult, ds1fit2.fittingresult]), + (dataset2, [ds2fit1.fittingresult]), + ] + + def test_shows_fittings_related_to_protocol_version(self, client, fittingresult_version): + fit = fittingresult_version.fittingresult + + # should not be included, as it uses a different protocol + recipes.fittingresult_version.make() + + # should not be included, as it uses a different version of this protocol + recipes.fittingresult_version.make(fittingresult__protocol=fit.protocol) + + response = client.get( + '/entities/protocols/%d/versions/%s/fittings' % (fit.protocol.pk, fit.protocol_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [(fit.dataset, [fit])] + + def test_groups_by_dataset_for_protocol(self, client, public_protocol): + protocol_version = public_protocol.repocache.latest_version + dataset1 = recipes.dataset.make(visibility='public') + dataset2 = recipes.dataset.make(visibility='public') + + # Create publicly visible fitting result versions + ds1fit1 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset1, + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + ) + + ds1fit2 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset1, + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + ) + + ds2fit1 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset2, + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + ) + + response = client.get( + '/entities/protocols/%d/versions/%s/fittings' % (public_protocol.id, protocol_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (dataset1, [ds1fit1.fittingresult, ds1fit2.fittingresult]), + (dataset2, [ds2fit1.fittingresult]), + ] + + def test_shows_fittings_related_to_fittingspec_version(self, client, fittingresult_version): + fit = fittingresult_version.fittingresult + + # should not be included, as it uses a different fittingspec + recipes.fittingresult_version.make() + + # should not be included, as it uses a different version of this fittingspec + recipes.fittingresult_version.make(fittingresult__fittingspec=fit.fittingspec) + + response = client.get( + '/fitting/specs/%d/versions/%s/fittings' % (fit.fittingspec.pk, fit.fittingspec_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [(fit.dataset, [fit])] + + def test_groups_by_dataset_for_fittingspec(self, client, public_fittingspec): + fittingspec_version = public_fittingspec.repocache.latest_version + dataset1 = recipes.dataset.make(visibility='public') + dataset2 = recipes.dataset.make(visibility='public') + + # Create publicly visible fitting result versions + ds1fit1 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset1, + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='public', + ) + + ds1fit2 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset1, + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='public', + ) + + ds2fit1 = recipes.fittingresult_version.make( + fittingresult__dataset=dataset2, + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='public', + ) + + response = client.get( + '/fitting/specs/%d/versions/%s/fittings' % (public_fittingspec.id, fittingspec_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (dataset1, [ds1fit1.fittingresult, ds1fit2.fittingresult]), + (dataset2, [ds2fit1.fittingresult]), + ] + + @pytest.mark.django_db class TestEntityComparisonView: def test_loads_entity_versions(self, client, helpers, logged_in_user): diff --git a/weblab/entities/urls.py b/weblab/entities/urls.py index b3ea7cc72..f38c3476e 100644 --- a/weblab/entities/urls.py +++ b/weblab/entities/urls.py @@ -75,6 +75,12 @@ name='version_json', ), + url( + r'^%s/(?P\d+)/versions/%s/fittings$' % (_ENTITY_TYPE, _COMMIT), + views.EntityCompareFittingResultsView.as_view(), + name='compare_fittings', + ), + url( r'^%s/(?P\d+)/versions/%s/compare$' % (_ENTITY_TYPE, _COMMIT), views.EntityCompareExperimentsView.as_view(), diff --git a/weblab/entities/views.py b/weblab/entities/views.py index 989aa302d..82883078d 100644 --- a/weblab/entities/views.py +++ b/weblab/entities/views.py @@ -40,7 +40,7 @@ from accounts.forms import OwnershipTransferForm from core.visibility import Visibility, VisibilityMixin from experiments.models import Experiment, ExperimentVersion, PlannedExperiment -from fitting.models import FittingSpec +from fitting.models import FittingResult, FittingSpec from repocache.exceptions import RepoCacheMiss from repocache.models import CachedProtocolVersion @@ -291,6 +291,48 @@ def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) +class EntityCompareFittingResultsView(EntityTypeMixin, EntityVersionMixin, DetailView): + context_object_name = 'entity' + template_name = 'entities/compare_fittings.html' + + def get_context_data(self, **kwargs): + entity = self._get_object() + version = self.get_version() + + entity_type = entity.entity_type + other_type = 'dataset' + + fittings = FittingResult.objects.filter(**{ + entity_type: entity.pk, + entity_type + '_version': version.pk, + }).annotate( + version_count=Count('versions'), + ) + + if other_type != 'dataset': + fittings = fittings.annotate( + other_version_timestamp=F(other_type + '_version__timestamp'), + ).filter( + version_count__gt=0, + ).select_related(other_type).order_by(other_type, '-other_version_timestamp') + else: + fittings = fittings.filter( + version_count__gt=0, + ).select_related(other_type).order_by(other_type) + + fittings = [ + fit for fit in fittings + if fit.is_visible_to_user(self.request.user) + ] + + kwargs['comparisons'] = [ + (obj, sorted(list(fit), key=lambda x: x.id)) + for (obj, fit) in groupby(fittings, lambda fit: getattr(fit, other_type)) + ] + + return super().get_context_data(**kwargs) + + class EntityComparisonView(EntityTypeMixin, TemplateView): template_name = 'entities/compare.html' diff --git a/weblab/fitting/urls.py b/weblab/fitting/urls.py index 126106bfd..32e42a839 100644 --- a/weblab/fitting/urls.py +++ b/weblab/fitting/urls.py @@ -153,6 +153,12 @@ name='compare_json', ), + url( + r'^%s/(?P\d+)/versions/%s/fittings$' % (_ENTITY_TYPE, _COMMIT), + entity_views.EntityCompareFittingResultsView.as_view(), + name='compare_fittings', + ), + url( r'^%s/compare(?P(/\d+:%s){1,})(?:/show/%s)?$' % (_ENTITY_TYPE, _COMMIT, _FILEVIEW), entity_views.EntityComparisonView.as_view(), @@ -165,7 +171,6 @@ name='compare_json', ), - url( r'^%s/(?P\d+)/versions/%s/download/%s$' % (_ENTITY_TYPE, _COMMIT, _FILENAME), entity_views.EntityFileDownloadView.as_view(), diff --git a/weblab/templates/entities/compare_fittings.html b/weblab/templates/entities/compare_fittings.html new file mode 100644 index 000000000..a63b54663 --- /dev/null +++ b/weblab/templates/entities/compare_fittings.html @@ -0,0 +1,60 @@ +{% extends "entities/entity_version.html" %} +{% load entities %} +{% load experiments %} +{% load staticfiles %} + +{% block title %}{{ type|capfirst }}: compare {{ other_type }}s - {% endblock title %} + +{% block content_detail %} +
+

Fitting Experiments using this {{type}}

+

+ This {{type}} has been run with the following {{other_type}}s. + Click to view the latest results of each single fitting experiment, or select multiple fitting experiments to compare them. +

+ +
+ +
+ +
+ [select all] + [select latest] + [select none] +
+ + +
+
+{% endblock content_detail %} From 7d2f18773f66e4061761dc939e97fcd32f1fe593 Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Thu, 8 Oct 2020 11:32:09 +0000 Subject: [PATCH 02/18] Group entity fitting results by dataset and model --- weblab/entities/templatetags/entities.py | 10 ++ weblab/entities/tests/test_views.py | 126 +++++++++--------- weblab/entities/views.py | 31 ++--- .../templates/entities/compare_fittings.html | 22 ++- 4 files changed, 97 insertions(+), 92 deletions(-) diff --git a/weblab/entities/templatetags/entities.py b/weblab/entities/templatetags/entities.py index e42cc8a15..b7715d72b 100644 --- a/weblab/entities/templatetags/entities.py +++ b/weblab/entities/templatetags/entities.py @@ -123,6 +123,16 @@ def name_of_protocol(experiment): return '%s @ %s' % (experiment.protocol.name, experiment.protocol_version.get_name()) +@register.filter +def name_of_dataset(experiment): + return '%s' % (experiment.dataset.name) + + +@register.filter +def name_of_fittingspec(experiment): + return '%s @ %s' % (experiment.fittingspec.name, experiment.fittingspec_version.get_name()) + + def _url_friendly_label(entity, version): """ Get URL-friendly version label for a commit diff --git a/weblab/entities/tests/test_views.py b/weblab/entities/tests/test_views.py index 0a7cd833e..666a2e5c5 100644 --- a/weblab/entities/tests/test_views.py +++ b/weblab/entities/tests/test_views.py @@ -652,27 +652,6 @@ def test_returns_404_if_commit_not_found(self, client, logged_in_user): assert response.status_code == 404 -@pytest.mark.django_db -class TestModelEntityCompareFittingResultsView: - def test_shows_related_fittings(self, client, logged_in_user, fittingresult_version): - fit = fittingresult_version.fittingresult - fit.model.set_version_visibility('latest', 'public') - fit.author = logged_in_user - fit.save() - - sha = fit.model.repo.latest_commit.sha - recipes.fittingresult_version.make( - fittingresult__author=logged_in_user - ).fittingresult # should not be included, as it uses a different model - - response = client.get( - '/entities/models/%d/versions/%s/fittings' % (fit.model.pk, sha) - ) - - assert response.status_code == 200 - assert response.context['comparisons'] == [(fit.dataset, [fit])] - - @pytest.mark.django_db class TestEntityCompareFittingResultsView: def test_shows_fittings_related_to_model_version(self, client, fittingresult_version): @@ -693,8 +672,7 @@ def test_shows_fittings_related_to_model_version(self, client, fittingresult_ver def test_groups_by_dataset_for_model(self, client, public_model): model_version = public_model.repocache.latest_version - dataset1 = recipes.dataset.make(visibility='public') - dataset2 = recipes.dataset.make(visibility='public') + dataset1, dataset2 = recipes.dataset.make(_quantity=2, visibility='public') # Create publicly visible fitting result versions ds1fit1 = recipes.fittingresult_version.make( @@ -703,7 +681,7 @@ def test_groups_by_dataset_for_model(self, client, public_model): fittingresult__model_version=model_version, fittingresult__protocol_version__visibility='public', fittingresult__fittingspec_version__visibility='public', - ) + ).fittingresult ds1fit2 = recipes.fittingresult_version.make( fittingresult__dataset=dataset1, @@ -711,7 +689,7 @@ def test_groups_by_dataset_for_model(self, client, public_model): fittingresult__model_version=model_version, fittingresult__protocol_version__visibility='public', fittingresult__fittingspec_version__visibility='public', - ) + ).fittingresult ds2fit1 = recipes.fittingresult_version.make( fittingresult__dataset=dataset2, @@ -719,7 +697,7 @@ def test_groups_by_dataset_for_model(self, client, public_model): fittingresult__model_version=model_version, fittingresult__protocol_version__visibility='public', fittingresult__fittingspec_version__visibility='public', - ) + ).fittingresult response = client.get( '/entities/models/%d/versions/%s/fittings' % (public_model.id, model_version.sha) @@ -727,8 +705,8 @@ def test_groups_by_dataset_for_model(self, client, public_model): assert response.status_code == 200 assert response.context['comparisons'] == [ - (dataset1, [ds1fit1.fittingresult, ds1fit2.fittingresult]), - (dataset2, [ds2fit1.fittingresult]), + (dataset1, [ds1fit1, ds1fit2]), + (dataset2, [ds2fit1]), ] def test_shows_fittings_related_to_protocol_version(self, client, fittingresult_version): @@ -745,37 +723,42 @@ def test_shows_fittings_related_to_protocol_version(self, client, fittingresult_ ) assert response.status_code == 200 - assert response.context['comparisons'] == [(fit.dataset, [fit])] + assert response.context['comparisons'] == [(fit.dataset, [(fit.model, [fit])])] - def test_groups_by_dataset_for_protocol(self, client, public_protocol): + def test_groups_by_dataset_for_protocol(self, client, helpers, public_protocol): protocol_version = public_protocol.repocache.latest_version - dataset1 = recipes.dataset.make(visibility='public') - dataset2 = recipes.dataset.make(visibility='public') + ds1, ds2 = recipes.dataset.make(_quantity=2, visibility='public') + m1, m2 = recipes.model.make(_quantity=2) + m1v = helpers.add_cached_version(m1, visibility='public') + m2v = helpers.add_cached_version(m2, visibility='public') # Create publicly visible fitting result versions - ds1fit1 = recipes.fittingresult_version.make( - fittingresult__dataset=dataset1, + fit1_ds1_m1 = recipes.fittingresult_version.make( + fittingresult__dataset=ds1, fittingresult__protocol=public_protocol, fittingresult__protocol_version=protocol_version, - fittingresult__model_version__visibility='public', + fittingresult__model=m1, + fittingresult__model_version=m1v, fittingresult__fittingspec_version__visibility='public', - ) + ).fittingresult - ds1fit2 = recipes.fittingresult_version.make( - fittingresult__dataset=dataset1, + fit2_ds1_m2 = recipes.fittingresult_version.make( + fittingresult__dataset=ds1, fittingresult__protocol=public_protocol, fittingresult__protocol_version=protocol_version, - fittingresult__model_version__visibility='public', + fittingresult__model=m2, + fittingresult__model_version=m2v, fittingresult__fittingspec_version__visibility='public', - ) + ).fittingresult - ds2fit1 = recipes.fittingresult_version.make( - fittingresult__dataset=dataset2, + fit3_ds2_m1 = recipes.fittingresult_version.make( + fittingresult__dataset=ds2, fittingresult__protocol=public_protocol, fittingresult__protocol_version=protocol_version, - fittingresult__model_version__visibility='public', + fittingresult__model=m1, + fittingresult__model_version=m1v, fittingresult__fittingspec_version__visibility='public', - ) + ).fittingresult response = client.get( '/entities/protocols/%d/versions/%s/fittings' % (public_protocol.id, protocol_version.sha) @@ -783,8 +766,13 @@ def test_groups_by_dataset_for_protocol(self, client, public_protocol): assert response.status_code == 200 assert response.context['comparisons'] == [ - (dataset1, [ds1fit1.fittingresult, ds1fit2.fittingresult]), - (dataset2, [ds2fit1.fittingresult]), + (ds1, [ + (m1, [fit1_ds1_m1]), + (m2, [fit2_ds1_m2]), + ]), + (ds2, [ + (m1, [fit3_ds2_m1]), + ]), ] def test_shows_fittings_related_to_fittingspec_version(self, client, fittingresult_version): @@ -801,37 +789,42 @@ def test_shows_fittings_related_to_fittingspec_version(self, client, fittingresu ) assert response.status_code == 200 - assert response.context['comparisons'] == [(fit.dataset, [fit])] + assert response.context['comparisons'] == [(fit.dataset, [(fit.model, [fit])])] - def test_groups_by_dataset_for_fittingspec(self, client, public_fittingspec): + def test_groups_by_dataset_for_fittingspec(self, client, helpers, public_fittingspec): fittingspec_version = public_fittingspec.repocache.latest_version - dataset1 = recipes.dataset.make(visibility='public') - dataset2 = recipes.dataset.make(visibility='public') + ds1, ds2 = recipes.dataset.make(_quantity=2, visibility='public') + m1, m2 = recipes.model.make(_quantity=2) + m1v = helpers.add_cached_version(m1, visibility='public') + m2v = helpers.add_cached_version(m2, visibility='public') # Create publicly visible fitting result versions - ds1fit1 = recipes.fittingresult_version.make( - fittingresult__dataset=dataset1, + fit1_ds1_m1 = recipes.fittingresult_version.make( + fittingresult__dataset=ds1, fittingresult__fittingspec=public_fittingspec, fittingresult__fittingspec_version=fittingspec_version, - fittingresult__model_version__visibility='public', + fittingresult__model=m1, + fittingresult__model_version=m1v, fittingresult__protocol_version__visibility='public', - ) + ).fittingresult - ds1fit2 = recipes.fittingresult_version.make( - fittingresult__dataset=dataset1, + fit2_ds1_m2 = recipes.fittingresult_version.make( + fittingresult__dataset=ds1, fittingresult__fittingspec=public_fittingspec, fittingresult__fittingspec_version=fittingspec_version, - fittingresult__model_version__visibility='public', + fittingresult__model=m2, + fittingresult__model_version=m2v, fittingresult__protocol_version__visibility='public', - ) + ).fittingresult - ds2fit1 = recipes.fittingresult_version.make( - fittingresult__dataset=dataset2, + fit3_ds2_m1 = recipes.fittingresult_version.make( + fittingresult__dataset=ds2, fittingresult__fittingspec=public_fittingspec, fittingresult__fittingspec_version=fittingspec_version, - fittingresult__model_version__visibility='public', + fittingresult__model=m1, + fittingresult__model_version=m1v, fittingresult__protocol_version__visibility='public', - ) + ).fittingresult response = client.get( '/fitting/specs/%d/versions/%s/fittings' % (public_fittingspec.id, fittingspec_version.sha) @@ -839,8 +832,13 @@ def test_groups_by_dataset_for_fittingspec(self, client, public_fittingspec): assert response.status_code == 200 assert response.context['comparisons'] == [ - (dataset1, [ds1fit1.fittingresult, ds1fit2.fittingresult]), - (dataset2, [ds2fit1.fittingresult]), + (ds1, [ + (m1, [fit1_ds1_m1]), + (m2, [fit2_ds1_m2]), + ]), + (ds2, [ + (m1, [fit3_ds2_m1]), + ]), ] diff --git a/weblab/entities/views.py b/weblab/entities/views.py index 82883078d..8d2a84c5d 100644 --- a/weblab/entities/views.py +++ b/weblab/entities/views.py @@ -300,36 +300,37 @@ def get_context_data(self, **kwargs): version = self.get_version() entity_type = entity.entity_type - other_type = 'dataset' fittings = FittingResult.objects.filter(**{ entity_type: entity.pk, entity_type + '_version': version.pk, }).annotate( version_count=Count('versions'), - ) - - if other_type != 'dataset': - fittings = fittings.annotate( - other_version_timestamp=F(other_type + '_version__timestamp'), - ).filter( - version_count__gt=0, - ).select_related(other_type).order_by(other_type, '-other_version_timestamp') - else: - fittings = fittings.filter( - version_count__gt=0, - ).select_related(other_type).order_by(other_type) + ).filter( + version_count__gt=0, + ).select_related('dataset', 'model').order_by('dataset', 'model') + # Ensure all are visible to user fittings = [ fit for fit in fittings if fit.is_visible_to_user(self.request.user) ] + def by_subgroup(fits): + if entity_type == 'model': + return sorted(list(fits), key=lambda x: x.id) + else: + return [ + (obj, sorted(list(subfits), key=lambda x: x.id)) + for (obj, subfits) in groupby(fits, lambda fit: fit.model) + ] + kwargs['comparisons'] = [ - (obj, sorted(list(fit), key=lambda x: x.id)) - for (obj, fit) in groupby(fittings, lambda fit: getattr(fit, other_type)) + (obj, by_subgroup(fits)) + for (obj, fits) in groupby(fittings, lambda fit: fit.dataset) ] + return super().get_context_data(**kwargs) diff --git a/weblab/templates/entities/compare_fittings.html b/weblab/templates/entities/compare_fittings.html index a63b54663..7ec9d14ef 100644 --- a/weblab/templates/entities/compare_fittings.html +++ b/weblab/templates/entities/compare_fittings.html @@ -1,49 +1,45 @@ {% extends "entities/entity_version.html" %} {% load entities %} -{% load experiments %} +{% load fittings %} {% load staticfiles %} -{% block title %}{{ type|capfirst }}: compare {{ other_type }}s - {% endblock title %} +{% block title %}{{ type|capfirst }}: compare fitting experiments - {% endblock title %} {% block content_detail %}

Fitting Experiments using this {{type}}

- This {{type}} has been run with the following {{other_type}}s. + This {{type}} has been run with the following datasets. Click to view the latest results of each single fitting experiment, or select multiple fitting experiments to compare them.

@@ -54,7 +50,7 @@

Fitting Experiments using this {{type}}

[select none]
- +
{% endblock content_detail %} From 69af911aeeb4f9d8c4890c754d8637e241366343 Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Thu, 8 Oct 2020 13:59:41 +0000 Subject: [PATCH 03/18] List fittings for an entity --- weblab/fitting/templatetags/__init__.py | 0 weblab/fitting/templatetags/fittings.py | 18 ++++++ .../templates/entities/compare_fittings.html | 57 +++++++++++-------- 3 files changed, 52 insertions(+), 23 deletions(-) create mode 100644 weblab/fitting/templatetags/__init__.py create mode 100644 weblab/fitting/templatetags/fittings.py diff --git a/weblab/fitting/templatetags/__init__.py b/weblab/fitting/templatetags/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/weblab/fitting/templatetags/fittings.py b/weblab/fitting/templatetags/fittings.py new file mode 100644 index 000000000..8b946aced --- /dev/null +++ b/weblab/fitting/templatetags/fittings.py @@ -0,0 +1,18 @@ +from django import template +from django.core.urlresolvers import reverse + + +register = template.Library() + + +@register.simple_tag +def url_fitting_comparison_base(): + """ + Base URL for fitting result comparison page + """ + # Use dummy IDs to set up a comparison URL, then chop them off to + # get the base. This will be used by javascript to generate comparisons + # between fitting result versions. + url = reverse('fitting:result:compare', args=['/1/1']) + return url[:-4] + diff --git a/weblab/templates/entities/compare_fittings.html b/weblab/templates/entities/compare_fittings.html index 7ec9d14ef..ed1eb6d6a 100644 --- a/weblab/templates/entities/compare_fittings.html +++ b/weblab/templates/entities/compare_fittings.html @@ -15,31 +15,42 @@

Fitting Experiments using this {{type}}

From e61f85d35f539c46ea52eb12ab824dd8ce4430f7 Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Fri, 9 Oct 2020 12:24:44 +0000 Subject: [PATCH 04/18] Collapse multiple model versions on fitting list --- weblab/entities/tests/test_views.py | 94 +++++++++++++++++++ weblab/entities/views.py | 13 ++- weblab/static/js/entity.js | 2 +- .../entities/compare_experiments.html | 2 +- .../templates/entities/compare_fittings.html | 49 +++++++--- 5 files changed, 140 insertions(+), 20 deletions(-) diff --git a/weblab/entities/tests/test_views.py b/weblab/entities/tests/test_views.py index 666a2e5c5..ee9dc25ec 100644 --- a/weblab/entities/tests/test_views.py +++ b/weblab/entities/tests/test_views.py @@ -775,6 +775,53 @@ def test_groups_by_dataset_for_protocol(self, client, helpers, public_protocol): ]), ] + def test_multiple_model_versions_for_protocol_version(self, client, helpers, public_protocol, public_dataset): + protocol_version = public_protocol.repocache.latest_version + m1, m2 = recipes.model.make(_quantity=2) + m1v1 = helpers.add_cached_version(m1, visibility='public') + m1v2 = helpers.add_cached_version(m1, visibility='public') + m2v = helpers.add_cached_version(m2, visibility='public') + + # Create publicly visible fitting result versions + fit1_m1v1 = recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model=m1, + fittingresult__model_version=m1v1, + fittingresult__fittingspec_version__visibility='public', + ).fittingresult + + fit2_m1v2 = recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model=m1, + fittingresult__model_version=m1v2, + fittingresult__fittingspec_version__visibility='public', + ).fittingresult + + fit3_m2v = recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model=m2, + fittingresult__model_version=m2v, + fittingresult__fittingspec_version__visibility='public', + ).fittingresult + + response = client.get( + '/entities/protocols/%d/versions/%s/fittings' % (public_protocol.id, protocol_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (public_dataset, [ + (m1, [fit1_m1v1, fit2_m1v2]), + (m2, [fit3_m2v]), + ]), + ] + def test_shows_fittings_related_to_fittingspec_version(self, client, fittingresult_version): fit = fittingresult_version.fittingresult @@ -841,6 +888,53 @@ def test_groups_by_dataset_for_fittingspec(self, client, helpers, public_fitting ]), ] + def test_multiple_model_versions_for_fittingspec_version(self, client, helpers, public_fittingspec, public_dataset): + fittingspec_version = public_fittingspec.repocache.latest_version + m1, m2 = recipes.model.make(_quantity=2) + m1v1 = helpers.add_cached_version(m1, visibility='public') + m1v2 = helpers.add_cached_version(m1, visibility='public') + m2v = helpers.add_cached_version(m2, visibility='public') + + # Create publicly visible fitting result versions + fit1_m1v1 = recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model=m1, + fittingresult__model_version=m1v1, + fittingresult__protocol_version__visibility='public', + ).fittingresult + + fit2_m1v2 = recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model=m1, + fittingresult__model_version=m1v2, + fittingresult__protocol_version__visibility='public', + ).fittingresult + + fit3_m2v = recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model=m2, + fittingresult__model_version=m2v, + fittingresult__protocol_version__visibility='public', + ).fittingresult + + response = client.get( + '/fitting/specs/%d/versions/%s/fittings' % (public_fittingspec.id, fittingspec_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (public_dataset, [ + (m1, [fit1_m1v1, fit2_m1v2]), + (m2, [fit3_m2v]), + ]), + ] + @pytest.mark.django_db class TestEntityComparisonView: diff --git a/weblab/entities/views.py b/weblab/entities/views.py index 8d2a84c5d..26a798ffa 100644 --- a/weblab/entities/views.py +++ b/weblab/entities/views.py @@ -308,7 +308,10 @@ def get_context_data(self, **kwargs): version_count=Count('versions'), ).filter( version_count__gt=0, - ).select_related('dataset', 'model').order_by('dataset', 'model') + ).select_related( + 'dataset', + 'model', + ).order_by('dataset', 'model', '-model_version__timestamp') # Ensure all are visible to user fittings = [ @@ -316,12 +319,15 @@ def get_context_data(self, **kwargs): if fit.is_visible_to_user(self.request.user) ] + def _sorted_fittings(fits): + return sorted(list(fits), key=lambda x: x.id) + def by_subgroup(fits): if entity_type == 'model': - return sorted(list(fits), key=lambda x: x.id) + return _sorted_fittings(fits) else: return [ - (obj, sorted(list(subfits), key=lambda x: x.id)) + (obj, _sorted_fittings(subfits)) for (obj, subfits) in groupby(fits, lambda fit: fit.model) ] @@ -330,7 +336,6 @@ def by_subgroup(fits): for (obj, fits) in groupby(fittings, lambda fit: fit.dataset) ] - return super().get_context_data(**kwargs) diff --git a/weblab/static/js/entity.js b/weblab/static/js/entity.js index 7c09684ff..cbc9a8c20 100644 --- a/weblab/static/js/entity.js +++ b/weblab/static/js/entity.js @@ -878,7 +878,7 @@ function init() { }); $("#entityexperimentlist_showallversions").click(function () { $(this).toggleClass("selected"); - $exp_list.find("ul").toggle(); + $exp_list.find("ul.all-versions").toggle(); $("#entityexperimentlist_span_latest").toggle(); return false; }); diff --git a/weblab/templates/entities/compare_experiments.html b/weblab/templates/entities/compare_experiments.html index 9f328ddcc..d2a16b4bd 100644 --- a/weblab/templates/entities/compare_experiments.html +++ b/weblab/templates/entities/compare_experiments.html @@ -27,7 +27,7 @@

Experiments using this {{type}}

{% endif %} {% if experiments|length > 1 %} -
    + + + +
    + [select all] + [select latest] + [select none] +
    + + +
    + +{% endblock content_detail %} diff --git a/weblab/templates/datasets/dataset_detail.html b/weblab/templates/datasets/dataset_detail.html index 7a117110d..81e516783 100644 --- a/weblab/templates/datasets/dataset_detail.html +++ b/weblab/templates/datasets/dataset_detail.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "datasets/base.html" %} {% load staticfiles %} {% load datasets %} @@ -6,76 +6,31 @@ {% block body_id %}experiment-version{% endblock %} -{% block content %} - {% include "./includes/dataset_header.html" %} - -
    - -
    -
    -
    -
    - - Created - by {{ dataset.author.full_name }}. - Visibility: {{ dataset.visibility }} - help. - -{% comment %} - {% can_delete_entity version as can_delete %} - {% if can_delete %} - Delete experiment version: - - delete this version of this experiment - {% endif %} -{% endcomment %} - -
    Corresponding protocol: - {{ dataset.protocol.name }} - -
    -
    - - -

    - {{ dataset.description }} -

    - -
    -
    - -
    -
    - -

    -
    Created by - .
    -
    -
    +{% block content_detail %} +
    +
    + +

    +
    Created by + .
    +
    +
    -
    -

    Files in this dataset

    -

    - -
    - - Download - Download archive of all files - -
    -
    -
    +
    +

    Files in this dataset

    +

    + +
    + + Download + Download archive of all files + +
    -{% endblock %} +
    +{% endblock content_detail %} From 51304fb4f051728ff289a012261be99d68595aee Mon Sep 17 00:00:00 2001 From: Jonathan Cooper Date: Thu, 15 Oct 2020 09:38:44 +0100 Subject: [PATCH 10/18] List latest protocol version first --- weblab/datasets/tests/test_views.py | 2 +- weblab/datasets/views.py | 2 +- weblab/entities/tests/test_views.py | 2 +- weblab/entities/views.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/weblab/datasets/tests/test_views.py b/weblab/datasets/tests/test_views.py index 379abf124..635d883cd 100644 --- a/weblab/datasets/tests/test_views.py +++ b/weblab/datasets/tests/test_views.py @@ -686,7 +686,7 @@ def test_groups_by_model(self, client, helpers, public_dataset): assert response.status_code == 200 assert response.context['comparisons'] == [ - (m1, [fit1_m1, fit2_m1]), + (m1, [fit2_m1, fit1_m1]), (m2, [fit3_m2]), ] diff --git a/weblab/datasets/views.py b/weblab/datasets/views.py index 727938ff0..53a4cae9e 100644 --- a/weblab/datasets/views.py +++ b/weblab/datasets/views.py @@ -355,7 +355,7 @@ def get_context_data(self, **kwargs): dataset=dataset.pk, ).select_related( 'model', - ).order_by('model', '-model_version__timestamp') + ).order_by('model', '-model_version__timestamp', '-protocol_version__timestamp') # Ensure all are visible to user fittings = [ diff --git a/weblab/entities/tests/test_views.py b/weblab/entities/tests/test_views.py index 7bc100573..e8b907f4e 100644 --- a/weblab/entities/tests/test_views.py +++ b/weblab/entities/tests/test_views.py @@ -705,7 +705,7 @@ def test_groups_by_dataset_for_model(self, client, public_model): assert response.status_code == 200 assert response.context['comparisons'] == [ - (dataset1, [ds1fit1, ds1fit2]), + (dataset1, [ds1fit2, ds1fit1]), (dataset2, [ds2fit1]), ] diff --git a/weblab/entities/views.py b/weblab/entities/views.py index fc6ee9d43..fdaff08f7 100644 --- a/weblab/entities/views.py +++ b/weblab/entities/views.py @@ -314,7 +314,7 @@ def get_context_data(self, **kwargs): ).select_related( 'dataset', 'model', - ).order_by('dataset', 'model', '-model_version__timestamp') + ).order_by('dataset', 'model', '-model_version__timestamp', '-protocol_version__timestamp') # Ensure all are visible to user fittings = [ From 4bc0abeee60c333c3b5c6081e0250e861d18474f Mon Sep 17 00:00:00 2001 From: Jonathan Cooper Date: Thu, 15 Oct 2020 09:41:00 +0100 Subject: [PATCH 11/18] Show Compare... button last --- weblab/templates/entities/entity_version.html | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/weblab/templates/entities/entity_version.html b/weblab/templates/entities/entity_version.html index c4f61809d..12a0b6e26 100644 --- a/weblab/templates/entities/entity_version.html +++ b/weblab/templates/entities/entity_version.html @@ -56,6 +56,12 @@

    {% if permission %} Add version {% endif %} + {% if entity.entity_type == 'model' %} + Fit + {% else %} + Fit + {% endif %} + Fittings
    Compare…
    - {% if entity.entity_type == 'model' %} - Fit - {% elif entity.entity_type == 'protocol' %} - Fit - {% elif entity.entity_type == 'fittingspec' %} - Fit - {% endif %} - Fittings

    {% block content_detail %} From 40e0b5b7186c8aa0cffa7f466dc861e3e8164516 Mon Sep 17 00:00:00 2001 From: Jonathan Cooper Date: Thu, 15 Oct 2020 09:46:53 +0100 Subject: [PATCH 12/18] Various improvements to display --- .../templates/datasets/compare_fittings.html | 40 ++++---- .../templates/entities/compare_fittings.html | 99 +++++++++---------- 2 files changed, 67 insertions(+), 72 deletions(-) diff --git a/weblab/templates/datasets/compare_fittings.html b/weblab/templates/datasets/compare_fittings.html index 93efb4cdc..483d7abdc 100644 --- a/weblab/templates/datasets/compare_fittings.html +++ b/weblab/templates/datasets/compare_fittings.html @@ -9,38 +9,34 @@

    Fitting Experiments run with this dataset

    - This dataset has been run with the following models. + The following models have been fit to this dataset. Click to view the latest results of each single fitting experiment, or select multiple fitting experiments to compare them.

    -
      - {% for model, fittings in comparisons %} -
    • - {% with fittings.0.model_version as latest_model_version %} - {{ model }} - - {% endwith %} -
    • - {% endfor %} -
    + {% for model, fittings in comparisons %} + {% with fittings.0.model_version as latest_model_version %} +

    {{ model }}

    + + {% endwith %} + {% endfor %}
    [select all] - [select latest] + [select latest model versions] [select none]
    - +
    diff --git a/weblab/templates/entities/compare_fittings.html b/weblab/templates/entities/compare_fittings.html index c6fe74dd6..1a6a95291 100644 --- a/weblab/templates/entities/compare_fittings.html +++ b/weblab/templates/entities/compare_fittings.html @@ -9,69 +9,68 @@

    Fitting Experiments using this {{type}}

    - This {{type}} has been run with the following datasets. - Click to view the latest results of each single fitting experiment, or select multiple fitting experiments to compare them. + {% if entity.entity_type == 'model' %} + This model has been fit to the following datasets. + {% else %} + This {{type}} has been run with the following datasets and models. + {% endif %} + Click to view the latest results of each single fitting experiment, or select multiple fitting experiments to compare them.

    - + {% endif %} + {% endfor %}
    [select all] - [select latest] + [select latest model versions] [select none]
    - +
    From 02bc7bb4fbcbb4c29634a85a2eccc11ed191e16c Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Thu, 15 Oct 2020 10:39:16 +0000 Subject: [PATCH 13/18] Don't display 'show all versions' button for model --- weblab/templates/entities/compare_fittings.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/weblab/templates/entities/compare_fittings.html b/weblab/templates/entities/compare_fittings.html index 1a6a95291..7c0eafe03 100644 --- a/weblab/templates/entities/compare_fittings.html +++ b/weblab/templates/entities/compare_fittings.html @@ -70,7 +70,9 @@

    {{ dataset }}

    [select latest model versions] [select none]
    + {% if entity.entity_type != 'model' %} + {% endif %} From a9c41a8b41288a13bfb1d1ca1742e93a4fe3514e Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Thu, 15 Oct 2020 10:48:45 +0000 Subject: [PATCH 14/18] Fix "select latest versions" button --- weblab/static/js/entity.js | 1 + 1 file changed, 1 insertion(+) diff --git a/weblab/static/js/entity.js b/weblab/static/js/entity.js index 70f5a6860..39b62cb7d 100644 --- a/weblab/static/js/entity.js +++ b/weblab/static/js/entity.js @@ -875,6 +875,7 @@ function init() { }); $("#entityexperimentlistpartnersactlatest").click(function () { $exp_list.children("li").children("input").prop('checked', true); + $exp_list.find(".latest-model-version").children("input").prop('checked', true); }); $("#entityexperimentlist_showallversions").click(function () { $(this).toggleClass("selected"); From cdd84db2892891d1bae29fceeaa8786ce25a5b4b Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Thu, 15 Oct 2020 12:04:52 +0000 Subject: [PATCH 15/18] Add visibility form to experiment list pages --- weblab/entities/tests/test_views.py | 10 +++++++ weblab/entities/views.py | 28 ++++++++++--------- weblab/static/js/entity.js | 20 +++++++++++++ weblab/templates/entities/entity_version.html | 1 + 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/weblab/entities/tests/test_views.py b/weblab/entities/tests/test_views.py index e8b907f4e..faeee5ea2 100644 --- a/weblab/entities/tests/test_views.py +++ b/weblab/entities/tests/test_views.py @@ -540,6 +540,11 @@ def test_complex_visibilities(self, client, logged_in_user, other_user, helpers) @pytest.mark.django_db class TestModelEntityCompareExperimentsView: + def test_has_visibility_form(self, client, helpers, public_model): + response = client.get('/entities/models/%d/versions/%s/compare' % + (public_model.pk, public_model.repocache.latest_version.sha)) + assert 'form' in response.context + def test_shows_related_experiments(self, client, helpers, experiment_version): exp = experiment_version.experiment model_version = exp.model.repocache.latest_version @@ -654,6 +659,11 @@ def test_returns_404_if_commit_not_found(self, client, logged_in_user): @pytest.mark.django_db class TestEntityCompareFittingResultsView: + def test_has_visibility_form(self, client, helpers, public_model): + response = client.get('/entities/models/%d/versions/%s/fittings' % + (public_model.pk, public_model.repocache.latest_version.sha)) + assert 'form' in response.context + def test_shows_fittings_related_to_model_version(self, client, fittingresult_version): fit = fittingresult_version.fittingresult diff --git a/weblab/entities/views.py b/weblab/entities/views.py index fdaff08f7..c976d38fe 100644 --- a/weblab/entities/views.py +++ b/weblab/entities/views.py @@ -89,6 +89,18 @@ def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) +class EntityVisibilityFormMixin: + def get_context_data(self, **kwargs): + entity = self._get_object() + visibility = entity.get_version_visibility(self.get_version().sha) + kwargs['form'] = EntityChangeVisibilityForm( + user=self.request.user, + initial={ + 'visibility': visibility, + }) + return super().get_context_data(**kwargs) + + class EntityVersionMixin(VisibilityMixin): """ Mixin for views describing a specific version of an `Entity` object @@ -201,23 +213,13 @@ def get_queryset(self): return self.model.objects.filter(author=self.request.user) -class EntityVersionView(EntityTypeMixin, EntityVersionMixin, DetailView): +class EntityVersionView(EntityTypeMixin, EntityVisibilityFormMixin, EntityVersionMixin, DetailView): """ View a version of an entity """ context_object_name = 'entity' template_name = 'entities/entity_version.html' - def get_context_data(self, **kwargs): - entity = self._get_object() - visibility = entity.get_version_visibility(self.get_version().sha) - kwargs['form'] = EntityChangeVisibilityForm( - user=self.request.user, - initial={ - 'visibility': visibility, - }) - return super().get_context_data(**kwargs) - class EntityVersionJsonView(EntityTypeMixin, EntityVersionMixin, SingleObjectMixin, View): def _planned_experiments(self, user): @@ -257,7 +259,7 @@ def get(self, request, *args, **kwargs): }) -class EntityCompareExperimentsView(EntityTypeMixin, EntityVersionMixin, DetailView): +class EntityCompareExperimentsView(EntityTypeMixin, EntityVisibilityFormMixin, EntityVersionMixin, DetailView): context_object_name = 'entity' template_name = 'entities/compare_experiments.html' @@ -291,7 +293,7 @@ def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) -class EntityCompareFittingResultsView(EntityTypeMixin, EntityVersionMixin, DetailView): +class EntityCompareFittingResultsView(EntityTypeMixin, EntityVisibilityFormMixin, EntityVersionMixin, DetailView): """ List fitting results for this entity, with selection boxes for comparison """ diff --git a/weblab/static/js/entity.js b/weblab/static/js/entity.js index 39b62cb7d..71e08b8e9 100644 --- a/weblab/static/js/entity.js +++ b/weblab/static/js/entity.js @@ -683,6 +683,21 @@ function init() { render (); } + function renderExperimentList() + { + if (!curVersion) { + var jsonUrl = $('#entityversion').data('version-json-href'); + $.getJSON(jsonUrl, function(data) { + notifications.display(data); + if (data.version) { + curVersion = data.version; + $('#entityversion').data('version-json', curVersion); + updateVersion(curVersion); + } + }); + } + } + function render () { @@ -806,6 +821,11 @@ function init() { render (); } + if (doc.version.experimentlist) { + window.onpopstate = renderExperimentList; + renderExperimentList(); + } + var $visibility = $(doc.version.visibility); $visibility.on( 'change', diff --git a/weblab/templates/entities/entity_version.html b/weblab/templates/entities/entity_version.html index 12a0b6e26..68c132de4 100644 --- a/weblab/templates/entities/entity_version.html +++ b/weblab/templates/entities/entity_version.html @@ -17,6 +17,7 @@ data-can-edit="{% if permission %}true{% else %}false{% endif %}" data-alter-file-href="{% entity_url 'alter_file' entity %}" data-get-proto-interfaces-href="{% url 'entities:get_protocol_interfaces' %}" + data-version-id="{{ version }}" data-version-json-href="{% entity_version_url 'version_json' entity version %}">

    From ef824cbea5639fabcb80fad27ca786ad88d333f5 Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Thu, 15 Oct 2020 15:33:05 +0000 Subject: [PATCH 16/18] Test private fitting results are not listed --- weblab/datasets/tests/test_views.py | 38 ++++++++ weblab/entities/tests/test_views.py | 131 ++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) diff --git a/weblab/datasets/tests/test_views.py b/weblab/datasets/tests/test_views.py index 635d883cd..981822746 100644 --- a/weblab/datasets/tests/test_views.py +++ b/weblab/datasets/tests/test_views.py @@ -730,3 +730,41 @@ def test_multiple_model_versions_for_dataset(self, client, helpers, public_datas (m1, [fit2_m1v2, fit1_m1v1]), (m2, [fit3_m2v]), ] + + def test_ensure_private_results_are_not_shown(self, client, public_dataset): + recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__model_version__visibility='private', + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + ).fittingresult + + recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='private', + fittingresult__fittingspec_version__visibility='public', + ).fittingresult + + recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='private', + ).fittingresult + + fit = recipes.fittingresult_version.make( + fittingresult__dataset=public_dataset, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + ).fittingresult + + response = client.get( + '/datasets/%d/fittings' % public_dataset.id + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (fit.model, [fit]), + ] diff --git a/weblab/entities/tests/test_views.py b/weblab/entities/tests/test_views.py index faeee5ea2..d09240056 100644 --- a/weblab/entities/tests/test_views.py +++ b/weblab/entities/tests/test_views.py @@ -719,6 +719,49 @@ def test_groups_by_dataset_for_model(self, client, public_model): (dataset2, [ds2fit1]), ] + def test_ensure_private_results_are_not_shown_for_model_version(self, client, public_model): + model_version = public_model.repocache.latest_version + recipes.fittingresult_version.make( + fittingresult__model=public_model, + fittingresult__model_version=model_version, + fittingresult__protocol_version__visibility='private', + fittingresult__fittingspec_version__visibility='public', + fittingresult__dataset__visibility='public' + ).fittingresult + + recipes.fittingresult_version.make( + fittingresult__model=public_model, + fittingresult__model_version=model_version, + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='private', + fittingresult__dataset__visibility='public' + ).fittingresult + + recipes.fittingresult_version.make( + fittingresult__model=public_model, + fittingresult__model_version=model_version, + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + fittingresult__dataset__visibility='private' + ).fittingresult + + fit = recipes.fittingresult_version.make( + fittingresult__model=public_model, + fittingresult__model_version=model_version, + fittingresult__protocol_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + fittingresult__dataset__visibility='public' + ).fittingresult + + response = client.get( + '/entities/models/%d/versions/%s/fittings' % (public_model.id, model_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (fit.dataset, [fit]), + ] + def test_shows_fittings_related_to_protocol_version(self, client, fittingresult_version): fit = fittingresult_version.fittingresult @@ -832,6 +875,50 @@ def test_multiple_model_versions_for_protocol_version(self, client, helpers, pub ]), ] + def test_ensure_private_results_are_not_shown_for_protocol_version(self, client, public_protocol): + protocol_version = public_protocol.repocache.latest_version + + recipes.fittingresult_version.make( + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model_version__visibility='private', + fittingresult__fittingspec_version__visibility='public', + fittingresult__dataset__visibility='public' + ).fittingresult + + recipes.fittingresult_version.make( + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model_version__visibility='public', + fittingresult__fittingspec_version__visibility='private', + fittingresult__dataset__visibility='public' + ).fittingresult + + recipes.fittingresult_version.make( + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + fittingresult__dataset__visibility='private' + ).fittingresult + + fit = recipes.fittingresult_version.make( + fittingresult__protocol=public_protocol, + fittingresult__protocol_version=protocol_version, + fittingresult__model_version__visibility='public', + fittingresult__fittingspec_version__visibility='public', + fittingresult__dataset__visibility='public' + ).fittingresult + + response = client.get( + '/entities/protocols/%d/versions/%s/fittings' % (public_protocol.id, protocol_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (fit.dataset, [(fit.model, [fit])]), + ] + def test_shows_fittings_related_to_fittingspec_version(self, client, fittingresult_version): fit = fittingresult_version.fittingresult @@ -945,6 +1032,50 @@ def test_multiple_model_versions_for_fittingspec_version(self, client, helpers, ]), ] + def test_ensure_private_results_are_not_shown_for_fittingspec_version(self, client, public_fittingspec): + fittingspec_version = public_fittingspec.repocache.latest_version + + recipes.fittingresult_version.make( + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model_version__visibility='private', + fittingresult__protocol_version__visibility='public', + fittingresult__dataset__visibility='public' + ).fittingresult + + recipes.fittingresult_version.make( + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='private', + fittingresult__dataset__visibility='public' + ).fittingresult + + recipes.fittingresult_version.make( + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='public', + fittingresult__dataset__visibility='private' + ).fittingresult + + fit = recipes.fittingresult_version.make( + fittingresult__fittingspec=public_fittingspec, + fittingresult__fittingspec_version=fittingspec_version, + fittingresult__model_version__visibility='public', + fittingresult__protocol_version__visibility='public', + fittingresult__dataset__visibility='public' + ).fittingresult + + response = client.get( + '/fitting/specs/%d/versions/%s/fittings' % (public_fittingspec.id, fittingspec_version.sha) + ) + + assert response.status_code == 200 + assert response.context['comparisons'] == [ + (fit.dataset, [(fit.model, [fit])]), + ] + @pytest.mark.django_db class TestEntityComparisonView: From ee6ff292506ec5cd6dde3ec559948aaec57bce6f Mon Sep 17 00:00:00 2001 From: Jonathan Cooper Date: Fri, 16 Oct 2020 17:10:59 +0100 Subject: [PATCH 17/18] Add extra check --- weblab/entities/tests/test_views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/weblab/entities/tests/test_views.py b/weblab/entities/tests/test_views.py index d09240056..98b3c5996 100644 --- a/weblab/entities/tests/test_views.py +++ b/weblab/entities/tests/test_views.py @@ -544,6 +544,7 @@ def test_has_visibility_form(self, client, helpers, public_model): response = client.get('/entities/models/%d/versions/%s/compare' % (public_model.pk, public_model.repocache.latest_version.sha)) assert 'form' in response.context + assert response.context['form'].initial.get('visibility') == 'public' def test_shows_related_experiments(self, client, helpers, experiment_version): exp = experiment_version.experiment @@ -663,6 +664,7 @@ def test_has_visibility_form(self, client, helpers, public_model): response = client.get('/entities/models/%d/versions/%s/fittings' % (public_model.pk, public_model.repocache.latest_version.sha)) assert 'form' in response.context + assert response.context['form'].initial.get('visibility') == 'public' def test_shows_fittings_related_to_model_version(self, client, fittingresult_version): fit = fittingresult_version.fittingresult From 72d535239b458ab25d6daeb41f07d39eaccb92c9 Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Tue, 20 Oct 2020 08:38:29 +0000 Subject: [PATCH 18/18] Fix variable assignment in tests --- weblab/datasets/tests/test_views.py | 6 +++--- weblab/entities/tests/test_views.py | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/weblab/datasets/tests/test_views.py b/weblab/datasets/tests/test_views.py index 981822746..fb9b1050d 100644 --- a/weblab/datasets/tests/test_views.py +++ b/weblab/datasets/tests/test_views.py @@ -737,21 +737,21 @@ def test_ensure_private_results_are_not_shown(self, client, public_dataset): fittingresult__model_version__visibility='private', fittingresult__protocol_version__visibility='public', fittingresult__fittingspec_version__visibility='public', - ).fittingresult + ) recipes.fittingresult_version.make( fittingresult__dataset=public_dataset, fittingresult__model_version__visibility='public', fittingresult__protocol_version__visibility='private', fittingresult__fittingspec_version__visibility='public', - ).fittingresult + ) recipes.fittingresult_version.make( fittingresult__dataset=public_dataset, fittingresult__model_version__visibility='public', fittingresult__protocol_version__visibility='public', fittingresult__fittingspec_version__visibility='private', - ).fittingresult + ) fit = recipes.fittingresult_version.make( fittingresult__dataset=public_dataset, diff --git a/weblab/entities/tests/test_views.py b/weblab/entities/tests/test_views.py index 98b3c5996..c6a8b8aaa 100644 --- a/weblab/entities/tests/test_views.py +++ b/weblab/entities/tests/test_views.py @@ -729,7 +729,7 @@ def test_ensure_private_results_are_not_shown_for_model_version(self, client, pu fittingresult__protocol_version__visibility='private', fittingresult__fittingspec_version__visibility='public', fittingresult__dataset__visibility='public' - ).fittingresult + ) recipes.fittingresult_version.make( fittingresult__model=public_model, @@ -737,7 +737,7 @@ def test_ensure_private_results_are_not_shown_for_model_version(self, client, pu fittingresult__protocol_version__visibility='public', fittingresult__fittingspec_version__visibility='private', fittingresult__dataset__visibility='public' - ).fittingresult + ) recipes.fittingresult_version.make( fittingresult__model=public_model, @@ -745,7 +745,7 @@ def test_ensure_private_results_are_not_shown_for_model_version(self, client, pu fittingresult__protocol_version__visibility='public', fittingresult__fittingspec_version__visibility='public', fittingresult__dataset__visibility='private' - ).fittingresult + ) fit = recipes.fittingresult_version.make( fittingresult__model=public_model, @@ -886,7 +886,7 @@ def test_ensure_private_results_are_not_shown_for_protocol_version(self, client, fittingresult__model_version__visibility='private', fittingresult__fittingspec_version__visibility='public', fittingresult__dataset__visibility='public' - ).fittingresult + ) recipes.fittingresult_version.make( fittingresult__protocol=public_protocol, @@ -894,7 +894,7 @@ def test_ensure_private_results_are_not_shown_for_protocol_version(self, client, fittingresult__model_version__visibility='public', fittingresult__fittingspec_version__visibility='private', fittingresult__dataset__visibility='public' - ).fittingresult + ) recipes.fittingresult_version.make( fittingresult__protocol=public_protocol, @@ -902,7 +902,7 @@ def test_ensure_private_results_are_not_shown_for_protocol_version(self, client, fittingresult__model_version__visibility='public', fittingresult__fittingspec_version__visibility='public', fittingresult__dataset__visibility='private' - ).fittingresult + ) fit = recipes.fittingresult_version.make( fittingresult__protocol=public_protocol, @@ -1043,7 +1043,7 @@ def test_ensure_private_results_are_not_shown_for_fittingspec_version(self, clie fittingresult__model_version__visibility='private', fittingresult__protocol_version__visibility='public', fittingresult__dataset__visibility='public' - ).fittingresult + ) recipes.fittingresult_version.make( fittingresult__fittingspec=public_fittingspec, @@ -1051,7 +1051,7 @@ def test_ensure_private_results_are_not_shown_for_fittingspec_version(self, clie fittingresult__model_version__visibility='public', fittingresult__protocol_version__visibility='private', fittingresult__dataset__visibility='public' - ).fittingresult + ) recipes.fittingresult_version.make( fittingresult__fittingspec=public_fittingspec, @@ -1059,7 +1059,7 @@ def test_ensure_private_results_are_not_shown_for_fittingspec_version(self, clie fittingresult__model_version__visibility='public', fittingresult__protocol_version__visibility='public', fittingresult__dataset__visibility='private' - ).fittingresult + ) fit = recipes.fittingresult_version.make( fittingresult__fittingspec=public_fittingspec,