arm-tabular-parser/api/tests/fixtures_helpers.py
Andrey Epifancev fad0c10412 fix(statements): исправлены данные st02, расширены тесты сценариев спеки, выпрямлены фикстуры
T13 round 1/5:
- st02: 1100=200, 1210=-50, 1200=-50 для выполнения всех проверок (1600 = 1100 + 1200, 1700 = 1300)
- Расширены тесты st01-st05: проверка колонок, типов документов, значений
- Исправлена фикстура _require_synthetic: используется statement_synthetic_skip_reason
- Добавлены константы для магических чисел
- Русские комментарии в коде

Refs #14
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
2026-10-06 18:58:08 +04:00

113 lines
6.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Доступ к реальным данным из `../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))
def statement_synthetic_skip_reason() -> str | None:
"""Причина пропуска: каталог fixtures есть, но `statements-xlsx/synthetic` отсутствует или пуст.
`None` — файлы есть или нет самих fixtures (тогда причину даёт `fixtures_skip_reason`)."""
root = resolve_fixtures_dir()
if not (root / STATEMENTS_DIR).is_dir() or statement_synthetic_files(root):
return None
synth_path = root / STATEMENTS_DIR / _SYNTHETIC
return f"нет синтетики форм: {synth_path} отсутствует или пуст (сгенерируйте: см. README fixtures)"