Summary
Cells whose only non-default font attribute is strike=True lose their style entirely: cell.style comes back as None. The same happens for underline-only cells.
Reproduction
from pathlib import Path
from tempfile import TemporaryDirectory
import openpyxl
from openpyxl.styles import Font
from ks_xlsx_parser 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)
sheet = parse_workbook(path=path).workbook.sheets[0]
for col in range(1, 4):
cell = sheet.get_cell(1, col)
font = cell.style.font if cell.style and cell.style.font else None
print(cell.coord.to_a1(), "has_style=", bool(cell.style), "font=",
font.model_dump(exclude_none=True) if font else None)
Actual
A1 has_style= True font= {'name': 'Calibri', 'size': 11.0, ..., 'strikethrough': False, 'color': 'theme:1'}
B1 has_style= False font= None
C1 has_style= True font= {'bold': True, 'strikethrough': True, 'color': 'FF0000'}
Expected: B1 keeps its style and reports strikethrough: true.
C1 works only incidentally — bold/color are what keep the style alive there, not the strike.
Cause
_extract_font() in src/parsers/cell_parser.py parses strikethrough correctly, but _extract_style() decides whether a cell is styled from a hand-written attribute list that omits both strikethrough and underline:
has_style = any([
font and (font.bold or font.italic or font.name or font.size or font.color),
fill and fill.fg_color,
border and any([border.left, border.right, border.top, border.bottom]),
alignment and (alignment.horizontal or alignment.vertical or alignment.wrap_text),
number_format,
])
When the whole CellStyle is discarded, the parsed font (strike included) goes with it.
The enumeration also under-reports two other cases: a fill with only bg_color, and an alignment with only text_rotation/indent. Each _extract_* helper already returns None when nothing is set, so the enumeration is redundant as well as lossy — comparing against a default DTO covers all of them:
has_style = any([
font is not None and font != _DEFAULT_FONT,
fill is not None,
border is not None,
alignment is not None,
number_format,
])
Secondary: expose strikethrough in to_json()
Chunk cells in result.to_json()["chunks"][...]["cells"] currently carry address, value, formula, font_color, fill_color. Strikethrough is widely used in real workbooks to mark deprecated or void rows, so downstream RAG/LLM consumers need it at that level too, alongside the colors:
{"address": "B1", "value": "Strike", "formula": null,
"font_color": null, "fill_color": null, "font_strikethrough": true}
Environment
Reported against ks-xlsx-parser 0.2.1, Python 3.13, Windows. Reproduced on main.
Reported by a user via project feedback.
Summary
Cells whose only non-default font attribute is
strike=Truelose their style entirely:cell.stylecomes back asNone. The same happens for underline-only cells.Reproduction
Actual
Expected: B1 keeps its style and reports
strikethrough: true.C1 works only incidentally —
bold/colorare what keep the style alive there, not the strike.Cause
_extract_font()insrc/parsers/cell_parser.pyparsesstrikethroughcorrectly, but_extract_style()decides whether a cell is styled from a hand-written attribute list that omits bothstrikethroughandunderline:When the whole
CellStyleis discarded, the parsed font (strike included) goes with it.The enumeration also under-reports two other cases: a fill with only
bg_color, and an alignment with onlytext_rotation/indent. Each_extract_*helper already returnsNonewhen nothing is set, so the enumeration is redundant as well as lossy — comparing against a default DTO covers all of them:Secondary: expose strikethrough in
to_json()Chunk cells in
result.to_json()["chunks"][...]["cells"]currently carryaddress,value,formula,font_color,fill_color. Strikethrough is widely used in real workbooks to mark deprecated or void rows, so downstream RAG/LLM consumers need it at that level too, alongside the colors:{"address": "B1", "value": "Strike", "formula": null, "font_color": null, "fill_color": null, "font_strikethrough": true}Environment
Reported against ks-xlsx-parser 0.2.1, Python 3.13, Windows. Reproduced on
main.Reported by a user via project feedback.