This commit is contained in:
2026-01-31 19:00:04 -08:00
parent dcf16e0cc4
commit 6513a3ad04
25 changed files with 617 additions and 397 deletions

View File

@@ -4,6 +4,10 @@ import subprocess
import sys
import shutil
from SYS.logger import log, debug
import logging
logger = logging.getLogger(__name__)
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Sequence, Set, Tuple
@@ -651,7 +655,7 @@ def write_tags(
)
sidecar = media_path.parent / f"{fallback_base}.tag"
except Exception:
pass
logger.exception("Failed to determine fallback .tag sidecar base for %s", media_path)
# Write via consolidated function
try:
@@ -1258,15 +1262,16 @@ def embed_metadata_in_file(
stderr_text = result.stderr.decode("utf-8", errors="replace")[:200]
debug(f"FFmpeg stderr: {stderr_text}", file=sys.stderr)
except Exception:
pass
logger.exception("Failed to decode FFmpeg stderr for %s", file_path)
return False
except Exception as exc:
if temp_file.exists():
try:
temp_file.unlink()
except Exception:
pass
logger.exception("Failed to remove FFmpeg temp file %s after error", temp_file)
debug(f"❌ Error embedding metadata: {exc}", file=sys.stderr)
logger.exception("Error embedding metadata into %s", file_path)
return False
@@ -2236,7 +2241,7 @@ def enrich_playlist_entries(entries: list, extractor: str) -> list:
enriched.append(full_info)
continue
except Exception:
pass
logger.exception("Failed to fetch full metadata for entry URL: %s", entry_url)
# Fallback to original entry if fetch failed
enriched.append(entry)
@@ -2306,7 +2311,7 @@ def extract_title_from_tags(tags_list: List[str]) -> Optional[str]:
if extracted:
return extracted
except Exception:
pass
logger.exception("extract_title failed while extracting title from tags")
for t in tags_list:
if isinstance(t, str) and t.lower().startswith("title:"):
@@ -2563,9 +2568,9 @@ def scrape_url_metadata(
}
)
except json_module.JSONDecodeError:
pass
logger.debug("Failed to decode flat playlist line %d as JSON: %r", idx, line[:200])
except Exception:
pass # Silently ignore if we can't get playlist entries
logger.exception("yt-dlp flat-playlist extraction failed for URL: %s", url)
# Fallback: if still no tags detected, get from first item
if not tags:
@@ -2751,6 +2756,7 @@ def apply_mutagen_metadata(path: Path, metadata: dict[str, str], fmt: str) -> No
audio[target_key] = [value]
changed = True
except Exception: # pragma: no cover - best effort only
logger.exception("mutagen: failed to set field %s for %s", target_key, path)
continue
if not changed:
return
@@ -2758,6 +2764,7 @@ def apply_mutagen_metadata(path: Path, metadata: dict[str, str], fmt: str) -> No
audio.save()
except Exception as exc: # pragma: no cover - best effort only
log(f"mutagen save failed: {exc}", file=sys.stderr)
logger.exception("mutagen save failed for %s", path)
def build_ffmpeg_command(

View File

@@ -8,7 +8,10 @@ import os
import shutil
import sys
import time
import logging
from threading import RLock
logger = logging.getLogger(__name__)
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Protocol, TextIO
@@ -474,7 +477,7 @@ class ProgressBar:
total=int(total)
)
except Exception:
pass
logger.exception("Failed to update pipeline UI transfer in ProgressBar._ensure_started")
return
if self._progress is not None and self._task_id is not None:
@@ -506,8 +509,8 @@ class ProgressBar:
else:
return
except Exception:
pass
logger.exception("Failed to initialize pipeline Live UI integration in ProgressBar._ensure_started")
stream = file if file is not None else sys.stderr
# Use shared stderr console when rendering to stderr (cooperates with PipelineLiveProgress).
if stream is sys.stderr:
@@ -516,6 +519,7 @@ class ProgressBar:
console = stderr_console()
except Exception:
logger.exception("Failed to acquire shared stderr Console from SYS.rich_display; using fallback Console")
console = Console(file=stream)
else:
console = Console(file=stream)
@@ -558,7 +562,7 @@ class ProgressBar:
int) and total > 0 else None,
)
except Exception:
pass
logger.exception("Failed to update pipeline UI transfer in ProgressBar.update")
return
if self._progress is None or self._task_id is None:
@@ -582,7 +586,7 @@ class ProgressBar:
try:
self._pipeline_ui.finish_transfer(label=self._pipeline_label)
except Exception:
pass
logger.exception("Failed to finish pipeline UI transfer in ProgressBar.finish")
finally:
self._pipeline_ui = None
self._pipeline_label = None
@@ -681,7 +685,7 @@ class ProgressFileReader:
# EOF
self._finish()
except Exception:
pass
logger.exception("Error while reading and updating ProgressFileReader")
return chunk
def seek(self, offset: int, whence: int = 0) -> Any:
@@ -695,7 +699,7 @@ class ProgressFileReader:
else:
self._read = pos
except Exception:
pass
logger.exception("Failed to determine file position in ProgressFileReader.seek")
return out
def tell(self) -> Any:
@@ -705,7 +709,7 @@ class ProgressFileReader:
try:
self._finish()
except Exception:
pass
logger.exception("Failed to finish ProgressFileReader progress in close")
return self._f.close()
def __getattr__(self, name: str) -> Any:
@@ -825,6 +829,7 @@ class PipelineLiveProgress:
try:
value = str(text or "").strip()
except Exception:
logger.exception("Failed to compute active subtask text in PipelineLiveProgress.set_active_subtask_text")
value = ""
self._active_subtask_text = value or None
@@ -1011,10 +1016,11 @@ class PipelineLiveProgress:
else:
stop_fn()
except Exception:
logger.exception("Failed to stop Live with clear parameter; retrying without clear")
try:
stop_fn()
except Exception:
pass
logger.exception("Failed to stop Live on retry")
self._live = None
self._console = None
@@ -1043,9 +1049,9 @@ class PipelineLiveProgress:
subtasks.stop_task(sub_id)
subtasks.update(sub_id, visible=False)
except Exception:
pass
logger.exception("Failed to stop or hide subtask %s in PipelineLiveProgress._hide_pipe_subtasks", sub_id)
except Exception:
pass
logger.exception("Failed to hide pipe subtasks for index %s", pipe_index)
def set_pipe_status_text(self, pipe_index: int, text: str) -> None:
"""Set a status line under the pipe bars for the given pipe."""
@@ -1071,20 +1077,21 @@ class PipelineLiveProgress:
try:
self._hide_pipe_subtasks(pidx)
except Exception:
pass
logger.exception("Failed to hide pipe subtasks while setting status text for pipe %s", pidx)
task_id = self._status_tasks.get(pidx)
if task_id is None:
try:
task_id = prog.add_task(msg)
except Exception:
logger.exception("Failed to add status task for pipe %s in set_pipe_status_text", pidx)
return
self._status_tasks[pidx] = task_id
try:
prog.update(task_id, description=msg, refresh=True)
except Exception:
pass
logger.exception("Failed to update status task %s in set_pipe_status_text", task_id)
def clear_pipe_status_text(self, pipe_index: int) -> None:
if not self._enabled:
@@ -1104,7 +1111,7 @@ class PipelineLiveProgress:
try:
prog.remove_task(task_id)
except Exception:
pass
logger.exception("Failed to remove pipe status task %s in clear_pipe_status_text", task_id)
def set_pipe_percent(self, pipe_index: int, percent: int) -> None:
"""Update the pipe bar as a percent (only when single-item mode is enabled)."""
@@ -1127,7 +1134,7 @@ class PipelineLiveProgress:
pipe_progress.update(pipe_task, completed=pct, total=100, refresh=True)
self._update_overall()
except Exception:
pass
logger.exception("Failed to set pipe percent for pipe %s in set_pipe_percent", pipe_index)
def _update_overall(self) -> None:
"""Update the overall pipeline progress task."""
@@ -1142,6 +1149,7 @@ class PipelineLiveProgress:
if self._pipe_done[i] >= max(1, self._pipe_totals[i])
)
except Exception:
logger.exception("Failed to compute completed pipes in _update_overall")
completed = 0
try:
@@ -1151,7 +1159,7 @@ class PipelineLiveProgress:
description=f"Pipeline: {completed}/{len(self._pipe_labels)} pipes completed",
)
except Exception:
pass
logger.exception("Failed to update overall pipeline task in _update_overall")
# Auto-stop Live rendering once all pipes are complete so the progress
# UI clears itself even if callers forget to stop it explicitly.
@@ -1161,7 +1169,7 @@ class PipelineLiveProgress:
if total_pipes > 0 and completed >= total_pipes:
self.stop()
except Exception:
pass
logger.exception("Failed to auto-stop Live UI after all pipes completed")
def begin_pipe_steps(self, pipe_index: int, *, total_steps: int) -> None:
"""Initialize step tracking for a pipe.
@@ -1187,11 +1195,11 @@ class PipelineLiveProgress:
try:
self.clear_pipe_status_text(pidx)
except Exception:
pass
logger.exception("Failed to clear pipe status text in begin_pipe_steps for %s", pidx)
try:
self.set_pipe_percent(pidx, 0)
except Exception:
pass
logger.exception("Failed to set initial pipe percent in begin_pipe_steps for %s", pidx)
def advance_pipe_step(self, pipe_index: int, text: str) -> None:
"""Advance the pipe's step counter by one.
@@ -1226,14 +1234,14 @@ class PipelineLiveProgress:
try:
self.set_pipe_status_text(pidx, line)
except Exception:
pass
logger.exception("Failed to set pipe status text in advance_pipe_step for pipe %s", pidx)
# Percent mapping only applies when the pipe is in percent mode (single-item).
try:
pct = 100 if done >= total else int(round((done / max(1, total)) * 100.0))
self.set_pipe_percent(pidx, pct)
except Exception:
pass
logger.exception("Failed to set pipe percent in advance_pipe_step for pipe %s", pidx)
def begin_transfer(self, *, label: str, total: Optional[int] = None) -> None:
if not self._enabled:
@@ -1247,14 +1255,14 @@ class PipelineLiveProgress:
if total is not None and total > 0:
self._transfers.update(self._transfer_tasks[key], total=int(total))
except Exception:
pass
logger.exception("Failed to update existing transfer task total for %s in begin_transfer", key)
return
task_total = int(total) if isinstance(total, int) and total > 0 else None
try:
task_id = self._transfers.add_task(key, total=task_total)
self._transfer_tasks[key] = task_id
except Exception:
pass
logger.exception("Failed to add transfer task %s in begin_transfer", key)
def update_transfer(
self,
@@ -1282,7 +1290,7 @@ class PipelineLiveProgress:
kwargs["total"] = int(total)
self._transfers.update(task_id, refresh=True, **kwargs)
except Exception:
pass
logger.exception("Failed to update transfer '%s'", key)
def finish_transfer(self, *, label: str) -> None:
if self._transfers is None:
@@ -1294,7 +1302,7 @@ class PipelineLiveProgress:
try:
self._transfers.remove_task(task_id)
except Exception:
pass
logger.exception("Failed to remove transfer task '%s' in finish_transfer", key)
def _ensure_pipe(self, pipe_index: int) -> bool:
if not self._enabled:
@@ -1330,12 +1338,12 @@ class PipelineLiveProgress:
try:
self.clear_pipe_status_text(pipe_index)
except Exception:
pass
logger.exception("Failed to clear pipe status text during begin_pipe for %s", pipe_index)
try:
self._pipe_step_total.pop(pipe_index, None)
self._pipe_step_done.pop(pipe_index, None)
except Exception:
pass
logger.exception("Failed to reset pipe step totals during begin_pipe for %s", pipe_index)
# If this pipe will process exactly one item, allow percent-based updates.
percent_mode = bool(int(total_items) == 1)
@@ -1351,7 +1359,7 @@ class PipelineLiveProgress:
try:
pipe_progress.start_task(pipe_task)
except Exception:
pass
logger.exception("Failed to start pipe task timer in begin_pipe for %s", pipe_index)
self._update_overall()
@@ -1386,6 +1394,7 @@ class PipelineLiveProgress:
"description",
"") or "").strip() or None
except Exception:
logger.exception("Failed to set active subtask text for first subtask %s in begin_pipe", first)
self._active_subtask_text = None
def on_emit(self, pipe_index: int, emitted: Any) -> None:
@@ -1429,7 +1438,7 @@ class PipelineLiveProgress:
f"{self._pipe_labels[pipe_index]}: {_pipeline_progress_item_label(emitted)}",
)
except Exception:
pass
logger.exception("Failed to update subtask description for current %s in on_emit", current)
subtasks.stop_task(current)
subtasks.update(current, visible=False)
@@ -1448,12 +1457,12 @@ class PipelineLiveProgress:
try:
self.clear_pipe_status_text(pipe_index)
except Exception:
pass
logger.exception("Failed to clear pipe status text after emit for %s", pipe_index)
try:
self._pipe_step_total.pop(pipe_index, None)
self._pipe_step_done.pop(pipe_index, None)
except Exception:
pass
logger.exception("Failed to pop pipe step totals after emit for %s", pipe_index)
# Start next subtask spinner.
next_index = active + 1
@@ -1468,6 +1477,7 @@ class PipelineLiveProgress:
"description",
"") or "").strip() or None
except Exception:
logger.exception("Failed to set active subtask text for next subtask %s in on_emit", nxt)
self._active_subtask_text = None
else:
self._active_subtask_text = None
@@ -1504,7 +1514,7 @@ class PipelineLiveProgress:
subtasks.stop_task(sub_id)
subtasks.update(sub_id, visible=False)
except Exception:
pass
logger.exception("Failed to stop or hide subtask %s during finish_pipe for pipe %s", sub_id, pipe_index)
# If we just finished the active pipe, clear the title context.
self._active_subtask_text = None
@@ -1513,19 +1523,19 @@ class PipelineLiveProgress:
try:
self.clear_pipe_status_text(pipe_index)
except Exception:
pass
logger.exception("Failed to clear pipe status text during finish_pipe for %s", pipe_index)
try:
self._pipe_step_total.pop(pipe_index, None)
self._pipe_step_done.pop(pipe_index, None)
except Exception:
pass
logger.exception("Failed to pop pipe step totals during finish_pipe for %s", pipe_index)
# Stop the per-pipe timer once the pipe is finished.
try:
pipe_task = self._pipe_tasks[pipe_index]
pipe_progress.stop_task(pipe_task)
except Exception:
pass
logger.exception("Failed to stop pipe task %s during finish_pipe", pipe_index)
self._update_overall()
@@ -1537,7 +1547,7 @@ class PipelineLiveProgress:
try:
self.finish_pipe(idx)
except Exception:
pass
logger.exception("Failed to finish pipe %s in complete_all_pipes", idx)
class PipelineStageContext:
@@ -1568,7 +1578,7 @@ class PipelineStageContext:
try:
cb(obj)
except Exception:
pass
logger.exception("Error in PipelineStageContext.emit callback")
def get_current_command_text(self) -> str:
"""Get the current command text (for backward compatibility)."""

