fix(parser): ячейки из одних пробелов не хранятся в Sheet.cells (T2.1)
make_cell возвращает None для строки, у которой strip() пуст (пробелы, NBSP и прочие Unicode-пробелы): «пробелы = пусто» на уровне хранения, sheet.cell даёт EMPTY_CELL. Тесты: пробельные ячейки xlsx/xlsb отсутствуют в cells, строка из пробелов пуста, merged-диапазон с пробельным origin даёт "". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
This commit is contained in:
parent
ed401a00a3
commit
c6a768dc70
@ -19,7 +19,8 @@ def make_cell(value: object, *, bold: bool = False, indent: int = 0) -> Cell | N
|
||||
"""Ячейка из значения библиотеки чтения; `None` — пустая ячейка (в `Sheet.cells` не попадает).
|
||||
|
||||
Числа — `Decimal(str(value))` без квантования (его делает `numbers.py`); bool проверяется раньше int.
|
||||
Строка из пробелов остаётся `text` (значение как пришло), её `Cell.text` пуст. Время без даты — текстом.
|
||||
Строка из одних пробельных символов (включая NBSP) — пустая ячейка (`None`): «пробелы» = пусто на уровне
|
||||
хранения, а не только в аксессорах `Sheet`. Время без даты — текстом.
|
||||
"""
|
||||
if value is None or value == "":
|
||||
return None
|
||||
@ -30,6 +31,8 @@ def make_cell(value: object, *, bold: bool = False, indent: int = 0) -> Cell | N
|
||||
if isinstance(value, datetime.date): # datetime.datetime — подкласс date
|
||||
return Cell(value, "date", bold=bold, indent=indent)
|
||||
text = value if isinstance(value, str) else str(value)
|
||||
if not text.strip():
|
||||
return None
|
||||
return Cell(text, "text", bold=bold, indent=indent or leading_spaces(text))
|
||||
|
||||
|
||||
|
||||
@ -14,13 +14,14 @@ from openpyxl.styles import Alignment, Font
|
||||
|
||||
from src.contract import ErrorCode
|
||||
from src.parser.errors import ParserError, UnreadableError, UnsupportedFormatError
|
||||
from src.parser.grid import Cell, MergedRange
|
||||
from src.parser.grid import EMPTY_CELL, Cell, MergedRange
|
||||
from src.parser.readers import read_book
|
||||
from src.parser.readers import xlsb as xlsb_reader
|
||||
|
||||
|
||||
def _synthetic_xlsx() -> bytes:
|
||||
"""Две страницы: шапка с merged-заголовками, outline 0/1/2, bold, отступ, число, дата, bool, пустые строки."""
|
||||
"""Две страницы: шапка с merged-заголовками, outline 0/1/2, bold, отступ, число, дата, bool, пустые строки,
|
||||
ячейки из пробелов и NBSP, merged-диапазон с пробельным origin."""
|
||||
book = openpyxl.Workbook()
|
||||
osv = book.active
|
||||
assert osv is not None
|
||||
@ -44,6 +45,9 @@ def _synthetic_xlsx() -> bytes:
|
||||
osv["B7"] = datetime.datetime(2024, 9, 30)
|
||||
osv.row_dimensions[7].outline_level = 2
|
||||
osv["A9"] = " "
|
||||
osv["B9"] = "\xa0"
|
||||
osv["D3"] = " "
|
||||
osv.merge_cells("D3:E3")
|
||||
osv["A10"] = "Итого"
|
||||
osv["C10"] = True
|
||||
other = book.create_sheet("Прочее")
|
||||
@ -67,14 +71,19 @@ def test_xlsx_reader_builds_sheet_model() -> None:
|
||||
assert osv.cell(7, 1) == Cell(" Контрагент", "text", indent=3)
|
||||
assert osv.cell(7, 2) == Cell(datetime.datetime(2024, 9, 30), "date")
|
||||
assert osv.cell(10, 3) == Cell(True, "bool")
|
||||
assert osv.cell(9, 1).kind == "text"
|
||||
assert osv.cell(9, 1) is EMPTY_CELL
|
||||
assert osv.cell(9, 2) is EMPTY_CELL
|
||||
assert (9, 1) not in osv.cells
|
||||
assert (9, 2) not in osv.cells
|
||||
assert osv.is_row_empty(8)
|
||||
assert osv.is_row_empty(9)
|
||||
assert set(osv.merged) == {MergedRange(3, 1, 4, 1), MergedRange(3, 2, 3, 3)}
|
||||
assert osv.text_at(3, 5) == ""
|
||||
assert osv.merged_origin(3, 5) == (3, 4)
|
||||
assert set(osv.merged) == {MergedRange(3, 1, 4, 1), MergedRange(3, 2, 3, 3), MergedRange(3, 4, 3, 5)}
|
||||
assert osv.text_at(4, 1) == "Счет"
|
||||
assert osv.text_at(3, 3) == "Сальдо на начало периода"
|
||||
assert [osv.outline(row) for row in range(1, 11)] == [0, 0, 0, 0, 0, 1, 2, 0, 0, 0]
|
||||
assert (osv.n_rows, osv.n_cols) == (10, 3)
|
||||
assert (osv.n_rows, osv.n_cols) == (10, 5)
|
||||
assert all(cell.kind != "empty" for cell in osv.cells.values())
|
||||
assert sheets[1].row_cells(1) == [(1, Cell("x", "text"))]
|
||||
|
||||
@ -168,7 +177,8 @@ def test_xlsb_signature_is_read_by_pyxlsb_without_outline(monkeypatch: pytest.Mo
|
||||
(sheet,) = sheets
|
||||
assert sheet.name == "Лист1"
|
||||
assert sheet.cell(1, 1) == Cell("Счет", "text")
|
||||
assert sheet.cell(1, 3) == Cell(" ", "text")
|
||||
assert sheet.cell(1, 3) is EMPTY_CELL
|
||||
assert (1, 3) not in sheet.cells
|
||||
assert sheet.cell(3, 2) == Cell(Decimal("0.1"), "number")
|
||||
assert sheet.cell(3, 3) == Cell(False, "bool")
|
||||
assert sheet.merged == ()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user