diff --git a/beat/web/toolchains/__init__.py b/beat/web/toolchains/__init__.py
index 79b80edb3190ce02f711ee35dbd693d3fc63b31a..ff40fa321810789515a1cd7efccc27b0ad520c45 100644
--- a/beat/web/toolchains/__init__.py
+++ b/beat/web/toolchains/__init__.py
@@ -25,4 +25,4 @@
 #                                                                             #
 ###############################################################################
 
-default_app_config = 'beat.web.toolchains.apps.ToolchainsConfig'
+default_app_config = "beat.web.toolchains.apps.ToolchainsConfig"
diff --git a/beat/web/toolchains/admin.py b/beat/web/toolchains/admin.py
index 16ce3f8a2e8579f6a249bcb60057fa1b4071ce98..e86fe4d407245a48a57850c69feb7b5ad3150c1d 100644
--- a/beat/web/toolchains/admin.py
+++ b/beat/web/toolchains/admin.py
@@ -29,60 +29,50 @@ from django import forms
 from django.contrib import admin
 from django.core.files.base import ContentFile
 
-
-from .models import Toolchain as ToolchainModel
-
-from ..ui.forms import CodeMirrorJSONFileField, CodeMirrorRSTFileField, \
-    NameField
-
 from ..common.texts import Messages
+from ..ui.forms import CodeMirrorJSONFileField
+from ..ui.forms import CodeMirrorRSTFileField
+from ..ui.forms import NameField
+from .models import Toolchain as ToolchainModel
 
-
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class ToolchainModelForm(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 = ToolchainModel
         exclude = []
         widgets = {
-            'short_description': forms.TextInput(
-                attrs=dict(size=100),
-            ),
-                'errors': forms.Textarea(
-                    attrs=dict(readonly=1,cols=150,),
-            ),
+            "short_description": forms.TextInput(attrs=dict(size=100),),
+            "errors": forms.Textarea(attrs=dict(readonly=1, cols=150,),),
         }
 
-
     def clean_declaration(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
@@ -90,55 +80,61 @@ class ToolchainModelForm(forms.ModelForm):
         # we don't validate toolchains - they should be saved in any state
 
         # 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"""
 
         # make sure we don't pass back a str field as 'file'
-        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
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 def rehash_toolchain(modeladmin, request, queryset):
     """Recalculates the hash of an toolchain"""
 
-    for q in queryset: q.save()
+    for q in queryset:
+        q.save()
+
 
-rehash_toolchain.short_description = 'Rehash selected toolchains'
+rehash_toolchain.short_description = "Rehash selected toolchains"
 
 
 class Toolchain(admin.ModelAdmin):
 
-    list_display       = ('id',
-                          'author',
-                          'name',
-                          'version',
-                          'short_description',
-                          'creation_date',
-                          'hash',
-                          'previous_version',
-                          'fork_of',
-                          'sharing',
-                         )
-    search_fields      = ['author__username',
-                          'name',
-                          'short_description',
-                          'previous_version__author__username',
-                          'previous_version__name',
-                          'fork_of__name'
-                         ]
-    list_display_links = ('id', 'name')
-    list_filter        = ('sharing', )
-    readonly_fields    = ('hash', 'errors', 'short_description')
+    list_display = (
+        "id",
+        "author",
+        "name",
+        "version",
+        "short_description",
+        "creation_date",
+        "hash",
+        "previous_version",
+        "fork_of",
+        "sharing",
+    )
+    search_fields = [
+        "author__username",
+        "name",
+        "short_description",
+        "previous_version__author__username",
+        "previous_version__name",
+        "fork_of__name",
+    ]
+    list_display_links = ("id", "name")
+    list_filter = ("sharing",)
+    readonly_fields = ("hash", "errors", "short_description")
 
     actions = [
         rehash_toolchain,
@@ -146,40 +142,32 @@ class Toolchain(admin.ModelAdmin):
 
     form = ToolchainModelForm
 
-    filter_horizontal = [
-        'shared_with',
-        'shared_with_team'
-    ]
+    filter_horizontal = ["shared_with", "shared_with_team"]
 
     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'),
-         ),
-          ),
-        ('Source code',
-         dict(
-             fields=('hash', 'declaration_file', 'errors'),
-         ),
-          ),
+        (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"),
+            ),
+        ),
+        ("Source code", dict(fields=("hash", "declaration_file", "errors"),),),
     )
 
+
 admin.site.register(ToolchainModel, Toolchain)
diff --git a/beat/web/toolchains/api.py b/beat/web/toolchains/api.py
index 1d861e1b985cb1f2649a73c4cf8c2ac1925dc2fe..08cf3ce036d0d8a1c09aedf5e0f46d76ac5be7c7 100644
--- a/beat/web/toolchains/api.py
+++ b/beat/web/toolchains/api.py
@@ -26,21 +26,16 @@
 ###############################################################################
 
 