View File

@@ -10,6 +10,8 @@ from contextvars import ContextVar
from typing import Any, Dict, List, Optional, Sequence, Callable
from SYS.models import PipelineStageContext
from SYS.logger import log, debug, is_debug_enabled
import logging
logger = logging.getLogger(__name__)
from SYS.worker import WorkerManagerRegistry, WorkerStages
from SYS.cli_parsing import SelectionSyntax, SelectionFilterSyntax
from SYS.rich_display import stdout_console
@@ -62,7 +64,7 @@ def suspend_live_progress():
try:
ui.resume()
except Exception:
pass
logger.exception("Failed to resume live progress UI after suspend")
def _is_selectable_table(table: Any) -> bool:
@@ -237,7 +239,7 @@ def print_if_visible(*args: Any, file=None, **kwargs: Any) -> None:
if should_print:
log(*args, **kwargs) if file is None else log(*args, file=file, **kwargs)
except Exception:
pass
logger.exception("Error in print_if_visible")
def store_value(key: str, value: Any) -> None:
@@ -253,7 +255,7 @@ def store_value(key: str, value: Any) -> None:
state = _get_pipeline_state()
state.pipeline_values[text] = value
except Exception:
pass
logger.exception("Failed to store pipeline value '%s'", key)
def load_value(key: str, default: Any = None) -> Any:
@@ -330,7 +332,7 @@ def set_pending_pipeline_tail(
state.pending_pipeline_source = clean_source if clean_source else None
except Exception:
# Keep existing pending tail on failure
pass
logger.exception("Failed to set pending pipeline tail; keeping existing pending tail")
def get_pending_pipeline_tail() -> List[List[str]]:
@@ -627,24 +629,9 @@ def set_last_result_table(
if result_table.rows and len(sorted_items) == len(result_table.rows):
state.last_result_items = sorted_items
except Exception:
pass
logger.exception("Failed to sort result_table and reorder items")
def set_last_result_table_overlay(
result_table: Optional[Any],
items: Optional[List[Any]] = None,
subject: Optional[Any] = None
) -> None:
"""
Set a result table as an overlay (display only, no history).
"""
state = _get_pipeline_state()
state.display_table = result_table
state.display_items = items or []
state.display_subject = subject
# Sort table by Title/Name column alphabetically if available
if (
result_table is not None
and hasattr(result_table, "sort_by_title")
@@ -662,23 +649,7 @@ def set_last_result_table_overlay(
if len(sorted_items) == len(result_table.rows):
state.display_items = sorted_items
except Exception:
pass
def set_last_result_table_preserve_history(
result_table: Optional[Any],
items: Optional[List[Any]] = None,
subject: Optional[Any] = None
) -> None:
"""
Update the last result table WITHOUT adding to history.
"""
state = _get_pipeline_state()
# Update current table WITHOUT pushing to history
state.last_result_table = result_table
state.last_result_items = items or []
state.last_result_subject = subject
logger.exception("Failed to sort overlay result_table and reorder items")
@@ -747,7 +718,7 @@ def restore_previous_result_table() -> bool:
try:
debug_table_state("restore_previous_result_table")
except Exception:
pass
logger.exception("Failed to debug_table_state during restore_previous_result_table")
return True
@@ -805,7 +776,7 @@ def restore_next_result_table() -> bool:
try:
debug_table_state("restore_next_result_table")
except Exception:
pass
logger.exception("Failed to debug_table_state during restore_next_result_table")
return True
@@ -926,7 +897,7 @@ def debug_table_state(label: str = "") -> None:
f"history={len(state.result_table_history or [])} forward={len(state.result_table_forward or [])} last_selection={list(state.last_selection or [])}"
)
except Exception:
pass
logger.exception("Failed to debug_table_state buffers summary")
def get_last_selectable_result_items() -> List[Any]:
@@ -1133,7 +1104,7 @@ class PipelineExecutor:
if self._config_loader is not None:
return self._config_loader.load()
except Exception:
pass
logger.exception("Failed to use config_loader.load(); falling back to SYS.config.load_config")
try:
from SYS.config import load_config
@@ -1209,7 +1180,7 @@ class PipelineExecutor:
if hasattr(ctx, "clear_pipeline_stop"):
ctx.clear_pipeline_stop()
except Exception:
pass
logger.exception("Failed to clear pipeline stop via ctx.clear_pipeline_stop")
@staticmethod
def _maybe_seed_current_stage_table(ctx: Any) -> None:
@@ -1231,7 +1202,7 @@ class PipelineExecutor:
if last_table:
ctx.set_current_stage_table(last_table)
except Exception:
pass
logger.exception("Failed to seed current_stage_table from display or last table")
@staticmethod
def _maybe_apply_pending_pipeline_tail(ctx: Any,
@@ -1290,13 +1261,13 @@ class PipelineExecutor:
if hasattr(ctx, "clear_pending_pipeline_tail"):
ctx.clear_pending_pipeline_tail()
except Exception:
pass
logger.exception("Failed to clear pending pipeline tail after appending pending tail")
else:
try:
if hasattr(ctx, "clear_pending_pipeline_tail"):
ctx.clear_pending_pipeline_tail()
except Exception:
pass
logger.exception("Failed to clear pending pipeline tail (source mismatch branch)")
return stages
def _apply_quiet_background_flag(self, config: Any) -> Any:
@@ -1410,7 +1381,7 @@ class PipelineExecutor:
if isinstance(meta, dict):
_add(meta.get("provider"))
except Exception:
pass
logger.exception("Failed to inspect current_table/table metadata in _maybe_run_class_selector")
for item in selected_items or []:
if isinstance(item, dict):
@@ -1443,7 +1414,7 @@ class PipelineExecutor:
if prefix and is_known_provider_name(prefix):
_add(prefix)
except Exception:
pass
logger.exception("Failed while computing provider prefix heuristics in _maybe_run_class_selector")
if get_provider is not None:
for key in candidates:
@@ -1453,7 +1424,7 @@ class PipelineExecutor:
continue
except Exception:
# If the predicate fails for any reason, fall back to legacy behavior.
pass
logger.exception("is_known_provider_name predicate failed for key %s; falling back", key)
try:
provider = get_provider(key, config)
except Exception:
@@ -1511,7 +1482,7 @@ class PipelineExecutor:
if handled:
return True
except Exception:
pass
logger.exception("Failed while running store-based selector logic in _maybe_run_class_selector")
return False
@@ -1544,7 +1515,7 @@ class PipelineExecutor:
try:
worker_manager.append_stdout(worker_id, text + "\n", channel="log")
except Exception:
pass
logger.exception("Failed to append pipeline event to worker stdout for %s", worker_id)
@staticmethod
def _maybe_open_url_selection(
@@ -1632,7 +1603,7 @@ class PipelineExecutor:
kwargs["output"] = output_fn
ensure_background_notifier(worker_manager, **kwargs)
except Exception:
pass
logger.exception("Failed to enable background notifier for session_worker_ids=%r", session_worker_ids)
@staticmethod
def _get_raw_stage_texts(ctx: Any) -> List[str]:
@@ -1691,7 +1662,7 @@ class PipelineExecutor:
if last_table is not None:
ctx.set_current_stage_table(last_table)
except Exception:
pass
logger.exception("Failed to sync current_stage_table from display/last table in _maybe_apply_initial_selection")
source_cmd = None
source_args_raw = None
@@ -1836,7 +1807,7 @@ class PipelineExecutor:
f"@N expansion: {source_cmd} + selected_args={selected_row_args} + source_args={source_args}",
)
except Exception:
pass
logger.exception("Failed to record pipeline log step for @N expansion (pipeline_session=%r)", getattr(pipeline_session, 'worker_id', None))
stage_table = None
try:
@@ -1939,7 +1910,7 @@ class PipelineExecutor:
continue
seen_track_ids.add(tid)
except Exception:
pass
logger.exception("Failed to extract/parse track metadata in album processing")
track_items.append(tr)
if track_items:
@@ -1969,7 +1940,7 @@ class PipelineExecutor:
f"Applied @N selection {' | '.join(selection_parts)}",
)
except Exception:
pass
logger.exception("Failed to record Applied @N selection log step (pipeline_session=%r)", getattr(pipeline_session, 'worker_id', None))
# Auto-insert downloader stages for provider tables.
try:
@@ -1979,6 +1950,7 @@ class PipelineExecutor:
if current_table is None:
current_table = ctx.get_last_result_table()
except Exception:
logger.exception("Failed to determine current_table for selection auto-insert; defaulting to None")
current_table = None
table_type = None
try:
@@ -1990,6 +1962,7 @@ class PipelineExecutor:
if current_table and hasattr(current_table, "table") else None
)
except Exception:
logger.exception("Failed to compute table_type from current_table; using fallback attribute access")
table_type = (
current_table.table
if current_table and hasattr(current_table, "table") else None
@@ -2100,7 +2073,7 @@ class PipelineExecutor:
try:
print(f"Auto-running selection via {auto_stage[0]}")
except Exception:
pass
logger.exception("Failed to print auto-run selection message for %s", auto_stage[0])
# Append the auto stage now. If the user also provided a selection
# (e.g., @1 | add-file ...), we want to attach the row selection
# args *to the auto-inserted stage* so the download command receives
@@ -2137,44 +2110,54 @@ class PipelineExecutor:
tail = [str(x) for x in inserted[1:]]
stages[-1] = [cmd] + [str(x) for x in row_args] + tail
except Exception:
pass
logger.exception("Failed to attach selection args to auto-inserted stage")
# If no auto stage inserted and there are selection-action tokens available
# for the single selected row, apply it as the pipeline stage so a bare
# `@N` runs the intended action (e.g., get-file for hash-backed rows).
if not stages and selection_indices and len(selection_indices) == 1:
try:
idx = selection_indices[0]
debug(f"@N initial selection idx={idx} last_items={len(ctx.get_last_result_items() or [])}")
row_action = None
try:
row_action = ctx.get_current_stage_table_row_selection_action(idx)
except Exception:
row_action = None
if not row_action:
# If no auto stage inserted and there are selection-action tokens available
# for the single selected row, apply it as the pipeline stage so a bare
# `@N` runs the intended action (e.g., get-file for hash-backed rows).
if not stages and selection_indices and len(selection_indices) == 1:
try:
items = ctx.get_last_result_items() or []
if 0 <= idx < len(items):
maybe = items[idx]
# Provide explicit debug output about the payload selected
try:
if isinstance(maybe, dict):
debug(f"@N payload: hash={maybe.get('hash')} store={maybe.get('store')} _selection_args={maybe.get('_selection_args')} _selection_action={maybe.get('_selection_action')}")
else:
debug(f"@N payload object type: {type(maybe).__name__}")
except Exception:
pass
if isinstance(maybe, dict):
candidate = maybe.get("_selection_action")
if isinstance(candidate, (list, tuple)):
row_action = [str(x) for x in candidate if x is not None]
debug(f"@N restored row_action from payload: {row_action}")
except Exception:
idx = selection_indices[0]
debug(f"@N initial selection idx={idx} last_items={len(ctx.get_last_result_items() or [])}")
row_action = None
try:
row_action = ctx.get_current_stage_table_row_selection_action(idx)
except Exception:
logger.exception("Failed to get current_stage_table row selection action for idx %s", idx)
row_action = None
if row_action:
debug(f"@N applying row action -> {row_action}")
if not row_action:
try:
items = ctx.get_last_result_items() or []
if 0 <= idx < len(items):
maybe = items[idx]
try:
if isinstance(maybe, dict):
debug(f"@N payload: hash={maybe.get('hash')} store={maybe.get('store')} _selection_args={maybe.get('_selection_args')} _selection_action={maybe.get('_selection_action')}")
else:
debug(f"@N payload object type: {type(maybe).__name__}")
except Exception:
logger.exception("Failed to debug selection payload for index %s", idx)
if isinstance(maybe, dict):
candidate = maybe.get("_selection_action")
if isinstance(candidate, (list, tuple)):
row_action = [str(x) for x in candidate if x is not None]
except Exception:
row_action = None
if row_action:
debug(f"@N applying row action -> {row_action}")
stages.append(row_action)
if pipeline_session and worker_manager:
try:
worker_manager.log_step(
pipeline_session.worker_id,
f"@N applied row action -> {' '.join(row_action)}",
)
except Exception:
logger.exception("Failed to record pipeline log step for applied row action (pipeline_session=%r)", getattr(pipeline_session, 'worker_id', None))
except Exception:
logger.exception("Failed to apply single-row selection action")
stages.append(row_action)
if pipeline_session and worker_manager:
try:
@@ -2183,9 +2166,7 @@ class PipelineExecutor:
f"@N applied row action -> {' '.join(row_action)}",
)
except Exception:
pass
except Exception:
pass
logger.exception("Failed to record pipeline log step for applied row action (pipeline_session=%r)", getattr(pipeline_session, 'worker_id', None))
else:
first_cmd = stages[0][0] if stages and stages[0] else None
if isinstance(table_type, str) and table_type.startswith("metadata.") and first_cmd not in (
@@ -2234,7 +2215,7 @@ class PipelineExecutor:
tail = [str(x) for x in inserted[1:]]
stages[0] = [cmd] + [str(x) for x in row_args] + tail
except Exception:
pass
logger.exception("Failed to attach selection args to inserted auto stage (alternate branch)")
# After inserting/appending an auto-stage, continue processing so later
# selection-expansion logic can still run (e.g., for example selectors).
@@ -2304,7 +2285,7 @@ class PipelineExecutor:
continue
i += 1
except Exception:
pass
logger.exception("Failed to inspect add-file stage tokens for potential directory; skipping Live progress")
if not name:
continue
# Display-only: avoid Live progress for relationship viewing.
@@ -2342,7 +2323,7 @@ class PipelineExecutor:
if hasattr(_pipeline_ctx, "set_live_progress"):
_pipeline_ctx.set_live_progress(progress_ui)
except Exception:
pass
logger.exception("Failed to register PipelineLiveProgress with pipeline context")
pipe_index_by_stage = {
stage_idx: pipe_idx
for pipe_idx, stage_idx in enumerate(pipe_stage_indices)
@@ -2366,7 +2347,7 @@ class PipelineExecutor:
if hasattr(ctx, "set_current_stage_table"):
ctx.set_current_stage_table(None)
except Exception:
pass
logger.exception("Failed to clear current_stage_table in execute_tokens")
# Preflight (URL-duplicate prompts, etc.) should be cached within a single
# pipeline run, not across independent pipelines.
@@ -2374,7 +2355,7 @@ class PipelineExecutor:
ctx.store_value("preflight",
{})
except Exception:
pass
logger.exception("Failed to set preflight cache in execute_tokens")
stages = self._split_stages(tokens)
if not stages:
@@ -2482,7 +2463,7 @@ class PipelineExecutor:
try:
ctx.set_last_items(pipe_items)
except Exception:
pass
logger.exception("Failed to set last items after @ selection")
if pipeline_session and worker_manager:
try:
worker_manager.log_step(
@@ -2490,7 +2471,7 @@ class PipelineExecutor:
"@ used last result items"
)
except Exception:
pass
logger.exception("Failed to record pipeline log step for '@ used last result items' (pipeline_session=%r)", getattr(pipeline_session, 'worker_id', None))
continue
subject = ctx.get_last_result_subject()
@@ -2505,7 +2486,7 @@ class PipelineExecutor:
list) else [subject]
ctx.set_last_items(subject_items)
except Exception:
pass
logger.exception("Failed to set last_items from subject during @ handling")
if pipeline_session and worker_manager:
try:
worker_manager.log_step(
@@ -2513,7 +2494,7 @@ class PipelineExecutor:
"@ used current table subject"
)
except Exception:
pass
logger.exception("Failed to record pipeline log step for '@ used current table subject' (pipeline_session=%r)", getattr(pipeline_session, 'worker_id', None))
continue
if cmd_name.startswith("@"): # selection stage
@@ -2550,7 +2531,7 @@ class PipelineExecutor:
ctx.set_current_stage_table(display_table)
stage_table = display_table
except Exception:
pass
logger.exception("Failed to set current_stage_table from display table during selection processing")
if not stage_table and display_table is not None:
stage_table = display_table
@@ -2561,7 +2542,7 @@ class PipelineExecutor:
if hasattr(ctx, "debug_table_state"):
ctx.debug_table_state(f"selection {selection_token}")
except Exception:
pass
logger.exception("Failed to debug_table_state during selection %s", selection_token)
if display_table is not None and stage_table is display_table:
items_list = ctx.get_last_result_items() or []
@@ -2600,9 +2581,9 @@ class PipelineExecutor:
try:
debug(f"Selection sample object: provider={getattr(sample, 'provider', None)} store={getattr(sample, 'store', None)}")
except Exception:
pass
logger.exception("Failed to debug selection sample object")
except Exception:
pass
logger.exception("Failed to produce selection debug sample for token %s", selection_token)
if not filtered:
print("No items matched selection\n")
@@ -2628,14 +2609,14 @@ class PipelineExecutor:
if base_table is not None and getattr(base_table, "table", None):
new_table.set_table(str(getattr(base_table, "table")))
except Exception:
pass
logger.exception("Failed to set table on new_table for filter overlay")
try:
# Attach a one-line header so users see the active filter.
safe = str(selection_token)[1:].strip()
new_table.set_header_line(f'filter: "{safe}"')
except Exception:
pass
logger.exception("Failed to set header line for filter overlay for token %s", selection_token)
for item in filtered:
new_table.add_result(item)
@@ -2643,15 +2624,15 @@ class PipelineExecutor:
try:
ctx.set_last_result_table_overlay(new_table, items=list(filtered), subject=ctx.get_last_result_subject())
except Exception:
pass
logger.exception("Failed to set last_result_table_overlay for filter selection")
try:
stdout_console().print()
stdout_console().print(new_table)
except Exception:
pass
logger.exception("Failed to render filter overlay to stdout_console")
except Exception:
pass
logger.exception("Failed while rendering filter overlay for selection %s", selection_token)
continue
# UX: selecting a single URL row from get-url tables should open it.
@@ -2667,7 +2648,7 @@ class PipelineExecutor:
stage_is_last=(stage_index + 1 >= len(stages)),
)
except Exception:
pass
logger.exception("Failed to open URL selection for table %s", getattr(current_table, 'table', None))
if PipelineExecutor._maybe_run_class_selector(
ctx,
@@ -2685,6 +2666,7 @@ class PipelineExecutor:
).replace("_",
"-").lower()
except Exception:
logger.exception("Failed to determine next_cmd during selection expansion for stage_index %s", stage_index)
next_cmd = None
def _is_tag_row(obj: Any) -> bool:
@@ -2696,12 +2678,12 @@ class PipelineExecutor:
"tag_name")):
return True
except Exception:
pass
logger.exception("Failed to inspect TagItem object while checking _is_tag_row")
try:
if isinstance(obj, dict) and obj.get("tag_name"):
return True
except Exception:
pass
logger.exception("Failed to inspect dict tag_name while checking _is_tag_row")
return False
if (next_cmd in {"delete-tag",
@@ -2788,7 +2770,7 @@ class PipelineExecutor:
try:
print(f"Auto-running selection via {auto_stage[0]}")
except Exception:
pass
logger.exception("Failed to print auto-run selection message for %s", auto_stage[0])
stages.append(list(auto_stage))
else:
if auto_stage:
@@ -2885,12 +2867,12 @@ class PipelineExecutor:
stdout_console().print()
stdout_console().print(overlay_table)
except Exception:
pass
logger.exception("Failed to render overlay_table to stdout_console")
if session:
try:
session.close()
except Exception:
pass
logger.exception("Failed to close pipeline stage session")
except Exception as exc:
pipeline_status = "failed"
@@ -2907,26 +2889,26 @@ class PipelineExecutor:
try:
progress_ui.complete_all_pipes()
except Exception:
pass
logger.exception("Failed to complete all pipe UI tasks in progress_ui.complete_all_pipes")
try:
progress_ui.stop()
except Exception:
pass
logger.exception("Failed to stop progress_ui")
try:
from SYS import pipeline as _pipeline_ctx
if hasattr(_pipeline_ctx, "set_live_progress"):
_pipeline_ctx.set_live_progress(None)
except Exception:
pass
logger.exception("Failed to clear live_progress on pipeline context")
# Close pipeline session and log final status
try:
if pipeline_session and worker_manager:
pipeline_session.close(status=pipeline_status, error_msg=pipeline_error)
except Exception:
pass
logger.exception("Failed to close pipeline session during finalization")
try:
if pipeline_session and worker_manager:
self._log_pipeline_event(worker_manager, pipeline_session.worker_id,
f"Pipeline {pipeline_status}: {pipeline_error or ''}")
except Exception:
pass
logger.exception("Failed to log final pipeline status (pipeline_session=%r)", getattr(pipeline_session, 'worker_id', None))

View File

@@ -3,6 +3,8 @@ from __future__ import annotations
import sys
from contextlib import contextmanager
from typing import Any, Iterator, Optional, Sequence, Tuple
import logging
logger = logging.getLogger(__name__)
class PipelineProgress:
@@ -31,6 +33,7 @@ class PipelineProgress:
) if hasattr(self._ctx,
"get_live_progress") else None
except Exception:
logger.exception("Failed to get live progress UI from pipeline context")
ui = None
pipe_idx: int = 0
@@ -48,6 +51,7 @@ class PipelineProgress:
if isinstance(maybe_idx, int):
pipe_idx = int(maybe_idx)
except Exception:
logger.exception("Failed to determine pipe index from stage context")
pipe_idx = 0
return ui, pipe_idx
@@ -61,6 +65,7 @@ class PipelineProgress:
if callable(begin):
begin(int(pipe_idx), total_steps=int(total_steps))
except Exception:
logger.exception("Failed to call begin_pipe_steps on UI")
return
def step(self, text: str) -> None:
@@ -72,6 +77,7 @@ class PipelineProgress:
if callable(adv):
adv(int(pipe_idx), str(text))
except Exception:
logger.exception("Failed to advance pipe step on UI")
return
def set_percent(self, percent: int) -> None:
@@ -83,6 +89,7 @@ class PipelineProgress:
if callable(set_pct):
set_pct(int(pipe_idx), int(percent))
except Exception:
logger.exception("Failed to set pipe percent on UI")
return
def set_status(self, text: str) -> None:
@@ -94,6 +101,7 @@ class PipelineProgress:
if callable(setter):
setter(int(pipe_idx), str(text))
except Exception:
logger.exception("Failed to set pipe status text on UI")
return
def clear_status(self) -> None:
@@ -105,6 +113,7 @@ class PipelineProgress:
if callable(clr):
clr(int(pipe_idx))
except Exception:
logger.exception("Failed to clear pipe status text on UI")
return
def begin_transfer(self, *, label: str, total: Optional[int] = None) -> None:
@@ -116,6 +125,7 @@ class PipelineProgress:
if callable(fn):
fn(label=str(label or "transfer"), total=total)
except Exception:
logger.exception("Failed to begin transfer on UI")
return
def update_transfer(
@@ -133,6 +143,7 @@ class PipelineProgress:
if callable(fn):
fn(label=str(label or "transfer"), completed=completed, total=total)
except Exception:
logger.exception("Failed to update transfer on UI")
return
def finish_transfer(self, *, label: str) -> None:
@@ -144,6 +155,7 @@ class PipelineProgress:
if callable(fn):
fn(label=str(label or "transfer"))
except Exception:
logger.exception("Failed to finish transfer on UI")
return
def begin_pipe(
@@ -164,6 +176,7 @@ class PipelineProgress:
items_preview=list(items_preview or []),
)
except Exception:
logger.exception("Failed to begin pipe on UI")
return
def on_emit(self, emitted: Any) -> None:
@@ -178,6 +191,7 @@ class PipelineProgress:
try:
self._local_ui.on_emit(0, emitted)
except Exception:
logger.exception("Failed to call local UI on_emit")
return
def ensure_local_ui(
@@ -196,6 +210,7 @@ class PipelineProgress:
"get_live_progress") else None
)
except Exception:
logger.exception("Failed to check existing live progress from pipeline context")
existing = None
if existing is not None:
@@ -213,6 +228,7 @@ class PipelineProgress:
self._ctx.set_live_progress(ui)
self._local_attached = True
except Exception:
logger.exception("Failed to attach local UI to pipeline context")
self._local_attached = False
try:
@@ -223,11 +239,12 @@ class PipelineProgress:
items_preview=list(items_preview or [])
)
except Exception:
pass
logger.exception("Failed to begin_pipe on local UI")
self._local_ui = ui
return True
except Exception:
logger.exception("Failed to create local PipelineLiveProgress UI")
self._local_ui = None
self._local_attached = False
return False
@@ -239,18 +256,18 @@ class PipelineProgress:
try:
self._local_ui.finish_pipe(0, force_complete=bool(force_complete))
except Exception:
pass
logger.exception("Failed to finish local UI pipe")
try:
self._local_ui.stop()
except Exception:
pass
logger.exception("Failed to stop local UI")
finally:
self._local_ui = None
try:
if self._local_attached and hasattr(self._ctx, "set_live_progress"):
self._ctx.set_live_progress(None)
except Exception:
pass
logger.exception("Failed to detach local progress from pipeline context")
self._local_attached = False
@contextmanager

View File

@@ -25,6 +25,9 @@ from ProviderCore.base import SearchResult
from SYS.html_table import extract_records
import lxml.html as lxml_html
import logging
logger = logging.getLogger(__name__)
class TableProviderMixin:
"""Mixin to simplify providers that scrape table/list results from HTML.
@@ -56,15 +59,18 @@ class TableProviderMixin:
resp = client.get(url)
content = resp.content
except Exception:
logger.exception("Failed to fetch URL %s for provider %s", url, getattr(self, 'name', '<provider>'))
return []
# Ensure we pass an lxml document or string (httpx returns bytes)
try:
doc = lxml_html.fromstring(content)
except Exception:
logger.debug("Failed to parse content with lxml; attempting to decode as utf-8", exc_info=True)
try:
doc = content.decode("utf-8")
except Exception:
logger.debug("Failed to decode content as utf-8; falling back to str()", exc_info=True)
doc = str(content)
records, chosen = extract_records(doc, base_url=url, xpaths=xpaths or self.DEFAULT_XPATHS)

View File

@@ -43,6 +43,9 @@ else:
# Reuse the existing format_bytes helper under a clearer alias
from SYS.utils import format_bytes as format_mb
import logging
logger = logging.getLogger(__name__)
def _sanitize_cell_text(value: Any) -> str:
"""Coerce to a single-line, tab-free string suitable for terminal display."""
@@ -82,6 +85,7 @@ def _format_duration_hms(duration: Any) -> str:
else:
seconds = float(duration)
except Exception:
logger.debug("Failed to format duration '%s' to hms", duration, exc_info=True)
return ""
if seconds < 0:
@@ -118,6 +122,7 @@ class TableColumn:
try:
return self.extractor(item)
except Exception:
logger.exception("TableColumn.extract failed for key '%s'", self.key)
return None
@@ -137,6 +142,7 @@ def _as_dict(item: Any) -> Optional[Dict[str, Any]]:
if hasattr(item, "__dict__"):
return dict(getattr(item, "__dict__"))
except Exception:
logger.exception("Failed to convert %s to dict in _as_dict", type(item))
return None
return None
@@ -201,6 +207,7 @@ def extract_ext_value(item: Any) -> str:
if suf:
ext = suf.lstrip(".")
except Exception:
logger.debug("Failed to extract suffix from raw_path: %r", raw_path, exc_info=True)
ext = ""
ext_str = str(ext or "").strip().lstrip(".")
@@ -242,6 +249,7 @@ def extract_size_bytes_value(item: Any) -> Optional[int]:
# Some sources might provide floats or numeric strings
return int(float(s))
except Exception:
logger.debug("Failed to parse size value '%r' to int", size_val, exc_info=True)
return None
@@ -471,6 +479,7 @@ class Table:
"get_current_cmdlet_name") else ""
)
except Exception:
logger.debug("Failed to get current cmdlet name from pipeline context", exc_info=True)
cmdlet_name = ""
stage_text = ""
@@ -481,6 +490,7 @@ class Table:
"get_current_stage_text") else ""
)
except Exception:
logger.debug("Failed to get current stage text from pipeline context", exc_info=True)
stage_text = ""
if cmdlet_name and stage_text:
@@ -494,7 +504,8 @@ class Table:
"-").startswith(normalized_cmd):
self.title = normalized_stage
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to introspect pipeline context to set ResultTable title")
self.title_width = title_width
self.max_columns = (
max_columns if max_columns is not None else 5
@@ -558,6 +569,7 @@ class Table:
try:
return dict(self.table_metadata)
except Exception:
logger.exception("Failed to copy table metadata")
return {}
def _interactive(self, interactive: bool = True) -> "Table":
@@ -835,7 +847,8 @@ class Table:
val = col.format_fn(val)
row.add_column(col.header, val)
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to extract column '%s' for row %r", getattr(col, 'header', '<col>'), r)
return instance
@@ -913,11 +926,13 @@ class Table:
md = getattr(result, "full_metadata", None)
md_dict = dict(md) if isinstance(md, dict) else {}
except Exception:
logger.debug("Failed to extract full_metadata for result of type %s", type(result), exc_info=True)
md_dict = {}
try:
selection_args = getattr(result, "selection_args", None)
except Exception:
logger.debug("Failed to get selection_args from result of type %s", type(result), exc_info=True)
selection_args = None
if selection_args is None:
selection_args = md_dict.get("_selection_args") or md_dict.get("selection_args")
@@ -927,6 +942,7 @@ class Table:
try:
selection_action = getattr(result, "selection_action", None)
except Exception:
logger.debug("Failed to get selection_action from result of type %s", type(result), exc_info=True)
selection_action = None
if selection_action is None:
selection_action = md_dict.get("_selection_action") or md_dict.get("selection_action")
@@ -1084,13 +1100,16 @@ class Table:
and "table" not in visible_data and "source" not in visible_data):
visible_data["store"] = store_extracted
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to extract store value for item: %r", data)
try:
ext_extracted = extract_ext_value(data)
# Always ensure `ext` exists so priority_groups keeps a stable column.
visible_data["ext"] = str(ext_extracted or "")
except Exception:
from SYS.logger import logger
logger.exception("Failed to extract ext value for item: %r", data)
visible_data.setdefault("ext", "")
try:
@@ -1099,7 +1118,8 @@ class Table:
and "size" not in visible_data):
visible_data["size_bytes"] = size_extracted
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to extract size bytes for item: %r", data)
# Handle extension separation for local files
store_val = str(
@@ -1168,7 +1188,8 @@ class Table:
col_value,
integer_only=False
)
except Exception:
except Exception as exc:
logger.debug("Failed to format 'size' column value: %r", col_value, exc_info=True)
col_value_str = format_value(col_value)
elif isinstance(col_name,
str) and col_name.strip().lower() == "duration":
@@ -1178,7 +1199,8 @@ class Table:
else:
dur = _format_duration_hms(col_value)
col_value_str = dur or format_value(col_value)
except Exception:
except Exception as exc:
logger.debug("Failed to format 'duration' column value: %r", col_value, exc_info=True)
col_value_str = format_value(col_value)
else:
col_value_str = format_value(col_value)
@@ -1201,7 +1223,7 @@ class Table:
) # Don't display full metadata as column
except Exception:
# Fall back to regular field handling if columns format is unexpected
pass
logger.exception("Failed to process 'columns' dynamic field list: %r", visible_data.get("columns"))
# Only add priority groups if we haven't already filled columns from 'columns' field
if column_count == 0:

View File

@@ -8,6 +8,9 @@ possible and let callers decide whether to `Console.print()` or capture output.
from __future__ import annotations
from typing import Any, Dict, Iterable, Optional
import logging
logger = logging.getLogger(__name__)
from SYS.result_table_api import ColumnSpec, ResultModel, ResultTable, Renderer
@@ -40,11 +43,13 @@ class RichRenderer(Renderer):
if col.format_fn:
try:
cell = col.format_fn(raw)
except Exception:
except Exception as exc:
logger.exception("Column format function failed for '%s': %s", col.header, exc)
cell = str(raw or "")
else:
cell = str(raw or "")
except Exception:
except Exception as exc:
logger.exception("Column extractor failed for '%s': %s", col.header, exc)
cell = ""
cells.append(cell)
table.add_row(*cells)

View File

@@ -29,7 +29,8 @@ try:
except TypeError:
_pretty_install()
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to configure rich pretty-printing")
_STDOUT_CONSOLE = Console(file=sys.stdout)
_STDERR_CONSOLE = Console(file=sys.stderr)
@@ -261,8 +262,10 @@ def render_image_to_console(image_path: str | Path, max_width: int | None = None
console.print(line)
except Exception:
# Silently fail if image cannot be rendered (e.g. missing PIL or corrupted file)
pass
# Emit logs to help diagnose rendering failures (PIL missing, corrupt file, terminal limitations)
from SYS.logger import logger
logger.exception("Failed to render image to console: %s", image_path)
return
def render_item_details_panel(item: Dict[str, Any], *, title: Optional[str] = None) -> None:
@@ -279,7 +282,8 @@ def render_item_details_panel(item: Dict[str, Any], *, title: Optional[str] = No
view.title = ""
view.header_lines = []
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to sanitize ItemDetailView title/header before printing")
# We want to print ONLY the elements from ItemDetailView, so we don't use stdout_console().print(view)
# as that would include the (empty) results panel.

View File

@@ -528,6 +528,7 @@ def get_api_key(config: dict[str, Any], service: str, key_path: str) -> str | No
return None
except Exception:
_format_logger.exception("Failed to resolve nested config key '%s'", key_path)
return None

View File

@@ -9,6 +9,7 @@ from typing import Any, Dict, Optional, Set, TextIO, Sequence
from SYS.config import get_local_storage_path
from SYS.worker_manager import WorkerManager
from SYS.logger import log
class WorkerOutputMirror(io.TextIOBase):
@@ -69,7 +70,8 @@ class WorkerOutputMirror(io.TextIOBase):
try:
self._manager.append_stdout(self._worker_id, text, channel=self._channel)
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to append stdout for worker '%s' channel '%s'", self._worker_id, self._channel)
@property
def encoding(self) -> str: # type: ignore[override]
@@ -112,7 +114,8 @@ class WorkerStageSession:
self.stdout_proxy.flush()
self.stderr_proxy.flush()
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to flush worker stdout/stderr proxies for '%s'", self.worker_id)
sys.stdout = self.orig_stdout
sys.stderr = self.orig_stderr
@@ -121,7 +124,8 @@ class WorkerStageSession:
try:
self.manager.disable_logging_for_worker(self.worker_id)
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to disable logging for worker '%s'", self.worker_id)
try:
if status == "completed":
@@ -131,14 +135,16 @@ class WorkerStageSession:
self.worker_id, f"{self._error_label}: {error_msg or status}"
)
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to log step for worker '%s' status='%s' error='%s'", self.worker_id, status, error_msg)
try:
self.manager.finish_worker(
self.worker_id, result=status or "completed", error_msg=error_msg or ""
)
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to finish worker '%s' with status '%s'", self.worker_id, status)
if self.config and self.config.get("_current_worker_id") == self.worker_id:
self.config.pop("_current_worker_id", None)
@@ -177,7 +183,8 @@ class WorkerManagerRegistry:
try:
cls._manager.close()
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to close existing WorkerManager during registry ensure")
cls._manager = WorkerManager(resolved_root, auto_refresh_interval=0.5)
cls._manager_root = resolved_root
@@ -192,7 +199,8 @@ class WorkerManagerRegistry:
reason="CLI session ended unexpectedly; marking worker as failed",
)
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to expire running workers during registry ensure")
else:
cls._orphan_cleanup_done = True
@@ -202,7 +210,7 @@ class WorkerManagerRegistry:
return manager
except Exception as exc:
print(f"[worker] Could not initialize worker manager: {exc}", file=sys.stderr)
log(f"[worker] Could not initialize worker manager: {exc}", file=sys.stderr)
return None
@classmethod
@@ -212,7 +220,8 @@ class WorkerManagerRegistry:
try:
cls._manager.close()
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to close WorkerManager during registry.close()")
cls._manager = None
cls._manager_root = None
cls._orphan_cleanup_done = False
@@ -254,7 +263,7 @@ class WorkerStages:
if not tracked:
return None
except Exception as exc:
print(f"[worker] Failed to track {worker_type}: {exc}", file=sys.stderr)
log(f"[worker] Failed to track {worker_type}: {exc}", file=sys.stderr)
return None
if session_worker_ids is not None:
@@ -279,7 +288,8 @@ class WorkerStages:
try:
worker_manager.log_step(worker_id, f"Started {worker_type}")
except Exception:
pass
from SYS.logger import logger
logger.exception("Failed to log start step for worker '%s'", worker_id)
return WorkerStageSession(
manager=worker_manager,

View File

@@ -400,7 +400,7 @@ class WorkerManager:
try:
self.flush_worker_stdout(worker_id)
except Exception:
pass
logger.exception("Failed to flush worker stdout for '%s'", worker_id)
logger.debug(
f"[WorkerManager] Disabled logging for worker: {worker_id}"
@@ -516,7 +516,7 @@ class WorkerManager:
try:
self.flush_worker_stdout(worker_id)
except Exception:
pass
logger.exception("Failed to flush worker stdout for '%s' during finish", worker_id)
kwargs = {
"status": "finished",
"result": result
@@ -900,7 +900,7 @@ class WorkerManager:
try:
self._flush_all_stdout_buffers()
except Exception:
pass
logger.exception("Failed to flush all stdout buffers during WorkerManager.close()")
logger.info("[WorkerManager] Closed")
def _flush_all_stdout_buffers(self) -> None: