arm-tabular-parser/api/tests/unit/parser/test_gridbuilder.py
Andrey Epifancev a833945669 feat(parser): детекторы листов ОСВ, заголовка таблицы и колонок по содержимому
detect.py: classify_sheet (ОСВ / форма ББ-ОФР / прочее по словарю), find_table_header
(строка с ≥ 2 группами сумм, «Дебет/Кредит» под группой в пределах merged-диапазона
или до следующей группы, заголовок в 1–4 строки, в т.ч. «Нач. сальдо Дт» в одной
ячейке; без «начала»; свёрнутое сальдо в *_debit + collapsed; свёрнутые «Обороты» и
половинчатая пара Дт/Кт — InvalidFormatError с названием группы), text_col, inn_col
(заголовок «ИНН» или ≥ 80 % значений из 10/12 цифр), right_edge, extra_cols,
group_label_rows, first_data_row, is_header_repeat (две группы или копия строки блока).

Pattern.search_normalized — ячейка нормализуется один раз (T3.6). osv_groups: известные
группировки OTHER перечислены явно, чтобы строка-метка «Основные средства» в
неслитом заголовке была частью блока. Хелпер тестов gridbuilder (Sheet из «картинки»).

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

57 lines
2.0 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.

"""Хелпер тестов `gridbuilder`: «картинка» строк превращается в `Sheet` так же, как его видят детекторы."""
from decimal import Decimal
import pytest
from gridbuilder import C, L, M, at, sheet_from_rows
from src.parser.grid import MergedRange
def test_rows_and_columns_are_one_based_and_values_typed() -> None:
sheet = sheet_from_rows([["Счет", 100, Decimal("1.50")], [], [None, "x"]])
assert sheet.cell(1, 1).text == "Счет"
assert sheet.cell(1, 2).value == Decimal(100)
assert sheet.cell(1, 2).kind == "number"
assert sheet.cell(1, 3).value == Decimal("1.50")
assert sheet.cell(3, 2).text == "x"
assert (sheet.n_rows, sheet.n_cols) == (3, 3)
def test_merged_cell_occupies_its_width_and_covers_rows_below() -> None:
sheet = sheet_from_rows([[M("Сальдо", 2, 2), "Обороты"], [None, None, "Дебет"]])
assert sheet.merged == (MergedRange(1, 1, 2, 2),)
assert sheet.cell(1, 3).text == "Обороты"
assert sheet.text_at(2, 2) == "Сальдо"
assert sheet.cell(2, 3).text == "Дебет"
def test_value_under_merged_range_is_rejected() -> None:
with pytest.raises(ValueError, match="merged"):
sheet_from_rows([[M("Сальдо", 1, 2)], ["лишнее"]])
def test_outline_style_and_sparse_rows() -> None:
sheet = sheet_from_rows([[L(2), C("60.01", bold=True, indent=3)], at({4: 7})])
assert [sheet.outline(1)] == [2]
assert sheet.outline(2) == 0
assert sheet.cell(1, 1).bold
assert [sheet.cell(1, 1).indent] == [3]
assert sheet.cell(2, 4).value == Decimal(7)
assert [sheet.n_cols] == [4]
def test_whitespace_text_is_kept_as_a_cell_but_row_is_empty_for_detectors() -> None:
sheet = sheet_from_rows([[" ", "\u00a0"]])
assert (1, 1) in sheet.cells
assert sheet.is_row_empty(1)
def test_float_is_rejected() -> None:
with pytest.raises(TypeError, match="float"):
sheet_from_rows([[0.1]])