From 10bec60c9f6e645b604f486537410a43ac44a792 Mon Sep 17 00:00:00 2001
From: Amir MOHAMMADI <amir.mohammadi@idiap.ch>
Date: Fri, 25 Feb 2022 15:20:20 +0100
Subject: [PATCH] pre-commit required changes

---
 CHANGELOG                                   |   2 +-
 bob/__init__.py                             |   1 +
 bob/fusion/__init__.py                      |   1 +
 bob/fusion/base/__init__.py                 |  18 +-
 bob/fusion/base/algorithm/AND.py            |  13 +-
 bob/fusion/base/algorithm/Algorithm.py      |  34 ++-
 bob/fusion/base/algorithm/AlgorithmBob.py   |  12 +-
 bob/fusion/base/algorithm/Empty.py          |  10 +-
 bob/fusion/base/algorithm/GMM.py            |  20 +-
 bob/fusion/base/algorithm/Weighted_Sum.py   |  13 +-
 bob/fusion/base/algorithm/__init__.py       |  16 +-
 bob/fusion/base/config/algorithm/gmm.py     |   6 +-
 bob/fusion/base/config/algorithm/llr_skl.py |  12 +-
 bob/fusion/base/config/algorithm/mean.py    |   9 +-
 bob/fusion/base/config/algorithm/plr_2.py   |  13 +-
 bob/fusion/base/config/algorithm/plr_3.py   |  13 +-
 bob/fusion/base/preprocessor/Tanh.py        |   8 +-
 bob/fusion/base/preprocessor/ZNorm.py       |   8 +-
 bob/fusion/base/preprocessor/__init__.py    |  12 +-
 bob/fusion/base/script/__init__.py          |   4 +-
 bob/fusion/base/script/boundary.py          |  34 ++-
 bob/fusion/base/script/fuse.py              | 317 +++++++++++++-------
 bob/fusion/base/script/fusion.py            |   4 +-
 bob/fusion/base/script/resource.py          |  37 ++-
 bob/fusion/base/test/test_algorithm.py      |  12 +-
 bob/fusion/base/test/test_preprocessor.py   |  50 ++-
 bob/fusion/base/test/test_scripts.py        |  12 +-
 bob/fusion/base/tools/__init__.py           |   6 +-
 bob/fusion/base/tools/common.py             |  67 +++--
 bob/fusion/base/tools/plotting.py           |   8 +-
 buildout.cfg                                |   2 +-
 develop.cfg                                 |   1 -
 doc/conf.py                                 | 150 ++++-----
 setup.py                                    |  83 +++--
 34 files changed, 585 insertions(+), 423 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 538671e..725a87c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1 +1 @@
-2.0.0  Initial stable release of the package.
\ No newline at end of file
+2.0.0  Initial stable release of the package.
diff --git a/bob/__init__.py b/bob/__init__.py
index 2ab1e28..edbb409 100644
--- a/bob/__init__.py
+++ b/bob/__init__.py
@@ -1,3 +1,4 @@
 # see https://docs.python.org/3/library/pkgutil.html
 from pkgutil import extend_path
+
 __path__ = extend_path(__path__, __name__)
diff --git a/bob/fusion/__init__.py b/bob/fusion/__init__.py
index 2ab1e28..edbb409 100644
--- a/bob/fusion/__init__.py
+++ b/bob/fusion/__init__.py
@@ -1,3 +1,4 @@
 # see https://docs.python.org/3/library/pkgutil.html
 from pkgutil import extend_path
+
 __path__ = extend_path(__path__, __name__)
diff --git a/bob/fusion/base/__init__.py b/bob/fusion/base/__init__.py
index 24c6385..0a5e912 100644
--- a/bob/fusion/base/__init__.py
+++ b/bob/fusion/base/__init__.py
@@ -1,14 +1,12 @@
-from . import algorithm
-from . import preprocessor
-from . import tools
-from . import config
-from . import script
+from . import algorithm, config, preprocessor, script, tools  # noqa: F401
+
 
 def get_config():
-  """Returns a string containing the configuration information.
-  """
-  import bob.extension
-  return bob.extension.get_config(__name__)
+    """Returns a string containing the configuration information."""
+    import bob.extension
+
+    return bob.extension.get_config(__name__)
+
 
 # gets sphinx autodoc done right - don't remove it
-__all__ = [_ for _ in dir() if not _.startswith('_')]
+__all__ = [_ for _ in dir() if not _.startswith("_")]
diff --git a/bob/fusion/base/algorithm/AND.py b/bob/fusion/base/algorithm/AND.py
index 7c10589..2f2b6ac 100644
--- a/bob/fusion/base/algorithm/AND.py
+++ b/bob/fusion/base/algorithm/AND.py
@@ -1,14 +1,13 @@
 #!/usr/bin/env python
 
-from __future__ import division
-from __future__ import absolute_import
+from __future__ import absolute_import, division
+
+import logging
 
 import numpy
 
 from .Algorithm import Algorithm
 
-import logging
-
 logger = logging.getLogger(__name__)
 
 
@@ -18,14 +17,14 @@ class AND(Algorithm):
     def __init__(self, thresholds=None, **kwargs):
         super(AND, self).__init__(classifier=self, **kwargs)
         self.thresholds = thresholds
-        self.str['thresholds'] = thresholds
+        self.str["thresholds"] = thresholds
 
     def fit(self, X, y):
         pass
 
     def decision_function(self, scores):
         if self.thresholds is None:
-            ValueError('No threshold was specified.')
+            ValueError("No threshold was specified.")
 
         for i, th in enumerate(self.thresholds):
             mask = scores[:, i + 1] < th
@@ -33,5 +32,5 @@ class AND(Algorithm):
 
         mask = numpy.sum(numpy.isnan(scores[:, 1:]), axis=1, dtype=bool)
         new_scores = numpy.array(scores[0])
-        new_scores[mask] = numpy.finfo('float16').min
+        new_scores[mask] = numpy.finfo("float16").min
         return new_scores
diff --git a/bob/fusion/base/algorithm/Algorithm.py b/bob/fusion/base/algorithm/Algorithm.py
index ece889d..aac95cd 100644
--- a/bob/fusion/base/algorithm/Algorithm.py
+++ b/bob/fusion/base/algorithm/Algorithm.py
@@ -1,12 +1,11 @@
 #!/usr/bin/env python
 
-from __future__ import division
-from __future__ import absolute_import
+from __future__ import absolute_import, division
 
-import numpy as np
+import logging
 import pickle
 
-import logging
+import numpy as np
 
 logger = logging.getLogger(__name__)
 
@@ -22,11 +21,7 @@ class Algorithm(object):
         A dictionary that its content will printed in the __str__ method.
     """
 
-    def __init__(self,
-                 preprocessors=None,
-                 classifier=None,
-                 **kwargs
-                 ):
+    def __init__(self, preprocessors=None, classifier=None, **kwargs):
         """
         Parameters
         ----------
@@ -44,9 +39,9 @@ class Algorithm(object):
         super(Algorithm, self).__init__(**kwargs)
         self.classifier = classifier
         self.preprocessors = preprocessors
-        self.str = {'preprocessors': preprocessors}
+        self.str = {"preprocessors": preprocessors}
         if classifier is not self:
-            self.str['classifier'] = classifier
+            self.str["classifier"] = classifier
 
     def train_preprocessors(self, X, y=None):
         """Train preprocessors in order.
@@ -81,7 +76,7 @@ class Algorithm(object):
         """
         train_scores = np.vstack((train_neg, train_pos))
         neg_len = train_neg.shape[0]
-        y = np.zeros((train_scores.shape[0],), dtype='bool')
+        y = np.zeros((train_scores.shape[0],), dtype="bool")
         y[neg_len:] = True
         self.classifier.fit(train_scores, y)
 
@@ -107,9 +102,16 @@ class Algorithm(object):
             A string containing the full information of all parameters of this
                 (and the derived) class.
         """
-        return "%s(%s)" % (str(self.__class__), ", ".join(
-            ["%s=%s" % (key, value) for key, value in
-             self.str.items() if value is not None]))
+        return "%s(%s)" % (
+            str(self.__class__),
+            ", ".join(
+                [
+                    "%s=%s" % (key, value)
+                    for key, value in self.str.items()
+                    if value is not None
+                ]
+            ),
+        )
 
     def save(self, model_file):
         """Save the instance of the algorithm.
@@ -140,6 +142,6 @@ class Algorithm(object):
         with open(model_file, "rb") as f:
             algo_class = pickle.load(f)
             algo = algo_class()
-            if not hasattr(algo, 'custom_save'):
+            if not hasattr(algo, "custom_save"):
                 return pickle.load(f)
         return algo.load(model_file)
diff --git a/bob/fusion/base/algorithm/AlgorithmBob.py b/bob/fusion/base/algorithm/AlgorithmBob.py
index be319ee..573c357 100644
--- a/bob/fusion/base/algorithm/AlgorithmBob.py
+++ b/bob/fusion/base/algorithm/AlgorithmBob.py
@@ -1,13 +1,13 @@
 #!/usr/bin/env python
 
-from __future__ import division
-from __future__ import absolute_import
+from __future__ import absolute_import, division
 
