From 3f771509e2c15da4f6d3bf1b63522dc7543bb52c Mon Sep 17 00:00:00 2001 From: LouisCarpentier42 Date: Mon, 6 Oct 2025 12:07:32 +0200 Subject: [PATCH 1/2] fix: Updated dependencies of foundation models Signed-off-by: LouisCarpentier42 --- README.md | 2 +- docs/additional_information/changelog.rst | 2 + docs/getting_started/installation.rst | 10 ++-- .../_BaseNeuralForecastingDetector.py | 5 -- .../_KShapeAnomalyDetector.py | 6 --- .../_MatrixProfileDetector.py | 23 --------- .../anomaly_detection/_SpectralResidual.py | 6 --- .../baselines/_SquaredDifference.py | 16 ------ dtaianomaly/windowing/_sliding_window.py | 6 --- pyproject.toml | 5 +- tests/anomaly_detection/test_Chronos.py | 51 ++++++++++++++++--- .../test_HybridKNearestNeighbors.py | 16 ++++++ .../test_SpectralResidual.py | 9 ++++ tests/anomaly_detection/test_TimeMoE.py | 44 ++++++++++++++++ tests/workflow/test_workflow_from_config.py | 33 ++++++++++-- 15 files changed, 154 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 8eaa9ae..90db1be 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ for more information. ## Installation -The preferred way to install `dtaianomaly` is via PyPi. See the [documentation](https://dtaianomaly.readthedocs.io/en/stable/index.html) +The preferred way to install `dtaianomaly` is via PyPi. See the [documentation](https://dtaianomaly.readthedocs.io/en/stable/getting_started/installation.html) for more options. ``` pip install dtaianomaly diff --git a/docs/additional_information/changelog.rst b/docs/additional_information/changelog.rst index 19d7fb3..fd02f2d 100644 --- a/docs/additional_information/changelog.rst +++ b/docs/additional_information/changelog.rst @@ -42,12 +42,14 @@ Changed - Replaced dependency on ``tslearn>=0.6.3`` by ``sktime[clustering]``, which includes the ``tslearn`` dependency. Before, ``tslearn`` was only used for ``KShapeAnomalyDetector`` to do the clustering. This capability is also offered by ``sktime`` through a direct interface to ``tslearn``. + - Added dependency ``tslearn>=0.6.3`` as it is not installed for Python >= 3.12 via ``sktime``. Fixed ^^^^^ - np.datetime64 are now also valid values in the ``utils.is_valid_array_like``. This was especially necessary for time indexes in a dataset. +- Added missing tests and removed temporary code to test the doctests. [0.4.2] - 2025-07-03 -------------------- diff --git a/docs/getting_started/installation.rst b/docs/getting_started/installation.rst index 3688e13..a9de574 100644 --- a/docs/getting_started/installation.rst +++ b/docs/getting_started/installation.rst @@ -29,10 +29,12 @@ Currently, following subsets are available: - ``docs``: Dependencies for generating the documentation. - ``notebooks``: Dependencies for using jupyter notebooks. - ``lint``: Dependencies for linting the code. -- ``chronos``: Install autogluon.timeseries, necessary for running Chronos. -- ``moment``: Install momentfm, necessary for running Chronos. **Warning:** Not included when - installing ``dtaianomaly[all]`` due to dependency conflicts! -- ``time_moe``: Install transformers==4.40.1, necessary for running MOMENT. +- ``chronos``: Install autogluon.timeseries, necessary for running Chronos. **Warning:** Not + included when installing ``dtaianomaly[all]``! +- ``moment``: Install momentfm, necessary for running MOMENT. **Warning:** Not included when + installing ``dtaianomaly[all]``! +- ``time_moe``: Install transformers==4.40.1, necessary for running Time-MoE. **Warning:** Not + included when installing ``dtaianomaly[all]``! - ``in_time_ad``: Dependencies for running the demonstrator. To install version ``X.Y.Z``, use the following command: diff --git a/dtaianomaly/anomaly_detection/_BaseNeuralForecastingDetector.py b/dtaianomaly/anomaly_detection/_BaseNeuralForecastingDetector.py index 67e4b9d..fde3d0d 100644 --- a/dtaianomaly/anomaly_detection/_BaseNeuralForecastingDetector.py +++ b/dtaianomaly/anomaly_detection/_BaseNeuralForecastingDetector.py @@ -198,11 +198,6 @@ def _evaluate_batch(self, batch: list[torch.Tensor]) -> torch.Tensor: torch.abs(forecast - future), dim=tuple(range(1, forecast.ndim)) ) - # Raise an error if invalid metric is given - raise ValueError( - f"Unknown error_metric '{self.error_metric}'. Valid options are ['mean-squared-error', 'mean-absolute-error']" - ) - def _evaluate(self, data_loader: torch.utils.data.DataLoader) -> np.array: decision_scores = super()._evaluate(data_loader) return np.concatenate( diff --git a/dtaianomaly/anomaly_detection/_KShapeAnomalyDetector.py b/dtaianomaly/anomaly_detection/_KShapeAnomalyDetector.py index 68971b6..c56c9e2 100644 --- a/dtaianomaly/anomaly_detection/_KShapeAnomalyDetector.py +++ b/dtaianomaly/anomaly_detection/_KShapeAnomalyDetector.py @@ -203,9 +203,3 @@ def _ncc_c(x: np.array, y: np.array) -> np.array: cc = np.fft.ifft(np.fft.fft(x, fft_size) * np.conj(np.fft.fft(y, fft_size))) cc = np.concatenate((cc[-(x.shape[0] - 1) :], cc[: x.shape[0]])) return np.real(cc) / den - - -if __name__ == "__main__": - import doctest - - doctest.testmod() diff --git a/dtaianomaly/anomaly_detection/_MatrixProfileDetector.py b/dtaianomaly/anomaly_detection/_MatrixProfileDetector.py index ae23447..f4e8c6f 100644 --- a/dtaianomaly/anomaly_detection/_MatrixProfileDetector.py +++ b/dtaianomaly/anomaly_detection/_MatrixProfileDetector.py @@ -186,26 +186,3 @@ def is_fitted(self) -> bool: for attr in self.__annotations__ if attr.endswith("_") and attr != "X_reference_" ) - - def requires_fitting(self) -> bool: - """ - Check whether this object requires fitting. - - Check whether any of the attributes of this object ends with an - underscore ('_'), which indicates that the attribute is set when - the object is fitted. Note that this method does not check whether - the object is fitted, i.e., whether the attributes have been set. - - Returns - ------- - bool - True if and only if this object has attributes that end with '_'. - """ - if self.novelty: - return super().requires_fitting() - else: - return any( - attr.endswith("_") - for attr in self._all_annotations() - if attr != "X_reference_" - ) diff --git a/dtaianomaly/anomaly_detection/_SpectralResidual.py b/dtaianomaly/anomaly_detection/_SpectralResidual.py index d1e1934..ea5ab92 100644 --- a/dtaianomaly/anomaly_detection/_SpectralResidual.py +++ b/dtaianomaly/anomaly_detection/_SpectralResidual.py @@ -112,9 +112,3 @@ def _decision_function(self, X: np.ndarray) -> np.array: saliency_map = np.sqrt(inverse_fourier.real**2 + inverse_fourier.imag**2) return saliency_map - - -if __name__ == "__main__": - import doctest - - doctest.testmod() diff --git a/dtaianomaly/anomaly_detection/baselines/_SquaredDifference.py b/dtaianomaly/anomaly_detection/baselines/_SquaredDifference.py index 22d5874..78453ee 100644 --- a/dtaianomaly/anomaly_detection/baselines/_SquaredDifference.py +++ b/dtaianomaly/anomaly_detection/baselines/_SquaredDifference.py @@ -54,19 +54,3 @@ def _decision_function(self, X: np.ndarray) -> np.array: if self.square_errors: decision_scores = np.square(decision_scores) return decision_scores - - -def main(): - from dtaianomaly.data import demonstration_time_series - from dtaianomaly.visualization import plot_anomaly_scores - - x, y = demonstration_time_series() - x = x.reshape(-1, 1) - - baseline = SquaredDifference().fit(x) - y_pred = baseline.decision_function(x) - plot_anomaly_scores(x, y, y_pred, figsize=(20, 5)).show() - - -if __name__ == "__main__": - main() diff --git a/dtaianomaly/windowing/_sliding_window.py b/dtaianomaly/windowing/_sliding_window.py index 96fd3c8..fd04bc9 100644 --- a/dtaianomaly/windowing/_sliding_window.py +++ b/dtaianomaly/windowing/_sliding_window.py @@ -59,9 +59,3 @@ def sliding_window(X: np.ndarray, window_size: int, stride: int) -> np.ndarray: ] windows.append(X[-window_size:].ravel()) return np.array(windows) - - -if __name__ == "__main__": - import doctest - - doctest.testmod() diff --git a/pyproject.toml b/pyproject.toml index a29aa38..495796e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,8 @@ dependencies = [ "matplotlib>=3.7", "statsmodels>=0.6", "pyod>=2.0.0", - "sktime[clustering]", + "tslearn>=0.6.3", + "sktime", "toml", "torch>=1.8.0", ] @@ -73,8 +74,6 @@ all = [ # All the optional dependencies "isort", 'tqdm', "sphinxcontrib-bibtex", - "autogluon.timeseries>=1.3.1", - "transformers==4.40.1", 'tqdm', "streamlit", "plotly" diff --git a/tests/anomaly_detection/test_Chronos.py b/tests/anomaly_detection/test_Chronos.py index 58664ff..feea754 100644 --- a/tests/anomaly_detection/test_Chronos.py +++ b/tests/anomaly_detection/test_Chronos.py @@ -8,72 +8,114 @@ from dtaianomaly.anomaly_detection._Chronos import MODEL_PATHS +def setup(): + # create dummy parent package and submodule + autogluon = types.ModuleType("autogluon") + timeseries = types.ModuleType("autogluon.timeseries") + autogluon.timeseries = timeseries + + # register both in sys.modules + sys.modules["autogluon"] = autogluon + sys.modules["autogluon.timeseries"] = timeseries + + +def cleanup(): + del sys.modules["autogluon"] + del sys.modules["autogluon.timeseries"] + + class TestChronos: def test_supervision(self): + setup() detector = Chronos(1) assert detector.supervision == Supervision.UNSUPERVISED + cleanup() def test_str(self): + setup() assert str(Chronos(5)) == "Chronos(window_size=5)" assert str(Chronos("fft")) == "Chronos(window_size='fft')" assert str(Chronos(15, "large")) == "Chronos(window_size=15,model_path='large')" assert str(Chronos(25, batch_size=3)) == "Chronos(window_size=25,batch_size=3)" + cleanup() @pytest.mark.parametrize("model_path", MODEL_PATHS) def test_model_path_valid(self, model_path): + setup() detector = Chronos(window_size="fft", model_path=model_path) assert detector.model_path == model_path + cleanup() @pytest.mark.parametrize("model_path", [0, True, None, ["a", "list"]]) def test_model_path_invalid_type(self, model_path): + setup() with pytest.raises(TypeError): Chronos(window_size="fft", model_path=model_path) + cleanup() @pytest.mark.parametrize("model_path", ["invalid"]) def test_model_path_invalid_value(self, model_path): + setup() with pytest.raises(ValueError): Chronos(window_size="fft", model_path=model_path) + cleanup() @pytest.mark.parametrize("batch_size", [8, 16, 32]) def test_batch_size_valid(self, batch_size): + setup() detector = Chronos(window_size="fft", batch_size=batch_size) assert detector.batch_size == batch_size + cleanup() @pytest.mark.parametrize("batch_size", ["8", 8.0]) def test_batch_size_invalid_type(self, batch_size): + setup() with pytest.raises(TypeError): Chronos(window_size="fft", batch_size=batch_size) + cleanup() @pytest.mark.parametrize("batch_size", [0, -8]) def test_batch_size_invalid_value(self, batch_size): + setup() with pytest.raises(ValueError): Chronos(window_size="fft", batch_size=batch_size) + cleanup() @pytest.mark.parametrize("forecast_horizon", [32, 16, 8]) def test_forecast_horizon_valid(self, forecast_horizon): + setup() detector = Chronos(window_size=16, forecast_horizon=forecast_horizon) assert detector.forecast_horizon == forecast_horizon + cleanup() @pytest.mark.parametrize("forecast_horizon", ["32", 16.0, True]) def test_forecast_horizon_invalid_type(self, forecast_horizon): + setup() with pytest.raises(TypeError): Chronos(window_size=16, forecast_horizon=forecast_horizon) + cleanup() @pytest.mark.parametrize("forecast_horizon", [0, -1, -16]) def test_forecast_horizon_invalid_value(self, forecast_horizon): + setup() with pytest.raises(ValueError): Chronos(window_size=16, forecast_horizon=forecast_horizon) + cleanup() @pytest.mark.parametrize("do_fine_tuning", [True, False]) def test_do_fine_tuning_valid(self, do_fine_tuning): + setup() detector = Chronos(window_size="fft", do_fine_tuning=do_fine_tuning) assert detector.do_fine_tuning == do_fine_tuning + cleanup() @pytest.mark.parametrize("do_fine_tuning", [5, 1.0, "invalid"]) def test_do_fine_tuning_invalid_type(self, do_fine_tuning): + setup() with pytest.raises(TypeError): Chronos(window_size="fft", do_fine_tuning=do_fine_tuning) + cleanup() def test_raises_if_autogluon_missing(self, monkeypatch): # simulate ImportError when trying to import autogluon.timeseries @@ -93,11 +135,6 @@ def fake_import(name, *args, **kwargs): Chronos(15) def test_no_error_if_autogluon_available(self, monkeypatch): - # simulate a dummy autogluon.timeseries module - sys.modules["autogluon.timeseries"] = types.ModuleType("autogluon.timeseries") - - # should NOT raise + setup() Chronos(15) # just runs, no exception - - # cleanup (avoid side effects on other tests) - del sys.modules["autogluon.timeseries"] + cleanup() diff --git a/tests/anomaly_detection/test_HybridKNearestNeighbors.py b/tests/anomaly_detection/test_HybridKNearestNeighbors.py index b581139..6dc4ae5 100644 --- a/tests/anomaly_detection/test_HybridKNearestNeighbors.py +++ b/tests/anomaly_detection/test_HybridKNearestNeighbors.py @@ -124,3 +124,19 @@ def test_seed(self, univariate_time_series): ) assert np.array_equal(y_pred1, y_pred2) + + @pytest.mark.parametrize( + "length,max_samples,expected", + [ + (1000, 50, 50), + (1000, 250, 250), + (1000, 0.5, 500), + (1000, 0.1, 100), + (1000, "auto", 125), + ], + ) + def test_create_subsets(self, length, max_samples, expected): + detector = HybridKNearestNeighbors(1, max_samples=max_samples, n_estimators=8) + subsets = detector._create_subsets(np.empty(shape=(length, 1))) + for subset in subsets: + assert subset.shape[0] == expected diff --git a/tests/anomaly_detection/test_SpectralResidual.py b/tests/anomaly_detection/test_SpectralResidual.py index c82fd13..10e5bf6 100644 --- a/tests/anomaly_detection/test_SpectralResidual.py +++ b/tests/anomaly_detection/test_SpectralResidual.py @@ -49,3 +49,12 @@ def test_epsilon_invalid_type(self, epsilon): def test_epsilon_invalid_value(self, epsilon): with pytest.raises(ValueError): SpectralResidual(3, epsilon) + + def test_multivariate(self, univariate_time_series, multivariate_time_series): + detector = SpectralResidual(16) + with pytest.raises(ValueError): + detector.fit(multivariate_time_series) + + detector.fit(univariate_time_series) + with pytest.raises(ValueError): + detector.decision_function(multivariate_time_series) diff --git a/tests/anomaly_detection/test_TimeMoE.py b/tests/anomaly_detection/test_TimeMoE.py index f211eca..6afb08e 100644 --- a/tests/anomaly_detection/test_TimeMoE.py +++ b/tests/anomaly_detection/test_TimeMoE.py @@ -9,13 +9,24 @@ from dtaianomaly.anomaly_detection._TimeMoE import MODEL_PATHS +def setup(): + sys.modules["transformers"] = types.ModuleType("transformers") + + +def cleanup(): + del sys.modules["transformers"] + + class TestTimeMoE: def test_supervision(self): + setup() detector = TimeMoE(1) assert detector.supervision == Supervision.UNSUPERVISED + cleanup() def test_str(self): + setup() assert str(TimeMoE(5)) == "TimeMoE(window_size=5)" assert str(TimeMoE("fft")) == "TimeMoE(window_size='fft')" assert ( @@ -23,76 +34,105 @@ def test_str(self): == "TimeMoE(window_size=15,model_path='TimeMoE-200M')" ) assert str(TimeMoE(25, batch_size=3)) == "TimeMoE(window_size=25,batch_size=3)" + cleanup() @pytest.mark.parametrize("model_path", MODEL_PATHS) def test_model_path_valid(self, model_path): + setup() detector = TimeMoE(window_size="fft", model_path=model_path) assert detector.model_path == model_path + cleanup() @pytest.mark.parametrize("model_path", [0, True, None, ["a", "list"]]) def test_model_path_invalid_type(self, model_path): + setup() with pytest.raises(TypeError): TimeMoE(window_size="fft", model_path=model_path) + cleanup() @pytest.mark.parametrize("model_path", ["invalid"]) def test_model_path_invalid_value(self, model_path): + setup() with pytest.raises(ValueError): TimeMoE(window_size="fft", model_path=model_path) + cleanup() @pytest.mark.parametrize("batch_size", [8, 16, 32]) def test_batch_size_valid(self, batch_size): + setup() detector = TimeMoE(window_size="fft", batch_size=batch_size) assert detector.batch_size == batch_size + cleanup() @pytest.mark.parametrize("batch_size", ["8", 8.0]) def test_batch_size_invalid_type(self, batch_size): + setup() with pytest.raises(TypeError): TimeMoE(window_size="fft", batch_size=batch_size) + cleanup() @pytest.mark.parametrize("batch_size", [0, -8]) def test_batch_size_invalid_value(self, batch_size): + setup() with pytest.raises(ValueError): TimeMoE(window_size="fft", batch_size=batch_size) + cleanup() @pytest.mark.parametrize("prediction_length", [32, 16, 8]) def test_prediction_length_valid(self, prediction_length): + setup() detector = TimeMoE(window_size=16, prediction_length=prediction_length) assert detector.prediction_length == prediction_length + cleanup() @pytest.mark.parametrize("prediction_length", ["32", 16.0, True]) def test_prediction_length_invalid_type(self, prediction_length): + setup() with pytest.raises(TypeError): TimeMoE(window_size=16, prediction_length=prediction_length) + cleanup() @pytest.mark.parametrize("prediction_length", [0, -1, -16]) def test_prediction_length_invalid_value(self, prediction_length): + setup() with pytest.raises(ValueError): TimeMoE(window_size=16, prediction_length=prediction_length) + cleanup() @pytest.mark.parametrize("normalize_sequences", [True, False]) def test_do_fine_tuning_valid(self, normalize_sequences): + setup() detector = TimeMoE(window_size="fft", normalize_sequences=normalize_sequences) assert detector.normalize_sequences == normalize_sequences + cleanup() @pytest.mark.parametrize("normalize_sequences", [5, 1.0, "invalid"]) def test_do_fine_tuning_invalid_type(self, normalize_sequences): + setup() with pytest.raises(TypeError): TimeMoE(window_size="fft", normalize_sequences=normalize_sequences) + cleanup() @pytest.mark.parametrize("min_std", [1e-5, 1e-3, 0.1, 1.0, 2.0]) def test_min_std_valid(self, min_std): + setup() detector = TimeMoE(3, min_std=min_std) assert detector.min_std == min_std + cleanup() @pytest.mark.parametrize("min_std", ["0", True, None, ["a", "list"]]) def test_min_std_invalid_type(self, min_std): + setup() with pytest.raises(TypeError): TimeMoE(3, min_std=min_std) + cleanup() @pytest.mark.parametrize("min_std", [-1e-16]) def test_min_std_invalid_value(self, min_std): + setup() with pytest.raises(ValueError): TimeMoE(3, min_std=min_std) + cleanup() def test_raises_if_transformers_missing(self, monkeypatch): real_import = builtins.__import__ @@ -118,6 +158,7 @@ def test_no_error_if_transformers_available(self, monkeypatch): class TestGetBatchStarts: def test_simple(self): + setup() time_moe = TimeMoE(window_size=2, batch_size=4, prediction_length=1) time_moe.window_size_ = 2 # Only for testing purposed! starts = time_moe._get_batch_starts(11) @@ -126,6 +167,7 @@ def test_simple(self): assert np.array_equal(starts[0], [0, 1, 2, 3]) assert np.array_equal(starts[1], [4, 5, 6, 7]) assert np.array_equal(starts[2], [8]) + cleanup() @pytest.mark.parametrize( "batch_size,window_size,length_time_series,prediction_length", @@ -137,6 +179,7 @@ def test_simple(self): ], ) def test(self, batch_size, window_size, length_time_series, prediction_length): + setup() time_moe = TimeMoE( window_size=window_size, batch_size=batch_size, @@ -157,3 +200,4 @@ def test(self, batch_size, window_size, length_time_series, prediction_length): assert ( total_nb_samples == length_time_series - window_size - prediction_length + 1 ) + cleanup() diff --git a/tests/workflow/test_workflow_from_config.py b/tests/workflow/test_workflow_from_config.py index 8d7d2c2..9f34adf 100644 --- a/tests/workflow/test_workflow_from_config.py +++ b/tests/workflow/test_workflow_from_config.py @@ -249,11 +249,40 @@ def test_name_not_in_config_not_required(self): class TestInterpretEntry: + @staticmethod + def setup(cls, mp): + if cls == anomaly_detection.MOMENT: + mp.setattr(sys, "version_info", (3, 11, 7, "final", 0)) + sys.modules["momentfm"] = types.ModuleType("momentfm") + + if cls == anomaly_detection.Chronos: + autogluon = types.ModuleType("autogluon") + timeseries = types.ModuleType("autogluon.timeseries") + autogluon.timeseries = timeseries + sys.modules["autogluon"] = autogluon + sys.modules["autogluon.timeseries"] = timeseries + + if cls == anomaly_detection.TimeMoE: + sys.modules["transformers"] = types.ModuleType("transformers") + + @staticmethod + def cleanup(cls): + if cls == anomaly_detection.MOMENT: + del sys.modules["momentfm"] + + if cls == anomaly_detection.Chronos: + del sys.modules["autogluon"] + del sys.modules["autogluon.timeseries"] + + if cls == anomaly_detection.TimeMoE: + del sys.modules["transformers"] + @pytest.mark.parametrize( "infer_entry", [infer_minimal_entry, infer_extensive_entry] ) @pytest.mark.parametrize("cls", ALL_CLASSES) def test(self, cls, infer_entry, monkeypatch): + self.setup(cls, monkeypatch) if cls == anomaly_detection.MOMENT: monkeypatch.setattr(sys, "version_info", (3, 11, 7, "final", 0)) sys.modules["momentfm"] = types.ModuleType("momentfm") @@ -278,9 +307,7 @@ def test(self, cls, infer_entry, monkeypatch): pytest.fail( f"Object should either have '{key}' as attribute, or have 'kwargs' as attribute, which in turn has '{key}' as attribute!" ) - - if cls == anomaly_detection.MOMENT: - del sys.modules["momentfm"] + self.cleanup(cls) @pytest.mark.parametrize("cls", ALL_CLASSES) def test_invalid_parameter(self, cls): From cdca3927cd1dc6a9e1d14cfdd89216a9f46a1c24 Mon Sep 17 00:00:00 2001 From: LouisCarpentier42 Date: Mon, 6 Oct 2025 12:23:35 +0200 Subject: [PATCH 2/2] fix: Updated failing doctests Signed-off-by: LouisCarpentier42 --- docs/additional_information/changelog.rst | 2 +- dtaianomaly/anomaly_detection/_Chronos.py | 10 +++++----- .../anomaly_detection/_HybridKNearestNeighbors.py | 2 +- .../anomaly_detection/_KShapeAnomalyDetector.py | 2 +- dtaianomaly/anomaly_detection/_TimeMoE.py | 10 +++++----- .../anomaly_detection/baselines/_AlwaysAnomalous.py | 2 +- .../anomaly_detection/baselines/_AlwaysNormal.py | 2 +- .../baselines/_MovingWindowVariance.py | 2 +- .../anomaly_detection/baselines/_RandomDetector.py | 2 +- .../anomaly_detection/baselines/_SquaredDifference.py | 2 +- dtaianomaly/pipeline/_Pipeline.py | 2 +- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/additional_information/changelog.rst b/docs/additional_information/changelog.rst index fd02f2d..6551c9a 100644 --- a/docs/additional_information/changelog.rst +++ b/docs/additional_information/changelog.rst @@ -42,7 +42,7 @@ Changed - Replaced dependency on ``tslearn>=0.6.3`` by ``sktime[clustering]``, which includes the ``tslearn`` dependency. Before, ``tslearn`` was only used for ``KShapeAnomalyDetector`` to do the clustering. This capability is also offered by ``sktime`` through a direct interface to ``tslearn``. - - Added dependency ``tslearn>=0.6.3`` as it is not installed for Python >= 3.12 via ``sktime``. +- Added dependency ``tslearn>=0.6.3`` as it is not installed for Python >= 3.12 via ``sktime``. Fixed ^^^^^ diff --git a/dtaianomaly/anomaly_detection/_Chronos.py b/dtaianomaly/anomaly_detection/_Chronos.py index 5faa0ab..245d2c1 100644 --- a/dtaianomaly/anomaly_detection/_Chronos.py +++ b/dtaianomaly/anomaly_detection/_Chronos.py @@ -94,11 +94,11 @@ class Chronos(BaseDetector): Examples -------- - >>> from dtaianomaly.anomaly_detection import Chronos - >>> from dtaianomaly.data import demonstration_time_series - >>> x, y = demonstration_time_series() - >>> chronos = Chronos(10).fit(x) - >>> chronos.decision_function(x) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> from dtaianomaly.anomaly_detection import Chronos # doctest: +SKIP + >>> from dtaianomaly.data import demonstration_time_series # doctest: +SKIP + >>> x, y = demonstration_time_series() # doctest: +SKIP + >>> chronos = Chronos(10).fit(x) # doctest: +SKIP + >>> chronos.decision_function(x) # doctest: +SKIP array([0.00027719, 0.00027719, 0.00027719, ..., 0.00058781, 0.02628242, 0.00010728]...) """ diff --git a/dtaianomaly/anomaly_detection/_HybridKNearestNeighbors.py b/dtaianomaly/anomaly_detection/_HybridKNearestNeighbors.py index 0489a47..1fc426d 100644 --- a/dtaianomaly/anomaly_detection/_HybridKNearestNeighbors.py +++ b/dtaianomaly/anomaly_detection/_HybridKNearestNeighbors.py @@ -121,7 +121,7 @@ class HybridKNearestNeighbors(BaseDetector): >>> hybrid_knn = HybridKNearestNeighbors(64, seed=0).fit(x) >>> hybrid_knn.decision_function(x) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE array([0.12284644, 0.38202247, 0.43220974, ..., 0.83470662, 0.81722846, - 0.85243446]) + 0.85243446]...) """ window_size: WINDOW_SIZE_TYPE diff --git a/dtaianomaly/anomaly_detection/_KShapeAnomalyDetector.py b/dtaianomaly/anomaly_detection/_KShapeAnomalyDetector.py index c56c9e2..7063600 100644 --- a/dtaianomaly/anomaly_detection/_KShapeAnomalyDetector.py +++ b/dtaianomaly/anomaly_detection/_KShapeAnomalyDetector.py @@ -76,7 +76,7 @@ class KShapeAnomalyDetector(BaseDetector): >>> kshape = KShapeAnomalyDetector(window_size=50).fit(x) >>> kshape.decision_function(x) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE array([7.07106781, 7.07106781, 7.07106781, ..., 7.07106781, 7.07106781, - 7.07106781]) + 7.07106781]...) """ window_size: WINDOW_SIZE_TYPE diff --git a/dtaianomaly/anomaly_detection/_TimeMoE.py b/dtaianomaly/anomaly_detection/_TimeMoE.py index d35b46c..e913046 100644 --- a/dtaianomaly/anomaly_detection/_TimeMoE.py +++ b/dtaianomaly/anomaly_detection/_TimeMoE.py @@ -74,11 +74,11 @@ class TimeMoE(BaseDetector): Examples -------- - >>> from dtaianomaly.anomaly_detection import TimeMoE - >>> from dtaianomaly.data import demonstration_time_series - >>> x, y = demonstration_time_series() - >>> time_moe = TimeMoE(10).fit(x) - >>> time_moe.decision_function(x) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE +SKIP + >>> from dtaianomaly.anomaly_detection import TimeMoE # doctest: +SKIP + >>> from dtaianomaly.data import demonstration_time_series # doctest: +SKIP + >>> x, y = demonstration_time_series() # doctest: +SKIP + >>> time_moe = TimeMoE(10).fit(x) # doctest: +SKIP + >>> time_moe.decision_function(x) # doctest: +SKIP array([6.34949149e-05, 6.34949149e-05, 6.34949149e-05, ..., 6.34949149e-05, 6.34949149e-05, 6.34949149e-05]...) """ diff --git a/dtaianomaly/anomaly_detection/baselines/_AlwaysAnomalous.py b/dtaianomaly/anomaly_detection/baselines/_AlwaysAnomalous.py index ce4fedc..2f2ccae 100644 --- a/dtaianomaly/anomaly_detection/baselines/_AlwaysAnomalous.py +++ b/dtaianomaly/anomaly_detection/baselines/_AlwaysAnomalous.py @@ -20,7 +20,7 @@ class AlwaysAnomalous(BaseDetector): >>> x, y = demonstration_time_series() >>> baseline = AlwaysAnomalous().fit(x) >>> baseline.decision_function(x) - array([1., 1., 1., ..., 1., 1., 1.]) + array([1., 1., 1., ..., 1., 1., 1.]...) """ def __init__(self): diff --git a/dtaianomaly/anomaly_detection/baselines/_AlwaysNormal.py b/dtaianomaly/anomaly_detection/baselines/_AlwaysNormal.py index b5e941c..369d86d 100644 --- a/dtaianomaly/anomaly_detection/baselines/_AlwaysNormal.py +++ b/dtaianomaly/anomaly_detection/baselines/_AlwaysNormal.py @@ -20,7 +20,7 @@ class AlwaysNormal(BaseDetector): >>> x, y = demonstration_time_series() >>> baseline = AlwaysNormal().fit(x) >>> baseline.decision_function(x) - array([0., 0., 0., ..., 0., 0., 0.]) + array([0., 0., 0., ..., 0., 0., 0.]...) """ def __init__(self): diff --git a/dtaianomaly/anomaly_detection/baselines/_MovingWindowVariance.py b/dtaianomaly/anomaly_detection/baselines/_MovingWindowVariance.py index 29f81ab..73b9235 100644 --- a/dtaianomaly/anomaly_detection/baselines/_MovingWindowVariance.py +++ b/dtaianomaly/anomaly_detection/baselines/_MovingWindowVariance.py @@ -41,7 +41,7 @@ class MovingWindowVariance(BaseDetector): >>> baseline = MovingWindowVariance(16).fit(x) >>> baseline.decision_function(x) array([0.06820711, 0.07130246, 0.07286874, ..., 0.01125165, 0.00984333, - 0.00986772]) + 0.00986772]...) """ window_size: WINDOW_SIZE_TYPE diff --git a/dtaianomaly/anomaly_detection/baselines/_RandomDetector.py b/dtaianomaly/anomaly_detection/baselines/_RandomDetector.py index 28ac5a4..fc2acc8 100644 --- a/dtaianomaly/anomaly_detection/baselines/_RandomDetector.py +++ b/dtaianomaly/anomaly_detection/baselines/_RandomDetector.py @@ -26,7 +26,7 @@ class RandomDetector(BaseDetector): >>> baseline = RandomDetector(seed=0).fit(x) >>> baseline.decision_function(x) array([0.63696169, 0.26978671, 0.04097352, ..., 0.70724404, 0.90315986, - 0.8944909 ]) + 0.8944909 ]...) """ seed: int | None diff --git a/dtaianomaly/anomaly_detection/baselines/_SquaredDifference.py b/dtaianomaly/anomaly_detection/baselines/_SquaredDifference.py index 78453ee..a6fb087 100644 --- a/dtaianomaly/anomaly_detection/baselines/_SquaredDifference.py +++ b/dtaianomaly/anomaly_detection/baselines/_SquaredDifference.py @@ -30,7 +30,7 @@ class SquaredDifference(BaseDetector): >>> baseline = SquaredDifference().fit(x) >>> baseline.decision_function(x) array([0.00779346, 0.00779346, 0.00260361, ..., 0.00286662, 0.05578398, - 0.02683475]) + 0.02683475]...) """ square_errors: bool diff --git a/dtaianomaly/pipeline/_Pipeline.py b/dtaianomaly/pipeline/_Pipeline.py index 5c5a59c..0146847 100644 --- a/dtaianomaly/pipeline/_Pipeline.py +++ b/dtaianomaly/pipeline/_Pipeline.py @@ -35,7 +35,7 @@ class Pipeline(BaseDetector): >>> pipeline = Pipeline(StandardScaler(), IsolationForest(16)) >>> pipeline.fit(X).decision_function(X) array([-0.01080726, -0.01053199, -0.00883758, ..., -0.05298726, - -0.05898066, -0.05713733]) + -0.05898066, -0.05713733]...) """ preprocessor: Preprocessor