-from ..common.api import (
-    CheckContributionNameView,
-    ShareView,
-    ListCreateContributionView,
-    RetrieveUpdateDestroyContributionView,
-)
-
+from ..common.api import CheckContributionNameView
+from ..common.api import ListContributionView
+from ..common.api import ListCreateContributionView
+from ..common.api import RetrieveUpdateDestroyContributionView
+from ..common.api import ShareView
 from .models import Toolchain
-from .serializers import ToolchainSerializer
 from .serializers import FullToolchainSerializer
 from .serializers import ToolchainCreationSerializer
 from .serializers import ToolchainModSerializer
-
-from ..common.api import ListContributionView
-
+from .serializers import ToolchainSerializer
 
 # ----------------------------------------------------------
 
diff --git a/beat/web/toolchains/apps.py b/beat/web/toolchains/apps.py
index 623cb76300880209de6296c5899f4198facd10b7..d12d820560d207e5e129d085170051fc720b41d6 100644
--- a/beat/web/toolchains/apps.py
+++ b/beat/web/toolchains/apps.py
@@ -25,18 +25,21 @@
 #                                                                             #
 ###############################################################################
 
-from ..common.apps import CommonAppConfig
 from django.utils.translation import ugettext_lazy as _
 
+from ..common.apps import CommonAppConfig
+
 
 class ToolchainsConfig(CommonAppConfig):
 
-    name = 'beat.web.toolchains'
-    verbose_name = _('Toolchains')
+    name = "beat.web.toolchains"
+    verbose_name = _("Toolchains")
 
     def ready(self):
         super(ToolchainsConfig, self).ready()
-        from .signals import auto_delete_file_on_delete, auto_delete_file_on_change
         from actstream import registry
-        registry.register(self.get_model('Toolchain'))
 
+        from .signals import auto_delete_file_on_change  # noqa: F401
+        from .signals import auto_delete_file_on_delete  # noqa: F401
+
+        registry.register(self.get_model("Toolchain"))
diff --git a/beat/web/toolchains/migrations/0001_initial.py b/beat/web/toolchains/migrations/0001_initial.py
index d69ded34631b7bf4a53cefd2f27c5f099f9f6fa0..7b9b053ca6b3c9613332dd1bc8e7fa9726b75a6e 100644
--- a/beat/web/toolchains/migrations/0001_initial.py
+++ b/beat/web/toolchains/migrations/0001_initial.py
@@ -27,46 +27,163 @@
 
 from __future__ import unicode_literals
 
-from django.db import migrations, models
 from django.conf import settings
-import beat.web.toolchains.models
+from django.db import migrations
+from django.db import models
+
 import beat.web.common.models
+import beat.web.toolchains.models
 
 
 class Migration(migrations.Migration):
 
     dependencies = [
         migrations.swappable_dependency(settings.AUTH_USER_MODEL),
-        ('team', '0001_initial'),
+        ("team", "0001_initial"),
     ]
 
     operations = [
         migrations.CreateModel(
-            name='Toolchain',
+            name="Toolchain",
             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)),
-                ('declaration_file', models.FileField(db_column='declaration', upload_to=beat.web.common.models.get_contribution_declaration_filename, storage=beat.web.toolchains.models.ToolchainStorage(), 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.toolchains.models.ToolchainStorage(), max_length=200, blank=True, null=True)),
-                ('errors', models.TextField(help_text='Errors detected while validating the toolchain. Automatically set by the platform.', null=True, blank=True)),
-                ('author', models.ForeignKey(related_name='toolchains', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
-                ('fork_of', models.ForeignKey(related_name='forks', blank=True, to='toolchains.Toolchain', null=True, on_delete=models.SET_NULL)),
-                ('previous_version', models.ForeignKey(related_name='next_versions', blank=True, to='toolchains.Toolchain', null=True, on_delete=models.SET_NULL)),
-                ('shared_with', models.ManyToManyField(related_name='shared_toolchains', to=settings.AUTH_USER_MODEL, blank=True)),
-                ('shared_with_team', models.ManyToManyField(related_name='shared_toolchains', 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,
+                    ),
+                ),
+                (
+                    "declaration_file",
+                    models.FileField(
+                        db_column="declaration",
+                        upload_to=beat.web.common.models.get_contribution_declaration_filename,
+                        storage=beat.web.toolchains.models.ToolchainStorage(),
+                        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.toolchains.models.ToolchainStorage(),
+                        max_length=200,
+                        blank=True,
+                        null=True,
+                    ),
+                ),
+                (
+                    "errors",
+                    models.TextField(
+                        help_text="Errors detected while validating the toolchain. Automatically set by the platform.",
+                        null=True,
+                        blank=True,
+                    ),
+                ),
+                (
+                    "author",
+                    models.ForeignKey(
+                        related_name="toolchains",
+                        to=settings.AUTH_USER_MODEL,
+                        on_delete=models.CASCADE,
+                    ),
+                ),
+                (
+                    "fork_of",
+                    models.ForeignKey(
+                        related_name="forks",
+                        blank=True,
+                        to="toolchains.Toolchain",
+                        null=True,
+                        on_delete=models.SET_NULL,
+                    ),
+                ),
+                (
+                    "previous_version",
+                    models.ForeignKey(
+                        related_name="next_versions",
+                        blank=True,
+                        to="toolchains.Toolchain",
+                        null=True,
+                        on_delete=models.SET_NULL,
+                    ),
+                ),
+                (
+                    "shared_with",
+                    models.ManyToManyField(
+                        related_name="shared_toolchains",
+                        to=settings.AUTH_USER_MODEL,
+                        blank=True,
+                    ),
+                ),
+                (
+                    "shared_with_team",
+                    models.ManyToManyField(
+                        related_name="shared_toolchains", to="team.Team", blank=True
+                    ),
+                ),
             ],
             options={
-                'ordering': ['author__username', 'name', 'version'],
-                'abstract': False,
+                "ordering": ["author__username", "name", "version"],
+                "abstract": False,
             },
         ),
         migrations.AlterUniqueTogether(
-            name='toolchain',
-            unique_together=set([('author', 'name', 'version')]),
+            name="toolchain", unique_together=set([("author", "name", "version")]),
         ),
     ]
diff --git a/beat/web/toolchains/models.py b/beat/web/toolchains/models.py
index 41ea825bf9195df4b59e91a200ad42dd097b7d30..133672e1f854cbc1b01af6e7a8f2edc83e3172c3 100644
--- a/beat/web/toolchains/models.py
+++ b/beat/web/toolchains/models.py
@@ -26,7 +26,6 @@
 ###############################################################################
 
 import simplejson
-
 from django.conf import settings
 from django.db import models
 from django.urls import reverse
@@ -41,8 +40,7 @@ from ..common.models import get_contribution_declaration_filename
 from ..common.models import get_contribution_description_filename
 from ..common.storage import OverwriteStorage
 
-
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 def validate_toolchain(declaration):
@@ -51,39 +49,49 @@ def validate_toolchain(declaration):
     toolchain = beat.core.toolchain.Toolchain(settings.PREFIX, declaration)
 
     if not toolchain.valid:
-        errors = 'The toolchain declaration is **invalid**. Errors:\n  * ' + \
-                 '\n  * '.join(toolchain.errors)
+        errors = (
+            "The toolchain declaration is **invalid**. Errors:\n  * "
+            + "\n  * ".join(toolchain.errors)
+        )
         raise SyntaxError(errors)
 
     return toolchain
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class ToolchainStorage(OverwriteStorage):
-
     def __init__(self, *args, **kwargs):
-        super(ToolchainStorage, self).__init__(*args, location=settings.TOOLCHAINS_ROOT, **kwargs)
+        super(ToolchainStorage, self).__init__(
+            *args, location=settings.TOOLCHAINS_ROOT, **kwargs
+        )
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class ToolchainManager(StoredContributionManager):
-
-    def create_toolchain(self, author, name, short_description='', description='',
-                         declaration=None, version=1, previous_version=None,
-                         fork_of=None):
+    def create_toolchain(
+        self,
+        author,
+        name,
+        short_description="",
+        description="",
+        declaration=None,
+        version=1,
+        previous_version=None,
+        fork_of=None,
+    ):
 
         # Create the database representation of the toolchain
         toolchain = self.model(
-            author = author,
-            name = self.model.sanitize_name(name),
-            version = version,
-            sharing = self.model.PRIVATE,
-            previous_version = previous_version,
-            fork_of = fork_of,
+            author=author,
+            name=self.model.sanitize_name(name),
+            version=version,
+            sharing=self.model.PRIVATE,
+            previous_version=previous_version,
+            fork_of=fork_of,
         )
 
         # Check the provided declaration
@@ -95,11 +103,11 @@ class ToolchainManager(StoredContributionManager):
             else:
                 tc = beat.core.toolchain.Toolchain(settings.PREFIX, data=None)
                 declaration = tc.data
-        elif not(isinstance(declaration, dict)):
+        elif not (isinstance(declaration, dict)):
             declaration = simplejson.loads(declaration)
 
         if len(short_description) > 0:
-            declaration['description'] = short_description
+            declaration["description"] = short_description
 
         toolchain.declaration = declaration
 
@@ -116,18 +124,18 @@ class ToolchainManager(StoredContributionManager):
         toolchain.save()
 
         if toolchain.errors:
-            toolchain.delete() # undo saving to respect current API
+            toolchain.delete()  # undo saving to respect current API
             return (None, toolchain.errors)
 
         return (toolchain, None)
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class Toolchain(StoredContribution):
 
-    #_____ Constants _______
+    # _____ Constants _______
     DEFAULT_TOOLCHAIN_TEXT = """\
 {
     "blocks": [],
@@ -137,68 +145,68 @@ class Toolchain(StoredContribution):
 }
 """
 