+import logging
 import pickle
-from .Algorithm import Algorithm
+
 from h5py import File as HDF5File
 
-import logging
+from .Algorithm import Algorithm
 
 logger = logging.getLogger(__name__)
 
@@ -16,13 +16,13 @@ class AlgorithmBob(Algorithm):
     """A class to be used in score fusion using bob machines."""
 
     def _get_hdf5_file(self, model_file):
-        return model_file[:-3] + 'hdf5'
+        return model_file[:-3] + "hdf5"
 
     def custom_save(self, model_file):
         # dump preprocessors in a pickle file because
         # we don't know how they look like
         # saves the class to create it later.
-        with open(model_file, 'wb') as f:
+        with open(model_file, "wb") as f:
             pickle.dump(type(self), f)
             pickle.dump(self.preprocessors, f)
             # just for consistent string representation
diff --git a/bob/fusion/base/algorithm/Empty.py b/bob/fusion/base/algorithm/Empty.py
index 8a7806a..a2ba0d2 100644
--- a/bob/fusion/base/algorithm/Empty.py
+++ b/bob/fusion/base/algorithm/Empty.py
@@ -1,11 +1,11 @@
 #!/usr/bin/env python
 
-from __future__ import division
-from __future__ import absolute_import
+from __future__ import absolute_import, division
 
-from .Algorithm import Algorithm
 import logging
 
+from .Algorithm import Algorithm
+
 logger = logging.getLogger(__name__)
 
 
@@ -15,9 +15,7 @@ class Empty(Algorithm):
     preprocessors."""
 
     def __init__(self, **kwargs):
-        super(Empty, self).__init__(
-            classifier=self,
-            **kwargs)
+        super(Empty, self).__init__(classifier=self, **kwargs)
 
     def fit(self, X, y):
         pass
diff --git a/bob/fusion/base/algorithm/GMM.py b/bob/fusion/base/algorithm/GMM.py
index 2619fe7..29c8309 100644
--- a/bob/fusion/base/algorithm/GMM.py
+++ b/bob/fusion/base/algorithm/GMM.py
@@ -1,14 +1,14 @@
 #!/usr/bin/env python
 
-from __future__ import division
-from __future__ import absolute_import
+from __future__ import absolute_import, division
+
+import logging
 
 import numpy as np
 
 from bob.learn.em.mixture import GMMMachine
-from .AlgorithmBob import AlgorithmBob
 
-import logging
+from .AlgorithmBob import AlgorithmBob
 
 logger = logging.getLogger("bob.fusion.base")
 
@@ -64,12 +64,10 @@ class GMM(AlgorithmBob):
         if self.n_gaussians is None:
             self.n_gaussians = array.shape[1] + 1
             logger.warning(
-                "Number of Gaussians was None. " "Using {}.".format(self.n_gaussians)
+                "Number of Gaussians was None. "
+                "Using {}.".format(self.n_gaussians)
             )
 
-        # Computes input size
-        input_size = array.shape[1]
-
         # Creates the machines (KMeans and GMM)
         logger.debug("Training GMM machine")
         self.machine = GMMMachine(
@@ -84,4 +82,8 @@ class GMM(AlgorithmBob):
         self.machine.fit(array)
 
     def decision_function(self, scores):
-        return np.fromiter((self.machine.log_likelihood(s) for s in scores), np.float, scores.shape[0])
+        return np.fromiter(
+            (self.machine.log_likelihood(s) for s in scores),
+            np.float,
+            scores.shape[0],
+        )
diff --git a/bob/fusion/base/algorithm/Weighted_Sum.py b/bob/fusion/base/algorithm/Weighted_Sum.py
index 556a4b0..20833f6 100644
--- a/bob/fusion/base/algorithm/Weighted_Sum.py
+++ b/bob/fusion/base/algorithm/Weighted_Sum.py
@@ -1,14 +1,13 @@
 #!/usr/bin/env python
 
-from __future__ import division
-from __future__ import absolute_import
+from __future__ import absolute_import, division
+
+import logging
 
 import numpy
 
 from .Algorithm import Algorithm
 
-import logging
-
 logger = logging.getLogger(__name__)
 
 
@@ -16,11 +15,9 @@ class Weighted_Sum(Algorithm):
     """weighted sum (default: mean)"""
 
     def __init__(self, weights=None, **kwargs):
-        super(Weighted_Sum, self).__init__(
-            classifier=self,
-            **kwargs)
+        super(Weighted_Sum, self).__init__(classifier=self, **kwargs)
         self.weights = weights
-        self.str['weights'] = weights
+        self.str["weights"] = weights
 
     def fit(self, X, y):
         pass
diff --git a/bob/fusion/base/algorithm/__init__.py b/bob/fusion/base/algorithm/__init__.py
index 74ceb6e..13b7d90 100644
--- a/bob/fusion/base/algorithm/__init__.py
+++ b/bob/fusion/base/algorithm/__init__.py
@@ -1,21 +1,21 @@
 from .Algorithm import Algorithm
 from .AlgorithmBob import AlgorithmBob
-from .Weighted_Sum import Weighted_Sum
-from .GMM import GMM
 from .Empty import Empty
+from .GMM import GMM
+from .Weighted_Sum import Weighted_Sum
 
 
 # gets sphinx autodoc done right - don't remove it
 def __appropriate__(*args):
     """Says object was actually declared here, an not on the import module.
 
-  Parameters:
+    Parameters:
 
-    *args: An iterable of objects to modify
+      *args: An iterable of objects to modify
 
-  Resolves `Sphinx referencing issues
-  <https://github.com/sphinx-doc/sphinx/issues/3048>`
-  """
+    Resolves `Sphinx referencing issues
+    <https://github.com/sphinx-doc/sphinx/issues/3048>`
+    """
 
     for obj in args:
         obj.__module__ = __name__
@@ -28,4 +28,4 @@ __appropriate__(
     GMM,
     Empty,
 )
-__all__ = [_ for _ in dir() if not _.startswith('_')]
+__all__ = [_ for _ in dir() if not _.startswith("_")]
diff --git a/bob/fusion/base/config/algorithm/gmm.py b/bob/fusion/base/config/algorithm/gmm.py
index b4dfb98..c10b5e7 100644
--- a/bob/fusion/base/config/algorithm/gmm.py
+++ b/bob/fusion/base/config/algorithm/gmm.py
@@ -1,9 +1,11 @@
 #!/usr/bin/env python
 
-import bob.fusion.base
 from sklearn.preprocessing import StandardScaler
 
+import bob.fusion.base
+
 algorithm = bob.fusion.base.algorithm.GMM(preprocessors=[StandardScaler()])
 
 algorithm_tanh = bob.fusion.base.algorithm.GMM(
-    preprocessors=[bob.fusion.base.preprocessor.Tanh()])
+    preprocessors=[bob.fusion.base.preprocessor.Tanh()]
+)
diff --git a/bob/fusion/base/config/algorithm/llr_skl.py b/bob/fusion/base/config/algorithm/llr_skl.py
index 891fb79..b7fc05d 100644
--- a/bob/fusion/base/config/algorithm/llr_skl.py
+++ b/bob/fusion/base/config/algorithm/llr_skl.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 
-import bob.fusion.base
-from sklearn.preprocessing import StandardScaler
 from sklearn.linear_model import LogisticRegression
+from sklearn.preprocessing import StandardScaler
+
+import bob.fusion.base
 
 algorithm = bob.fusion.base.algorithm.Algorithm(
-    preprocessors=[StandardScaler()],
-    classifier=LogisticRegression())
+    preprocessors=[StandardScaler()], classifier=LogisticRegression()
+)
 
 algorithm_tanh = bob.fusion.base.algorithm.Algorithm(
     preprocessors=[bob.fusion.base.preprocessor.Tanh()],
-    classifier=LogisticRegression())
+    classifier=LogisticRegression(),
+)
diff --git a/bob/fusion/base/config/algorithm/mean.py b/bob/fusion/base/config/algorithm/mean.py
index fecb8f1..6b3ab2c 100644
--- a/bob/fusion/base/config/algorithm/mean.py
+++ b/bob/fusion/base/config/algorithm/mean.py
@@ -1,10 +1,13 @@
 #!/usr/bin/env python
 
-import bob.fusion.base
 from sklearn.preprocessing import StandardScaler
 
+import bob.fusion.base
+
 algorithm = bob.fusion.base.algorithm.Weighted_Sum(
-    preprocessors=[StandardScaler()])
+    preprocessors=[StandardScaler()]
+)
 
 algorithm_tanh = bob.fusion.base.algorithm.Weighted_Sum(
-    preprocessors=[bob.fusion.base.preprocessor.Tanh()])
+    preprocessors=[bob.fusion.base.preprocessor.Tanh()]
+)
diff --git a/bob/fusion/base/config/algorithm/plr_2.py b/bob/fusion/base/config/algorithm/plr_2.py
index 5874566..c0c4a20 100644
--- a/bob/fusion/base/config/algorithm/plr_2.py
+++ b/bob/fusion/base/config/algorithm/plr_2.py
@@ -1,11 +1,16 @@
 #!/usr/bin/env python
 
