cleanup/core/model.py
2026-09-05 15:24:52 +02:00

72 lines
2.8 KiB
Python

"""
FileRecord: one row per file under review. Both the GUI and the batch/
spreadsheet front end read and write the same fields, so nothing about
a file's state is front-end-specific.
Every editable field defaults to "no change" (current filename, current
folder) when a record is first created — so a file you never touch in
review simply stays exactly as it is. Nothing is lost by omission.
"""
from dataclasses import dataclass, field
from pathlib import Path
from typing import List
@dataclass
class FileRecord:
path: Path # current absolute path on disk
root: Path # vault root this file was scanned under
filename: str = "" # current filename, including extension
ext: str = ""
fs_date: str = "" # best-guess filesystem date — a starting
# point only, never treated as authoritative
name_matches_convention: bool = False
near_miss: bool = False # matched a "close but not quite" date format
# --- Editable fields ---
date_override: str = "" # what actually goes in the filename
topic: str = ""
subtopic: str = ""
extra: str = ""
more: str = ""
version: str = ""
dest_folder: str = "" # relative to root
keep_filename: bool = False # if True, move only — never rebuild the name.
# Defaults to True for files that already match
# the convention, so opening one to move it
# doesn't blank out a name that was already fine.
suggested_folders: List[str] = field(default_factory=list)
# pending -> not yet reviewed | confirmed -> ready for apply_batch
# skip -> deliberately left alone | done -> already applied
status: str = "pending"
@property
def identity(self) -> str:
"""Stable across rename/move — see core.identity. Use this, not
rel_path, as the key for anything that needs to survive a file
actually being moved (e.g. resuming progress across sessions)."""
from .identity import file_identity
return file_identity(self.path)
@property
def rel_path(self) -> str:
return str(self.path.relative_to(self.root))
@property
def current_folder(self) -> str:
return str(self.path.parent.relative_to(self.root))
@property
def new_filename_preview(self) -> str:
if self.keep_filename:
return self.filename
from .sanitiser import build_filename
return build_filename(
date=self.date_override or self.fs_date,
topic=self.topic, subtopic=self.subtopic,
extra=self.extra, more=self.more, version=self.version,
ext=self.ext,
)