From 66d6266002be0f2b5ee05d4719df43de4e6efcfe Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 14 May 2025 20:17:42 +0100 Subject: [PATCH] fixing unit tests --- recommendations/HeatingRecommender.py | 13 +- .../test_data/heating_recommendations_data.py | 128 ++---------------- recommendations/tests/test_data/materials.py | 24 ++++ .../tests/test_heating_recommendations.py | 10 -- .../tests/test_lighting_recommendations.py | 28 ++-- 5 files changed, 57 insertions(+), 146 deletions(-) diff --git a/recommendations/HeatingRecommender.py b/recommendations/HeatingRecommender.py index 20f5e7ad..18e1110b 100644 --- a/recommendations/HeatingRecommender.py +++ b/recommendations/HeatingRecommender.py @@ -185,17 +185,24 @@ class HeatingRecommender: self.property.main_heating["clean_description"] ]["dual"]["types"] - recommendation_system_types = list(set([x["system_type"] for x in self.heating_recommendations])) + heating_measures = [ + m for m in self.heating_recommendations if + m["measure_type"] not in ["time_temperature_zone_control", "roomstat_programmer_trvs"] + ] + + recommendation_system_types = list( + set([x["system_type"] for x in heating_measures]) + ) # We check if we have the required type if not any([x in recommendation_system_types for x in dual_heating_description]): return type_1_recommendations = [ - x for x in self.heating_recommendations if x["system_type"] == dual_heating_description[0] + x for x in heating_measures if x["system_type"] == dual_heating_description[0] ] type_2_recommendations = [ - x for x in self.heating_recommendations if x["system_type"] == dual_heating_description[1] + x for x in heating_measures if x["system_type"] == dual_heating_description[1] ] # we combine the two recommendations combined_recommendations = [] diff --git a/recommendations/tests/test_data/heating_recommendations_data.py b/recommendations/tests/test_data/heating_recommendations_data.py index 26263826..53f8bd25 100644 --- a/recommendations/tests/test_data/heating_recommendations_data.py +++ b/recommendations/tests/test_data/heating_recommendations_data.py @@ -39,8 +39,7 @@ testing_examples = [ 'fixed-lighting-outlets-count': 10.0, 'low-energy-fixed-light-count': 7.0, 'uprn': 100110195416.0, 'uprn-source': 'Address Matched' }, - "heating_measure_types": ["air_source_heat_pump"], - "heating_controls_measure_types": ["time_temperature_zone_control"], + "heating_measure_types": ["air_source_heat_pump", "time_temperature_zone_control"], "notes": "This property has a boiler, radiators & mains gas with good efficiency so the only recommendation" "we expect here is for an air source heat pump. The heating controls are a programmer, room thermostat" "and TRVs and so we should expect a TTZC recommendation" @@ -89,7 +88,6 @@ testing_examples = [ "heating_measure_types": [ "high_heat_retention_storage_heater", ], - "heating_controls_measure_types": [], "notes": "This property has electric room heaters and is off gas so a boiler recommendation is not appropriate." "We would expect a high heat retention storage recommendation. The property is a flat and therefore" "we don't expect an air source heat pump recommendation. We also wouldn't expect a specific heating" @@ -137,7 +135,6 @@ testing_examples = [ 'uprn': 100090311351.0, 'uprn-source': 'Address Matched', 'property-type_y': None, 'built-form_y': None, }, "heating_measure_types": ['high_heat_retention_storage_heater', 'air_source_heat_pump'], - "heating_controls_measure_types": [], "notes": "This test has electric storage heaters with automatic charge control - we recommend hhr storage" "heaters in this case, but because there are already electic storage heaters in place, we " "note, in the description of the recommendation, that this upgrade may be possible by retrofitting" @@ -181,8 +178,8 @@ testing_examples = [ 'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 100021560521.0, 'uprn-source': 'Address Matched', }, - "heating_measure_types": ['boiler_upgrade'], - "heating_controls_measure_types": [ + "heating_measure_types": [ + 'boiler_upgrade', 'roomstat_programmer_trvs', 'time_temperature_zone_control', ], @@ -231,10 +228,9 @@ testing_examples = [ 'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': 9.0, 'low-energy-fixed-light-count': 5.0, 'uprn': 100021936225.0, 'uprn-source': 'Address Matched', }, - "heating_measure_types": [], - "heating_controls_measure_types": [ + "heating_measure_types": [ 'roomstat_programmer_trvs', - 'time_temperature_zone_control', + 'time_temperature_zone_control' ], "notes": "Because this property already has a boiler, we don't recommend HHR. We don't recommend an ashp " "because the home is mid-terraced. Because the heating controls are " @@ -284,7 +280,6 @@ testing_examples = [ "heating_measure_types": [ 'high_heat_retention_storage_heater', ], - "heating_controls_measure_types": [], "notes": "This property is a flat so we don't have an ASHP recommendation. It also doesn't have access to the " "mains and so it can't have a gas boiler. We don't expect any controls recommendations" }, @@ -326,8 +321,8 @@ testing_examples = [ 'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 100080513604.0, 'uprn-source': 'Address Matched' }, - "heating_measure_types": ['air_source_heat_pump'], - "heating_controls_measure_types": [ + "heating_measure_types": [ + 'air_source_heat_pump', 'roomstat_programmer_trvs', 'time_temperature_zone_control', ], @@ -381,7 +376,6 @@ testing_examples = [ 'high_heat_retention_storage_heater', 'boiler_upgrade' ], - "heating_controls_measure_types": [], "notes": "This property has assumed electric heating and is mid-terrace house. It has a mains gas connection." "We can recommend a boiler upgrade and high heat retention storage heaters" }, @@ -427,7 +421,6 @@ testing_examples = [ 'air_source_heat_pump', 'high_heat_retention_storage_heater', ], - "heating_controls_measure_types": [], "notes": "This property has an oil boiler and doesn't have a mains gas connection so we can only recommend" "an air source heat pump and HHR (since if the home has a non-gas boiler, we recommend HHR)" }, @@ -477,7 +470,6 @@ testing_examples = [ 'air_source_heat_pump', 'boiler_upgrade' # TTZs ], - "heating_controls_measure_types": [], "notes": "This property has room heaters, from the mains gas supply. We recommend a boiler upgrade as" "well as an air source heat pump and HHR (since the home has a room heater set up)" }, @@ -525,7 +517,6 @@ testing_examples = [ 'boiler_upgrade', 'high_heat_retention_storage_heater', ], - "heating_controls_measure_types": [], "notes": "This property has assumed electric heaters. Boiler upgrade, HHR are recommended. We don't recommend" "an ASHP off of the bat because it's mid-terrace." }, @@ -572,7 +563,6 @@ testing_examples = [ 'high_heat_retention_storage_heater', 'boiler_upgrade' ], - "heating_controls_measure_types": [], "notes": "This has a form of assumed electric heating and has a mains connection so we recommend HHR, boiler" "upgrade and ASHP" }, @@ -620,7 +610,6 @@ testing_examples = [ 'boiler_upgrade', 'high_heat_retention_storage_heater', ], - "heating_controls_measure_types": [], "notes": "This property already has storage heaters with manual charge control. The home is mid terrace so" "the ashp is not suitable" }, @@ -668,7 +657,6 @@ testing_examples = [ 'high_heat_retention_storage_heater', 'air_source_heat_pump', ], - "heating_controls_measure_types": [], "notes": "This property has an LFG boiler but it doesn't have a mains gas connection so we can only recommend" "an air source heat pump and hhr storage" }, @@ -714,7 +702,6 @@ testing_examples = [ 'high_heat_retention_storage_heater', 'air_source_heat_pump', ], - "heating_controls_measure_types": [], "notes": "This property has electric boilers in place, but does not have a mains connection so we don't " "recommend a boiler upgrade. We recommend HHR and ASHP" }, @@ -762,7 +749,6 @@ testing_examples = [ 'air_source_heat_pump', 'high_heat_retention_storage_heater' ], - "heating_controls_measure_types": [], "notes": "This property has a dual fuel boiler and no mains gas connection. We recommend ASHP and HHR, but" "no gas condensing boiler" }, @@ -807,7 +793,6 @@ testing_examples = [ 'air_source_heat_pump', 'high_heat_retention_storage_heater', ], - "heating_controls_measure_types": [], "notes": "This property has a coal boiler and no mains gas connection. We recommend ASHP and HHR, but" "no gas condensing boiler" }, @@ -855,7 +840,6 @@ testing_examples = [ 'air_source_heat_pump', 'high_heat_retention_storage_heater', ], - "heating_controls_measure_types": [], "notes": "This property has a smokeless fuel boiler and no mains gas connection. We recommend ASHP and HHR, but" "no gas condensing boiler" }, @@ -901,7 +885,6 @@ testing_examples = [ 'air_source_heat_pump', 'high_heat_retention_storage_heater', ], - "heating_controls_measure_types": [], "notes": "This property has a wood pellets boiler and no mains gas connection. We recommend ASHP and HHR, but" "no gas condensing boiler" }, @@ -948,7 +931,6 @@ testing_examples = [ 'high_heat_retention_storage_heater', 'air_source_heat_pump', ], - "heating_controls_measure_types": [], "notes": "This is an end-terrace house, without mains gas connection, so we recommend is HHR & ASHP" }, { @@ -990,7 +972,6 @@ testing_examples = [ 'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None }, "heating_measure_types": [], - "heating_controls_measure_types": [], "notes": "This property already has an ashp. We don't recommend any heating upgrades" }, { @@ -1032,9 +1013,7 @@ testing_examples = [ }, "heating_measure_types": [ 'air_source_heat_pump', - 'high_heat_retention_storage_heater' - ], - "heating_controls_measure_types": [ + 'high_heat_retention_storage_heater', 'time_temperature_zone_control', ], "notes": "This property has dual heating. A boiler and electric storage heaters. The heating is efficient so" @@ -1081,9 +1060,7 @@ testing_examples = [ 'air_source_heat_pump', 'boiler_upgrade', 'boiler_upgrade+high_heat_retention_storage_heater', - 'high_heat_retention_storage_heater' - ], - "heating_controls_measure_types": [ + 'high_heat_retention_storage_heater', 'time_temperature_zone_control' ], "notes": "This property is a modified version of the previous dual heating property, where we lower the" @@ -1132,7 +1109,6 @@ testing_examples = [ 'air_source_heat_pump', 'high_heat_retention_storage_heater' ], - "heating_controls_measure_types": [], "notes": "This property has anthracite heating without mains. " "We recommend ASHP and HHR, but no gas condensing boiler" }, @@ -1180,7 +1156,6 @@ testing_examples = [ 'boiler_upgrade', 'high_heat_retention_storage_heater' ], - "heating_controls_measure_types": [], "notes": "This property has room heaters with two different fuel sources, so we recommend HHR, ASHP, and a " "boiler upgrade" }, @@ -1224,7 +1199,6 @@ testing_examples = [ "heating_measure_types": [ 'high_heat_retention_storage_heater' ], - "heating_controls_measure_types": [], "notes": "This property is a flag, without mains gas connection. Currently has underfloor electric heating" "so we recommend HHR" }, @@ -1272,7 +1246,6 @@ testing_examples = [ 'boiler_upgrade', 'high_heat_retention_storage_heater' ], - "heating_controls_measure_types": [], "notes": "The property has warm air electricaire heating, so we recommend ASHP and HHR. It also has a mains" "connection so we recommend a gas condensing boiler" }, @@ -1320,89 +1293,6 @@ testing_examples = [ 'boiler_upgrade', 'boiler_upgrade', ], - "heating_controls_measure_types": [], "notes": "This property has warm air mains gas heating, so we recommend a gas condensing boiler" } ] - -# import random -# from pathlib import Path -# import inspect -# import pandas as pd -# -# # this can be used to get example data to build the test cases -# src_file_path = inspect.getfile(lambda: None) -# EPC_DIRECTORY = Path(src_file_path).parent / "local_data" / "all-domestic-certificates" -# epc_directories = [entry for entry in EPC_DIRECTORY.iterdir() if entry.is_dir()] -# directory = random.sample(epc_directories, 1)[0] -# data = pd.read_csv(directory / "certificates.csv", low_memory=False) -# # Rename the columns to the same format as the api returns -# data.columns = [c.replace("_", "-").lower() for c in data.columns] -# data["floor-height"] = data["floor-height"].fillna(2.45) -# -# used_examples = pd.DataFrame( -# [ -# { -# "mainheat-description": x["epc"]["mainheat-description"], -# "mainheat-energy-eff": x["epc"]["mainheat-energy-eff"], -# "property-type": x["epc"]["property-type"], -# "built-form": x["epc"]["built-form"], -# "used": True -# } for x in testing_examples -# ] -# ) -# -# data = data.merge( -# used_examples, how="left", on=["mainheat-description", "mainheat-energy-eff", "built-form", "property-type"] -# ) -# data = data[pd.isnull(data["used"])].drop(columns=["used"]) -# -# eg = data.sample(1).to_dict("records")[0] -# print(eg["mainheat-description"]) -# print(eg["mainheat-energy-eff"]) -# print(eg["property-type"]) -# print(eg["built-form"]) -# print(eg["mainheatcont-description"]) -# -# ### We also use the Midlands EPC F/G portfolio to get examples to create tests -# -# completed_descriptions = [ -# "Portable electric heaters assumed for most rooms", -# "Boiler and radiators, oil", -# "Boiler and radiators, mains gas", -# "Room heaters, mains gas", -# "No system present: electric heaters assumed", -# "Room heaters, electric", -# "Electric storage heaters", -# "Boiler and radiators, LPG", -# "Boiler and radiators, electric", -# "Boiler and radiators, dual fuel (mineral and wood)", -# "Boiler and radiators, coal", -# "Boiler and radiators, smokeless fuel", -# "Boiler and radiators, wood pellets", -# "Room heaters, dual fuel (mineral and wood)", -# "Air source heat pump, radiators, electric", -# "Portable electric heaters assumed for most rooms, Room heaters, electric", -# "Boiler and radiators, mains gas, Electric storage heaters", -# "Room heaters, anthracite", -# "Room heaters, mains gas, Room heaters, dual fuel (mineral and wood)", -# "Electric underfloor heating", -# "Warm air, Electricaire" -# ] -# -# portfolio = pd.read_excel( -# "/Users/khalimconn-kowlessar/Documents/hestia/Customers/sfr/20240820 portfolio_epc_data.xlsx" -# ) -# portfolio.columns = [c.replace("_", "-").lower() for c in portfolio.columns] -# portfolio = portfolio[~portfolio["mainheat-description"].isin(completed_descriptions)] -# portfolio['sheating-energy-eff'] = None -# portfolio['sheating-env-eff'] = None -# portfolio["lodgement-datetime"] = portfolio["lodgement-datetime"].astype(str) -# -# print(portfolio["mainheat-description"].value_counts()) -# -# eg = portfolio[ -# (portfolio["mainheat-description"] == "Warm air, mains gas") -# ].sample(1) -# eg = eg.squeeze().to_dict() -# print(eg) diff --git a/recommendations/tests/test_data/materials.py b/recommendations/tests/test_data/materials.py index 194971e9..13b1ea08 100644 --- a/recommendations/tests/test_data/materials.py +++ b/recommendations/tests/test_data/materials.py @@ -1,6 +1,30 @@ import datetime materials = [ + { + 'id': 2484, + 'type': 'room_roof_insulation', + 'description': 'Room in roof insulation', + 'depth': 100, + 'depth_unit': 'mm', + 'cost_unit': 'gbp_per_m2', + 'r_value_per_mm': 0.038, + 'r_value_unit': 'square_meter_kelvin_per_watt', + 'thermal_conductivity': 0.022, + 'thermal_conductivity_unit': 'watt_per_meter_kelvin', + 'link': 'SCIS', + 'created_at': '2025-03-16 15:26:22.379', + 'cost': None, + 'is_active': True, + 'prime_material_cost': None, + 'material_cost': 0.0, + 'labour_cost': 0.0, + 'labour_hours_per_unit': 0.0, + 'plant_cost': 0.0, + 'total_cost': 210.0, + 'notes': None, + 'is_installer_quote': True + }, {'id': 1997, 'type': 'cavity_wall_insulation', 'description': 'Imperial Bead cavity wall insulation', 'depth': 75.0, 'depth_unit': 'mm', 'cost': None, 'cost_unit': 'gbp_per_m2', 'r_value_per_mm': 0.030303031, 'r_value_unit': 'square_meter_kelvin_per_watt', 'thermal_conductivity': 0.033, diff --git a/recommendations/tests/test_heating_recommendations.py b/recommendations/tests/test_heating_recommendations.py index ed2e037d..b1ac4d18 100644 --- a/recommendations/tests/test_heating_recommendations.py +++ b/recommendations/tests/test_heating_recommendations.py @@ -92,23 +92,13 @@ class TestHeatingRecommendations: recommender = HeatingRecommender(property_instance=p) # Check they're empty assert not recommender.heating_recommendations - assert not recommender.heating_control_recommendations recommender.recommend(has_cavity_or_loft_recommendations=False) assert len(recommender.heating_recommendations) == len(test_case["heating_measure_types"]) - assert ( - len(recommender.heating_control_recommendations) == - len(test_case["heating_controls_measure_types"]) - ) # Check the exact measure types assert ( {x["measure_type"] for x in recommender.heating_recommendations} == set(test_case["heating_measure_types"]) ) - - assert ( - {x["measure_type"] for x in recommender.heating_control_recommendations} == - set(test_case["heating_controls_measure_types"]) - ) diff --git a/recommendations/tests/test_lighting_recommendations.py b/recommendations/tests/test_lighting_recommendations.py index 32d607de..4b1e1d84 100644 --- a/recommendations/tests/test_lighting_recommendations.py +++ b/recommendations/tests/test_lighting_recommendations.py @@ -41,18 +41,18 @@ class TestLightingRecommendations: assert len(lr.recommendation) == 1 assert lr.recommendation == [ - { - 'phase': 0, 'parts': [], 'type': 'low_energy_lighting', 'measure_type': 'low_energy_lighting', - 'description': 'Install low energy lighting in 4 outlets', 'starting_u_value': None, - 'new_u_value': None, - 'already_installed': False, 'sap_points': 0.4, 'kwh_savings': 219.0, 'co2_equivalent_savings': 0.035478, - 'description_simulation': { - 'lighting-energy-eff': 'Very Good', - 'lighting-description': 'Low energy lighting in all fixed outlets', - 'low-energy-lighting': 100 - }, - 'total': 240.24, 'subtotal': 200.20000000000002, - 'vat': 40.040000000000006, 'contingency': 14.3, 'preliminaries': 14.3, 'material': 80.0, 'profit': 28.6, - 'labour_hours': 3.2, 'labour_days': 0.4, 'labour_cost': 63.0, 'survey': False - } + {'phase': 0, 'parts': [], 'type': 'low_energy_lighting', 'measure_type': 'low_energy_lighting', + 'description': 'Install low energy lighting in 4 outlets', 'starting_u_value': None, 'new_u_value': None, + 'already_installed': False, 'sap_points': 0.4, 'kwh_savings': 219.0, 'energy_cost_savings': 54.4434, + 'co2_equivalent_savings': 0.035478, 'description_simulation': { + 'lighting-energy-eff': 'Very Good', + 'lighting-description': 'Low energy ' + 'lighting in all ' + 'fixed outlets', + 'low-energy-lighting': 100 + }, + 'total': 240.24, + 'subtotal': 200.20000000000002, 'vat': 40.040000000000006, 'contingency': 14.3, 'preliminaries': 14.3, + 'material': 80.0, 'profit': 28.6, 'labour_hours': 3.2, 'labour_days': 0.4, 'labour_cost': 63.0, + 'survey': False} ]