From bc5497526e658a651dc1acd6c5606470d46ca9c3 Mon Sep 17 00:00:00 2001 From: Vladimir Iglovikov Date: Tue, 23 Jul 2024 18:36:47 -0700 Subject: [PATCH] Show in check message how to disable checks (#1855) --- albumentations/check_version.py | 10 +++-- tests/test_check_version.py | 4 +- tests/test_domain_adaptation.py | 78 +++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 tests/test_domain_adaptation.py diff --git a/albumentations/check_version.py b/albumentations/check_version.py index 873e47a1d..44ba535ae 100644 --- a/albumentations/check_version.py +++ b/albumentations/check_version.py @@ -59,8 +59,12 @@ def check_for_updates() -> None: latest_version = parse_version(data) if latest_version and latest_version != current_version: logger.info( - f"A new version of Albumentations is available: {latest_version} (you have {current_version})." - " Upgrade using: pip install --upgrade albumentations", + f"A new version of Albumentations is available: {latest_version} (you have {current_version})." # noqa: S608 + " Upgrade using: pip install -U albumentations." + " To disable automatic update checks, set the environment variable NO_ALBUMENTATIONS_UPDATE to 1.", ) except Exception as e: # General exception catch to ensure silent failure # noqa: BLE001 - logger.info(f"Failed to check for updates due to an unexpected error: {e}") + logger.info( + f"Failed to check for updates due to an unexpected error: {e}. " # noqa: S608 + "To disable automatic update checks, set the environment variable NO_ALBUMENTATIONS_UPDATE to 1.", + ) diff --git a/tests/test_check_version.py b/tests/test_check_version.py index 49e770f66..fb864dd94 100644 --- a/tests/test_check_version.py +++ b/tests/test_check_version.py @@ -44,7 +44,7 @@ def test_check_for_updates_new_version_available(mocker): log_mock = mocker.patch('logging.Logger.info') check_for_updates() log_mock.assert_called_once_with( - "A new version of Albumentations is available: 1.0.2 (you have 1.0.1). Upgrade using: pip install --upgrade albumentations" + 'A new version of Albumentations is available: 1.0.2 (you have 1.0.1). Upgrade using: pip install -U albumentations. To disable automatic update checks, set the environment variable NO_ALBUMENTATIONS_UPDATE to 1.' ) def test_check_for_updates_no_update_needed(mocker): @@ -58,7 +58,7 @@ def test_check_for_updates_exception_handling(mocker): mocker.patch('albumentations.check_version.fetch_version_info', side_effect=Exception("Error")) log_mock = mocker.patch('logging.Logger.info') check_for_updates() - log_mock.assert_called_once_with("Failed to check for updates due to an unexpected error: Error") + log_mock.assert_called_once_with("Failed to check for updates due to an unexpected error: Error. To disable automatic update checks, set the environment variable NO_ALBUMENTATIONS_UPDATE to 1.") def test_parse_version_correct_input(): json_input = '{"info": {"version": "1.0.2"}}' diff --git a/tests/test_domain_adaptation.py b/tests/test_domain_adaptation.py new file mode 100644 index 000000000..5df2f50ef --- /dev/null +++ b/tests/test_domain_adaptation.py @@ -0,0 +1,78 @@ +import pytest +import numpy as np +import cv2 +from albumentations.augmentations.domain_adaptation_functional import MinMaxScaler, StandardScaler, PCA + + + +@pytest.mark.parametrize("feature_range, data, expected", [ + ((0.0, 1.0), np.array([[1, 2], [3, 4], [5, 6]]), np.array([[0.0, 0.0], [0.5, 0.5], [1.0, 1.0]])), + ((-1.0, 1.0), np.array([[1, 2], [3, 4], [5, 6]]), np.array([[-1.0, -1.0], [0.0, 0.0], [1.0, 1.0]])), + ((0.0, 1.0), np.array([[1, 1], [1, 1], [1, 1]]), np.array([[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]])), # edge case: all values are the same +]) +def test_minmax_scaler(feature_range, data, expected): + scaler = MinMaxScaler(feature_range) + result = scaler.fit_transform(data) + np.testing.assert_almost_equal(result, expected) + +@pytest.mark.parametrize("feature_range, data, data_scaled, expected", [ + ((0.0, 1.0), np.array([[1, 2], [3, 4], [5, 6]]), np.array([[0.0, 0.0], [0.5, 0.5], [1.0, 1.0]]), np.array([[1, 2], [3, 4], [5, 6]])), + ((-1.0, 1.0), np.array([[1, 2], [3, 4], [5, 6]]), np.array([[-1.0, -1.0], [0.0, 0.0], [1.0, 1.0]]), np.array([[1, 2], [3, 4], [5, 6]])), +]) +def test_minmax_inverse_transform(feature_range, data, data_scaled, expected): + scaler = MinMaxScaler(feature_range) + scaler.fit(data) + result = scaler.inverse_transform(data_scaled) + np.testing.assert_almost_equal(result, expected) + +@pytest.mark.parametrize("data, expected", [ + (np.array([[1, 2], [3, 4], [5, 6]]), np.array([[-1.22474487, -1.22474487], [0.0, 0.0], [1.22474487, 1.22474487]])), + (np.array([[1, 1], [1, 1], [1, 1]]), np.array([[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]])), # edge case: all values are the same +]) +def test_standard_scaler(data, expected): + scaler = StandardScaler() + result = scaler.fit_transform(data) + np.testing.assert_almost_equal(result, expected) + +@pytest.mark.parametrize("data, data_scaled, expected", [ + (np.array([[1, 2], [3, 4], [5, 6]]), np.array([[-1.22474487, -1.22474487], [0.0, 0.0], [1.22474487, 1.22474487]]), np.array([[1, 2], [3, 4], [5, 6]])), +]) +def test_standard_inverse_transform(data, data_scaled, expected): + scaler = StandardScaler() + scaler.fit(data) + result = scaler.inverse_transform(data_scaled) + np.testing.assert_almost_equal(result, expected) + + +@pytest.mark.parametrize("n_components, data, expected_shape", [ + (1, np.array([[2.5, 2.4], [0.5, 0.7], [2.2, 2.9], [1.9, 2.2], [3.1, 3.0], + [2.3, 2.7], [2.0, 1.6], [1.0, 1.1], [1.5, 1.6], [1.1, 0.9]]), (10, 1)), + (2, np.array([[2.5, 2.4], [0.5, 0.7], [2.2, 2.9], [1.9, 2.2], [3.1, 3.0], + [2.3, 2.7], [2.0, 1.6], [1.0, 1.1], [1.5, 1.6], [1.1, 0.9]]), (10, 2)), +]) +def test_pca_transform(n_components, data, expected_shape): + pca = PCA(n_components) + transformed = pca.fit_transform(data) + assert transformed.shape == expected_shape + assert np.all(np.isfinite(transformed)), "Transformed data contains non-finite values" + + +@pytest.mark.parametrize("n_components, data, expected_transformed, expected_inverse", + [(1, np.array([[2.5, 2.4], [0.5, 0.7], [2.2, 2.9], [1.9, 2.2], [3.1, 3.0], + [2.3, 2.7], [2.0, 1.6], [1.0, 1.1], [1.5, 1.6], [1.1, 0.9]]), + np.array([[0.8279701862010879], [-1.7775803252804292], [0.9921974944148886], [0.27421041597539936], [1.6758014186445398], [0.9129491031588081], [-0.09910943749844434], [-1.1445721637986601], [-0.4380461367624502], [-1.2238205550547405]]), + np.array([[2.3712589640000026, 2.518706008322169], [0.6050255837456271, 0.6031608863381424], [2.4825842875499986, 2.639442419978468], [1.995879946589024, 2.111593644953067], [2.9459812029146377, 3.142013433918504], [2.428863911241362, 2.5811806942407656], [1.7428163487767303, 1.837136856988131], [1.0341249774652423, 1.068534975444947], [1.5130601765607719, 1.58795783010856], [0.9804046011566055, 1.0102732497072444]]) + + ), + (2, np.array([[2.5, 2.4], [0.5, 0.7], [2.2, 2.9], [1.9, 2.2], [3.1, 3.0], + [2.3, 2.7], [2.0, 1.6], [1.0, 1.1], [1.5, 1.6], [1.1, 0.9]]), + np.array([[0.8279701862010879, 0.17511530704691558], [-1.7775803252804292, -0.14285722654428068], [0.9921974944148886, -0.3843749888804125], [0.27421041597539936, -0.13041720657412711], [1.6758014186445398, 0.20949846125675342], [0.9129491031588081, -0.17528244362036988], [-0.09910943749844434, 0.34982469809712086], [-1.1445721637986601, -0.04641725818328135], [-0.4380461367624502, -0.017764629675083188], [-1.2238205550547405, 0.16267528707676182]]), + np.array([[2.5, 2.4], [0.4999999999999998, 0.7], [2.2, 2.9], [1.9, 2.2], [3.1000000000000005, 3.0], [2.3, 2.7], [2.0, 1.6], [0.9999999999999999, 1.1], [1.5, 1.6], [1.0999999999999999, 0.9000000000000001]]), + ), +]) +def test_pca_inverse_transform(n_components, data, expected_transformed, expected_inverse): + pca = PCA(n_components) + transformed = pca.fit_transform(data) + inversed = pca.inverse_transform(transformed) + assert np.array_equal(transformed, expected_transformed) + assert np.array_equal(inversed, expected_inverse)