diff --git a/openstef/app_settings.py b/openstef/app_settings.py new file mode 100644 index 000000000..f6c9d0b54 --- /dev/null +++ b/openstef/app_settings.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> +# +# SPDX-License-Identifier: MPL-2.0 + +from pydantic import Field +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class AppSettings(BaseSettings): + """Global app settings.""" + + # Logging settings. + log_level: str = Field("INFO", description="Log level used for logging statements.") + + model_config = SettingsConfigDict( + env_prefix="openstef_", env_file=".env", extra="ignore" + ) diff --git a/openstef/feature_engineering/data_preparation.py b/openstef/feature_engineering/data_preparation.py index 5556d83df..44dd9779a 100644 --- a/openstef/feature_engineering/data_preparation.py +++ b/openstef/feature_engineering/data_preparation.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017-2023 Alliander N.V. # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging from abc import ABC, abstractmethod from datetime import timedelta from typing import Optional @@ -20,6 +21,7 @@ ) from openstef.model.regressors.regressor import OpenstfRegressor from openstef.pipeline.utils import generate_forecast_datetime_range +from openstef.settings import Settings class AbstractDataPreparation(ABC): @@ -120,6 +122,11 @@ def prepare_train_data(self, data: pd.DataFrame) -> pd.DataFrame: def prepare_forecast_data( self, data: pd.DataFrame ) -> tuple[pd.DataFrame, pd.DataFrame]: + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) self.check_model() # Prep forecast input by selecting only the forecast datetime interval (this is much smaller than the input range) diff --git a/openstef/feature_engineering/general.py b/openstef/feature_engineering/general.py index 3547c905c..a1a86eca0 100644 --- a/openstef/feature_engineering/general.py +++ b/openstef/feature_engineering/general.py @@ -3,10 +3,14 @@ # SPDX-License-Identifier: MPL-2.0 """This modelu contains various helper functions.""" +import logging + import numpy as np import pandas as pd import structlog +from openstef.settings import Settings + def add_missing_feature_columns( input_data: pd.DataFrame, features: list[str] @@ -30,6 +34,11 @@ def add_missing_feature_columns( Input dataframe with missing columns filled with ``np.N=nan``. """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) if features is None: @@ -61,6 +70,11 @@ def remove_non_requested_feature_columns( Model input data with features. """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) if requested_features is None: diff --git a/openstef/feature_engineering/weather_features.py b/openstef/feature_engineering/weather_features.py index 74ee3d0a4..170bc1b5d 100644 --- a/openstef/feature_engineering/weather_features.py +++ b/openstef/feature_engineering/weather_features.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: MPL-2.0 """This module contains all wheather related functions used for feature engineering.""" +import logging from typing import Union import numpy as np @@ -12,7 +13,13 @@ from pvlib.location import Location from openstef.data_classes.prediction_job import PredictionJobDataClass +from openstef.settings import Settings +structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) +) logger = structlog.get_logger(__name__) diff --git a/openstef/metrics/reporter.py b/openstef/metrics/reporter.py index c28e9d1fc..d6341579f 100644 --- a/openstef/metrics/reporter.py +++ b/openstef/metrics/reporter.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MPL-2.0 """Defines reporter class.""" +import logging import os import warnings from dataclasses import dataclass @@ -16,6 +17,7 @@ from openstef.metrics import figure from openstef.metrics.metrics import bias, mae, nsme, r_mae, rmse from openstef.model.regressors.regressor import OpenstfRegressor +from openstef.settings import Settings @dataclass @@ -167,6 +169,11 @@ def get_metrics(y_pred: np.array, y_true: np.array) -> dict: def write_report_to_disk(report: Report, report_folder: str): """Write report to disk; e.g. for viewing report of latest models using grafana.""" # Initialize logger and serializer + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) if report_folder: # create path if does not exist diff --git a/openstef/model/confidence_interval_applicator.py b/openstef/model/confidence_interval_applicator.py index 31baf5ca9..278fa7697 100644 --- a/openstef/model/confidence_interval_applicator.py +++ b/openstef/model/confidence_interval_applicator.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging from datetime import datetime import numpy as np @@ -11,12 +12,18 @@ from openstef.data_classes.prediction_job import PredictionJobDataClass from openstef.exceptions import ModelWithoutStDev +from openstef.settings import Settings class ConfidenceIntervalApplicator: def __init__(self, model: RegressorMixin, forecast_input_data: pd.DataFrame): self.model = model self.forecast_input_data = forecast_input_data + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) self.logger = structlog.get_logger(self.__class__.__name__) def add_confidence_interval( diff --git a/openstef/model/model_creator.py b/openstef/model/model_creator.py index 9d1c6c68e..145acd0c7 100644 --- a/openstef/model/model_creator.py +++ b/openstef/model/model_creator.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging from typing import Union import structlog @@ -13,7 +14,13 @@ from openstef.model.regressors.regressor import OpenstfRegressor from openstef.model.regressors.xgb import XGBOpenstfRegressor from openstef.model.regressors.xgb_quantile import XGBQuantileOpenstfRegressor +from openstef.settings import Settings +structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) +) logger = structlog.get_logger(__name__) valid_model_kwargs = { diff --git a/openstef/model/serializer.py b/openstef/model/serializer.py index c092d46f0..6020f4587 100644 --- a/openstef/model/serializer.py +++ b/openstef/model/serializer.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MPL-2.0 import json +import logging import os import shutil from datetime import datetime @@ -20,10 +21,16 @@ from openstef.data_classes.model_specifications import ModelSpecificationDataClass from openstef.metrics.reporter import Report from openstef.model.regressors.regressor import OpenstfRegressor +from openstef.settings import Settings class MLflowSerializer: def __init__(self, mlflow_tracking_uri: str): + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) self.logger = structlog.get_logger(self.__class__.__name__) mlflow.set_tracking_uri(mlflow_tracking_uri) self.logger.debug(f"MLflow tracking uri at init= {mlflow_tracking_uri}") diff --git a/openstef/monitoring/teams.py b/openstef/monitoring/teams.py index 819a1c06f..36c80a546 100644 --- a/openstef/monitoring/teams.py +++ b/openstef/monitoring/teams.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging from typing import Union import pandas as pd @@ -8,6 +9,8 @@ import structlog from pymsteams import cardsection +from openstef.settings import Settings + def post_teams( msg: Union[str, dict], @@ -38,6 +41,11 @@ def post_teams( Note: This function is namespace-specific. """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) # If no url is passed, give warning and don't send teams message if url is None: diff --git a/openstef/pipeline/create_basecase_forecast.py b/openstef/pipeline/create_basecase_forecast.py index 8c11b31df..8a1bb7278 100644 --- a/openstef/pipeline/create_basecase_forecast.py +++ b/openstef/pipeline/create_basecase_forecast.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging from pathlib import Path import pandas as pd @@ -18,6 +19,7 @@ add_components_base_case_forecast, add_prediction_job_properties_to_forecast, ) +from openstef.settings import Settings from openstef.validation import validation MODEL_LOCATION = Path(".") @@ -42,6 +44,11 @@ def create_basecase_forecast_pipeline( NoRealisedLoadError: When no realised load for given datetime range. """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) logger.info("Preprocessing data for basecase forecast") diff --git a/openstef/pipeline/create_component_forecast.py b/openstef/pipeline/create_component_forecast.py index 48288eeda..afc4780fc 100644 --- a/openstef/pipeline/create_component_forecast.py +++ b/openstef/pipeline/create_component_forecast.py @@ -2,6 +2,8 @@ # # SPDX-License-Identifier: MPL-2.0 +import logging + import joblib import numpy as np import pandas as pd @@ -12,6 +14,7 @@ from openstef.data_classes.prediction_job import PredictionJobDataClass from openstef.enums import ForecastType from openstef.model.regressors.dazls import Dazls +from openstef.settings import Settings # Set the path for the Dazls stored model DAZLS_STORED = str( @@ -95,6 +98,11 @@ def create_components_forecast_pipeline( "algtype" """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) logger.info("Make components prediction", pid=pj["id"]) @@ -124,7 +132,6 @@ def create_components_forecast_pipeline( dazls_model.target_columns = joblib.load(DAZLS_STORED + "target.z") dazls_model.target_scaler = joblib.load(DAZLS_STORED + "target_scaler.z") - logger = structlog.get_logger(__name__) logger.info("DAZLS model loaded", dazls_model=str(dazls_model)) # Use the predict function of Dazls model diff --git a/openstef/pipeline/create_forecast.py b/openstef/pipeline/create_forecast.py index 107b99900..54951631d 100644 --- a/openstef/pipeline/create_forecast.py +++ b/openstef/pipeline/create_forecast.py @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging + import pandas as pd import structlog @@ -18,6 +20,7 @@ add_prediction_job_properties_to_forecast, sort_quantiles, ) +from openstef.settings import Settings from openstef.validation import validation @@ -85,6 +88,11 @@ def create_forecast_pipeline_core( InputDataOngoingZeroFlatlinerError: When all recent load measurements are zero. """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) fallback_strategy = "extreme_day" # this can later be expanded diff --git a/openstef/pipeline/optimize_hyperparameters.py b/openstef/pipeline/optimize_hyperparameters.py index 1fba405aa..8739fc365 100644 --- a/openstef/pipeline/optimize_hyperparameters.py +++ b/openstef/pipeline/optimize_hyperparameters.py @@ -1,8 +1,9 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging import os -from typing import Any, Union +from typing import Any import optuna import pandas as pd @@ -26,11 +27,17 @@ DEFAULT_TRAIN_HORIZONS_HOURS, train_model_pipeline_core, ) +from openstef.settings import Settings from openstef.validation import validation optuna.logging.enable_propagation() # Propagate logs to the root logger. optuna.logging.disable_default_handler() # Stop showing logs in sys.stderr. +structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) +) logger = structlog.get_logger(__name__) # See https://optuna.readthedocs.io/en/stable/reference/generated/optuna.study.Study.html#optuna.study.Study.optimize diff --git a/openstef/pipeline/train_model.py b/openstef/pipeline/train_model.py index bcaba505b..647637ad7 100644 --- a/openstef/pipeline/train_model.py +++ b/openstef/pipeline/train_model.py @@ -23,6 +23,7 @@ from openstef.model.serializer import MLflowSerializer from openstef.model.standard_deviation_generator import StandardDeviationGenerator from openstef.model_selection.model_selection import split_data_train_validation_test +from openstef.settings import Settings from openstef.validation import validation DEFAULT_TRAIN_HORIZONS_HOURS: list[float] = [0.25, 47.0] @@ -31,6 +32,11 @@ DEFAULT_EARLY_STOPPING_ROUNDS: int = 10 PENALTY_FACTOR_OLD_MODEL: float = 1.2 +structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) +) logger = structlog.get_logger(__name__) @@ -180,8 +186,6 @@ def train_model_pipeline_core( - Datasets (tuple[pd.DataFrmae, pd.DataFrame, pd.Dataframe): The train, validation and test sets """ - logger = structlog.get_logger(__name__) - # Call common pipeline ( model, diff --git a/openstef/postprocessing/postprocessing.py b/openstef/postprocessing/postprocessing.py index fe8d60602..36ad84b85 100644 --- a/openstef/postprocessing/postprocessing.py +++ b/openstef/postprocessing/postprocessing.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging from enum import Enum import numpy as np @@ -10,6 +11,7 @@ from openstef.data_classes.prediction_job import PredictionJobDataClass from openstef.enums import ForecastType from openstef.feature_engineering import weather_features +from openstef.settings import Settings # this is the default for "Lagerwey100" TURBINE_DATA = { @@ -219,6 +221,11 @@ def add_prediction_job_properties_to_forecast( Dataframe with added metadata. """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) logger.info("Postproces in preparation of storing") diff --git a/openstef/settings.py b/openstef/settings.py new file mode 100644 index 000000000..2955c100c --- /dev/null +++ b/openstef/settings.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> +# +# SPDX-License-Identifier: MPL-2.0 + +from functools import lru_cache + +from openstef.app_settings import AppSettings + + +@lru_cache +def _get_app_settings() -> AppSettings: + return AppSettings() + + +Settings = _get_app_settings() diff --git a/openstef/tasks/calculate_kpi.py b/openstef/tasks/calculate_kpi.py index cbcd476c2..8d58328a3 100644 --- a/openstef/tasks/calculate_kpi.py +++ b/openstef/tasks/calculate_kpi.py @@ -18,6 +18,8 @@ $ python calculate_kpi.py """ +import logging + # Import builtins from datetime import datetime, timedelta from pathlib import Path @@ -30,6 +32,7 @@ from openstef.enums import MLModelType from openstef.exceptions import NoPredictedLoadError, NoRealisedLoadError from openstef.metrics import metrics +from openstef.settings import Settings from openstef.tasks.utils.predictionjobloop import PredictionJobLoop from openstef.tasks.utils.taskcontext import TaskContext from openstef.validation import validation @@ -153,7 +156,12 @@ def calc_kpi_for_specific_pid( COMPLETENESS_REALISED_THRESHOLDS = 0.7 COMPLETENESS_PREDICTED_LOAD_THRESHOLD = 0.7 - log = structlog.get_logger(__name__) + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) + logger = structlog.get_logger(__name__) # If predicted is empty if len(predicted_load) == 0: @@ -187,9 +195,9 @@ def calc_kpi_for_specific_pid( # Raise exception in case of constant load if combined.load.nunique() == 1: - structlog.get_logger(__name__).warning( + logger.warning( "The load is constant! KPIs will still be calculated, but relative metrics" - " will be nan" + " will be nan." ) # Define output dictonary @@ -206,7 +214,7 @@ def calc_kpi_for_specific_pid( date = pd.to_datetime(end_time) # Calculate model metrics and add them to the output dictionary - log.info("Start calculating kpis") + logger.info("Start calculating kpis") for hor_cols in hor_list: t_ahead_h = hor_cols[0].split("_")[1] fc = combined[hor_cols[0]] # load predictions @@ -265,7 +273,7 @@ def calc_kpi_for_specific_pid( ) if completeness_realised < COMPLETENESS_REALISED_THRESHOLDS: - log.warning( + logger.warning( "Completeness realised load too low", prediction_id=pid, start_time=start_time, @@ -275,7 +283,7 @@ def calc_kpi_for_specific_pid( ) set_incomplete_kpi_to_nan(kpis, t_ahead_h) if completeness_predicted_load.any() < COMPLETENESS_PREDICTED_LOAD_THRESHOLD: - log.warning( + logger.warning( "Completeness predicted load of specific horizon too low", prediction_id=pid, horizon=t_ahead_h, diff --git a/openstef/tasks/create_components_forecast.py b/openstef/tasks/create_components_forecast.py index 473db87e6..5034fdfaa 100644 --- a/openstef/tasks/create_components_forecast.py +++ b/openstef/tasks/create_components_forecast.py @@ -21,6 +21,7 @@ $ python create_components_forecast.py """ +import logging from datetime import datetime, timedelta, timezone from pathlib import Path @@ -33,6 +34,7 @@ from openstef.pipeline.create_component_forecast import ( create_components_forecast_pipeline, ) +from openstef.settings import Settings from openstef.tasks.utils.predictionjobloop import PredictionJobLoop from openstef.tasks.utils.taskcontext import TaskContext @@ -56,6 +58,11 @@ def create_components_forecast_task( (less than 30 minutes in advance) """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) if pj["train_components"] == 0: context.logger.info( diff --git a/openstef/tasks/split_forecast.py b/openstef/tasks/split_forecast.py index b686f85f6..033313add 100644 --- a/openstef/tasks/split_forecast.py +++ b/openstef/tasks/split_forecast.py @@ -22,6 +22,7 @@ $ python split_forecast.py """ +import logging from datetime import datetime from pathlib import Path @@ -33,6 +34,7 @@ import openstef.monitoring.teams as monitoring from openstef.data_classes.prediction_job import PredictionJobDataClass from openstef.enums import MLModelType +from openstef.settings import Settings from openstef.tasks.utils.predictionjobloop import PredictionJobLoop from openstef.tasks.utils.taskcontext import TaskContext @@ -70,6 +72,11 @@ def split_forecast_task( Energy splitting coefficients. """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) logger.info("Start splitting energy", pid=pj["id"]) diff --git a/openstef/tasks/utils/taskcontext.py b/openstef/tasks/utils/taskcontext.py index 3df8c979f..2c0daeb68 100644 --- a/openstef/tasks/utils/taskcontext.py +++ b/openstef/tasks/utils/taskcontext.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging import traceback from typing import Callable @@ -9,6 +10,7 @@ from openstef.exceptions import PredictionJobException from openstef.monitoring.performance_meter import PerformanceMeter from openstef.monitoring.teams import post_teams +from openstef.settings import Settings class TaskContext: @@ -62,6 +64,11 @@ def __init__( self.database = database def __enter__(self): + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) self.logger = structlog.get_logger(__name__).bind(task=self.name) self.perf_meter = PerformanceMeter(self.logger) diff --git a/openstef/validation/validation.py b/openstef/validation/validation.py index 68b5220c1..d635e4ac1 100644 --- a/openstef/validation/validation.py +++ b/openstef/validation/validation.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project # noqa E501> # # SPDX-License-Identifier: MPL-2.0 +import logging import math from datetime import datetime, timedelta from typing import Union @@ -12,6 +13,7 @@ from openstef.exceptions import InputDataOngoingZeroFlatlinerError from openstef.model.regressors.regressor import OpenstfRegressor from openstef.preprocessing.preprocessing import replace_repeated_values_with_nan +from openstef.settings import Settings def validate( @@ -41,6 +43,11 @@ def validate( InputDataOngoingZeroFlatlinerError: If all recent load measurements are zero. """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) if not isinstance(data.index, pd.DatetimeIndex): @@ -84,6 +91,11 @@ def validate( def drop_target_na(data: pd.DataFrame) -> pd.DataFrame: + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) len_original = len(data) # Remove where load is NA, NaN features are preserved @@ -122,6 +134,11 @@ def is_data_sufficient( else: weights = model.feature_importance_dataframe + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) # Set output variable is_sufficient = True @@ -254,6 +271,11 @@ def calc_completeness_dataframe( Dataframe with fraction of completeness per column """ + structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger( + logging.getLevelName(Settings.log_level) + ) + ) logger = structlog.get_logger(__name__) if homogenise and isinstance(df.index, pd.DatetimeIndex) and len(df) > 0: diff --git a/requirements.txt b/requirements.txt index 86c35299a..665c4b29a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,7 @@ pandas~=2.2.0 plotly~=5.18 pvlib==0.9.4 pydantic~=2.4 +pydantic-settings~=2.2.1 pymsteams~=0.2.2 # TODO remove teams dependency scikit-learn~=1.3 scipy~=1.10 diff --git a/test/unit/feature_engineering/test_data_preparation.py b/test/unit/feature_engineering/test_data_preparation.py index 32cbdde44..3881b3559 100644 --- a/test/unit/feature_engineering/test_data_preparation.py +++ b/test/unit/feature_engineering/test_data_preparation.py @@ -4,13 +4,11 @@ from pathlib import Path from test.unit.utils.data import TestData from unittest import TestCase -from unittest.mock import patch, MagicMock +from unittest.mock import MagicMock, patch import numpy as np -from openstef.feature_engineering.data_preparation import ( - LegacyDataPreparation, -) +from openstef.feature_engineering.data_preparation import LegacyDataPreparation from openstef.model.serializer import MLflowSerializer diff --git a/test/unit/model/test_serializer.py b/test/unit/model/test_serializer.py index 5ca11fac2..e5d1e37fb 100644 --- a/test/unit/model/test_serializer.py +++ b/test/unit/model/test_serializer.py @@ -4,16 +4,16 @@ import glob import tempfile -import yaml -from pathlib import Path from datetime import datetime, timedelta from distutils.dir_util import copy_tree +from pathlib import Path from test.unit.utils.base import BaseTestCase from test.unit.utils.data import TestData from unittest.mock import MagicMock, PropertyMock, patch import numpy as np import pandas as pd +import yaml from openstef.data_classes.model_specifications import ModelSpecificationDataClass from openstef.metrics.reporter import Report diff --git a/test/unit/pipeline/test_create_component_forecast.py b/test/unit/pipeline/test_create_component_forecast.py index 23666311b..72800722c 100644 --- a/test/unit/pipeline/test_create_component_forecast.py +++ b/test/unit/pipeline/test_create_component_forecast.py @@ -2,24 +2,20 @@ # # SPDX-License-Identifier: MPL-2.0 from datetime import datetime, timedelta, timezone +from pathlib import Path from test.unit.utils.base import BaseTestCase from test.unit.utils.data import TestData -import joblib +import joblib import pandas as pd -from pathlib import Path - PROJECT_ROOT = Path(__file__).parent.parent.parent.parent.absolute() +from openstef.model.regressors.dazls import Dazls from openstef.pipeline.create_component_forecast import ( create_components_forecast_pipeline, ) -from openstef.model.regressors.dazls import ( - Dazls, -) - class TestComponentForecast(BaseTestCase): def setUp(self) -> None: diff --git a/test/unit/pipeline/test_optimize_hyperparameters.py b/test/unit/pipeline/test_optimize_hyperparameters.py index 0b9d057b9..55fc1f319 100644 --- a/test/unit/pipeline/test_optimize_hyperparameters.py +++ b/test/unit/pipeline/test_optimize_hyperparameters.py @@ -14,9 +14,9 @@ InputDataWrongColumnOrderError, ) from openstef.metrics.reporter import Report -from openstef.model_selection.model_selection import split_data_train_validation_test -from openstef.model.regressors.regressor import OpenstfRegressor from openstef.model.objective_creator import ObjectiveCreator +from openstef.model.regressors.regressor import OpenstfRegressor +from openstef.model_selection.model_selection import split_data_train_validation_test from openstef.pipeline.optimize_hyperparameters import ( optimize_hyperparameters_pipeline, optimize_hyperparameters_pipeline_core, diff --git a/test/unit/pipeline/test_pipeline_create_forecast.py b/test/unit/pipeline/test_pipeline_create_forecast.py index 7c5089574..d204f9b39 100644 --- a/test/unit/pipeline/test_pipeline_create_forecast.py +++ b/test/unit/pipeline/test_pipeline_create_forecast.py @@ -5,7 +5,8 @@ from pathlib import Path from test.unit.utils.base import BaseTestCase from test.unit.utils.data import TestData -from unittest.mock import patch, MagicMock +from unittest.mock import MagicMock, patch + from mlflow.exceptions import MlflowException from openstef.model.serializer import MLflowSerializer diff --git a/test/unit/pipeline/test_pipeline_train_model.py b/test/unit/pipeline/test_pipeline_train_model.py index 78427a95a..f4b5b7491 100644 --- a/test/unit/pipeline/test_pipeline_train_model.py +++ b/test/unit/pipeline/test_pipeline_train_model.py @@ -13,8 +13,8 @@ import pandas as pd import sklearn -from openstef.data_classes.split_function import SplitFuncDataClass from openstef.data_classes.data_prep import DataPrepDataClass +from openstef.data_classes.split_function import SplitFuncDataClass from openstef.enums import MLModelType from openstef.exceptions import ( InputDataInsufficientError, @@ -31,12 +31,12 @@ from openstef.model.regressors.custom_regressor import CustomOpenstfRegressor from openstef.model_selection.model_selection import split_data_train_validation_test from openstef.pipeline.train_model import ( + DEFAULT_TRAIN_HORIZONS_HOURS, train_model_pipeline, train_model_pipeline_core, train_pipeline_common, ) from openstef.validation import validation -from openstef.pipeline.train_model import DEFAULT_TRAIN_HORIZONS_HOURS class DummyObjective(RegressorObjective): diff --git a/test/unit/pipeline/test_train_predict_backtest.py b/test/unit/pipeline/test_train_predict_backtest.py index aea3de19c..19e36eb9c 100644 --- a/test/unit/pipeline/test_train_predict_backtest.py +++ b/test/unit/pipeline/test_train_predict_backtest.py @@ -4,8 +4,8 @@ from test.unit.utils.base import BaseTestCase from test.unit.utils.data import TestData -import pandas as pd import numpy as np +import pandas as pd from sklearn.model_selection import TimeSeriesSplit from openstef.data_classes.split_function import SplitFuncDataClass diff --git a/test/unit/tasks/test_create_forecast.py b/test/unit/tasks/test_create_forecast.py index 288b17c3f..f1683c5b4 100644 --- a/test/unit/tasks/test_create_forecast.py +++ b/test/unit/tasks/test_create_forecast.py @@ -7,9 +7,10 @@ from unittest.mock import MagicMock, patch import pytest + +import openstef.tasks.create_forecast as task from openstef.enums import PipelineType from openstef.exceptions import InputDataOngoingZeroFlatlinerError -import openstef.tasks.create_forecast as task from openstef.model.serializer import MLflowSerializer from openstef.tasks.create_forecast import create_forecast_task diff --git a/test/unit/tasks/test_train_model.py b/test/unit/tasks/test_train_model.py index d6735c8ca..e9cf9fb50 100644 --- a/test/unit/tasks/test_train_model.py +++ b/test/unit/tasks/test_train_model.py @@ -5,13 +5,12 @@ from test.unit.utils.data import TestData from unittest import TestCase from unittest.mock import MagicMock, patch -import pytest - -from openstef.exceptions import InputDataOngoingZeroFlatlinerError import pandas as pd +import pytest from openstef.enums import PipelineType +from openstef.exceptions import InputDataOngoingZeroFlatlinerError from openstef.tasks.train_model import main as task_main from openstef.tasks.train_model import train_model_task diff --git a/test/unit/validation/test_validation.py b/test/unit/validation/test_validation.py index 505d4ae84..540994869 100644 --- a/test/unit/validation/test_validation.py +++ b/test/unit/validation/test_validation.py @@ -8,9 +8,8 @@ import numpy as np import pytest -from openstef.validation import validation - from openstef.exceptions import InputDataOngoingZeroFlatlinerError +from openstef.validation import validation class TestDataValidation(BaseTestCase): diff --git a/test/unit/validation/test_validation_calc_completeness.py b/test/unit/validation/test_validation_calc_completeness.py index bb31388a2..a0559c021 100644 --- a/test/unit/validation/test_validation_calc_completeness.py +++ b/test/unit/validation/test_validation_calc_completeness.py @@ -2,17 +2,17 @@ # # SPDX-License-Identifier: MPL-2.0 -import numpy as np -import pandas as pd - -from openstef.validation.validation import calc_completeness_features - from pathlib import Path from test.unit.utils.base import BaseTestCase from test.unit.utils.data import TestData -from unittest.mock import patch, MagicMock +from unittest.mock import MagicMock, patch + +import numpy as np +import pandas as pd from mlflow.exceptions import MlflowException + from openstef.model.serializer import MLflowSerializer +from openstef.validation.validation import calc_completeness_features class CalcCompletenessTest(BaseTestCase): diff --git a/test/unit/validation/test_validation_detect_ongoing_zero_flatliner.py b/test/unit/validation/test_validation_detect_ongoing_zero_flatliner.py index 42f9a5dae..e997e3bda 100644 --- a/test/unit/validation/test_validation_detect_ongoing_zero_flatliner.py +++ b/test/unit/validation/test_validation_detect_ongoing_zero_flatliner.py @@ -3,10 +3,11 @@ # SPDX-License-Identifier: MPL-2.0 from datetime import datetime, timedelta -from freezegun import freeze_time from test.unit.utils.base import BaseTestCase + import numpy as np import pandas as pd +from freezegun import freeze_time from openstef.validation.validation import detect_ongoing_zero_flatliner