From dbfe543733e94263d2e62211dce0a71436c43ed3 Mon Sep 17 00:00:00 2001
From: Amir MOHAMMADI <amir.mohammadi@idiap.ch>
Date: Mon, 29 Mar 2021 23:53:06 +0200
Subject: [PATCH] Replace nose with pytest

---
 bob/bio/face/test/test_algorithms.py   |  4 ---
 bob/bio/face/test/test_baselines.py    | 15 ++++----
 bob/bio/face/test/test_databases.py    | 50 +++++++++++++-------------
 bob/bio/face/test/test_embeddings.py   | 16 ++++-----
 bob/bio/face/test/test_extractors.py   |  4 ---
 bob/bio/face/test/test_picklability.py |  5 ++-
 bob/bio/face/test/test_transformers.py | 16 ++++-----
 conda/meta.yaml                        |  7 ++--
 pyproject.toml                         |  3 ++
 9 files changed, 57 insertions(+), 63 deletions(-)

diff --git a/bob/bio/face/test/test_algorithms.py b/bob/bio/face/test/test_algorithms.py
index ca2243ba..3581e94a 100644
--- a/bob/bio/face/test/test_algorithms.py
+++ b/bob/bio/face/test/test_algorithms.py
@@ -20,12 +20,8 @@
 import bob.io.base
 import bob.ip.gabor
 
-import unittest
-import os
 import numpy
 import math
-import tempfile
-from nose.plugins.skip import SkipTest
 
 import pkg_resources
 
diff --git a/bob/bio/face/test/test_baselines.py b/bob/bio/face/test/test_baselines.py
index b1177216..2de487ad 100644
--- a/bob/bio/face/test/test_baselines.py
+++ b/bob/bio/face/test/test_baselines.py
@@ -1,4 +1,3 @@
-from bob.extension.config import load
 import pkg_resources
 import numpy as np
 from bob.pipelines import Sample, SampleSet, DelayedSample
@@ -12,7 +11,7 @@ import os
 import bob.io.base
 import functools
 import copy
-from nose.plugins.attrib import attr
+import pytest
 
 from bob.bio.base.test.utils import is_library_available
 
@@ -107,37 +106,37 @@ def run_baseline(baseline, samples_for_training=[]):
         assert "scores" in dirs
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_facenet_baseline():
     run_baseline("facenet-sanderberg")
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_inception_resnetv2_msceleb():
     run_baseline("inception-resnetv2-msceleb")
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_inception_resnetv2_casiawebface():
     run_baseline("inception-resnetv2-casiawebface")
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_inception_resnetv1_msceleb():
     run_baseline("inception-resnetv1-msceleb")
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_inception_resnetv1_casiawebface():
     run_baseline("inception-resnetv1-casiawebface")
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("mxnet")
 def test_arcface_insightface():
     run_baseline("arcface-insightface")
diff --git a/bob/bio/face/test/test_databases.py b/bob/bio/face/test/test_databases.py
index 7526f6e9..b3b31710 100644
--- a/bob/bio/face/test/test_databases.py
+++ b/bob/bio/face/test/test_databases.py
@@ -18,13 +18,13 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
-from nose.plugins.skip import SkipTest
+import pytest
 
+import os
 import bob.bio.base
 from bob.bio.base.test.utils import db_available
 from bob.bio.base.test.test_database_implementations import (
     check_database,
-    check_database_zt,
 )
 import bob.core
 from bob.extension.download import get_file
@@ -72,14 +72,14 @@ def test_arface():
     try:
         check_database(database, groups=("dev", "eval"))
     except IOError as e:
-        raise SkipTest(
-            "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'"
+        pytest.skip("The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e
+
         )
     try:
         _check_annotations(database)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
             % e
         )
@@ -93,7 +93,7 @@ def test_atnt():
     try:
         check_database(database)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e
         )
@@ -109,14 +109,14 @@ def test_gbu():
         check_database(database, protocol="Bad", models_depend=True)
         check_database(database, protocol="Ugly", models_depend=True)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e
         )
     try:
         _check_annotations(database, limit_files=1000)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
             % e
         )
@@ -144,14 +144,14 @@ def test_lfw():
             models_depend=True,
         )
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e
         )
     try:
         _check_annotations(database, limit_files=1000)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
             % e
         )
@@ -167,7 +167,7 @@ def test_mobio():
     # Removing the file before the test
     try:
         os.remove(filename)
-    except:
+    except Exception:
         pass
 
     protocols = MobioDatabase.protocols()
@@ -206,7 +206,7 @@ def test_multipie():
     # Removing the file before the test
     try:
         os.remove(filename)
-    except:
+    except Exception:
         pass
 
     protocols = MultipieDatabase.protocols()
@@ -239,14 +239,14 @@ def test_replay_licit():
     try:
         check_database(database, groups=("dev", "eval"))
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e
         )
     try:
         _check_annotations(database, topleft=True)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
             % e
         )
@@ -260,14 +260,14 @@ def test_replay_spoof():
     try:
         check_database(database, groups=("dev", "eval"))
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e
         )
     try:
         _check_annotations(database, topleft=True)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
             % e
         )
@@ -281,14 +281,14 @@ def test_replaymobile_licit():
     try:
         check_database(database, groups=("dev", "eval"))
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e
         )
     try:
         _check_annotations(database, topleft=True, limit_files=20)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
             % e
         )
@@ -302,14 +302,14 @@ def test_replaymobile_spoof():
     try:
         check_database(database, groups=("dev", "eval"))
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e
         )
     try:
         _check_annotations(database, topleft=True, limit_files=20)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
             % e
         )
@@ -323,11 +323,11 @@ def test_ijbc():
     try:
         check_database(database, models_depend=True, training_depends=True)
     except IOError as e:
-        raise SkipTest("The database could not queried; Here is the error: '%s'" % e)
+        pytest.skip("The database could not queried; Here is the error: '%s'" % e)
     try:
         _check_annotations(database, topleft=True, limit_files=1000)
     except IOError as e:
