Add YAPF style + ignore, and format tracked Python files
This commit is contained in:
173
TUI/tui.py
173
TUI/tui.py
@@ -38,10 +38,10 @@ for path in (BASE_DIR, ROOT_DIR):
|
||||
from pipeline_runner import PipelineRunResult # type: ignore # noqa: E402
|
||||
from result_table import ResultTable # type: ignore # noqa: E402
|
||||
|
||||
from config import load_config # type: ignore # noqa: E402
|
||||
from SYS.config import load_config # type: ignore # noqa: E402
|
||||
from Store.registry import Store as StoreRegistry # type: ignore # noqa: E402
|
||||
from cmdlet_catalog import ensure_registry_loaded, list_cmdlet_names # type: ignore # noqa: E402
|
||||
from cli_syntax import validate_pipeline_text # type: ignore # noqa: E402
|
||||
from SYS.cmdlet_catalog import ensure_registry_loaded, list_cmdlet_names # type: ignore # noqa: E402
|
||||
from SYS.cli_syntax import validate_pipeline_text # type: ignore # noqa: E402
|
||||
|
||||
from pipeline_runner import PipelineRunner # type: ignore # noqa: E402
|
||||
|
||||
@@ -84,6 +84,7 @@ def _extract_tag_names(emitted: Sequence[Any]) -> List[str]:
|
||||
|
||||
|
||||
class TextPopup(ModalScreen[None]):
|
||||
|
||||
def __init__(self, *, title: str, text: str) -> None:
|
||||
super().__init__()
|
||||
self._title = str(title)
|
||||
@@ -100,7 +101,14 @@ class TextPopup(ModalScreen[None]):
|
||||
|
||||
|
||||
class TagEditorPopup(ModalScreen[None]):
|
||||
def __init__(self, *, seeds: Any, store_name: str, file_hash: Optional[str]) -> None:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
seeds: Any,
|
||||
store_name: str,
|
||||
file_hash: Optional[str]
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._seeds = seeds
|
||||
self._store = str(store_name or "").strip()
|
||||
@@ -138,7 +146,10 @@ class TagEditorPopup(ModalScreen[None]):
|
||||
except Exception as exc:
|
||||
tags = []
|
||||
try:
|
||||
app.call_from_thread(self._set_status, f"Error: {type(exc).__name__}: {exc}")
|
||||
app.call_from_thread(
|
||||
self._set_status,
|
||||
f"Error: {type(exc).__name__}: {exc}"
|
||||
)
|
||||
except Exception:
|
||||
self._set_status(f"Error: {type(exc).__name__}: {exc}")
|
||||
self._original_tags = tags
|
||||
@@ -172,8 +183,10 @@ class TagEditorPopup(ModalScreen[None]):
|
||||
desired = self._parse_editor_tags()
|
||||
current = _dedup_preserve_order(list(self._original_tags or []))
|
||||
|
||||
desired_set = {t.lower() for t in desired}
|
||||
current_set = {t.lower() for t in current}
|
||||
desired_set = {t.lower()
|
||||
for t in desired}
|
||||
current_set = {t.lower()
|
||||
for t in current}
|
||||
|
||||
to_add = [t for t in desired if t.lower() not in current_set]
|
||||
to_del = [t for t in current if t.lower() not in desired_set]
|
||||
@@ -187,7 +200,10 @@ class TagEditorPopup(ModalScreen[None]):
|
||||
|
||||
@work(thread=True)
|
||||
def _save_tags_background(
|
||||
self, to_add: List[str], to_del: List[str], desired: List[str]
|
||||
self,
|
||||
to_add: List[str],
|
||||
to_del: List[str],
|
||||
desired: List[str]
|
||||
) -> None:
|
||||
app = self.app # PipelineHubApp
|
||||
try:
|
||||
@@ -204,9 +220,11 @@ class TagEditorPopup(ModalScreen[None]):
|
||||
if not getattr(del_res, "success", False):
|
||||
failures.append(
|
||||
str(
|
||||
getattr(del_res, "error", "")
|
||||
or getattr(del_res, "stderr", "")
|
||||
or "delete-tag failed"
|
||||
getattr(del_res,
|
||||
"error",
|
||||
"") or getattr(del_res,
|
||||
"stderr",
|
||||
"") or "delete-tag failed"
|
||||
).strip()
|
||||
)
|
||||
|
||||
@@ -217,9 +235,11 @@ class TagEditorPopup(ModalScreen[None]):
|
||||
if not getattr(add_res, "success", False):
|
||||
failures.append(
|
||||
str(
|
||||
getattr(add_res, "error", "")
|
||||
or getattr(add_res, "stderr", "")
|
||||
or "add-tag failed"
|
||||
getattr(add_res,
|
||||
"error",
|
||||
"") or getattr(add_res,
|
||||
"stderr",
|
||||
"") or "add-tag failed"
|
||||
).strip()
|
||||
)
|
||||
|
||||
@@ -233,12 +253,18 @@ class TagEditorPopup(ModalScreen[None]):
|
||||
|
||||
self._original_tags = list(desired)
|
||||
try:
|
||||
app.call_from_thread(self._set_status, f"Saved (+{len(to_add)}, -{len(to_del)})")
|
||||
app.call_from_thread(
|
||||
self._set_status,
|
||||
f"Saved (+{len(to_add)}, -{len(to_del)})"
|
||||
)
|
||||
except Exception:
|
||||
self._set_status(f"Saved (+{len(to_add)}, -{len(to_del)})")
|
||||
except Exception as exc:
|
||||
try:
|
||||
app.call_from_thread(self._set_status, f"Error: {type(exc).__name__}: {exc}")
|
||||
app.call_from_thread(
|
||||
self._set_status,
|
||||
f"Error: {type(exc).__name__}: {exc}"
|
||||
)
|
||||
except Exception:
|
||||
self._set_status(f"Error: {type(exc).__name__}: {exc}")
|
||||
|
||||
@@ -248,10 +274,20 @@ class PipelineHubApp(App):
|
||||
|
||||
CSS_PATH = "tui.tcss"
|
||||
BINDINGS = [
|
||||
Binding("ctrl+enter", "run_pipeline", "Run Pipeline"),
|
||||
Binding("f5", "refresh_workers", "Refresh Workers"),
|
||||
Binding("ctrl+l", "focus_command", "Focus Input", show=False),
|
||||
Binding("ctrl+g", "focus_logs", "Focus Logs", show=False),
|
||||
Binding("ctrl+enter",
|
||||
"run_pipeline",
|
||||
"Run Pipeline"),
|
||||
Binding("f5",
|
||||
"refresh_workers",
|
||||
"Refresh Workers"),
|
||||
Binding("ctrl+l",
|
||||
"focus_command",
|
||||
"Focus Input",
|
||||
show=False),
|
||||
Binding("ctrl+g",
|
||||
"focus_logs",
|
||||
"Focus Logs",
|
||||
show=False),
|
||||
]
|
||||
|
||||
def __init__(self) -> None:
|
||||
@@ -281,7 +317,10 @@ class PipelineHubApp(App):
|
||||
with Container(id="app-shell"):
|
||||
with Vertical(id="command-pane"):
|
||||
with Horizontal(id="command-row"):
|
||||
yield Input(placeholder="Enter pipeline command...", id="pipeline-input")
|
||||
yield Input(
|
||||
placeholder="Enter pipeline command...",
|
||||
id="pipeline-input"
|
||||
)
|
||||
yield Button("Run", id="run-button")
|
||||
yield Button("Tags", id="tags-button")
|
||||
yield Button("Metadata", id="metadata-button")
|
||||
@@ -392,7 +431,10 @@ class PipelineHubApp(App):
|
||||
suggestion = str(event.option.prompt)
|
||||
except Exception:
|
||||
return
|
||||
new_text = self._apply_suggestion_to_text(str(self.command_input.value or ""), suggestion)
|
||||
new_text = self._apply_suggestion_to_text(
|
||||
str(self.command_input.value or ""),
|
||||
suggestion
|
||||
)
|
||||
self.command_input.value = new_text
|
||||
self.suggestion_list.display = False
|
||||
self.command_input.focus()
|
||||
@@ -428,7 +470,8 @@ class PipelineHubApp(App):
|
||||
return
|
||||
|
||||
self.command_input.value = self._apply_suggestion_to_text(
|
||||
str(self.command_input.value or ""), suggestion
|
||||
str(self.command_input.value or ""),
|
||||
suggestion
|
||||
)
|
||||
if self.suggestion_list:
|
||||
self.suggestion_list.display = False
|
||||
@@ -436,7 +479,9 @@ class PipelineHubApp(App):
|
||||
event.stop()
|
||||
|
||||
def _get_first_suggestion(self) -> str:
|
||||
if not self.suggestion_list or not bool(getattr(self.suggestion_list, "display", False)):
|
||||
if not self.suggestion_list or not bool(getattr(self.suggestion_list,
|
||||
"display",
|
||||
False)):
|
||||
return ""
|
||||
# Textual OptionList API differs across versions; handle best-effort.
|
||||
try:
|
||||
@@ -525,9 +570,9 @@ class PipelineHubApp(App):
|
||||
first_stage_cmd = ""
|
||||
try:
|
||||
first_stage_cmd = (
|
||||
str(stages[0].split()[0]).replace("_", "-").strip().lower()
|
||||
if stages[0].split()
|
||||
else ""
|
||||
str(stages[0].split()[0]).replace("_",
|
||||
"-").strip().lower()
|
||||
if stages[0].split() else ""
|
||||
)
|
||||
except Exception:
|
||||
first_stage_cmd = ""
|
||||
@@ -536,7 +581,8 @@ class PipelineHubApp(App):
|
||||
if output_path:
|
||||
first = stages[0]
|
||||
low = first.lower()
|
||||
if low.startswith("download-media") and " -path" not in low and " --path" not in low:
|
||||
if low.startswith("download-media"
|
||||
) and " -path" not in low and " --path" not in low:
|
||||
stages[0] = f"{first} -path {json.dumps(output_path)}"
|
||||
|
||||
joined = " | ".join(stages)
|
||||
@@ -545,9 +591,12 @@ class PipelineHubApp(App):
|
||||
|
||||
# Only auto-append add-file for download pipelines.
|
||||
should_auto_add_file = bool(
|
||||
selected_store
|
||||
and ("add-file" not in low_joined)
|
||||
and (first_stage_cmd in {"download-media", "download-file", "download-torrent"})
|
||||
selected_store and ("add-file" not in low_joined) and (
|
||||
first_stage_cmd
|
||||
in {"download-media",
|
||||
"download-file",
|
||||
"download-torrent"}
|
||||
)
|
||||
)
|
||||
|
||||
if should_auto_add_file:
|
||||
@@ -570,7 +619,10 @@ class PipelineHubApp(App):
|
||||
@work(exclusive=True, thread=True)
|
||||
def _run_pipeline_background(self, pipeline_text: str) -> None:
|
||||
try:
|
||||
run_result = self.executor.run_pipeline(pipeline_text, on_log=self._log_from_worker)
|
||||
run_result = self.executor.run_pipeline(
|
||||
pipeline_text,
|
||||
on_log=self._log_from_worker
|
||||
)
|
||||
except Exception as exc:
|
||||
# Ensure the UI never gets stuck in "running" state.
|
||||
run_result = PipelineRunResult(
|
||||
@@ -589,7 +641,11 @@ class PipelineHubApp(App):
|
||||
self._set_status(status_text, level=status_level)
|
||||
|
||||
if not run_result.success:
|
||||
self.notify(run_result.error or "Pipeline failed", severity="error", timeout=6)
|
||||
self.notify(
|
||||
run_result.error or "Pipeline failed",
|
||||
severity="error",
|
||||
timeout=6
|
||||
)
|
||||
else:
|
||||
self.notify("Pipeline completed", timeout=3)
|
||||
|
||||
@@ -649,13 +705,23 @@ class PipelineHubApp(App):
|
||||
|
||||
# Fallback for items without a table
|
||||
for idx, item in enumerate(self.result_items, start=1):
|
||||
self.results_table.add_row(str(idx), str(item), "—", "—", key=str(idx - 1))
|
||||
self.results_table.add_row(
|
||||
str(idx),
|
||||
str(item),
|
||||
"—",
|
||||
"—",
|
||||
key=str(idx - 1)
|
||||
)
|
||||
|
||||
def _load_cmdlet_names(self) -> None:
|
||||
try:
|
||||
ensure_registry_loaded()
|
||||
names = list_cmdlet_names() or []
|
||||
self._cmdlet_names = sorted({str(n).replace("_", "-") for n in names if str(n).strip()})
|
||||
self._cmdlet_names = sorted(
|
||||
{str(n).replace("_",
|
||||
"-")
|
||||
for n in names if str(n).strip()}
|
||||
)
|
||||
except Exception:
|
||||
self._cmdlet_names = []
|
||||
|
||||
@@ -702,10 +768,14 @@ class PipelineHubApp(App):
|
||||
pass
|
||||
|
||||
try:
|
||||
self.suggestion_list.add_options([Option(m) for m in matches]) # type: ignore[attr-defined]
|
||||
self.suggestion_list.add_options(
|
||||
[Option(m) for m in matches]
|
||||
) # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
try:
|
||||
self.suggestion_list.options = [Option(m) for m in matches] # type: ignore[attr-defined]
|
||||
self.suggestion_list.options = [
|
||||
Option(m) for m in matches
|
||||
] # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -743,7 +813,11 @@ class PipelineHubApp(App):
|
||||
parts[-1] = leading + replaced
|
||||
return "|".join(parts)
|
||||
|
||||
def _resolve_selected_item(self) -> Tuple[Optional[Any], Optional[str], Optional[str]]:
|
||||
def _resolve_selected_item(
|
||||
self
|
||||
) -> Tuple[Optional[Any],
|
||||
Optional[str],
|
||||
Optional[str]]:
|
||||
"""Return (item, store_name, hash) for the currently selected row."""
|
||||
index = int(getattr(self, "_selected_row_index", 0) or 0)
|
||||
if index < 0:
|
||||
@@ -753,8 +827,9 @@ class PipelineHubApp(App):
|
||||
|
||||
# Prefer mapping displayed table row -> source item.
|
||||
if self.current_result_table and 0 <= index < len(
|
||||
getattr(self.current_result_table, "rows", []) or []
|
||||
):
|
||||
getattr(self.current_result_table,
|
||||
"rows",
|
||||
[]) or []):
|
||||
row = self.current_result_table.rows[index]
|
||||
src_idx = getattr(row, "source_index", None)
|
||||
if isinstance(src_idx, int) and 0 <= src_idx < len(self.result_items):
|
||||
@@ -807,7 +882,11 @@ class PipelineHubApp(App):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.push_screen(TagEditorPopup(seeds=seeds, store_name=store_name, file_hash=file_hash))
|
||||
self.push_screen(
|
||||
TagEditorPopup(seeds=seeds,
|
||||
store_name=store_name,
|
||||
file_hash=file_hash)
|
||||
)
|
||||
|
||||
def _open_metadata_popup(self) -> None:
|
||||
item, _store_name, _file_hash = self._resolve_selected_item()
|
||||
@@ -817,10 +896,13 @@ class PipelineHubApp(App):
|
||||
text = ""
|
||||
idx = int(getattr(self, "_selected_row_index", 0) or 0)
|
||||
if self.current_result_table and 0 <= idx < len(
|
||||
getattr(self.current_result_table, "rows", []) or []
|
||||
):
|
||||
getattr(self.current_result_table,
|
||||
"rows",
|
||||
[]) or []):
|
||||
row = self.current_result_table.rows[idx]
|
||||
lines = [f"{col.name}: {col.value}" for col in getattr(row, "columns", []) or []]
|
||||
lines = [
|
||||
f"{col.name}: {col.value}" for col in getattr(row, "columns", []) or []
|
||||
]
|
||||
text = "\n".join(lines)
|
||||
elif isinstance(item, dict):
|
||||
try:
|
||||
@@ -911,7 +993,8 @@ class PipelineHubApp(App):
|
||||
worker_type = str(worker.get("worker_type") or worker.get("type") or "?")
|
||||
status = str(worker.get("status") or worker.get("result") or "running")
|
||||
details = (
|
||||
worker.get("current_step") or worker.get("description") or worker.get("pipe") or ""
|
||||
worker.get("current_step") or worker.get("description")
|
||||
or worker.get("pipe") or ""
|
||||
)
|
||||
self.worker_table.add_row(worker_id, worker_type, status, str(details)[:80])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user