Coverage for src\genesis\parsers\formatting_detector.py: 100%
40 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 14:20 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 14:20 +0800
1from __future__ import annotations
3from genesis.data_models import CellComment, CellFormatting
4from genesis.parsers.provenance import build_source_uri
6_BLACK_RGB = ("00000000", "FF000000")
9def _to_rgb_hex(color) -> str | None:
10 """将 openpyxl Color 转为 RGB 十六进制;非 RGB 主题色/默认色返回 None"""
11 if color is None:
12 return None
13 try:
14 value = str(color.rgb)
15 except Exception:
16 return None
17 if not value or value in _BLACK_RGB:
18 return None
19 if len(value) not in (6, 8):
20 return None
21 if not all(ch in "0123456789ABCDEFabcdef" for ch in value):
22 return None
23 return value
26def cell_formatting(cell) -> CellFormatting | None:
27 strike = bool(cell.font.strike)
28 font_color = _to_rgb_hex(getattr(cell.font, "color", None))
29 bg_color = None
30 fill = cell.fill
31 if fill is not None:
32 bg_color = _to_rgb_hex(getattr(fill, "fgColor", None))
33 if strike or font_color or bg_color:
34 return CellFormatting(
35 strikethrough=strike, font_color=font_color, bg_color=bg_color,
36 )
37 return None
40def cell_comment(cell, file_name: str) -> CellComment | None:
41 if cell.comment is None:
42 return None
43 return CellComment(
44 author=cell.comment.author or "",
45 text=cell.comment.text or "",
46 source_uri=build_source_uri(file_name, cell.parent.title, cell.coordinate),
47 )
50def collect_comments(ws, file_name: str) -> list[CellComment]:
51 result = []
52 for row in ws.iter_rows():
53 for cell in row:
54 cm = cell_comment(cell, file_name)
55 if cm is not None:
56 result.append(cm)
57 return result