+from sklearn.preprocessing import PolynomialFeatures, StandardScaler
+
 import bob.fusion.base
-from sklearn.preprocessing import StandardScaler, PolynomialFeatures
 
 algorithm = bob.fusion.base.algorithm.LLR(
-    preprocessors=[StandardScaler(), PolynomialFeatures(degree=2)])
+    preprocessors=[StandardScaler(), PolynomialFeatures(degree=2)]
+)
 
 algorithm_tanh = bob.fusion.base.algorithm.LLR(
-    preprocessors=[bob.fusion.base.preprocessor.Tanh(),
-                   PolynomialFeatures(degree=2)])
+    preprocessors=[
+        bob.fusion.base.preprocessor.Tanh(),
+        PolynomialFeatures(degree=2),
+    ]
+)
diff --git a/bob/fusion/base/config/algorithm/plr_3.py b/bob/fusion/base/config/algorithm/plr_3.py
index 675633b..e156b4f 100644
--- a/bob/fusion/base/config/algorithm/plr_3.py
+++ b/bob/fusion/base/config/algorithm/plr_3.py
@@ -1,11 +1,16 @@
 #!/usr/bin/env python
 
+from sklearn.preprocessing import PolynomialFeatures, StandardScaler
+
 import bob.fusion.base
-from sklearn.preprocessing import StandardScaler, PolynomialFeatures
 
 algorithm = bob.fusion.base.algorithm.LLR(
-    preprocessors=[StandardScaler(), PolynomialFeatures(degree=3)])
+    preprocessors=[StandardScaler(), PolynomialFeatures(degree=3)]
+)
 
 algorithm_tanh = bob.fusion.base.algorithm.LLR(
-    preprocessors=[bob.fusion.base.preprocessor.Tanh(),
-                   PolynomialFeatures(degree=3)])
+    preprocessors=[
+        bob.fusion.base.preprocessor.Tanh(),
+        PolynomialFeatures(degree=3),
+    ]
+)
diff --git a/bob/fusion/base/preprocessor/Tanh.py b/bob/fusion/base/preprocessor/Tanh.py
index aae1a3e..1a445c9 100644
--- a/bob/fusion/base/preprocessor/Tanh.py
+++ b/bob/fusion/base/preprocessor/Tanh.py
@@ -1,8 +1,9 @@
-from sklearn.preprocessing import StandardScaler
 import numpy as np
 
+from sklearn.preprocessing import StandardScaler
+
 # to fix the sphinx docs
-StandardScaler.__module__ = 'sklearn.preprocessing'
+StandardScaler.__module__ = "sklearn.preprocessing"
 
 
 class Tanh(StandardScaler):
@@ -22,7 +23,8 @@ class Tanh(StandardScaler):
     def __init__(self, copy=True, **kwargs):
         """Initialize self. See help(type(self)) for accurate signature."""
         super(Tanh, self).__init__(
-            copy=copy, with_mean=True, with_std=True, **kwargs)
+            copy=copy, with_mean=True, with_std=True, **kwargs
+        )
 
     def fit(self, X, y=None):
         """Estimates the mean and standard deviation of samples.
diff --git a/bob/fusion/base/preprocessor/ZNorm.py b/bob/fusion/base/preprocessor/ZNorm.py
index 6159cf7..fab1e00 100644
--- a/bob/fusion/base/preprocessor/ZNorm.py
+++ b/bob/fusion/base/preprocessor/ZNorm.py
@@ -1,8 +1,9 @@
-from sklearn.preprocessing import StandardScaler
 import numpy as np
 
+from sklearn.preprocessing import StandardScaler
+
 # to fix the sphinx docs
-StandardScaler.__module__ = 'sklearn.preprocessing'
+StandardScaler.__module__ = "sklearn.preprocessing"
 
 
 class ZNorm(StandardScaler):
@@ -16,7 +17,8 @@ class ZNorm(StandardScaler):
     def __init__(self, copy=True, **kwargs):
         """Initialize self. See help(type(self)) for accurate signature."""
         super(ZNorm, self).__init__(
-            copy=copy, with_mean=True, with_std=True, **kwargs)
+            copy=copy, with_mean=True, with_std=True, **kwargs
+        )
 
     def fit(self, X, y=None):
         """Estimates the mean and standard deviation of samples.
diff --git a/bob/fusion/base/preprocessor/__init__.py b/bob/fusion/base/preprocessor/__init__.py
index fb44e5f..6002b0c 100644
--- a/bob/fusion/base/preprocessor/__init__.py
+++ b/bob/fusion/base/preprocessor/__init__.py
@@ -6,13 +6,13 @@ from .ZNorm import ZNorm
 def __appropriate__(*args):
     """Says object was actually declared here, an not on the import module.
 
-  Parameters:
+    Parameters:
 
-    *args: An iterable of objects to modify
+      *args: An iterable of objects to modify
 
-  Resolves `Sphinx referencing issues
-  <https://github.com/sphinx-doc/sphinx/issues/3048>`
-  """
+    Resolves `Sphinx referencing issues
+    <https://github.com/sphinx-doc/sphinx/issues/3048>`
+    """
 
     for obj in args:
         obj.__module__ = __name__
@@ -22,4 +22,4 @@ __appropriate__(
     Tanh,
     ZNorm,
 )
-__all__ = [_ for _ in dir() if not _.startswith('_')]
+__all__ = [_ for _ in dir() if not _.startswith("_")]
diff --git a/bob/fusion/base/script/__init__.py b/bob/fusion/base/script/__init__.py
index 203a0fa..6494818 100644
--- a/bob/fusion/base/script/__init__.py
+++ b/bob/fusion/base/script/__init__.py
@@ -1,4 +1,4 @@
-from .fuse import routine_fusion
+from .fuse import routine_fusion  # noqa: F401
 
 # gets sphinx autodoc done right - don't remove it
-__all__ = [_ for _ in dir() if not _.startswith('_')]
+__all__ = [_ for _ in dir() if not _.startswith("_")]
diff --git a/bob/fusion/base/script/boundary.py b/bob/fusion/base/script/boundary.py
index 91fc77d..55caad6 100644
--- a/bob/fusion/base/script/boundary.py
+++ b/bob/fusion/base/script/boundary.py
@@ -1,20 +1,21 @@
 """Plots the decision boundaries of fusion algorithms.
 """
 import logging
+
 import click
-from bob.extension.scripts.click_helper import verbosity_option
 import numpy as np
 
 from bob.bio.base.score import load_score
+from bob.extension.scripts.click_helper import verbosity_option
 
+from ..algorithm import Algorithm
 from ..tools import (
-    get_gza_from_lines_list,
     check_consistency,
+    get_gza_from_lines_list,
     get_scores,
-    remove_nan,
     grouping,
+    remove_nan,
 )
-from ..algorithm import Algorithm
 
 logger = logging.getLogger(__name__)
 
@@ -58,7 +59,8 @@ def plot_boundary_decision(
     x_min, x_max = X[:, i1].min() - x_pad, X[:, i1].max() + x_pad
     y_min, y_max = X[:, i2].min() - y_pad, X[:, i2].max() + y_pad
     xx, yy = np.meshgrid(
-        np.linspace(x_min, x_max, resolution), np.linspace(y_min, y_max, resolution)
+        np.linspace(x_min, x_max, resolution),
+        np.linspace(y_min, y_max, resolution),
     )
 
     contourf = None
@@ -82,10 +84,17 @@ def plot_boundary_decision(
             continue
         try:
             plt.scatter(
-                X[:, 0], X[:, 1], marker=markers[i], alpha=alpha, c=color, label=legends[i]
+                X[:, 0],
+                X[:, 1],
+                marker=markers[i],
+                alpha=alpha,
+                c=color,
+                label=legends[i],
             )
         except Exception as e:
-            raise RuntimeError(f"matplotlib backend: {matplotlib.get_backend()}") from e
+            raise RuntimeError(
+                f"matplotlib backend: {matplotlib.get_backend()}"
+            ) from e
 
     plt.legend(
         bbox_to_anchor=(-0.05, 1.02, 1.05, 0.102),
@@ -173,7 +182,8 @@ $ bob fusion boundary -vvv {sys1,sys2}/scores-eval -m /path/to/Model.pkl
     "--skip-check",
     is_flag=True,
     show_default=True,
-    help="If True, it will skip checking for the consistency " "between scores.",
+    help="If True, it will skip checking for the consistency "
+    "between scores.",
 )
 @verbosity_option()
 def boundary(
@@ -201,13 +211,17 @@ def boundary(
     algorithm = None
     if model_file:
         algorithm = Algorithm().load(model_file)
-        assert threshold is not None, "threshold must be provided with the model"
+        assert (
+            threshold is not None
+        ), "threshold must be provided with the model"
 
     # load the scores
     score_lines_list_eval = [load_score(path) for path in scores]
 
     # genuine, zero effort impostor, and attack list
-    idx1, gen_le, zei_le, atk_le = get_gza_from_lines_list(score_lines_list_eval)
+    idx1, gen_le, zei_le, atk_le = get_gza_from_lines_list(
+        score_lines_list_eval
+    )
 
     # check if score lines are consistent
     if not skip_check:
diff --git a/bob/fusion/base/script/fuse.py b/bob/fusion/base/script/fuse.py
index 8ad23f3..de9d050 100644
--- a/bob/fusion/base/script/fuse.py
+++ b/bob/fusion/base/script/fuse.py
@@ -1,26 +1,40 @@
 """A script to help for score fusion experiments
 """
-from __future__ import print_function, absolute_import, division
+from __future__ import absolute_import, division, print_function
+
 import logging
-import click
-from bob.extension.scripts.click_helper import (
-    verbosity_option, ResourceOption)
 import os
+
+import click
 import numpy as np
 
-from bob.bio.base.score import load_score, dump_score
 from bob.bio.base import utils
-
-from ..tools import get_gza_from_lines_list, \
-    check_consistency, get_scores, remove_nan, get_score_lines, \
-    get_2negatives_1positive
+from bob.bio.base.score import dump_score, load_score
+from bob.extension.scripts.click_helper import ResourceOption, verbosity_option
+
+from ..tools import (
+    check_consistency,
+    get_2negatives_1positive,
+    get_gza_from_lines_list,
+    get_score_lines,
+    get_scores,
+    remove_nan,
+)
 
 logger = logging.getLogger(__name__)
 
 
-def write_info(scores, algorithm, groups, output_dir, model_file, skip_check,
-               force, **kwargs):
-    info = '''
+def write_info(
+    scores,
+    algorithm,
+    groups,
+    output_dir,
+    model_file,
+    skip_check,
+    force,
+    **kwargs
+):
+    info = """
 scores: %s
 algorithm: %s
 groups: %s
