Strict-raise on an unrecognised PasHub main-heating Fuel label 🟥

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Roth 2026-07-14 14:30:49 +00:00
parent 02ad8701d3
commit 1fead6e4c7
2 changed files with 46 additions and 0 deletions

View file

@ -7030,6 +7030,30 @@ def _elmhurst_main_fuel_int(fuel_type: str) -> Optional[int]:
return _ELMHURST_MAIN_FUEL_TO_SAP10.get(fuel_type)
class UnmappedPasHubLabel(ValueError):
"""A PasHub Site-Notes survey lodged a finite-enum label that the mapper
does not yet know how to translate to the SAP10 cascade enum.
Raised by the strict PasHub label-to-code helpers to surface mapper-
coverage gaps at the `from_site_notes` boundary (ADR-0015) instead of
passing the raw string downstream, where it resurfaces as the
calculator's deep `MissingMainFuelType` raise — or worse, is silently
mis-billed. Mirrors `UnmappedApiCode` / `UnmappedElmhurstLabel`.
Distinguish "lodging absent" (a genuinely blank cell the helper returns
it unchanged, correct) from "lodging present but unrecognised" (raise
a Fuel label the lookup doesn't yet cover, needs a dict entry added).
"""
def __init__(self, field: str, value: str) -> None:
super().__init__(
f"unmapped PasHub {field} label: {value!r}; "
f"add an entry to the corresponding mapper lookup dict"
)
self.field = field
self.value = value
# PasHub Site-Notes surveyed main-heating "Fuel" labels mapped to SAP10 fuel
# codes (the epc-codes `main_fuel` enum the calculator's resolver routes via
# its API→Table-12/32 translation). Seeded only with labels confirmed from

View file

@ -820,3 +820,25 @@ class TestElmhurstSecondaryFuelFromSapCode:
# Act / Assert
with pytest.raises(UnmappedElmhurstLabel):
_elmhurst_secondary_fuel_from_sap_code(620)
class TestPasHubUnmappedMainFuel:
"""A PasHub survey whose surveyed main-heating Fuel label the mapper does
not yet cover must strict-raise `UnmappedPasHubLabel` at the boundary,
naming the label so a coverage gap is fixed here (a one-line lookup
addition) rather than passed downstream as a raw string to resurface as
the calculator's `MissingMainFuelType`, or silently mis-billed.
"""
def test_unrecognised_fuel_label_raises_naming_the_label(self) -> None:
# Arrange — an example fixture whose Fuel cell carries a label the
# PasHub lookup does not yet know.
from datatypes.epc.domain.mapper import UnmappedPasHubLabel
raw = load("pashub_rdsap_site_notes_example1.json")
raw["heating_and_hot_water"]["main_heating"]["fuel"] = "Anthracite"
survey = from_dict(PasHubRdSapSiteNotes, raw)
# Act / Assert
with pytest.raises(UnmappedPasHubLabel, match="Anthracite"):
EpcPropertyDataMapper.from_site_notes(survey)