from __future__ import annotations import logging import threading from PySide6.QtCore import Property, QObject, Qt, Signal, Slot from pygui.backend.utils import slot_error_boundary from pygui.backend.wafer.batch_export import BatchExportResult, export_batch log = logging.getLogger(__name__) class BatchExportController(QObject): busyChanged = Signal() exportFinished = Signal(str) _batchFinished = Signal(list) def __init__(self, parent: QObject | None = None) -> None: super().__init__(parent) self._busy = False self._batchFinished.connect(self._handle_batch_finished, Qt.ConnectionType.QueuedConnection) @Property(bool, notify=busyChanged) def busy(self) -> bool: return self._busy @Slot("QVariantList", str) def start(self, file_paths: list, output_dir: str) -> None: if self._busy: return self._busy = True self.busyChanged.emit() threading.Thread( target=self._worker, args=(list(file_paths), output_dir), daemon=True ).start() def _worker(self, file_paths: list[str], output_dir: str) -> None: try: results = export_batch(file_paths, output_dir) except Exception as exc: log.exception("Batch export worker crashed: %s", exc) results = [] self._batchFinished.emit(results) @Slot(list) @slot_error_boundary def _handle_batch_finished(self, results: list[BatchExportResult]) -> None: try: total = len(results) succeeded = sum(1 for r in results if r.success) failed = total - succeeded summary = ( f"Exported {succeeded}/{total} — {failed} failed" if failed else f"Exported {succeeded}/{total}" ) self.exportFinished.emit(summary) finally: self._busy = False self.busyChanged.emit()