diff --git a/model_data/epc_attributes/FloorAttributes.py b/model_data/epc_attributes/FloorAttributes.py index 394a2d54..b5514cbb 100644 --- a/model_data/epc_attributes/FloorAttributes.py +++ b/model_data/epc_attributes/FloorAttributes.py @@ -1,20 +1,27 @@ -from typing import Dict, Union, Optional +from typing import Dict, Union +from model_data.BaseUtility import BaseUtility from model_data.epc_attributes.attribute_utils import extract_thermal_transmittance, extract_component_types -class FloorAttributes: +class FloorAttributes(BaseUtility): DWELLING_BELOW = ["another dwelling below", "other premises below"] FLOOR_TYPES = ["assumed", "to unheated space", "to external air", "suspended", "solid"] def __init__(self, description: str): self.description: str = description.lower() + self.nodata = not description or description in self.DATA_ANOMALY_MATCHES + if not description or not any( rt in self.description for rt in self.FLOOR_TYPES + self.DWELLING_BELOW + ["average thermal transmittance"] ): raise ValueError('Invalid description') def process(self) -> Dict[str, Union[str, bool, int, None]]: + + if self.nodata: + return {} + result: Dict[str, Union[float, str, bool, None]] = {} description = self.description diff --git a/model_data/epc_attributes/HotWaterAttributes.py b/model_data/epc_attributes/HotWaterAttributes.py index 65a85185..20133f7b 100644 --- a/model_data/epc_attributes/HotWaterAttributes.py +++ b/model_data/epc_attributes/HotWaterAttributes.py @@ -1,8 +1,9 @@ from typing import Dict, Union -from model_data.epc_attributes.attribute_utils import clean_description, remove_punctuation, find_keyword +from model_data.BaseUtility import BaseUtility +from model_data.epc_attributes.attribute_utils import clean_description, find_keyword -class HotWaterAttributes: +class HotWaterAttributes(BaseUtility): # HEATER_TYPES refer to the main devices used for heating water. These devices can be powered by different energy # sources. HEATER_TYPES = [ @@ -78,6 +79,8 @@ class HotWaterAttributes: def __init__(self, description: str): self.description: str = clean_description(description.lower()) + self.nodata = not description or description in self.DATA_ANOMALY_MATCHES + if not any( self._keyword_in_description(keywords) for keywords in [ @@ -98,6 +101,22 @@ class HotWaterAttributes: return any(keyword in self.description for keyword in keywords) def process(self) -> Dict[str, Union[str, bool]]: + + if self.nodata: + return { + "heater_type": None, + "system_type": None, + "thermostat_characteristics": None, + "heating_scope": None, + "energy_recovery": None, + "tariff_type": None, + "extra_features": None, + "chp_systems": None, + "distribution_system": None, + "no_system_present": None, + "assumed": None, + } + result: Dict[str, Union[str, bool]] = { "heater_type": find_keyword(self.description, self.HEATER_TYPES), "system_type": find_keyword(self.description, self.SYSTEM_TYPES), diff --git a/model_data/epc_attributes/MainheatAttributes.py b/model_data/epc_attributes/MainheatAttributes.py index c03efec8..2154b64f 100644 --- a/model_data/epc_attributes/MainheatAttributes.py +++ b/model_data/epc_attributes/MainheatAttributes.py @@ -1,8 +1,9 @@ +from model_data.BaseUtility import BaseUtility from model_data.epc_attributes.attribute_utils import clean_description, process_part from typing import Dict, Union -class MainHeatAttributes: +class MainHeatAttributes(BaseUtility): HEAT_SYSTEMS = ["boiler", "air source heat pump", "room heaters", "electric storage heaters", "warm air", "electric underfloor heating", "electric ceiling heating", "community scheme", "ground source heat pump", "no system present", "portable electric heaters", @@ -16,6 +17,7 @@ class MainHeatAttributes: def __init__(self, description: str): self.description: str = clean_description(description.lower()) # Remove special characters + self.nodata = not description or description in self.DATA_ANOMALY_MATCHES if not description or not any( rt in self.description for rt in @@ -31,6 +33,9 @@ class MainHeatAttributes: result.update({f'has_{ot.replace(" ", "_")}': False for ot in self.OTHERS}) result['has_underfloor_heating'] = False + if self.nodata: + return result + description = self.description.split(',') # Process each part separately diff --git a/model_data/epc_attributes/MainheatControlAttributes.py b/model_data/epc_attributes/MainheatControlAttributes.py index 4c997feb..b325a85f 100644 --- a/model_data/epc_attributes/MainheatControlAttributes.py +++ b/model_data/epc_attributes/MainheatControlAttributes.py @@ -1,8 +1,9 @@ from typing import Dict, Union -from model_data.epc_attributes.attribute_utils import clean_description, remove_punctuation, find_keyword +from model_data.BaseUtility import BaseUtility +from model_data.epc_attributes.attribute_utils import clean_description, find_keyword -class MainheatControlAttributes: +class MainheatControlAttributes(BaseUtility): # These systems allow for the automatic regulation of temperature THERMOSTATIC_CONTROL_KEYWORDS = [ 'room thermostats', @@ -67,7 +68,7 @@ class MainheatControlAttributes: def __init__(self, description: str): self.description: str = clean_description(description.lower()) - self.nodata = not description + self.nodata = not description or description in self.DATA_ANOMALY_MATCHES if not self.nodata: if not any( diff --git a/model_data/epc_attributes/RoofAttributes.py b/model_data/epc_attributes/RoofAttributes.py index 02379f8c..af56cdbb 100644 --- a/model_data/epc_attributes/RoofAttributes.py +++ b/model_data/epc_attributes/RoofAttributes.py @@ -1,9 +1,10 @@ import re from typing import Dict, Union +from model_data.BaseUtility import BaseUtility from model_data.epc_attributes.attribute_utils import extract_component_types, extract_thermal_transmittance -class RoofAttributes: +class RoofAttributes(BaseUtility): ROOF_TYPES = ['pitched', 'roof room', 'loft', 'flat', 'thatched', 'at rafters', 'assumed'] DWELLING_ABOVE = ["another dwelling above", "other premises above"] @@ -13,6 +14,7 @@ class RoofAttributes: """ self.description: str = description.lower() + self.nodata = not description or description in self.DATA_ANOMALY_MATCHES if not description or not any( rt in self.description for rt in self.ROOF_TYPES + self.DWELLING_ABOVE + ["average thermal transmittance"] @@ -22,6 +24,10 @@ class RoofAttributes: def process(self) -> Dict[str, Union[float, str, bool, None]]: result: Dict[str, Union[float, str, bool, None]] = {} + + if self.nodata: + return result + description = self.description # thermal transmittance diff --git a/model_data/epc_attributes/WallAttributes.py b/model_data/epc_attributes/WallAttributes.py index cd38559d..5b8226dd 100644 --- a/model_data/epc_attributes/WallAttributes.py +++ b/model_data/epc_attributes/WallAttributes.py @@ -1,8 +1,9 @@ from typing import Dict, Union +from model_data.BaseUtility import BaseUtility from model_data.epc_attributes.attribute_utils import extract_component_types, extract_thermal_transmittance -class WallAttributes: +class WallAttributes(BaseUtility): WALL_TYPES = ['cavity wall', 'filled cavity', 'solid brick', 'system built', 'timber frame', 'granite or whinstone', 'as built', 'cob', 'assumed', 'sandstone or limestone'] @@ -12,8 +13,13 @@ class WallAttributes: """ self.description: str = description + self.nodata = not description or description in self.DATA_ANOMALY_MATCHES + def process(self) -> Dict[str, Union[float, str, bool, None]]: result: Dict[str, Union[float, str, bool, None]] = {} + if self.nodata: + return result + description = self.description.lower() # thermal transmittance - it can be negative which is errneous however we'll still pull it out diff --git a/model_data/epc_attributes/WindowAttributes.py b/model_data/epc_attributes/WindowAttributes.py index 3aeaddc8..8b087cb1 100644 --- a/model_data/epc_attributes/WindowAttributes.py +++ b/model_data/epc_attributes/WindowAttributes.py @@ -1,8 +1,9 @@ from typing import Dict, Union +from model_data.BaseUtility import BaseUtility from model_data.epc_attributes.attribute_utils import clean_description -class WindowAttributes: +class WindowAttributes(BaseUtility): GLAZING_KEYWORDS = ["glazing", "glazed", "glaze"] GLAZING_COVERAGE = ["fully", "mostly", "partial", "some", "full", "thoughout"] GLAZING_TYPES = ["double", "triple", "secondary", "multiple", "high performance", "single"] @@ -21,7 +22,7 @@ class WindowAttributes: # In the case of an empty description, we want to return a dictionary with all values set to False # and indicate there was no data - self.nodata = not description + self.nodata = not description or description in self.DATA_ANOMALY_MATCHES if not self.nodata: if not any(