Praneshrajan15's picture
Deploy DataForge playground API
13fe504 verified
Raw
History Blame Contribute Delete
3.5 kB
"""CSV table-store wrapper around DataForge's existing repair engine."""
from __future__ import annotations
from pathlib import Path
from dataforge.detectors.base import Schema
from dataforge.engine.repair import apply_transaction, read_csv
from dataforge.repairers.base import ProposedFix
from dataforge.stores.base import StoreApplyReceipt, TableStore
from dataforge.stores.patch_plan import PatchOperation, PatchPlan, RowIdentity
from dataforge.table import TableLike, row_count
class CSVStore(TableStore):
"""Reference table-store implementation for local CSV files."""
backend = "csv"
def __init__(self, path: Path) -> None:
self.path = path.resolve()
self.target = str(self.path)
self.relation = self.path.name
self.row_identity_columns: tuple[str, ...] = ("_row",)
def read_table(self) -> TableLike:
"""Read the CSV using the existing string-preserving reader."""
return read_csv(self.path)
def build_patch_plan(
self,
fixes: list[ProposedFix],
*,
schema: Schema | None,
safety_verdict: str,
touched_constraints: tuple[str, ...] = (),
smt_obligations: tuple[str, ...] = (),
) -> PatchPlan:
"""Describe existing CSV cell edits as a patch plan."""
del schema
operations = tuple(
PatchOperation.from_cell_fix(
fix.fix,
relation=self.relation,
row_identity=RowIdentity(
kind="csv_position",
columns=("_row",),
values={"_row": str(fix.fix.row)},
stable=True,
reason="CSV byte snapshot plus row position is reversible in the local engine.",
),
reason=fix.reason,
confidence=fix.confidence,
provenance=fix.provenance,
)
for fix in fixes
)
return PatchPlan.new(
backend=self.backend,
target=self.target,
relation=self.relation,
row_identity_columns=self.row_identity_columns,
operations=operations,
safety_verdict=safety_verdict,
rows_scanned=row_count(self.read_table()),
reason="CSV patch plan mirrors the existing reversible transaction engine.",
touched_constraints=touched_constraints,
smt_obligations=smt_obligations,
audit_metadata={"source": "csv_reference_engine"},
apply_supported=bool(operations),
reversible=True,
)
def apply_patch_plan(
self,
plan: PatchPlan,
*,
state_root: Path | None = None,
source_bytes: bytes | None = None,
fixes: list[ProposedFix] | None = None,
) -> StoreApplyReceipt:
"""Apply through the existing CSV transaction path."""
del state_root
if fixes is None or source_bytes is None:
raise ValueError("CSVStore.apply_patch_plan requires source bytes and fixes.")
txn_id = apply_transaction(self.path, fixes, source_bytes)
return StoreApplyReceipt(
ok=True,
txn_id=txn_id,
backend=self.backend,
target=self.target,
patch_plan_sha256=plan.sha256(),
reason=f"Applied {len(fixes)} CSV fix(es).",
)