From 0e7d7bb45fa561b9d49859b61cd95d9101b3e14f Mon Sep 17 00:00:00 2001 From: Samuel Gaist <samuel.gaist@idiap.ch> Date: Wed, 9 Sep 2020 15:49:57 +0200 Subject: [PATCH] [experiments][all] Pre-commit cleanup --- beat/web/experiments/admin.py | 560 ++++++++++++++-------------- beat/web/experiments/api.py | 50 ++- beat/web/experiments/apps.py | 14 +- beat/web/experiments/serializers.py | 25 +- beat/web/experiments/signals.py | 14 +- beat/web/experiments/utils.py | 11 +- beat/web/experiments/views.py | 185 ++++----- 7 files changed, 426 insertions(+), 433 deletions(-) diff --git a/beat/web/experiments/admin.py b/beat/web/experiments/admin.py index 313e38e69..6d453ef13 100755 --- a/beat/web/experiments/admin.py +++ b/beat/web/experiments/admin.py @@ -26,77 +26,72 @@ ############################################################################### import simplejson as json - from django import forms from django.contrib import admin from django.core.files.base import ContentFile - +from django.db.models import Count +from django.db.models import Max +from django.urls import reverse from django.utils.html import format_html from django.utils.safestring import mark_safe -from django.urls import reverse -from django.db.models import Max, Count -from .models import Experiment as ExperimentModel +from ..common.texts import Messages +from ..ui.forms import CodeMirrorJSONCharField +from ..ui.forms import CodeMirrorJSONFileField +from ..ui.forms import CodeMirrorRSTFileField +from ..ui.forms import NameField from .models import Block as BlockModel -from .models import Result as ResultModel -from .models import CachedFile as CachedFileModel from .models import BlockInput as BlockInputModel +from .models import CachedFile as CachedFileModel +from .models import Experiment as ExperimentModel +from .models import Result as ResultModel from .models import validate_experiment -from ..ui.forms import CodeMirrorJSONFileField, CodeMirrorRSTFileField, \ - NameField, CodeMirrorJSONCharField +# ---------------------------------------------------------- -from ..common.texts import Messages - - -#---------------------------------------------------------- class ExperimentModelForm(forms.ModelForm): name = NameField( - widget=forms.TextInput(attrs=dict(size=80)), - help_text=Messages['name'], + widget=forms.TextInput(attrs=dict(size=80)), help_text=Messages["name"], ) declaration_file = CodeMirrorJSONFileField( - label='Declaration', - help_text=Messages['json'], + label="Declaration", help_text=Messages["json"], ) description_file = CodeMirrorRSTFileField( - label='Description', + label="Description", required=False, allow_empty_file=True, - help_text=Messages['description'], + help_text=Messages["description"], ) class Meta: model = ExperimentModel exclude = [] widgets = { - 'short_description': forms.TextInput( - attrs=dict(size=100), - ), + "short_description": forms.TextInput(attrs=dict(size=100),), } def clean_declaration_file(self): """Cleans-up the declaration_file data, make sure it is really new""" - new_declaration = self.cleaned_data['declaration_file'].read() - old_declaration = '' + new_declaration = self.cleaned_data["declaration_file"].read() + old_declaration = "" if self.instance and self.instance.declaration_file.name is not None: old_declaration = self.instance.declaration_string if new_declaration == old_declaration: - self.changed_data.remove('declaration_file') + self.changed_data.remove("declaration_file") content_file = ContentFile(old_declaration) content_file.name = self.instance.declaration_file.name return content_file try: - core_experiment, errors = \ - validate_experiment(json.loads(new_declaration), - self.cleaned_data['toolchain'].declaration) + core_experiment, errors = validate_experiment( + json.loads(new_declaration), self.cleaned_data["toolchain"].declaration + ) except SyntaxError as e: raise forms.ValidationError(str(e)) @@ -104,84 +99,98 @@ class ExperimentModelForm(forms.ModelForm): all_errors = [forms.ValidationError(k) for k in errors] raise forms.ValidationError(all_errors) - self.cleaned_data['declaration_file'].seek(0) #reset ContentFile readout - return self.cleaned_data['declaration_file'] + self.cleaned_data["declaration_file"].seek(0) # reset ContentFile readout + return self.cleaned_data["declaration_file"] def clean(self): """Cleans-up the input data, make sure it overall validates""" - if 'declaration_file' in self.data and \ - isinstance(self.data['declaration_file'], str): + if "declaration_file" in self.data and isinstance( + self.data["declaration_file"], str + ): mutable_data = self.data.copy() - mutable_data['declaration_file'] = ContentFile(self.data['declaration_file'], name='unsaved') + mutable_data["declaration_file"] = ContentFile( + self.data["declaration_file"], name="unsaved" + ) self.data = mutable_data - class BlockInline(admin.TabularInline): model = BlockModel extra = 0 - readonly_fields = ['execution_order', 'link', 'algorithm', 'analyzer', - 'status'] - ordering = ['execution_order'] + readonly_fields = ["execution_order", "link", "algorithm", "analyzer", "status"] + ordering = ["execution_order"] fields = readonly_fields def link(self, obj): - url = reverse('admin:experiments_block_change', args=(obj.pk,)) - return mark_safe('<a href="%s">%s</a>' % (url, obj.name)) - link.short_description = 'name' + url = reverse("admin:experiments_block_change", args=(obj.pk,)) + return mark_safe('<a href="%s">%s</a>' % (url, obj.name)) # nosec + + link.short_description = "name" def has_delete_permission(self, request, obj=None): return False def has_add_permission(self, request): - return False + return False -#---------------------------------------------------------- +# ---------------------------------------------------------- def reset_experiment(modeladmin, request, queryset): - for q in queryset: q.reset() -reset_experiment.short_description = 'Reset selected experiments' + for q in queryset: + q.reset() + + +reset_experiment.short_description = "Reset selected experiments" def cancel_experiment(modeladmin, request, queryset): - for q in queryset: q.cancel() -cancel_experiment.short_description = 'Cancel selected experiments' + for q in queryset: + q.cancel() + + +cancel_experiment.short_description = "Cancel selected experiments" def rehash_experiment(modeladmin, request, queryset): - for q in queryset: q.save() -rehash_experiment.short_description = 'Rehash selected experiments' + for q in queryset: + q.save() + + +rehash_experiment.short_description = "Rehash selected experiments" + class Experiment(admin.ModelAdmin): - list_display = ('id', - 'author', - 'toolchain', - 'name', - 'creation_date', - 'start_date', - 'end_date', - 'status', - 'sharing', - ) - search_fields = ['author__username', - 'toolchain__name', - 'toolchain__author__username', - 'name', - 'short_description', - ] - readonly_fields = ( - 'hash', - 'referenced_datasets', - 'referenced_algorithms', - 'short_description', + list_display = ( + "id", + "author", + "toolchain", + "name", + "creation_date", + "start_date", + "end_date", + "status", + "sharing", + ) + search_fields = [ + "author__username", + "toolchain__name", + "toolchain__author__username", + "name", + "short_description", + ] + readonly_fields = ( + "hash", + "referenced_datasets", + "referenced_algorithms", + "short_description", ) - list_display_links = ('id', ) + list_display_links = ("id",) actions = [ rehash_experiment, @@ -191,135 +200,126 @@ class Experiment(admin.ModelAdmin): form = ExperimentModelForm - filter_horizontal = [ - 'shared_with', - 'shared_with_team' - ] + filter_horizontal = ["shared_with", "shared_with_team"] inlines = [ BlockInline, ] fieldsets = ( - (None, - dict( - fields=('name', 'author', 'toolchain'), - ), - ), - ('Status and dates', - dict( - classes=('collapse',), - fields=('start_date', 'end_date', 'status'), - ), - ), - ('Documentation', - dict( - classes=('collapse',), - fields=('short_description', 'description_file',), - ), - ), - ('References (read-only)', - dict( - classes=('collapse',), - fields=('referenced_datasets', 'referenced_algorithms',), - ), - ), - ('Sharing', - dict( - classes=('collapse',), - fields=('sharing', 'shared_with', 'shared_with_team'), - ), - ), - ('Source code', - dict( - fields=('hash', 'declaration_file'), - ), - ), + (None, dict(fields=("name", "author", "toolchain"),),), + ( + "Status and dates", + dict(classes=("collapse",), fields=("start_date", "end_date", "status"),), + ), + ( + "Documentation", + dict( + classes=("collapse",), + fields=("short_description", "description_file",), + ), + ), + ( + "References (read-only)", + dict( + classes=("collapse",), + fields=("referenced_datasets", "referenced_algorithms",), + ), + ), + ( + "Sharing", + dict( + classes=("collapse",), + fields=("sharing", "shared_with", "shared_with_team"), + ), + ), + ("Source code", dict(fields=("hash", "declaration_file"),),), ) + admin.site.register(ExperimentModel, Experiment) -#---------------------------------------------------------- +# ---------------------------------------------------------- class BlockInputInline(admin.TabularInline): - model = BlockInputModel - verbose_name = 'Input' - verbose_name_plural = 'Inputs' - extra = 0 - ordering = ['database', 'cache'] - readonly_fields = ['input', 'channel'] + model = BlockInputModel + verbose_name = "Input" + verbose_name_plural = "Inputs" + extra = 0 + ordering = ["database", "cache"] + readonly_fields = ["input", "channel"] fields = readonly_fields def input(self, obj): if obj.database: - url = reverse('admin:databases_databaseset_change', - args=(obj.database.set.pk,)) - text = '%s (%s)' % (obj.database, obj.database.hash) - what = 'Dataset Output' + url = reverse( + "admin:databases_databaseset_change", args=(obj.database.set.pk,) + ) + text = "%s (%s)" % (obj.database, obj.database.hash) + what = "Dataset Output" else: - url = reverse('admin:experiments_cachedfile_change', - args=(obj.cache.pk,)) + url = reverse("admin:experiments_cachedfile_change", args=(obj.cache.pk,)) text = obj.cache.hash - what = 'Cached File' - return mark_safe('%s: <a href="%s">%s</a>' % (what, url, text)) + what = "Cached File" + return mark_safe('%s: <a href="%s">%s</a>' % (what, url, text)) # nosec def has_delete_permission(self, request, obj=None): return False def has_add_permission(self, request): - return False + return False class CachedFileInline(admin.TabularInline): model = CachedFileModel.blocks.through - verbose_name = 'Output' - verbose_name_plural = 'Outputs' + verbose_name = "Output" + verbose_name_plural = "Outputs" extra = 0 - readonly_fields = ['output'] + readonly_fields = ["output"] fields = readonly_fields def output(self, obj): - url = reverse('admin:experiments_cachedfile_change', args=(obj.cachedfile.pk,)) + url = reverse("admin:experiments_cachedfile_change", args=(obj.cachedfile.pk,)) text = obj.cachedfile.hash - what = 'Cached File' - return mark_safe('%s: <a href="%s">%s</a>' % (what, url, text)) + what = "Cached File" + return mark_safe('%s: <a href="%s">%s</a>' % (what, url, text)) # nosec def has_delete_permission(self, request, obj=None): return False def has_add_permission(self, request): - return False + return False class BlockDependentsInline(admin.TabularInline): model = BlockModel.dependencies.through - verbose_name = 'Dependent' - verbose_name_plural = 'Dependents' - fk_name = 'to_block' + verbose_name = "Dependent" + verbose_name_plural = "Dependents" + fk_name = "to_block" extra = 0 - readonly_fields = ['order', 'name', 'algorithm', 'analyzer', - 'status'] - ordering = ['id'] + readonly_fields = ["order", "name", "algorithm", "analyzer", "status"] + ordering = ["id"] fields = readonly_fields def order(self, obj): return obj.from_block.execution_order def name(self, obj): - url = reverse('admin:experiments_block_change', args=(obj.from_block.pk,)) - return mark_safe('<a href="%s">%s</a>' % (url, obj.from_block.name)) + url = reverse("admin:experiments_block_change", args=(obj.from_block.pk,)) + return mark_safe('<a href="%s">%s</a>' % (url, obj.from_block.name)) # nosec def algorithm(self, obj): return obj.from_block.algorithm def analyzer(self, obj): return obj.from_block.analyzer + analyzer.boolean = True def status(self, obj): @@ -329,33 +329,34 @@ class BlockDependentsInline(admin.TabularInline): return False def has_add_permission(self, request): - return False + return False class BlockDependenciesInline(admin.TabularInline): model = BlockModel.dependencies.through - verbose_name = 'Dependency' - verbose_name_plural = 'Dependencies' - fk_name = 'from_block' + verbose_name = "Dependency" + verbose_name_plural = "Dependencies" + fk_name = "from_block" extra = 0 - readonly_fields = ['order', 'name', 'algorithm', 'analyzer', 'status'] - ordering = ['id'] + readonly_fields = ["order", "name", "algorithm", "analyzer", "status"] + ordering = ["id"] fields = readonly_fields def order(self, obj): return obj.to_block.execution_order def name(self, obj): - url = reverse('admin:experiments_block_change', args=(obj.to_block.pk,)) - return mark_safe('<a href="%s">%s</a>' % (url, obj.to_block.name)) + url = reverse("admin:experiments_block_change", args=(obj.to_block.pk,)) + return mark_safe('<a href="%s">%s</a>' % (url, obj.to_block.name)) # nosec def algorithm(self, obj): return obj.to_block.algorithm def analyzer(self, obj): return obj.to_block.analyzer + analyzer.boolean = True def status(self, obj): @@ -365,15 +366,12 @@ class BlockDependenciesInline(admin.TabularInline): return False def has_add_permission(self, request): - return False + return False class BlockModelForm(forms.ModelForm): - command = CodeMirrorJSONCharField( - help_text=Messages['json'], - readonly=True, - ) + command = CodeMirrorJSONCharField(help_text=Messages["json"], readonly=True,) class Meta: model = BlockModel @@ -383,34 +381,34 @@ class BlockModelForm(forms.ModelForm): class Block(admin.ModelAdmin): list_display = ( - 'id', - 'author', - 'toolchain', - 'xp', - 'execution_order', - 'name', - 'algorithm', - 'analyzer', - 'status', - 'ins', - 'outs', - 'environment', - 'q' + "id", + "author", + "toolchain", + "xp", + "execution_order", + "name", + "algorithm", + "analyzer", + "status", + "ins", + "outs", + "environment", + "q", ) search_fields = [ - 'name', - 'experiment__author__username', - 'experiment__toolchain__author__username', - 'experiment__toolchain__name', - 'experiment__name', - 'algorithm__author__username', - 'algorithm__name', - 'environment__name', - 'environment__version', + "name", + "experiment__author__username", + "experiment__toolchain__author__username", + "experiment__toolchain__name", + "experiment__name", + "algorithm__author__username", + "algorithm__name", + "environment__name", + "environment__version", ] - list_display_links = ('id', 'name') + list_display_links = ("id", "name") inlines = [ BlockDependenciesInline, @@ -419,11 +417,11 @@ class Block(admin.ModelAdmin): BlockDependentsInline, ] - exclude = ['dependencies'] + exclude = ["dependencies"] def get_queryset(self, request): qs = super(Block, self).get_queryset(request) - return qs.annotate(Count('outputs')) + return qs.annotate(Count("outputs")) def author(self, obj): return obj.experiment.author @@ -433,116 +431,106 @@ class Block(admin.ModelAdmin): def xp(self, obj): return obj.experiment.name - xp.short_description = 'experiment' + + xp.short_description = "experiment" def ins(self, obj): return obj.inputs.count() def outs(self, obj): return obj.outputs__count - outs.admin_order_field = 'outputs__count' + + outs.admin_order_field = "outputs__count" def q(self, obj): - if obj.queue: return obj.queue.name + if obj.queue: + return obj.queue.name return None - q.short_description = 'queue' + + q.short_description = "queue" def get_readonly_fields(self, request, obj=None): - return list(self.readonly_fields) + \ - [field.name for field in obj._meta.fields if field.name != 'command'] + return list(self.readonly_fields) + [ + field.name for field in obj._meta.fields if field.name != "command" + ] def has_delete_permission(self, request, obj=None): return False def has_add_permission(self, request): - return False + return False form = BlockModelForm fieldsets = ( - (None, - dict( - fields=('id', 'name', 'experiment'), - ), - ), - ('Status and dates', - dict( - fields=('creation_date', 'start_date', 'end_date', 'status'), - ), - ), - ('Code', - dict( - classes=('collapse',), - fields=('algorithm', 'analyzer',), - ), - ), - ('Backend', - dict( - classes=('collapse',), - fields=('environment', 'queue', 'required_slots', 'channel'), - ), - ), - ('Command', - dict( - classes=('collapse',), - fields=('command',), - ), - ), + (None, dict(fields=("id", "name", "experiment"),),), + ( + "Status and dates", + dict(fields=("creation_date", "start_date", "end_date", "status"),), + ), + ("Code", dict(classes=("collapse",), fields=("algorithm", "analyzer",),),), + ( + "Backend", + dict( + classes=("collapse",), + fields=("environment", "queue", "required_slots", "channel"), + ), + ), + ("Command", dict(classes=("collapse",), fields=("command",),),), ) + admin.site.register(BlockModel, Block) -#---------------------------------------------------------- +# ---------------------------------------------------------- class Result(admin.ModelAdmin): - list_display = ('id', 'cache', 'name', 'type', 'primary', 'data_value') + list_display = ("id", "cache", "name", "type", "primary", "data_value") search_fields = [ - 'name', - 'cache__hash', + "name", + "cache__hash", ] - list_display_links = ('id', 'name') + list_display_links = ("id", "name") - list_select_related = ( - 'cache', - ) + list_select_related = ("cache",) def get_readonly_fields(self, request, obj=None): - return list(self.readonly_fields) + \ - [field.name for field in obj._meta.fields] + return list(self.readonly_fields) + [field.name for field in obj._meta.fields] def has_delete_permission(self, request, obj=None): return False def has_add_permission(self, request): - return False + return False + admin.site.register(ResultModel, Result) -#---------------------------------------------------------- +# ---------------------------------------------------------- def delete_file_on_fs(modeladmin, request, queryset): - ''' + """ Delete the files contained in the cache - ''' + """ for obj in queryset: obj.delete_files() -delete_file_on_fs.short_description = 'Delete files from the cache' +delete_file_on_fs.short_description = "Delete files from the cache" def cascading_delete_file_on_fs(modeladmin, request, queryset): - ''' + """ Delete the files contained in the cache - ''' + """ for obj in queryset: for block in obj.blocks.all(): @@ -556,108 +544,104 @@ def cascading_delete_file_on_fs(modeladmin, request, queryset): input_.cache.delete_files() -cascading_delete_file_on_fs.short_description = 'Delete files from the ' \ - 'selected and related caches' +cascading_delete_file_on_fs.short_description = ( + "Delete files from the " "selected and related caches" +) class CachedFile(admin.ModelAdmin): search_fields = [ - 'hash', - 'blocks__name', - 'blocks__experiment__name', + "hash", + "blocks__name", + "blocks__experiment__name", ] list_display = ( - 'id', - 'hash', - 'status', - 'date', - 'blocks_url', + "id", + "hash", + "status", + "date", + "blocks_url", ) - list_display_links = ('id', 'hash') + list_display_links = ("id", "hash") - list_filter = ('status', ) + list_filter = ("status",) # to avoid very slow loading of cached files - raw_id_fields = ('blocks',) + raw_id_fields = ("blocks",) actions = [delete_file_on_fs, cascading_delete_file_on_fs] def get_queryset(self, request): qs = super(CachedFile, self).get_queryset(request) - return qs.annotate(date=Max('blocks__start_date')) + return qs.annotate(date=Max("blocks__start_date")) def get_actions(self, request): actions = super(CachedFile, self).get_actions(request) - if 'delete_selected' in actions: - del actions['delete_selected'] + if "delete_selected" in actions: + del actions["delete_selected"] return actions def date(self, obj): return obj.date - date.admin_order_field = '-date' + date.admin_order_field = "-date" def blocks_url(self, obj): - retval = '<ul>' + retval = "<ul>" for block in obj.blocks.all(): - retval += format_html("<li><a href='{block_url}'>{block_name}</a> @ <a href='{experiment_url}'>{experiment_name}</a> ({block_status})</li>", - experiment_url=reverse('admin:experiments_experiment_change', args=(block.experiment.id,)), - experiment_name=block.experiment.fullname(), - block_url=reverse('admin:experiments_block_change', args=(block.id,)), - block_name=block.name, - block_status=block.get_status_display(), + retval += format_html( + "<li><a href='{block_url}'>{block_name}</a> @ <a href='{experiment_url}'>{experiment_name}</a> ({block_status})</li>", + experiment_url=reverse( + "admin:experiments_experiment_change", args=(block.experiment.id,) + ), + experiment_name=block.experiment.fullname(), + block_url=reverse("admin:experiments_block_change", args=(block.id,)), + block_name=block.name, + block_status=block.get_status_display(), ) - return retval + '</ul>' + return retval + "</ul>" blocks_url.short_description = "Blocks" blocks_url.allow_tags = True - fieldsets = ( - (None, - dict( - fields=('hash', 'status', 'blocks',) - ), - ), - ('Logging', - dict( - fields=('error_report', 'stderr', 'stdout'), - ), - ), - ('Performance', - dict( - classes=('collapse',), - fields=( - 'linear_execution_time', - 'speed_up_real', - 'speed_up_maximal', - 'cpu_time', - 'max_memory', - 'queuing_time', - 'data_read_time', - 'data_read_size', - 'data_read_nb_blocks', - 'data_written_time', - 'data_written_size', - 'data_written_nb_blocks', - ), - ), - ), + (None, dict(fields=("hash", "status", "blocks",)),), + ("Logging", dict(fields=("error_report", "stderr", "stdout"),),), + ( + "Performance", + dict( + classes=("collapse",), + fields=( + "linear_execution_time", + "speed_up_real", + "speed_up_maximal", + "cpu_time", + "max_memory", + "queuing_time", + "data_read_time", + "data_read_size", + "data_read_nb_blocks", + "data_written_time", + "data_written_size", + "data_written_nb_blocks", + ), + ), + ), ) - readonly_fields = ['blocks'] + readonly_fields = ["blocks"] def get_readonly_fields(self, request, obj=None): - return list(self.readonly_fields) + \ - [field.name for field in obj._meta.fields] + return list(self.readonly_fields) + [field.name for field in obj._meta.fields] def has_delete_permission(self, request, obj=None): return False def has_add_permission(self, request): - return False + return False + admin.site.register(CachedFileModel, CachedFile) diff --git a/beat/web/experiments/api.py b/beat/web/experiments/api.py index aa947acb3..fcd849272 100755 --- a/beat/web/experiments/api.py +++ b/beat/web/experiments/api.py @@ -25,48 +25,42 @@ # # ############################################################################### -import simplejson import functools +import simplejson from django.conf import settings -from django.shortcuts import get_object_or_404 - from django.core.exceptions import ValidationError - -from rest_framework.response import Response -from rest_framework import permissions +from django.shortcuts import get_object_or_404 from rest_framework import generics +from rest_framework import permissions from rest_framework import serializers -from rest_framework.views import APIView -from rest_framework.reverse import reverse from rest_framework.exceptions import ParseError +from rest_framework.response import Response +from rest_framework.reverse import reverse +from rest_framework.views import APIView -import beat.core.hash import beat.core.algorithm +import beat.core.hash import beat.core.toolchain -from .models import Experiment -from .serializers import ( - ExperimentSerializer, - ExperimentResultsSerializer, - ExperimentCreationSerializer, -) -from .permissions import IsDatabaseAccessible - -from ..common.responses import BadRequestResponse, ForbiddenResponse -from ..common.api import ( - ShareView, - ListContributionView, - ListCreateContributionView, - RetrieveUpdateDestroyContributionView, -) -from ..common.mixins import CommonContextMixin +from ..common.api import ListContributionView +from ..common.api import ListCreateContributionView +from ..common.api import RetrieveUpdateDestroyContributionView +from ..common.api import ShareView from ..common.exceptions import ShareError +from ..common.mixins import CommonContextMixin +from ..common.responses import BadRequestResponse +from ..common.responses import ForbiddenResponse from ..common.serializers import SharingSerializer -from ..common.utils import validate_restructuredtext, ensure_html, py3_cmp - +from ..common.utils import ensure_html +from ..common.utils import py3_cmp +from ..common.utils import validate_restructuredtext from ..toolchains.models import Toolchain - +from .models import Experiment +from .permissions import IsDatabaseAccessible +from .serializers import ExperimentCreationSerializer +from .serializers import ExperimentResultsSerializer +from .serializers import ExperimentSerializer # ---------------------------------------------------------- diff --git a/beat/web/experiments/apps.py b/beat/web/experiments/apps.py index 6392aa6ee..1c188d63b 100644 --- a/beat/web/experiments/apps.py +++ b/beat/web/experiments/apps.py @@ -25,15 +25,19 @@ # # ############################################################################### -from ..common.apps import CommonAppConfig from django.utils.translation import ugettext_lazy as _ +from ..common.apps import CommonAppConfig + + class ExperimentsConfig(CommonAppConfig): - name = 'beat.web.experiments' - verbose_name = _('Experiments') + name = "beat.web.experiments" + verbose_name = _("Experiments") def ready(self): super(ExperimentsConfig, self).ready() - from .signals import on_team_delete from actstream import registry - registry.register(self.get_model('Experiment')) + + from .signals import on_team_delete # noqa: F401 + + registry.register(self.get_model("Experiment")) diff --git a/beat/web/experiments/serializers.py b/beat/web/experiments/serializers.py index ec7e24bc3..7221a8bc2 100755 --- a/beat/web/experiments/serializers.py +++ b/beat/web/experiments/serializers.py @@ -25,31 +25,24 @@ # # ############################################################################### -import simplejson as json - -import beat.core - from datetime import datetime -from rest_framework import serializers +import simplejson as json +from django.contrib.humanize.templatetags.humanize import naturaltime from rest_framework import exceptions as drf_exceptions +from rest_framework import serializers -from django.contrib.humanize.templatetags.humanize import naturaltime +import beat.core +from ..common import fields as beat_fields from ..common.serializers import ShareableSerializer -from ..common.utils import validate_restructuredtext from ..common.utils import annotate_full_name -from ..common import fields as beat_fields - -from ..ui.templatetags.markup import restructuredtext - +from ..common.utils import validate_restructuredtext from ..toolchains.models import Toolchain - -from .models.experiment import validate_experiment - -from .models import Experiment +from ..ui.templatetags.markup import restructuredtext from .models import Block - +from .models import Experiment +from .models.experiment import validate_experiment # ---------------------------------------------------------- diff --git a/beat/web/experiments/signals.py b/beat/web/experiments/signals.py index e05055c70..01e199bae 100755 --- a/beat/web/experiments/signals.py +++ b/beat/web/experiments/signals.py @@ -25,13 +25,12 @@ # # ############################################################################### + from django.db import models from django.dispatch import receiver from ..team.models import Team -from .models import Experiment, Block - -from datetime import datetime +from .models import Experiment # These two auto-delete files from filesystem when they are unneeded: @@ -70,7 +69,8 @@ def auto_delete_file_on_change(sender, instance, **kwargs): old_descr.delete(save=False) -#_________ Algorithms _________ +# _________ Algorithms _________ + def build_user_algorithm_set(user): all_algorithms = [] @@ -80,6 +80,7 @@ def build_user_algorithm_set(user): return set(all_algorithms) + def process_algorithms(team): team_algorithms = set(team.shared_algorithms.all() | team.usable_algorithms.all()) @@ -90,7 +91,8 @@ def process_algorithms(team): algorithm.share(public=False, users=[member]) -#_________ Toolchains _________ +# _________ Toolchains _________ + def build_user_toolchain_set(user): all_toolchains = [] @@ -113,6 +115,6 @@ def process_toolchains(team): @receiver(models.signals.pre_delete, sender=Team) def on_team_delete(sender, **kwargs): - team = kwargs.get('instance') + team = kwargs.get("instance") process_algorithms(team) process_toolchains(team) diff --git a/beat/web/experiments/utils.py b/beat/web/experiments/utils.py index 1b25bd01f..bed0fb6cc 100644 --- a/beat/web/experiments/utils.py +++ b/beat/web/experiments/utils.py @@ -26,26 +26,25 @@ ############################################################################### -'''Utilities for experiment management''' - +"""Utilities for experiment management""" +import logging from django.db.models import Count from .models import CachedFile -import logging logger = logging.getLogger(__name__) def list_orphaned_cachedfiles(): - '''Lists orphaned cache files that do not exist in the disk either''' + """Lists orphaned cache files that do not exist in the disk either""" - q = CachedFile.objects.annotate(Count('blocks')).filter(blocks__count__lt=1) + q = CachedFile.objects.annotate(Count("blocks")).filter(blocks__count__lt=1) return [c for c in q if not c.exists()] def cleanup_orphaned_cachedfiles(): - '''Cleans-up orphaned cache files that do not exist in the disk either''' + """Cleans-up orphaned cache files that do not exist in the disk either""" for c in list_orphaned_cachedfiles(): logger.info("Removing orphaned CachedFile object `%s'..." % c.hash) diff --git a/beat/web/experiments/views.py b/beat/web/experiments/views.py index 33079c9bd..9a24fcaa3 100644 --- a/beat/web/experiments/views.py +++ b/beat/web/experiments/views.py @@ -25,26 +25,27 @@ # # ############################################################################### -from django.shortcuts import get_object_or_404 -from django.shortcuts import render, redirect -from django.http import Http404 +from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User -from django.conf import settings from django.db.models.functions import Coalesce +from django.http import Http404 +from django.shortcuts import get_object_or_404 +from django.shortcuts import redirect +from django.shortcuts import render -from .models import Experiment -from ..toolchains.models import Toolchain from ..team.models import Team +from ..toolchains.models import Toolchain +from .models import Experiment - -#---------------------------------------------------------- +# ---------------------------------------------------------- @login_required -def new_from_toolchain(request, toolchain_author_name, toolchain_name, - toolchain_version): - '''Sets up a new experiment from a toolchain name''' +def new_from_toolchain( + request, toolchain_author_name, toolchain_name, toolchain_version +): + """Sets up a new experiment from a toolchain name""" # Retrieve the toolchain toolchain = get_object_or_404( @@ -56,23 +57,22 @@ def new_from_toolchain(request, toolchain_author_name, toolchain_name, # Check that the user can access it has_access = toolchain.accessibility_for(request.user)[0] - if not(has_access): raise Http404() + if not (has_access): + raise Http404() - return render(request, - 'experiments/setup.html', - { - 'toolchain': toolchain, - 'action': 'new', - }) + return render( + request, "experiments/setup.html", {"toolchain": toolchain, "action": "new"} + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- @login_required -def fork(request, author_name, toolchain_author_name, - toolchain_name, toolchain_version, name): - '''Sets up a new experiment from an experiment fork''' +def fork( + request, author_name, toolchain_author_name, toolchain_name, toolchain_version, name +): + """Sets up a new experiment from an experiment fork""" # Retrieve the experiment experiment = get_object_or_404( @@ -81,28 +81,31 @@ def fork(request, author_name, toolchain_author_name, toolchain__author__username=toolchain_author_name, toolchain__name=toolchain_name, toolchain__version=toolchain_version, - name=name + name=name, ) # Check that the user can access it (has_access, accessibility) = experiment.accessibility_for(request.user) - if not(has_access): raise Http404() + if not (has_access): + raise Http404() + + return render( + request, + "experiments/setup.html", + { + "toolchain": experiment.toolchain, + "experiment": experiment, + "action": "fork", + }, + ) - return render(request, - 'experiments/setup.html', - { - 'toolchain': experiment.toolchain, - 'experiment': experiment, - 'action': 'fork', - }) +# ---------------------------------------------------------- -#---------------------------------------------------------- @login_required -def reset(request, toolchain_author_name, - toolchain_name, toolchain_version, name): - '''Resets the current experiment so it can run again''' +def reset(request, toolchain_author_name, toolchain_name, toolchain_version, name): + """Resets the current experiment so it can run again""" # Retrieve the experiment experiment = get_object_or_404( @@ -111,19 +114,21 @@ def reset(request, toolchain_author_name, toolchain__author__username=toolchain_author_name, toolchain__name=toolchain_name, toolchain__version=toolchain_version, - name=name + name=name, ) - if not experiment.deletable(): raise Http404() + if not experiment.deletable(): + raise Http404() experiment.reset() return redirect(experiment) -def view(request, author_name, toolchain_author_name, toolchain_name, - toolchain_version, name): - '''Views an experiment no matter its present state''' +def view( + request, author_name, toolchain_author_name, toolchain_name, toolchain_version, name +): + """Views an experiment no matter its present state""" # Retrieve the experiment experiment = get_object_or_404( @@ -132,80 +137,92 @@ def view(request, author_name, toolchain_author_name, toolchain_name, toolchain__author__username=toolchain_author_name, toolchain__name=toolchain_name, toolchain__version=toolchain_version, - name=name + name=name, ) # Check that the user can access it (has_access, accessibility) = experiment.accessibility_for(request.user) - if not(has_access): raise Http404() + if not (has_access): + raise Http404() if experiment.status == Experiment.PENDING: - if request.user.is_anonymous: raise Http404() - return render(request, - 'experiments/setup.html', - { - 'toolchain': experiment.toolchain, - 'experiment': experiment, - 'action': 'pending', - }) + if request.user.is_anonymous: + raise Http404() + return render( + request, + "experiments/setup.html", + { + "toolchain": experiment.toolchain, + "experiment": experiment, + "action": "pending", + }, + ) # Users the object can be shared with - users = User.objects.exclude(username__in=settings.ACCOUNTS_TO_EXCLUDE_FROM_TEAMS).order_by('username') + users = User.objects.exclude( + username__in=settings.ACCOUNTS_TO_EXCLUDE_FROM_TEAMS + ).order_by("username") # The experiment was already done, show results - return render(request, - 'experiments/view.html', - { - 'experiment': experiment, - 'owner': experiment.author == request.user, - 'users': users, - 'teams': Team.objects.for_user(request.user, True) - }) + return render( + request, + "experiments/view.html", + { + "experiment": experiment, + "owner": experiment.author == request.user, + "users": users, + "teams": Team.objects.for_user(request.user, True), + }, + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def ls(request, author_name): - '''List all accessible experiments to the request user''' + """List all accessible experiments to the request user""" - if not author_name: return public_ls(request) + if not author_name: + return public_ls(request) # check that the user exists on the system author = get_object_or_404(User, username=author_name) # orders so that experiments that the latest information is displayed first - objects = Experiment.objects.from_author_and_public(request.user, - author_name).annotate(updated=Coalesce('end_date', 'start_date', - 'creation_date')).order_by('-updated') + objects = ( + Experiment.objects.from_author_and_public(request.user, author_name) + .annotate(updated=Coalesce("end_date", "start_date", "creation_date")) + .order_by("-updated") + ) if request.user.is_anonymous: objects = objects.exclude(status=Experiment.PENDING) - owner = (request.user == author) + owner = request.user == author - return render(request, - 'experiments/list.html', - dict( - objects=objects, - author=author, - owner=owner, - )) + return render( + request, + "experiments/list.html", + dict(objects=objects, author=author, owner=owner,), + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def public_ls(request): - '''List all publicly accessible experiments''' + """List all publicly accessible experiments""" # orders so that recent objects are displayed first - objects = Experiment.objects.public().exclude(status=Experiment.PENDING).annotate(updated=Coalesce('end_date', 'start_date', 'creation_date')).order_by('-updated') - - return render(request, - 'experiments/list.html', - dict( - objects=objects, - author=request.user, #anonymous - owner=False, - )) + objects = ( + Experiment.objects.public() + .exclude(status=Experiment.PENDING) + .annotate(updated=Coalesce("end_date", "start_date", "creation_date")) + .order_by("-updated") + ) + + return render( + request, + "experiments/list.html", + dict(objects=objects, author=request.user, owner=False,), # anonymous + ) -- GitLab