-    #_____ Fields __________
-
-    declaration_file = models.FileField(storage=ToolchainStorage(),
-                                        upload_to=get_contribution_declaration_filename,
-                                        blank=True, null=True,
-                                        max_length=200,
-                                        db_column='declaration'
-                                       )
-
-    description_file = models.FileField(storage=ToolchainStorage(),
-                                        upload_to=get_contribution_description_filename,
-                                        blank=True, null=True,
-                                        max_length=200,
-                                        db_column='description'
-                                       )
+    # _____ Fields __________
+
+    declaration_file = models.FileField(
+        storage=ToolchainStorage(),
+        upload_to=get_contribution_declaration_filename,
+        blank=True,
+        null=True,
+        max_length=200,
+        db_column="declaration",
+    )
+
+    description_file = models.FileField(
+        storage=ToolchainStorage(),
+        upload_to=get_contribution_description_filename,
+        blank=True,
+        null=True,
+        max_length=200,
+        db_column="description",
+    )
 
     # read-only parameters that are updated at every save(), if required
-    errors = models.TextField(blank=True, null=True,
-                              help_text="Errors detected while validating the toolchain. Automatically set by the platform.")
-
+    errors = models.TextField(
+        blank=True,
+        null=True,
+        help_text="Errors detected while validating the toolchain. Automatically set by the platform.",
+    )
 
     objects = ToolchainManager()
 
-
-    #_____ Utilities __________
+    # _____ Utilities __________
 
     def get_absolute_url(self):
 
         return reverse(
-            'toolchains:view',
-                args=(self.author.username, self.name, self.version,),
+            "toolchains:view", args=(self.author.username, self.name, self.version,),
         )
 
-
     def get_api_update_url(self):
-        '''Returns the endpoint to update this object'''
+        """Returns the endpoint to update this object"""
 
         return reverse(
-            'api_toolchains:object',
-                args=(self.author.username, self.name, self.version,),
+            "api_toolchains:object",
+            args=(self.author.username, self.name, self.version,),
         )
 
-
     def get_api_share_url(self):
-        '''Returns the endpoint to share this object'''
+        """Returns the endpoint to share this object"""
 
         return reverse(
-            'api_toolchains:share',
-                args=(self.author.username, self.name, self.version,),
+            "api_toolchains:share",
+            args=(self.author.username, self.name, self.version,),
         )
 
-
     def get_new_experiment_url(self):
-        '''Returns the view to create a new experiment from self'''
+        """Returns the view to create a new experiment from self"""
 
         return reverse(
-            'experiments:new-from-toolchain',
-                args=(self.author.username, self.name, self.version,),
+            "experiments:new-from-toolchain",
+            args=(self.author.username, self.name, self.version,),
         )
 
-
-    #_____ Overrides __________
+    # _____ Overrides __________
 
     def save(self, *args, **kwargs):
 
@@ -206,20 +214,24 @@ class Toolchain(StoredContribution):
         declaration = self.declaration
 
         # Compute the hash of the content
-        content_hash = beat.core.hash.hashJSON(declaration, 'description')
-        content_modified = (content_hash != self.hash)
+        content_hash = beat.core.hash.hashJSON(declaration, "description")
+        content_modified = content_hash != self.hash
 
         if content_modified:
             # toolchains can be saved even if they are not valid...
             wrapper = None
-            errors = ''
+            errors = ""
             try:
                 wrapper = validate_toolchain(declaration)
             except Exception as e:
                 errors = str(e)
 
             self.hash = content_hash
-            self.short_description = wrapper.description if (wrapper is not None) and (wrapper.description is not None) else ''
+            self.short_description = (
+                wrapper.description
+                if (wrapper is not None) and (wrapper.description is not None)
+                else ""
+            )
 
             # Store the errors (if applicable)
             if errors is not None and not errors.strip():
@@ -227,7 +239,7 @@ class Toolchain(StoredContribution):
             else:
                 self.errors = errors
         else:
-            self.short_description = declaration.get('description', '')
+            self.short_description = declaration.get("description", "")
 
         # Ensures that the sharing informations are consistent
         if self.sharing == Contribution.USABLE:
@@ -236,11 +248,10 @@ class Toolchain(StoredContribution):
         # Invoke the base implementation
         super(Toolchain, self).save(*args, **kwargs)
 
-
-    #_____ Methods __________
+    # _____ Methods __________
 
     def is_valid(self):
-        return (self.errors is None)
+        return self.errors is None
 
     def modifiable(self):
         return (self.experiments.count() == 0) and super(Toolchain, self).modifiable()
diff --git a/beat/web/toolchains/serializers.py b/beat/web/toolchains/serializers.py
index 247cf1399c24672be7e1e9508ece03a6c1d76531..676bc510215083fcc466b92b7ab1ae6bf7d4f598 100644
--- a/beat/web/toolchains/serializers.py
+++ b/beat/web/toolchains/serializers.py
@@ -27,19 +27,15 @@
 
 from rest_framework import serializers
 
