debugging some failed runs

This commit is contained in:
Khalim Conn-Kowlessar 2026-01-02 17:39:48 +08:00
parent 33e61507c4
commit 3fc1e69e50
4 changed files with 105 additions and 58 deletions

View file

@ -1,3 +1,4 @@
from sqlalchemy import text
from sqlalchemy import insert, delete, select
from sqlalchemy.orm import Session
from sqlalchemy.exc import SQLAlchemyError
@ -365,84 +366,122 @@ def delete_property_batch(session: Session, property_ids: list[int]):
if not property_ids:
return
# --------------------------------------------------
# Shared subqueries (computed once)
# --------------------------------------------------
plan_ids = (
select(Plan.id)
.where(Plan.property_id.in_(property_ids))
)
params = {"property_ids": property_ids}
recommendation_ids = (
select(Recommendation.id)
.where(Recommendation.property_id.in_(property_ids))
)
funding_package_ids = (
select(FundingPackage.id)
.where(FundingPackage.plan_id.in_(plan_ids))
# --------------------------------------------------
# recommendation_materials (via recommendation)
# --------------------------------------------------
session.execute(
text("""
DELETE FROM recommendation_materials rm
USING recommendation r
WHERE rm.recommendation_id = r.id
AND r.property_id = ANY(:property_ids)
"""),
params,
)
# --------------------------------------------------
# Leaf tables FIRST
# plan_recommendations (via plan)
# --------------------------------------------------
session.execute(
delete(RecommendationMaterials)
.where(RecommendationMaterials.recommendation_id.in_(recommendation_ids))
)
session.execute(
delete(PlanRecommendations)
.where(PlanRecommendations.plan_id.in_(plan_ids))
)
session.execute(
delete(FundingPackageMeasures)
.where(FundingPackageMeasures.funding_package_id.in_(funding_package_ids))
)
session.execute(
delete(InspectionModel)
.where(InspectionModel.property_id.in_(property_ids))
text("""
DELETE FROM plan_recommendations pr
USING plan p
WHERE pr.plan_id = p.id
AND p.property_id = ANY(:property_ids)
"""),
params,
)
# --------------------------------------------------
# Mid-level tables
# funding_package_measures
# --------------------------------------------------
session.execute(
delete(FundingPackage)
.where(FundingPackage.id.in_(funding_package_ids))
)
session.execute(
delete(Recommendation)
.where(Recommendation.id.in_(recommendation_ids))
)
session.execute(
delete(Plan)
.where(Plan.id.in_(plan_ids))
text("""
DELETE FROM funding_package_measures fpm
USING funding_package fp, plan p
WHERE fpm.funding_package_id = fp.id
AND fp.plan_id = p.id
AND p.property_id = ANY(:property_ids)
"""),
params,
)
# --------------------------------------------------
# Property-scoped tables
# inspections (direct)
# --------------------------------------------------
session.execute(
delete(PropertyDetailsEpcModel)
.where(PropertyDetailsEpcModel.property_id.in_(property_ids))
)
session.execute(
delete(PropertyTargetsModel)
.where(PropertyTargetsModel.property_id.in_(property_ids))
text("""
DELETE FROM inspections
WHERE property_id = ANY(:property_ids)
"""),
params,
)
# --------------------------------------------------
# Properties LAST
# funding_package
# --------------------------------------------------
session.execute(
delete(PropertyModel)
.where(PropertyModel.id.in_(property_ids))
text("""
DELETE FROM funding_package fp
USING plan p
WHERE fp.plan_id = p.id
AND p.property_id = ANY(:property_ids)
"""),
params,
)
# --------------------------------------------------
# recommendation (direct — CRITICAL FIX)
# --------------------------------------------------
session.execute(
text("""
DELETE FROM recommendation
WHERE property_id = ANY(:property_ids)
"""),
params,
)
# --------------------------------------------------
# plan (direct)
# --------------------------------------------------
session.execute(
text("""
DELETE FROM plan
WHERE property_id = ANY(:property_ids)
"""),
params,
)
# --------------------------------------------------
# property-scoped tables
# --------------------------------------------------
session.execute(
text("""
DELETE FROM property_details_epc
WHERE property_id = ANY(:property_ids)
"""),
params,
)
session.execute(
text("""
DELETE FROM property_targets
WHERE property_id = ANY(:property_ids)
"""),
params,
)
# --------------------------------------------------
# properties LAST
# --------------------------------------------------
session.execute(
text("""
DELETE FROM property
WHERE id = ANY(:property_ids)
"""),
params,
)
@ -481,11 +520,14 @@ def clear_portfolio_in_batches(
return
total = (len(property_ids) + property_batch_size - 1) // property_batch_size
import time
for i, batch in enumerate(chunked(property_ids, property_batch_size), start=1):
print(f"Deleting batch {i}/{total} ({len(batch)} properties)")
start_time = time.time()
with db_session() as session:
delete_property_batch(session, batch)
finish_time = time.time()
print(f"Batch {i} deleted in {finish_time - start_time:.2f} seconds")
# scenario deletion happens AFTER all properties are gone
delete_portfolio_scenarios_if_empty(portfolio_id)

View file

@ -100,6 +100,7 @@ class HotWaterAttributes(Definitions):
WELSH_TEXT = {
"ogçör brif system": "from main system",
"o r brif system": "from main system",
"or brif system": "from main system",
"ogçör brif system, adfer gwres nwyon ffliw": "from main system, flue gas heat recovery",
"bwyler/cylchredydd nwy": "gas boiler/circulator",
"ogçör brif system, dim thermostat ar y silindr": "from main system, no cylinder thermostat",

View file

@ -39,6 +39,8 @@ class WallAttributes(Definitions):
"Waliau ceudod, fel yGÇÖu hadeiladwyd, wediGÇÖu hinswleiddio (rhagdybiaeth)": "Cavity wall, as built, "
"insulated (assumed)",
"Waliau ceudod, fel yGÇÖu hadeiladwyd, wediGÇÖu hinswleiddio": "Cavity wall, as built, insulated",
"Waliau ceudod, fel yu hadeiladwyd, wediu hinswleiddio (rhagdybiaeth)": "Cavity wall, as built, insulated ("
"assumed)",
"Gwenithfaen neu risgraig, fel yGÇÖu hadeiladwyd, dim inswleiddio (rhagdybiaeth)": "Granite or whinstone, "
"as built, no insulation ("
"assumed)",

View file

@ -72,6 +72,7 @@ class WallRecommendations(Definitions):
'Timber frame, as built, partial insulation': 'Timber frame, with external insulation',
"Sandstone or limestone, as built, no insulation": "Sandstone or limestone, with external insulation",
"Sandstone, as built, no insulation": "Sandstone, with external insulation",
"Sandstone, as built, partial insulation": "Sandstone, with external insulation",
}
# These are the ending descriptions we consider for walls with internal insulation
@ -88,6 +89,7 @@ class WallRecommendations(Definitions):
'Timber frame, as built, partial insulation': 'Timber frame, with internal insulation',
"Sandstone or limestone, as built, no insulation": "Sandstone or limestone, with internal insulation",
"Sandstone, as built, no insulation": "Sandstone, with internal insulation",
"Sandstone, as built, partial insulation": "Sandstone, with internal insulation",
}
def __init__(