Refs #14 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
103 lines
5.4 KiB
Python
103 lines
5.4 KiB
Python
"""Доступ к реальным данным из `../fixtures` (отдельный репозиторий, внутренний доступ)."""
|
||
|
||
import os
|
||
from pathlib import Path
|
||
|
||
FIXTURES_ENV = "ARM_KA_FIXTURES"
|
||
OSV_EXTENSIONS = frozenset({".xls", ".xlsx", ".xlsb"})
|
||
STATEMENTS_DIR = "statements-xlsx"
|
||
_SYNTHETIC = "synthetic"
|
||
_OSV_DKB = "osv-dkb"
|
||
# Golden-снимок делается для файла пакета ДКБ не больше 1 МиБ: у больших (Агрокомплекс, 9–14 МБ, ~50 тыс. строк)
|
||
# снимок — десятки МБ JSON, для них остаются property-тесты инвариантов
|
||
GOLDEN_MAX_BYTES = 1024 * 1024
|
||
_ANALYSIS_REPORTS = "analysis-reports"
|
||
# Не фикстуры: скрытые файлы и каталоги («.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 osv_dkb_files(root: Path) -> list[Path]:
|
||
"""Файлы Excel пакета ДКБ `root/osv-dkb/**` (многолистовые книги, статусы `needs_check`), кроме отчётов
|
||
«Анализ счета» (`analysis-reports/`: не ОСВ); отсортированы. Нет каталога — пусто."""
|
||
directory = root / _OSV_DKB
|
||
if not directory.is_dir():
|
||
return []
|
||
reports = directory / _ANALYSIS_REPORTS
|
||
found = (path for path in directory.rglob("*") if _is_workbook(path, directory))
|
||
return sorted(path for path in found if reports not in path.parents)
|
||
|
||
|
||
def osv_dkb_golden_files(root: Path) -> list[Path]:
|
||
"""Файлы пакета ДКБ, для которых хранится golden-снимок: размер не больше `GOLDEN_MAX_BYTES`."""
|
||
return [path for path in osv_dkb_files(root) if path.stat().st_size <= GOLDEN_MAX_BYTES]
|
||
|
||
|
||
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))
|
||
|
||
|
||
def statement_files(root: Path) -> list[Path]:
|
||
"""Книги форм `root/statements-xlsx/**` (включая `templates/`), кроме `synthetic/`; отсортированы."""
|
||
directory = root / STATEMENTS_DIR
|
||
if not directory.is_dir():
|
||
return []
|
||
synthetic = directory / _SYNTHETIC
|
||
return sorted(
|
||
path for path in directory.rglob("*") if _is_workbook(path, directory) and synthetic not in path.parents
|
||
)
|
||
|
||
|
||
def statement_synthetic_files(root: Path) -> list[Path]:
|
||
"""Файлы синтетических форм `root/statements-xlsx/synthetic/*.xls|xlsx|xlsb`; отсортированы."""
|
||
directory = root / STATEMENTS_DIR / _SYNTHETIC
|
||
if not directory.is_dir():
|
||
return []
|
||
return sorted(path for path in directory.iterdir() if _is_workbook(path, directory))
|