from __future__ import annotations import re from datetime import datetime FILE_NAME_PATTERNS = ( re.compile(r"^SKO115FZ_\d{2}_[A-Za-zА-Яа-я0-9]{9}_\d{8}_[ХX]\d{5}\.xml$"), ) DEFAULT_OUTPUT_DIR_NAME = "Out" DEFAULT_ERROR_DIR_NAME = "Err" DEFAULT_PROCESSED_DIR_NAME = "Processed" REPORT_FILE_TEMPLATE = "report_{date_key}_{run_number}.xlsx" PROTOCOL_FILE_TEMPLATE = "protocol_{date_key}_{run_number}.xlsx" PROCESS_LOG_FILE_TEMPLATE = "process_{date_key}_{run_number}.log" def validate_file_name(file_name: str) -> bool: return any(pattern.match(file_name) for pattern in FILE_NAME_PATTERNS) def build_date_parts(now: datetime | None = None) -> tuple[str, str, str, str]: current = now or datetime.now() year = str(current.year) month = str(current.month) day = str(current.day) date_key = current.strftime("%Y%m%d") return year, month, day, date_key def build_out_dir(base_dir: str, now: datetime | None = None) -> str: year, month, day, _ = build_date_parts(now) return join_path(base_dir, DEFAULT_OUTPUT_DIR_NAME, year, month, day) def build_run_dir(base_dir: str, run_number: int, now: datetime | None = None) -> str: out_dir = build_out_dir(base_dir, now) return join_path(out_dir, str(run_number)) def build_error_dir(base_dir: str) -> str: return join_path(base_dir, DEFAULT_ERROR_DIR_NAME) def build_processed_dir(base_dir: str) -> str: return join_path(base_dir, DEFAULT_PROCESSED_DIR_NAME) def build_report_file_name(date_key: str, run_number: int) -> str: return REPORT_FILE_TEMPLATE.format(date_key=date_key, run_number=run_number) def build_protocol_file_name(date_key: str, run_number: int) -> str: return PROTOCOL_FILE_TEMPLATE.format(date_key=date_key, run_number=run_number) def build_process_log_file_name(date_key: str, run_number: int) -> str: return PROCESS_LOG_FILE_TEMPLATE.format(date_key=date_key, run_number=run_number) def join_path(*parts: str) -> str: raw_parts = [part for part in parts if part and part.strip("/\\")] if not raw_parts: return "" first = raw_parts[0] is_unc = ( first.startswith("//") or first.startswith("\\\\") or first.startswith("/") or first.startswith("\\") ) cleaned = [part.replace("/", "\\").strip("\\") for part in raw_parts] joined = "\\".join(cleaned) if is_unc: return "\\\\" + joined.lstrip("\\") return joined def get_parent_dir(path: str) -> str: normalized = path.rstrip("/\\") if "\\" in normalized: return normalized.rsplit("\\", maxsplit=1)[0] if "/" in normalized: return normalized.rsplit("/", maxsplit=1)[0] return normalized