Merge pull request #1290 from Hestia-Homes/fix/building-part-int-identifier

Tolerate non-string building-part identifier (fix TypeError, cohort cert)
This commit is contained in:
Jun-te Kim 2026-06-24 11:59:31 +01:00 committed by GitHub
commit e9a8ad9cd9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 34 additions and 4 deletions

View file

@ -35,15 +35,18 @@ class BuildingPartIdentifier(Enum):
OTHER = "other"
@classmethod
def from_api_string(cls, api_identifier: Optional[str]) -> "BuildingPartIdentifier":
def from_api_string(
cls, api_identifier: Optional[object]
) -> "BuildingPartIdentifier":
"""Map a gov-EPC API `BuildingPart.identifier` to its canonical
member. "Main Dwelling" MAIN; "Extension N" EXTENSION_N
(for N in 1..4). `None` (permitted by the 21_0_1 schema) and
anything unrecognised fall to OTHER.
(for N in 1..4). `None` (permitted by the 21_0_1 schema), a non-string
identifier (some SAP-16.x certs lodge a bare int), and anything else
unrecognised fall to OTHER.
"""
if api_identifier == "Main Dwelling":
return cls.MAIN
if api_identifier is not None:
if isinstance(api_identifier, str):
match = _API_EXTENSION.match(api_identifier)
if match is not None:
return cls.extension(int(match.group(1)))

View file

@ -0,0 +1,27 @@
from __future__ import annotations
from datatypes.epc.domain.epc_property_data import BuildingPartIdentifier
def test_main_dwelling_maps_to_main() -> None:
assert BuildingPartIdentifier.from_api_string("Main Dwelling") == (
BuildingPartIdentifier.MAIN
)
def test_extension_string_maps_to_numbered_extension() -> None:
assert BuildingPartIdentifier.from_api_string("Extension 2") == (
BuildingPartIdentifier.EXTENSION_2
)
def test_none_falls_to_other() -> None:
assert BuildingPartIdentifier.from_api_string(None) == BuildingPartIdentifier.OTHER
def test_non_string_identifier_falls_to_other_not_crash() -> None:
# Some SAP-16.x certs lodge a bare int building-part identifier (e.g. the
# second part as `1` after "Main Dwelling"). This previously raised
# `TypeError: expected string or bytes-like object, got 'int'` and failed
# the whole property — now it falls to OTHER like any unrecognised value.
assert BuildingPartIdentifier.from_api_string(1) == BuildingPartIdentifier.OTHER