diff --git a/beat/web/algorithms/__init__.py b/beat/web/algorithms/__init__.py index cc57d1eaebcb674e758dc0c84384079f5db83fbd..d0430713a0885ceb513a520dfc6996db2cc36ed2 100644 --- a/beat/web/algorithms/__init__.py +++ b/beat/web/algorithms/__init__.py @@ -25,4 +25,4 @@ # # ############################################################################### -default_app_config = 'beat.web.algorithms.apps.AlgorithmsConfig' +default_app_config = "beat.web.algorithms.apps.AlgorithmsConfig" diff --git a/beat/web/algorithms/admin.py b/beat/web/algorithms/admin.py index 7885db22f9a5206d8bc613cbdcb1cc3c4af0139c..7e4705765412374f45fdddefd0d055db26439668 100755 --- a/beat/web/algorithms/admin.py +++ b/beat/web/algorithms/admin.py @@ -25,87 +25,72 @@ # # ############################################################################### +import simplejson as json from django import forms from django.contrib import admin from django.core.files.base import ContentFile -from ..ui.forms import CodeMirrorPythonFileField, CodeMirrorRSTFileField, \ - CodeMirrorJSONFileField, CodeMirrorJSONCharField - from ..common.texts import Messages - +from ..ui.forms import CodeMirrorJSONCharField +from ..ui.forms import CodeMirrorJSONFileField +from ..ui.forms import CodeMirrorPythonFileField +from ..ui.forms import CodeMirrorRSTFileField +from ..ui.forms import NameField from .models import Algorithm as AlgorithmModel from .models import AlgorithmEndpoint as AlgorithmEndpointModel from .models import validate_algorithm -from ..ui.forms import NameField - -import simplejson as json - - -#---------------------------------------------------------- +# ---------------------------------------------------------- class AlgorithmModelForm(forms.ModelForm): name = NameField( - widget=forms.TextInput(attrs=dict(size=80)), - help_text=Messages['algo_name'], + widget=forms.TextInput(attrs=dict(size=80)), help_text=Messages["algo_name"], ) declaration_file = CodeMirrorJSONFileField( - label='Declaration', - help_text=Messages['json'], + label="Declaration", help_text=Messages["json"], ) source_code_file = CodeMirrorPythonFileField( - label='Source code', - help_text=Messages['code'], + label="Source code", help_text=Messages["code"], ) description_file = CodeMirrorRSTFileField( - label='Description', + label="Description", required=False, allow_empty_file=True, - help_text=Messages['description'], + help_text=Messages["description"], ) - parameters = CodeMirrorJSONCharField( - readonly=True, - required=False, - ) + parameters = CodeMirrorJSONCharField(readonly=True, required=False,) - result_dataformat = CodeMirrorJSONCharField( - readonly=True, - required=False, - ) + result_dataformat = CodeMirrorJSONCharField(readonly=True, required=False,) class Meta: model = AlgorithmModel exclude = [] widgets = { - 'short_description': forms.TextInput( - attrs=dict(size=100), - ), + "short_description": forms.TextInput(attrs=dict(size=100),), } - def __init__(self, *args, **kwargs): super(AlgorithmModelForm, self).__init__(*args, **kwargs) - if kwargs['instance'].is_binary(): - del self.fields['source_code_file'] + if kwargs["instance"].is_binary(): + del self.fields["source_code_file"] def clean_declaration_file(self): """Cleans-up the 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 @@ -118,70 +103,76 @@ class AlgorithmModelForm(forms.ModelForm): raise forms.ValidationError(str(e)) # if that works out, then we return the passed file - 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 AlgorithmEndpointInline(admin.TabularInline): - model = AlgorithmEndpointModel - can_delete = False - extra = 0 - max_num = 0 - readonly_fields = ('id', 'input', 'channel', 'name', 'dataformat') - ordering = ('input', 'channel', 'name') + model = AlgorithmEndpointModel + can_delete = False + extra = 0 + max_num = 0 + readonly_fields = ("id", "input", "channel", "name", "dataformat") + ordering = ("input", "channel", "name") -#---------------------------------------------------------- +# ---------------------------------------------------------- + def rehash_algorithm(modeladmin, request, queryset): """Recalculates the hash of an algorithm""" - for q in queryset: q.save() + for q in queryset: + q.save() + -rehash_algorithm.short_description = 'Rehash selected algorithms' +rehash_algorithm.short_description = "Rehash selected algorithms" class Algorithm(admin.ModelAdmin): - list_display = ( - 'id', - 'author', - 'name', - 'version', - 'splittable', - 'short_description', - 'creation_date', - 'analysis', - 'previous_version', - 'fork_of', - 'sharing', - 'hash' + list_display = ( + "id", + "author", + "name", + "version", + "splittable", + "short_description", + "creation_date", + "analysis", + "previous_version", + "fork_of", + "sharing", + "hash", ) - search_fields = [ - 'author__username', - 'name', - 'short_description', - 'previous_version__author__username', - 'previous_version__name', - 'fork_of__author__username', - 'fork_of__name' + search_fields = [ + "author__username", + "name", + "short_description", + "previous_version__author__username", + "previous_version__name", + "fork_of__author__username", + "fork_of__name", ] - list_filter = ('sharing', ) - list_display_links = ('id', 'name') - readonly_fields = ('hash', 'splittable', 'short_description') + list_filter = ("sharing",) + list_display_links = ("id", "name") + readonly_fields = ("hash", "splittable", "short_description") inlines = [ AlgorithmEndpointInline, @@ -194,56 +185,77 @@ class Algorithm(admin.ModelAdmin): form = AlgorithmModelForm filter_horizontal = [ - 'shared_with', - 'shared_with_team', - 'usable_by', - 'usable_by_team', - 'referenced_libraries' + "shared_with", + "shared_with_team", + "usable_by", + "usable_by_team", + "referenced_libraries", ] fieldsets = ( - (None, - dict( - fields=('name', 'author',), - ), - ), - ('Documentation', - dict( - classes=('collapse',), - fields=('short_description', 'description_file',), - ), - ), - ('Versioning', - dict( - classes=('collapse',), - fields=('version', 'previous_version', 'fork_of'), - ), - ), - ('Sharing', - dict( - classes=('collapse',), - fields=('sharing', 'shared_with', 'shared_with_team', 'usable_by', 'usable_by_team'), - ), - ), - ('Cached Information (read-only)', - dict( - classes=('collapse',), - fields=('parameters', 'result_dataformat', 'referenced_libraries'), - ), - ), - ('Definition', - dict( - fields=('hash', 'splittable', 'declaration_file', 'language', 'source_code_file'), - ), - ), + (None, dict(fields=("name", "author",),),), + ( + "Documentation", + dict( + classes=("collapse",), + fields=("short_description", "description_file",), + ), + ), + ( + "Versioning", + dict( + classes=("collapse",), + fields=("version", "previous_version", "fork_of"), + ), + ), + ( + "Sharing", + dict( + classes=("collapse",), + fields=( + "sharing", + "shared_with", + "shared_with_team", + "usable_by", + "usable_by_team", + ), + ), + ), + ( + "Cached Information (read-only)", + dict( + classes=("collapse",), + fields=("parameters", "result_dataformat", "referenced_libraries"), + ), + ), + ( + "Definition", + dict( + fields=( + "hash", + "splittable", + "declaration_file", + "language", + "source_code_file", + ), + ), + ), ) def get_form(self, request, obj=None, **kwargs): if obj.is_binary(): - self.exclude = ('source_code_file',) - fieldsets = [fieldset for fieldset in self.fieldsets if fieldset[0] == 'Definition'][0] - fieldsets[1]['fields'] = ('hash', 'splittable', 'declaration_file', 'language') + self.exclude = ("source_code_file",) + fieldsets = [ + fieldset for fieldset in self.fieldsets if fieldset[0] == "Definition" + ][0] + fieldsets[1]["fields"] = ( + "hash", + "splittable", + "declaration_file", + "language", + ) form = super(Algorithm, self).get_form(request, obj, **kwargs) return form + admin.site.register(AlgorithmModel, Algorithm) diff --git a/beat/web/algorithms/api.py b/beat/web/algorithms/api.py index 35a7d357646468ee24b27a106eb6ff1b7086ed64..4684029bc33e7c12f82ed1fca3feb1339eca2628 100755 --- a/beat/web/algorithms/api.py +++ b/beat/web/algorithms/api.py @@ -26,31 +26,25 @@ ############################################################################### from django.core.files import File - from rest_framework import exceptions as drf_exceptions from rest_framework import parsers from rest_framework import renderers from rest_framework import response from rest_framework import views +from ..code.api import DiffView +from ..code.api import RetrieveUpdateDestroyCodeView +from ..code.api import ShareCodeView +from ..code.serializers import CodeDiffSerializer +from ..common import permissions as beat_permissions +from ..common.api import CheckContributionNameView +from ..common.api import ListContributionView +from ..common.api import ListCreateContributionView from .models import Algorithm -from .serializers import AlgorithmSerializer -from .serializers import FullAlgorithmSerializer from .serializers import AlgorithmCreationSerializer from .serializers import AlgorithmModSerializer - -from ..code.api import ShareCodeView, RetrieveUpdateDestroyCodeView -from ..code.serializers import CodeDiffSerializer - -from ..common.api import ( - CheckContributionNameView, - ListContributionView, - ListCreateContributionView, -) -from ..common import permissions as beat_permissions - -from ..code.api import DiffView - +from .serializers import AlgorithmSerializer +from .serializers import FullAlgorithmSerializer # ---------------------------------------------------------- diff --git a/beat/web/algorithms/apps.py b/beat/web/algorithms/apps.py index 97c03eb5f53511dfa9d4781913e5c1d2c1189bc8..9ac6c8d48871997aa7cf9a4b2ae4d4c6f088ff1f 100644 --- a/beat/web/algorithms/apps.py +++ b/beat/web/algorithms/apps.py @@ -25,18 +25,23 @@ # # ############################################################################### -from ..common.apps import CommonAppConfig from django.utils.translation import ugettext_lazy as _ +from ..common.apps import CommonAppConfig + + class AlgorithmsConfig(CommonAppConfig): - name = 'beat.web.algorithms' - verbose_name = _('Algorithms') + name = "beat.web.algorithms" + verbose_name = _("Algorithms") def ready(self): super(AlgorithmsConfig, self).ready() - from .signals import (create_endpoints, delete_endpoints, - auto_delete_file_on_delete, auto_delete_file_on_change) - from actstream import registry - registry.register(self.get_model('Algorithm')) + + from .signals import auto_delete_file_on_change # noqa: F401 + from .signals import auto_delete_file_on_delete # noqa: F401 + from .signals import create_endpoints # noqa: F401 + from .signals import delete_endpoints # noqa: F401 + + registry.register(self.get_model("Algorithm")) diff --git a/beat/web/algorithms/migrations/0001_initial.py b/beat/web/algorithms/migrations/0001_initial.py index a3eb95751142687e8c9296902c00bb4bdf1973cd..4634a15ee4a226d75a1238da5f0c4767110fd758 100644 --- a/beat/web/algorithms/migrations/0001_initial.py +++ b/beat/web/algorithms/migrations/0001_initial.py @@ -27,67 +27,247 @@ from __future__ import unicode_literals -from django.db import migrations, models -import beat.web.code.models -import beat.web.algorithms.models from django.conf import settings +from django.db import migrations +from django.db import models + +import beat.web.algorithms.models +import beat.web.code.models import beat.web.common.models class Migration(migrations.Migration): dependencies = [ - ('dataformats', '0001_initial'), + ("dataformats", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('team', '0001_initial'), - ('libraries', '0001_initial'), + ("team", "0001_initial"), + ("libraries", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Algorithm', + name="Algorithm", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('sharing', models.CharField(default='P', max_length=1, choices=[('P', 'Private'), ('S', 'Shared'), ('A', 'Public'), ('U', 'Usable')])), - ('name', models.CharField(help_text='The name for this object (space-like characters will be automatically replaced by dashes)', max_length=200)), - ('version', models.PositiveIntegerField(default=1, help_text='The version of this object (an integer starting from 1)')), - ('short_description', models.CharField(default='', help_text='Describe the object succinctly (try to keep it under 80 characters)', max_length=100, blank=True)), - ('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation date')), - ('hash', models.CharField(help_text='Hashed value of the object contents (<a href="https://docs.python.org/2/library/hashlib.html">SHA256, hexadecimal digest</a>). This field is auto-generated and managed by the platform.', max_length=64, editable=False)), - ('language', models.CharField(default='P', max_length=1, choices=[('U', 'Unknown'), ('', 'Binary'), ('M', 'Matla'), ('P', 'Python'), ('R', 'R')])), - ('declaration_file', models.FileField(db_column='declaration', upload_to=beat.web.common.models.get_contribution_declaration_filename, storage=beat.web.algorithms.models.AlgorithmStorage(), max_length=200, blank=True, null=True)), - ('description_file', models.FileField(db_column='description', upload_to=beat.web.common.models.get_contribution_description_filename, storage=beat.web.algorithms.models.AlgorithmStorage(), max_length=200, blank=True, null=True)), - ('source_code_file', models.FileField(db_column='source_code', upload_to=beat.web.code.models.get_contribution_source_code_filename, storage=beat.web.algorithms.models.AlgorithmStorage(), max_length=200, blank=True, null=True)), - ('parameters', models.TextField(null=True, blank=True)), - ('result_dataformat', models.TextField(null=True, blank=True)), - ('splittable', models.BooleanField(default=False, help_text='Defines if the code can be executed in multiple instances')), - ('author', models.ForeignKey(related_name='algorithms', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), - ('fork_of', models.ForeignKey(related_name='forks', blank=True, to='algorithms.Algorithm', null=True, on_delete=models.SET_NULL)), - ('previous_version', models.ForeignKey(related_name='next_versions', blank=True, to='algorithms.Algorithm', null=True, on_delete=models.SET_NULL)), - ('referenced_libraries', models.ManyToManyField(related_name='used_by_algorithms', to='libraries.Library', blank=True)), - ('shared_with', models.ManyToManyField(related_name='shared_algorithms', to=settings.AUTH_USER_MODEL, blank=True)), - ('shared_with_team', models.ManyToManyField(related_name='shared_algorithms', to='team.Team', blank=True)), - ('usable_by', models.ManyToManyField(related_name='usable_algorithms', to=settings.AUTH_USER_MODEL, blank=True)), - ('usable_by_team', models.ManyToManyField(related_name='usable_algorithms', to='team.Team', blank=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "sharing", + models.CharField( + default="P", + max_length=1, + choices=[ + ("P", "Private"), + ("S", "Shared"), + ("A", "Public"), + ("U", "Usable"), + ], + ), + ), + ( + "name", + models.CharField( + help_text="The name for this object (space-like characters will be automatically replaced by dashes)", + max_length=200, + ), + ), + ( + "version", + models.PositiveIntegerField( + default=1, + help_text="The version of this object (an integer starting from 1)", + ), + ), + ( + "short_description", + models.CharField( + default="", + help_text="Describe the object succinctly (try to keep it under 80 characters)", + max_length=100, + blank=True, + ), + ), + ( + "creation_date", + models.DateTimeField( + auto_now_add=True, verbose_name="Creation date" + ), + ), + ( + "hash", + models.CharField( + help_text='Hashed value of the object contents (<a href="https://docs.python.org/2/library/hashlib.html">SHA256, hexadecimal digest</a>). This field is auto-generated and managed by the platform.', + max_length=64, + editable=False, + ), + ), + ( + "language", + models.CharField( + default="P", + max_length=1, + choices=[ + ("U", "Unknown"), + ("", "Binary"), + ("M", "Matla"), + ("P", "Python"), + ("R", "R"), + ], + ), + ), + ( + "declaration_file", + models.FileField( + db_column="declaration", + upload_to=beat.web.common.models.get_contribution_declaration_filename, + storage=beat.web.algorithms.models.AlgorithmStorage(), + max_length=200, + blank=True, + null=True, + ), + ), + ( + "description_file", + models.FileField( + db_column="description", + upload_to=beat.web.common.models.get_contribution_description_filename, + storage=beat.web.algorithms.models.AlgorithmStorage(), + max_length=200, + blank=True, + null=True, + ), + ), + ( + "source_code_file", + models.FileField( + db_column="source_code", + upload_to=beat.web.code.models.get_contribution_source_code_filename, + storage=beat.web.algorithms.models.AlgorithmStorage(), + max_length=200, + blank=True, + null=True, + ), + ), + ("parameters", models.TextField(null=True, blank=True)), + ("result_dataformat", models.TextField(null=True, blank=True)), + ( + "splittable", + models.BooleanField( + default=False, + help_text="Defines if the code can be executed in multiple instances", + ), + ), + ( + "author", + models.ForeignKey( + related_name="algorithms", + to=settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ), + ), + ( + "fork_of", + models.ForeignKey( + related_name="forks", + blank=True, + to="algorithms.Algorithm", + null=True, + on_delete=models.SET_NULL, + ), + ), + ( + "previous_version", + models.ForeignKey( + related_name="next_versions", + blank=True, + to="algorithms.Algorithm", + null=True, + on_delete=models.SET_NULL, + ), + ), + ( + "referenced_libraries", + models.ManyToManyField( + related_name="used_by_algorithms", + to="libraries.Library", + blank=True, + ), + ), + ( + "shared_with", + models.ManyToManyField( + related_name="shared_algorithms", + to=settings.AUTH_USER_MODEL, + blank=True, + ), + ), + ( + "shared_with_team", + models.ManyToManyField( + related_name="shared_algorithms", to="team.Team", blank=True + ), + ), + ( + "usable_by", + models.ManyToManyField( + related_name="usable_algorithms", + to=settings.AUTH_USER_MODEL, + blank=True, + ), + ), + ( + "usable_by_team", + models.ManyToManyField( + related_name="usable_algorithms", to="team.Team", blank=True + ), + ), ], options={ - 'ordering': ['author__username', 'name', 'version'], - 'abstract': False, + "ordering": ["author__username", "name", "version"], + "abstract": False, }, ), migrations.CreateModel( - name='AlgorithmEndpoint', + name="AlgorithmEndpoint", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('input', models.BooleanField(default=False)), - ('name', models.CharField(max_length=200)), - ('channel', models.CharField(max_length=200)), - ('algorithm', models.ForeignKey(related_name='endpoints', to='algorithms.Algorithm', on_delete=models.CASCADE)), - ('dataformat', models.ForeignKey(related_name='algorithm_endpoints', to='dataformats.DataFormat', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("input", models.BooleanField(default=False)), + ("name", models.CharField(max_length=200)), + ("channel", models.CharField(max_length=200)), + ( + "algorithm", + models.ForeignKey( + related_name="endpoints", + to="algorithms.Algorithm", + on_delete=models.CASCADE, + ), + ), + ( + "dataformat", + models.ForeignKey( + related_name="algorithm_endpoints", + to="dataformats.DataFormat", + on_delete=models.CASCADE, + ), + ), ], ), migrations.AlterUniqueTogether( - name='algorithm', - unique_together=set([('author', 'name', 'version')]), + name="algorithm", unique_together=set([("author", "name", "version")]), ), ] diff --git a/beat/web/algorithms/migrations/0002_cxx_backend.py b/beat/web/algorithms/migrations/0002_cxx_backend.py index abe1969adf9f9b37f82813da6237c71b66bfe482..d4762bdc05d40b4fd25749ce3519474e099f9688 100644 --- a/beat/web/algorithms/migrations/0002_cxx_backend.py +++ b/beat/web/algorithms/migrations/0002_cxx_backend.py @@ -2,19 +2,30 @@ # Generated by Django 1.9.11 on 2016-11-09 11:05 from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): dependencies = [ - ('algorithms', '0001_initial'), + ("algorithms", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='algorithm', - name='language', - field=models.CharField(choices=[(b'U', b'Unknown'), (b'C', b'C++'), (b'M', b'Matlab'), (b'P', b'Python'), (b'R', b'R')], default=b'P', max_length=1), + model_name="algorithm", + name="language", + field=models.CharField( + choices=[ + (b"U", b"Unknown"), + (b"C", b"C++"), + (b"M", b"Matlab"), + (b"P", b"Python"), + (b"R", b"R"), + ], + default=b"P", + max_length=1, + ), ), ] diff --git a/beat/web/algorithms/migrations/0003_auto_20161123_1218.py b/beat/web/algorithms/migrations/0003_auto_20161123_1218.py index da49951e775d8f132c4758076f44d0a1513e2872..a57b9caa27436e5945e1585ad235c89c218d1568 100644 --- a/beat/web/algorithms/migrations/0003_auto_20161123_1218.py +++ b/beat/web/algorithms/migrations/0003_auto_20161123_1218.py @@ -2,19 +2,30 @@ # Generated by Django 1.9.11 on 2016-11-23 12:18 from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): dependencies = [ - ('algorithms', '0002_cxx_backend'), + ("algorithms", "0002_cxx_backend"), ] operations = [ migrations.AlterField( - model_name='algorithm', - name='language', - field=models.CharField(choices=[(b'U', b'Unknown'), (b'C', b'Cxx'), (b'M', b'Matlab'), (b'P', b'Python'), (b'R', b'R')], default=b'P', max_length=1), + model_name="algorithm", + name="language", + field=models.CharField( + choices=[ + (b"U", b"Unknown"), + (b"C", b"Cxx"), + (b"M", b"Matlab"), + (b"P", b"Python"), + (b"R", b"R"), + ], + default=b"P", + max_length=1, + ), ), ] diff --git a/beat/web/algorithms/migrations/0004_algorithm_type.py b/beat/web/algorithms/migrations/0004_algorithm_type.py index c736ba0119d7e3eb6d23d194ef4ca03b5ee29a1d..c69eda1fbd146a4d6e9219da911d7910081da270 100644 --- a/beat/web/algorithms/migrations/0004_algorithm_type.py +++ b/beat/web/algorithms/migrations/0004_algorithm_type.py @@ -2,38 +2,39 @@ # Generated by Django 1.9.13 on 2018-01-30 10:27 from __future__ import unicode_literals -from django.db import migrations, models -from django.conf import settings - import simplejson +from django.db import migrations +from django.db import models def determine_types(apps, schema_editor): - '''Refreshes each database so datasets/outputs are recreated''' + """Refreshes each database so datasets/outputs are recreated""" Algorithm = apps.get_model("algorithms", "Algorithm") if Algorithm.objects.count(): - print('') + print("") - for algorithm in Algorithm.objects.order_by('id'): - print("Determining type of algorithm '%s/%s/%d'..." % \ - (algorithm.author.username, algorithm.name, algorithm.version)) + for algorithm in Algorithm.objects.order_by("id"): + print( + "Determining type of algorithm '%s/%s/%d'..." + % (algorithm.author.username, algorithm.name, algorithm.version) + ) print(algorithm.declaration_file.path) - with open(algorithm.declaration_file.path, 'r') as f: + with open(algorithm.declaration_file.path, "r") as f: declaration = simplejson.load(f) - if 'type' in declaration: - if declaration['type'] == 'sequential': - algorithm.type = 'S' - elif declaration['type'] == 'autonomous': - algorithm.type = 'A' + if "type" in declaration: + if declaration["type"] == "sequential": + algorithm.type = "S" + elif declaration["type"] == "autonomous": + algorithm.type = "A" else: - algorithm.type = 'L' + algorithm.type = "L" else: - algorithm.type = 'L' + algorithm.type = "L" algorithm.save() @@ -41,14 +42,22 @@ def determine_types(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('algorithms', '0003_auto_20161123_1218'), + ("algorithms", "0003_auto_20161123_1218"), ] operations = [ migrations.AddField( - model_name='algorithm', - name='type', - field=models.CharField(choices=[(b'L', b'Legacy'), (b'S', b'Sequential'), (b'A', b'Autonomous')], default=b'S', max_length=1), + model_name="algorithm", + name="type", + field=models.CharField( + choices=[ + (b"L", b"Legacy"), + (b"S", b"Sequential"), + (b"A", b"Autonomous"), + ], + default=b"S", + max_length=1, + ), ), migrations.RunPython(determine_types), ] diff --git a/beat/web/algorithms/models.py b/beat/web/algorithms/models.py index f4ebe2200a8f3ebb4c9159f02ca60e47644b4be3..033df0f4988dc733ea6e31b08b35949133e0ae02 100755 --- a/beat/web/algorithms/models.py +++ b/beat/web/algorithms/models.py @@ -25,31 +25,27 @@ # # ############################################################################### -from django.db import models +import collections + +import simplejson from django.conf import settings +from django.db import models from django.urls import reverse import beat.core.algorithm import beat.core.library - from beat.core.utils import NumpyJSONEncoder -from ..dataformats.models import DataFormat - -from ..common.storage import OverwriteStorage -from ..common.exceptions import ShareError -from ..common.models import get_contribution_declaration_filename -from ..common.models import get_contribution_description_filename - from ..code.models import Code from ..code.models import CodeManager from ..code.models import get_contribution_source_code_filename +from ..common.exceptions import ShareError +from ..common.models import get_contribution_declaration_filename +from ..common.models import get_contribution_description_filename +from ..common.storage import OverwriteStorage +from ..dataformats.models import DataFormat from ..libraries.models import Library -import simplejson -import collections - - # ---------------------------------------------------------- @@ -273,10 +269,12 @@ class Algorithm(Code): # reset referenced libraries self.referenced_libraries.clear() if wrapper.uses is not None: - for l in set(wrapper.uses.values()): - s = beat.core.library.Storage(settings.PREFIX, l) + for library_name in set(wrapper.uses.values()): + lib_storage = beat.core.library.Storage(settings.PREFIX, library_name) library = Library.objects.get( - author__username=s.username, name=s.name, version=s.version + author__username=lib_storage.username, + name=lib_storage.name, + version=lib_storage.version, ) self.referenced_libraries.add(library) @@ -371,10 +369,14 @@ class Algorithm(Code): class AlgorithmEndpoint(models.Model): - algorithm = models.ForeignKey(Algorithm, related_name="endpoints", on_delete=models.CASCADE) + algorithm = models.ForeignKey( + Algorithm, related_name="endpoints", on_delete=models.CASCADE + ) input = models.BooleanField(default=False) name = models.CharField(max_length=200) - dataformat = models.ForeignKey(DataFormat, related_name="algorithm_endpoints", on_delete=models.CASCADE) + dataformat = models.ForeignKey( + DataFormat, related_name="algorithm_endpoints", on_delete=models.CASCADE + ) channel = models.CharField(max_length=200) def __str__(self): diff --git a/beat/web/algorithms/serializers.py b/beat/web/algorithms/serializers.py index d44166586e4515fa8a850bd9b30865d80ae78b08..2b0d2c3d120991c7f4537c549188fd592f11c343 100755 --- a/beat/web/algorithms/serializers.py +++ b/beat/web/algorithms/serializers.py @@ -25,24 +25,24 @@ # # ############################################################################### +from operator import itemgetter + import simplejson as json +from rest_framework import serializers import beat.core.algorithm -from rest_framework import serializers -from operator import itemgetter - -from ..code.serializers import CodeSerializer, CodeCreationSerializer, CodeModSerializer -from ..libraries.serializers import LibraryReferenceSerializer -from ..dataformats.serializers import ReferencedDataFormatSerializer from ..attestations.serializers import AttestationSerializer -from ..experiments.serializers import ExperimentSerializer -from ..experiments.models import Experiment from ..backend.serializers import EnvironmentInfoSerializer - +from ..code.serializers import CodeCreationSerializer +from ..code.serializers import CodeModSerializer +from ..code.serializers import CodeSerializer +from ..dataformats.serializers import ReferencedDataFormatSerializer +from ..experiments.models import Experiment +from ..experiments.serializers import ExperimentSerializer +from ..libraries.serializers import LibraryReferenceSerializer from .models import Algorithm - # ---------------------------------------------------------- diff --git a/beat/web/algorithms/signals.py b/beat/web/algorithms/signals.py index c74bfa313e68dd7c2d05954069b39b72666c8bcc..021ab64097d67ebe911262406121652e4450960b 100644 --- a/beat/web/algorithms/signals.py +++ b/beat/web/algorithms/signals.py @@ -29,11 +29,10 @@ from django.db import models from django.dispatch import receiver from ..dataformats.models import DataFormat +from .models import Algorithm +from .models import AlgorithmEndpoint -from .models import Algorithm, AlgorithmEndpoint - - -#---------------------------------------------------------- +# ---------------------------------------------------------- # These two auto-delete files from filesystem when they are unneeded: @@ -82,7 +81,7 @@ def auto_delete_file_on_change(sender, instance, **kwargs): old_code.delete(save=False) -#---------------------------------------------------------- +# ---------------------------------------------------------- @receiver(models.signals.pre_delete, sender=Algorithm) @@ -90,7 +89,7 @@ def delete_endpoints(sender, instance, **kwargs): instance.endpoints.all().delete() -#---------------------------------------------------------- +# ---------------------------------------------------------- @receiver(models.signals.post_save, sender=Algorithm) @@ -104,42 +103,40 @@ def create_endpoints(sender, instance, **kwargs): def _create_or_reuse_endpoint(isinput, name, formatname, channel): - (df_author, df_name, df_version) = formatname.split('/') + (df_author, df_name, df_version) = formatname.split("/") df = DataFormat.objects.get( - author__username=df_author, - name=df_name, - version=df_version, + author__username=df_author, name=df_name, version=df_version, ) endpoint = AlgorithmEndpoint.objects.filter( - algorithm = instance, - input = isinput, - name = name, - #channel = channel_name, - dataformat = df, + algorithm=instance, + input=isinput, + name=name, + # channel = channel_name, + dataformat=df, ) if not endpoint: - endpoint = AlgorithmEndpoint() - endpoint.algorithm = instance - endpoint.input = isinput - endpoint.name = name - endpoint.channel = channel + endpoint = AlgorithmEndpoint() + endpoint.algorithm = instance + endpoint.input = isinput + endpoint.name = name + endpoint.channel = channel endpoint.dataformat = df endpoint.save() used_endpoints.append(endpoint) else: endpoint[0].channel = channel - endpoint[0].save() # reset channel name with new standard + endpoint[0].save() # reset channel name with new standard used_endpoints.append(endpoint[0]) for group in wrapper.groups: - group_name = group.get('name', '__io_group_%d__' % len(used_names)) + group_name = group.get("name", "__io_group_%d__" % len(used_names)) used_names.add(group_name) - for name, details in group['inputs'].items(): - _create_or_reuse_endpoint(True, name, details['type'], group_name) - for name, details in group.get('outputs', {}).items(): - _create_or_reuse_endpoint(False, name, details['type'], group_name) + for name, details in group["inputs"].items(): + _create_or_reuse_endpoint(True, name, details["type"], group_name) + for name, details in group.get("outputs", {}).items(): + _create_or_reuse_endpoint(False, name, details["type"], group_name) # cleans up unused endpoints all_endpoints = AlgorithmEndpoint.objects.filter(algorithm=instance) diff --git a/beat/web/algorithms/templates/algorithms/list.html b/beat/web/algorithms/templates/algorithms/list.html index 687f2c01ae7f9e7adb8c5e2d5c4395a7e3355c7a..43003cd43e0da0d9154aa78f9588d8f29c8e593e 100644 --- a/beat/web/algorithms/templates/algorithms/list.html +++ b/beat/web/algorithms/templates/algorithms/list.html @@ -2,21 +2,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/algorithms/templates/algorithms/panels/actions.html b/beat/web/algorithms/templates/algorithms/panels/actions.html index effba5f53684af32fbbbfb34cebd83f8a767e637..6617986b3ff2be42d1e4e39ea8316bbcf509a005 100644 --- a/beat/web/algorithms/templates/algorithms/panels/actions.html +++ b/beat/web/algorithms/templates/algorithms/panels/actions.html @@ -1,21 +1,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/algorithms/templates/algorithms/panels/sharing.html b/beat/web/algorithms/templates/algorithms/panels/sharing.html index 467487ad346d11c61bc76960fe17c36513ebd3dd..22379a4ded17a10d654cec75a3be5035caa05fd1 100644 --- a/beat/web/algorithms/templates/algorithms/panels/sharing.html +++ b/beat/web/algorithms/templates/algorithms/panels/sharing.html @@ -1,21 +1,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/algorithms/templates/algorithms/panels/table.html b/beat/web/algorithms/templates/algorithms/panels/table.html index b25605051b791c22c49bb499cc276e98464e492a..a0471d05052ff20d8b38e0bedcd89f64b2f0303e 100644 --- a/beat/web/algorithms/templates/algorithms/panels/table.html +++ b/beat/web/algorithms/templates/algorithms/panels/table.html @@ -1,21 +1,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/algorithms/templatetags/algorithm_tags.py b/beat/web/algorithms/templatetags/algorithm_tags.py index 209448d2a2242475cb369c8431dcf8abe8e4f415..bbd025d8559114732f6f5b9b9bb99a70de804159 100755 --- a/beat/web/algorithms/templatetags/algorithm_tags.py +++ b/beat/web/algorithms/templatetags/algorithm_tags.py @@ -27,16 +27,16 @@ from django import template -from django.conf import settings -from ...common.texts import Messages as Texts + from ...common.models import Shareable +from ...common.texts import Messages as Texts register = template.Library() -@register.inclusion_tag('algorithms/panels/table.html', takes_context=True) +@register.inclusion_tag("algorithms/panels/table.html", takes_context=True) def algorithm_table(context, objects, owner, panel_id): - '''Composes a algorithm list table + """Composes a algorithm list table This panel primarily exists for user's algorithm list page. @@ -48,19 +48,19 @@ def algorithm_table(context, objects, owner, panel_id): panel_id: The HTML id to set on the generated table. This is handy for the filter functionality normally available on list pages. - ''' + """ return { - 'request': context['request'], - 'objects': objects, - 'owner': owner, - 'panel_id': panel_id, + "request": context["request"], + "objects": objects, + "owner": owner, + "panel_id": panel_id, } -@register.inclusion_tag('algorithms/panels/actions.html', takes_context=True) +@register.inclusion_tag("algorithms/panels/actions.html", takes_context=True) def algorithm_actions(context, obj, display_count): - '''Composes the action buttons for a particular algorithm + """Composes the action buttons for a particular algorithm This panel primarily exists for showing action buttons for a given algorithm taking into consideration it is being displayed for a given user. @@ -72,49 +72,50 @@ def algorithm_actions(context, obj, display_count): display_count (bool): If the set of buttons should include one with the number of experiments using this algorithm. - ''' - request = context['request'] + """ + request = context["request"] return { - 'request': request, - 'object': obj, - 'display_count': display_count, - 'open_source': obj.open_source(request.user), + "request": request, + "object": obj, + "display_count": display_count, + "open_source": obj.open_source(request.user), } -@register.inclusion_tag('algorithms/panels/editor.html', takes_context=True) +@register.inclusion_tag("algorithms/panels/editor.html", takes_context=True) def algorithm_editor(context, obj): - request = context['request'] + request = context["request"] return { - 'owner': request.user == obj.author, - 'object': obj, - 'texts': Texts, - 'open_source': obj.open_source(request.user), - 'downloadable': obj.is_binary() and ((request.user == obj.author) or (obj.sharing == Shareable.PUBLIC)), + "owner": request.user == obj.author, + "object": obj, + "texts": Texts, + "open_source": obj.open_source(request.user), + "downloadable": obj.is_binary() + and ((request.user == obj.author) or (obj.sharing == Shareable.PUBLIC)), } -@register.inclusion_tag('algorithms/panels/sharing.html', takes_context=True) +@register.inclusion_tag("algorithms/panels/sharing.html", takes_context=True) def algorithm_sharing(context, obj): - '''Composes the current sharing properties and a form to change them + """Composes the current sharing properties and a form to change them Parameters: obj (Algorithm): The algorithm object concerned for which the sharing panel will be drawn - ''' + """ return { - 'request': context['request'], - 'object': obj, - 'owner': context['request'].user == obj.author, - 'users': context['users'], - 'teams': context['teams'], + "request": context["request"], + "object": obj, + "owner": context["request"].user == obj.author, + "users": context["users"], + "teams": context["teams"], } @register.simple_tag(takes_context=True) def visible_experiments(context, object): - '''Calculates the visible experiments for a given algorithm and requestor''' + """Calculates the visible experiments for a given algorithm and requestor""" - return object.experiments.for_user(context['request'].user, True) + return object.experiments.for_user(context["request"].user, True) diff --git a/beat/web/algorithms/tests/core.py b/beat/web/algorithms/tests/core.py index 122fb7c7259f284fa067157d80e3e86b7d8d51a7..3ae5dbc4c6492e927c7177964ba0aba7cc400f24 100755 --- a/beat/web/algorithms/tests/core.py +++ b/beat/web/algorithms/tests/core.py @@ -30,19 +30,17 @@ import os import shutil import simplejson as json - -from django.contrib.auth.models import User from django.conf import settings +from django.contrib.auth.models import User + +from beat.core.algorithm import Storage -from ...dataformats.models import DataFormat from ...common.testutils import BaseTestCase from ...common.testutils import tearDownModule # noqa test runner will call it +from ...dataformats.models import DataFormat from ...team.models import Team - from ..models import Algorithm -from beat.core.algorithm import Storage - TEST_PWD = "1234" diff --git a/beat/web/algorithms/tests/tests.py b/beat/web/algorithms/tests/tests.py index b33e28cf7167fe74ed94502638f07c7337c74985..1eb1ed26d1e4c1ee5f9a17a560f90916b296f591 100644 --- a/beat/web/algorithms/tests/tests.py +++ b/beat/web/algorithms/tests/tests.py @@ -27,11 +27,9 @@ from django.contrib.auth.models import User -from ...libraries.models import Library from ...common.testutils import tearDownModule # noqa test runner will call it - +from ...libraries.models import Library from ..models import Algorithm - from .core import AlgorithmsBaseTestCase diff --git a/beat/web/algorithms/tests/tests_api.py b/beat/web/algorithms/tests/tests_api.py index 85d8e1c3d0aa9702e966b245da3b1da00ec506e8..32756499719055cc0fc9128156f43564e9e1d9ad 100755 --- a/beat/web/algorithms/tests/tests_api.py +++ b/beat/web/algorithms/tests/tests_api.py @@ -27,21 +27,18 @@ import simplejson as json - -from django.contrib.auth.models import User from django.conf import settings -from django.urls import reverse +from django.contrib.auth.models import User from django.core.files.uploadedfile import SimpleUploadedFile - -from ...dataformats.models import DataFormat -from ...common.testutils import tearDownModule # noqa test runner will call it -from ...common.testutils import get_algorithms_from_data -from ...code.models import Code +from django.urls import reverse import beat.core.algorithm +from ...code.models import Code +from ...common.testutils import get_algorithms_from_data +from ...common.testutils import tearDownModule # noqa test runner will call it +from ...dataformats.models import DataFormat from ..models import Algorithm - from .core import AlgorithmsAPIBase diff --git a/beat/web/algorithms/tests/tests_team.py b/beat/web/algorithms/tests/tests_team.py index 163413208a6bcb600008b8ba1327c89e31373cae..c7567a1725dcfc4f59a289e253eaf70944a3a3e7 100644 --- a/beat/web/algorithms/tests/tests_team.py +++ b/beat/web/algorithms/tests/tests_team.py @@ -27,12 +27,10 @@ from django.contrib.auth.models import User -from ...team.models import Team -from ...dataformats.models import DataFormat from ...common.testutils import tearDownModule # noqa test runner will call it - +from ...dataformats.models import DataFormat +from ...team.models import Team from ..models import Algorithm - from .core import AlgorithmsAccessibilityFunctionsBase diff --git a/beat/web/algorithms/tests/tests_user.py b/beat/web/algorithms/tests/tests_user.py index c0e2e1294f6b4e054964e7010e450467101f3934..4b35763a6ead74a51b0a2121129a5fa763c4f118 100644 --- a/beat/web/algorithms/tests/tests_user.py +++ b/beat/web/algorithms/tests/tests_user.py @@ -26,10 +26,9 @@ ############################################################################### +from ...common.testutils import tearDownModule # noqa test runner will call it from ..models import Algorithm - from .core import AlgorithmsAccessibilityFunctionsBase -from ...common.testutils import tearDownModule # noqa test runner will call it class NotSharedAlgorithm_CheckAccessibilityFunction( diff --git a/beat/web/algorithms/views.py b/beat/web/algorithms/views.py index b6663f2adf569982e9f2eff9658a498c933eac39..000354d594283bee64bdd13ee5b665eaef607a43 100755 --- a/beat/web/algorithms/views.py +++ b/beat/web/algorithms/views.py @@ -25,24 +25,24 @@ # # ############################################################################### -from django.http import Http404, HttpResponseForbidden -from django.shortcuts import get_object_or_404 -from django.shortcuts import render -from django.contrib.auth.decorators import login_required +import simplejson as json from django.conf import settings +from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User +from django.http import Http404 +from django.http import HttpResponseForbidden +from django.shortcuts import get_object_or_404 +from django.shortcuts import render + +from beat.core import prototypes -from .models import Algorithm -from ..team.models import Team from ..common.texts import Messages from ..common.utils import ensure_string +from ..team.models import Team from ..ui.templatetags.markup import restructuredtext +from .models import Algorithm -from beat.core import prototypes - -import simplejson as json - -#---------------------------------------------------------- +# ---------------------------------------------------------- @login_required @@ -52,22 +52,22 @@ def create(request, name=None): The user must be authenticated before it can add a new algorithm """ - parameters = {'algorithm_author': request.user.username, - 'algorithm_name': name, - 'algorithm_version': 1, - 'short_description': '', - 'description': '', - 'messages': Messages, - 'edition': False, - 'plot_account': settings.PLOT_ACCOUNT, - } + parameters = { + "algorithm_author": request.user.username, + "algorithm_name": name, + "algorithm_version": 1, + "short_description": "", + "description": "", + "messages": Messages, + "edition": False, + "plot_account": settings.PLOT_ACCOUNT, + } # Retrieves the existing algorithm (if necessary) if name is not None: previous_versions = Algorithm.objects.filter( - author=request.user, - name__iexact=name, - ).order_by('-version') + author=request.user, name__iexact=name, + ).order_by("-version") if len(previous_versions) == 0: raise Http404() @@ -75,30 +75,35 @@ def create(request, name=None): description = ensure_string(previous_version.description) - parameters['algorithm_version'] = previous_version.version + 1 - parameters['declaration'] = previous_version.declaration_string.replace('\n', '') - parameters['short_description'] = previous_version.short_description - parameters['description'] = description.replace('\n', '\\n') - parameters['html_description'] = restructuredtext(description).replace('\n', '') - parameters['algorithm_language'] = previous_version.json_language - parameters['algorithm_language_name'] = previous_version.language_fullname() - parameters['binary'] = previous_version.is_binary() - parameters['new_version'] = True + parameters["algorithm_version"] = previous_version.version + 1 + parameters["declaration"] = previous_version.declaration_string.replace( + "\n", "" + ) + parameters["short_description"] = previous_version.short_description + parameters["description"] = description.replace("\n", "\\n") + parameters["html_description"] = restructuredtext(description).replace("\n", "") + parameters["algorithm_language"] = previous_version.json_language + parameters["algorithm_language_name"] = previous_version.language_fullname() + parameters["binary"] = previous_version.is_binary() + parameters["new_version"] = True if not previous_version.is_binary(): - parameters['source_code'] = previous_version.source_code_file.read() + parameters["source_code"] = previous_version.source_code_file.read() else: - parameters['source_code'] = ensure_string(prototypes.binary_load('algorithm.py')) \ - .replace('\n\n # TODO: Implement this algorithm\n\n', - '\n # TODO: Implement this algorithm\n') - declaration, errors = prototypes.load('algorithm') - declaration['language'] = 'python' - parameters['declaration'] = json.dumps(declaration) + parameters["source_code"] = ensure_string( + prototypes.binary_load("algorithm.py") + ).replace( + "\n\n # TODO: Implement this algorithm\n\n", + "\n # TODO: Implement this algorithm\n", + ) + declaration, errors = prototypes.load("algorithm") + declaration["language"] = "python" + parameters["declaration"] = json.dumps(declaration) - return render(request, 'algorithms/edition.html', parameters) + return render(request, "algorithms/edition.html", parameters) -#---------------------------------------------------------- +# ---------------------------------------------------------- @login_required @@ -109,43 +114,45 @@ def fork(request, author, name, version): """ # Retrieves the forked algorithm based on user accessible algorithms - fork_of = get_object_or_404(Algorithm.objects.for_user(request.user, True), - author__username__iexact=author, - name__iexact=name, - version=int(version) - ) + fork_of = get_object_or_404( + Algorithm.objects.for_user(request.user, True), + author__username__iexact=author, + name__iexact=name, + version=int(version), + ) # The only case a user can't fork an algorithm is if it's usable rather # than shared if fork_of.sharing == Algorithm.USABLE and fork_of.author != request.user: - raise Http404() + raise Http404() description = ensure_string(fork_of.description) - parameters = {'original_author': author, - 'algorithm_author': request.user.username, - 'algorithm_name': name, - 'algorithm_version': fork_of.version, - 'algorithm_language': fork_of.json_language, - 'algorithm_language_name': fork_of.language_fullname(), - 'declaration': fork_of.declaration_string.replace('\n', ''), - 'short_description': fork_of.short_description, - 'description': description.replace('\n', '\\n'), - 'html_description': restructuredtext(description).replace('\n', ''), - 'messages': Messages, - 'fork_of': fork_of, - 'edition': False, - 'binary': fork_of.is_binary(), - 'plot_account': settings.PLOT_ACCOUNT, - } + parameters = { + "original_author": author, + "algorithm_author": request.user.username, + "algorithm_name": name, + "algorithm_version": fork_of.version, + "algorithm_language": fork_of.json_language, + "algorithm_language_name": fork_of.language_fullname(), + "declaration": fork_of.declaration_string.replace("\n", ""), + "short_description": fork_of.short_description, + "description": description.replace("\n", "\\n"), + "html_description": restructuredtext(description).replace("\n", ""), + "messages": Messages, + "fork_of": fork_of, + "edition": False, + "binary": fork_of.is_binary(), + "plot_account": settings.PLOT_ACCOUNT, + } if not fork_of.is_binary(): - parameters['source_code'] = fork_of.source_code_file.read() + parameters["source_code"] = fork_of.source_code_file.read() - return render(request, 'algorithms/edition.html', parameters) + return render(request, "algorithms/edition.html", parameters) -#---------------------------------------------------------- +# ---------------------------------------------------------- @login_required @@ -159,40 +166,43 @@ def edit(request, author, name, version): raise Http404() # Retrieves the algorithm - algorithm = get_object_or_404(Algorithm, - author__username__iexact=author, - name__iexact=name, - version=int(version) - ) + algorithm = get_object_or_404( + Algorithm, + author__username__iexact=author, + name__iexact=name, + version=int(version), + ) if not algorithm.modifiable(): - return HttpResponseForbidden('Algorithm %s is not modifiable' % \ - algorithm.fullname()) + return HttpResponseForbidden( + "Algorithm %s is not modifiable" % algorithm.fullname() + ) description = ensure_string(algorithm.description) - parameters = {'algorithm_author': request.user.username, - 'algorithm_name': name, - 'algorithm_version': algorithm.version, - 'algorithm_language': algorithm.json_language, - 'algorithm_language_name': algorithm.language_fullname(), - 'declaration': algorithm.declaration_string.replace('\n', ''), - 'short_description': algorithm.short_description, - 'description': description.replace('\n', '\\n'), - 'html_description': restructuredtext(description).replace('\n', ''), - 'messages': Messages, - 'edition': True, - 'binary': algorithm.is_binary(), - 'plot_account': settings.PLOT_ACCOUNT, - } + parameters = { + "algorithm_author": request.user.username, + "algorithm_name": name, + "algorithm_version": algorithm.version, + "algorithm_language": algorithm.json_language, + "algorithm_language_name": algorithm.language_fullname(), + "declaration": algorithm.declaration_string.replace("\n", ""), + "short_description": algorithm.short_description, + "description": description.replace("\n", "\\n"), + "html_description": restructuredtext(description).replace("\n", ""), + "messages": Messages, + "edition": True, + "binary": algorithm.is_binary(), + "plot_account": settings.PLOT_ACCOUNT, + } if not algorithm.is_binary(): - parameters['source_code'] = algorithm.source_code_file.read() + parameters["source_code"] = algorithm.source_code_file.read() - return render(request, 'algorithms/edition.html', parameters) + return render(request, "algorithms/edition.html", parameters) -#---------------------------------------------------------- +# ---------------------------------------------------------- def view(request, author, name, version=None): @@ -209,8 +219,9 @@ def view(request, author, name, version=None): version=int(version), ) else: - algorithm = Algorithm.objects.filter(author__username__iexact=author, - name__iexact=name).order_by('-version') + algorithm = Algorithm.objects.filter( + author__username__iexact=author, name__iexact=name + ).order_by("-version") if not algorithm: raise Http404() else: @@ -218,25 +229,30 @@ def view(request, author, name, version=None): (has_access, _, __) = algorithm.accessibility_for(request.user) - if not has_access: raise Http404() + if not has_access: + raise Http404() - owner = (request.user == algorithm.author) + owner = request.user == algorithm.author # 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") # Render the page - return render(request, - 'algorithms/view.html', - { - 'algorithm': algorithm, - 'owner': owner, - 'users': users, - 'teams': Team.objects.for_user(request.user, True) - }) + return render( + request, + "algorithms/view.html", + { + "algorithm": algorithm, + "owner": owner, + "users": users, + "teams": Team.objects.for_user(request.user, True), + }, + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def diff(request, author1, name1, version1, author2, name2, version2): @@ -244,56 +260,57 @@ def diff(request, author1, name1, version1, author2, name2, version2): retrieve the details about the algorithms and check the accessibility. """ - return render(request, - 'algorithms/diff.html', - {'algorithm1_author': author1, - 'algorithm1_name': name1, - 'algorithm1_version': version1, - 'algorithm2_author': author2, - 'algorithm2_name': name2, - 'algorithm2_version': version2, - }) + return render( + request, + "algorithms/diff.html", + { + "algorithm1_author": author1, + "algorithm1_name": name1, + "algorithm1_version": version1, + "algorithm2_author": author2, + "algorithm2_name": name2, + "algorithm2_version": version2, + }, + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def ls(request, author_name): - '''List all accessible algorithms to the request user''' + """List all accessible algorithms 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 algorithms so that the latest information is displayed first - objects = Algorithm.objects.from_author_and_public(request.user, - author_name).order_by('-creation_date') + objects = Algorithm.objects.from_author_and_public( + request.user, author_name + ).order_by("-creation_date") objects = Algorithm.filter_latest_versions(objects) - return render(request, - 'algorithms/list.html', - dict( - objects=objects, - author=author, - owner=(request.user == author) - )) + return render( + request, + "algorithms/list.html", + dict(objects=objects, author=author, owner=(request.user == author)), + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def public_ls(request): - '''List all publicly accessible objects''' + """List all publicly accessible objects""" # orders so that objects with latest information are displayed first - objects = Algorithm.objects.public().order_by('-creation_date') + objects = Algorithm.objects.public().order_by("-creation_date") objects = Algorithm.filter_latest_versions(objects) - return render(request, - 'algorithms/list.html', - dict( - objects=objects, - author=request.user, # anonymous - owner=False - )) + return render( + request, + "algorithms/list.html", + dict(objects=objects, author=request.user, owner=False), # anonymous + )