Skip to content

[bug] Strikethrough-only cells are treated as unstyled #16

Description

@rp-tx

What happened?

Hi, thanks for maintaining excel-parser.

I noticed that cells whose only non-default font attribute is strikethrough=True are treated as unstyled.

Minimal reproduction

from pathlib import Path
from tempfile import TemporaryDirectory

import openpyxl
from openpyxl.styles import Font
from ks_xlsx_parser.pipeline import parse_workbook
# or: from excel_parser.pipeline import parse_workbook

with TemporaryDirectory() as td:
    path = Path(td) / "strike_test.xlsx"

    wb = openpyxl.Workbook()
    ws = wb.active
    ws["A1"] = "Normal"
    ws["B1"] = "Strike"
    ws["B1"].font = Font(strike=True)
    ws["C1"] = "BoldStrike"
    ws["C1"].font = Font(bold=True, strike=True, color="FF0000")
    wb.save(path)

    result = parse_workbook(path=path)
    sheet = result.workbook.sheets[0]

    for col in range(1, 4):
        cell = sheet.get_cell(1, col)
        font = cell.style.font if cell and cell.style and cell.style.font else None
        print(
            cell.coord.to_a1(),
            cell.display_value,
            "has_style=",
            bool(cell.style),
            "font=",
            font.model_dump(exclude_none=True) if font else None,
        )

Actual result

A1 Normal      has_style=True  strikethrough=False
B1 Strike      has_style=False font=None
C1 BoldStrike  has_style=True  strikethrough=True

B1 only has strikethrough formatting, but cell.style becomes None.

Expected result

B1 should keep its style and expose:

{
  "strikethrough": true
}

Suspected cause

_extract_font() already parses this correctly:

strikethrough=bool(f.strikethrough)

But _extract_style() does not include font.strikethrough in the has_style check:

font and (font.bold or font.italic or font.name or font.size or font.color)

A possible fix:

font and (
    font.bold
    or font.italic
    or font.underline
    or font.strikethrough
    or font.name
    or font.size
    or font.color
)

Secondary related issue

Even when strikethrough is parsed internally, it is not exposed in result.to_json()["chunks"][...]["cells"].

Currently chunk cells include:

{
  "address": "...",
  "value": "...",
  "formula": "...",
  "font_color": "...",
  "fill_color": "..."
}

It would be helpful to also expose something like:

{
  "font_strikethrough": true
}

This matters because many Excel files use strikethrough to mark deprecated or invalid rows. Without preserving it, downstream LLM/RAG pipelines may treat deprecated content as active.

Thanks again for the project.

Minimal reproduction

from pathlib import Path
from tempfile import TemporaryDirectory
import json

import openpyxl
from openpyxl.styles import Font
from ks_xlsx_parser.pipeline import parse_workbook
# or, in the current repo namespace:
# from excel_parser.pipeline import parse_workbook

with TemporaryDirectory() as td:
    path = Path(td) / "strike_test.xlsx"

    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "Sheet1"

    ws["A1"] = "Normal"

    ws["B1"] = "Strike"
    ws["B1"].font = Font(strike=True)

    ws["C1"] = "BoldStrike"
    ws["C1"].font = Font(bold=True, strike=True, color="FF0000")

    wb.save(path)

    result = parse_workbook(path=path)
    sheet = result.workbook.sheets[0]

    for col in range(1, 4):
        cell = sheet.get_cell(1, col)
        font = cell.style.font if cell and cell.style and cell.style.font else None
        print(
            "internal",
            cell.coord.to_a1(),
            cell.display_value,
            "has_style=",
            bool(cell.style),
            "font=",
            font.model_dump(exclude_none=True) if font else None,
        )

    data = result.to_json()
    for chunk in data.get("chunks", []):
        for cell in chunk.get("cells", []):
            if cell["address"] in {"A1", "B1", "C1"}:
                print("json_cell", json.dumps(cell, ensure_ascii=False))

Expected behavior

{
"strikethrough": true
}

ks-xlsx-parser version

0.2.1

Python version

3.13

Operating system

Windows

Traceback (if any)

Benchmark check

  • I ran make bench-robust and my file failed (attach the row from results.csv if you can).
  • The file is from outside SpreadsheetBench; I can attach a minimal reproducer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions