"""Доступ к реальным данным из `../fixtures` (отдельный репозиторий, внутренний доступ).""" import os from pathlib import Path FIXTURES_ENV = "ARM_KA_FIXTURES" OSV_EXTENSIONS = frozenset({".xls", ".xlsx", ".xlsb"}) _SYNTHETIC = "synthetic" # Не фикстуры: скрытые файлы и каталоги («.DS_Store», «.cache/») и lock-файлы Excel («~$книга.xlsx», пока она открыта) _IGNORED_PREFIXES = (".", "~$") def _is_workbook(path: Path, base: Path) -> bool: """Файл книги Excel под `base`: расширение xls/xlsx/xlsb, ни файл, ни каталоги на пути — не скрытые и не lock.""" if not path.is_file() or path.suffix.lower() not in OSV_EXTENSIONS: return False return not any(part.startswith(_IGNORED_PREFIXES) for part in path.relative_to(base).parts) def resolve_fixtures_dir() -> Path: """Каталог фикстур: `ARM_KA_FIXTURES` или соседний с репозиторием `fixtures/` (workspace).""" override = os.environ.get(FIXTURES_ENV) if override: return Path(override) return Path(__file__).resolve().parents[3] / "fixtures" def fixtures_skip_reason() -> str | None: """Причина пропуска тестов на фикстурах (None — каталог доступен). Текст называет переменную и путь (OQ-81).""" root = resolve_fixtures_dir() if (root / "osv").is_dir(): return None return f"каталог фикстур не найден: {root} (задайте {FIXTURES_ENV}=<путь к репозиторию fixtures>)" def synthetic_skip_reason() -> str | None: """Причина пропуска тестов на синтетике: каталог fixtures есть, но `osv/synthetic` отсутствует или пуст (например, fixtures на main до слияния ветки с синтетикой). `None` — файлы есть или нет самих fixtures (тогда причину даёт `fixtures_skip_reason`).""" root = resolve_fixtures_dir() if not (root / "osv").is_dir() or synthetic_files(root): return None return f"нет синтетики: {root / 'osv' / _SYNTHETIC} отсутствует или пуст (сгенерируйте: см. README fixtures)" def osv_fixture_files(root: Path) -> list[Path]: """Все `*.xls/*.xlsx/*.xlsb` под `root/osv`, кроме каталога synthetic, скрытых и lock-файлов; отсортированы.""" osv = root / "osv" if not osv.is_dir(): return [] synthetic = osv / _SYNTHETIC return sorted(path for path in osv.rglob("*") if _is_workbook(path, osv) and synthetic not in path.parents) def synthetic_files(root: Path) -> list[Path]: """Файлы Excel `root/osv/synthetic/*.xls|xlsx|xlsb` (скрытые, lock-файлы `~$…` и пояснения вроде `README.md` не считаются); отсортированы.""" directory = root / "osv" / _SYNTHETIC if not directory.is_dir(): return [] return sorted(path for path in directory.iterdir() if _is_workbook(path, directory))