Summary
Reading Font.highlight_color on a run whose <w:highlight> element has w:val="none" raises:
ValueError: WD_COLOR_INDEX has no XML mapping for 'none'
none is a valid ST_HighlightColor value — Word writes <w:highlight w:val="none"/> when a highlight is explicitly cleared from a run. Because the exception is raised during parsing (any access to font.highlight_color), it aborts processing of the entire document, not just the affected run.
Environment
- python-docx 1.2.0
- Python 3.12
Reproduction
from docx import Document
from docx.oxml.ns import qn
doc = Document()
r = doc.add_paragraph().add_run("hi")._r
hl = r.get_or_add_rPr().makeelement(qn("w:highlight"), {qn("w:val"): "none"})
r.get_or_add_rPr().append(hl)
doc.paragraphs[0].runs[0].font.highlight_color
# ValueError: WD_COLOR_INDEX has no XML mapping for 'none'
Traceback bottoms out in BaseXmlEnum.from_xml() (docx/enum/base.py), via CT_Highlight.val → highlight_val.
Root cause
WD_COLOR_INDEX (docx/enum/text.py) maps every ST_HighlightColor value except none. CT_RPr.highlight_val does return highlight.val, and the RequiredAttribute("w:val", WD_COLOR_INDEX) descriptor calls WD_COLOR_INDEX.from_xml("none"), which has no member and raises.
Proposed fix
none semantically means "not highlighted" — exactly what python-docx already represents as None (the value returned when no w:highlight element is present, and the value the highlight_val setter writes by removing the element). So map the explicit none value to None in the getter:
@property
def highlight_val(self) -> WD_COLOR_INDEX | None:
highlight = self.highlight
if highlight is None:
return None
if highlight.get(qn("w:val")) == "none":
return None
return highlight.val
none is the only ST_HighlightColor value absent from WD_COLOR_INDEX, so this closes the gap completely without an enum-value collision (a none enum member would have no distinct MS-API integer — AUTO already occupies 0).
I have a branch with this fix plus a unit test and will open a PR referencing this issue.
Summary
Reading
Font.highlight_coloron a run whose<w:highlight>element hasw:val="none"raises:noneis a validST_HighlightColorvalue — Word writes<w:highlight w:val="none"/>when a highlight is explicitly cleared from a run. Because the exception is raised during parsing (any access tofont.highlight_color), it aborts processing of the entire document, not just the affected run.Environment
Reproduction
Traceback bottoms out in
BaseXmlEnum.from_xml()(docx/enum/base.py), viaCT_Highlight.val→highlight_val.Root cause
WD_COLOR_INDEX(docx/enum/text.py) maps everyST_HighlightColorvalue exceptnone.CT_RPr.highlight_valdoesreturn highlight.val, and theRequiredAttribute("w:val", WD_COLOR_INDEX)descriptor callsWD_COLOR_INDEX.from_xml("none"), which has no member and raises.Proposed fix
nonesemantically means "not highlighted" — exactly what python-docx already represents asNone(the value returned when now:highlightelement is present, and the value thehighlight_valsetter writes by removing the element). So map the explicitnonevalue toNonein the getter:noneis the onlyST_HighlightColorvalue absent fromWD_COLOR_INDEX, so this closes the gap completely without an enum-value collision (anoneenum member would have no distinct MS-API integer —AUTOalready occupies0).I have a branch with this fix plus a unit test and will open a PR referencing this issue.