mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
Add Hyde property_overrides build script + creds-free smoke test 🟩
Two-pass org_ref-matched builder for property_overrides (classify via ChatGPT into the landlord ledger, validate+apply user edits, write idempotently); ephemeral-Postgres smoke proves the one-property chain without creds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
85e43b3737
commit
c1ab179d51
3 changed files with 26 additions and 14 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -313,3 +313,8 @@ scripts/eon/epc_cache.pkl
|
|||
scripts/hyde/.elmhurst-session/
|
||||
scripts/hyde/elmhurst_downloads/
|
||||
scripts/hyde/.elmhurst-creds.json
|
||||
|
||||
# Hyde property-overrides script artifacts
|
||||
overrides_cache.json
|
||||
overrides_unknowns.csv
|
||||
overrides_edits.csv
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ from datetime import datetime, timezone
|
|||
from enum import Enum
|
||||
from typing import Any, Optional
|
||||
|
||||
import pandas as pd
|
||||
import pandas as pd # pyright: ignore[reportMissingTypeStubs]
|
||||
from sqlalchemy import Table, text
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from sqlmodel import SQLModel
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ from domain.epc.property_overrides.water_heating_type import WaterHeatingType
|
|||
from infrastructure.landlord_overrides.landlord_overrides_postgres_repository import (
|
||||
LandlordOverridesRepository,
|
||||
)
|
||||
from repositories.property.landlord_override_overlays import overlays_from
|
||||
from repositories.property.property_overrides_postgres_reader import (
|
||||
PropertyOverridesPostgresReader,
|
||||
)
|
||||
|
||||
PORTFOLIO = 795
|
||||
ORG_REF = "55180004001"
|
||||
|
|
@ -36,7 +40,7 @@ SEED = {
|
|||
"property_type": ("House: MidTerrace", PropertyType.HOUSE),
|
||||
"built_form_type": ("House: MidTerrace", BuiltFormType.MID_TERRACE),
|
||||
"wall_type": ("TimberFrame: AsBuilt", WallType.TIMBER_FRAME_AS_BUILT_NO_INSULATION_ASSUMED),
|
||||
"roof_type": ("PitchedNormalLoftAccess: 300mm", RoofType.PITCHED_300_MM),
|
||||
"roof_type": ("PitchedNormalLoftAccess: 300mm", RoofType.PITCHED_LOFT_300MM),
|
||||
"construction_age_band": ("L: 2012-2022", ConstructionAgeBand.L_2012_2022),
|
||||
"main_fuel": ("Gas: Mains Gas", MainFuelType.MAINS_GAS),
|
||||
"glazing": ("100% Double glazing 2002 or later", GlazingType.DOUBLE_POST_2002),
|
||||
|
|
@ -45,20 +49,21 @@ SEED = {
|
|||
}
|
||||
|
||||
|
||||
def test_one_property_end_to_end(db_engine: Engine, monkeypatch: Any, capsys: Any) -> None:
|
||||
specs = b._specs_by_component()
|
||||
def test_one_property_end_to_end(db_engine: Engine, monkeypatch: Any) -> None:
|
||||
specs = b._specs_by_component() # pyright: ignore[reportPrivateUsage]
|
||||
|
||||
# minimal FE-owned `property` table + the one row we'll match by org_ref
|
||||
with Session(db_engine) as s:
|
||||
s.execute(text(
|
||||
s.execute(text( # pyright: ignore[reportDeprecated]
|
||||
"CREATE TABLE property (id bigint PRIMARY KEY, portfolio_id bigint, "
|
||||
"landlord_property_id text)"))
|
||||
s.execute(text("INSERT INTO property VALUES (1, :p, :ref)"),
|
||||
s.execute(text("INSERT INTO property VALUES (1, :p, :ref)"), # pyright: ignore[reportDeprecated]
|
||||
{"p": PORTFOLIO, "ref": ORG_REF})
|
||||
# seed the classifier ledger (keyed on normalised description)
|
||||
for comp, (raw, member) in SEED.items():
|
||||
LandlordOverridesRepository(s, specs[comp].row_type).upsert_all(
|
||||
PORTFOLIO, {b._norm(raw): member})
|
||||
repo: LandlordOverridesRepository[Any] = LandlordOverridesRepository(
|
||||
s, specs[comp].row_type)
|
||||
repo.upsert_all(PORTFOLIO, {b._norm(raw): member}) # pyright: ignore[reportPrivateUsage]
|
||||
s.commit()
|
||||
|
||||
# point the script at the ephemeral engine
|
||||
|
|
@ -69,7 +74,7 @@ def test_one_property_end_to_end(db_engine: Engine, monkeypatch: Any, capsys: An
|
|||
portfolio_id=PORTFOLIO, org_ref=ORG_REF, limit=None, apply=True))
|
||||
|
||||
with Session(db_engine) as s:
|
||||
rows = list(s.execute(text(
|
||||
rows = list(s.execute(text( # pyright: ignore[reportDeprecated]
|
||||
"SELECT override_component, building_part, override_value "
|
||||
"FROM property_overrides WHERE property_id = 1 ORDER BY override_component")))
|
||||
got = {c: v for c, _, v in rows}
|
||||
|
|
@ -81,8 +86,10 @@ def test_one_property_end_to_end(db_engine: Engine, monkeypatch: Any, capsys: An
|
|||
assert got["water_heating"] == "From main system, mains gas"
|
||||
assert len(rows) == 9 # all 9 components
|
||||
|
||||
# --- run the real verify() and confirm overlays are produced ---
|
||||
b.verify(argparse.Namespace(portfolio_id=PORTFOLIO, org_ref=ORG_REF))
|
||||
out = capsys.readouterr().out
|
||||
print(out) # surfaced with -s so we can eyeball the one-property result
|
||||
assert "EpcSimulation overlay" in out
|
||||
# --- the overrides reach the SAP overlay surface ---
|
||||
b.verify(argparse.Namespace(portfolio_id=PORTFOLIO, org_ref=ORG_REF)) # exercises verify()
|
||||
overlays = overlays_from(
|
||||
PropertyOverridesPostgresReader(lambda: Session(db_engine)).overrides_for(1))
|
||||
assert len(overlays) == 9
|
||||
assert any(o.heating is not None and o.heating.main_fuel_type == 26 for o in overlays)
|
||||
assert any(o.glazing is not None and o.glazing.glazing_type == 2 for o in overlays)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue