grid.py: Cell, MergedRange, Sheet (1-based, только непустые ячейки, ленивые индексы строк и merged; диапазоны больше 10 000 ячеек проверяются перебором), column_letter для диагностики. errors.py: ParserError и коды контракта. readers: read_book определяет формат по сигнатуре (zip → XLSX/XLSB по xl/workbook.bin, OLE2 → XLS), предупреждает о несовпадении с file_type; ошибки библиотек → UnreadableError одной строкой. Числа — Decimal(str(value)), bool отдельно, даты как datetime; xlsb без outline/merged с предупреждением. Тесты: синтетическая книга openpyxl, подмена file_type, мусор/обрезанные файлы, xlsb через подменённый pyxlsb; 66 реальных ОСВ читаются < 5 с с outline и merged; xls «62 за 3 квартал 2024»: строка 15 — outline 3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
50 lines
2.0 KiB
Python
50 lines
2.0 KiB
Python
"""Читатели на реальных ОСВ из ../fixtures: все 66 файлов читаются быстро, outline и merged на месте."""
|
||
|
||
import time
|
||
from pathlib import Path
|
||
from typing import cast
|
||
|
||
import pytest
|
||
|
||
from src.contract import FileType
|
||
from src.parser.readers import read_book
|
||
|
||
READ_SECONDS_LIMIT = 5.0
|
||
NAMED_XLS = "osv/schastl/2024-Q3/Оборотносальдовая ведомость по счету 62 за 3 квартал 2024 г..xls"
|
||
# Строка 15 (1-based) — контрагент «МАЛЕЧКИНСКАЯ ПТИЦЕФАБРИКА ООО» под 62 → 62.01 → «БП Аренда»
|
||
NAMED_XLS_ROW = 15
|
||
NAMED_XLS_OUTLINE = 3
|
||
|
||
|
||
@pytest.mark.fixtures
|
||
def test_real_file_is_read_quickly_with_outline_and_merged(osv_file: Path) -> None:
|
||
data = osv_file.read_bytes()
|
||
started = time.perf_counter()
|
||
|
||
sheets, warnings = read_book(data, cast(FileType, osv_file.suffix.lstrip(".").upper()))
|
||
|
||
assert time.perf_counter() - started < READ_SECONDS_LIMIT
|
||
assert warnings == []
|
||
assert sheets
|
||
assert any(sheet.row_outline for sheet in sheets)
|
||
assert all(level >= 1 for sheet in sheets for level in sheet.row_outline.values())
|
||
assert any(sheet.merged for sheet in sheets)
|
||
assert any(sheet.cells for sheet in sheets)
|
||
|
||
|
||
@pytest.mark.fixtures
|
||
def test_named_xls_outline_level(fixtures_dir: Path) -> None:
|
||
sheets, _ = read_book((fixtures_dir / NAMED_XLS).read_bytes(), "XLS")
|
||
|
||
sheet = sheets[0]
|
||
assert sheet.cell(NAMED_XLS_ROW, 1).text == "МАЛЕЧКИНСКАЯ ПТИЦЕФАБРИКА ООО"
|
||
assert sheet.outline(NAMED_XLS_ROW) == NAMED_XLS_OUTLINE
|
||
|
||
|
||
@pytest.mark.fixtures
|
||
def test_biff8_content_with_xlsx_file_type_is_read_as_xls(fixtures_dir: Path) -> None:
|
||
sheets, warnings = read_book((fixtures_dir / NAMED_XLS).read_bytes(), "XLSX")
|
||
|
||
assert warnings == ["file_type=XLSX, но содержимое BIFF8: прочитано как XLS"]
|
||
assert sheets[0].outline(NAMED_XLS_ROW) == NAMED_XLS_OUTLINE
|