Add YAPF style + ignore, and format tracked Python files
This commit is contained in:
@@ -23,18 +23,25 @@ class Delete_File(sh.Cmdlet):
|
||||
def __init__(self) -> None:
|
||||
super().__init__(
|
||||
name="delete-file",
|
||||
summary="Delete a file locally and/or from Hydrus, including database entries.",
|
||||
usage='delete-file [-query "hash:<sha256>"] [-conserve <local|hydrus>] [-lib-root <path>] [reason]',
|
||||
summary=
|
||||
"Delete a file locally and/or from Hydrus, including database entries.",
|
||||
usage=
|
||||
'delete-file [-query "hash:<sha256>"] [-conserve <local|hydrus>] [-lib-root <path>] [reason]',
|
||||
alias=["del-file"],
|
||||
arg=[
|
||||
sh.SharedArgs.QUERY,
|
||||
sh.CmdletArg(
|
||||
"conserve", description="Choose which copy to keep: 'local' or 'hydrus'."
|
||||
"conserve",
|
||||
description="Choose which copy to keep: 'local' or 'hydrus'."
|
||||
),
|
||||
sh.CmdletArg(
|
||||
"lib-root", description="Path to local library root for database cleanup."
|
||||
"lib-root",
|
||||
description="Path to local library root for database cleanup."
|
||||
),
|
||||
sh.CmdletArg(
|
||||
"reason",
|
||||
description="Optional reason for deletion (free text)."
|
||||
),
|
||||
sh.CmdletArg("reason", description="Optional reason for deletion (free text)."),
|
||||
],
|
||||
detail=[
|
||||
"Default removes both the local file and Hydrus file.",
|
||||
@@ -53,8 +60,10 @@ class Delete_File(sh.Cmdlet):
|
||||
conserve: str | None,
|
||||
lib_root: str | None,
|
||||
reason: str,
|
||||
config: Dict[str, Any],
|
||||
) -> List[Dict[str, Any]]:
|
||||
config: Dict[str,
|
||||
Any],
|
||||
) -> List[Dict[str,
|
||||
Any]]:
|
||||
"""Process deletion for a single item.
|
||||
|
||||
Returns display rows (for the final Rich table). Returning an empty list
|
||||
@@ -68,9 +77,11 @@ class Delete_File(sh.Cmdlet):
|
||||
else:
|
||||
hash_hex_raw = sh.get_field(item, "hash_hex") or sh.get_field(item, "hash")
|
||||
target = (
|
||||
sh.get_field(item, "target")
|
||||
or sh.get_field(item, "file_path")
|
||||
or sh.get_field(item, "path")
|
||||
sh.get_field(item,
|
||||
"target") or sh.get_field(item,
|
||||
"file_path")
|
||||
or sh.get_field(item,
|
||||
"path")
|
||||
)
|
||||
title_val = sh.get_field(item, "title") or sh.get_field(item, "name")
|
||||
|
||||
@@ -142,11 +153,9 @@ class Delete_File(sh.Cmdlet):
|
||||
is_hydrus_store = False
|
||||
|
||||
# Backwards-compatible fallback heuristic (older items might only carry a name).
|
||||
if (
|
||||
(not is_hydrus_store)
|
||||
and bool(store_lower)
|
||||
and ("hydrus" in store_lower or store_lower in {"home", "work"})
|
||||
):
|
||||
if ((not is_hydrus_store) and bool(store_lower)
|
||||
and ("hydrus" in store_lower or store_lower in {"home",
|
||||
"work"})):
|
||||
is_hydrus_store = True
|
||||
store_label = str(store) if store else "default"
|
||||
hydrus_prefix = f"[hydrusnetwork:{store_label}]"
|
||||
@@ -156,14 +165,16 @@ class Delete_File(sh.Cmdlet):
|
||||
hash_hex_raw = target
|
||||
|
||||
hash_hex = (
|
||||
sh.normalize_hash(override_hash) if override_hash else sh.normalize_hash(hash_hex_raw)
|
||||
sh.normalize_hash(override_hash)
|
||||
if override_hash else sh.normalize_hash(hash_hex_raw)
|
||||
)
|
||||
|
||||
local_deleted = False
|
||||
local_target = (
|
||||
isinstance(target, str)
|
||||
and target.strip()
|
||||
and not str(target).lower().startswith(("http://", "https://"))
|
||||
isinstance(target,
|
||||
str) and target.strip()
|
||||
and not str(target).lower().startswith(("http://",
|
||||
"https://"))
|
||||
)
|
||||
deleted_rows: List[Dict[str, Any]] = []
|
||||
|
||||
@@ -180,7 +191,9 @@ class Delete_File(sh.Cmdlet):
|
||||
if backend is not None:
|
||||
|
||||
# Prefer hash when available.
|
||||
hash_candidate = sh.normalize_hash(hash_hex_raw) if hash_hex_raw else None
|
||||
hash_candidate = sh.normalize_hash(
|
||||
hash_hex_raw
|
||||
) if hash_hex_raw else None
|
||||
if not hash_candidate and isinstance(target, str):
|
||||
hash_candidate = sh.normalize_hash(target)
|
||||
|
||||
@@ -189,13 +202,15 @@ class Delete_File(sh.Cmdlet):
|
||||
if hash_candidate and hasattr(backend, "get_file"):
|
||||
candidate_path = backend.get_file(hash_candidate)
|
||||
resolved_path = (
|
||||
candidate_path if isinstance(candidate_path, Path) else None
|
||||
candidate_path if isinstance(candidate_path,
|
||||
Path) else None
|
||||
)
|
||||
except Exception:
|
||||
resolved_path = None
|
||||
|
||||
identifier = hash_candidate or (
|
||||
str(target).strip() if isinstance(target, str) else ""
|
||||
str(target).strip() if isinstance(target,
|
||||
str) else ""
|
||||
)
|
||||
if identifier:
|
||||
deleter = getattr(backend, "delete_file", None)
|
||||
@@ -204,11 +219,10 @@ class Delete_File(sh.Cmdlet):
|
||||
|
||||
size_bytes: int | None = None
|
||||
try:
|
||||
if (
|
||||
resolved_path is not None
|
||||
and isinstance(resolved_path, Path)
|
||||
and resolved_path.exists()
|
||||
):
|
||||
if (resolved_path is not None
|
||||
and isinstance(resolved_path,
|
||||
Path)
|
||||
and resolved_path.exists()):
|
||||
size_bytes = int(resolved_path.stat().st_size)
|
||||
except Exception:
|
||||
size_bytes = None
|
||||
@@ -216,25 +230,34 @@ class Delete_File(sh.Cmdlet):
|
||||
deleted_rows.append(
|
||||
{
|
||||
"title": (
|
||||
str(title_val).strip()
|
||||
if title_val
|
||||
else (resolved_path.name if resolved_path else identifier)
|
||||
str(title_val).strip() if title_val else (
|
||||
resolved_path.name
|
||||
if resolved_path else identifier
|
||||
)
|
||||
),
|
||||
"store":
|
||||
store_label,
|
||||
"hash":
|
||||
hash_candidate or (hash_hex or ""),
|
||||
"size_bytes":
|
||||
size_bytes,
|
||||
"ext":
|
||||
_get_ext_from_item() or (
|
||||
resolved_path.suffix.lstrip(".")
|
||||
if resolved_path else ""
|
||||
),
|
||||
"store": store_label,
|
||||
"hash": hash_candidate or (hash_hex or ""),
|
||||
"size_bytes": size_bytes,
|
||||
"ext": _get_ext_from_item()
|
||||
or (resolved_path.suffix.lstrip(".") if resolved_path else ""),
|
||||
}
|
||||
)
|
||||
|
||||
# Best-effort remove sidecars if we know the resolved path.
|
||||
try:
|
||||
if resolved_path is not None and isinstance(resolved_path, Path):
|
||||
if resolved_path is not None and isinstance(
|
||||
resolved_path,
|
||||
Path):
|
||||
for sidecar in (
|
||||
resolved_path.with_suffix(".tag"),
|
||||
resolved_path.with_suffix(".metadata"),
|
||||
resolved_path.with_suffix(".notes"),
|
||||
resolved_path.with_suffix(".tag"),
|
||||
resolved_path.with_suffix(".metadata"),
|
||||
resolved_path.with_suffix(".notes"),
|
||||
):
|
||||
try:
|
||||
if sidecar.exists() and sidecar.is_file():
|
||||
@@ -266,7 +289,8 @@ class Delete_File(sh.Cmdlet):
|
||||
local_deleted = True
|
||||
deleted_rows.append(
|
||||
{
|
||||
"title": str(title_val).strip() if title_val else path.name,
|
||||
"title":
|
||||
str(title_val).strip() if title_val else path.name,
|
||||
"store": store_label,
|
||||
"hash": hash_hex or sh.normalize_hash(path.stem) or "",
|
||||
"size_bytes": size_bytes,
|
||||
@@ -282,11 +306,14 @@ class Delete_File(sh.Cmdlet):
|
||||
local_deleted = True
|
||||
deleted_rows.append(
|
||||
{
|
||||
"title": str(title_val).strip() if title_val else path.name,
|
||||
"title":
|
||||
str(title_val).strip() if title_val else path.name,
|
||||
"store": store_label,
|
||||
"hash": hash_hex or sh.normalize_hash(path.stem) or "",
|
||||
"hash": hash_hex or sh.normalize_hash(path.stem)
|
||||
or "",
|
||||
"size_bytes": size_bytes,
|
||||
"ext": _get_ext_from_item() or path.suffix.lstrip("."),
|
||||
"ext": _get_ext_from_item()
|
||||
or path.suffix.lstrip("."),
|
||||
}
|
||||
)
|
||||
except Exception as exc:
|
||||
@@ -299,7 +326,8 @@ class Delete_File(sh.Cmdlet):
|
||||
local_deleted = True
|
||||
deleted_rows.append(
|
||||
{
|
||||
"title": str(title_val).strip() if title_val else path.name,
|
||||
"title":
|
||||
str(title_val).strip() if title_val else path.name,
|
||||
"store": store_label,
|
||||
"hash": hash_hex or sh.normalize_hash(path.stem) or "",
|
||||
"size_bytes": size_bytes,
|
||||
@@ -311,9 +339,9 @@ class Delete_File(sh.Cmdlet):
|
||||
|
||||
# Remove common sidecars regardless of file removal success
|
||||
for sidecar in (
|
||||
path.with_suffix(".tag"),
|
||||
path.with_suffix(".metadata"),
|
||||
path.with_suffix(".notes"),
|
||||
path.with_suffix(".tag"),
|
||||
path.with_suffix(".metadata"),
|
||||
path.with_suffix(".notes"),
|
||||
):
|
||||
try:
|
||||
if sidecar.exists() and sidecar.is_file():
|
||||
@@ -370,7 +398,10 @@ class Delete_File(sh.Cmdlet):
|
||||
return False
|
||||
if client is None:
|
||||
if not local_deleted:
|
||||
log(f"Hydrus client unavailable for store '{store}'", file=sys.stderr)
|
||||
log(
|
||||
f"Hydrus client unavailable for store '{store}'",
|
||||
file=sys.stderr
|
||||
)
|
||||
return False
|
||||
else:
|
||||
# No store context; use default Hydrus client.
|
||||
@@ -385,18 +416,29 @@ class Delete_File(sh.Cmdlet):
|
||||
log("Hydrus client unavailable", file=sys.stderr)
|
||||
return False
|
||||
|
||||
payload: Dict[str, Any] = {"hashes": [hash_hex]}
|
||||
payload: Dict[str,
|
||||
Any] = {
|
||||
"hashes": [hash_hex]
|
||||
}
|
||||
if reason:
|
||||
payload["reason"] = reason
|
||||
try:
|
||||
client._post("/add_files/delete_files", data=payload) # type: ignore[attr-defined]
|
||||
client._post(
|
||||
"/add_files/delete_files",
|
||||
data=payload
|
||||
) # type: ignore[attr-defined]
|
||||
# Best-effort clear deletion record if supported by this client.
|
||||
try:
|
||||
clearer = getattr(client, "clear_file_deletion_record", None)
|
||||
if callable(clearer):
|
||||
clearer([hash_hex])
|
||||
else:
|
||||
client._post("/add_files/clear_file_deletion_record", data={"hashes": [hash_hex]}) # type: ignore[attr-defined]
|
||||
client._post(
|
||||
"/add_files/clear_file_deletion_record",
|
||||
data={
|
||||
"hashes": [hash_hex]
|
||||
}
|
||||
) # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -408,7 +450,10 @@ class Delete_File(sh.Cmdlet):
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
debug(f"{hydrus_prefix} Deleted hash:{hash_hex}", file=sys.stderr)
|
||||
debug(
|
||||
f"{hydrus_prefix} Deleted hash:{hash_hex}",
|
||||
file=sys.stderr
|
||||
)
|
||||
except Exception:
|
||||
# If it's not in Hydrus (e.g. 404 or similar), that's fine
|
||||
if not local_deleted:
|
||||
@@ -420,7 +465,10 @@ class Delete_File(sh.Cmdlet):
|
||||
if isinstance(item, dict):
|
||||
size_hint = item.get("size_bytes") or item.get("size")
|
||||
else:
|
||||
size_hint = sh.get_field(item, "size_bytes") or sh.get_field(item, "size")
|
||||
size_hint = sh.get_field(item,
|
||||
"size_bytes"
|
||||
) or sh.get_field(item,
|
||||
"size")
|
||||
except Exception:
|
||||
size_hint = None
|
||||
deleted_rows.append(
|
||||
@@ -456,24 +504,32 @@ class Delete_File(sh.Cmdlet):
|
||||
while i < len(args):
|
||||
token = args[i]
|
||||
low = str(token).lower()
|
||||
if low in {"-query", "--query", "query"} and i + 1 < len(args):
|
||||
if low in {"-query",
|
||||
"--query",
|
||||
"query"} and i + 1 < len(args):
|
||||
override_query = str(args[i + 1]).strip()
|
||||
i += 2
|
||||
continue
|
||||
if low in {"-conserve", "--conserve"} and i + 1 < len(args):
|
||||
if low in {"-conserve",
|
||||
"--conserve"} and i + 1 < len(args):
|
||||
value = str(args[i + 1]).strip().lower()
|
||||
if value in {"local", "hydrus"}:
|
||||
if value in {"local",
|
||||
"hydrus"}:
|
||||
conserve = value
|
||||
i += 2
|
||||
continue
|
||||
if low in {"-lib-root", "--lib-root", "lib-root"} and i + 1 < len(args):
|
||||
if low in {"-lib-root",
|
||||
"--lib-root",
|
||||
"lib-root"} and i + 1 < len(args):
|
||||
lib_root = str(args[i + 1]).strip()
|
||||
i += 2
|
||||
continue
|
||||
reason_tokens.append(token)
|
||||
i += 1
|
||||
|
||||
override_hash = sh.parse_single_hash_query(override_query) if override_query else None
|
||||
override_hash = sh.parse_single_hash_query(
|
||||
override_query
|
||||
) if override_query else None
|
||||
if override_query and not override_hash:
|
||||
log("Invalid -query value (expected hash:<sha256>)", file=sys.stderr)
|
||||
return 1
|
||||
@@ -481,8 +537,10 @@ class Delete_File(sh.Cmdlet):
|
||||
# If no lib_root provided, try to get the first folder store from config
|
||||
if not lib_root:
|
||||
try:
|
||||
storage_config = config.get("storage", {})
|
||||
folder_config = storage_config.get("folder", {})
|
||||
storage_config = config.get("storage",
|
||||
{})
|
||||
folder_config = storage_config.get("folder",
|
||||
{})
|
||||
if folder_config:
|
||||
# Get first folder store path
|
||||
for store_name, store_config in folder_config.items():
|
||||
@@ -494,7 +552,8 @@ class Delete_File(sh.Cmdlet):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
reason = " ".join(token for token in reason_tokens if str(token).strip()).strip()
|
||||
reason = " ".join(token for token in reason_tokens
|
||||
if str(token).strip()).strip()
|
||||
|
||||
items = []
|
||||
if isinstance(result, list):
|
||||
@@ -510,7 +569,12 @@ class Delete_File(sh.Cmdlet):
|
||||
deleted_rows: List[Dict[str, Any]] = []
|
||||
for item in items:
|
||||
rows = self._process_single_item(
|
||||
item, override_hash, conserve, lib_root, reason, config
|
||||
item,
|
||||
override_hash,
|
||||
conserve,
|
||||
lib_root,
|
||||
reason,
|
||||
config
|
||||
)
|
||||
if rows:
|
||||
success_count += 1
|
||||
@@ -525,7 +589,9 @@ class Delete_File(sh.Cmdlet):
|
||||
result_row.add_column("Store", row.get("store", ""))
|
||||
result_row.add_column("Hash", row.get("hash", ""))
|
||||
result_row.add_column(
|
||||
"Size", _format_size(row.get("size_bytes"), integer_only=False)
|
||||
"Size",
|
||||
_format_size(row.get("size_bytes"),
|
||||
integer_only=False)
|
||||
)
|
||||
result_row.add_column("Ext", row.get("ext", ""))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user