Skip to content

Commit

Permalink
Implemented Marshmallow Schemas amidts other small fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
paul-florentin-charles committed Nov 8, 2023
1 parent 46df692 commit 99b015c
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 62 deletions.
74 changes: 74 additions & 0 deletions src/api/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""
Provides a bunch of Marshmallow Schemas to validate rainfall data processed through the API.
"""

from typing import Optional, Union

from flasgger import Schema, fields

from src.core.utils.enums.time_modes import TimeMode


class BaseRainfall(Schema):
"""
Base schema for depicting a value linked to rainfall data.
Should be used as a parent class.
"""
value: Union[float, int] = fields.Number()
begin_year: int = fields.Int()
end_year: Optional[int] = fields.Int()
time_mode: str = fields.Str()


class AverageYearlyRainfall(BaseRainfall):
"""
Schema for depicting an average rainfall for a yearly time mode.
"""
name: str = fields.Str(load_default='average rainfall')
value: float = fields.Float()
time_mode: str = fields.Str(load_default=TimeMode.YEARLY.value)


class NormalYearlyRainfall(BaseRainfall):
"""
Schema for depicting a rainfall normal for a yearly time mode.
"""
name: str = fields.Str(load_default='rainfall normal')
value: float = fields.Float()
time_mode: str = fields.Str(load_default=TimeMode.YEARLY.value)


class RelativeDistanceToNormalYearlyRainfall(BaseRainfall):
"""
Schema for depicting a relative distance to rainfall normal for a yearly time mode.
"""
name: str = fields.Str(load_default='rainfall relative distance to normal')
value: float = fields.Float()
time_mode: str = fields.Str(load_default=TimeMode.YEARLY.value)


class StandardDeviationYearlyRainfall(BaseRainfall):
"""
Schema for depicting a rainfall standard deviation for a yearly time mode.
"""
name: str = fields.Str(load_default='rainfall standard deviation')
value: float = fields.Float()
time_mode: str = fields.Str(load_default=TimeMode.YEARLY.value)


class YearsAboveNormalSchema(BaseRainfall):
"""
Schema for giving the number of years above rainfall normal for a yearly time mode.
"""
name: str = fields.Str(load_default='years above rainfall normal')
value: float = fields.Int()
time_mode: str = fields.Str(load_default=TimeMode.YEARLY.value)


class YearsBelowNormalSchema(BaseRainfall):
"""
Schema for giving the number of years below rainfall normal for a yearly time mode.
"""
name: str = fields.Str(load_default='years below rainfall normal')
value: float = fields.Int()
time_mode: str = fields.Str(load_default=TimeMode.YEARLY.value)
9 changes: 3 additions & 6 deletions src/api/swagger/rainfall/average_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"""

import src.api.swagger.parameters_specs as param

from src.api.schemas import AverageYearlyRainfall

