From 3760c6050b8703266bd5f792343b2e7f4729131f Mon Sep 17 00:00:00 2001 From: William de Vazelhes 80055062 Date: Wed, 7 Apr 2021 08:59:22 +0200 Subject: [PATCH 01/10] Update repo to work with both new and old scikit-learn, and add a travis job to test the old scikit-learn --- .travis.yml | 12 +++++++ test/metric_learn_test.py | 7 +++- test/test_base_metric.py | 8 ++++- test/test_components_metric_conversion.py | 7 +++- test/test_mahalanobis_mixin.py | 7 +++- test/test_pairs_classifiers.py | 7 +++- test/test_quadruplets_classifiers.py | 8 ++++- test/test_sklearn_compat.py | 44 ++++++++++++++--------- test/test_triplets_classifiers.py | 7 +++- test/test_utils.py | 7 +++- 10 files changed, 89 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index d294c294..4e03ce17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,18 @@ matrix: - pytest test --cov; after_success: - bash <(curl -s https://codecov.io/bash) + - name: "Pytest python 3.6 with skggm + scikit-learn 0.20.3" + python: "3.6" + before_install: + - sudo apt-get install liblapack-dev + - pip install --upgrade pip pytest + - pip install wheel cython numpy scipy codecov pytest-cov + - pip install scikit-learn==0.20.3 + - pip install git+https://github.com/skggm/skggm.git@${SKGGM_VERSION}; + script: + - pytest test --cov; + after_success: + - bash <(curl -s https://codecov.io/bash) - name: "Syntax checking with flake8" python: "3.7" before_install: diff --git a/test/metric_learn_test.py b/test/metric_learn_test.py index 4db0a1fc..ea3fc5bc 100644 --- a/test/metric_learn_test.py +++ b/test/metric_learn_test.py @@ -9,7 +9,12 @@ make_spd_matrix) from numpy.testing import (assert_array_almost_equal, assert_array_equal, assert_allclose) -from sklearn.utils.testing import assert_warns_message +import sklearn +from packaging import version +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import assert_warns_message +else: + from sklearn.utils.testing import assert_warns_message from sklearn.exceptions import ConvergenceWarning from sklearn.utils.validation import check_X_y from sklearn.preprocessing import StandardScaler diff --git a/test/test_base_metric.py b/test/test_base_metric.py index fed9018a..516d76fd 100644 --- a/test/test_base_metric.py +++ b/test/test_base_metric.py @@ -4,7 +4,13 @@ import metric_learn import numpy as np from sklearn import clone -from sklearn.utils.testing import set_random_state +import sklearn +from packaging import version +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import set_random_state +else: + from sklearn.utils.testing import set_random_state + from test.test_utils import ids_metric_learners, metric_learners, remove_y diff --git a/test/test_components_metric_conversion.py b/test/test_components_metric_conversion.py index 04d0d007..6d4d9a30 100644 --- a/test/test_components_metric_conversion.py +++ b/test/test_components_metric_conversion.py @@ -4,7 +4,12 @@ from scipy.stats import ortho_group from sklearn.datasets import load_iris from numpy.testing import assert_array_almost_equal, assert_allclose -from sklearn.utils.testing import ignore_warnings +import sklearn +from packaging import version +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import ignore_warnings +else: + from sklearn.utils.testing import ignore_warnings from metric_learn import ( LMNN, NCA, LFDA, Covariance, MLKR, diff --git a/test/test_mahalanobis_mixin.py b/test/test_mahalanobis_mixin.py index ab7e972d..1bdf71a4 100644 --- a/test/test_mahalanobis_mixin.py +++ b/test/test_mahalanobis_mixin.py @@ -11,7 +11,12 @@ from sklearn.datasets import make_spd_matrix, make_blobs from sklearn.utils import check_random_state, shuffle from sklearn.utils.multiclass import type_of_target -from sklearn.utils.testing import set_random_state +import sklearn +from packaging import version +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import set_random_state +else: + from sklearn.utils.testing import set_random_state from metric_learn._util import make_context, _initialize_metric_mahalanobis from metric_learn.base_metric import (_QuadrupletsClassifierMixin, diff --git a/test/test_pairs_classifiers.py b/test/test_pairs_classifiers.py index c5ca27f4..5b553cb1 100644 --- a/test/test_pairs_classifiers.py +++ b/test/test_pairs_classifiers.py @@ -11,7 +11,12 @@ from sklearn.model_selection import train_test_split from test.test_utils import pairs_learners, ids_pairs_learners -from sklearn.utils.testing import set_random_state +import sklearn +from packaging import version +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import set_random_state +else: + from sklearn.utils.testing import set_random_state from sklearn import clone import numpy as np from itertools import product diff --git a/test/test_quadruplets_classifiers.py b/test/test_quadruplets_classifiers.py index efe10030..337bab06 100644 --- a/test/test_quadruplets_classifiers.py +++ b/test/test_quadruplets_classifiers.py @@ -3,7 +3,13 @@ from sklearn.model_selection import train_test_split from test.test_utils import quadruplets_learners, ids_quadruplets_learners -from sklearn.utils.testing import set_random_state +import sklearn +from packaging import version + +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import set_random_state +else: + from sklearn.utils.testing import set_random_state from sklearn import clone import numpy as np diff --git a/test/test_sklearn_compat.py b/test/test_sklearn_compat.py index e18eb7f4..88b3f44c 100644 --- a/test/test_sklearn_compat.py +++ b/test/test_sklearn_compat.py @@ -4,9 +4,17 @@ from sklearn.base import TransformerMixin from sklearn.pipeline import make_pipeline from sklearn.utils import check_random_state -from sklearn.utils.estimator_checks import is_public_parameter -from sklearn.utils.testing import (assert_allclose_dense_sparse, - set_random_state) +import sklearn +from packaging import version +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import (assert_allclose_dense_sparse, + set_random_state, _get_args) + from sklearn.utils.estimator_checks import (_is_public_parameter + as is_public_parameter) +else: + from sklearn.utils.testing import (assert_allclose_dense_sparse, + set_random_state, _get_args) + from sklearn.utils.estimator_checks import is_public_parameter from metric_learn import (Covariance, LFDA, LMNN, MLKR, NCA, ITML_Supervised, LSML_Supervised, @@ -16,8 +24,10 @@ import numpy as np from sklearn.model_selection import (cross_val_score, cross_val_predict, train_test_split, KFold) -from sklearn.metrics.scorer import get_scorer -from sklearn.utils.testing import _get_args +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.metrics._scorer import get_scorer +else: + from sklearn.metrics.scorer import get_scorer from test.test_utils import (metric_learners, ids_metric_learners, mock_preprocessor, tuples_learners, ids_tuples_learners, pairs_learners, @@ -52,37 +62,37 @@ def __init__(self, sparsity_param=0.01, class TestSklearnCompat(unittest.TestCase): def test_covariance(self): - check_estimator(Covariance) + check_estimator(Covariance()) def test_lmnn(self): - check_estimator(LMNN) + check_estimator(LMNN()) def test_lfda(self): - check_estimator(LFDA) + check_estimator(LFDA()) def test_mlkr(self): - check_estimator(MLKR) + check_estimator(MLKR()) def test_nca(self): - check_estimator(NCA) + check_estimator(NCA()) def test_lsml(self): - check_estimator(LSML_Supervised) + check_estimator(LSML_Supervised()) def test_itml(self): - check_estimator(ITML_Supervised) + check_estimator(ITML_Supervised()) def test_mmc(self): - check_estimator(MMC_Supervised) + check_estimator(MMC_Supervised()) def test_sdml(self): - check_estimator(Stable_SDML_Supervised) + check_estimator(Stable_SDML_Supervised()) def test_rca(self): - check_estimator(Stable_RCA_Supervised) + check_estimator(Stable_RCA_Supervised()) def test_scml(self): - check_estimator(SCML_Supervised) + check_estimator(SCML_Supervised()) RNG = check_random_state(0) @@ -160,7 +170,7 @@ def test_various_scoring_on_tuples_learners(estimator, build_dataset, with_preprocessor): """Tests that scikit-learn's scoring returns something finite, for other scoring than default scoring. (List of scikit-learn's scores can be - found in sklearn.metrics.scorer). For each type of output (predict, + found in sklearn.metrics._scorer). For each type of output (predict, predict_proba, decision_function), we test a bunch of scores. We only test on pairs learners because quadruplets don't have a y argument. """ diff --git a/test/test_triplets_classifiers.py b/test/test_triplets_classifiers.py index 10393919..e8c42167 100644 --- a/test/test_triplets_classifiers.py +++ b/test/test_triplets_classifiers.py @@ -3,7 +3,12 @@ from sklearn.model_selection import train_test_split from test.test_utils import triplets_learners, ids_triplets_learners -from sklearn.utils.testing import set_random_state +import sklearn +from packaging import version +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import set_random_state +else: + from sklearn.utils.testing import set_random_state from sklearn import clone import numpy as np diff --git a/test/test_utils.py b/test/test_utils.py index 5ddf3d71..0fc479c5 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -5,7 +5,12 @@ from numpy.testing import assert_array_equal, assert_equal from sklearn.model_selection import train_test_split from sklearn.utils import check_random_state, shuffle -from sklearn.utils.testing import set_random_state +import sklearn +from packaging import version +if version.parse(sklearn.__version__) >= version.parse('0.22.0'): + from sklearn.utils._testing import set_random_state +else: + from sklearn.utils.testing import set_random_state from sklearn.base import clone from metric_learn._util import (check_input, make_context, preprocess_tuples, make_name, preprocess_points, From 777f8d632eecc54f4134771fdcfbb128782f0179 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Wed, 7 Apr 2021 11:13:41 +0200 Subject: [PATCH 02/10] Add random seed for test --- test/test_sklearn_compat.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_sklearn_compat.py b/test/test_sklearn_compat.py index 88b3f44c..4c636e2f 100644 --- a/test/test_sklearn_compat.py +++ b/test/test_sklearn_compat.py @@ -131,7 +131,8 @@ def test_array_like_inputs(estimator, build_dataset, with_preprocessor): # we subsample the data for the test to be more efficient input_data, _, labels, _ = train_test_split(input_data, labels, - train_size=20) + train_size=20, + random_state=42) X = X[:10] estimator = clone(estimator) From e5c240d6e5eac81080afd36fa72542c2e982f018 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Sun, 11 Apr 2021 12:44:29 +0200 Subject: [PATCH 03/10] fix str representation for various sklearn versions --- test/test_base_metric.py | 126 ++++++++++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 16 deletions(-) diff --git a/test/test_base_metric.py b/test/test_base_metric.py index 516d76fd..74eb43b5 100644 --- a/test/test_base_metric.py +++ b/test/test_base_metric.py @@ -6,7 +6,8 @@ from sklearn import clone import sklearn from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): +skversion = version.parse(sklearn.__version__) +if skversion >= version.parse('0.22.0'): from sklearn.utils._testing import set_random_state else: from sklearn.utils.testing import set_random_state @@ -18,63 +19,156 @@ def remove_spaces(s): return re.sub(r'\s+', '', s) +def sk_repr_kwargs(def_kwargs, nndef_kwargs): + """Given the non-default arguments, and the default + keywords arguments, build the string that will appear + in the __repr__ of the estimator, depending on the + version of scikit-learn. + """ + if skversion >= version.parse('0.22.0'): + def_kwargs = "" + nndef_kwargs = eval(f"dict({nndef_kwargs})") + def_kwargs = eval(f"dict({def_kwargs})") + def_kwargs.update(nndef_kwargs) + args_str = ",".join(f"{key}={strify(value)}" + for key, value in def_kwargs.items()) + return args_str + + +def strify(obj): + """Function to add the quotation marks if the object + is a string""" + if type(obj) is str: + return f"'{obj}'" + else: + return str(obj) + + class TestStringRepr(unittest.TestCase): def test_covariance(self): + def_kwargs = "preprocessor=None" + nndef_kwargs = "" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.Covariance())), - remove_spaces("Covariance()")) + remove_spaces(f"Covariance({merged_kwargs})")) def test_lmnn(self): + def_kwargs = """convergence_tol=0.001, init='auto', k=3, + learn_rate=1e-07, max_iter=1000, min_iter=50, n_components=None, + preprocessor=None, random_state=None, regularization=0.5, + verbose=False""" + nndef_kwargs = "convergence_tol=0.01, k=6" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.LMNN(convergence_tol=0.01, k=6))), - remove_spaces("LMNN(convergence_tol=0.01, k=6)")) + remove_spaces(f"LMNN({merged_kwargs})")) def test_nca(self): + def_kwargs = """init='auto', max_iter=100, n_components=None, + preprocessor=None, random_state=None, tol=None, verbose=False""" + nndef_kwargs = "max_iter=42" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.NCA(max_iter=42))), - remove_spaces("NCA(max_iter=42)")) + remove_spaces(f"NCA({merged_kwargs})")) def test_lfda(self): + def_kwargs = """embedding_type='weighted', k=None, + n_components=None,preprocessor=None""" + nndef_kwargs = "k=2" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.LFDA(k=2))), - remove_spaces("LFDA(k=2)")) + remove_spaces(f"LFDA({merged_kwargs})")) def test_itml(self): + def_kwargs = """convergence_threshold=0.001, gamma=1.0, + max_iter=1000, preprocessor=None, prior='identity', random_state=None, + verbose=False""" + nndef_kwargs = "gamma=0.5" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.ITML(gamma=0.5))), - remove_spaces("ITML(gamma=0.5)")) + remove_spaces(f"ITML({merged_kwargs})")) + def_kwargs = """convergence_threshold=0.001, gamma=1.0, + max_iter=1000, num_constraints=None,preprocessor=None, + prior='identity', random_state=None, verbose=False""" + nndef_kwargs = "num_constraints=7" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.ITML_Supervised(num_constraints=7))), - remove_spaces("ITML_Supervised(num_constraints=7)")) + remove_spaces(f"ITML_Supervised({merged_kwargs})")) def test_lsml(self): + def_kwargs = """max_iter=1000, preprocessor=None, prior='identity', + random_state=None, tol=0.001, verbose=False""" + nndef_kwargs = "tol=0.1" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.LSML(tol=0.1))), - remove_spaces("LSML(tol=0.1)")) + remove_spaces(f"LSML({merged_kwargs})")) + def_kwargs = """max_iter=1000, num_constraints=None, preprocessor=None, + prior='identity', random_state=None, tol=0.001, verbose=False, + weights=None""" + nndef_kwargs = "verbose=True" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.LSML_Supervised(verbose=True))), - remove_spaces("LSML_Supervised(verbose=True)")) + remove_spaces(f"LSML_Supervised({merged_kwargs})")) def test_sdml(self): + def_kwargs = """ + balance_param=0.5, preprocessor=None, prior='identity', random_state=None, + sparsity_param=0.01, verbose=False""" + nndef_kwargs = "verbose=True" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.SDML(verbose=True))), - remove_spaces("SDML(verbose=True)")) + remove_spaces(f"SDML({merged_kwargs})")) + def_kwargs = """balance_param=0.5, num_constraints=None, + preprocessor=None, prior='identity', random_state=None, + sparsity_param=0.01, verbose=False""" + nndef_kwargs = "sparsity_param=0.5" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.SDML_Supervised(sparsity_param=0.5))), - remove_spaces("SDML_Supervised(sparsity_param=0.5)")) + remove_spaces(f"SDML_Supervised({merged_kwargs})")) def test_rca(self): + def_kwargs = "n_components=None, preprocessor=None" + nndef_kwargs = "n_components=3" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.RCA(n_components=3))), - remove_spaces("RCA(n_components=3)")) + remove_spaces(f"RCA({merged_kwargs})")) + def_kwargs = """chunk_size=2, n_components=None, num_chunks=100, + preprocessor=None, random_state=None""" + nndef_kwargs = "num_chunks=5" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.RCA_Supervised(num_chunks=5))), - remove_spaces("RCA_Supervised(num_chunks=5)")) + remove_spaces(f"RCA_Supervised({merged_kwargs})")) def test_mlkr(self): + def_kwargs = """init='auto', max_iter=1000, n_components=None, + preprocessor=None, random_state=None, tol=None, verbose=False""" + nndef_kwargs = "max_iter=777" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.MLKR(max_iter=777))), - remove_spaces("MLKR(max_iter=777)")) + remove_spaces(f"MLKR({merged_kwargs})")) def test_mmc(self): + def_kwargs = """convergence_threshold=0.001, diagonal=False, + diagonal_c=1.0, init='identity', max_iter=100, max_proj=10000, + preprocessor=None, random_state=None, verbose=False""" + nndef_kwargs = "diagonal=True" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.MMC(diagonal=True))), - remove_spaces("MMC(diagonal=True)")) + remove_spaces(f"MMC({merged_kwargs})")) + def_kwargs = """convergence_threshold=1e-06, diagonal=False, + diagonal_c=1.0, init='identity', max_iter=100, max_proj=10000, + num_constraints=None, preprocessor=None, random_state=None, + verbose=False""" + nndef_kwargs = "max_iter=1" + merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.MMC_Supervised(max_iter=1))), - remove_spaces("MMC_Supervised(max_iter=1)")) + remove_spaces(f"MMC_Supervised({merged_kwargs})")) @pytest.mark.parametrize('estimator, build_dataset', metric_learners, From b754930cde2dd22cd10347b74d2b58ef992805d7 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Mon, 12 Apr 2021 09:19:20 +0200 Subject: [PATCH 04/10] fix flake8 error --- test/test_base_metric.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_base_metric.py b/test/test_base_metric.py index 74eb43b5..9ba9ee92 100644 --- a/test/test_base_metric.py +++ b/test/test_base_metric.py @@ -6,14 +6,13 @@ from sklearn import clone import sklearn from packaging import version +from test.test_utils import ids_metric_learners, metric_learners, remove_y skversion = version.parse(sklearn.__version__) if skversion >= version.parse('0.22.0'): from sklearn.utils._testing import set_random_state else: from sklearn.utils.testing import set_random_state -from test.test_utils import ids_metric_learners, metric_learners, remove_y - def remove_spaces(s): return re.sub(r'\s+', '', s) From 195da0ab185b66f9d5d20b92d5a5e299bdc9130d Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Mon, 12 Apr 2021 09:55:38 +0200 Subject: [PATCH 05/10] add more samples to the test for robustness --- test/test_sklearn_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_sklearn_compat.py b/test/test_sklearn_compat.py index 4c636e2f..14cbed31 100644 --- a/test/test_sklearn_compat.py +++ b/test/test_sklearn_compat.py @@ -131,7 +131,7 @@ def test_array_like_inputs(estimator, build_dataset, with_preprocessor): # we subsample the data for the test to be more efficient input_data, _, labels, _ = train_test_split(input_data, labels, - train_size=20, + train_size=40, random_state=42) X = X[:10] From 0c780b0580dfe052dc310b49ee57e9744bff26c1 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Mon, 12 Apr 2021 14:46:53 +0200 Subject: [PATCH 06/10] add comment for additional travis test --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4e03ce17..03ba1706 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,6 +40,7 @@ matrix: after_success: - bash <(curl -s https://codecov.io/bash) - name: "Pytest python 3.6 with skggm + scikit-learn 0.20.3" + # checks that tests work for the oldest supported scikit-learn version python: "3.6" before_install: - sudo apt-get install liblapack-dev From bfea74213560b71356b260c11f7043da8817dc07 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Tue, 13 Apr 2021 13:16:56 +0200 Subject: [PATCH 07/10] change str to dict for simplicity --- test/test_base_metric.py | 129 +++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 66 deletions(-) diff --git a/test/test_base_metric.py b/test/test_base_metric.py index 9ba9ee92..47dedcc5 100644 --- a/test/test_base_metric.py +++ b/test/test_base_metric.py @@ -25,145 +25,142 @@ def sk_repr_kwargs(def_kwargs, nndef_kwargs): version of scikit-learn. """ if skversion >= version.parse('0.22.0'): - def_kwargs = "" - nndef_kwargs = eval(f"dict({nndef_kwargs})") - def_kwargs = eval(f"dict({def_kwargs})") + def_kwargs = {} def_kwargs.update(nndef_kwargs) - args_str = ",".join(f"{key}={strify(value)}" + args_str = ",".join(f"{key}={repr(value)}" for key, value in def_kwargs.items()) return args_str -def strify(obj): - """Function to add the quotation marks if the object - is a string""" - if type(obj) is str: - return f"'{obj}'" - else: - return str(obj) - - class TestStringRepr(unittest.TestCase): def test_covariance(self): - def_kwargs = "preprocessor=None" - nndef_kwargs = "" + def_kwargs = {'preprocessor': None} + nndef_kwargs = {} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.Covariance())), remove_spaces(f"Covariance({merged_kwargs})")) def test_lmnn(self): - def_kwargs = """convergence_tol=0.001, init='auto', k=3, - learn_rate=1e-07, max_iter=1000, min_iter=50, n_components=None, - preprocessor=None, random_state=None, regularization=0.5, - verbose=False""" - nndef_kwargs = "convergence_tol=0.01, k=6" + def_kwargs = {'convergence_tol': 0.001, 'init': 'auto', 'k': 3, + 'learn_rate': 1e-07, 'max_iter': 1000, 'min_iter': 50, + 'n_components': None, 'preprocessor': None, + 'random_state': None, 'regularization': 0.5, + 'verbose': False} + nndef_kwargs = {'convergence_tol': 0.01, 'k': 6} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.LMNN(convergence_tol=0.01, k=6))), remove_spaces(f"LMNN({merged_kwargs})")) def test_nca(self): - def_kwargs = """init='auto', max_iter=100, n_components=None, - preprocessor=None, random_state=None, tol=None, verbose=False""" - nndef_kwargs = "max_iter=42" + def_kwargs = {'init': 'auto', 'max_iter': 100, 'n_components': None, + 'preprocessor': None, 'random_state': None, 'tol': None, + 'verbose': False} + nndef_kwargs = {'max_iter': 42} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.NCA(max_iter=42))), remove_spaces(f"NCA({merged_kwargs})")) def test_lfda(self): - def_kwargs = """embedding_type='weighted', k=None, - n_components=None,preprocessor=None""" - nndef_kwargs = "k=2" + def_kwargs = {'embedding_type': 'weighted', 'k': None, + 'n_components': None, 'preprocessor': None} + nndef_kwargs = {'k': 2} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.LFDA(k=2))), remove_spaces(f"LFDA({merged_kwargs})")) def test_itml(self): - def_kwargs = """convergence_threshold=0.001, gamma=1.0, - max_iter=1000, preprocessor=None, prior='identity', random_state=None, - verbose=False""" - nndef_kwargs = "gamma=0.5" + def_kwargs = {'convergence_threshold': 0.001, 'gamma': 1.0, + 'max_iter': 1000, 'preprocessor': None, + 'prior': 'identity', 'random_state': None, 'verbose': False} + nndef_kwargs = {'gamma': 0.5} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.ITML(gamma=0.5))), remove_spaces(f"ITML({merged_kwargs})")) - def_kwargs = """convergence_threshold=0.001, gamma=1.0, - max_iter=1000, num_constraints=None,preprocessor=None, - prior='identity', random_state=None, verbose=False""" - nndef_kwargs = "num_constraints=7" + def_kwargs = {'convergence_threshold': 0.001, 'gamma': 1.0, + 'max_iter': 1000, 'num_constraints': None, + 'preprocessor': None, 'prior': 'identity', + 'random_state': None, 'verbose': False} + nndef_kwargs = {'num_constraints': 7} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.ITML_Supervised(num_constraints=7))), remove_spaces(f"ITML_Supervised({merged_kwargs})")) def test_lsml(self): - def_kwargs = """max_iter=1000, preprocessor=None, prior='identity', - random_state=None, tol=0.001, verbose=False""" - nndef_kwargs = "tol=0.1" + def_kwargs = {'max_iter': 1000, 'preprocessor': None, 'prior': 'identity', + 'random_state': None, 'tol': 0.001, 'verbose': False} + nndef_kwargs = {'tol': 0.1} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.LSML(tol=0.1))), remove_spaces(f"LSML({merged_kwargs})")) - def_kwargs = """max_iter=1000, num_constraints=None, preprocessor=None, - prior='identity', random_state=None, tol=0.001, verbose=False, - weights=None""" - nndef_kwargs = "verbose=True" + def_kwargs = {'max_iter': 1000, 'num_constraints': None, + 'preprocessor': None, 'prior': 'identity', + 'random_state': None, 'tol': 0.001, 'verbose': False, + 'weights': None} + nndef_kwargs = {'verbose': True} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.LSML_Supervised(verbose=True))), remove_spaces(f"LSML_Supervised({merged_kwargs})")) def test_sdml(self): - def_kwargs = """ - balance_param=0.5, preprocessor=None, prior='identity', random_state=None, - sparsity_param=0.01, verbose=False""" - nndef_kwargs = "verbose=True" + def_kwargs = {'balance_param': 0.5, 'preprocessor': None, + 'prior': 'identity', 'random_state': None, + 'sparsity_param': 0.01, 'verbose': False} + nndef_kwargs = {'verbose': True} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.SDML(verbose=True))), remove_spaces(f"SDML({merged_kwargs})")) - def_kwargs = """balance_param=0.5, num_constraints=None, - preprocessor=None, prior='identity', random_state=None, - sparsity_param=0.01, verbose=False""" - nndef_kwargs = "sparsity_param=0.5" + def_kwargs = {'balance_param': 0.5, 'num_constraints': None, + 'preprocessor': None, 'prior': 'identity', + 'random_state': None, 'sparsity_param': 0.01, + 'verbose': False} + nndef_kwargs = {'sparsity_param': 0.5} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.SDML_Supervised(sparsity_param=0.5))), remove_spaces(f"SDML_Supervised({merged_kwargs})")) def test_rca(self): - def_kwargs = "n_components=None, preprocessor=None" - nndef_kwargs = "n_components=3" + def_kwargs = {'n_components': None, 'preprocessor': None} + nndef_kwargs = {'n_components': 3} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.RCA(n_components=3))), remove_spaces(f"RCA({merged_kwargs})")) - def_kwargs = """chunk_size=2, n_components=None, num_chunks=100, - preprocessor=None, random_state=None""" - nndef_kwargs = "num_chunks=5" + def_kwargs = {'chunk_size': 2, 'n_components': None, 'num_chunks': 100, + 'preprocessor': None, 'random_state': None} + nndef_kwargs = {'num_chunks': 5} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.RCA_Supervised(num_chunks=5))), remove_spaces(f"RCA_Supervised({merged_kwargs})")) def test_mlkr(self): - def_kwargs = """init='auto', max_iter=1000, n_components=None, - preprocessor=None, random_state=None, tol=None, verbose=False""" - nndef_kwargs = "max_iter=777" + def_kwargs = {'init': 'auto', 'max_iter': 1000, + 'n_components': None, 'preprocessor': None, + 'random_state': None, 'tol': None, 'verbose': False} + nndef_kwargs = {'max_iter': 777} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.MLKR(max_iter=777))), remove_spaces(f"MLKR({merged_kwargs})")) def test_mmc(self): - def_kwargs = """convergence_threshold=0.001, diagonal=False, - diagonal_c=1.0, init='identity', max_iter=100, max_proj=10000, - preprocessor=None, random_state=None, verbose=False""" - nndef_kwargs = "diagonal=True" + def_kwargs = {'convergence_threshold': 0.001, 'diagonal': False, + 'diagonal_c': 1.0, 'init': 'identity', 'max_iter': 100, + 'max_proj': 10000, 'preprocessor': None, + 'random_state': None, 'verbose': False} + nndef_kwargs = {'diagonal': True} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual(remove_spaces(str(metric_learn.MMC(diagonal=True))), remove_spaces(f"MMC({merged_kwargs})")) - def_kwargs = """convergence_threshold=1e-06, diagonal=False, - diagonal_c=1.0, init='identity', max_iter=100, max_proj=10000, - num_constraints=None, preprocessor=None, random_state=None, - verbose=False""" - nndef_kwargs = "max_iter=1" + def_kwargs = {'convergence_threshold': 1e-06, 'diagonal': False, + 'diagonal_c': 1.0, 'init': 'identity', 'max_iter': 100, + 'max_proj': 10000, 'num_constraints': None, + 'preprocessor': None, 'random_state': None, + 'verbose': False} + nndef_kwargs = {'max_iter': 1} merged_kwargs = sk_repr_kwargs(def_kwargs, nndef_kwargs) self.assertEqual( remove_spaces(str(metric_learn.MMC_Supervised(max_iter=1))), From 61755dd09579be33f8e934904c63487a7bc213f1 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Tue, 13 Apr 2021 13:34:48 +0200 Subject: [PATCH 08/10] simplify conditional imports with sklearn_shims file --- metric_learn/sklearn_shims.py | 27 +++++++++++++++++++++++ test/metric_learn_test.py | 7 +----- test/test_base_metric.py | 10 ++------- test/test_components_metric_conversion.py | 7 +----- test/test_mahalanobis_mixin.py | 7 +----- test/test_pairs_classifiers.py | 7 +----- test/test_quadruplets_classifiers.py | 7 +----- test/test_sklearn_compat.py | 19 +++------------- test/test_triplets_classifiers.py | 7 +----- test/test_utils.py | 7 +----- 10 files changed, 39 insertions(+), 66 deletions(-) create mode 100644 metric_learn/sklearn_shims.py diff --git a/metric_learn/sklearn_shims.py b/metric_learn/sklearn_shims.py new file mode 100644 index 00000000..654a9144 --- /dev/null +++ b/metric_learn/sklearn_shims.py @@ -0,0 +1,27 @@ +"""This file is for fixing imports due to different APIs +depending on the scikit-learn version""" +import sklearn +from packaging import version +SKLEARN_AT_LEAST_0_22 = (version.parse(sklearn.__version__) + >= version.parse('0.22.0')) +if SKLEARN_AT_LEAST_0_22: + from sklearn.utils._testing import (set_random_state, + assert_warns_message, + ignore_warnings, + assert_allclose_dense_sparse, + _get_args) + from sklearn.utils.estimator_checks import (_is_public_parameter + as is_public_parameter) + from sklearn.metrics._scorer import get_scorer +else: + from sklearn.utils.testing import (set_random_state, + assert_warns_message, + ignore_warnings, + assert_allclose_dense_sparse, + _get_args) + from sklearn.utils.estimator_checks import is_public_parameter + from sklearn.metrics.scorer import get_scorer + +__all__ = ['set_random_state', 'assert_warns_message', 'set_random_state', + 'ignore_warnings', 'assert_allclose_dense_sparse', '_get_args', + 'is_public_parameter', 'get_scorer'] diff --git a/test/metric_learn_test.py b/test/metric_learn_test.py index ea3fc5bc..5cae80f2 100644 --- a/test/metric_learn_test.py +++ b/test/metric_learn_test.py @@ -9,12 +9,7 @@ make_spd_matrix) from numpy.testing import (assert_array_almost_equal, assert_array_equal, assert_allclose) -import sklearn -from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.utils._testing import assert_warns_message -else: - from sklearn.utils.testing import assert_warns_message +from metric_learn.sklearn_shims import assert_warns_message from sklearn.exceptions import ConvergenceWarning from sklearn.utils.validation import check_X_y from sklearn.preprocessing import StandardScaler diff --git a/test/test_base_metric.py b/test/test_base_metric.py index 47dedcc5..67f9b6a0 100644 --- a/test/test_base_metric.py +++ b/test/test_base_metric.py @@ -4,14 +4,8 @@ import metric_learn import numpy as np from sklearn import clone -import sklearn -from packaging import version from test.test_utils import ids_metric_learners, metric_learners, remove_y -skversion = version.parse(sklearn.__version__) -if skversion >= version.parse('0.22.0'): - from sklearn.utils._testing import set_random_state -else: - from sklearn.utils.testing import set_random_state +from metric_learn.sklearn_shims import set_random_state, SKLEARN_AT_LEAST_0_22 def remove_spaces(s): @@ -24,7 +18,7 @@ def sk_repr_kwargs(def_kwargs, nndef_kwargs): in the __repr__ of the estimator, depending on the version of scikit-learn. """ - if skversion >= version.parse('0.22.0'): + if SKLEARN_AT_LEAST_0_22: def_kwargs = {} def_kwargs.update(nndef_kwargs) args_str = ",".join(f"{key}={repr(value)}" diff --git a/test/test_components_metric_conversion.py b/test/test_components_metric_conversion.py index 6d4d9a30..5502ad90 100644 --- a/test/test_components_metric_conversion.py +++ b/test/test_components_metric_conversion.py @@ -4,12 +4,7 @@ from scipy.stats import ortho_group from sklearn.datasets import load_iris from numpy.testing import assert_array_almost_equal, assert_allclose -import sklearn -from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.utils._testing import ignore_warnings -else: - from sklearn.utils.testing import ignore_warnings +from metric_learn.sklearn_shims import ignore_warnings from metric_learn import ( LMNN, NCA, LFDA, Covariance, MLKR, diff --git a/test/test_mahalanobis_mixin.py b/test/test_mahalanobis_mixin.py index 1bdf71a4..84058b32 100644 --- a/test/test_mahalanobis_mixin.py +++ b/test/test_mahalanobis_mixin.py @@ -11,12 +11,7 @@ from sklearn.datasets import make_spd_matrix, make_blobs from sklearn.utils import check_random_state, shuffle from sklearn.utils.multiclass import type_of_target -import sklearn -from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.utils._testing import set_random_state -else: - from sklearn.utils.testing import set_random_state +from metric_learn.sklearn_shims import set_random_state from metric_learn._util import make_context, _initialize_metric_mahalanobis from metric_learn.base_metric import (_QuadrupletsClassifierMixin, diff --git a/test/test_pairs_classifiers.py b/test/test_pairs_classifiers.py index 5b553cb1..824bb622 100644 --- a/test/test_pairs_classifiers.py +++ b/test/test_pairs_classifiers.py @@ -11,12 +11,7 @@ from sklearn.model_selection import train_test_split from test.test_utils import pairs_learners, ids_pairs_learners -import sklearn -from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.utils._testing import set_random_state -else: - from sklearn.utils.testing import set_random_state +from metric_learn.sklearn_shims import set_random_state from sklearn import clone import numpy as np from itertools import product diff --git a/test/test_quadruplets_classifiers.py b/test/test_quadruplets_classifiers.py index 337bab06..57269cc3 100644 --- a/test/test_quadruplets_classifiers.py +++ b/test/test_quadruplets_classifiers.py @@ -3,13 +3,8 @@ from sklearn.model_selection import train_test_split from test.test_utils import quadruplets_learners, ids_quadruplets_learners -import sklearn -from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.utils._testing import set_random_state -else: - from sklearn.utils.testing import set_random_state +from metric_learn.sklearn_shims import set_random_state from sklearn import clone import numpy as np diff --git a/test/test_sklearn_compat.py b/test/test_sklearn_compat.py index 14cbed31..3ad69712 100644 --- a/test/test_sklearn_compat.py +++ b/test/test_sklearn_compat.py @@ -4,18 +4,9 @@ from sklearn.base import TransformerMixin from sklearn.pipeline import make_pipeline from sklearn.utils import check_random_state -import sklearn -from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.utils._testing import (assert_allclose_dense_sparse, - set_random_state, _get_args) - from sklearn.utils.estimator_checks import (_is_public_parameter - as is_public_parameter) -else: - from sklearn.utils.testing import (assert_allclose_dense_sparse, - set_random_state, _get_args) - from sklearn.utils.estimator_checks import is_public_parameter - +from metric_learn.sklearn_shims import (assert_allclose_dense_sparse, + set_random_state, _get_args, + is_public_parameter, get_scorer) from metric_learn import (Covariance, LFDA, LMNN, MLKR, NCA, ITML_Supervised, LSML_Supervised, MMC_Supervised, RCA_Supervised, SDML_Supervised, @@ -24,10 +15,6 @@ import numpy as np from sklearn.model_selection import (cross_val_score, cross_val_predict, train_test_split, KFold) -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.metrics._scorer import get_scorer -else: - from sklearn.metrics.scorer import get_scorer from test.test_utils import (metric_learners, ids_metric_learners, mock_preprocessor, tuples_learners, ids_tuples_learners, pairs_learners, diff --git a/test/test_triplets_classifiers.py b/test/test_triplets_classifiers.py index e8c42167..0f0bf7df 100644 --- a/test/test_triplets_classifiers.py +++ b/test/test_triplets_classifiers.py @@ -3,12 +3,7 @@ from sklearn.model_selection import train_test_split from test.test_utils import triplets_learners, ids_triplets_learners -import sklearn -from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.utils._testing import set_random_state -else: - from sklearn.utils.testing import set_random_state +from metric_learn.sklearn_shims import set_random_state from sklearn import clone import numpy as np diff --git a/test/test_utils.py b/test/test_utils.py index 0fc479c5..072b94c5 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -5,12 +5,7 @@ from numpy.testing import assert_array_equal, assert_equal from sklearn.model_selection import train_test_split from sklearn.utils import check_random_state, shuffle -import sklearn -from packaging import version -if version.parse(sklearn.__version__) >= version.parse('0.22.0'): - from sklearn.utils._testing import set_random_state -else: - from sklearn.utils.testing import set_random_state +from metric_learn.sklearn_shims import set_random_state from sklearn.base import clone from metric_learn._util import (check_input, make_context, preprocess_tuples, make_name, preprocess_points, From 4dac77b1e67b1c3be618f0340a399f35e6d44b5e Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Tue, 13 Apr 2021 13:38:06 +0200 Subject: [PATCH 09/10] remove typo added blankline --- test/test_quadruplets_classifiers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_quadruplets_classifiers.py b/test/test_quadruplets_classifiers.py index 57269cc3..a8319961 100644 --- a/test/test_quadruplets_classifiers.py +++ b/test/test_quadruplets_classifiers.py @@ -3,7 +3,6 @@ from sklearn.model_selection import train_test_split from test.test_utils import quadruplets_learners, ids_quadruplets_learners - from metric_learn.sklearn_shims import set_random_state from sklearn import clone import numpy as np From ee856ad1caa03be0990a129d9a5ac4bd9ee3c54f Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Thu, 15 Apr 2021 11:55:06 +0200 Subject: [PATCH 10/10] empty commit