diff --git a/beat/web/algorithms/models.py b/beat/web/algorithms/models.py
index 3b74c9df06aa739e0b85b3c610da80fc81fc62c9..a4d4e5aaa8e29e45a6ceb64b46108e3ed1b0dbe0 100755
--- a/beat/web/algorithms/models.py
+++ b/beat/web/algorithms/models.py
@@ -28,7 +28,6 @@
 from django.db import models
 from django.conf import settings
 from django.core.urlresolvers import reverse
-from django.db.models import Count, Q
 
 import beat.core.algorithm
 import beat.core.library
@@ -49,21 +48,22 @@ from ..libraries.models import Library
 
 import simplejson
 import collections
-import itertools
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 def validate_algorithm(declaration):
     """Validates the declaration of an algorithm code, returns wrapper"""
 
     if not declaration:
-        raise SyntaxError('Algorithm declaration cannot be empty')
+        raise SyntaxError("Algorithm declaration cannot be empty")
 
-    if not(isinstance(declaration, dict)):
+    if not isinstance(declaration, dict):
         try:
-            declaration_dict = simplejson.loads(declaration, object_pairs_hook=collections.OrderedDict)
+            declaration_dict = simplejson.loads(
+                declaration, object_pairs_hook=collections.OrderedDict
+            )
         except Exception as e:
             raise SyntaxError(str(e))
     else:
@@ -72,154 +72,149 @@ def validate_algorithm(declaration):
     algorithm = beat.core.algorithm.Algorithm(settings.PREFIX, declaration_dict)
 
     if not algorithm.valid:
-        raise SyntaxError('\n  * %s' % '\n  * '.join(algorithm.errors))
+        raise SyntaxError("\n  * %s" % "\n  * ".join(algorithm.errors))
 
     return algorithm
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class AlgorithmStorage(OverwriteStorage):
-
     def __init__(self, *args, **kwargs):
-        kwargs['location'] = settings.ALGORITHMS_ROOT
+        kwargs["location"] = settings.ALGORITHMS_ROOT
         super(AlgorithmStorage, self).__init__(*args, **kwargs)
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class AlgorithmManager(CodeManager):
-
-    def create_algorithm(self, author, name, short_description='',
-                         description='', declaration=None, code=None, version=1,
-                         previous_version=None, fork_of=None):
+    def create_algorithm(
+        self,
+        author,
+        name,
+        short_description="",
+        description="",
+        declaration=None,
+        code=None,
+        version=1,
+        previous_version=None,
+        fork_of=None,
+    ):
 
         default = beat.core.algorithm.Algorithm(settings.PREFIX, data=None)
 
-        return self.create_code(author, name, default, short_description,
-                                description, declaration, code, version,
-                                previous_version, fork_of)
+        return self.create_code(
+            author,
+            name,
+            default,
+            short_description,
+            description,
+            declaration,
+            code,
+            version,
+            previous_version,
+            fork_of,
+        )
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class Algorithm(Code):
 
-    LEGACY     = 'L'
-    SEQUENTIAL = 'S'
-    AUTONOMOUS = 'A'
+    LEGACY = "L"
+    SEQUENTIAL = "S"
+    AUTONOMOUS = "A"
 
-    TYPES = (
-        (LEGACY,     'Legacy'),
-        (SEQUENTIAL, 'Sequential'),
-        (AUTONOMOUS, 'Autonomous'),
-    )
+    TYPES = ((LEGACY, "Legacy"), (SEQUENTIAL, "Sequential"), (AUTONOMOUS, "Autonomous"))
 
-
-    #_____ Fields __________
+    # _____ Fields __________
 
     declaration_file = models.FileField(
         storage=AlgorithmStorage(),
         upload_to=get_contribution_declaration_filename,
-        blank=True, null=True,
+        blank=True,
+        null=True,
         max_length=200,
-        db_column='declaration'
+        db_column="declaration",
     )
 
     description_file = models.FileField(
         storage=AlgorithmStorage(),
         upload_to=get_contribution_description_filename,
-        blank=True, null=True,
+        blank=True,
+        null=True,
         max_length=200,
-        db_column='description'
+        db_column="description",
     )
 
     source_code_file = models.FileField(
         storage=AlgorithmStorage(),
         upload_to=get_contribution_source_code_filename,
-        blank=True, null=True,
+        blank=True,
+        null=True,
         max_length=200,
-        db_column='source_code'
+        db_column="source_code",
     )
 
     # Read-only parameters that are updated at every save(), if required
-    parameters        = models.TextField(blank=True, null=True)
+    parameters = models.TextField(blank=True, null=True)
     result_dataformat = models.TextField(blank=True, null=True)
-    splittable        = models.BooleanField(default=False,
-                                            help_text='Defines if the code can be executed ' \
-                                            'in multiple instances')
-    type              = models.CharField(max_length=1, choices=TYPES, default=SEQUENTIAL)
+    splittable = models.BooleanField(
+        default=False,
+        help_text="Defines if the code can be executed " "in multiple instances",
+    )
+    type = models.CharField(max_length=1, choices=TYPES, default=SEQUENTIAL)
 
-    referenced_libraries = models.ManyToManyField(Library,
-                                                  blank=True, related_name='used_by_algorithms',
-                                                  symmetrical=False)
+    referenced_libraries = models.ManyToManyField(
+        Library, blank=True, related_name="used_by_algorithms", symmetrical=False
+    )
 
     objects = AlgorithmManager()
 
-
-    #_____ Utilities __________
+    # _____ Utilities __________
 
     def get_absolute_url(self):
 
         return reverse(
-            'algorithms:view',
-                args=(self.author.username, self.name, self.version,),
+            "algorithms: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_algorithms:object',
-                args=(self.author.username, self.name, self.version,),
+            "api_algorithms: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_algorithms:share',
-                args=(self.author.username, self.name, self.version,),
+            "api_algorithms:share", args=(self.author.username, self.name, self.version)
         )
 
-
     def environments(self):
