style: apply ruff auto-fixes

This commit is contained in:
2026-01-19 03:14:30 -08:00
parent 3ab122a55d
commit a961ac3ce7
72 changed files with 2477 additions and 2871 deletions

View File

@@ -4,7 +4,7 @@ import json
import re
import shutil
import sys
from fnmatch import fnmatch, translate
from fnmatch import fnmatch
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
@@ -177,7 +177,7 @@ class Folder(Store):
Checks for sidecars (.metadata, .tag) and imports them before renaming.
Also ensures all files have a title: tag.
"""
from API.folder import API_folder_store, read_sidecar, write_sidecar, find_sidecar
from API.folder import API_folder_store, read_sidecar, find_sidecar
try:
with API_folder_store(location_path) as db:

View File

@@ -1894,6 +1894,61 @@ class HydrusNetwork(Store):
debug(f"{self._log_prefix()} add_url_bulk failed: {exc}")
return False
def add_tags_bulk(self, items: List[tuple[str, List[str]]], *, service_name: str | None = None) -> bool:
"""Bulk add tags to multiple Hydrus files.
Groups files by identical tag-sets and uses the Hydrus `mutate_tags_by_key`
call (when a service key is available) to reduce the number of API calls.
Falls back to per-hash `add_tag` calls if necessary.
"""
try:
client = self._client
if client is None:
debug(f"{self._log_prefix()} add_tags_bulk: client unavailable")
return False
# Group by canonical tag set (sorted tuple) to batch identical additions
buckets: dict[tuple[str, ...], list[str]] = {}
for file_identifier, tags in items or []:
h = str(file_identifier or "").strip().lower()
if len(h) != 64:
continue
tlist = [str(t).strip().lower() for t in (tags or []) if isinstance(t, str) and str(t).strip()]
if not tlist:
continue
key = tuple(sorted(tlist))
buckets.setdefault(key, []).append(h)
if not buckets:
return False
svc = service_name or "my tags"
service_key = self._get_service_key(svc)
any_success = False
for tag_tuple, hashes in buckets.items():
try:
if service_key:
# Mutate tags for many hashes in a single request
client.mutate_tags_by_key(hashes=hashes, service_key=service_key, add_tags=list(tag_tuple))
any_success = True
continue
except Exception as exc:
debug(f"{self._log_prefix()} add_tags_bulk mutate failed for tags {tag_tuple}: {exc}")
# Fallback: apply per-hash add_tag
for h in hashes:
try:
client.add_tag(h, list(tag_tuple), svc)
any_success = True
except Exception:
continue
return any_success
except Exception as exc:
debug(f"{self._log_prefix()} add_tags_bulk failed: {exc}")
return False
def delete_url(self, file_identifier: str, url: List[str], **kwargs: Any) -> bool:
"""Delete one or more url from a Hydrus file."""
try:

View File

@@ -20,9 +20,6 @@ Notes:
from __future__ import annotations
import json
import sys
import time
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
@@ -355,7 +352,6 @@ class ZeroTier(Store):
Returns the file hash on success, or None on failure.
"""
from SYS.utils import sha256_file
p = Path(file_path)
if not p.exists():
@@ -404,17 +400,60 @@ class ZeroTier(Store):
data.append(("url", u))
files = {"file": (p.name, fh, "application/octet-stream")}
resp = httpx.post(url, headers=headers, files=files, data=data, timeout=self._timeout)
resp.raise_for_status()
if resp.status_code in (200, 201):
# Prefer `requests` for local testing / WSGI servers which may not accept
# chunked uploads reliably with httpx/httpcore. Fall back to httpx otherwise.
try:
try:
payload = resp.json()
file_hash = payload.get("hash") or payload.get("file_hash")
return file_hash
except Exception:
import requests
# Convert data list-of-tuples to dict for requests (acceptable for repeated fields)
data_dict = {}
for k, v in data:
if k in data_dict:
existing = data_dict[k]
if not isinstance(existing, list):
data_dict[k] = [existing]
data_dict[k].append(v)
else:
data_dict[k] = v
r = requests.post(url, headers=headers, files=files, data=data_dict or None, timeout=self._timeout)
if r.status_code in (200, 201):
try:
payload = r.json()
file_hash = payload.get("hash") or payload.get("file_hash")
return file_hash
except Exception:
return None
try:
debug(f"[zerotier-debug] upload failed (requests) status={r.status_code} body={r.text}")
except Exception:
pass
debug(f"ZeroTier add_file failed (requests): status {r.status_code} body={getattr(r, 'text', '')}")
return None
debug(f"ZeroTier add_file failed: status {resp.status_code}")
return None
except Exception:
import httpx
resp = httpx.post(url, headers=headers, files=files, data=data, timeout=self._timeout)
# Note: some environments may not create request.files correctly; capture body for debugging
try:
if resp.status_code in (200, 201):
try:
payload = resp.json()
file_hash = payload.get("hash") or payload.get("file_hash")
return file_hash
except Exception:
return None
# Debug output to help tests capture server response
try:
debug(f"[zerotier-debug] upload failed status={resp.status_code} body={resp.text}")
except Exception:
pass
debug(f"ZeroTier add_file failed: status {resp.status_code} body={getattr(resp, 'text', '')}")
return None
except Exception as exc:
debug(f"ZeroTier add_file exception: {exc}")
return None
except Exception as exc:
debug(f"ZeroTier add_file exception: {exc}")
return None
except Exception as exc:
debug(f"ZeroTier add_file exception: {exc}")
return None

View File

@@ -15,8 +15,7 @@ import importlib
import inspect
import pkgutil
import re
from pathlib import Path
from typing import Any, Dict, Iterable, Optional, Type
from typing import Any, Dict, Optional, Type
from SYS.logger import debug
from SYS.utils import expand_path