mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
Two review points from @dancafc: 1) Rename the `Comparable` dataclass → `ComparableProperty` (it models one comparable *property*; the collection stays `ComparableProperties`). Applied across domain, repositories, orchestration, harness, scripts, and tests with a word-boundary rename so `ComparableProperties` is untouched. 2) Move `PredictionTarget` out of comparable_properties.py into prediction_target.py (where `PredictionTargetAttributes` + `build_prediction_target` already live). comparable_properties.py now imports it; no import cycle (prediction_target no longer depends on comparable_properties). Importers updated. 92 tests pass across the touched suites; pyright strict clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
56 lines
1.9 KiB
Python
56 lines
1.9 KiB
Python
"""Assembling an EPC-less Property's PredictionTarget, and the eligibility gate:
|
|
a Property whose property type is unknown is not predicted (ADR-0031 slice-5d)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Optional
|
|
|
|
from domain.epc_prediction.prediction_target import (
|
|
PredictionTarget,
|
|
PredictionTargetAttributes,
|
|
build_prediction_target,
|
|
)
|
|
from domain.geospatial.coordinates import Coordinates
|
|
from domain.property.property import PropertyIdentity
|
|
|
|
|
|
def _identity(postcode: str = "LS6 1AA") -> PropertyIdentity:
|
|
return PropertyIdentity(
|
|
portfolio_id=1, postcode=postcode, address="1 Some Street", uprn=12345
|
|
)
|
|
|
|
|
|
def test_target_is_assembled_from_identity_coords_and_overrides() -> None:
|
|
# Arrange — a known property type + built form + wall (Landlord Overrides),
|
|
# and resolved coordinates.
|
|
here = Coordinates(longitude=-1.55, latitude=53.81)
|
|
attributes = PredictionTargetAttributes(
|
|
property_type="2", built_form="3", wall_construction=1
|
|
)
|
|
|
|
# Act
|
|
target: Optional[PredictionTarget] = build_prediction_target(
|
|
_identity(), here, attributes
|
|
)
|
|
|
|
# Assert — every known input is threaded onto the target.
|
|
assert target is not None
|
|
assert target.postcode == "LS6 1AA"
|
|
assert target.property_type == "2"
|
|
assert target.built_form == "3"
|
|
assert target.wall_construction == 1
|
|
assert target.coordinates is here
|
|
|
|
|
|
def test_an_unknown_property_type_gates_the_property_out() -> None:
|
|
# Arrange — property type is the hard cohort filter; without it the Property
|
|
# must not be predicted from a mixed-type cohort (ADR-0031).
|
|
attributes = PredictionTargetAttributes(property_type=None)
|
|
|
|
# Act
|
|
target: Optional[PredictionTarget] = build_prediction_target(
|
|
_identity(), None, attributes
|
|
)
|
|
|
|
# Assert — gated out: no target to predict from.
|
|
assert target is None
|