From 8cd84163fb09b43eefc863af1cc56988f6f87b2f Mon Sep 17 00:00:00 2001 From: polochinoc Date: Tue, 23 Jul 2024 23:21:26 +0200 Subject: [PATCH 1/2] Removed redundant jsonify calls, along some pretty useless stuff just to keep this project alive... TODO: finally migrate it to FastAPI --- app.py | 71 ++++++++++++++++++++++++++++------------------ src/api/schemas.py | 5 ++-- src/api/utils.py | 8 +++--- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/app.py b/app.py index 36f7b72..9e70d0b 100644 --- a/app.py +++ b/app.py @@ -7,9 +7,11 @@ """ from __future__ import annotations +from typing import Any + import matplotlib.pyplot as plt from flasgger import Swagger, swag_from -from flask import Flask, jsonify, request, Response, send_file +from flask import Flask, request, Response, send_file import src.api.swagger.parameters_specs as param from src.api.schemas import ( @@ -27,7 +29,7 @@ standard_deviation_specs, ) from src.api.swagger.year import below_normal_specs, above_normal_specs -from src.api.utils import parse_args, manage_time_mode_errors +from src.api.utils import parse_args, return_time_mode_error_or_fill_response_dict from src.config import Config from src.core.models.all_rainfall import AllRainfall from src.core.utils.enums.time_modes import TimeMode @@ -54,9 +56,11 @@ def average_rainfall() -> Response: param.season, ) - to_return = manage_time_mode_errors({}, params[0], params[3], params[4]) - if isinstance(to_return, Response): - return to_return + to_return: dict[str, Any] = {} + if error := return_time_mode_error_or_fill_response_dict( + to_return, params[0], params[3], params[4] + ): + return error to_return.update( { @@ -68,7 +72,7 @@ def average_rainfall() -> Response: } ) - return jsonify(RainfallSchema().dump(to_return)) + return RainfallSchema().dump(to_return) @app.route(f"{base_path}/rainfall/normal") @@ -78,9 +82,11 @@ def normal_rainfall() -> Response: request.args, param.time_mode, param.begin_year, param.month, param.season ) - to_return = manage_time_mode_errors({}, params[0], params[2], params[3]) - if isinstance(to_return, Response): - return to_return + to_return: dict[str, Any] = {} + if error := return_time_mode_error_or_fill_response_dict( + to_return, params[0], params[2], params[3] + ): + return error to_return.update( { @@ -92,7 +98,7 @@ def normal_rainfall() -> Response: } ) - return jsonify(RainfallSchema().dump(to_return)) + return RainfallSchema().dump(to_return) @app.route(f"{base_path}/rainfall/relative_distance_to_normal") @@ -108,9 +114,11 @@ def rainfall_relative_distance_to_normal() -> Response: param.season, ) - to_return = manage_time_mode_errors({}, params[0], params[4], params[5]) - if isinstance(to_return, Response): - return to_return + to_return: dict[str, Any] = {} + if error := return_time_mode_error_or_fill_response_dict( + to_return, params[0], params[4], params[5] + ): + return error to_return.update( { @@ -123,7 +131,7 @@ def rainfall_relative_distance_to_normal() -> Response: } ) - return jsonify(RelativeDistanceToRainfallNormalSchema().dump(to_return)) + return RelativeDistanceToRainfallNormalSchema().dump(to_return) @app.route(f"{base_path}/rainfall/standard_deviation") @@ -138,9 +146,11 @@ def rainfall_standard_deviation() -> Response: param.season, ) - to_return = manage_time_mode_errors({}, params[0], params[3], params[4]) - if isinstance(to_return, Response): - return to_return + to_return: dict[str, Any] = {} + if error := return_time_mode_error_or_fill_response_dict( + to_return, params[0], params[3], params[4] + ): + return error to_return.update( { @@ -152,7 +162,7 @@ def rainfall_standard_deviation() -> Response: } ) - return jsonify(RainfallSchema().dump(to_return)) + return RainfallSchema().dump(to_return) @app.route(f"{base_path}/year/below_normal") @@ -168,9 +178,11 @@ def years_below_normal() -> Response: param.season, ) - to_return = manage_time_mode_errors({}, params[0], params[4], params[5]) - if isinstance(to_return, Response): - return to_return + to_return: dict[str, Any] = {} + if error := return_time_mode_error_or_fill_response_dict( + to_return, params[0], params[4], params[5] + ): + return error to_return.update( { @@ -183,7 +195,7 @@ def years_below_normal() -> Response: } ) - return jsonify(YearsAboveOrBelowNormalSchema().dump(to_return)) + return YearsAboveOrBelowNormalSchema().dump(to_return) @app.route(f"{base_path}/year/above_normal") @@ -199,9 +211,11 @@ def years_above_normal() -> Response: param.season, ) - to_return = manage_time_mode_errors({}, params[0], params[4], params[5]) - if isinstance(to_return, Response): - return to_return + to_return: dict[str, Any] = {} + if error := return_time_mode_error_or_fill_response_dict( + to_return, params[0], params[4], params[5] + ): + return error to_return.update( { @@ -214,7 +228,7 @@ def years_above_normal() -> Response: } ) - return jsonify(YearsAboveOrBelowNormalSchema().dump(to_return)) + return YearsAboveOrBelowNormalSchema().dump(to_return) @app.route(f"{base_path}/csv/minimal_csv") @@ -224,8 +238,9 @@ def minimal_csv() -> Response: request.args, param.time_mode, param.month, param.season, param.file_name ) - error = manage_time_mode_errors({}, params[0], params[1], params[2]) - if isinstance(error, Response): + if error := return_time_mode_error_or_fill_response_dict( + {}, params[0], params[1], params[2] + ): return error all_rainfall.export_as_csv(*params) diff --git a/src/api/schemas.py b/src/api/schemas.py index a41cad0..e607f67 100644 --- a/src/api/schemas.py +++ b/src/api/schemas.py @@ -37,12 +37,13 @@ class RainfallSchema(BaseRainfallSchema): value: float = fields.Float() -class RelativeDistanceToRainfallNormalSchema(RainfallSchema): +class RelativeDistanceToRainfallNormalSchema(BaseRainfallSchema): """ Schema for depicting a relative distance to rainfall normal. """ normal_year: int = fields.Int(load_default=param.normal_year["default"]) + value: float = fields.Float() class YearsAboveOrBelowNormalSchema(BaseRainfallSchema): @@ -51,7 +52,7 @@ class YearsAboveOrBelowNormalSchema(BaseRainfallSchema): """ normal_year: int = fields.Int(load_default=param.normal_year["default"]) - value: float = fields.Int() + value: int = fields.Int() class ApiError(Schema): diff --git a/src/api/utils.py b/src/api/utils.py index 83f8d12..3aefbde 100644 --- a/src/api/utils.py +++ b/src/api/utils.py @@ -49,12 +49,12 @@ def swagger_type_to_python_type(swagger_type: str) -> type | None: return python_type -def manage_time_mode_errors( +def return_time_mode_error_or_fill_response_dict( response_dict: dict, time_mode: str, month: str | None = None, season: str | None = None, -) -> Response | dict: +) -> Response | None: """ Manage errors related to time mode issues. If time mode is set to monthly and month is None. @@ -67,7 +67,7 @@ def manage_time_mode_errors( :param season: A string corresponding to the season name. Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL']. Set if time_mode is 'SEASONAL' (optional) - :return: Either a Flask Response if there is an error or the updated dictionary. + :return: Either a Flask Response if there is an error or None. """ if time_mode == TimeMode.MONTHLY.name: if month is None: @@ -81,4 +81,4 @@ def manage_time_mode_errors( response_dict["season"] = Season[season] - return response_dict + return None From dd724ed65fa3a52c128e4a9abd730f60cc308224 Mon Sep 17 00:00:00 2001 From: polochinoc Date: Mon, 12 Aug 2024 23:09:15 +0200 Subject: [PATCH 2/2] Make begin_year argument always compulsory, use list of Rainfall models directly instead of using dicts & remove useless type hints --- app.py | 8 +- src/core/models/all_rainfall.py | 33 ++++-- src/core/models/yearly_rainfall.py | 12 +- .../utils/functions/dataframe_operations.py | 12 +- src/core/utils/functions/metrics.py | 2 +- src/core/utils/functions/plotting.py | 38 +++--- tst/core/models/test_all_rainfall.py | 62 +++++----- tst/core/models/test_yearly_rainfall.py | 110 +++++++++--------- tst/core/utils/enums/test_labels.py | 2 +- tst/core/utils/enums/test_months.py | 50 ++++---- tst/core/utils/enums/test_seasons.py | 18 +-- tst/core/utils/enums/test_time_modes.py | 2 +- .../functions/test_dataframe_operations.py | 43 ++++--- tst/core/utils/functions/test_metrics.py | 31 +++-- tst/core/utils/functions/test_plotting.py | 29 ++--- tst/test_config.py | 20 ++-- 16 files changed, 245 insertions(+), 227 deletions(-) diff --git a/app.py b/app.py index 9e70d0b..dcf8a97 100644 --- a/app.py +++ b/app.py @@ -65,7 +65,13 @@ def average_rainfall() -> Response: to_return.update( { "name": "average rainfall (mm)", - "value": all_rainfall.get_average_rainfall(*params), + "value": all_rainfall.get_average_rainfall( + params[0], + begin_year=params[1], + end_year=params[2], + month=params[3], + season=params[4], + ), "begin_year": params[1], "end_year": params[2] or all_rainfall.get_last_year(), "time_mode": TimeMode[params[0]], diff --git a/src/core/models/all_rainfall.py b/src/core/models/all_rainfall.py index 942a451..5f20651 100644 --- a/src/core/models/all_rainfall.py +++ b/src/core/models/all_rainfall.py @@ -121,7 +121,8 @@ def export_as_csv( def get_average_rainfall( self, time_mode: str, - begin_year: int | None = None, + *, + begin_year: int, end_year: int | None = None, month: str | None = None, season: str | None = None, @@ -131,7 +132,7 @@ def get_average_rainfall( :param time_mode: A string setting the time period ['YEARLY', 'MONTHLY', 'SEASONAL'] :param begin_year: An integer representing the year - to start getting our rainfall values (optional). + to start getting our rainfall values. :param end_year: An integer representing the year to end getting our rainfall values (optional). :param month: A string corresponding to the month name. @@ -322,29 +323,35 @@ def get_last_year(self) -> int: def bar_rainfall_averages( self, - monthly=True, - begin_year: int | None = None, + begin_year: int, end_year: int | None = None, + monthly=True, ) -> list: """ Plots a bar graphic displaying average rainfall for each month or each season. - :param monthly: If True, plots monthly rainfall averages. - If False, plots seasonal rainfall averages. Defaults to True (optional). :param begin_year: An integer representing the year - to start getting our rainfall values. (optional). + to start getting our rainfall values. :param end_year: An integer representing the year to end getting our rainfall values (optional). + :param monthly: If True, plots monthly rainfall averages. + If False, plots seasonal rainfall averages. Defaults to True (optional). :return: A list of the Rainfall averages for each month or season. """ label = f"Average rainfall (mm) between {begin_year or self.starting_year} and {self.get_last_year()}" if monthly: return plotting.bar_monthly_rainfall_averages( - self.monthly_rainfalls, label, begin_year, end_year + list(self.monthly_rainfalls.values()), + begin_year=begin_year, + end_year=end_year, + label=label, ) return plotting.bar_seasonal_rainfall_averages( - self.seasonal_rainfalls, label, begin_year, end_year + list(self.seasonal_rainfalls.values()), + begin_year=begin_year, + end_year=end_year, + label=label, ) def bar_rainfall_linreg_slopes(self, monthly=True) -> list: @@ -356,9 +363,13 @@ def bar_rainfall_linreg_slopes(self, monthly=True) -> list: :return: A list of the Rainfall LinReg slopes for each month or season. """ if monthly: - return plotting.bar_monthly_rainfall_linreg_slopes(self.monthly_rainfalls) + return plotting.bar_monthly_rainfall_linreg_slopes( + list(self.monthly_rainfalls.values()) + ) - return plotting.bar_seasonal_rainfall_linreg_slopes(self.seasonal_rainfalls) + return plotting.bar_seasonal_rainfall_linreg_slopes( + list(self.seasonal_rainfalls.values()) + ) def get_entity_for_time_mode( self, time_mode: str, month: str | None = None, season: str | None = None diff --git a/src/core/models/yearly_rainfall.py b/src/core/models/yearly_rainfall.py index fef8936..d448968 100644 --- a/src/core/models/yearly_rainfall.py +++ b/src/core/models/yearly_rainfall.py @@ -80,20 +80,22 @@ def load_rainfall( ) def get_yearly_rainfall( - self, begin_year: int | None = None, end_year: int | None = None + self, begin_year: int, end_year: int | None = None ) -> pd.DataFrame: """ Retrieves Yearly Rainfall within a specific year range. :param begin_year: An integer representing the year - to start getting our rainfall values (optional). + to start getting our rainfall values. :param end_year: An integer representing the year to end getting our rainfall values (optional). :return: A pandas DataFrame displaying rainfall data (in mm) for instance month according to year. """ - return df_opr.get_rainfall_within_year_interval(self.data, begin_year, end_year) + return df_opr.get_rainfall_within_year_interval( + self.data, begin_year=begin_year, end_year=end_year + ) def export_as_csv(self, path: str | Path | None = None) -> str | None: """ @@ -107,13 +109,13 @@ def export_as_csv(self, path: str | Path | None = None) -> str | None: return self.data.to_csv(path_or_buf=path, index=False) def get_average_yearly_rainfall( - self, begin_year: int | None = None, end_year: int | None = None + self, begin_year: int, end_year: int | None = None ) -> float: """ Computes Rainfall average for a specific year range. :param begin_year: An integer representing the year - to start getting our rainfall values (optional). + to start getting our rainfall values. :param end_year: An integer representing the year to end getting our rainfall values (optional). :return: A float representing the average Rainfall. diff --git a/src/core/utils/functions/dataframe_operations.py b/src/core/utils/functions/dataframe_operations.py index afcdb05..f3272c2 100644 --- a/src/core/utils/functions/dataframe_operations.py +++ b/src/core/utils/functions/dataframe_operations.py @@ -11,7 +11,8 @@ def get_rainfall_within_year_interval( yearly_rainfall: pd.DataFrame, - begin_year: int | None = None, + *, + begin_year: int, end_year: int | None = None, ) -> pd.DataFrame: """ @@ -19,21 +20,16 @@ def get_rainfall_within_year_interval( :param yearly_rainfall: A pandas DataFrame displaying rainfall data (in mm) according to year. :param begin_year: An integer representing the year - to start getting our rainfall values (optional). + to start getting our rainfall values. :param end_year: An integer representing the year to end getting our rainfall values (optional). :return: A pandas DataFrame displaying rainfall data (in mm) according to year. """ - if begin_year is not None: - yearly_rainfall = yearly_rainfall[ - yearly_rainfall[Label.YEAR.value] >= begin_year - ] - if end_year is not None: yearly_rainfall = yearly_rainfall[yearly_rainfall[Label.YEAR.value] <= end_year] - return yearly_rainfall + return yearly_rainfall[yearly_rainfall[Label.YEAR.value] >= begin_year] def remove_column(yearly_rainfall: pd.DataFrame, label: Label) -> bool: diff --git a/src/core/utils/functions/metrics.py b/src/core/utils/functions/metrics.py index 555f5e2..609c47a 100644 --- a/src/core/utils/functions/metrics.py +++ b/src/core/utils/functions/metrics.py @@ -74,7 +74,7 @@ def get_normal(yearly_rainfall: pd.DataFrame, begin_year, round_precision=2) -> return get_average_rainfall( df_opr.get_rainfall_within_year_interval( - yearly_rainfall, begin_year, begin_year + 29 + yearly_rainfall, begin_year=begin_year, end_year=begin_year + 29 ), round_precision, ) diff --git a/src/core/utils/functions/plotting.py b/src/core/utils/functions/plotting.py index 97511a9..6b8cff5 100644 --- a/src/core/utils/functions/plotting.py +++ b/src/core/utils/functions/plotting.py @@ -86,26 +86,27 @@ def bar_column_according_to_year(yearly_rainfall: pd.DataFrame, label: Label) -> def bar_monthly_rainfall_averages( - monthly_rainfalls: dict, - label="Average rainfall (mm)", - begin_year: int | None = None, + monthly_rainfalls: list, + *, + begin_year: int, end_year: int | None = None, + label="Average rainfall (mm)", ) -> list: """ Plots a bar graphic displaying average rainfall for each month passed through the dict. :param monthly_rainfalls: A list of instances of MonthlyRainfall. To be purposeful, all instances should have the same time frame in years. - :param label: A string to use as a label for bar graphic. (optional) - Defaults to "Average rainfall (mm)". :param begin_year: An integer representing the year - to start getting our rainfall values (optional). + to start getting our rainfall values. :param end_year: An integer representing the year to end getting our rainfall values (optional). + :param label: A string to use as a label for bar graphic. (optional) + Defaults to "Average rainfall (mm)". :return: A list of the Rainfall averages for each month. """ month_labels, averages = [], [] - for monthly_rainfall in monthly_rainfalls.values(): + for monthly_rainfall in monthly_rainfalls: month_labels.append(monthly_rainfall.month.name[:3]) averages.append( monthly_rainfall.get_average_yearly_rainfall( @@ -119,7 +120,7 @@ def bar_monthly_rainfall_averages( return averages -def bar_monthly_rainfall_linreg_slopes(monthly_rainfalls: dict) -> list: +def bar_monthly_rainfall_linreg_slopes(monthly_rainfalls: list) -> list: """ Plots a bar graphic displaying linear regression slope for each month passed through the dict. @@ -128,7 +129,7 @@ def bar_monthly_rainfall_linreg_slopes(monthly_rainfalls: dict) -> list: :return: A list of the Rainfall LinReg slopes for each month. """ month_labels, slopes = [], [] - for monthly_rainfall in monthly_rainfalls.values(): + for monthly_rainfall in monthly_rainfalls: month_labels.append(monthly_rainfall.month.name[:3]) slopes.append(monthly_rainfall.add_linear_regression()[1]) @@ -139,26 +140,27 @@ def bar_monthly_rainfall_linreg_slopes(monthly_rainfalls: dict) -> list: def bar_seasonal_rainfall_averages( - seasonal_rainfalls: dict, - label="Average rainfall (mm)", - begin_year: int | None = None, + seasonal_rainfalls: list, + *, + begin_year: int, end_year: int | None = None, + label="Average rainfall (mm)", ) -> list: """ Plots a bar graphic displaying average rainfall for each season passed through the dict. :param seasonal_rainfalls: A list of instances of SeasonalRainfall. To be purposeful, all instances should have the same time frame in years. - :param label: A string to use as a label for bar graphic. (optional) - Defaults to "Average rainfall (mm)". :param begin_year: An integer representing the year - to start getting our rainfall values (optional). + to start getting our rainfall values. :param end_year: An integer representing the year to end getting our rainfall values (optional). + :param label: A string to use as a label for bar graphic. (optional) + Defaults to "Average rainfall (mm)". :return: A list of the Rainfall averages for each season. """ season_labels, averages = [], [] - for seasonal_rainfall in seasonal_rainfalls.values(): + for seasonal_rainfall in seasonal_rainfalls: season_labels.append(seasonal_rainfall.season.name) averages.append( seasonal_rainfall.get_average_yearly_rainfall( @@ -172,7 +174,7 @@ def bar_seasonal_rainfall_averages( return averages -def bar_seasonal_rainfall_linreg_slopes(seasonal_rainfalls: dict) -> list: +def bar_seasonal_rainfall_linreg_slopes(seasonal_rainfalls: list) -> list: """ Plots a bar graphic displaying linear regression slope for each season passed through the dict. @@ -181,7 +183,7 @@ def bar_seasonal_rainfall_linreg_slopes(seasonal_rainfalls: dict) -> list: :return: A list of the Rainfall LinReg slopes for each season. """ season_labels, slopes = [], [] - for seasonal_rainfall in seasonal_rainfalls.values(): + for seasonal_rainfall in seasonal_rainfalls: season_labels.append(seasonal_rainfall.season.name) slopes.append(seasonal_rainfall.add_linear_regression()[1]) diff --git a/tst/core/models/test_all_rainfall.py b/tst/core/models/test_all_rainfall.py index 0a86d3f..c9e400a 100644 --- a/tst/core/models/test_all_rainfall.py +++ b/tst/core/models/test_all_rainfall.py @@ -12,23 +12,23 @@ from src.core.utils.enums.time_modes import TimeMode from tst.test_config import config -all_rainfall = AllRainfall(config.get_dataset_url()) +ALL_RAINFALL = AllRainfall(config.get_dataset_url()) -normal_year: int = 1971 -begin_year: int = 1991 -end_year: int = 2020 +normal_year = 1971 +begin_year = 1991 +end_year = 2020 -time_mode: str = TimeMode.YEARLY.value -month: str = Month.MAY.name -season: str = Season.SPRING.name +time_mode = TimeMode.YEARLY.value +month = Month.MAY.name +season = Season.SPRING.name class TestAllRainfall: @staticmethod - def test_export_all_data_to_csv() -> None: + def test_export_all_data_to_csv(): folder_path: str | None = None try: - folder_path = all_rainfall.export_all_data_to_csv() + folder_path = ALL_RAINFALL.export_all_data_to_csv() assert isinstance(folder_path, str) assert Path(folder_path).exists() @@ -37,25 +37,29 @@ def test_export_all_data_to_csv() -> None: rmtree(folder_path, ignore_errors=True) @staticmethod - def test_get_average_rainfall() -> None: + def test_get_average_rainfall(): for t_mode in TimeMode.values(): - avg_rainfall = all_rainfall.get_average_rainfall( - t_mode, begin_year, end_year, month, season + avg_rainfall = ALL_RAINFALL.get_average_rainfall( + t_mode, + begin_year=begin_year, + end_year=end_year, + month=month, + season=season, ) assert isinstance(avg_rainfall, float) @staticmethod - def test_get_normal() -> None: + def test_get_normal(): for t_mode in TimeMode.values(): - normal = all_rainfall.get_normal(t_mode, begin_year, month, season) + normal = ALL_RAINFALL.get_normal(t_mode, begin_year, month, season) assert isinstance(normal, float) @staticmethod - def test_get_years_below_normal() -> None: + def test_get_years_below_normal(): for t_mode in TimeMode.values(): - n_years_below_avg = all_rainfall.get_years_below_normal( + n_years_below_avg = ALL_RAINFALL.get_years_below_normal( t_mode, normal_year, begin_year, end_year, month, season ) @@ -63,9 +67,9 @@ def test_get_years_below_normal() -> None: assert n_years_below_avg <= end_year - begin_year + 1 @staticmethod - def test_get_years_above_normal() -> None: + def test_get_years_above_normal(): for t_mode in TimeMode.values(): - n_years_above_avg = all_rainfall.get_years_above_normal( + n_years_above_avg = ALL_RAINFALL.get_years_above_normal( t_mode, normal_year, begin_year, end_year, month, season ) @@ -73,13 +77,13 @@ def test_get_years_above_normal() -> None: assert n_years_above_avg <= end_year - begin_year + 1 @staticmethod - def test_get_last_year() -> None: - assert isinstance(all_rainfall.get_last_year(), int) + def test_get_last_year(): + assert isinstance(ALL_RAINFALL.get_last_year(), int) @staticmethod - def test_get_relative_distance_from_normal() -> None: + def test_get_relative_distance_from_normal(): for t_mode in TimeMode.values(): - relative_distance = all_rainfall.get_relative_distance_from_normal( + relative_distance = ALL_RAINFALL.get_relative_distance_from_normal( t_mode, normal_year, begin_year, end_year, month, season ) @@ -87,29 +91,29 @@ def test_get_relative_distance_from_normal() -> None: assert -100.0 <= relative_distance <= 100.0 @staticmethod - def test_get_standard_deviation() -> None: + def test_get_standard_deviation(): for t_mode in TimeMode.values(): - std = all_rainfall.get_rainfall_standard_deviation( + std = ALL_RAINFALL.get_rainfall_standard_deviation( t_mode, begin_year, end_year, month, season ) assert isinstance(std, float) @staticmethod - def test_get_entity_for_time_mode() -> None: + def test_get_entity_for_time_mode(): assert isinstance( - all_rainfall.get_entity_for_time_mode(TimeMode.YEARLY), YearlyRainfall + ALL_RAINFALL.get_entity_for_time_mode(TimeMode.YEARLY), YearlyRainfall ) assert isinstance( - all_rainfall.get_entity_for_time_mode( + ALL_RAINFALL.get_entity_for_time_mode( TimeMode.SEASONAL, season=Season.SPRING.name ), SeasonalRainfall, ) assert isinstance( - all_rainfall.get_entity_for_time_mode( + ALL_RAINFALL.get_entity_for_time_mode( TimeMode.MONTHLY, month=Month.OCTOBER.name ), MonthlyRainfall, ) - assert all_rainfall.get_entity_for_time_mode("unknown_time_mode") is None + assert ALL_RAINFALL.get_entity_for_time_mode("unknown_time_mode") is None diff --git a/tst/core/models/test_yearly_rainfall.py b/tst/core/models/test_yearly_rainfall.py index 7a28092..8435dfb 100644 --- a/tst/core/models/test_yearly_rainfall.py +++ b/tst/core/models/test_yearly_rainfall.py @@ -5,27 +5,27 @@ from src.core.utils.custom_exceptions import DataFormatError from src.core.utils.enums.labels import Label from src.core.utils.enums.months import Month -from tst.test_config import config from tst.core.models.test_all_rainfall import ( - all_rainfall, + ALL_RAINFALL, normal_year, begin_year, end_year, ) +from tst.test_config import config -yearly_rainfall = all_rainfall.yearly_rainfall +YEARLY_RAINFALL = ALL_RAINFALL.yearly_rainfall class TestYearlyRainfall: @staticmethod - def test_load_yearly_rainfall() -> None: - data: pd.DataFrame = yearly_rainfall.load_yearly_rainfall() + def test_load_yearly_rainfall(): + data = YEARLY_RAINFALL.load_yearly_rainfall() assert isinstance(data, pd.DataFrame) @staticmethod - def test_load_rainfall() -> None: - data: pd.DataFrame = yearly_rainfall.load_rainfall( + def test_load_rainfall(): + data = YEARLY_RAINFALL.load_rainfall( start_month=Month.JUNE.value, end_month=Month.OCTOBER.value ) assert isinstance(data, pd.DataFrame) @@ -33,7 +33,7 @@ def test_load_rainfall() -> None: assert Label.YEAR in data and Label.RAINFALL in data @staticmethod - def test_load_rainfall_fails_because_data_format_error() -> None: + def test_load_rainfall_fails_because_data_format_error(): with raises(DataFormatError): YearlyRainfall( raw_data=pd.DataFrame(), @@ -42,35 +42,33 @@ def test_load_rainfall_fails_because_data_format_error() -> None: ) @staticmethod - def test_get_yearly_rainfall() -> None: - data: pd.DataFrame = yearly_rainfall.get_yearly_rainfall(begin_year, end_year) + def test_get_yearly_rainfall(): + data = YEARLY_RAINFALL.get_yearly_rainfall(begin_year, end_year) assert isinstance(data, pd.DataFrame) assert len(data) == end_year - begin_year + 1 @staticmethod - def test_export_as_csv() -> None: - csv_as_str = yearly_rainfall.export_as_csv() + def test_export_as_csv(): + csv_as_str = YEARLY_RAINFALL.export_as_csv() assert isinstance(csv_as_str, str) @staticmethod - def test_get_average_yearly_rainfall() -> None: - avg_rainfall: float = yearly_rainfall.get_average_yearly_rainfall( - begin_year, end_year - ) + def test_get_average_yearly_rainfall(): + avg_rainfall = YEARLY_RAINFALL.get_average_yearly_rainfall(begin_year, end_year) assert isinstance(avg_rainfall, float) @staticmethod - def test_get_normal() -> None: - normal: float = yearly_rainfall.get_normal(begin_year) + def test_get_normal(): + normal = YEARLY_RAINFALL.get_normal(begin_year) assert isinstance(normal, float) @staticmethod - def test_get_years_below_average() -> None: - n_years_below_avg: int = yearly_rainfall.get_years_below_normal( + def test_get_years_below_average(): + n_years_below_avg = YEARLY_RAINFALL.get_years_below_normal( normal_year, begin_year, end_year ) @@ -78,8 +76,8 @@ def test_get_years_below_average() -> None: assert n_years_below_avg <= end_year - begin_year + 1 @staticmethod - def test_get_years_above_average() -> None: - n_years_above_avg: int = yearly_rainfall.get_years_above_normal( + def test_get_years_above_average(): + n_years_above_avg = YEARLY_RAINFALL.get_years_above_normal( normal_year, begin_year, end_year ) @@ -87,12 +85,12 @@ def test_get_years_above_average() -> None: assert n_years_above_avg <= end_year - begin_year + 1 @staticmethod - def test_get_last_year() -> None: - assert isinstance(yearly_rainfall.get_last_year(), int) + def test_get_last_year(): + assert isinstance(YEARLY_RAINFALL.get_last_year(), int) @staticmethod - def test_get_relative_distance_from_normal() -> None: - relative_distance: float = yearly_rainfall.get_relative_distance_from_normal( + def test_get_relative_distance_from_normal(): + relative_distance = YEARLY_RAINFALL.get_relative_distance_from_normal( normal_year, begin_year, end_year ) @@ -100,64 +98,64 @@ def test_get_relative_distance_from_normal() -> None: assert -100.0 <= relative_distance <= 100.0 @staticmethod - def test_get_standard_deviation() -> None: - std = yearly_rainfall.get_standard_deviation(yearly_rainfall.starting_year) + def test_get_standard_deviation(): + std = YEARLY_RAINFALL.get_standard_deviation(YEARLY_RAINFALL.starting_year) assert isinstance(std, float) - yearly_rainfall.remove_column(label=Label.SAVITZKY_GOLAY_FILTER) - std = yearly_rainfall.get_standard_deviation( - yearly_rainfall.starting_year, label=Label.SAVITZKY_GOLAY_FILTER + YEARLY_RAINFALL.remove_column(label=Label.SAVITZKY_GOLAY_FILTER) + std = YEARLY_RAINFALL.get_standard_deviation( + YEARLY_RAINFALL.starting_year, label=Label.SAVITZKY_GOLAY_FILTER ) assert std is None @staticmethod - def test_add_percentage_of_normal() -> None: - yearly_rainfall.add_percentage_of_normal(yearly_rainfall.starting_year) + def test_add_percentage_of_normal(): + YEARLY_RAINFALL.add_percentage_of_normal(YEARLY_RAINFALL.starting_year) - assert Label.PERCENTAGE_OF_NORMAL in yearly_rainfall.data + assert Label.PERCENTAGE_OF_NORMAL in YEARLY_RAINFALL.data @staticmethod - def test_add_linear_regression() -> None: - yearly_rainfall.add_linear_regression() + def test_add_linear_regression(): + YEARLY_RAINFALL.add_linear_regression() - assert Label.LINEAR_REGRESSION in yearly_rainfall.data + assert Label.LINEAR_REGRESSION in YEARLY_RAINFALL.data @staticmethod - def test_add_savgol_filter() -> None: - yearly_rainfall.add_savgol_filter() + def test_add_savgol_filter(): + YEARLY_RAINFALL.add_savgol_filter() - assert Label.SAVITZKY_GOLAY_FILTER in yearly_rainfall.data + assert Label.SAVITZKY_GOLAY_FILTER in YEARLY_RAINFALL.data @staticmethod - def test_add_kmeans() -> None: - kmeans_clusters: int = 5 - n_clusters: int = yearly_rainfall.add_kmeans(kmeans_clusters) + def test_add_kmeans(): + kmeans_clusters = 5 + n_clusters = YEARLY_RAINFALL.add_kmeans(kmeans_clusters) assert n_clusters == kmeans_clusters - assert Label.KMEANS in yearly_rainfall.data + assert Label.KMEANS in YEARLY_RAINFALL.data @staticmethod - def test_remove_column() -> None: - removed: bool = yearly_rainfall.remove_column(Label.YEAR) + def test_remove_column(): + removed = YEARLY_RAINFALL.remove_column(Label.YEAR) - assert Label.YEAR in yearly_rainfall.data.columns + assert Label.YEAR in YEARLY_RAINFALL.data.columns assert not removed - removed = yearly_rainfall.remove_column(Label.SAVITZKY_GOLAY_FILTER) + removed = YEARLY_RAINFALL.remove_column(Label.SAVITZKY_GOLAY_FILTER) - assert Label.SAVITZKY_GOLAY_FILTER not in yearly_rainfall.data.columns + assert Label.SAVITZKY_GOLAY_FILTER not in YEARLY_RAINFALL.data.columns assert removed - yearly_rainfall.add_savgol_filter() + YEARLY_RAINFALL.add_savgol_filter() @staticmethod - def test_plot_rainfall_and_models() -> None: - yearly_rainfall.plot_rainfall() - yearly_rainfall.plot_linear_regression() - yearly_rainfall.plot_savgol_filter() + def test_plot_rainfall_and_models(): + YEARLY_RAINFALL.plot_rainfall() + YEARLY_RAINFALL.plot_linear_regression() + YEARLY_RAINFALL.plot_savgol_filter() @staticmethod - def test_plot_normal() -> None: - yearly_rainfall.plot_normal() + def test_plot_normal(): + YEARLY_RAINFALL.plot_normal() diff --git a/tst/core/utils/enums/test_labels.py b/tst/core/utils/enums/test_labels.py index a3b3b00..fe91b12 100644 --- a/tst/core/utils/enums/test_labels.py +++ b/tst/core/utils/enums/test_labels.py @@ -1,6 +1,6 @@ from src.core.utils.enums.labels import Label -def test_labels() -> None: +def test_labels(): for label in Label: assert isinstance(label.value, str) diff --git a/tst/core/utils/enums/test_months.py b/tst/core/utils/enums/test_months.py index 7708f84..e9d2a38 100644 --- a/tst/core/utils/enums/test_months.py +++ b/tst/core/utils/enums/test_months.py @@ -3,89 +3,89 @@ class TestMonths: @staticmethod - def test_months_count() -> None: + def test_months_count(): assert len(Month) == 12 @staticmethod - def test_january() -> None: - month: Month = Month.JANUARY + def test_january(): + month = Month.JANUARY assert isinstance(month.value, int) assert month.value == 1 @staticmethod - def test_february() -> None: - month: Month = Month.FEBRUARY + def test_february(): + month = Month.FEBRUARY assert isinstance(month.value, int) assert month.value == 2 @staticmethod - def test_march() -> None: - month: Month = Month.MARCH + def test_march(): + month = Month.MARCH assert isinstance(month.value, int) assert month.value == 3 @staticmethod - def test_april() -> None: - month: Month = Month.APRIL + def test_april(): + month = Month.APRIL assert isinstance(month.value, int) assert month.value == 4 @staticmethod - def test_may() -> None: - month: Month = Month.MAY + def test_may(): + month = Month.MAY assert isinstance(month.value, int) assert month.value == 5 @staticmethod - def test_june() -> None: - month: Month = Month.JUNE + def test_june(): + month = Month.JUNE assert isinstance(month.value, int) assert month.value == 6 @staticmethod - def test_july() -> None: - month: Month = Month.JULY + def test_july(): + month = Month.JULY assert isinstance(month.value, int) assert month.value == 7 @staticmethod - def test_august() -> None: - month: Month = Month.AUGUST + def test_august(): + month = Month.AUGUST assert isinstance(month.value, int) assert month.value == 8 @staticmethod - def test_september() -> None: - month: Month = Month.SEPTEMBER + def test_september(): + month = Month.SEPTEMBER assert isinstance(month.value, int) assert month.value == 9 @staticmethod - def test_october() -> None: - month: Month = Month.OCTOBER + def test_october(): + month = Month.OCTOBER assert isinstance(month.value, int) assert month.value == 10 @staticmethod - def test_november() -> None: - month: Month = Month.NOVEMBER + def test_november(): + month = Month.NOVEMBER assert isinstance(month.value, int) assert month.value == 11 @staticmethod - def test_december() -> None: - month: Month = Month.DECEMBER + def test_december(): + month = Month.DECEMBER assert isinstance(month.value, int) assert month.value == 12 diff --git a/tst/core/utils/enums/test_seasons.py b/tst/core/utils/enums/test_seasons.py index 7b116fb..74872b4 100644 --- a/tst/core/utils/enums/test_seasons.py +++ b/tst/core/utils/enums/test_seasons.py @@ -4,12 +4,12 @@ class TestSeasons: @staticmethod - def test_seasons_count() -> None: + def test_seasons_count(): assert len(Season) == 4 @staticmethod - def test_winter() -> None: - season: Season = Season.WINTER + def test_winter(): + season = Season.WINTER assert isinstance(season.value, list) assert len(season.value) == 3 @@ -17,8 +17,8 @@ def test_winter() -> None: assert isinstance(month, Month) @staticmethod - def test_spring() -> None: - season: Season = Season.SPRING + def test_spring(): + season = Season.SPRING assert isinstance(season.value, list) assert len(season.value) == 3 @@ -26,8 +26,8 @@ def test_spring() -> None: assert isinstance(month, Month) @staticmethod - def test_summer() -> None: - season: Season = Season.SUMMER + def test_summer(): + season = Season.SUMMER assert isinstance(season.value, list) assert len(season.value) == 3 @@ -35,8 +35,8 @@ def test_summer() -> None: assert isinstance(month, Month) @staticmethod - def test_fall() -> None: - season: Season = Season.FALL + def test_fall(): + season = Season.FALL assert isinstance(season.value, list) assert len(season.value) == 3 diff --git a/tst/core/utils/enums/test_time_modes.py b/tst/core/utils/enums/test_time_modes.py index 12e8a40..13ef369 100644 --- a/tst/core/utils/enums/test_time_modes.py +++ b/tst/core/utils/enums/test_time_modes.py @@ -1,7 +1,7 @@ from src.core.utils.enums.time_modes import TimeMode -def test_time_modes() -> None: +def test_time_modes(): assert len(TimeMode) == 3 for t_mode in TimeMode.values(): diff --git a/tst/core/utils/functions/test_dataframe_operations.py b/tst/core/utils/functions/test_dataframe_operations.py index 81fea66..cba29a6 100644 --- a/tst/core/utils/functions/test_dataframe_operations.py +++ b/tst/core/utils/functions/test_dataframe_operations.py @@ -5,41 +5,40 @@ import src.core.utils.functions.dataframe_operations as df_opr from src.core.utils.enums.labels import Label from src.core.utils.enums.months import Month -from tst.core.models.test_yearly_rainfall import yearly_rainfall +from tst.core.models.test_yearly_rainfall import YEARLY_RAINFALL class TestDataframeOperations: @staticmethod - def test_get_rainfall_within_year_interval() -> None: - begin_year: int = 1995 - end_year: int = 2015 - cropped_yearly_rainfall: pd.DataFrame = ( - df_opr.get_rainfall_within_year_interval( - yearly_rainfall.data, begin_year, end_year - ) + def test_get_rainfall_within_year_interval(): + begin_year = 1995 + end_year = 2015 + + cropped_yearly_rainfall = df_opr.get_rainfall_within_year_interval( + YEARLY_RAINFALL.data, begin_year=begin_year, end_year=end_year ) assert len(cropped_yearly_rainfall) <= end_year - begin_year + 1 @staticmethod - def test_remove_column() -> None: - removed: bool = df_opr.remove_column(yearly_rainfall.data, Label.YEAR) + def test_remove_column(): + removed = df_opr.remove_column(YEARLY_RAINFALL.data, Label.YEAR) - assert Label.YEAR in yearly_rainfall.data.columns + assert Label.YEAR in YEARLY_RAINFALL.data.columns assert not removed - yearly_rainfall.add_savgol_filter() + YEARLY_RAINFALL.add_savgol_filter() removed = df_opr.remove_column( - yearly_rainfall.data, Label.SAVITZKY_GOLAY_FILTER + YEARLY_RAINFALL.data, Label.SAVITZKY_GOLAY_FILTER ) - assert Label.SAVITZKY_GOLAY_FILTER not in yearly_rainfall.data.columns + assert Label.SAVITZKY_GOLAY_FILTER not in YEARLY_RAINFALL.data.columns assert removed - yearly_rainfall.add_savgol_filter() + YEARLY_RAINFALL.add_savgol_filter() @staticmethod - def test_concat_columns() -> None: + def test_concat_columns(): result = df_opr.concat_columns( [ pd.DataFrame(data={"col1": [1, 2, 3]}), @@ -52,14 +51,14 @@ def test_concat_columns() -> None: assert len(result) == 3 @staticmethod - def test_retrieve_rainfall_data_with_constraints() -> None: - result: pd.DataFrame = df_opr.retrieve_rainfall_data_with_constraints( - yearly_rainfall.data, - yearly_rainfall.starting_year, - yearly_rainfall.round_precision, + def test_retrieve_rainfall_data_with_constraints(): + result = df_opr.retrieve_rainfall_data_with_constraints( + YEARLY_RAINFALL.data, + YEARLY_RAINFALL.starting_year, + YEARLY_RAINFALL.round_precision, Month.MAY.value, Month.SEPTEMBER.value, ) assert isinstance(result, pd.DataFrame) - assert len(result) <= datetime.now().year - yearly_rainfall.starting_year + 1 + assert len(result) <= datetime.now().year - YEARLY_RAINFALL.starting_year + 1 diff --git a/tst/core/utils/functions/test_metrics.py b/tst/core/utils/functions/test_metrics.py index 89581f7..f1e6442 100644 --- a/tst/core/utils/functions/test_metrics.py +++ b/tst/core/utils/functions/test_metrics.py @@ -1,42 +1,39 @@ from operator import lt -from src.core.utils.functions import metrics from src.core.utils.enums.labels import Label - -from tst.core.models.test_yearly_rainfall import yearly_rainfall +from src.core.utils.functions import metrics +from tst.core.models.test_yearly_rainfall import YEARLY_RAINFALL class TestMetrics: @staticmethod - def test_get_average_rainfall() -> None: - precision: int = 3 - avg_rainfall: float = metrics.get_average_rainfall( - yearly_rainfall.data, precision - ) + def test_get_average_rainfall(): + precision = 3 + avg_rainfall = metrics.get_average_rainfall(YEARLY_RAINFALL.data, precision) assert isinstance(avg_rainfall, float) assert len(str(avg_rainfall).split(".")[1]) <= precision @staticmethod - def test_get_years_compared_to_given_rainfall_value() -> None: - nb_years: int = metrics.get_years_compared_to_given_rainfall_value( - yearly_rainfall.data, metrics.get_average_rainfall(yearly_rainfall.data), lt + def test_get_years_compared_to_given_rainfall_value(): + nb_years = metrics.get_years_compared_to_given_rainfall_value( + YEARLY_RAINFALL.data, metrics.get_average_rainfall(YEARLY_RAINFALL.data), lt ) - assert nb_years <= len(yearly_rainfall.data) + assert nb_years <= len(YEARLY_RAINFALL.data) @staticmethod - def test_get_clusters_number() -> None: - nb_clusters: int = metrics.get_clusters_number(yearly_rainfall.data) + def test_get_clusters_number(): + nb_clusters = metrics.get_clusters_number(YEARLY_RAINFALL.data) - if Label.KMEANS not in yearly_rainfall.data: + if Label.KMEANS not in YEARLY_RAINFALL.data: assert nb_clusters == 0 else: assert nb_clusters > 0 @staticmethod - def test_get_normal() -> None: - normal: float = metrics.get_normal(yearly_rainfall.data, begin_year=1991) + def test_get_normal(): + normal = metrics.get_normal(YEARLY_RAINFALL.data, begin_year=1991) assert isinstance(normal, float) assert normal >= 0.0 diff --git a/tst/core/utils/functions/test_plotting.py b/tst/core/utils/functions/test_plotting.py index 14167f5..f97fbea 100644 --- a/tst/core/utils/functions/test_plotting.py +++ b/tst/core/utils/functions/test_plotting.py @@ -1,14 +1,15 @@ -from src.core.utils.functions import plotting from src.core.utils.enums.labels import Label +from src.core.utils.functions import plotting +from tst.core.models.test_yearly_rainfall import YEARLY_RAINFALL, ALL_RAINFALL -from tst.core.models.test_yearly_rainfall import yearly_rainfall, all_rainfall +BEGIN_YEAR = 1970 class TestPlotting: @staticmethod def test_plot_column_according_to_year(): is_plotted = plotting.plot_column_according_to_year( - yearly_rainfall.data, Label.RAINFALL + YEARLY_RAINFALL.data, Label.RAINFALL ) assert isinstance(is_plotted, bool) @@ -17,7 +18,7 @@ def test_plot_column_according_to_year(): @staticmethod def test_scatter_column_according_to_year(): is_plotted = plotting.scatter_column_according_to_year( - yearly_rainfall.data, Label.RAINFALL + YEARLY_RAINFALL.data, Label.RAINFALL ) assert isinstance(is_plotted, bool) @@ -26,7 +27,7 @@ def test_scatter_column_according_to_year(): @staticmethod def test_bar_column_according_to_year(): is_plotted = plotting.bar_column_according_to_year( - yearly_rainfall.data, Label.RAINFALL + YEARLY_RAINFALL.data, Label.RAINFALL ) assert isinstance(is_plotted, bool) @@ -35,43 +36,45 @@ def test_bar_column_according_to_year(): @staticmethod def test_bar_monthly_rainfall_averages(): averages = plotting.bar_monthly_rainfall_averages( - all_rainfall.monthly_rainfalls + ALL_RAINFALL.monthly_rainfalls.values(), + begin_year=BEGIN_YEAR, ) assert isinstance(averages, list) - assert len(averages) == len(all_rainfall.monthly_rainfalls) + assert len(averages) == len(ALL_RAINFALL.monthly_rainfalls.values()) for average in averages: assert isinstance(average, float) @staticmethod def test_bar_monthly_rainfall_linreg_slopes(): slopes = plotting.bar_monthly_rainfall_linreg_slopes( - all_rainfall.monthly_rainfalls + ALL_RAINFALL.monthly_rainfalls.values() ) assert isinstance(slopes, list) - assert len(slopes) == len(all_rainfall.monthly_rainfalls) + assert len(slopes) == len(ALL_RAINFALL.monthly_rainfalls) for slope in slopes: assert isinstance(slope, float) @staticmethod def test_bar_seasonal_rainfall_averages(): averages = plotting.bar_seasonal_rainfall_averages( - all_rainfall.seasonal_rainfalls + ALL_RAINFALL.seasonal_rainfalls.values(), + begin_year=BEGIN_YEAR, ) assert isinstance(averages, list) - assert len(averages) == len(all_rainfall.seasonal_rainfalls) + assert len(averages) == len(ALL_RAINFALL.seasonal_rainfalls) for average in averages: assert isinstance(average, float) @staticmethod def test_bar_seasonal_rainfall_linreg_slopes(): slopes = plotting.bar_seasonal_rainfall_linreg_slopes( - all_rainfall.seasonal_rainfalls + ALL_RAINFALL.seasonal_rainfalls.values() ) assert isinstance(slopes, list) - assert len(slopes) == len(all_rainfall.seasonal_rainfalls) + assert len(slopes) == len(ALL_RAINFALL.seasonal_rainfalls) for slope in slopes: assert isinstance(slope, float) diff --git a/tst/test_config.py b/tst/test_config.py index 8189573..c4f21fe 100644 --- a/tst/test_config.py +++ b/tst/test_config.py @@ -8,31 +8,31 @@ class TestConfig: @staticmethod - def test_get_dataset_url() -> None: - dataset_url: str = config.get_dataset_url() + def test_get_dataset_url(): + dataset_url = config.get_dataset_url() assert isinstance(dataset_url, str) @staticmethod - def test_get_start_year() -> None: - start_year: int = config.get_start_year() + def test_get_start_year(): + start_year = config.get_start_year() assert isinstance(start_year, int) @staticmethod - def test_get_rainfall_precision() -> None: - rainfall_precision: int = config.get_rainfall_precision() + def test_get_rainfall_precision(): + rainfall_precision = config.get_rainfall_precision() assert isinstance(rainfall_precision, int) @staticmethod - def test_get_kmeans_clusters() -> None: - kmeans_clusters: int = config.get_kmeans_clusters() + def test_get_kmeans_clusters(): + kmeans_clusters = config.get_kmeans_clusters() assert isinstance(kmeans_clusters, int) @staticmethod - def test_config_file_not_found() -> None: + def test_config_file_not_found(): with raises(FileNotFoundError): Config(path="/there/is/no/config/file/there/dude.yaml") @staticmethod - def test_config_file_invalid() -> None: + def test_config_file_invalid(): with raises(ParserError): Config(path="README.md")