Skip to content

Reading Font.highlight_color raises ValueError for valid w:highlight w:val="none" #1559

Description

@mithunvoe

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.valhighlight_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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions