"""Локальный прогон пайплайна без SMB и без Streamlit UI. Берёт XML-файлы из указанной локальной папки, парсит их и формирует report.xlsx + protocol.xlsx в текущей рабочей директории (или в папке, заданной через --out). Пример: python scripts/run_local.py /path/to/xml_folder python scripts/run_local.py /path/to/xml_folder --out /tmp/result """ from __future__ import annotations import argparse import getpass import sys from datetime import datetime from pathlib import Path ROOT = Path(__file__).resolve().parent if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from app.pipeline.parser import parse_xml_content # noqa: E402 from app.pipeline.protocol import ProtocolRow, write_protocol # noqa: E402 from app.pipeline.report import ReportRow, StreamingReportWriter # noqa: E402 from app.pipeline.service import ( # noqa: E402 # переиспользуем логику статуса _resolve_parse_status, ) def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("input_dir", type=Path, help="Локальная папка с XML-файлами") parser.add_argument( "--out", type=Path, default=Path.cwd(), help="Куда сохранить report.xlsx/protocol.xlsx (по умолчанию — текущая директория)", ) parser.add_argument( "--launcher", default=getpass.getuser(), help="Имя запустившего (для протокола); по умолчанию — текущий пользователь ОС", ) args = parser.parse_args() input_dir: Path = args.input_dir out_dir: Path = args.out if not input_dir.is_dir(): print(f"Папка не найдена: {input_dir}", file=sys.stderr) return 1 out_dir.mkdir(parents=True, exist_ok=True) xml_paths = sorted(input_dir.rglob("*.xml")) if not xml_paths: print(f"В {input_dir} не найдено XML-файлов.") return 1 report_writer = StreamingReportWriter() protocol_rows: list[ProtocolRow] = [] for xml_path in xml_paths: file_name = xml_path.name content = xml_path.read_bytes() parse_result = parse_xml_content(file_name=file_name, xml_content=content) for row in parse_result.rows: report_writer.append_row( ReportRow( file_name=row.file_name, record_id=row.record_id, operation_index=row.operation_index, operation_fields=row.operation_fields, participant_fields=row.participant_fields, is_continuation=row.is_continuation, ) ) status, message = _resolve_parse_status(parse_result) protocol_rows.append( ProtocolRow( file_name=file_name, status=status, message=message, operations_total=parse_result.total_operations, rows_written=len(parse_result.rows), launcher=args.launcher, processed_at=datetime.now(), ) ) print(f"{file_name}: {status} — {message}") report_path = out_dir / "report.xlsx" protocol_path = out_dir / "protocol.xlsx" report_writer.save(report_path) write_protocol(protocol_rows, protocol_path) processed = sum(1 for r in protocol_rows if r.status == "success") partial = sum(1 for r in protocol_rows if r.status == "partial") errors = sum(1 for r in protocol_rows if r.status == "error") print(f"\nГотово: успешно={processed}, частично={partial}, с ошибками={errors}.") print(f"Отчёт: {report_path}") print(f"Протокол: {protocol_path}") return 0 if __name__ == "__main__": raise SystemExit(main())