Relocate condition-data ingestion into the DDD layout 🟪

Behaviour-preserving lift-and-shift of the condition module out of legacy
backend/condition/ into domain/condition, infrastructure/condition,
infrastructure/postgres/condition_tables.py, repositories/condition,
applications/condition, and tests/condition. Imports rewritten to the DDD
paths; ConditionPostgres and the ORM models keep the legacy backend.app.db
Base/db_session bridges so the existing suite proves behaviour is unchanged
(SQLModel + session-DI conversion tracked as a follow-up in ADR-0064).

16 condition tests pass at the new location.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-13 14:51:25 +00:00
parent 89602eb814
commit 735e83cef2
59 changed files with 117 additions and 110 deletions

View file

@ -1,12 +1,12 @@
from typing import Optional
from backend.condition.condition_trigger_request import ConditionFileType
from backend.condition.domain.mapping.lbwf.lbwf_mapper import LbwfMapper
from backend.condition.domain.mapping.mapper import Mapper
from backend.condition.domain.mapping.peabody.peabody_mapper import PeabodyMapper
from backend.condition.lookups.uprn_lookup import UprnLookup
from backend.condition.parsing.parser import Parser
from backend.condition.parsing.lbwf_parser import LbwfParser
from backend.condition.parsing.peabody_parser import PeabodyParser
from applications.condition.condition_trigger_request import ConditionFileType
from domain.condition.mapping.lbwf.lbwf_mapper import LbwfMapper
from domain.condition.mapping.mapper import Mapper
from domain.condition.mapping.peabody.peabody_mapper import PeabodyMapper
from repositories.condition.uprn_lookup import UprnLookup
from infrastructure.condition.parsing.parser import Parser
from infrastructure.condition.parsing.lbwf_parser import LbwfParser
from infrastructure.condition.parsing.peabody_parser import PeabodyParser
def select_parser(

View file

@ -2,9 +2,9 @@ import json
from typing import Mapping, Any
from io import BytesIO
from backend.condition.condition_trigger_request import ConditionTriggerRequest
from backend.condition.lookups.uprn_lookup_s3 import UprnLookupS3
from backend.condition.processor import process_file
from applications.condition.condition_trigger_request import ConditionTriggerRequest
from infrastructure.condition.lookups.uprn_lookup_s3 import UprnLookupS3
from applications.condition.processor import process_file
from utils.logger import setup_logger
from utils.s3 import read_io_from_s3

View file

@ -1,8 +1,8 @@
from pathlib import Path
from backend.condition.condition_trigger_request import ConditionFileType
from backend.condition.lookups.uprn_lookup_csv import UprnLookupLocal
from backend.condition.processor import process_file
from applications.condition.condition_trigger_request import ConditionFileType
from infrastructure.condition.lookups.uprn_lookup_csv import UprnLookupLocal
from applications.condition.processor import process_file
def main() -> None:

View file

@ -1,14 +1,14 @@
from typing import Any, BinaryIO, List, Optional
from datetime import datetime
from backend.condition.condition_trigger_request import ConditionFileType
from backend.condition.lookups.uprn_lookup import UprnLookup
from applications.condition.condition_trigger_request import ConditionFileType
from repositories.condition.uprn_lookup import UprnLookup
from utils.logger import setup_logger
from backend.condition.domain.mapping.mapper import Mapper
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from backend.condition.parsing.parser import Parser
from backend.condition.persistence.condition_postgres import ConditionPostgres
from backend.condition.parsing.factory import select_parser, select_mapper
from domain.condition.mapping.mapper import Mapper
from domain.condition.property_condition_survey import PropertyConditionSurvey
from infrastructure.condition.parsing.parser import Parser
from repositories.condition.condition_postgres import ConditionPostgres
from applications.condition.factory import select_parser, select_mapper
logger = setup_logger()

View file

@ -3,7 +3,7 @@ from sqlalchemy import insert, delete
from sqlalchemy.orm import Session
from backend.app.db.connection import db_session, db_read_session
from backend.app.db.models.condition import PropertyConditionSurveyModel
from infrastructure.postgres.condition_tables import PropertyConditionSurveyModel
def bulk_insert_property_surveys(

View file

@ -91,7 +91,14 @@ solar is a front-end presentation overlay, not an engine output.**
orchestration) as a full lift-and-shift — shared core, the Peabody and LBWF
adapters, and the delivery path — with Calico added as a new adapter alongside
them. Peabody/LBWF keep their Lambda after the move; the relocation is
behaviour-preserving for them.
behaviour-preserving for them. **The move is deliberately relocation-only:** the
ORM models stay SQLAlchemy-declarative and `ConditionPostgres` keeps the legacy
`backend.app.db` `Base` / `db_session` bridges, so the existing test suite proves
behaviour is unchanged. Converting the tables to SQLModel and the repository to
constructor session-injection (matching the rest of `infrastructure/postgres`),
and clearing the module's pre-existing pyright-strict debt, are tracked
follow-ups to run where a database is available to verify them — not bundled into
the move.
- A new `Calico` `ConditionFileType`, parser + row DTO, roof-covering element map
(`"Roof Covering"` → roof `ElementType`, `MATERIAL` aspect = `Type`), and mapper
are added and registered in the factory. Roof covering is already a modelled

View file

View file

@ -2,7 +2,7 @@ from dataclasses import dataclass
from typing import Optional
from datetime import date
from backend.condition.domain.aspect_type import AspectType
from domain.condition.aspect_type import AspectType
@dataclass

View file

@ -1,8 +1,8 @@
from dataclasses import dataclass
from typing import List
from backend.condition.domain.aspect_condition import AspectCondition
from backend.condition.domain.element_type import ElementType
from domain.condition.aspect_condition import AspectCondition
from domain.condition.element_type import ElementType
@dataclass

View file

View file

@ -1,8 +1,8 @@
from dataclasses import dataclass
from typing import Optional
from backend.condition.domain.aspect_type import AspectType
from backend.condition.domain.element_type import ElementType
from domain.condition.aspect_type import AspectType
from domain.condition.element_type import ElementType
@dataclass(frozen=True)

View file

@ -1,6 +1,6 @@
from backend.condition.domain.element_type import ElementType
from backend.condition.domain.aspect_type import AspectType
from backend.condition.domain.mapping.element_mapping import ElementMapping
from domain.condition.element_type import ElementType
from domain.condition.aspect_type import AspectType
from domain.condition.mapping.element_mapping import ElementMapping
LBWF_ELEMENT_MAP: dict[str, ElementMapping] = {

View file

@ -1,17 +1,17 @@
from typing import Any, Dict, Optional, Tuple
from datetime import date
from backend.condition.domain.aspect_condition import AspectCondition
from backend.condition.domain.element import Element
from backend.condition.domain.element_type import ElementType
from backend.condition.domain.mapping.element_mapping import ElementMapping
from backend.condition.domain.mapping.lbwf.lbwf_element_map import LBWF_ELEMENT_MAP
from backend.condition.domain.mapping.mapper import Mapper
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from backend.condition.parsing.records.lbwf.lbwf_asset_condition import (
from domain.condition.aspect_condition import AspectCondition
from domain.condition.element import Element
from domain.condition.element_type import ElementType
from domain.condition.mapping.element_mapping import ElementMapping
from domain.condition.mapping.lbwf.lbwf_element_map import LBWF_ELEMENT_MAP
from domain.condition.mapping.mapper import Mapper
from domain.condition.property_condition_survey import PropertyConditionSurvey
from domain.condition.records.lbwf.lbwf_asset_condition import (
LbwfAssetCondition,
)
from backend.condition.parsing.records.lbwf.lbwf_house import LbwfHouse
from domain.condition.records.lbwf.lbwf_house import LbwfHouse
from utils.logger import setup_logger
logger = setup_logger()

View file

@ -1,8 +1,8 @@
from abc import ABC, abstractmethod
from typing import Any, List, Optional
from backend.condition.domain.element import Element
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from domain.condition.element import Element
from domain.condition.property_condition_survey import PropertyConditionSurvey
class Mapper(ABC):

View file

@ -1,6 +1,6 @@
from backend.condition.domain.aspect_type import AspectType
from backend.condition.domain.element_type import ElementType
from backend.condition.domain.mapping.element_mapping import ElementMapping
from domain.condition.aspect_type import AspectType
from domain.condition.element_type import ElementType
from domain.condition.mapping.element_mapping import ElementMapping
PEABODY_ELEMENT_MAP = {

View file

@ -1,19 +1,19 @@
from typing import Any, Dict, Optional, Tuple
from datetime import date
from backend.condition.domain.aspect_condition import AspectCondition
from backend.condition.domain.element import Element
from backend.condition.domain.element_type import ElementType
from backend.condition.domain.mapping.element_mapping import ElementMapping
from backend.condition.domain.mapping.peabody.peabody_element_map import (
from domain.condition.aspect_condition import AspectCondition
from domain.condition.element import Element
from domain.condition.element_type import ElementType
from domain.condition.mapping.element_mapping import ElementMapping
from domain.condition.mapping.peabody.peabody_element_map import (
PEABODY_ELEMENT_MAP,
)
from backend.condition.domain.mapping.mapper import Mapper
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from backend.condition.parsing.records.peabody.peabody_asset_condition import (
from domain.condition.mapping.mapper import Mapper
from domain.condition.property_condition_survey import PropertyConditionSurvey
from domain.condition.records.peabody.peabody_asset_condition import (
PeabodyAssetCondition,
)
from backend.condition.parsing.records.peabody.peabody_property import PeabodyProperty
from domain.condition.records.peabody.peabody_property import PeabodyProperty
from utils.logger import setup_logger
logger = setup_logger()

View file

@ -2,7 +2,7 @@ from dataclasses import dataclass
from typing import List
from datetime import date
from backend.condition.domain.element import Element
from domain.condition.element import Element
@dataclass

View file

View file

@ -1,7 +1,7 @@
from dataclasses import dataclass
from typing import List
from backend.condition.parsing.records.lbwf.lbwf_asset_condition import LbwfAssetCondition
from domain.condition.records.lbwf.lbwf_asset_condition import LbwfAssetCondition
@dataclass
class LbwfHouse:

View file

@ -1,7 +1,7 @@
from dataclasses import dataclass
from typing import List
from backend.condition.parsing.records.peabody.peabody_asset_condition import PeabodyAssetCondition
from domain.condition.records.peabody.peabody_asset_condition import PeabodyAssetCondition
@dataclass
class PeabodyProperty:

View file

View file

@ -1,7 +1,7 @@
import csv
from io import TextIOWrapper
from typing import BinaryIO, Dict, TextIO
from backend.condition.lookups.uprn_lookup import UprnLookup
from repositories.condition.uprn_lookup import UprnLookup
class UprnLookupLocal(UprnLookup):

View file

@ -2,7 +2,7 @@ import csv
from io import BytesIO, TextIOWrapper
from typing import BinaryIO, Dict, TextIO
from backend.condition.lookups.uprn_lookup import UprnLookup
from repositories.condition.uprn_lookup import UprnLookup
from utils.s3 import read_io_from_s3

View file

@ -2,12 +2,12 @@ from typing import BinaryIO, Any, Dict, Iterator, List, Optional, Tuple
from openpyxl import Workbook, load_workbook
from collections import defaultdict
from backend.condition.parsing.parser import Parser
from backend.condition.parsing.records.lbwf.lbwf_asset_condition import (
from infrastructure.condition.parsing.parser import Parser
from domain.condition.records.lbwf.lbwf_asset_condition import (
LbwfAssetCondition,
)
from backend.condition.parsing.records.lbwf.lbwf_house import LbwfHouse
from backend.condition.utils.date_utils import normalise_date
from domain.condition.records.lbwf.lbwf_house import LbwfHouse
from infrastructure.condition.date_utils import normalise_date
from utils.logger import setup_logger
logger = setup_logger()

View file

@ -4,12 +4,12 @@ from typing import Any, BinaryIO, Dict, List, Optional, Tuple, DefaultDict
from openpyxl import Workbook, load_workbook
from collections import defaultdict
from backend.condition.lookups.uprn_lookup import UprnLookup
from backend.condition.parsing.parser import Parser
from backend.condition.parsing.records.peabody.peabody_asset_condition import (
from repositories.condition.uprn_lookup import UprnLookup
from infrastructure.condition.parsing.parser import Parser
from domain.condition.records.peabody.peabody_asset_condition import (
PeabodyAssetCondition,
)
from backend.condition.parsing.records.peabody.peabody_property import PeabodyProperty
from domain.condition.records.peabody.peabody_property import PeabodyProperty
from utils.logger import setup_logger
logger = setup_logger()

View file

@ -9,8 +9,8 @@ from sqlalchemy import (
)
from sqlalchemy.orm import relationship
from backend.condition.domain.aspect_type import AspectType
from backend.condition.domain.element_type import ElementType
from domain.condition.aspect_type import AspectType
from domain.condition.element_type import ElementType
from backend.app.db.base import Base

View file

View file

@ -3,12 +3,12 @@ from typing import List, Optional
from sqlmodel import Session
from utils.logger import setup_logger
from backend.app.db.models.condition import (
from infrastructure.postgres.condition_tables import (
AspectConditionModel,
ElementModel,
PropertyConditionSurveyModel,
)
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from domain.condition.property_condition_survey import PropertyConditionSurvey
from backend.app.db.connection import db_session
logger = setup_logger()

View file

View file

@ -1,5 +1,5 @@
from backend.app.db.models.condition import PropertyConditionSurveyModel
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from infrastructure.postgres.condition_tables import PropertyConditionSurveyModel
from domain.condition.property_condition_survey import PropertyConditionSurvey
class CustomAsserts:

View file

View file

@ -2,7 +2,7 @@ import pytest
from typing import Dict
from tempfile import NamedTemporaryFile
from backend.condition.lookups.uprn_lookup_csv import UprnLookupLocal
from infrastructure.condition.lookups.uprn_lookup_csv import UprnLookupLocal
@pytest.fixture

View file

View file

@ -1,16 +1,16 @@
from datetime import date
from backend.condition.domain.aspect_condition import AspectCondition
from backend.condition.domain.aspect_type import AspectType
from backend.condition.domain.element_type import ElementType
from backend.condition.domain.mapping.lbwf.lbwf_mapper import LbwfMapper
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from backend.condition.parsing.records.lbwf.lbwf_house import LbwfHouse
from backend.condition.parsing.records.lbwf.lbwf_asset_condition import (
from domain.condition.aspect_condition import AspectCondition
from domain.condition.aspect_type import AspectType
from domain.condition.element_type import ElementType
from domain.condition.mapping.lbwf.lbwf_mapper import LbwfMapper
from domain.condition.property_condition_survey import PropertyConditionSurvey
from domain.condition.records.lbwf.lbwf_house import LbwfHouse
from domain.condition.records.lbwf.lbwf_asset_condition import (
LbwfAssetCondition,
)
from backend.condition.domain.element import Element
from backend.condition.tests.custom_asserts import CustomAsserts
from domain.condition.element import Element
from tests.condition.custom_asserts import CustomAsserts
def test_lbwf_mapper_maps_house():

View file

@ -1,16 +1,16 @@
from datetime import datetime, date
from backend.condition.domain.aspect_condition import AspectCondition
from backend.condition.domain.aspect_type import AspectType
from backend.condition.domain.element_type import ElementType
from backend.condition.domain.mapping.peabody.peabody_mapper import PeabodyMapper
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from backend.condition.parsing.records.peabody.peabody_asset_condition import (
from domain.condition.aspect_condition import AspectCondition
from domain.condition.aspect_type import AspectType
from domain.condition.element_type import ElementType
from domain.condition.mapping.peabody.peabody_mapper import PeabodyMapper
from domain.condition.property_condition_survey import PropertyConditionSurvey
from domain.condition.records.peabody.peabody_asset_condition import (
PeabodyAssetCondition,
)
from backend.condition.parsing.records.peabody.peabody_property import PeabodyProperty
from backend.condition.domain.element import Element
from backend.condition.tests.custom_asserts import CustomAsserts
from domain.condition.records.peabody.peabody_property import PeabodyProperty
from domain.condition.element import Element
from tests.condition.custom_asserts import CustomAsserts
def test_peabody_mapper_maps_property():

View file

View file

@ -4,9 +4,9 @@ from io import BytesIO
from openpyxl import Workbook
from datetime import datetime
from backend.condition.parsing.lbwf_parser import LbwfParser
from backend.condition.parsing.records.lbwf.lbwf_asset_condition import LbwfAssetCondition
from backend.condition.parsing.records.lbwf.lbwf_house import LbwfHouse
from infrastructure.condition.parsing.lbwf_parser import LbwfParser
from domain.condition.records.lbwf.lbwf_asset_condition import LbwfAssetCondition
from domain.condition.records.lbwf.lbwf_house import LbwfHouse
@pytest.fixture
def lbwf_homes_xlsx_bytes() -> BytesIO:

View file

@ -1,8 +1,8 @@
import pytest
from backend.condition.condition_trigger_request import ConditionFileType
from backend.condition.lookups.uprn_lookup_csv import UprnLookupLocal
from backend.condition.parsing.factory import select_parser
from applications.condition.condition_trigger_request import ConditionFileType
from infrastructure.condition.lookups.uprn_lookup_csv import UprnLookupLocal
from applications.condition.factory import select_parser
def test_selects_lbwf_parser():

View file

@ -5,12 +5,12 @@ from io import BytesIO
from openpyxl import Workbook
from datetime import datetime
from backend.condition.lookups.uprn_lookup_csv import UprnLookupLocal
from backend.condition.parsing.peabody_parser import PeabodyParser
from backend.condition.parsing.records.peabody.peabody_asset_condition import (
from infrastructure.condition.lookups.uprn_lookup_csv import UprnLookupLocal
from infrastructure.condition.parsing.peabody_parser import PeabodyParser
from domain.condition.records.peabody.peabody_asset_condition import (
PeabodyAssetCondition,
)
from backend.condition.parsing.records.peabody.peabody_property import PeabodyProperty
from domain.condition.records.peabody.peabody_property import PeabodyProperty
@pytest.fixture

View file

View file

@ -1,14 +1,14 @@
import pytest
from datetime import date
from backend.condition.persistence.condition_postgres import ConditionPostgres
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey
from backend.condition.domain.element import Element
from backend.condition.domain.element_type import ElementType
from backend.condition.domain.aspect_condition import AspectCondition
from backend.condition.domain.aspect_type import AspectType
from backend.app.db.models.condition import PropertyConditionSurveyModel
from backend.condition.tests.custom_asserts import CustomAsserts
from repositories.condition.condition_postgres import ConditionPostgres
from domain.condition.property_condition_survey import PropertyConditionSurvey
from domain.condition.element import Element
from domain.condition.element_type import ElementType
from domain.condition.aspect_condition import AspectCondition
from domain.condition.aspect_type import AspectType
from infrastructure.postgres.condition_tables import PropertyConditionSurveyModel
from tests.condition.custom_asserts import CustomAsserts
def test_map_survey_to_model() -> None: