"""@file worker.py @brief Фоновый поток построения каталога. Разбор библиотеки идёт минутами и часами, поэтому выполняется в отдельном потоке QThread: окно остаётся отзывчивым, а ход работы приходит сигналами. """ from __future__ import annotations import traceback from pathlib import Path from PySide6.QtCore import QThread, Signal from .. import analyze as analyze_mod from .. import config, db, report, scanner class BuildWorker(QThread): """@brief Полный цикл: обход папки, анализ, выгрузка отчётов.""" #: сделано, всего, поясняющая строка progress = Signal(int, int, str) #: строка в журнал message = Signal(str) #: итоговая строка состояния finished_ok = Signal(str) #: текст ошибки с трассировкой failed = Signal(str) def __init__(self, root: Path, jobs: int, max_pages: int, force: bool = False, parent=None) -> None: super().__init__(parent) self._root = Path(root) self._jobs = jobs self._max_pages = max_pages self._force = force self._stop = False def request_stop(self) -> None: """@brief Просит остановиться после текущей порции файлов. Разобранное уже записано в базу, поэтому следующий запуск продолжит с того же места. """ self._stop = True def run(self) -> None: # noqa: D102 — контракт QThread try: config.remember(self._root) db_path, out_dir = config.paths_for(self._root) con = db.connect(db_path) self.message.emit("Папка: %s" % self._root) stats = scanner.scan( con, self._root, max_pages=self._max_pages, jobs=self._jobs, force=self._force, quiet=True, progress=lambda d, t, m: self.progress.emit(d, t, m), stop=lambda: self._stop) self.message.emit( "Разобрано %(processed)d, с ошибками %(errors)d, " "пропущено %(skipped)d, за %(seconds)s с" % stats) self.progress.emit(0, 0, "Анализ текстов…") analyze_mod.analyze( con, quiet=True, progress=lambda d, t, m: self.progress.emit(d, t, m)) self.progress.emit(0, 0, "Выгрузка отчётов…") for kind, path in report.build_all(con, out_dir).items(): self.message.emit("%-5s %s" % (kind, path)) total = con.execute("SELECT COUNT(*) c FROM docs").fetchone()["c"] con.close() self.finished_ok.emit( "Каталог готов: %d документов%s" % (total, " (остановлено)" if self._stop else "")) except Exception: # noqa: BLE001 — окно должно показать причину self.failed.emit(traceback.format_exc())