-        '''Calculates environment usage for this algorithm
+        """Calculates environment usage for this algorithm
 
         Returns:
 
-          list: mapping environment to usage counts, determining how many times
-            a given algorithm has been successfuly used on that environment
+          list: annotated environment with usage counts, determining how many times
+            a given algorithm has been successfully used on that environment
 
-        '''
+        """
 
-        from ..experiments.models import Block
-        from ..experiments.models import Experiment
         from ..backend.models import Environment
 
-
         # Tries to figure through a maximum if an algorithm has been
-        # successfuly used inside an environment.
-
-        # Case 1) The block is part of an experiment that was successful
-        # Case 2) The block is part of an experiment that is not successful
-        # (failed or other), but it is CACHED (if not cached, then we can't
-        # attest anything about the algorithm/environment relationship!)
+        # successfully used inside an environment.
 
-        envs = Environment.objects.filter(blocks__in=self.blocks.filter(
-            Q(experiment__status=Experiment.DONE) | \
-            ((~Q(experiment__status=Experiment.DONE)) & Q(status=Block.DONE))
-        )).annotate(itemcount=Count('id')).order_by('-creation_date').distinct()
+        return Environment.objects.use_count(self.blocks)
 
-        return [(k, k.itemcount) for k in envs]
-
-
-    #_____ Overrides __________
+    # _____ Overrides __________
 
     def save(self, *args, **kwargs):
         wrapper = self._save_preprocessing()
@@ -229,44 +224,45 @@ class Algorithm(Code):
         else:
             parameters = []
             for name, details in wrapper.parameters.items():
-                parameters.append({
-                    "name":          name,
-                    "default_value": details.get('default'),
-                    "comment":       details.get('description', ''),
-                    "type":          details['type'],
-                }
+                parameters.append(
+                    {
+                        "name": name,
+                        "default_value": details.get("default"),
+                        "comment": details.get("description", ""),
+                        "type": details["type"],
+                    }
                 )
 
-                if 'choice' in details:
-                    parameters[-1]['choices'] = details['choice']
+                if "choice" in details:
+                    parameters[-1]["choices"] = details["choice"]
 
-                if 'range' in details:
-                    parameters[-1]['minimum'] = details['range'][0]
-                    parameters[-1]['maximum'] = details['range'][1]
+                if "range" in details:
+                    parameters[-1]["minimum"] = details["range"][0]
+                    parameters[-1]["maximum"] = details["range"][1]
 
-            self.parameters = simplejson.dumps(parameters,
-                                               indent=4,
-                                               cls=NumpyJSONEncoder)
+            self.parameters = simplejson.dumps(
+                parameters, indent=4, cls=NumpyJSONEncoder
+            )
 
         if not wrapper.results:
             self.result_dataformat = None
         else:
             results = {}
             for name, details in wrapper.results.items():
-                key = name if not details.get('display') else ('+' + name)
-                results[key] = details['type']
+                key = name if not details.get("display") else ("+" + name)
+                results[key] = details["type"]
 
-            self.result_dataformat = simplejson.dumps(results,
-                                                      indent=4,
-                                                      cls=NumpyJSONEncoder)
+            self.result_dataformat = simplejson.dumps(
+                results, indent=4, cls=NumpyJSONEncoder
+            )
 
         # Set splittability
         self.splittable = wrapper.splittable
 
         # Set type
-        if wrapper.type == 'sequential':
+        if wrapper.type == "sequential":
             self.type = Algorithm.SEQUENTIAL
-        elif wrapper.type == 'autonomous':
+        elif wrapper.type == "autonomous":
             self.type = Algorithm.AUTONOMOUS
         else:
             self.type = Algorithm.LEGACY
@@ -279,34 +275,37 @@ class Algorithm(Code):
         if wrapper.uses is not None:
             for l in set(wrapper.uses.values()):
                 s = beat.core.library.Storage(settings.PREFIX, l)
-                library = Library.objects.get(author__username=s.username,
-                                              name=s.name,
-                                              version=s.version,
-                                             )
+                library = Library.objects.get(
+                    author__username=s.username, name=s.name, version=s.version
+                )
                 self.referenced_libraries.add(library)
 
-
     def share(self, public, users=None, teams=None):
         self._share_dataformats(users=users, teams=teams)
         super(Algorithm, self).share(public=public, users=users, teams=teams)
 
-
-    #_____ Methods __________
+    # _____ Methods __________
 
     def validate(self, declaration):
         return validate_algorithm(declaration)
 
     def analysis(self):
-        return (self.result_dataformat is not None)
+        return self.result_dataformat is not None
 
     def all_referenced_result_dataformats(self):
         retval = set()
         if self.result_dataformat:
             result_dataformat = simplejson.loads(self.result_dataformat)
             for value in result_dataformat.values():
-                elements = value.split('/')
+                elements = value.split("/")
                 if len(elements) == 3:
-                    retval.add(DataFormat.objects.get(author__username=elements[0], name=elements[1], version=elements[2]))
+                    retval.add(
+                        DataFormat.objects.get(
+                            author__username=elements[0],
+                            name=elements[1],
+                            version=elements[2],
+                        )
+                    )
         return retval
 
     def all_referenced_dataformats(self):
@@ -322,33 +321,32 @@ class Algorithm(Code):
         return list(set(result))
 
     def modifiable(self):
-        return (self.experiments.count() == 0) and super(Algorithm, self).modifiable()
+        return self.experiments.count() == 0 and super(Algorithm, self).modifiable()
 
     def deletable(self):
-        return (self.experiments.count() == 0) and super(Algorithm, self).deletable()
+        return self.experiments.count() == 0 and super(Algorithm, self).deletable()
 
     def valid(self):
-        return (self.source_code_file.name is not None) and (self.source_code_file.name != '')
-
+        return (
+            self.source_code_file.name is not None and self.source_code_file.name != ""
+        )
 
     def core(self):
         return validate_algorithm(self.declaration)
 
-
     def uses_and_groups(self):
         core = self.core()
         return core.uses, core.groups
 
-
     def json_parameters(self):
         return simplejson.loads(self.parameters) if self.parameters else []
 
-
     def json_result(self):
-        return simplejson.loads(self.result_dataformat) if self.result_dataformat else {}
-
+        return (
+            simplejson.loads(self.result_dataformat) if self.result_dataformat else {}
+        )
 
-    #_____ Protected methods __________
+    # _____ Protected methods __________
 
     def _share_dataformats(self, users, teams):
         # Retrieve and process the list of referenced dataformats
@@ -369,15 +367,15 @@ class Algorithm(Code):
             dataformats.share(users=users, teams=teams)
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class AlgorithmEndpoint(models.Model):
-    algorithm  = models.ForeignKey(Algorithm, related_name='endpoints')
-    input      = models.BooleanField(default=False)
-    name       = models.CharField(max_length=200)
-    dataformat = models.ForeignKey(DataFormat, related_name='algorithm_endpoints')
-    channel    = models.CharField(max_length=200)
+    algorithm = models.ForeignKey(Algorithm, related_name="endpoints")
+    input = models.BooleanField(default=False)
+    name = models.CharField(max_length=200)
+    dataformat = models.ForeignKey(DataFormat, related_name="algorithm_endpoints")
+    channel = models.CharField(max_length=200)
 
     def __str__(self):
-        return self.algorithm.fullname() + ', ' + self.name
+        return self.algorithm.fullname() + ", " + self.name
diff --git a/beat/web/algorithms/serializers.py b/beat/web/algorithms/serializers.py
index fa486b256cc72ef6264736c9e57458beba52920b..3f40b5be298074e110c7e9d823fc58c9a13fb290 100755
--- a/beat/web/algorithms/serializers.py
+++ b/beat/web/algorithms/serializers.py
@@ -25,6 +25,10 @@
 #                                                                             #
 ###############################################################################
 
+import simplejson as json
+
+import beat.core.algorithm
+
 from rest_framework import serializers
 from operator import itemgetter
 
@@ -34,15 +38,12 @@ 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 .models import Algorithm
 
-import simplejson as json
-
-import beat.core.algorithm
-
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class AlgorithmCreationSerializer(CodeCreationSerializer):
@@ -51,7 +52,7 @@ class AlgorithmCreationSerializer(CodeCreationSerializer):
         beat_core_class = beat.core.algorithm
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class AlgorithmSerializer(CodeSerializer):
@@ -62,13 +63,17 @@ class AlgorithmSerializer(CodeSerializer):
     outputs = serializers.SerializerMethodField()
     referencing_experiments = serializers.SerializerMethodField()
     referenced_libraries = LibraryReferenceSerializer(many=True)
-    referenced_dataformats = ReferencedDataFormatSerializer(many=True, source='all_referenced_dataformats')
-    needed_dataformats = ReferencedDataFormatSerializer(many=True, source='all_needed_dataformats')
+    referenced_dataformats = ReferencedDataFormatSerializer(
+        many=True, source="all_referenced_dataformats"
+    )
+    needed_dataformats = ReferencedDataFormatSerializer(
+        many=True, source="all_needed_dataformats"
+    )
+    environments = EnvironmentInfoSerializer(many=True)
 
     class Meta(CodeSerializer.Meta):
         model = Algorithm
 
-
     def get_result_dataformat(self, obj):
         return json.loads(obj.result_dataformat) if obj.result_dataformat else None
 
@@ -76,33 +81,45 @@ class AlgorithmSerializer(CodeSerializer):
         return json.loads(obj.parameters) if obj.parameters else None
 
     def get_inputs(self, obj):
-        return map(lambda x: {
-            'name': x.name,
-                  'dataformat': x.dataformat.fullname(),
-                  'channel': x.channel
-        }, obj.endpoints.filter(input=True).order_by('name'))
+        return map(
+            lambda x: {
+                "name": x.name,
+                "dataformat": x.dataformat.fullname(),
+                "channel": x.channel,
+            },
+            obj.endpoints.filter(input=True).order_by("name"),
+        )
 
     def get_outputs(self, obj):
-        return map(lambda x: {
-            'name': x.name,
-                        'dataformat': x.dataformat.fullname(),
-                        'channel': x.channel,
-        }, obj.endpoints.filter(input=False).order_by('name'))
+        return map(
+            lambda x: {
+                "name": x.name,
+                "dataformat": x.dataformat.fullname(),
+                "channel": x.channel,
+            },
+            obj.endpoints.filter(input=False).order_by("name"),
+        )
 
     def get_referencing_experiments(self, obj):
-        user = self.context.get('user')
-        experiments = Experiment.objects.for_user(user, True).filter(blocks=obj.blocks.all()).distinct()
+        user = self.context.get("user")
+        experiments = (
+            Experiment.objects.for_user(user, True)
+            .filter(blocks=obj.blocks.all())
+            .distinct()
+        )
         serializer = ExperimentSerializer(experiments, many=True)
         referencing_experiments = serializer.data
 
         # Put the pending experiments first
-        return sorted(referencing_experiments, key=itemgetter('creation_date'))
+        return sorted(referencing_experiments, key=itemgetter("creation_date"))
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class FullAlgorithmSerializer(AlgorithmSerializer):
-
     class Meta(AlgorithmSerializer.Meta):
-        default_fields = AlgorithmSerializer.Meta.default_fields + AlgorithmSerializer.Meta.extra_fields
+        default_fields = (
+            AlgorithmSerializer.Meta.default_fields
+            + AlgorithmSerializer.Meta.extra_fields
+        )
diff --git a/beat/web/algorithms/templates/algorithms/view.html b/beat/web/algorithms/templates/algorithms/view.html
index 1998f2d4176760f93ebdcc141ecb992c80122f25..e36218cdc3488a2f25de076dd2934671186b77a6 100644
--- a/beat/web/algorithms/templates/algorithms/view.html
+++ b/beat/web/algorithms/templates/algorithms/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 %}
@@ -128,7 +128,7 @@
           This algorithm was never executed.
           {% else %}
           <ul class="list-group">
-            {% for key, value in execinfo %}<li class="list-group-item"><a title="Click to view" data-toggle="tooltip" data-placement="top" href="{% url 'backend:view-environment' key.name key.version %}">{{ key.fullname }}</a> <span class="badge">{{ value }}</span></li>{% endfor %}
+            {% for info in execinfo %}<li class="list-group-item"><a title="Click to view" data-toggle="tooltip" data-placement="top" href="{% url 'backend:view-environment' info.name info.version %}">{{ info.fullname }}</a> <span class="badge">{{ info.use_count }}</span></li>{% endfor %}
           </ul>
           <p class="help">This table shows the number of times this algorithm
           has been <b>successfully</b> run using the given environment. Note
diff --git a/beat/web/backend/models/environment.py b/beat/web/backend/models/environment.py
index 7233b79201caf2ca1f14e49ba7f1f308509d975c..3dc14b3334dbc797d0945af893e1bf2a15c6a9f9 100755
--- a/beat/web/backend/models/environment.py
+++ b/beat/web/backend/models/environment.py
@@ -27,6 +27,7 @@
 
 from django.db import models
 from django.core.urlresolvers import reverse
+from django.db.models import Count, Q
 
 from ...code.models import Code
 from ...common.models import Shareable
@@ -34,112 +35,122 @@ from ...common.models import ShareableManager
 from ...common.texts import Messages
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class EnvironmentManager(ShareableManager):
-
     def get_by_natural_key(self, name, version):
         return self.get(name=name, version=version)
 
     def get_by_fullname(self, fullname):
-        name, version = fullname.rsplit(' ', 1)
+        name, version = fullname.rsplit(" ", 1)
         return self.get_by_natural_key(name, version[1:-1])
 
+    def use_count(self, block_list):
+        """Returns a list of environments used for the blocks in that list with
+        how many times each has been used.
+
+        Parameters:
+            block_list (Block) : list of blocks to analyze.
+
+        Returns:
+            list: annotated environments with the number of time they have been
+                used for blocks that are done.
+        """
+
+        from ...experiments.models import Experiment
+        from ...experiments.models import Block
+
+        # Tries to figure through a maximum if blocks in the list have been
+        # successfully used inside an environment.
+
+        # Case 1) The block is part of an experiment that was successful
+        # Case 2) The block is part of an experiment that is not successful
+        # (failed or other), but it is CACHED (if not cached, then we can't
+        # attest anything about the block/environment relationship!)
+
+        return (
+            self.filter(
+                blocks__in=block_list.filter(
+                    Q(experiment__status=Experiment.DONE)
+                    | ((~Q(experiment__status=Experiment.DONE)) & Q(status=Block.DONE))
+                )
+            )
+            .annotate(use_count=Count("id"))
+            .order_by("-creation_date")
+            .distinct()
+        )
+
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class Environment(Shareable):
     """Defines a software environment to run algorithms"""
 
-    name = models.CharField(
-        max_length=200,
-        help_text=Messages['name'],
-    )
+    name = models.CharField(max_length=200, help_text=Messages["name"])
 
     version = models.CharField(
         max_length=20,
-        help_text='Free-style version for this environment (normally read from the Worker/Scheduler available environments)',
+        help_text="Free-style version for this environment (normally read from the Worker/Scheduler available environments)",
     )
 
     short_description = models.CharField(
-        max_length=100,
-        default='',
-        blank=True,
-        help_text=Messages['short_description'],
+        max_length=100, default="", blank=True, help_text=Messages["short_description"]
     )
 
     description = models.TextField(
-        default='',
-        blank=True,
-        help_text=Messages['description'],
+        default="", blank=True, help_text=Messages["description"]
     )
 
-    creation_date = models.DateTimeField(
-        'Creation date',
-        auto_now_add = True,
-    )
+    creation_date = models.DateTimeField("Creation date", auto_now_add=True)
 
     active = models.BooleanField(
-        default=True,
-        help_text='If this environment can be used in experiments',
+        default=True, help_text="If this environment can be used in experiments"
     )
 
     previous_version = models.ForeignKey(
-        'self',
-        related_name='next_versions',
+        "self",
+        related_name="next_versions",
         null=True,
         blank=True,
         on_delete=models.SET_NULL,
     )
 
-
     objects = EnvironmentManager()
 
-
-    #_____ Meta parameters __________
+    # _____ Meta parameters __________
 
     class Meta:
-        unique_together = ('name', 'version')
+        unique_together = ("name", "version")
 
-
-    #_____ Overrides __________
+    # _____ Overrides __________
 
     def __str__(self):
         return self.fullname()
 
-
     def natural_key(self):
         return (self.name, self.version)
 
-
-    #_____ Utilities __________
+    # _____ Utilities __________
 
     def fullname(self):
-        return '%s (%s)' % (self.name, self.version)
-
+        return "%s (%s)" % (self.name, self.version)
 
     def get_absolute_url(self):
-        return reverse(
-            'backend:view-environment',
-            args=(self.name, self.version,),
-        )
-
+        return reverse("backend:view-environment", args=(self.name, self.version))
 
     def get_admin_change_url(self):
-        return reverse('admin:backend_environment_change', args=(self.id,))
-
+        return reverse("admin:backend_environment_change", args=(self.id,))
 
     def queues_for(self, user):
         """Returns all queues associated to this environment for which the user
         has the 'can_access' permission"""
 
-        return [q for q in self.queues.all() if user.has_perm('backend.can_access', q)]
-
+        return [q for q in self.queues.all() if user.has_perm("backend.can_access", q)]
 
     def as_dict(self):
-        '''Returns a representation as a dictionary'''
+        """Returns a representation as a dictionary"""
 
         return dict(
             name=self.name,
@@ -149,12 +160,13 @@ class Environment(Shareable):
         )
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class EnvironmentLanguage(models.Model):
 
-    environment = models.ForeignKey(Environment, related_name='languages')
+    environment = models.ForeignKey(Environment, related_name="languages")
 
-    language = models.CharField(max_length=1, choices=Code.CODE_LANGUAGE,
-                                default=Code.PYTHON)
+    language = models.CharField(
+        max_length=1, choices=Code.CODE_LANGUAGE, default=Code.PYTHON
+    )
diff --git a/beat/web/backend/serializers.py b/beat/web/backend/serializers.py
new file mode 100644
index 0000000000000000000000000000000000000000..2de73c3144c1b9a0d1800fd88fc9c5cb567cf99a
--- /dev/null
+++ b/beat/web/backend/serializers.py
@@ -0,0 +1,35 @@
+###############################################################################
+#                                                                             #
+# Copyright (c) 2020 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/.           #
+#                                                                             #
+###############################################################################
+
+from rest_framework import serializers
+
+from .models import Environment
+
+
+class EnvironmentInfoSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Environment
+        fields = ["name", "version", "use_count"]
+
+    use_count = serializers.IntegerField()
diff --git a/beat/web/libraries/models.py b/beat/web/libraries/models.py
index 6e85a6cc010f5a00529f0f2d62c7158e6ecb9973..685ec3fba5c484b73839d710c95966f551742693 100644
--- a/beat/web/libraries/models.py
+++ b/beat/web/libraries/models.py
@@ -43,18 +43,20 @@ import simplejson
 import collections
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 def validate_library(declaration):
     """Validates the declaration of a library code, returns wrapper"""
 
     if not declaration:
-        raise SyntaxError('Library declaration cannot be empty')
+        raise SyntaxError("Library declaration cannot be empty")
 
-    if not(isinstance(declaration, dict)):
+    if not (isinstance(declaration, dict)):
         try:
-            declaration_dict = simplejson.loads(declaration, object_pairs_hook=collections.OrderedDict)
+            declaration_dict = simplejson.loads(
+                declaration, object_pairs_hook=collections.OrderedDict
+            )
         except Exception as e:
             raise SyntaxError(str(e))
     else:
@@ -63,111 +65,122 @@ def validate_library(declaration):
     library = beat.core.library.Library(settings.PREFIX, declaration_dict)
 
     if not library.valid:
-        raise SyntaxError('\n  * %s' % '\n  * '.join(library.errors))
+        raise SyntaxError("\n  * %s" % "\n  * ".join(library.errors))
 
     return library
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class LibraryStorage(OverwriteStorage):
-
     def __init__(self, *args, **kwargs):
-        kwargs['location'] = settings.LIBRARIES_ROOT
+        kwargs["location"] = settings.LIBRARIES_ROOT
         super(LibraryStorage, self).__init__(*args, **kwargs)
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class LibraryManager(CodeManager):
-
-    def create_library(self, author, name, short_description='',
-                       description='', declaration=None, code=None, version=1,
-                       previous_version=None, fork_of=None):
+    def create_library(
+        self,
+        author,
+        name,
+        short_description="",
+        description="",
+        declaration=None,
+        code=None,
+        version=1,
+        previous_version=None,
+        fork_of=None,
+    ):
 
         default = beat.core.library.Library(settings.PREFIX, data=None)
 
-        return self.create_code(author, name, default, short_description,
-                                description, declaration, code, version,
-                                previous_version, fork_of)
+        return self.create_code(
+            author,
+            name,
+            default,
+            short_description,
+            description,
+            declaration,
+            code,
+            version,
+            previous_version,
+            fork_of,
+        )
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class Library(Code):
 
-    #_____ Fields __________
+    # _____ Fields __________
 
     declaration_file = models.FileField(
         storage=LibraryStorage(),
         upload_to=get_contribution_declaration_filename,
-        blank=True, null=True,
+        blank=True,
+        null=True,
         max_length=200,
-        db_column='declaration'
+        db_column="declaration",
     )
 
     description_file = models.FileField(
         storage=LibraryStorage(),
         upload_to=get_contribution_description_filename,
-        blank=True, null=True,
+        blank=True,
+        null=True,
         max_length=200,
-        db_column='description'
+        db_column="description",
     )
 
     source_code_file = models.FileField(
         storage=LibraryStorage(),
         upload_to=get_contribution_source_code_filename,
-        blank=True, null=True,
+        blank=True,
+        null=True,
         max_length=200,
-        db_column='source_code'
+        db_column="source_code",
     )
 
     # Read-only parameters that are updated at every save(), if required
-    referenced_libraries = models.ManyToManyField('self',
-                                                  blank=True, related_name='referencing',
-                                                  symmetrical=False)
+    referenced_libraries = models.ManyToManyField(
+        "self", blank=True, related_name="referencing", symmetrical=False
+    )
 
     objects = LibraryManager()
 
-
-    #_____ Meta parameters __________
+    # _____ Meta parameters __________
 
     class Meta(Code.Meta):
-        verbose_name_plural = 'libraries'
+        verbose_name_plural = "libraries"
 
-
-    #_____ Utilities __________
+    # _____ Utilities __________
 
     def get_absolute_url(self):
 
         return reverse(
-            'libraries:view',
-                args=(self.author.username, self.name, self.version,),
+            "libraries: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_libraries:object',
-                args=(self.author.username, self.name, self.version,),
+            "api_libraries: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_libraries:share',
-                args=(self.author.username, self.name, self.version,),
+            "api_libraries:share", args=(self.author.username, self.name, self.version)
         )
 
-
-    #_____ Overrides __________
+    # _____ Overrides __________
 
     def save(self, *args, **kwargs):
         wrapper = self._save_preprocessing()
@@ -179,69 +192,54 @@ class Library(Code):
         if wrapper.uses is not None:
             for l in set(wrapper.uses.values()):
                 s = beat.core.library.Storage(settings.PREFIX, l)
-                library = Library.objects.get(author__username=s.username,
-                                              name=s.name,
-                                              version=s.version,
-                                             )
+                library = Library.objects.get(
+                    author__username=s.username, name=s.name, version=s.version
+                )
                 self.referenced_libraries.add(library)
 
-
-    #_____ Methods __________
+    # _____ Methods __________
 
     def validate(self, declaration):
         return validate_library(declaration)
 
-
     def modifiable(self):
         """Can modify if nobody points at me"""
-        return super(Library, self).modifiable() and ((self.referencing.count() + self.used_by_algorithms.count()) == 0)
-
+        return super(Library, self).modifiable() and (
+            (self.referencing.count() + self.used_by_algorithms.count()) == 0
+        )
 
     def deletable(self):
         """Can delete if nobody points at me"""
-        return super(Library, self).deletable() and ((self.referencing.count() + self.used_by_algorithms.count()) == 0)
-
+        return super(Library, self).deletable() and (
+            (self.referencing.count() + self.used_by_algorithms.count()) == 0
+        )
 
     def valid(self):
-        return True     # A library (at least for now) is always implemented in Python,
-                        # thus always valid
+        return True  # A library (at least for now) is always implemented in Python,
+        # thus always valid
 
     def core(self):
         return validate_library(self.declaration)
 
-
     def uses(self):
         return self.core().uses
 
-
     def environments(self):
-        '''Calculates environment usage for this library
+        """Calculates environment usage for this library
 
         Returns:
 
-          list: mapping environment to usage counts, determining how many times
-            a given algorithm has been successfuly used on that environment
+          list: annotated environment with usage counts, determining how many times
+            a given library used in algorithms has been successfully used on that environment
 
-        '''
+        """
 
-        from django.db.models import Count, Q
         from ..experiments.models import Block
-        from ..experiments.models import Experiment
         from ..backend.models import Environment
 
         # Tries to figure through a maximum if using algorithms have been
-        # successfuly used inside an environment.
-
-        # Case 1) The block is part of an experiment that was successful
-        # Case 2) The block is part of an experiment that is not successful
-        # (failed or other), but it is CACHED (if not cached, then we can't
-        # attest anything about the algorithm/environment relationship!)
+        # successfully used inside an environment.
 
-        envs = Environment.objects.filter(blocks__in=Block.objects.filter( \
-            algorithm__in=self.used_by_algorithms.all()).filter( \
-            Q(experiment__status=Experiment.DONE) | \
-            ((~Q(experiment__status=Experiment.DONE)) & Q(status=Block.DONE))
-        )).annotate(itemcount=Count('id')).order_by('-creation_date' \
-                ).distinct()
-
-        return [(k, k.itemcount) for k in envs]
+        return Environment.objects.use_count(
+            Block.objects.filter(algorithm__in=self.used_by_algorithms.all())
+        )
diff --git a/beat/web/libraries/serializers.py b/beat/web/libraries/serializers.py
index 3e2feb817950666e4c1116c984e60d39bd224243..4fac5d1c88da2d6abc049b3ddbde4ddd3401a4d9 100644
--- a/beat/web/libraries/serializers.py
+++ b/beat/web/libraries/serializers.py
@@ -25,17 +25,19 @@
 #                                                                             #
 ###############################################################################
 
+import beat.core.library
+
 from rest_framework import serializers
 
 from ..code.serializers import CodeSerializer, CodeCreationSerializer
 
-from .models import Library
 from ..algorithms.models import Algorithm
+from ..backend.serializers import EnvironmentInfoSerializer
 
-import beat.core.library
+from .models import Library
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class LibraryCreationSerializer(CodeCreationSerializer):
@@ -44,7 +46,7 @@ class LibraryCreationSerializer(CodeCreationSerializer):
         beat_core_class = beat.core.library
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class ReferenceSerializer(serializers.ModelSerializer):
@@ -53,49 +55,51 @@ class ReferenceSerializer(serializers.ModelSerializer):
     is_owner = serializers.SerializerMethodField()
 
     class Meta:
-        fields = ['name', 'short_description', 'accessibility', 'is_owner']
+        fields = ["name", "short_description", "accessibility", "is_owner"]
 
     def get_accessibility(self, obj):
         return obj.get_sharing_display().lower()
 
     def get_is_owner(self, obj):
-        return (obj.author == self.context.get('user'))
+        return obj.author == self.context.get("user")
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class LibraryReferenceSerializer(ReferenceSerializer):
-
     class Meta(ReferenceSerializer.Meta):
         model = Library
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class AlgorithmReferenceSerializer(ReferenceSerializer):
-
     class Meta(ReferenceSerializer.Meta):
         model = Algorithm
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class LibrarySerializer(CodeSerializer):
     referenced_libraries = LibraryReferenceSerializer(many=True)
-    referencing_libraries = LibraryReferenceSerializer(many=True, source='referencing')
-    referencing_algorithms = AlgorithmReferenceSerializer(many=True, source='used_by_algorithms')
+    referencing_libraries = LibraryReferenceSerializer(many=True, source="referencing")
+    referencing_algorithms = AlgorithmReferenceSerializer(
+        many=True, source="used_by_algorithms"
+    )
+    environments = EnvironmentInfoSerializer(many=True)
 
     class Meta(CodeSerializer.Meta):
         model = Library
 
 
-#----------------------------------------------------------
+# ----------------------------------------------------------
 
 
 class FullLibrarySerializer(LibrarySerializer):
-
     class Meta(LibrarySerializer.Meta):
-        default_fields = LibrarySerializer.Meta.default_fields + LibrarySerializer.Meta.extra_fields
+        default_fields = (
+            LibrarySerializer.Meta.default_fields + LibrarySerializer.Meta.extra_fields
+        )
diff --git a/beat/web/libraries/templates/libraries/view.html b/beat/web/libraries/templates/libraries/view.html
index dc37dfa75f0cc1cf1160a0ddff6b8e25818e15b5..b2fbe2da50fd8a9a4192e7e87a50bc5db6655f29 100644
--- a/beat/web/libraries/templates/libraries/view.html
+++ b/beat/web/libraries/templates/libraries/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 %}
@@ -174,7 +174,7 @@
           </div>
           {% else %}
           <ul class="list-group">
-            {% for key, value in execinfo %}<li class="list-group-item"><a title="Click to view" data-toggle="tooltip" data-placement="top" href="{% url 'backend:view-environment' key.name key.version %}">{{ key.fullname }}</a> <span class="badge">{{ value }}</span></li>{% endfor %}
+            {% for info in execinfo %}<li class="list-group-item"><a title="Click to view" data-toggle="tooltip" data-placement="top" href="{% url 'backend:view-environment' info.name info.version %}">{{ item.fullname }}</a> <span class="badge">{{ item.use_count }}</span></li>{% endfor %}
           </ul>
           <p class="help">This table shows the number of times this library
           has been <b>successfuly</b> used at a given environment. Note
diff --git a/beat/web/plotters/templates/plotters/view.html b/beat/web/plotters/templates/plotters/view.html
index 260400e042a0ada3e7317cf4e72aff0b86ad07ed..3d080a11c3a4a80bb73f22602f2126e472ab176a 100644
--- a/beat/web/plotters/templates/plotters/view.html
+++ b/beat/web/plotters/templates/plotters/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 %}
@@ -121,23 +121,6 @@
       <div role="tabpanel" class="tab-pane" id="history">
         {% history 'plotters' plotter 'history' 400 %}
       </div>
-      <div role="tabpanel" class="tab-pane" id="compatibility">
-        <div class="col-sm-5">
-          {% with plotter.environments as execinfo %}
-          {% if not execinfo %}
-          This plotter was never executed.
-          {% else %}
-          <ul class="list-group">
-            {% for key, value in execinfo %}<li class="list-group-item"><a title="Click to view" data-toggle="tooltip" data-placement="top" href="{% url 'backend:view-environment' key.name key.version %}">{{ key.fullname }}</a> <span class="badge">{{ value }}</span></li>{% endfor %}
-          </ul>
-          <p class="help">This table shows the number of times this plotter
-          has been <b>successfuly</b> run using the given environment. Note
-          this does not provide sufficient information to evaluate if the
-          plotter will run when submitted to different conditions.</p>
-          {% endif %}
-          {% endwith %}
-        </div>
-      </div>
     </div>
 
   </div>
diff --git a/common.cfg b/common.cfg
index faf2ab9c50a7aa47b1d1d9e2b7087819cdb5e0dd..cc651cee6056e85b79a2352e47ce6999d4167f0e 100644
--- a/common.cfg
+++ b/common.cfg
@@ -15,7 +15,8 @@ django-rest-swagger = >2.1
 django-guardian = >=1.4,<2.0
 djangorestframework = >3.7
 django-activity-stream = >= 0.6.5
-django-jsonfield = >= 1.0.1
+django-jsonfield = >=1.0.1
+django-post-office = <3.3
 jsonfield = <3.0
 
 [scripts]