from __future__ import annotations from abc import ABC, abstractmethod from types import TracebackType from typing import Optional from repositories.property_baseline.property_baseline_repository import PropertyBaselineRepository from repositories.epc.epc_repository import EpcRepository from repositories.property.property_repository import PropertyRepository from repositories.solar.solar_repository import SolarRepository class UnitOfWork(ABC): """A single batch transaction across the DB-backed repos (ADR-0012). A context manager that exposes the repos bound to one session. A stage runs its whole batch inside one unit and calls ``commit()`` once; leaving the block without committing — including via an exception — rolls back, so a failed batch persists nothing and the subtask fails noisily. The non-DB dependencies (EPC/Solar fetchers, the geospatial S3 repo, the Rebaseliner) are *not* part of the unit — only transactional DB work is. """ property: PropertyRepository epc: EpcRepository solar: SolarRepository property_baseline: PropertyBaselineRepository @abstractmethod def commit(self) -> None: ... @abstractmethod def rollback(self) -> None: ... def __enter__(self) -> "UnitOfWork": return self def __exit__( self, exc_type: Optional[type[BaseException]], exc: Optional[BaseException], tb: Optional[TracebackType], ) -> None: # Roll back whatever was not explicitly committed (a no-op after a # successful commit). All-or-nothing per batch. self.rollback()