@@ -29,12 +43,20 @@ model_file: %s
 skip_check: %s
 force: %s
 kwargs: %s
-    ''' % (scores, algorithm, groups, output_dir, model_file, skip_check,
-           force, kwargs)
+    """ % (
+        scores,
+        algorithm,
+        groups,
+        output_dir,
+        model_file,
+        skip_check,
+        force,
+        kwargs,
+    )
     logger.debug(info)
 
-    info_file = os.path.join(output_dir, 'Experiment.info')
-    with open(info_file, 'w') as f:
+    info_file = os.path.join(output_dir, "Experiment.info")
+    with open(info_file, "w") as f:
         f.write("Command line:\n")
         f.write(str(click.get_os_args()) + "\n\n")
         f.write("Configuration:\n\n")
@@ -42,24 +64,36 @@ kwargs: %s
 
 
 def save_fused_scores(save_path, fused_scores, score_lines):
-    score_lines['score'] = fused_scores
+    score_lines["score"] = fused_scores
     gen, zei, atk, _, _, _ = get_2negatives_1positive(score_lines)
     os.makedirs(os.path.dirname(save_path), exist_ok=True)
     dump_score(save_path, score_lines)
-    dump_score(save_path + '-licit', np.append(gen, zei))
-    dump_score(save_path + '-spoof', np.append(gen, atk))
-    dump_score(save_path + '-real', np.append(gen, zei))
-    dump_score(save_path + '-attack', atk)
+    dump_score(save_path + "-licit", np.append(gen, zei))
+    dump_score(save_path + "-spoof", np.append(gen, atk))
+    dump_score(save_path + "-real", np.append(gen, zei))
+    dump_score(save_path + "-attack", atk)
 
 
 def routine_fusion(
-        algorithm, model_file,
-        scores_train_lines, scores_train, train_neg, train_pos,
-        fused_train_file,
-        scores_dev_lines=None, scores_dev=None, dev_neg=None, dev_pos=None,
-        fused_dev_file=None,
-        scores_eval_lines=None, scores_eval=None, fused_eval_file=None,
-        force=False, min_file_size=1000, do_training=True):
+    algorithm,
+    model_file,
+    scores_train_lines,
+    scores_train,
+    train_neg,
+    train_pos,
+    fused_train_file,
+    scores_dev_lines=None,
+    scores_dev=None,
+    dev_neg=None,
+    dev_pos=None,
+    fused_dev_file=None,
+    scores_eval_lines=None,
+    scores_eval=None,
+    fused_eval_file=None,
+    force=False,
+    min_file_size=1000,
+    do_training=True,
+):
 
     # load the model if model_file exists and no training data was provided
     if os.path.exists(model_file) and not do_training:
@@ -70,20 +104,22 @@ def routine_fusion(
     if train_neg is not None and do_training:
         train_scores = np.vstack((train_neg, train_pos))
         neg_len = train_neg.shape[0]
-        y = np.zeros((train_scores.shape[0],), dtype='bool')
+        y = np.zeros((train_scores.shape[0],), dtype="bool")
         y[neg_len:] = True
         algorithm.train_preprocessors(train_scores, y)
 
     # preprocess data
     if scores_train is not None:
         scores_train = algorithm.preprocess(scores_train)
-        train_neg, train_pos = \
-            algorithm.preprocess(train_neg), algorithm.preprocess(train_pos)
+        train_neg, train_pos = algorithm.preprocess(
+            train_neg
+        ), algorithm.preprocess(train_pos)
 
     if scores_dev is not None:
         scores_dev = algorithm.preprocess(scores_dev)
-        dev_neg, dev_pos = \
-            algorithm.preprocess(dev_neg), algorithm.preprocess(dev_pos)
+        dev_neg, dev_pos = algorithm.preprocess(dev_neg), algorithm.preprocess(
+            dev_pos
+        )
 
     if scores_eval is not None:
         scores_eval = algorithm.preprocess(scores_eval)
@@ -91,8 +127,7 @@ def routine_fusion(
     # Train the classifier
     if train_neg is not None and do_training:
         if utils.check_file(model_file, force, min_file_size):
-            logger.info(
-                "model '%s' already exists.", model_file)
+            logger.info("model '%s' already exists.", model_file)
             algorithm = algorithm.load(model_file)
         else:
             algorithm.train(train_neg, train_pos, dev_neg, dev_pos)
@@ -101,35 +136,36 @@ def routine_fusion(
     # fuse the scores (train)
     if scores_train is not None:
         if utils.check_file(fused_train_file, force, min_file_size):
-            logger.info(
-                "score file '%s' already exists.", fused_train_file)
+            logger.info("score file '%s' already exists.", fused_train_file)
         else:
             fused_scores_train = algorithm.fuse(scores_train)
-            save_fused_scores(fused_train_file,
-                              fused_scores_train, scores_train_lines)
+            save_fused_scores(
+                fused_train_file, fused_scores_train, scores_train_lines
+            )
 
     # fuse the scores (dev)
     if scores_dev is not None:
         if utils.check_file(fused_dev_file, force, min_file_size):
-            logger.info(
-                "score file '%s' already exists.", fused_dev_file)
+            logger.info("score file '%s' already exists.", fused_dev_file)
         else:
             fused_scores_dev = algorithm.fuse(scores_dev)
             save_fused_scores(
-                fused_dev_file, fused_scores_dev, scores_dev_lines)
+                fused_dev_file, fused_scores_dev, scores_dev_lines
+            )
 
     # fuse the scores (eval)
     if scores_eval is not None:
         if utils.check_file(fused_eval_file, force, min_file_size):
-            logger.info(
-                "score file '%s' already exists.", fused_eval_file)
+            logger.info("score file '%s' already exists.", fused_eval_file)
         else:
             fused_scores_eval = algorithm.fuse(scores_eval)
             save_fused_scores(
-                fused_eval_file, fused_scores_eval, scores_eval_lines)
+                fused_eval_file, fused_scores_eval, scores_eval_lines
+            )
 
 
-@click.command(epilog='''\b
+@click.command(
+    epilog="""\b
 Examples:
 # normal score fusion using the mean algorithm:
 $ bob fusion fuse -vvv sys1/scores-{world,dev,eval} sys2/scores-{world,dev,eval} -a mean
@@ -143,34 +179,68 @@ $ bob fusion fuse -vvv {sys1,sys2}/scores-{dev,dev,eval} -a mean
 $ bob fusion fuse -vvv {sys1,sys2}/scores-{world,dev} -g train -g dev -a mean
 # run fusion with bio and pad systems:
 $ bob fusion fuse -vvv sys_bio/scores-{world,dev,eval} sys_pad/scores-{train,dev,eval} -a mean
-''')
-@click.argument('scores', nargs=-1, required=True,
-                type=click.Path(exists=True))
-@click.option('--algorithm', '-a', required=True, cls=ResourceOption,
-              entry_point_group='bob.fusion.algorithm',
-              help='The fusion algorithm '
-              '(:any:`bob.fusion.algorithm.Algorithm`).')
-@click.option('--groups', '-g', default=('train', 'dev', 'eval'),
-              multiple=True, show_default=True,
-              type=click.Choice(('train', 'dev', 'eval')),
-              help='The groups of the scores. This should correspond to the '
-              'scores that are provided. The order of options are important '
-              'and should be in the same order as (train, dev, eval). Repeat '
-              'this option for multiple values.')
-@click.option('--output-dir', '-o', required=True, default='fusion_result',
-              show_default=True,
-              type=click.Path(writable=True),
-              help='The directory to save the annotations.')
-@click.option('--model-file', '-m',
-              help='The path to where the algorithm will be saved/loaded.')
-@click.option('--skip-check', is_flag=True, show_default=True,
-              help='If True, it will skip checking for '
-              'the consistency between scores.')
-@click.option('--force', '-f', is_flag=True, show_default=True,
-              help='Whether to overwrite existing files.')
+"""
+)
+@click.argument("scores", nargs=-1, required=True, type=click.Path(exists=True))
+@click.option(
+    "--algorithm",
+    "-a",
+    required=True,
+    cls=ResourceOption,
+    entry_point_group="bob.fusion.algorithm",
+    help="The fusion algorithm " "(:any:`bob.fusion.algorithm.Algorithm`).",
+)
+@click.option(
+    "--groups",
+    "-g",
+    default=("train", "dev", "eval"),
+    multiple=True,
+    show_default=True,
+    type=click.Choice(("train", "dev", "eval")),
+    help="The groups of the scores. This should correspond to the "
+    "scores that are provided. The order of options are important "
+    "and should be in the same order as (train, dev, eval). Repeat "
+    "this option for multiple values.",
+)
+@click.option(
+    "--output-dir",
+    "-o",
+    required=True,
+    default="fusion_result",
+    show_default=True,
+    type=click.Path(writable=True),
+    help="The directory to save the annotations.",
+)
+@click.option(
+    "--model-file",
+    "-m",
+    help="The path to where the algorithm will be saved/loaded.",
+)
+@click.option(
+    "--skip-check",
+    is_flag=True,
+    show_default=True,
+    help="If True, it will skip checking for "
+    "the consistency between scores.",
+)
+@click.option(
+    "--force",
+    "-f",
+    is_flag=True,
+    show_default=True,
+    help="Whether to overwrite existing files.",
+)
 @verbosity_option()
-def fuse(scores, algorithm, groups, output_dir, model_file, skip_check, force,
-         **kwargs):
+def fuse(
+    scores,
+    algorithm,
+    groups,
+    output_dir,
+    model_file,
+    skip_check,
+    force,
+    **kwargs
+):
     """Score fusion
 
     The script takes several scores from different biometric and pad systems
@@ -192,39 +262,49 @@ def fuse(scores, algorithm, groups, output_dir, model_file, skip_check, force,
     os.makedirs(output_dir, exist_ok=True)
     if not model_file:
         do_training = True
-        model_file = os.path.join(output_dir, 'Model.pkl')
+        model_file = os.path.join(output_dir, "Model.pkl")
     else:
         do_training = False
-    fused_train_file = os.path.join(output_dir, 'scores-train')
-    fused_dev_file = os.path.join(output_dir, 'scores-dev')
-    fused_eval_file = os.path.join(output_dir, 'scores-eval')
+    fused_train_file = os.path.join(output_dir, "scores-train")
+    fused_dev_file = os.path.join(output_dir, "scores-dev")
+    fused_eval_file = os.path.join(output_dir, "scores-eval")
 
     if not len(scores) % len(groups) == 0:
         raise click.BadArgumentUsage(
-            'The number of scores must be a multiple of the number of groups.')
+            "The number of scores must be a multiple of the number of groups."
+        )
 
     if algorithm is None:
         raise click.MissingParameter(
-            "algorithm must be provided.", param_type='option')
-
-    write_info(scores, algorithm, groups, output_dir, model_file, skip_check,
-               force, **kwargs)
+            "algorithm must be provided.", param_type="option"
+        )
+
+    write_info(
+        scores,
+        algorithm,
+        groups,
+        output_dir,
+        model_file,
+        skip_check,
+        force,
+        **kwargs
+    )
 
     """Do the actual fusion."""
 
     train_files, dev_files, eval_files = [], [], []
-    for i, (files, grp) in enumerate(zip(
-        (train_files, dev_files, eval_files),
-            ('train', 'dev', 'eval'))):
+    for i, (files, grp) in enumerate(
+        zip((train_files, dev_files, eval_files), ("train", "dev", "eval"))
+    ):
         try:
             idx = groups.index(grp)
-            files.extend(scores[idx::len(groups)])
+            files.extend(scores[idx :: len(groups)])
         except ValueError:
             pass
 
-    click.echo('train_files: %s' % train_files)
-    click.echo('dev_files: %s' % dev_files)
-    click.echo('eval_files: %s' % eval_files)
+    click.echo("train_files: %s" % train_files)
+    click.echo("dev_files: %s" % dev_files)
+    click.echo("eval_files: %s" % eval_files)
 
     # load the scores
     if train_files:
@@ -238,40 +318,49 @@ def fuse(scores, algorithm, groups, output_dir, model_file, skip_check, force,
     # train, development and evaluation data.
     if train_files:
         _, gen_lt, zei_lt, atk_lt = get_gza_from_lines_list(
-            score_lines_list_train)
+            score_lines_list_train
+        )
     if dev_files:
         _, gen_ld, zei_ld, atk_ld = get_gza_from_lines_list(
-            score_lines_list_dev)
+            score_lines_list_dev
+        )
     if eval_files:
         _, gen_le, zei_le, atk_le = get_gza_from_lines_list(
-            score_lines_list_eval)
+            score_lines_list_eval
+        )
 
     # check if score lines are consistent
     if not skip_check:
         if train_files:
-            logger.info('Checking the training files for consistency ...')
+            logger.info("Checking the training files for consistency ...")
             check_consistency(gen_lt, zei_lt, atk_lt)
         if dev_files:
-            logger.info('Checking the development files for consistency ...')
+            logger.info("Checking the development files for consistency ...")
             check_consistency(gen_ld, zei_ld, atk_ld)
         if eval_files:
-            logger.info('Checking the evaluation files for consistency ...')
+            logger.info("Checking the evaluation files for consistency ...")
             check_consistency(gen_le, zei_le, atk_le)
 
     if train_files:
         scores_train = get_scores(gen_lt, zei_lt, atk_lt)
         scores_train_lines = get_score_lines(
-            gen_lt[0:1], zei_lt[0:1], atk_lt[0:1])
+            gen_lt[0:1], zei_lt[0:1], atk_lt[0:1]
+        )
         train_neg = get_scores(zei_lt, atk_lt)
         train_pos = get_scores(gen_lt)
     else:
-        scores_train, scores_train_lines, train_neg, train_pos = \
-            None, None, None, None
+        scores_train, scores_train_lines, train_neg, train_pos = (
+            None,
+            None,
+            None,
+            None,
+        )
 
     if dev_files:
         scores_dev = get_scores(gen_ld, zei_ld, atk_ld)
         scores_dev_lines = get_score_lines(
-            gen_ld[0:1], zei_ld[0:1], atk_ld[0:1])
+            gen_ld[0:1], zei_ld[0:1], atk_ld[0:1]
+        )
         dev_neg = get_scores(zei_ld, atk_ld)
         dev_pos = get_scores(gen_ld)
     else:
@@ -280,15 +369,15 @@ def fuse(scores, algorithm, groups, output_dir, model_file, skip_check, force,
     if eval_files:
         scores_eval = get_scores(gen_le, zei_le, atk_le)
         scores_eval_lines = get_score_lines(
-            gen_le[0:1], zei_le[0:1], atk_le[0:1])
+            gen_le[0:1], zei_le[0:1], atk_le[0:1]
+        )
     else:
         scores_eval, scores_eval_lines = None, None
 
     # check for nan values
     found_nan = False
     if train_files:
-        found_nan, nan_train, scores_train = remove_nan(
-            scores_train, found_nan)
+        found_nan, nan_train, scores_train = remove_nan(scores_train, found_nan)
         scores_train_lines = scores_train_lines[~nan_train]
         found_nan, _, train_neg = remove_nan(train_neg, found_nan)
         found_nan, _, train_pos = remove_nan(train_pos, found_nan)
@@ -302,10 +391,24 @@ def fuse(scores, algorithm, groups, output_dir, model_file, skip_check, force,
         scores_eval_lines = scores_eval_lines[~nan_eval]
 
     if found_nan:
-        logger.warning('Some nan values were removed.')
+        logger.warning("Some nan values were removed.")
 
     routine_fusion(
-        algorithm, model_file, scores_train_lines, scores_train,
-        train_neg, train_pos, fused_train_file, scores_dev_lines,
-        scores_dev, dev_neg, dev_pos, fused_dev_file, scores_eval_lines,
-        scores_eval, fused_eval_file, force, do_training=do_training)
+        algorithm,
+        model_file,
+        scores_train_lines,
+        scores_train,
+        train_neg,
+        train_pos,
+        fused_train_file,
+        scores_dev_lines,
+        scores_dev,
+        dev_neg,
+        dev_pos,
+        fused_dev_file,
+        scores_eval_lines,
+        scores_eval,
+        fused_eval_file,
+        force,
+        do_training=do_training,
+    )
diff --git a/bob/fusion/base/script/fusion.py b/bob/fusion/base/script/fusion.py
index 5bf22be..f30807b 100644
--- a/bob/fusion/base/script/fusion.py
+++ b/bob/fusion/base/script/fusion.py
@@ -2,11 +2,13 @@
 """
 import click
 import pkg_resources
+
 from click_plugins import with_plugins
+
 from bob.extension.scripts.click_helper import AliasedGroup
 
 
-@with_plugins(pkg_resources.iter_entry_points('bob.fusion.cli'))
+@with_plugins(pkg_resources.iter_entry_points("bob.fusion.cli"))
 @click.group(cls=AliasedGroup)
 def fusion():
     """Score fusion related scripts"""
diff --git a/bob/fusion/base/script/resource.py b/bob/fusion/base/script/resource.py
index e1a2898..7ed23e9 100644
--- a/bob/fusion/base/script/resource.py
+++ b/bob/fusion/base/script/resource.py
@@ -1,26 +1,41 @@
 """A script to list the resources.
 """
-from __future__ import print_function, absolute_import, division
+from __future__ import absolute_import, division, print_function
+
 import logging
+
 import click
-from bob.extension.scripts.click_helper import verbosity_option
+
 import bob.bio.base
 
+from bob.extension.scripts.click_helper import verbosity_option
+
 logger = logging.getLogger(__name__)
 
 
-@click.command(epilog='''\b
+@click.command(
+    epilog="""\b
 Examples:
 $ bob fusion resource
 $ bob fusion resource -v
-''')
-@click.option('--packages', '-p', multiple=True,
-              help='List only the resources from these packages.')
+"""
+)
+@click.option(
+    "--packages",
+    "-p",
+    multiple=True,
+    help="List only the resources from these packages.",
+)
 @verbosity_option()
 @click.pass_context
 def resource(ctx, packages, **kwargs):
-    """Lists fusion algorithm resources.
-    """
-    click.echo(bob.bio.base.list_resources(
-        'algorithm', strip=['dummy'], package_prefix='bob.fusion.',
-        verbose=ctx.meta['verbosity'], packages=packages or None))
+    """Lists fusion algorithm resources."""
+    click.echo(
+        bob.bio.base.list_resources(
+            "algorithm",
+            strip=["dummy"],
+            package_prefix="bob.fusion.",
+            verbose=ctx.meta["verbosity"],
+            packages=packages or None,
+        )
+    )
diff --git a/bob/fusion/base/test/test_algorithm.py b/bob/fusion/base/test/test_algorithm.py
index 82328c4..a467c18 100644
--- a/bob/fusion/base/test/test_algorithm.py
+++ b/bob/fusion/base/test/test_algorithm.py
@@ -1,12 +1,16 @@
 #!/usr/bin/env python
+import logging
+
+from tempfile import NamedTemporaryFile
+
 import numpy as np
+
 from numpy import array
-from tempfile import NamedTemporaryFile
+from sklearn.linear_model import LogisticRegression
+from sklearn.preprocessing import StandardScaler
+
 import bob.fusion.base
 import bob.learn.linear
-from sklearn.preprocessing import StandardScaler
-from sklearn.linear_model import LogisticRegression
-import logging
 
 logger = logging.getLogger("bob.fusion.base")
 
diff --git a/bob/fusion/base/test/test_preprocessor.py b/bob/fusion/base/test/test_preprocessor.py
index 46bc0ca..2ffa432 100644
--- a/bob/fusion/base/test/test_preprocessor.py
+++ b/bob/fusion/base/test/test_preprocessor.py
@@ -1,21 +1,17 @@
-from bob.fusion.base.preprocessor import Tanh
-from sklearn.preprocessing import StandardScaler
 import numpy as np
 
+from sklearn.preprocessing import StandardScaler
+
+from bob.fusion.base.preprocessor import Tanh
+
 
 def test_tanh_preprocessor():
-    DATA = [[0, 0],
-            [0, 0],
-            [1, 1],
-            [1, 1]]
+    DATA = [[0, 0], [0, 0], [1, 1], [1, 1]]
     Y = np.ones(len(DATA), dtype=bool)
     MEAN = [0.5, 0.5]
-    DATA_T = [[-1., - 1.],
-              [-1., - 1.],
-              [1., 1.],
-              [1., 1.]]
+    DATA_T = [[-1.0, -1.0], [-1.0, -1.0], [1.0, 1.0], [1.0, 1.0]]
     DATA2 = [[2, 2]]
-    DATA2_T = [[3., 3.]]
+    DATA2_T = [[3.0, 3.0]]
     scaler = StandardScaler()
     scaler.fit(np.asarray(DATA))
     assert np.allclose(scaler.mean_, MEAN)
@@ -28,27 +24,27 @@ def test_tanh_preprocessor():
     scaler = Tanh()
     scaler.fit(DATA, y=Y)
     assert np.allclose(scaler.mean_, MEAN)
-    assert np.allclose(scaler.transform(DATA),
-                       tanh(DATA, scaler.mean_, scaler.scale_))
-    assert np.allclose(scaler.transform(DATA2),
-                       tanh(DATA2, scaler.mean_, scaler.scale_))
+    assert np.allclose(
+        scaler.transform(DATA), tanh(DATA, scaler.mean_, scaler.scale_)
+    )
+    assert np.allclose(
+        scaler.transform(DATA2), tanh(DATA2, scaler.mean_, scaler.scale_)
+    )
 
-    assert np.allclose(scaler.inverse_transform(scaler.transform(DATA2)),
-                       DATA2)
+    assert np.allclose(scaler.inverse_transform(scaler.transform(DATA2)), DATA2)
 
-    assert np.allclose(scaler.inverse_transform(scaler.transform(DATA)),
-                       DATA)
+    assert np.allclose(scaler.inverse_transform(scaler.transform(DATA)), DATA)
 
     scaler = Tanh()
     scaler.fit_transform(DATA, y=Y)
     assert np.allclose(scaler.mean_, MEAN)
-    assert np.allclose(scaler.transform(DATA),
-                       tanh(DATA, scaler.mean_, scaler.scale_))
-    assert np.allclose(scaler.transform(DATA2),
-                       tanh(DATA2, scaler.mean_, scaler.scale_))
+    assert np.allclose(
+        scaler.transform(DATA), tanh(DATA, scaler.mean_, scaler.scale_)
+    )
+    assert np.allclose(
+        scaler.transform(DATA2), tanh(DATA2, scaler.mean_, scaler.scale_)
+    )
 
-    assert np.allclose(scaler.inverse_transform(scaler.transform(DATA2)),
-                       DATA2)
+    assert np.allclose(scaler.inverse_transform(scaler.transform(DATA2)), DATA2)
 
-    assert np.allclose(scaler.inverse_transform(scaler.transform(DATA)),
-                       DATA)
+    assert np.allclose(scaler.inverse_transform(scaler.transform(DATA)), DATA)
diff --git a/bob/fusion/base/test/test_scripts.py b/bob/fusion/base/test/test_scripts.py
index 3758980..cda42c3 100644
--- a/bob/fusion/base/test/test_scripts.py
+++ b/bob/fusion/base/test/test_scripts.py
@@ -1,13 +1,17 @@
 #!/usr/bin/env python
 
 import os
+
 import numpy
-from ..script.fuse import fuse
-from ..script.boundary import boundary
-from bob.io.base.test_utils import datafile
-from bob.bio.base.score import load_score
+
 from click.testing import CliRunner
+
+from bob.bio.base.score import load_score
 from bob.extension.scripts.click_helper import assert_click_runner_result
+from bob.io.base.test_utils import datafile
+
+from ..script.boundary import boundary
+from ..script.fuse import fuse
 
 train_files = [
     datafile("scores-train-1", "bob.fusion.base", "test/data"),
diff --git a/bob/fusion/base/tools/__init__.py b/bob/fusion/base/tools/__init__.py
index d6fb8cd..a182e28 100644
--- a/bob/fusion/base/tools/__init__.py
+++ b/bob/fusion/base/tools/__init__.py
@@ -1,5 +1,5 @@
-from .common import *
-from .plotting import *
+from .common import *  # noqa: F401,F403
+from .plotting import *  # noqa: F401,F403
 
 # gets sphinx autodoc done right - don't remove it
-__all__ = [_ for _ in dir() if not _.startswith('_')]
+__all__ = [_ for _ in dir() if not _.startswith("_")]
diff --git a/bob/fusion/base/tools/common.py b/bob/fusion/base/tools/common.py
index b625366..5339e18 100644
--- a/bob/fusion/base/tools/common.py
+++ b/bob/fusion/base/tools/common.py
@@ -1,18 +1,21 @@
-import numpy as np
+import logging
+
 from collections import defaultdict
 
-import logging
+import numpy as np
 
 logger = logging.getLogger(__name__)
 
 
 def get_2negatives_1positive(score_lines):
-    gen_mask = score_lines['claimed_id'] == score_lines['real_id']
+    gen_mask = score_lines["claimed_id"] == score_lines["real_id"]
     atk_mask = np.logical_or(
-        np.char.count(score_lines['real_id'], 'spoof') > 0,
-        np.char.count(score_lines['real_id'], 'attack') > 0)
-    zei_mask = np.logical_and(np.logical_not(
-        gen_mask), np.logical_not(atk_mask))
+        np.char.count(score_lines["real_id"], "spoof") > 0,
+        np.char.count(score_lines["real_id"], "attack") > 0,
+    )
+    zei_mask = np.logical_and(
+        np.logical_not(gen_mask), np.logical_not(atk_mask)
+    )
     gen = score_lines[gen_mask]
     zei = score_lines[zei_mask]
     atk = score_lines[atk_mask]
@@ -22,28 +25,28 @@ def get_2negatives_1positive(score_lines):
 def check_consistency(gen_l, zei_l, atk_l):
     if len(gen_l) < 2:
         raise ValueError(
-            'Check failed since less than two system is available.')
+            "Check failed since less than two system is available."
+        )
     for score_lines_list in (gen_l, zei_l, atk_l):
         if not score_lines_list:
             continue
         score_lines0 = score_lines_list[0]
         for score_lines in score_lines_list[1:]:
-            match = np.all(score_lines['claimed_id'] ==
-                           score_lines0['claimed_id'])
+            match = np.all(
+                score_lines["claimed_id"] == score_lines0["claimed_id"]
+            )
             if not match:
-                raise ValueError(
-                    "claimed ids do not match between score files")
+                raise ValueError("claimed ids do not match between score files")
 
-            match = np.all(score_lines['real_id'] == score_lines0['real_id'])
+            match = np.all(score_lines["real_id"] == score_lines0["real_id"])
             if not match:
-                raise ValueError(
-                    "real ids do not match between score files")
+                raise ValueError("real ids do not match between score files")
 
 
 def get_scores(*args):
     scores = []
     for temp in zip(*args):
-        scores.append(np.concatenate([a['score'] for a in temp], axis=0))
+        scores.append(np.concatenate([a["score"] for a in temp], axis=0))
     return np.vstack(scores).T
 
 
@@ -51,7 +54,7 @@ def get_score_lines(*args):
     # get the dtype names
     names = list(args[0][0].dtype.names)
     if len(names) != 4:
-        names = [n for n in names if 'model_label' not in n]
+        names = [n for n in names if "model_label" not in n]
     logger.debug(names)
 
     # find the (max) size of strigns
@@ -64,7 +67,7 @@ def get_score_lines(*args):
     # make a new dtype
     new_dtype = []
     for name in names[:-1]:
-        new_dtype.append((name, 'U{}'.format(max(lengths[name]))))
+        new_dtype.append((name, "U{}".format(max(lengths[name]))))
     new_dtype.append((names[-1], float))
 
     score_lines = []
@@ -96,9 +99,11 @@ def get_gza_from_lines_list(score_lines_list):
     zei_lengths = np.array(zei_lengths)
     idx1 = 0  # used later if it does not enter the if.
     if not (np.all(zei_lengths == 0) or np.all(zei_lengths > 0)):
-        logger.info("Trying to fill-in the missing zero effort impostor scores"
-                    " for pad systems. If you see a numpy index error below, "
-                    "your biometric scores do not match your pad scores.")
+        logger.info(
+            "Trying to fill-in the missing zero effort impostor scores"
+            " for pad systems. If you see a numpy index error below, "
+            "your biometric scores do not match your pad scores."
+        )
         # generate the missing ones
         # find one that has zei
         idx1 = zei_lengths.nonzero()[0][0]
@@ -108,20 +113,24 @@ def get_gza_from_lines_list(score_lines_list):
                 continue
             temp = np.array(zei_full)
             # make sure we replace all scores.
-            temp['score'] = np.nan
+            temp["score"] = np.nan
             # get the list of ids
-            real_ids = np.unique(temp['real_id'])
+            real_ids = np.unique(temp["real_id"])
             # find pad score of that id and replace the score
             for real_id in real_ids:
                 # get the list of test_labels
                 test_labels = np.unique(
-                    temp['test_label'][temp['real_id'] == real_id])
+                    temp["test_label"][temp["real_id"] == real_id]
+                )
                 for test_label in test_labels:
-                    idx3 = np.logical_and(temp['real_id'] == real_id,
-                                          temp['test_label'] == test_label)
+                    idx3 = np.logical_and(
+                        temp["real_id"] == real_id,
+                        temp["test_label"] == test_label,
+                    )
                     idx4 = np.logical_and(
-                        gen_l[idx2]['real_id'] == real_id,
-                        gen_l[idx2]['test_label'] == test_label)
-                    temp['score'][idx3] = gen_l[idx2]['score'][idx4]
+                        gen_l[idx2]["real_id"] == real_id,
+                        gen_l[idx2]["test_label"] == test_label,
+                    )
+                    temp["score"][idx3] = gen_l[idx2]["score"][idx4]
             zei_l[idx2] = temp
     return idx1, gen_l, zei_l, atk_l
diff --git a/bob/fusion/base/tools/plotting.py b/bob/fusion/base/tools/plotting.py
index e75bcf0..7da7fb3 100644
--- a/bob/fusion/base/tools/plotting.py
+++ b/bob/fusion/base/tools/plotting.py
@@ -1,9 +1,11 @@
 #!/usr/bin/env python
 
-import bob.learn.em
 import numpy as np
+
 from numpy.random import default_rng
 
+import bob.learn.em
+
 
 def grouping(scores, gformat="random", npoints=500, seed=None, **kwargs):
 
@@ -12,7 +14,9 @@ def grouping(scores, gformat="random", npoints=500, seed=None, **kwargs):
         return scores
 
     if gformat == "kmeans":
-        kmeans_machine = bob.learn.em.KMeansMachine(n_clusters=npoints, convergence_threshold=0.1, max_iter=500)
+        kmeans_machine = bob.learn.em.KMeansMachine(
+            n_clusters=npoints, convergence_threshold=0.1, max_iter=500
+        )
         kmeans_machine.fit(scores)
         scores = kmeans_machine.means
 
diff --git a/buildout.cfg b/buildout.cfg
index a959ae4..44d8d99 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -11,4 +11,4 @@ verbose = true
 
 [scripts]
 recipe = bob.buildout:scripts
-dependent-scripts = true
\ No newline at end of file
+dependent-scripts = true
diff --git a/develop.cfg b/develop.cfg
index b2e43bc..3e7ed68 100644
--- a/develop.cfg
+++ b/develop.cfg
@@ -26,4 +26,3 @@ bob.learn.em = git git@gitlab.idiap.ch:bob/bob.learn.em
 [scripts]
 recipe = bob.buildout:scripts
 dependent-scripts = true
-
diff --git a/doc/conf.py b/doc/conf.py
index 66328c7..0666276 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -2,32 +2,30 @@
 # vim: set fileencoding=utf-8 :
 
 import os
-import sys
-import glob
-import pkg_resources
 
+import pkg_resources
 
 # -- General configuration -----------------------------------------------------
 
 # If your documentation needs a minimal Sphinx version, state it here.
-needs_sphinx = '1.3'
+needs_sphinx = "1.3"
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = [
-    'sphinx.ext.todo',
-    'sphinx.ext.coverage',
-    'sphinx.ext.ifconfig',
-    'sphinx.ext.autodoc',
-    'sphinx.ext.autosummary',
-    'sphinx.ext.doctest',
-    'sphinx.ext.graphviz',
-    'sphinx.ext.intersphinx',
-    'sphinx.ext.napoleon',
-    'sphinx.ext.viewcode',
-    'sphinx.ext.mathjax',
-    #'matplotlib.sphinxext.plot_directive'
-    ]
+    "sphinx.ext.todo",
+    "sphinx.ext.coverage",
+    "sphinx.ext.ifconfig",
+    "sphinx.ext.autodoc",
+    "sphinx.ext.autosummary",
+    "sphinx.ext.doctest",
+    "sphinx.ext.graphviz",
+    "sphinx.ext.intersphinx",
+    "sphinx.ext.napoleon",
+    "sphinx.ext.viewcode",
+    "sphinx.ext.mathjax",
+    # 'matplotlib.sphinxext.plot_directive'
+]
 
 # Be picky about warnings
 nitpicky = False
@@ -36,13 +34,13 @@ nitpicky = False
 nitpick_ignore = []
 
 # Allows the user to override warnings from a separate file
-if os.path.exists('nitpick-exceptions.txt'):
-    for line in open('nitpick-exceptions.txt'):
+if os.path.exists("nitpick-exceptions.txt"):
+    for line in open("nitpick-exceptions.txt"):
         if line.strip() == "" or line.startswith("#"):
             continue
         dtype, target = line.split(None, 1)
         target = target.strip()
-        try: # python 2.x
+        try:  # python 2.x
             target = unicode(target)
         except NameError:
             pass
@@ -58,25 +56,27 @@ autosummary_generate = True
 numfig = True
 
 # If we are on OSX, the 'dvipng' path maybe different
-dvipng_osx = '/opt/local/libexec/texlive/binaries/dvipng'
-if os.path.exists(dvipng_osx): pngmath_dvipng = dvipng_osx
+dvipng_osx = "/opt/local/libexec/texlive/binaries/dvipng"
+if os.path.exists(dvipng_osx):
+    pngmath_dvipng = dvipng_osx
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
 
 # The suffix of source filenames.
-source_suffix = '.rst'
+source_suffix = ".rst"
 
 # The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
 
 # The master toctree document.
-master_doc = 'index'
+master_doc = "index"
 
 # General information about the project.
-project = u'bob.fusion.base'
+project = u"bob.fusion.base"
 import time
-copyright = u'%s, Idiap Research Institute' % time.strftime('%Y')
+
+copyright = u"%s, Idiap Research Institute" % time.strftime("%Y")
 
 # Grab the setup entry
 distribution = pkg_resources.require(project)[0]
@@ -92,42 +92,42 @@ release = distribution.version
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
-#language = None
+# language = None
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
-#today = ''
+# today = ''
 # Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
-exclude_patterns = ['links.rst']
+exclude_patterns = ["links.rst"]
 
 # The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
+# default_role = None
 
 # If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
 
 # If true, the current module name will be prepended to all description
 # unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
 
 # If true, sectionauthor and moduleauthor directives will be shown in the
 # output. They are ignored by default.
-#show_authors = False
+# show_authors = False
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
 
 # A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
 
 # Some variables which are useful for generated material
-project_variable = project.replace('.', '_')
-short_description = u'Score fusion in biometric and pad experiments'
-owner = [u'Idiap Research Institute']
+project_variable = project.replace(".", "_")
+short_description = u"Score fusion in biometric and pad experiments"
+owner = [u"Idiap Research Institute"]
 
 
 # -- Options for HTML output ---------------------------------------------------
@@ -135,80 +135,81 @@ owner = [u'Idiap Research Institute']
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 import sphinx_rtd_theme
-html_theme = 'sphinx_rtd_theme'
+
+html_theme = "sphinx_rtd_theme"
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
 # documentation.
-#html_theme_options = {}
+# html_theme_options = {}
 
 # Add any paths that contain custom themes here, relative to this directory.
 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
 
 # The name for this set of Sphinx documents.  If None, it defaults to
 # "<project> v<release> documentation".
-#html_title = None
+# html_title = None
 
 # A shorter title for the navigation bar.  Default is the same as html_title.
-#html_short_title = project_variable
+# html_short_title = project_variable
 
 # The name of an image file (relative to this directory) to place at the top
 # of the sidebar.
-html_logo = 'img/logo.png'
+html_logo = "img/logo.png"
 
 # The name of an image file (within the static path) to use as favicon of the
 # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
 # pixels large.
-html_favicon = 'img/favicon.ico'
+html_favicon = "img/favicon.ico"
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-#html_static_path = ['_static']
+# html_static_path = ['_static']
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
 
 # If true, SmartyPants will be used to convert quotes and dashes to
 # typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
 
 # Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
 
 # Additional templates that should be rendered to pages, maps page names to
 # template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
 
 # If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
 
 # If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
 
 # If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
 
 # If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
 
 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
 
 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
 
 # If true, an OpenSearch description file will be output, and all pages will
 # contain a <link> tag referring to it.  The value of this option must be the
 # base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
 
 # This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = project_variable + u'_doc'
+htmlhelp_basename = project_variable + u"_doc"
 
 
 # -- Post configuration --------------------------------------------------------
@@ -218,26 +219,27 @@ rst_epilog = """
 .. |project| replace:: Bob
 .. |version| replace:: %s
 .. |current-year| date:: %%Y
-""" % (version,)
+""" % (
+    version,
+)
 
 # Default processing flags for sphinx
-autoclass_content = 'class'
-autodoc_member_order = 'bysource'
+autoclass_content = "class"
+autodoc_member_order = "bysource"
 autodoc_default_options = {
-  "members": True,
-  "undoc-members": True,
-  "show-inheritance": True,
+    "members": True,
+    "undoc-members": True,
+    "show-inheritance": True,
 }
 
 # For inter-documentation mapping:
 from bob.extension.utils import link_documentation, load_requirements
+
 sphinx_requirements = "extra-intersphinx.txt"
 if os.path.exists(sphinx_requirements):
-  intersphinx_mapping = link_documentation(
-      additional_packages=['python','numpy'] + \
-          load_requirements(sphinx_requirements)
-          )
+    intersphinx_mapping = link_documentation(
+        additional_packages=["python", "numpy"]
+        + load_requirements(sphinx_requirements)
+    )
 else:
-  intersphinx_mapping = link_documentation()
-
-
+    intersphinx_mapping = link_documentation()
diff --git a/setup.py b/setup.py
index fa9959a..ffa14e5 100644
--- a/setup.py
+++ b/setup.py
@@ -1,68 +1,59 @@
 #!/usr/bin/env python
 # vim: set fileencoding=utf-8 :
 
