arm-tabular-parser/api/tests/fixtures/test_hierarchy_real.py
Andrey Epifancev 4a16f193af feat(parser): классификация строк по group_schema (§1.3)
classify.py: collect_body_rows — строки таблицы до «Итого» (пустые, из пробелов,
повторы заголовка и строки правее таблицы пропускаются; подвал после «Итого» не данные),
«Итого» по тексту и корневому оформлению до уровней, без требования сумм (R-13, T3.3),
шесть сумм через to_money с номером строки в предупреждениях, свёрнутое сальдо по знаку
(R-1); classify_rows — ACCOUNT по ACCOUNT_RE, позиция в схеме, OTHER за схемой, TOTAL,
COUNTERPARTY с ИНН (inn_digits), Вал./Кол./код валюты -> data_type, extra без
дубликатов ключей и без колонок подвала (T4.5).

Fixtures-тесты иерархии (R-2) и классификации на всех 66 реальных ОСВ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-05 14:07:33 +04:00

45 lines
2.2 KiB
Python
Raw 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 (ruling R-2, R-13; spec «Иерархия строк — каскад стратегий»).
Свойства без таблицы файлов: дерево непротиворечиво, «Итого» — уровень 0; у файла со строками данных — `outline`
(у всех фикстур есть группировки Excel), у пустой ОСВ (только «Итого») — `trivial`. Разбор файла укладывается в 5 с.
"""
from pathlib import Path
import pytest
from real_osv import parse_real
from src.parser.hierarchy import TRIVIAL_STRATEGY, is_consistent
MAX_SECONDS_PER_FILE = 5
RB_66_FY = Path("osv/rb/2024-FY/ОСВ_66 за 2024.xls")
YUG_FINANS = "Юг-Финанс / ПЕКАРНЯ СЧАСТЛИВОЧНАЯ"
COUNTERPARTY_LEVEL = 2 # счёт (0) → субсчёт (1) → контрагент (2)
@pytest.mark.fixtures
def test_real_osv_hierarchy(osv_file: Path) -> None:
parsed = parse_real(osv_file)
assert is_consistent(parsed.body, parsed.levels.by_row, parsed.total_row)
assert parsed.total_row is not None
assert parsed.levels.by_row[parsed.total_row] == 0
assert parsed.levels.parent[parsed.total_row] is None
expected = "outline" if parsed.data_rows else TRIVIAL_STRATEGY
assert parsed.levels.strategy == expected
assert parsed.seconds < MAX_SECONDS_PER_FILE
@pytest.mark.fixtures
def test_rb_66_fy_outline_tree(fixtures_dir: Path) -> None:
"""Spec «Outline level (реальные файлы)»: 66 (0) → 66.01 (1) → контрагент (2); «Юг-Финанс» — под 66.03."""
parsed = parse_real(fixtures_dir / RB_66_FY)
assert parsed.levels.strategy == "outline"
account, subaccount, counterparty = parsed.rows[:3]
assert [(account.body.text, account.level), (subaccount.body.text, subaccount.level)] == [("66", 0), ("66.01", 1)]
assert (counterparty.level, counterparty.parent) == (COUNTERPARTY_LEVEL, subaccount.body.row)
first = parsed.by_text(YUG_FINANS)[0]
assert first.parent is not None
assert parsed.row(first.parent).body.text == "66.03"