Add YAPF style + ignore, and format tracked Python files

This commit is contained in:
2025-12-29 18:42:02 -08:00
parent c019c00aed
commit 507946a3e4
108 changed files with 11664 additions and 6494 deletions

View File

@@ -26,7 +26,6 @@ get_field = sh.get_field
from Store import Store
from SYS.utils import sha256_file
_FIELD_NAME_RE = re.compile(r"^[A-Za-z0-9_]+$")
@@ -106,13 +105,15 @@ def _compile_extract_template(template: str) -> tuple[re.Pattern[str], List[str]
last_end = 0
for idx, m in enumerate(matches):
literal = tpl[last_end : m.start()]
literal = tpl[last_end:m.start()]
if literal:
parts.append(_literal_to_title_pattern_regex(literal))
raw_name = (m.group(1) or "").strip()
if not raw_name or not _FIELD_NAME_RE.fullmatch(raw_name):
raise ValueError(f"invalid field name '{raw_name}' (use A-Z, 0-9, underscore)")
raise ValueError(
f"invalid field name '{raw_name}' (use A-Z, 0-9, underscore)"
)
field_names.append(raw_name)
name_lower = raw_name.lower()
@@ -123,15 +124,15 @@ def _compile_extract_template(template: str) -> tuple[re.Pattern[str], List[str]
# Heuristic: common numeric fields should capture full digit runs.
# This avoids ambiguous splits like track='2', title='3 ...'.
if name_lower in {
"disk",
"disc",
"cd",
"track",
"trk",
"episode",
"ep",
"season",
"year",
"disk",
"disc",
"cd",
"track",
"trk",
"episode",
"ep",
"season",
"year",
}:
parts.append(rf"(?P<{raw_name}>\d+)")
else:
@@ -170,7 +171,8 @@ def _extract_tags_from_title(title_text: str, template: str) -> List[str]:
def _get_title_candidates_for_extraction(
res: Any, existing_tags: Optional[List[str]] = None
res: Any,
existing_tags: Optional[List[str]] = None
) -> List[str]:
"""Return a list of possible title strings in priority order."""
@@ -209,9 +211,9 @@ def _get_title_candidates_for_extraction(
return candidates
def _extract_tags_from_title_candidates(
candidates: List[str], template: str
) -> tuple[List[str], Optional[str]]:
def _extract_tags_from_title_candidates(candidates: List[str],
template: str) -> tuple[List[str],
Optional[str]]:
"""Try candidates in order; return (tags, matched_candidate)."""
for c in candidates:
@@ -223,7 +225,8 @@ def _extract_tags_from_title_candidates(
def _try_compile_extract_template(
template: Optional[str],
) -> tuple[Optional[re.Pattern[str]], Optional[str]]:
) -> tuple[Optional[re.Pattern[str]],
Optional[str]]:
"""Compile template for debug; return (pattern, error_message)."""
if template is None:
return None, None
@@ -408,7 +411,8 @@ def _refresh_tag_view(
target_hash: Optional[str],
store_name: Optional[str],
target_path: Optional[str],
config: Dict[str, Any],
config: Dict[str,
Any],
) -> None:
"""Refresh tag display via get-tag. Prefer current subject; fall back to direct hash refresh."""
try:
@@ -450,13 +454,15 @@ class Add_Tag(Cmdlet):
super().__init__(
name="add-tag",
summary="Add tag to a file in a store.",
usage='add-tag -store <store> [-query "hash:<sha256>"] [-duplicate <format>] [-list <list>[,<list>...]] [--all] <tag>[,<tag>...]',
usage=
'add-tag -store <store> [-query "hash:<sha256>"] [-duplicate <format>] [-list <list>[,<list>...]] [--all] <tag>[,<tag>...]',
arg=[
CmdletArg(
"tag",
type="string",
required=False,
description="One or more tag to add. Comma- or space-separated. Can also use {list_name} syntax. If omitted, uses tag from pipeline payload.",
description=
"One or more tag to add. Comma- or space-separated. Can also use {list_name} syntax. If omitted, uses tag from pipeline payload.",
variadic=True,
),
SharedArgs.QUERY,
@@ -464,27 +470,32 @@ class Add_Tag(Cmdlet):
CmdletArg(
"-extract",
type="string",
description='Extract tags from the item\'s title using a simple template with (field) placeholders. Example: -extract "(artist) - (album) - (disk)-(track) (title)" will add artist:, album:, disk:, track:, title: tags.',
description=
'Extract tags from the item\'s title using a simple template with (field) placeholders. Example: -extract "(artist) - (album) - (disk)-(track) (title)" will add artist:, album:, disk:, track:, title: tags.',
),
CmdletArg(
"--extract-debug",
type="flag",
description="Print debug info for -extract matching (matched title source and extracted tags).",
description=
"Print debug info for -extract matching (matched title source and extracted tags).",
),
CmdletArg(
"-duplicate",
type="string",
description="Copy existing tag values to new namespaces. Formats: title:album,artist (explicit) or title,album,artist (inferred)",
description=
"Copy existing tag values to new namespaces. Formats: title:album,artist (explicit) or title,album,artist (inferred)",
),
CmdletArg(
"-list",
type="string",
description="Load predefined tag lists from adjective.json. Comma-separated list names (e.g., -list philosophy,occult).",
description=
"Load predefined tag lists from adjective.json. Comma-separated list names (e.g., -list philosophy,occult).",
),
CmdletArg(
"--all",
type="flag",
description="Include temporary files in tagging (by default, only tag non-temporary files).",
description=
"Include temporary files in tagging (by default, only tag non-temporary files).",
),
],
detail=[
@@ -523,7 +534,10 @@ class Add_Tag(Cmdlet):
query_hash = sh.parse_single_hash_query(parsed.get("query"))
if parsed.get("query") and not query_hash:
log("[add_tag] Error: -query must be of the form hash:<sha256>", file=sys.stderr)
log(
"[add_tag] Error: -query must be of the form hash:<sha256>",
file=sys.stderr
)
return 1
# If add-tag is in the middle of a pipeline (has downstream stages), default to
@@ -532,7 +546,9 @@ class Add_Tag(Cmdlet):
store_override = parsed.get("store")
stage_ctx = ctx.get_stage_context()
has_downstream = bool(
stage_ctx is not None and not getattr(stage_ctx, "is_last_stage", False)
stage_ctx is not None and not getattr(stage_ctx,
"is_last_stage",
False)
)
include_temp = bool(parsed.get("all", False))
@@ -598,11 +614,17 @@ class Add_Tag(Cmdlet):
tag_to_add = expand_tag_groups(tag_to_add)
if not tag_to_add and not extract_template:
log("No tag provided to add (and no -extract template provided)", file=sys.stderr)
log(
"No tag provided to add (and no -extract template provided)",
file=sys.stderr
)
return 1
if extract_template and extract_debug and extract_debug_err:
log(f"[add_tag] extract template error: {extract_debug_err}", file=sys.stderr)
log(
f"[add_tag] extract template error: {extract_debug_err}",
file=sys.stderr
)
return 1
# Get other flags
@@ -643,8 +665,7 @@ class Add_Tag(Cmdlet):
if not store_override:
store_name_str = str(store_name) if store_name is not None else ""
local_mode_requested = (
(not store_name_str)
or (store_name_str.upper() == "PATH")
(not store_name_str) or (store_name_str.upper() == "PATH")
or (store_name_str.lower() == "local")
)
is_known_backend = bool(store_name_str) and store_registry.is_available(
@@ -656,14 +677,16 @@ class Add_Tag(Cmdlet):
if Path(str(raw_path)).expanduser().exists():
existing_tag_list = _extract_item_tags(res)
existing_lower = {
t.lower() for t in existing_tag_list if isinstance(t, str)
t.lower()
for t in existing_tag_list if isinstance(t, str)
}
item_tag_to_add = list(tag_to_add)
if extract_template:
candidates = _get_title_candidates_for_extraction(
res, existing_tag_list
res,
existing_tag_list
)
extracted, matched = _extract_tags_from_title_candidates(
candidates, extract_template
@@ -683,17 +706,20 @@ class Add_Tag(Cmdlet):
if extract_debug:
rx_preview = (
extract_debug_rx.pattern
if extract_debug_rx
else "<uncompiled>"
if extract_debug_rx else "<uncompiled>"
)
cand_preview = "; ".join(
[repr(c) for c in candidates[:3]]
)
cand_preview = "; ".join([repr(c) for c in candidates[:3]])
log(
f"[add_tag] extract no match for template {extract_template!r}. regex: {rx_preview!r}. candidates: {cand_preview}",
file=sys.stderr,
)
item_tag_to_add = collapse_namespace_tag(
item_tag_to_add, "title", prefer="last"
item_tag_to_add,
"title",
prefer="last"
)
if duplicate_arg:
@@ -703,12 +729,17 @@ class Add_Tag(Cmdlet):
if len(parts) > 1:
source_ns = parts[0]
targets = [t.strip() for t in parts[1].split(",") if t.strip()]
targets = [
t.strip() for t in parts[1].split(",")
if t.strip()
]
else:
parts2 = str(duplicate_arg).split(",")
if len(parts2) > 1:
source_ns = parts2[0]
targets = [t.strip() for t in parts2[1:] if t.strip()]
targets = [
t.strip() for t in parts2[1:] if t.strip()
]
if source_ns and targets:
source_prefix = source_ns.lower() + ":"
@@ -730,21 +761,22 @@ class Add_Tag(Cmdlet):
continue
ns_prefix = ns.lower() + ":"
for t in existing_tag_list:
if (
t.lower().startswith(ns_prefix)
and t.lower() != new_tag.lower()
):
if (t.lower().startswith(ns_prefix)
and t.lower() != new_tag.lower()):
removed_namespace_tag.append(t)
removed_namespace_tag = sorted({t for t in removed_namespace_tag})
removed_namespace_tag = sorted(
{t
for t in removed_namespace_tag}
)
actual_tag_to_add = [
t
for t in item_tag_to_add
if isinstance(t, str) and t.lower() not in existing_lower
t for t in item_tag_to_add if isinstance(t, str)
and t.lower() not in existing_lower
]
updated_tag_list = [
t for t in existing_tag_list if t not in removed_namespace_tag
t for t in existing_tag_list
if t not in removed_namespace_tag
]
updated_tag_list.extend(actual_tag_to_add)
@@ -777,13 +809,15 @@ class Add_Tag(Cmdlet):
return 1
resolved_hash = (
normalize_hash(hash_override) if hash_override else normalize_hash(raw_hash)
normalize_hash(hash_override)
if hash_override else normalize_hash(raw_hash)
)
if not resolved_hash and raw_path:
try:
p = Path(str(raw_path))
stem = p.stem
if len(stem) == 64 and all(c in "0123456789abcdef" for c in stem.lower()):
if len(stem) == 64 and all(c in "0123456789abcdef"
for c in stem.lower()):
resolved_hash = stem.lower()
elif p.exists() and p.is_file():
resolved_hash = sha256_file(p)
@@ -801,7 +835,10 @@ class Add_Tag(Cmdlet):
try:
backend = store_registry[str(store_name)]
except Exception as exc:
log(f"[add_tag] Error: Unknown store '{store_name}': {exc}", file=sys.stderr)
log(
f"[add_tag] Error: Unknown store '{store_name}': {exc}",
file=sys.stderr
)
return 1
try:
@@ -810,14 +847,18 @@ class Add_Tag(Cmdlet):
existing_tag = []
existing_tag_list = [t for t in (existing_tag or []) if isinstance(t, str)]
existing_lower = {t.lower() for t in existing_tag_list}
existing_lower = {t.lower()
for t in existing_tag_list}
original_title = _extract_title_tag(existing_tag_list)
# Per-item tag list (do not mutate shared list)
item_tag_to_add = list(tag_to_add)
if extract_template:
candidates2 = _get_title_candidates_for_extraction(res, existing_tag_list)
candidates2 = _get_title_candidates_for_extraction(
res,
existing_tag_list
)
extracted2, matched2 = _extract_tags_from_title_candidates(
candidates2, extract_template
)
@@ -835,7 +876,8 @@ class Add_Tag(Cmdlet):
extract_no_match_items += 1
if extract_debug:
rx_preview2 = (
extract_debug_rx.pattern if extract_debug_rx else "<uncompiled>"
extract_debug_rx.pattern
if extract_debug_rx else "<uncompiled>"
)
cand_preview2 = "; ".join([repr(c) for c in candidates2[:3]])
log(
@@ -843,7 +885,11 @@ class Add_Tag(Cmdlet):
file=sys.stderr,
)
item_tag_to_add = collapse_namespace_tag(item_tag_to_add, "title", prefer="last")
item_tag_to_add = collapse_namespace_tag(
item_tag_to_add,
"title",
prefer="last"
)
# Handle -duplicate logic (copy existing tag to new namespaces)
if duplicate_arg:
@@ -881,15 +927,19 @@ class Add_Tag(Cmdlet):
try:
refreshed_tag, _src2 = backend.get_tag(resolved_hash, config=config)
refreshed_list = [t for t in (refreshed_tag or []) if isinstance(t, str)]
refreshed_list = [
t for t in (refreshed_tag or []) if isinstance(t, str)
]
except Exception:
refreshed_list = existing_tag_list
# Decide whether anything actually changed (case-sensitive so title casing updates count).
if set(refreshed_list) != set(existing_tag_list):
changed = True
before_lower = {t.lower() for t in existing_tag_list}
after_lower = {t.lower() for t in refreshed_list}
before_lower = {t.lower()
for t in existing_tag_list}
after_lower = {t.lower()
for t in refreshed_list}
total_added += len(after_lower - before_lower)
total_modified += 1
@@ -903,7 +953,12 @@ class Add_Tag(Cmdlet):
_apply_title_to_result(res, final_title)
if final_title and (not original_title or final_title != original_title):
_refresh_result_table_title(final_title, resolved_hash, str(store_name), raw_path)
_refresh_result_table_title(
final_title,
resolved_hash,
str(store_name),
raw_path
)
if changed:
_refresh_tag_view(res, resolved_hash, str(store_name), raw_path, config)