-from setuptools import setup, dist
-dist.Distribution(dict(setup_requires=['bob.extension']))
+from setuptools import dist, setup
+
+dist.Distribution(dict(setup_requires=["bob.extension"]))
+
+from bob.extension.utils import find_packages, load_requirements
 
-from bob.extension.utils import load_requirements, find_packages
 install_requires = load_requirements()
 
 setup(
-
-    name='bob.fusion.base',
+    name="bob.fusion.base",
     version=open("version.txt").read().rstrip(),
-    description='Score fusion in biometric and pad experiments',
-
-    url='https://gitlab.idiap.ch/bob/bob.fusion.base',
-    license='GPLv3',
-    author='Amir Mohammadi',
-    author_email='amir.mohammadi@idiap.ch',
-    keywords='bob, score fusion, evaluation, biometric',
-
-    long_description=open('README.rst').read(),
-
+    description="Score fusion in biometric and pad experiments",
+    url="https://gitlab.idiap.ch/bob/bob.fusion.base",
+    license="GPLv3",
+    author="Amir Mohammadi",
+    author_email="amir.mohammadi@idiap.ch",
+    keywords="bob, score fusion, evaluation, biometric",
+    long_description=open("README.rst").read(),
     packages=find_packages(),
     include_package_data=True,
     zip_safe=False,
-
     install_requires=install_requires,
-
     entry_points={
-
         # main entry for bob fusion cli
-        'bob.cli': [
-            'fusion = bob.fusion.base.script.fusion:fusion',
+        "bob.cli": [
+            "fusion = bob.fusion.base.script.fusion:fusion",
         ],
-
         # bob fusion scripts
-        'bob.fusion.cli': [
-            'fuse = bob.fusion.base.script.fuse:fuse',
-            'resource = bob.fusion.base.script.resource:resource',
-            'boundary = bob.fusion.base.script.boundary:boundary',
+        "bob.fusion.cli": [
+            "fuse = bob.fusion.base.script.fuse:fuse",
+            "resource = bob.fusion.base.script.resource:resource",
+            "boundary = bob.fusion.base.script.boundary:boundary",
         ],
-
-        'bob.fusion.algorithm': [
-            'mean         = bob.fusion.base.config.algorithm.mean:algorithm',
-            'mean-tanh    = bob.fusion.base.config.algorithm.mean:algorithm_tanh',
-            'llr          = bob.fusion.base.config.algorithm.llr_skl:algorithm',
-            'llr-tanh     = bob.fusion.base.config.algorithm.llr_skl:algorithm_tanh',
-            'plr-2        = bob.fusion.base.config.algorithm.plr_2:algorithm',
-            'plr-2-tanh   = bob.fusion.base.config.algorithm.plr_2:algorithm_tanh',
-            'plr-3        = bob.fusion.base.config.algorithm.plr_3:algorithm',
-            'plr-3-tanh   = bob.fusion.base.config.algorithm.plr_3:algorithm_tanh',
-            'gmm          = bob.fusion.base.config.algorithm.gmm:algorithm',
-            'gmm-tanh     = bob.fusion.base.config.algorithm.gmm:algorithm_tanh',
+        "bob.fusion.algorithm": [
+            "mean         = bob.fusion.base.config.algorithm.mean:algorithm",
+            "mean-tanh    = bob.fusion.base.config.algorithm.mean:algorithm_tanh",
+            "llr          = bob.fusion.base.config.algorithm.llr_skl:algorithm",
+            "llr-tanh     = bob.fusion.base.config.algorithm.llr_skl:algorithm_tanh",
+            "plr-2        = bob.fusion.base.config.algorithm.plr_2:algorithm",
+            "plr-2-tanh   = bob.fusion.base.config.algorithm.plr_2:algorithm_tanh",
+            "plr-3        = bob.fusion.base.config.algorithm.plr_3:algorithm",
+            "plr-3-tanh   = bob.fusion.base.config.algorithm.plr_3:algorithm_tanh",
+            "gmm          = bob.fusion.base.config.algorithm.gmm:algorithm",
+            "gmm-tanh     = bob.fusion.base.config.algorithm.gmm:algorithm_tanh",
         ],
-
     },
-
     classifiers=[
-        'Framework :: Bob',
-        'Development Status :: 3 - Alpha',
-        'Intended Audience :: Developers',
-        'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
-        'Natural Language :: English',
-        'Programming Language :: Python',
-        'Topic :: Scientific/Engineering :: Artificial Intelligence',
+        "Framework :: Bob",
+        "Development Status :: 3 - Alpha",
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
+        "Natural Language :: English",
+        "Programming Language :: Python",
+        "Topic :: Scientific/Engineering :: Artificial Intelligence",
     ],
 )
-- 
GitLab