-from ..common.serializers import (
-    ContributionSerializer,
-    ContributionCreationSerializer,
-    ContributionModSerializer,
-)
+import beat.core.toolchain
+
 from ..attestations.serializers import AttestationSerializer
+from ..common.serializers import ContributionCreationSerializer
+from ..common.serializers import ContributionModSerializer
+from ..common.serializers import ContributionSerializer
 from ..experiments.serializers import ExperimentSerializer
-
 from .models import Toolchain
 
-import beat.core.toolchain
-
-
 # ----------------------------------------------------------
 
 
diff --git a/beat/web/toolchains/signals.py b/beat/web/toolchains/signals.py
index c2dbe242293454a281100fe583d96d80cbbc6f1e..1deef398c12d60ab7e2d049fe31eec49f9041c22 100644
--- a/beat/web/toolchains/signals.py
+++ b/beat/web/toolchains/signals.py
@@ -30,8 +30,7 @@ from django.dispatch import receiver
 
 from .models import Toolchain
 
-
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 # These two auto-delete files from filesystem when they are unneeded:
@@ -46,7 +45,7 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
         instance.description_file.delete(save=False)
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 @receiver(models.signals.pre_save, sender=Toolchain)
diff --git a/beat/web/toolchains/templates/toolchains/dialogs/import_settings.html b/beat/web/toolchains/templates/toolchains/dialogs/import_settings.html
index e4a5593242fe14671c10afd1d66d3c8c6b704743..4adaa742005d260ddb01c112b9d196a43697496f 100644
--- a/beat/web/toolchains/templates/toolchains/dialogs/import_settings.html
+++ b/beat/web/toolchains/templates/toolchains/dialogs/import_settings.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/toolchains/templates/toolchains/diff.html b/beat/web/toolchains/templates/toolchains/diff.html
index 9645fa4f1411ed9c921a25cd2b32fd59086a5561..188f5dcae1aded02b8aad68d72d7a7c512890b42 100644
--- a/beat/web/toolchains/templates/toolchains/diff.html
+++ b/beat/web/toolchains/templates/toolchains/diff.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/toolchains/templates/toolchains/list.html b/beat/web/toolchains/templates/toolchains/list.html
index 90783efe3c8387e5657468892cf842fc991d172d..df9de3aa4d57c1447383a59929ed3e1248eb004c 100644
--- a/beat/web/toolchains/templates/toolchains/list.html
+++ b/beat/web/toolchains/templates/toolchains/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/toolchains/templates/toolchains/panels/actions.html b/beat/web/toolchains/templates/toolchains/panels/actions.html
index 1fd152d7fd5af6261fdea4c1df768254be4df57e..9b3c073815c98bcb6b69b2b8a20028ed9d94672f 100644
--- a/beat/web/toolchains/templates/toolchains/panels/actions.html
+++ b/beat/web/toolchains/templates/toolchains/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/toolchains/templates/toolchains/panels/editor.html b/beat/web/toolchains/templates/toolchains/panels/editor.html
index e122929086195d749f4c73074578955b7b752be3..bf1988fca5e7ba906f689f73e4acee2ccf4c93d1 100644
--- a/beat/web/toolchains/templates/toolchains/panels/editor.html
+++ b/beat/web/toolchains/templates/toolchains/panels/editor.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/toolchains/templates/toolchains/panels/sharing.html b/beat/web/toolchains/templates/toolchains/panels/sharing.html
index 822d2e1faca323b633f6fa382829b7bb1c57fb69..892ffec9b79146200357a488a522ea29d9e9fc7b 100644
--- a/beat/web/toolchains/templates/toolchains/panels/sharing.html
+++ b/beat/web/toolchains/templates/toolchains/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/toolchains/templates/toolchains/panels/table.html b/beat/web/toolchains/templates/toolchains/panels/table.html
index e6cd6a3340a2d1cdc6e492f44325ba60b8f3fc95..45f1429f4cb890eb3ab146045aa30cac2b917cf5 100644
--- a/beat/web/toolchains/templates/toolchains/panels/table.html
+++ b/beat/web/toolchains/templates/toolchains/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/toolchains/templates/toolchains/panels/viewer.html b/beat/web/toolchains/templates/toolchains/panels/viewer.html
index 84f25f86f8468a32e1aec0d46a3f98c9bcfcd574..4578f785dde3abe8b55aeac3aae9375a157b43ce 100644
--- a/beat/web/toolchains/templates/toolchains/panels/viewer.html
+++ b/beat/web/toolchains/templates/toolchains/panels/viewer.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/toolchains/templates/toolchains/view.html b/beat/web/toolchains/templates/toolchains/view.html
index f7adfeed4bd5c02aca1e6f437033a1302679816a..5fa377cf70cf46278652e77bba30de750373f599 100644
--- a/beat/web/toolchains/templates/toolchains/view.html
+++ b/beat/web/toolchains/templates/toolchains/view.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/toolchains/templatetags/toolchain_tags.py b/beat/web/toolchains/templatetags/toolchain_tags.py
index 8aa1ad4df03495ab656f92fe51f0f6632c4e08f9..0eda1314b6e9e70c98dbdea8b240be2addd3b5e9 100644
--- a/beat/web/toolchains/templatetags/toolchain_tags.py
+++ b/beat/web/toolchains/templatetags/toolchain_tags.py
@@ -36,9 +36,9 @@ from ..models import Toolchain
 register = template.Library()
 
 
