mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
82 lines
3.3 KiB
Python
82 lines
3.3 KiB
Python
from pydantic import BaseModel, Field, BeforeValidator
|
|
from typing import Annotated, List, Optional
|
|
|
|
# Example constants for validation
|
|
TYPICAL_MEASURE_TYPES = [
|
|
"wall_insulation", "roof_insulation", "ventilation", "floor_insulation",
|
|
"windows", "fireplace", "heating", "hot_water", "low_energy_lighting",
|
|
"secondary_heating", "solar_pv"
|
|
]
|
|
|
|
SPECIFIC_MEASURES = [
|
|
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation",
|
|
"loft_insulation", "flat_roof_insulation", "room_roof_insulation",
|
|
"suspended_floor_insulation", "solid_floor_insulation",
|
|
"boiler_upgrade", "high_heat_retention_storage_heater", "air_source_heat_pump",
|
|
"secondary_heating", "solar_pv", "double_glazing", "secondary_glazing",
|
|
"ventilation", "low_energy_lighting", "fireplace", "hot_water"
|
|
]
|
|
|
|
NON_INVASIVE_SPECIFIC_MEASURES = [
|
|
"trickle_vents", "draught_proofing", "mixed_glazing", "cavity_extract_and_refill",
|
|
"extension_cavity_wall_insulation"
|
|
]
|
|
|
|
# This allows us to extend high level categories for measures such as "wall_insulation" to the specific measures
|
|
# such as "external_wall_insulation", "internal_wall_insulation", "cavity_wall_insulation"
|
|
MEASURE_MAP = {
|
|
"wall_insulation": [
|
|
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation",
|
|
],
|
|
"roof_insulation": ["loft_insulation", "flat_roof_insulation", "room_roof_insulation"],
|
|
"floor_insulation": ["suspended_floor_insulation", "solid_floor_insulation"],
|
|
"heating": ["boiler_upgrade", "high_heat_retention_storage_heater", "air_source_heat_pump"],
|
|
"windows": ["double_glazing", "secondary_glazing"],
|
|
"heating_controls": ["roomstat_programmer_trvs", "time_temperature_zone_control"]
|
|
}
|
|
|
|
VALID_GOALS = ["Increasing EPC"]
|
|
VALID_HOUSING_TYPES = ["Social", "Private"]
|
|
|
|
|
|
# Define the validation function for inclusions/exclusions
|
|
def check_inclusion_or_exclusion(value: str) -> str:
|
|
if value not in TYPICAL_MEASURE_TYPES + SPECIFIC_MEASURES + NON_INVASIVE_SPECIFIC_MEASURES:
|
|
raise ValueError(f"{value} is not an allowed inclusion")
|
|
return value
|
|
|
|
|
|
def check_goals(value: str) -> str:
|
|
assert value in VALID_GOALS, f"{value} is not a valid goal"
|
|
return value
|
|
|
|
|
|
def check_housing_type(value: str) -> str:
|
|
assert value in VALID_HOUSING_TYPES, f"{value} is not a valid housing type"
|
|
return value
|
|
|
|
|
|
# Use Annotated with BeforeValidator for each list item validation
|
|
InclusionOrExclusionItem = Annotated[str, BeforeValidator(check_inclusion_or_exclusion)]
|
|
Goal = Annotated[str, BeforeValidator(check_goals)]
|
|
HousingType = Annotated[str, BeforeValidator(check_housing_type)]
|
|
|
|
|
|
class PlanTriggerRequest(BaseModel):
|
|
budget: Optional[float] = None
|
|
goal: Goal
|
|
housing_type: HousingType
|
|
goal_value: str
|
|
portfolio_id: int
|
|
trigger_file_path: str
|
|
already_installed_file_path: Optional[str] = None
|
|
patches_file_path: Optional[str] = None
|
|
non_invasive_recommendations_file_path: Optional[str] = None
|
|
valuation_file_path: Optional[str] = None
|
|
exclusions: Optional[List[InclusionOrExclusionItem]] = Field(default=None, min_length=1)
|
|
inclusions: Optional[List[InclusionOrExclusionItem]] = Field(default=None, min_length=1)
|
|
|
|
scenario_name: Optional[str] = ""
|
|
multi_plan: Optional[bool] = False
|
|
optimise: Optional[bool] = True
|
|
default_u_values: Optional[bool] = True
|