-        raise SkipTest(
+        pytest.skip(
             "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
             % e
         )
@@ -341,7 +341,7 @@ def test_fargo():
     try:
         check_database(database)
     except IOError as e:
-        raise SkipTest("The database could not queried; Here is the error: '%s'" % e)
+        pytest.skip("The database could not queried; Here is the error: '%s'" % e)
 
 
 def test_meds():
@@ -355,7 +355,7 @@ def test_meds():
     # Removing the file before the test
     try:
         os.remove(filename)
-    except:
+    except Exception:
         pass
 
     database = MEDSDatabase("verification_fold1")
@@ -382,7 +382,7 @@ def test_morph():
     # Removing the file before the test
     try:
         os.remove(filename)
-    except:
+    except Exception:
         pass
 
     database = MorphDatabase("verification_fold1")
diff --git a/bob/bio/face/test/test_embeddings.py b/bob/bio/face/test/test_embeddings.py
index 10b5cf27..9432e3e0 100644
--- a/bob/bio/face/test/test_embeddings.py
+++ b/bob/bio/face/test/test_embeddings.py
@@ -4,10 +4,10 @@ import numpy as np
 from bob.pipelines import Sample, wrap
 import pkg_resources
 from bob.bio.base.test.utils import is_library_available
-from nose.plugins.attrib import attr
+import pytest
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_idiap_inceptionv2_msceleb():
     from bob.bio.face.embeddings.tf2_inception_resnet import (
@@ -34,7 +34,7 @@ def test_idiap_inceptionv2_msceleb():
     assert output.size == 128, output.shape
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_idiap_inceptionv2_msceleb_memory_demanding():
     from bob.bio.face.embeddings.tf2_inception_resnet import (
@@ -62,7 +62,7 @@ def test_idiap_inceptionv2_msceleb_memory_demanding():
     assert output.size == 128, output.shape
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_idiap_inceptionv2_casia():
     from bob.bio.face.embeddings.tf2_inception_resnet import (
@@ -89,7 +89,7 @@ def test_idiap_inceptionv2_casia():
     assert output.size == 128, output.shape
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_idiap_inceptionv1_msceleb():
     from bob.bio.face.embeddings.tf2_inception_resnet import (
@@ -116,7 +116,7 @@ def test_idiap_inceptionv1_msceleb():
     assert output.size == 128, output.shape
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_idiap_inceptionv1_casia():
     from bob.bio.face.embeddings.tf2_inception_resnet import (
@@ -143,7 +143,7 @@ def test_idiap_inceptionv1_casia():
     assert output.size == 128, output.shape
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_facenet_sanderberg():
     from bob.bio.face.embeddings.tf2_inception_resnet import (
@@ -170,7 +170,7 @@ def test_facenet_sanderberg():
     assert output.size == 128, output.shape
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("mxnet")
 def test_arcface_insight_face():
     from bob.bio.face.embeddings.mxnet_models import ArcFaceInsightFace
diff --git a/bob/bio/face/test/test_extractors.py b/bob/bio/face/test/test_extractors.py
index 30936866..c935beb2 100644
--- a/bob/bio/face/test/test_extractors.py
+++ b/bob/bio/face/test/test_extractors.py
@@ -20,14 +20,10 @@
 import bob.bio.base
 import bob.bio.face
 
-import unittest
-import os
 import numpy
 import math
-from nose.plugins.skip import SkipTest
 
 import bob.io.base.test_utils
-from bob.bio.base.test import utils
 
 import pkg_resources
 
diff --git a/bob/bio/face/test/test_picklability.py b/bob/bio/face/test/test_picklability.py
index b5c60ae4..c6870fc4 100644
--- a/bob/bio/face/test/test_picklability.py
+++ b/bob/bio/face/test/test_picklability.py
@@ -2,7 +2,6 @@ import bob.bio.face
 import bob.bio.base
 import numpy as np
 import pickle
-import nose
 
 import bob.ip.base
 import bob.ip.flandmark
@@ -41,13 +40,13 @@ def assert_picklable_with_exceptions(obj):
     obj = obj.__dict__
     new_obj = new_obj.__dict__
     assert len(obj) == len(new_obj)
-    nose.tools.assert_equal(sorted(list(obj.keys())), sorted(list(new_obj.keys())))
+    assert sorted(list(obj.keys())) == sorted(list(new_obj.keys()))
     for k, v in obj.items():
         if isinstance(v, np.ndarray):
             np.testing.assert_equal(v, new_obj[k])
         else:
             if type(v) not in exception_list:
-                nose.tools.assert_equal(v, new_obj[k])
+                assert v == new_obj[k]
     return True
 
 
diff --git a/bob/bio/face/test/test_transformers.py b/bob/bio/face/test/test_transformers.py
index 309f344c..1af1a86d 100644
--- a/bob/bio/face/test/test_transformers.py
+++ b/bob/bio/face/test/test_transformers.py
@@ -1,10 +1,8 @@
-from bob.extension.config import load
-import pkg_resources
 import numpy as np
-from bob.pipelines import Sample, SampleSet
+from bob.pipelines import Sample
 from bob.bio.base import load_resource
 from bob.bio.base.test.utils import is_library_available
-from nose.plugins.attrib import attr
+import pytest
 
 
 def get_fake_sample(face_size=(160, 160), eyes={"leye": (46, 107), "reye": (46, 53)}):
@@ -14,7 +12,7 @@ def get_fake_sample(face_size=(160, 160), eyes={"leye": (46, 107), "reye": (46,
     return Sample(data, key="1", annotations=annotations)
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_facenet_sanderberg():
     transformer = load_resource("facenet-sanderberg", "transformer")
@@ -26,7 +24,7 @@ def test_facenet_sanderberg():
     assert transformed_sample.data.size == 128
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_inception_resnetv2_msceleb():
     transformer = load_resource("inception-resnetv2-msceleb", "transformer")
@@ -38,7 +36,7 @@ def test_inception_resnetv2_msceleb():
     assert transformed_sample.data.size == 128
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_inception_resnetv2_casiawebface():
     transformer = load_resource("inception-resnetv2-casiawebface", "transformer")
@@ -50,7 +48,7 @@ def test_inception_resnetv2_casiawebface():
     assert transformed_sample.data.size == 128
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_inception_resnetv1_msceleb():
     transformer = load_resource("inception-resnetv1-msceleb", "transformer")
@@ -62,7 +60,7 @@ def test_inception_resnetv1_msceleb():
     assert transformed_sample.data.size == 128
 
 
-@attr('slow')
+@pytest.mark.slow
 @is_library_available("tensorflow")
 def test_inception_resnetv1_casiawebface():
     transformer = load_resource("inception-resnetv1-casiawebface", "transformer")
diff --git a/conda/meta.yaml b/conda/meta.yaml
index 44e4780d..7643d12e 100644
--- a/conda/meta.yaml
+++ b/conda/meta.yaml
@@ -59,14 +59,17 @@ test:
     - {{ name }}
   commands:
     - bob bio display-face-annotations --help
-    - nosetests --with-coverage --cover-package={{ name }} -sv {{ name }}
+    # runs tests for package only, report only what is in the package
+    # creates html and xml reports and place them in specific directories
+    - pytest --verbose --cov {{ name }} --cov-report term-missing --cov-report html:{{ project_dir }}/sphinx/coverage --cov-report xml:{{ project_dir }}/coverage.xml --pyargs {{ name }}
     - sphinx-build -aEW {{ project_dir }}/doc {{ project_dir }}/sphinx
     - sphinx-build -aEb doctest {{ project_dir }}/doc sphinx
     - conda inspect linkages -p $PREFIX {{ name }}  # [not win]
     - conda inspect objects -p $PREFIX {{ name }}  # [osx]
   requires:
     - bob-devel {{ bob_devel }}.*
-    - nose
+    - pytest
+    - pytest-cov
     - coverage
     - sphinx
     - sphinx_rtd_theme
diff --git a/pyproject.toml b/pyproject.toml
index bb5e83cb..ff2f6ba2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,3 +1,6 @@
 [build-system]
 requires = ["setuptools", "wheel", "bob.extension"]
 build-backend = "setuptools.build_meta"
+
+[tool.pytest.ini_options]
+markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"]
-- 
GitLab