route_specs: dict = {
"operationId": "getRainfallAverage",
Expand All @@ -22,11 +22,8 @@
],
"responses": {
"200": {
"description": "the average rainfall (in mm)",
"schema": {
"type": "number",
"example": 623.75
}
"description": "The average rainfall (in mm)",
"schema": AverageYearlyRainfall
}
},
"parameters": [
Expand Down
9 changes: 3 additions & 6 deletions src/api/swagger/rainfall/normal_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"""

import src.api.swagger.parameters_specs as param

from src.api.schemas import NormalYearlyRainfall

route_specs: dict = {
"operationId": "getRainfallNormal",
Expand All @@ -19,11 +19,8 @@
],
"responses": {
"200": {
"description": "the 30 years normal (in mm)",
"schema": {
"type": "number",
"example": 607.28
}
"description": "The 30 years normal (in mm)",
"schema": NormalYearlyRainfall
}
},
"parameters": [
Expand Down
9 changes: 3 additions & 6 deletions src/api/swagger/rainfall/relative_distance_to_normal_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"""

import src.api.swagger.parameters_specs as param

from src.api.schemas import RelativeDistanceToNormalYearlyRainfall

route_specs: dict = {
"operationId": "getRainfallRelativeDistanceToNormal",
Expand All @@ -30,11 +30,8 @@
],
"responses": {
"200": {
"description": "the relative distance to normal as a percentage.",
"schema": {
"type": "number",
"example": -25.67
}
"description": "The relative distance to normal as a percentage.",
"schema": RelativeDistanceToNormalYearlyRainfall
}
},
"parameters": [
Expand Down
9 changes: 3 additions & 6 deletions src/api/swagger/rainfall/standard_deviation_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"""

import src.api.swagger.parameters_specs as param

from src.api.schemas import StandardDeviationYearlyRainfall

route_specs: dict = {
"operationId": "getRainfallStandardDeviation",
Expand All @@ -22,11 +22,8 @@
],
"responses": {
"200": {
"description": "the rainfall standard deviation (in mm)",
"schema": {
"type": "number",
"example": 172.43
}
"description": "The rainfall standard deviation (in mm)",
"schema": StandardDeviationYearlyRainfall
}
},
"parameters": [
Expand Down
7 changes: 2 additions & 5 deletions src/api/swagger/year/above_normal_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"""

import src.api.swagger.parameters_specs as param

from src.api.schemas import YearsAboveNormalSchema

route_specs: dict = {
"operationId": "getYearsAboveNormal",
Expand All @@ -21,10 +21,7 @@
"responses": {
"200": {
"description": "the number of years above normal",
"schema": {
"type": "integer",
"example": 23
}
"schema": YearsAboveNormalSchema
}
},
"parameters": [
Expand Down
9 changes: 3 additions & 6 deletions src/api/swagger/year/below_normal_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"""

import src.api.swagger.parameters_specs as param

from src.api.schemas import YearsBelowNormalSchema

route_specs: dict = {
"operationId": "getYearsBelowNormal",
Expand All @@ -20,11 +20,8 @@
],
"responses": {
"200": {
"description": "the number of years below normal",
"schema": {
"type": "integer",
"example": 27
}
"description": "The number of years below normal",
"schema": YearsBelowNormalSchema
}
},
"parameters": [
Expand Down
95 changes: 69 additions & 26 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from flask import Flask, jsonify, request, Response

from api.parameters import Parameter
import src.api.schemas as model
from src.api.swagger.rainfall import (average_specs, normal_specs,
relative_distance_to_normal_specs,
standard_deviation_specs)
Expand All @@ -30,57 +31,99 @@
@app.route(f"{swagger.template['basePath']}/rainfall/average")
@swag_from(average_specs.route_specs)
def average_rainfall() -> Response:
return jsonify(all_rainfall.yearly_rainfall.get_average_yearly_rainfall(
begin_year=request.args.get(*Parameter.BEGIN_YEAR.value),
end_year=request.args.get(*Parameter.END_YEAR.value)
))
begin_year: int = request.args.get(*Parameter.BEGIN_YEAR.value)
end_year: int = request.args.get(*Parameter.END_YEAR.value)
value: float = all_rainfall.yearly_rainfall.get_average_yearly_rainfall(begin_year, end_year)

return jsonify(model.AverageYearlyRainfall().load({
"value": value,
"begin_year": begin_year,
"end_year": end_year,
}))


@app.route(f"{swagger.template['basePath']}/rainfall/normal")
@swag_from(normal_specs.route_specs)
def normal_rainfall() -> Response:
return jsonify(all_rainfall.yearly_rainfall.get_normal(
begin_year=request.args.get(*Parameter.BEGIN_YEAR.value))
)
begin_year: int = request.args.get(*Parameter.BEGIN_YEAR.value)
value: float = all_rainfall.yearly_rainfall.get_normal(begin_year)

return jsonify(model.NormalYearlyRainfall().load({
"value": value,
"begin_year": begin_year,
"end_year": begin_year + 29
}))


@app.route(f"{swagger.template['basePath']}/rainfall/relative_distance_to_normal")
@swag_from(relative_distance_to_normal_specs.route_specs)
def rainfall_relative_distance_to_normal() -> Response:
return jsonify(all_rainfall.yearly_rainfall.get_relative_distance_from_normal(
normal_year=request.args.get(*Parameter.NORMAL_YEAR.value),
begin_year=request.args.get(*Parameter.BEGIN_YEAR.value),
end_year=request.args.get(*Parameter.END_YEAR.value)
))
normal_year: int = request.args.get(*Parameter.NORMAL_YEAR.value)
begin_year: int = request.args.get(*Parameter.BEGIN_YEAR.value)
end_year: int = request.args.get(*Parameter.END_YEAR.value)
value: float = all_rainfall.yearly_rainfall.get_relative_distance_from_normal(
normal_year,
begin_year,
end_year
)

return jsonify(model.RelativeDistanceToNormalYearlyRainfall().load({
"value": value,
"begin_year": begin_year,
"end_year": end_year,
}))


@app.route(f"{swagger.template['basePath']}/rainfall/standard_deviation")
@swag_from(standard_deviation_specs.route_specs)
def standard_deviation() -> Response:
return jsonify(all_rainfall.yearly_rainfall.get_standard_deviation(
begin_year=request.args.get(*Parameter.BEGIN_YEAR.value),
end_year=request.args.get(*Parameter.END_YEAR.value)
))
begin_year: int = request.args.get(*Parameter.BEGIN_YEAR.value)
end_year: int = request.args.get(*Parameter.END_YEAR.value)
value: float = all_rainfall.yearly_rainfall.get_standard_deviation(begin_year, end_year)

return jsonify(model.StandardDeviationYearlyRainfall().load({
"value": value,
"begin_year": begin_year,
"end_year": end_year,
}))


@app.route(f"{swagger.template['basePath']}/year/below_normal")
@swag_from(below_normal_specs.route_specs)
def years_below_normal() -> Response:
return jsonify(all_rainfall.yearly_rainfall.get_years_below_normal(
normal_year=request.args.get(*Parameter.NORMAL_YEAR.value),
begin_year=request.args.get(*Parameter.BEGIN_YEAR.value),
end_year=request.args.get(*Parameter.END_YEAR.value)
))
normal_year: int = request.args.get(*Parameter.NORMAL_YEAR.value)
begin_year: int = request.args.get(*Parameter.BEGIN_YEAR.value)
end_year: int = request.args.get(*Parameter.END_YEAR.value)
value: float = all_rainfall.yearly_rainfall.get_years_below_normal(
normal_year,
begin_year,
end_year
)

return jsonify(model.YearsBelowNormalSchema().load({
"value": value,
"begin_year": begin_year,
"end_year": end_year,
}))


@app.route(f"{swagger.template['basePath']}/year/above_normal")
@swag_from(above_normal_specs.route_specs)
def years_above_normal() -> Response:
return jsonify(all_rainfall.yearly_rainfall.get_years_above_normal(
normal_year=request.args.get(*Parameter.NORMAL_YEAR.value),
begin_year=request.args.get(*Parameter.BEGIN_YEAR.value),
end_year=request.args.get(*Parameter.END_YEAR.value)
))
normal_year: int = request.args.get(*Parameter.NORMAL_YEAR.value)
begin_year: int = request.args.get(*Parameter.BEGIN_YEAR.value)
end_year: int = request.args.get(*Parameter.END_YEAR.value)
value: float = all_rainfall.yearly_rainfall.get_years_above_normal(
normal_year,
begin_year,
end_year
)

return jsonify(model.YearsAboveNormalSchema().load({
"value": value,
"begin_year": begin_year,
"end_year": end_year,
}))


if __name__ == '__main__':
Expand Down
1 change: 1 addition & 0 deletions src/core/utils/enums/seasons.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Provides list of Month (Enum) equivalents for all four seasons of the year.
"""

from enum import Enum

from src.core.utils.enums.months import Month
Expand Down
14 changes: 14 additions & 0 deletions src/core/utils/enums/time_modes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""
Provides list of Time modes (Enum) to inform on what timeframe is used on current rainfall data.
"""

from enum import Enum


class TimeMode(str, Enum):
"""
An enum listing time modes (yearly, monthly and seasonal) represented by strings.
"""
YEARLY: str = 'yearly'
SEASONAL: str = 'seasonal'
MONTHLY: str = 'monthly'
2 changes: 1 addition & 1 deletion src/core/utils/functions/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,5 @@ def get_normal(yearly_rainfall: pd.DataFrame, begin_year) -> float:
return get_average_rainfall(
df_opr.get_rainfall_within_year_interval(yearly_rainfall,
begin_year,
begin_year + 30)
begin_year + 29)
)

0 comments on commit 99b015c

Please sign in to comment.