mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-08-03 05:18:22 +00:00
Report how many files a rename run renamed 🟥
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
82e1dd555a
commit
5dc524be8f
2 changed files with 61 additions and 1 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import csv
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
from domain.pashub_fetcher.sharepoint_subfolders import SharepointSubfolders
|
||||
|
|
@ -16,6 +17,34 @@ BATCH_FOLDER_PREFIX = "_Sero Batch"
|
|||
logger = setup_logger()
|
||||
|
||||
|
||||
@dataclass
|
||||
class RenameFailure:
|
||||
"""One file SharePoint refused to rename, and why."""
|
||||
|
||||
uprn: str
|
||||
original_name: str
|
||||
new_name: str
|
||||
error: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class RenameSummary:
|
||||
"""What a run did, threaded back up through the traversal.
|
||||
|
||||
Counts are per-**file**; ``missing_folders`` is per-**property** (a UPRN with
|
||||
no assessment folder under any root, so no file was even looked at)."""
|
||||
|
||||
renamed: int = 0
|
||||
would_rename: int = 0
|
||||
skipped_already_canonical: int = 0
|
||||
skipped_images: int = 0
|
||||
missing_folders: list[str] = field(default_factory=list)
|
||||
failed: list[RenameFailure] = field(default_factory=list)
|
||||
|
||||
def merge_in(self, other: "RenameSummary") -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def build_canonical_filename(
|
||||
uprn: str, address: str, postcode: str, original_name: str
|
||||
) -> Optional[str]:
|
||||
|
|
@ -76,7 +105,8 @@ class SharepointRenamerOrchestrator:
|
|||
)
|
||||
return [BASE_PATH, *batch_roots]
|
||||
|
||||
def run(self) -> None:
|
||||
def run(self) -> RenameSummary:
|
||||
summary = RenameSummary()
|
||||
roots = self._discover_roots()
|
||||
with open(self._csv_path, newline="", encoding="utf-8-sig") as f:
|
||||
reader = csv.DictReader(f)
|
||||
|
|
@ -93,6 +123,7 @@ class SharepointRenamerOrchestrator:
|
|||
address=row["Address"].strip(),
|
||||
postcode=row["Postcode"].strip(),
|
||||
)
|
||||
return summary
|
||||
|
||||
def _process_row(
|
||||
self, roots: list[str], uprn: str, address: str, postcode: str
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from domain.pashub_fetcher.sharepoint_subfolders import SharepointSubfolders
|
|||
from orchestration.sharepoint_renamer_orchestrator import (
|
||||
ASSESSMENT_SUBFOLDER,
|
||||
BASE_PATH,
|
||||
RenameSummary,
|
||||
SharepointRenamerOrchestrator,
|
||||
build_canonical_filename,
|
||||
)
|
||||
|
|
@ -124,6 +125,34 @@ def test_run_renames_files_for_property_under_batch_root(tmp_path: Path) -> None
|
|||
sp.rename_file.assert_called_once_with("id-1", "100_1 High St AB1 2CD_Survey.pdf")
|
||||
|
||||
|
||||
def test_run_summary_counts_each_renamed_file(tmp_path: Path) -> None:
|
||||
# Arrange
|
||||
csv_path = _write_csv(tmp_path, [("100", "1 High St", "AB1 2CD")])
|
||||
assessment = _assessment_path(BASE_PATH, "1 High St", "AB1 2CD")
|
||||
|
||||
sp = MagicMock()
|
||||
|
||||
def fake_get(path: str) -> dict[str, Any]:
|
||||
if path == BASE_PATH:
|
||||
return {"value": []}
|
||||
if path == assessment:
|
||||
return {
|
||||
"value": [
|
||||
_make_file("Survey.pdf", "id-1"),
|
||||
_make_file("Report.docx", "id-2"),
|
||||
]
|
||||
}
|
||||
raise ValueError("not found")
|
||||
|
||||
sp.get_folders_in_path.side_effect = fake_get
|
||||
|
||||
# Act
|
||||
summary = SharepointRenamerOrchestrator(sp, csv_path).run()
|
||||
|
||||
# Assert
|
||||
assert summary.renamed == 2
|
||||
|
||||
|
||||
def test_run_uprn_prefixed_address_yields_single_uprn_filename(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue