Skip to content

Commit

Permalink
cleanup: move config to python code
Browse files Browse the repository at this point in the history
  • Loading branch information
franciscobmacedo committed May 30, 2024
1 parent 44a67bf commit 4445aa5
Show file tree
Hide file tree
Showing 18 changed files with 429 additions and 504 deletions.
15 changes: 5 additions & 10 deletions dm_regional_app/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from dm_regional_app.forms import HistoricDataFilter, PredictFilter
from dm_regional_app.models import SavedScenario, SessionScenario
from dm_regional_app.utils import apply_filters
from ssda903 import Config
from ssda903.config import PlacementCategories
from ssda903.population_stats import PopulationStats
from ssda903.predictor import predict
from ssda903.reader import read_data
Expand Down Expand Up @@ -146,8 +146,7 @@ def prediction(request):
else:
empty_dataframe = False

config = Config()
stats = PopulationStats(historic_data, config)
stats = PopulationStats(historic_data)

# Call predict function with default dates
prediction = predict(
Expand Down Expand Up @@ -181,7 +180,6 @@ def historic_data(request):
if "session_scenario_id" in request.session:
pk = request.session["session_scenario_id"]
session_scenario = get_object_or_404(SessionScenario, pk=pk)
config = Config()
# read data
datacontainer = read_data(source=settings.DATA_SOURCE)

Expand Down Expand Up @@ -218,16 +216,13 @@ def historic_data(request):
data = apply_filters(datacontainer.enriched_view, form.initial)

entry_into_care_count = data.loc[
data.placement_type_before
== datacontainer.config.PlacementCategories.NOT_IN_CARE
data.placement_type_before == PlacementCategories.NOT_IN_CARE.value.name
]["CHILD"].nunique()
exiting_care_count = data.loc[
data.placement_type_after
== datacontainer.config.PlacementCategories.NOT_IN_CARE
data.placement_type_after == PlacementCategories.NOT_IN_CARE.value.name
]["CHILD"].nunique()

config = Config()
stats = PopulationStats(data, config)
stats = PopulationStats(data)

chart = historic_chart(stats)

Expand Down
2 changes: 0 additions & 2 deletions ssda903/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from .config import Config
from .datacontainer import DemandModellingDataContainer
from .datastore import StorageDataStore
from .population_stats import PopulationStats

__all__ = [
"DemandModellingDataContainer",
"PopulationStats",
"Config",
"StorageDataStore",
]
7 changes: 5 additions & 2 deletions ssda903/config/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from ._configuration_loader import Config
from ._age_brackets import AgeBrackets
from ._costs import Costs
from ._placement_categories import PlacementCategories

__all__ = ["Config"]
YEAR_IN_DAYS = 365.24
__all__ = ["AgeBrackets", "PlacementCategories", "Costs", "YEAR_IN_DAYS"]
159 changes: 89 additions & 70 deletions ssda903/config/_age_brackets.py
Original file line number Diff line number Diff line change
@@ -1,96 +1,115 @@
import logging
from dataclasses import dataclass
from enum import Enum
from typing import Any, Dict, Optional, Tuple

from ._placement_categories import PlacementCategories
from typing import Optional

logger = logging.getLogger(__name__)


class AgeBrackets(Enum):
def __init__(self, config):
PlacementCategories = config.get("placement_categories", [])
logger.debug("Configuring AgeBracket with %s", config)

self.__index = config["index"]
self.__start = config.get("min", -1)
self.__end = config.get("max", 30)
self.__label = config.get("label", f"{self.start} to {self.end}")
self.__length_in_days = config.get(
"length_in_days", (self.end - self.start) * 365
)
self.__placement_categories = tuple(
[PlacementCategories[cat] for cat in config.get("categories", [])]
+ [PlacementCategories.OTHER]
)
self.__index = config.get("index", 0)
self._value_ = self.__label
DEFAULT_START = -1
DEFAULT_END = 30

@property
def start(self) -> int:
return self.__start

@property
def end(self) -> int:
return self.__end
@dataclass
class AgeBracket:
index: int
_name: Optional[str] = None
start: Optional[int] = DEFAULT_START
end: Optional[int] = DEFAULT_END
_length_in_days: Optional[int] = None

@property
def placement_categories(self) -> Tuple[PlacementCategories]:
return self.__placement_categories
def length_in_days(self):
if self._length_in_days is not None:
return self._length_in_days
return (self.end - self.start) * 365

@property
def label(self):
return self.__label
def name(self):
if self._name is not None:
return self._name
return f"{self.start} to {self.end}"

@property
def index(self):
return self.__index
def daily_probability(self):
return 1 / self.length_in_days

@property
def next(self):
return type(self).for_index(self.index + 1)
def __str__(self):
return self.name

@property
def previous(self):
return type(self).for_index(self.index - 1)
def __repr__(self):
return f"<{self.__class__.__name__}: {self.name}>"

@property
def length_in_days(self):
return self.__length_in_days

@property
def daily_probability(self):
return 1 / self.length_in_days
class AgeBrackets(Enum):
"""
Age Brackets Enum.
@classmethod
def bracket_for_age(cls, age: float) -> Optional["AgeBrackets"]:
for bracket in cls:
if bracket.start <= age < bracket.end:
return bracket
return None
to get a age bracket dataclass:
ab = AgeBrackets.BIRTH_TO_ONE.value
ab will be <AgeBracket: Birth to 1>
@classmethod
def for_index(cls, index: int) -> Optional["AgeBrackets"]:
for bracket in cls:
if bracket.index == index:
return bracket
return None
def __str__(self):
return self.label
if you do AgeBrackets.BIRTH_TO_ONE that's actually the Enum member, not the AgeBracket:
not_ab = AgeBrackets.BIRTH_TO_ONE
not_ab will be <AgeBrackets.BIRTH_TO_ONE: <AgeBracket: Birth to 1>
which is not the same as <AgeBracket: Birth to 1>
def __repr__(self):
return f"<{self.__class__.__name__}.{self.name}: {self.label}>"
to get a age bracket name:
ab_name = AgeBrackets.BIRTH_TO_ONE.value.name
ab_name will be "Birth to 1"
if you do AgeBrackets.BIRTH_TO_ONE.name that's actually the name of the Enum member, not the name of the AgeBracket:
not_ab_name = AgeBrackets.BIRTH_TO_ONE.name
not_ab_name will be "BIRTH_TO_ONE"
which is not the same "Birth to 1"
"""

def __lt__(self, other):
return self.__index < other.__index
BIRTH_TO_ONE = AgeBracket(_name="Birth to 1", end=1, index=0, _length_in_days=365)
ONE_TO_FIVE = AgeBracket(start=1, end=5, index=1)
FIVE_TO_TEN = AgeBracket(start=5, end=10, index=2)
TEN_TO_SIXTEEN = AgeBracket(start=10, end=16, index=3)
SIXTEEN_TO_EIGHTEEN = AgeBracket(_name="16 to 18+", start=16, index=4)

@classmethod
def values(cls) -> list[AgeBracket]:
return [a.value for a in cls._members_by_index()]

def build_age_brackets(config: Dict[str, Any], placement_categories=None):
config = config.copy()
for ix, v in enumerate(config.values()):
v["index"] = ix
if placement_categories:
v["placement_categories"] = placement_categories
@classmethod
def _members_by_index(cls) -> list["AgeBrackets"]:
"""
Returns a list of all members of the enum ordered by index.
"""
return sorted(list(cls.__members__.values()), key=lambda x: x.value.index)

return AgeBrackets("AgeBrackets", config)
@property
def next(self) -> Optional["AgeBrackets"]:
"""
Returns the next AgeBrackets in the enum.
If the current AgeBrackets is the last one, returns None.
"""
members = self._members_by_index()
current_index = members.index(self)
if current_index == len(members) - 1:
return None
return members[current_index + 1]

@property
def previous(self) -> Optional["AgeBrackets"]:
"""
Returns the previous AgeBrackets in the enum.
If the current AgeBrackets is the first one, returns None.
"""
members = self._members_by_index()
current_index = members.index(self)
if current_index == 0:
return None
return members[current_index - 1]

@classmethod
def bracket_for_age(cls, age: float) -> Optional[AgeBracket]:
for bracket in cls:
if bracket.value.start <= age < bracket.value.end:
return bracket.value
return None
107 changes: 0 additions & 107 deletions ssda903/config/_configuration_loader.py

This file was deleted.

Loading

0 comments on commit 4445aa5

Please sign in to comment.