Skip to content

Commit

Permalink
Put list of strings as Enums in Marshmallow schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
paul-florentin-charles committed Nov 29, 2023
1 parent 64931c5 commit fc94f07
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 53 deletions.
8 changes: 5 additions & 3 deletions src/api/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from flasgger import Schema, fields

from src.core.utils.enums.months import Month
from src.core.utils.enums.seasons import Season
from src.core.utils.enums.time_modes import TimeMode
import src.api.swagger.parameters_specs as param

Expand All @@ -21,9 +23,9 @@ class BaseSchema(Schema):
value: Union[float, int] = fields.Number()
begin_year: int = fields.Int(load_default=param.begin_year["default"])
end_year: Optional[int] = fields.Int(allow_none=True)
time_mode: str = fields.Str(load_default=TimeMode.YEARLY.value)
month: Optional[str] = fields.Str(allow_none=True)
season: Optional[str] = fields.Str(allow_none=True)
time_mode: TimeMode = fields.Enum(TimeMode, load_default=TimeMode.YEARLY)
month: Optional[Month] = fields.Enum(Month, allow_none=True)
season: Optional[Season] = fields.Enum(Season, allow_none=True)


class RainfallSchema(BaseSchema):
Expand Down
4 changes: 2 additions & 2 deletions src/api/swagger/parameters_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
}

time_mode: dict = {
"default": TimeMode.YEARLY.value,
"default": TimeMode.YEARLY.name,
"required": True,
"type": "string",
"enum": TimeMode.values(),
"enum": TimeMode.names(),
"name": "time_mode",
"in": "query",
}
Expand Down
16 changes: 9 additions & 7 deletions src/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from werkzeug.datastructures.structures import MultiDict

from src.api.error_wrappers import bad_request
from src.core.utils.enums.months import Month
from src.core.utils.enums.seasons import Season
from src.core.utils.enums.time_modes import TimeMode


Expand Down Expand Up @@ -58,24 +60,24 @@ def manage_time_mode_errors(
If time mode is set to seasonal and season is None.
:param response_dict: Dict where to store response fields.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
:param time_mode: A string setting the time period ['YEARLY', 'MONTHLY', 'SEASONAL']
:param month: A string corresponding to the month name.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
:param season: A string corresponding to the season name.
Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL'].
Set if time_mode is 'seasonal' (optional)
Set if time_mode is 'SEASONAL' (optional)
:return: Either a Flask Response if there is an error or the updated dictionary.
"""
if time_mode == TimeMode.MONTHLY.value:
if time_mode == TimeMode.MONTHLY.name:
if month is None:
return bad_request("Month cannot be null.")

response_dict["month"] = month.lower()
response_dict["month"] = Month[month]

if time_mode == TimeMode.SEASONAL.value:
if time_mode == TimeMode.SEASONAL.name:
if season is None:
return bad_request("Season cannot be null.")

response_dict["season"] = season.lower()
response_dict["season"] = Season[season]

return response_dict
25 changes: 13 additions & 12 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from src.api.utils import parse_args, manage_time_mode_errors
from src.config import Config
from src.core.models.all_rainfall import AllRainfall
from src.core.utils.enums.time_modes import TimeMode

cfg = Config()
all_rainfall = AllRainfall(
Expand Down Expand Up @@ -66,11 +67,11 @@ def average_rainfall() -> Response:
"end_year": params[2]
if params[2] is not None
else all_rainfall.get_last_year(),
"time_mode": params[0],
"time_mode": TimeMode[params[0]],
}
)

return jsonify(RainfallSchema().load(to_return))
return jsonify(RainfallSchema().dump(to_return))


@app.route(f"{base_path}/rainfall/normal")
Expand All @@ -92,11 +93,11 @@ def normal_rainfall() -> Response:
"value": all_rainfall.get_normal(*params),
"begin_year": params[1],
"end_year": params[1] + 29,
"time_mode": params[0],
"time_mode": TimeMode[params[0]],
}
)

return jsonify(RainfallSchema().load(to_return))
return jsonify(RainfallSchema().dump(to_return))


@app.route(f"{base_path}/rainfall/relative_distance_to_normal")
Expand Down Expand Up @@ -127,11 +128,11 @@ def rainfall_relative_distance_to_normal() -> Response:
"end_year": params[3]
if params[3] is not None
else all_rainfall.get_last_year(),
"time_mode": params[0],
"time_mode": TimeMode[params[0]],
}
)

return jsonify(RelativeDistanceToRainfallNormalSchema().load(to_return))
return jsonify(RelativeDistanceToRainfallNormalSchema().dump(to_return))


@app.route(f"{base_path}/rainfall/standard_deviation")
Expand Down Expand Up @@ -160,11 +161,11 @@ def rainfall_standard_deviation() -> Response:
"end_year": params[2]
if params[2] is not None
else all_rainfall.get_last_year(),
"time_mode": params[0],
"time_mode": TimeMode[params[0]],
}
)

return jsonify(RainfallSchema().load(to_return))
return jsonify(RainfallSchema().dump(to_return))


@app.route(f"{base_path}/year/below_normal")
Expand Down Expand Up @@ -195,11 +196,11 @@ def years_below_normal() -> Response:
"end_year": params[3]
if params[3] is not None
else all_rainfall.get_last_year(),
"time_mode": params[0],
"time_mode": TimeMode[params[0]],
}
)

return jsonify(YearsAboveOrBelowNormalSchema().load(to_return))
return jsonify(YearsAboveOrBelowNormalSchema().dump(to_return))


@app.route(f"{base_path}/year/above_normal")
Expand Down Expand Up @@ -230,11 +231,11 @@ def years_above_normal() -> Response:
"end_year": params[3]
if params[3] is not None
else all_rainfall.get_last_year(),
"time_mode": params[0],
"time_mode": TimeMode[params[0]],
}
)

return jsonify(YearsAboveOrBelowNormalSchema().load(to_return))
return jsonify(YearsAboveOrBelowNormalSchema().dump(to_return))


@app.route(f"{base_path}/csv/minimal_csv")
Expand Down
57 changes: 29 additions & 28 deletions src/core/models/all_rainfall.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ def export_as_csv(
Export the data state of a specific time mode as a CSV.
Could be for a yearly time frame, a specific month or a given season.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
:param time_mode: A string setting the time period ['YEARLY', 'MONTHLY', 'SEASONAL']
:param month: A string corresponding to the month name.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
:param season: A string corresponding to the season name.
Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL'].
Set if time_mode is 'seasonal' (optional)
Set if time_mode is 'SEASONAL' (optional)
:param path: path to csv file to save our data (optional).
:return: CSV data as a string if no path is set.
None otherwise.
Expand All @@ -123,16 +123,16 @@ def get_average_rainfall(
"""
Computes Rainfall average for a specific year range and time mode.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
: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).
:param end_year: An integer representing the year
to end getting our rainfall values (optional).
:param month: A string corresponding to the month name.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
:param season: A string corresponding to the season name.
Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL'].
Set if time_mode is 'seasonal' (optional)
Set if time_mode is 'SEASONAL' (optional)
:return: A float representing the average Rainfall.
"""
entity = self.get_entity_for_time_mode(time_mode, month, season)
Expand All @@ -152,14 +152,14 @@ def get_normal(
"""
Computes Rainfall normal from a specific year and time mode.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
:param time_mode: A string setting the time period ['YEARLY', 'MONTHLY', 'SEASONAL']
:param begin_year: An integer representing the year
to start computing rainfall normal.
:param month: A string corresponding to the month name.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
:param season: A string corresponding to the season name.
Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL'].
Set if time_mode is 'seasonal' (optional)
Set if time_mode is 'SEASONAL' (optional)
:return: A float representing the Rainfall normal.
"""

Expand All @@ -182,18 +182,18 @@ def get_relative_distance_from_normal(
"""
Computes relative distance to Rainfall normal for a specific year range and time mode.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
:param time_mode: A string setting the time period ['YEARLY', 'MONTHLY', 'SEASONAL']
:param normal_year: An integer representing the year
to start computing the 30 years normal of the rainfall.
:param begin_year: An integer representing the year
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.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
:param season: A string corresponding to the season name.
Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL'].
Set if time_mode is 'seasonal' (optional)
Set if time_mode is 'SEASONAL' (optional)
:return: A float representing the relative distance to rainfall normal.
"""
entity = self.get_entity_for_time_mode(time_mode, month, season)
Expand All @@ -218,16 +218,16 @@ def get_rainfall_standard_deviation(
for a specific year range and time mode.
By default, it uses the 'Rainfall' column.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
: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).
:param end_year: An integer representing the year
to end getting our rainfall values (optional).
:param month: A string corresponding to the month name.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
:param season: A string corresponding to the season name.
Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL'].
Set if time_mode is 'seasonal' (optional)
Set if time_mode is 'SEASONAL' (optional)
:return: The standard deviation as a float.
Nothing if the specified column does not exist.
"""
Expand All @@ -250,18 +250,18 @@ def get_years_below_normal(
"""
Computes the number of years below rainfall normal for a specific year range and time mode.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
:param time_mode: A string setting the time period ['YEARLY', 'MONTHLY', 'SEASONAL']
:param normal_year: An integer representing the year
to start computing the 30 years normal of the rainfall.
:param begin_year: An integer representing the year
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.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
:param season: A string corresponding to the season name.
Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL'].
Set if time_mode is 'seasonal' (optional)
Set if time_mode is 'SEASONAL' (optional)
:return: A float representing the relative distance to rainfall normal.
"""
entity = self.get_entity_for_time_mode(time_mode, month, season)
Expand All @@ -283,18 +283,18 @@ def get_years_above_normal(
"""
Computes the number of years above rainfall normal for a specific year range and time mode.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
:param time_mode: A string setting the time period ['YEARLY', 'MONTHLY', 'SEASONAL']
:param normal_year: An integer representing the year
to start computing the 30 years normal of the rainfall.
:param begin_year: An integer representing the year
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.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
:param season: A string corresponding to the season name.
Possible values are within ['WINTER', 'SPRING', 'SUMMER', 'FALL'].
Set if time_mode is 'seasonal' (optional)
Set if time_mode is 'SEASONAL' (optional)
:return: A float representing the relative distance to rainfall normal.
"""
entity = self.get_entity_for_time_mode(time_mode, month, season)
Expand Down Expand Up @@ -348,21 +348,22 @@ def get_entity_for_time_mode(
amongst instances of YearlyRainfall, MonthlyRainfall or SeasonsalRainfall.
Month or Season should be specified according to time mode.
:param time_mode: A string setting the time period ['yearly', 'monthly', 'seasonal']
:param time_mode: A string setting the time period ['YEARLY', 'MONTHLY', 'SEASONAL']
:param month: A string corresponding to the month name.
Set if time_mode is 'monthly' (optional)
Set if time_mode is 'MONTHLY' (optional)
: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: Corresponding entity as a class instance.
None if time mode is unknown.
"""
entity: Union[YearlyRainfall, MonthlyRainfall, SeasonalRainfall, None] = None

if time_mode.casefold() == TimeMode.YEARLY.value.casefold():
if time_mode.casefold() == TimeMode.YEARLY:
entity = self.yearly_rainfall
elif time_mode.casefold() == TimeMode.MONTHLY.value.casefold():
entity = self.monthly_rainfalls[month.upper()]
elif time_mode.casefold() == TimeMode.SEASONAL.value.casefold():
entity = self.seasonal_rainfalls[season.upper()]
elif time_mode.casefold() == TimeMode.MONTHLY:
entity = self.monthly_rainfalls[month]
elif time_mode.casefold() == TimeMode.SEASONAL:
entity = self.seasonal_rainfalls[season]

return entity
2 changes: 1 addition & 1 deletion src/core/utils/enums/months.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from src.core.utils.enums.base_enum import BaseEnum


class Month(BaseEnum):
class Month(int, BaseEnum):
"""
An Enum listing months as integers.
"""
Expand Down

0 comments on commit fc94f07

Please sign in to comment.