-@register.inclusion_tag('toolchains/panels/table.html', takes_context=True)
+@register.inclusion_tag("toolchains/panels/table.html", takes_context=True)
 def toolchain_table(context, objects, owner, id):
-    '''Composes a toolchain list table
+    """Composes a toolchain list table
 
     This panel primarily exists for user's toolchain list page.
 
@@ -50,19 +50,14 @@ def toolchain_table(context, objects, owner, id):
         id: The HTML id to set on the generated table. This is handy for the
           filter functionality normally available on list pages.
 
-    '''
+    """
 
-    return dict(
-        request=context['request'],
-        objects=objects,
-        owner=owner,
-        panel_id=id,
-    )
+    return dict(request=context["request"], objects=objects, owner=owner, panel_id=id,)
 
 
-@register.inclusion_tag('toolchains/panels/actions.html', takes_context=True)
+@register.inclusion_tag("toolchains/panels/actions.html", takes_context=True)
 def toolchain_actions(context, object, display_count):
-    '''Composes the action buttons for a particular toolchain
+    """Composes the action buttons for a particular toolchain
 
     This panel primarily exists for showing action buttons for a given
     toolchain taking into consideration it is being displayed for a given user.
@@ -74,36 +69,32 @@ def toolchain_actions(context, object, display_count):
         display_count (bool): If the set of buttons should include one with the
           number of experiments using this toolchain.
 
-    '''
-    return dict(
-        request=context['request'],
-        object=object,
-        display_count=display_count,
-    )
+    """
+    return dict(request=context["request"], object=object, display_count=display_count,)
 
 
-@register.inclusion_tag('toolchains/panels/sharing.html', takes_context=True)
+@register.inclusion_tag("toolchains/panels/sharing.html", takes_context=True)
 def toolchain_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 (Toolchain): The toolchain 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.inclusion_tag('toolchains/panels/viewer.html', takes_context=True)
+@register.inclusion_tag("toolchains/panels/viewer.html", takes_context=True)
 def toolchain_viewer(context, obj, xp, id):
-    '''Composes a canvas with the toolchain (no further JS setup is
+    """Composes a canvas with the toolchain (no further JS setup is
     required)
 
     Parameters:
@@ -114,49 +105,50 @@ def toolchain_viewer(context, obj, xp, id):
           components. If not given, just draw the toolchain.
         id (str): The id of the canvas element that will be created
 
-    '''
+    """
     return {
-        'request': context['request'],
-            'object': obj,
-            'xp': xp,
-            'panel_id': id,
-            'URL_PREFIX': settings.URL_PREFIX,
+        "request": context["request"],
+        "object": obj,
+        "xp": xp,
+        "panel_id": id,
+        "URL_PREFIX": settings.URL_PREFIX,
     }
 
 
 @register.simple_tag(takes_context=True)
 def random_toolchain(context):
-    '''Returns a random toolchain that is visible to the current user'''
-
-    candidates = Toolchain.objects.for_user(context['request'].user, True)
-    return candidates[random.randint(0, candidates.count()-1)]
+    """Returns a random toolchain that is visible to the current user"""
 
+    candidates = Toolchain.objects.for_user(context["request"].user, True)
+    return candidates[random.randint(0, candidates.count() - 1)]  # nosec: B311
 
 
 @register.simple_tag(takes_context=True)
 def visible_toolchains(context):
-    '''Calculates the visible toolchains for a given user'''
+    """Calculates the visible toolchains for a given user"""
 
-    return Toolchain.objects.for_user(context['request'].user, True)
+    return Toolchain.objects.for_user(context["request"].user, True)
 
 
 @register.simple_tag(takes_context=True)
 def visible_experiments(context, object):
-    '''Calculates the visible experiments for a given toolchain and requestor'''
+    """Calculates the visible experiments for a given toolchain and requestor"""
 
-    return object.experiments.for_user(context['request'].user, True)
+    return object.experiments.for_user(context["request"].user, True)
 
 
-#----------------------------------------------------------------
+# ----------------------------------------------------------------
 
 
-@register.inclusion_tag('toolchains/panels/editor.html')
+@register.inclusion_tag("toolchains/panels/editor.html")
 def toolchain_editor(id):
-    return { 'editor_id': id,
-           }
+    return {
+        "editor_id": id,
+    }
 
 
-@register.inclusion_tag('toolchains/dialogs/import_settings.html')
+@register.inclusion_tag("toolchains/dialogs/import_settings.html")
 def toolchain_import_settings(id):
-    return { 'dialog_id': id,
-           }
+    return {
+        "dialog_id": id,
+    }
diff --git a/beat/web/toolchains/views.py b/beat/web/toolchains/views.py
index 94e34d1b6c0f995ff894f125af35c76716b9ced6..5c8ee39b792cf560c03a0ef3eca456aa2b72d588 100644
--- a/beat/web/toolchains/views.py
+++ b/beat/web/toolchains/views.py
@@ -25,25 +25,22 @@
 #                                                                             #
 ###############################################################################
 
+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.shortcuts import get_object_or_404
 from django.shortcuts import render
-from django.contrib.auth.decorators import login_required
-from django.conf import settings
-from django.contrib.auth.models import User
-from django.db.models.functions import Coalesce
 
+from beat.core import prototypes
 
-from .models import Toolchain
-from ..team.models import Team
-from ..reports.models import Report
 from ..common.texts import Messages
 from ..common.utils import ensure_string
+from ..reports.models import Report
+from ..team.models import Team
 from ..ui.templatetags.markup import restructuredtext
-
-from beat.core import prototypes
-
-import simplejson as json
+from .models import Toolchain
 
 
 @login_required
@@ -53,22 +50,22 @@ def create(request, name=None):
     The user must be authenticated before it can add a new toolchain
     """
 
-    parameters = {'toolchain_author':  request.user.username,
-                  'toolchain_name':    name,
-                  'toolchain_version': 1,
-                  'short_description': '',
-                  'description':       '',
-                  'errors':            '',
-                  'edition':           False,
-                  'messages':          Messages,
-                 }
+    parameters = {
+        "toolchain_author": request.user.username,
+        "toolchain_name": name,
+        "toolchain_version": 1,
+        "short_description": "",
+        "description": "",
+        "errors": "",
+        "edition": False,
+        "messages": Messages,
+    }
 
     # Retrieves the existing toolchain (if necessary)
     if name is not None:
         previous_versions = Toolchain.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()
 
@@ -76,19 +73,23 @@ def create(request, name=None):
 
         description = ensure_string(previous_version.description)
 
-        parameters['toolchain_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['errors']            = previous_version.errors.replace('\n', '\\n') if previous_version.errors is not None else ''
+        parameters["toolchain_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["errors"] = (
+            previous_version.errors.replace("\n", "\\n")
+            if previous_version.errors is not None
+            else ""
+        )
     else:
-        declaration, errors = prototypes.load('toolchain')
-        parameters['declaration'] = json.dumps(declaration)
+        declaration, errors = prototypes.load("toolchain")
+        parameters["declaration"] = json.dumps(declaration)
 
-    return render(request,
-                  'toolchains/edition.html',
-                  parameters)
+    return render(request, "toolchains/edition.html", parameters)
 
 
 @login_required
@@ -99,30 +100,30 @@ def fork(request, author, name, version):
     """
 
     # Retrieves the forked toolchain
-    fork_of = get_object_or_404(Toolchain.objects.for_user(request.user, True),
-                                author__username__iexact=author,
-                                name__iexact=name,
-                                version=int(version)
-                               )
+    fork_of = get_object_or_404(
+        Toolchain.objects.for_user(request.user, True),
+        author__username__iexact=author,
+        name__iexact=name,
+        version=int(version),
+    )
 
     description = ensure_string(fork_of.description)
     errors = ensure_string(fork_of.errors)
 
-    parameters = {'toolchain_author':  request.user.username,
-                  'toolchain_name':    name,
-                  'toolchain_version': 1,
-                  'fork_of':           fork_of,
-                  'declaration':       fork_of.declaration_string.replace('\n', ''),
-                  'short_description': fork_of.short_description,
-                  'description':       description.replace('\n', '\\n'),
-                  'errors':            errors.replace('\n', '\\n'),
-                  'edition':           False,
-                  'messages':          Messages,
-                 }
+    parameters = {
+        "toolchain_author": request.user.username,
+        "toolchain_name": name,
+        "toolchain_version": 1,
+        "fork_of": fork_of,
+        "declaration": fork_of.declaration_string.replace("\n", ""),
+        "short_description": fork_of.short_description,
+        "description": description.replace("\n", "\\n"),
+        "errors": errors.replace("\n", "\\n"),
+        "edition": False,
+        "messages": Messages,
+    }
 
-    return render(request,
-                  'toolchains/edition.html',
-                  parameters)
+    return render(request, "toolchains/edition.html", parameters)
 
 
 @login_required
@@ -136,29 +137,33 @@ def edit(request, author, name, version):
         raise Http404()
 
     # Retrieves the toolchain
-    toolchain = get_object_or_404(Toolchain,
-                                  author__username__iexact=author,
-                                  name__iexact=name,
-                                  version=int(version)
-                                 )
+    toolchain = get_object_or_404(
+        Toolchain,
+        author__username__iexact=author,
+        name__iexact=name,
+        version=int(version),
+    )
 
     description = ensure_string(toolchain.description)
     errors = ensure_string(toolchain.errors)
 
     # Render the page
-    return render(request,
-                  'toolchains/edition.html',
-                  {'toolchain_author':  request.user.username,
-                   'toolchain_name':    name,
-                   'toolchain_version': toolchain.version,
-                   'declaration':       toolchain.declaration_string.replace('\n', ''),
-                   'short_description': toolchain.short_description,
-                   'description':       description.replace('\n', '\\n'),
-                   'html_description':  restructuredtext(description).replace('\n', ''),
-                   'errors':            errors.replace('\n', '\\n'),
-                   'edition':           True,
-                   'messages':          Messages,
-                  })
+    return render(
+        request,
+        "toolchains/edition.html",
+        {
+            "toolchain_author": request.user.username,
+            "toolchain_name": name,
+            "toolchain_version": toolchain.version,
+            "declaration": toolchain.declaration_string.replace("\n", ""),
+            "short_description": toolchain.short_description,
+            "description": description.replace("\n", "\\n"),
+            "html_description": restructuredtext(description).replace("\n", ""),
+            "errors": errors.replace("\n", "\\n"),
+            "edition": True,
+            "messages": Messages,
+        },
+    )
 
 
 def view(request, author, name, version=None):
@@ -175,8 +180,9 @@ def view(request, author, name, version=None):
             version=int(version),
         )
     else:
-        toolchain = Toolchain.objects.filter(author__username__iexact=author,
-                                             name__iexact=name).order_by('-version')
+        toolchain = Toolchain.objects.filter(
+            author__username__iexact=author, name__iexact=name
+        ).order_by("-version")
         if not toolchain:
             raise Http404()
         else:
@@ -187,25 +193,29 @@ def view(request, author, name, version=None):
     if not has_access:
         raise Http404()
 
-    owner = (request.user == toolchain.author)
+    owner = request.user == toolchain.author
 
     reports = None
-    if not request.user.is_anonymous: #fetch user reports, if any
+    if not request.user.is_anonymous:  # fetch user reports, if any
         reports = Report.objects.filter(author=request.user)
 
     # 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,
-                  'toolchains/view.html',
-                  {
-                      'toolchain': toolchain,
-                      'owner': owner,
-                      'reports': reports,
-                      'users': users,
-                      'teams': Team.objects.for_user(request.user, True)
-                  })
+    return render(
+        request,
+        "toolchains/view.html",
+        {
+            "toolchain": toolchain,
+            "owner": owner,
+            "reports": reports,
+            "users": users,
+            "teams": Team.objects.for_user(request.user, True),
+        },
+    )
 
 
 def diff(request, author1, name1, version1, author2, name2, version2):
@@ -220,7 +230,8 @@ def diff(request, author1, name1, version1, author2, name2, version2):
         version=int(version1),
     )
     has_access, _ = toolchain1.accessibility_for(request.user)
-    if not has_access: raise Http404()
+    if not has_access:
+        raise Http404()
 
     toolchain2 = get_object_or_404(
         Toolchain,
@@ -229,49 +240,47 @@ def diff(request, author1, name1, version1, author2, name2, version2):
         version=int(version2),
     )
     has_access, _ = toolchain2.accessibility_for(request.user)
-    if not has_access: raise Http404()
+    if not has_access:
+        raise Http404()
 
-    return render(request,
-                  'toolchains/diff.html',
-                  {
-                      'toolchain1':  toolchain1,
-                      'toolchain2':  toolchain2,
-                  })
+    return render(
+        request,
+        "toolchains/diff.html",
+        {"toolchain1": toolchain1, "toolchain2": toolchain2},
+    )
 
 
 def ls(request, author_name):
-    '''List all accessible toolchains to the request user'''
+    """List all accessible toolchains 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 toolchains so that the latest information is displayed first
-    objects = Toolchain.objects.from_author_and_public(request.user,
-                                                       author_name).order_by('-creation_date')
+    objects = Toolchain.objects.from_author_and_public(
+        request.user, author_name
+    ).order_by("-creation_date")
     objects = Toolchain.filter_latest_versions(objects)
 
-    return render(request,
-                  'toolchains/list.html',
-                  dict(
-                      objects=objects,
-                      author=author,
-                      owner=(request.user==author),
-                  ))
+    return render(
+        request,
+        "toolchains/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 more recent are first
-    objects = Toolchain.objects.public().order_by('-creation_date')
+    objects = Toolchain.objects.public().order_by("-creation_date")
     objects = Toolchain.filter_latest_versions(objects)
 
-    return render(request,
-                  'toolchains/list.html',
-                  dict(
-                      objects=objects,
-                      author=request.user, #anonymous
-                      owner=False,
-                  ))
+    return render(
+        request,
+        "toolchains/list.html",
+        dict(objects=objects, author=request.user, owner=False,),  # anonymous
+    )