Spaces:
Paused
Paused
| """Custom element classes related to the styles part.""" | |
| from __future__ import annotations | |
| from docx.enum.style import WD_STYLE_TYPE | |
| from docx.oxml.simpletypes import ST_DecimalNumber, ST_OnOff, ST_String | |
| from docx.oxml.xmlchemy import ( | |
| BaseOxmlElement, | |
| OptionalAttribute, | |
| RequiredAttribute, | |
| ZeroOrMore, | |
| ZeroOrOne, | |
| ) | |
| def styleId_from_name(name): | |
| """Return the style id corresponding to `name`, taking into account special-case | |
| names such as 'Heading 1'.""" | |
| return { | |
| "caption": "Caption", | |
| "heading 1": "Heading1", | |
| "heading 2": "Heading2", | |
| "heading 3": "Heading3", | |
| "heading 4": "Heading4", | |
| "heading 5": "Heading5", | |
| "heading 6": "Heading6", | |
| "heading 7": "Heading7", | |
| "heading 8": "Heading8", | |
| "heading 9": "Heading9", | |
| }.get(name, name.replace(" ", "")) | |
| class CT_LatentStyles(BaseOxmlElement): | |
| """`w:latentStyles` element, defining behavior defaults for latent styles and | |
| containing `w:lsdException` child elements that each override those defaults for a | |
| named latent style.""" | |
| lsdException = ZeroOrMore("w:lsdException", successors=()) | |
| count = OptionalAttribute("w:count", ST_DecimalNumber) | |
| defLockedState = OptionalAttribute("w:defLockedState", ST_OnOff) | |
| defQFormat = OptionalAttribute("w:defQFormat", ST_OnOff) | |
| defSemiHidden = OptionalAttribute("w:defSemiHidden", ST_OnOff) | |
| defUIPriority = OptionalAttribute("w:defUIPriority", ST_DecimalNumber) | |
| defUnhideWhenUsed = OptionalAttribute("w:defUnhideWhenUsed", ST_OnOff) | |
| def bool_prop(self, attr_name): | |
| """Return the boolean value of the attribute having `attr_name`, or |False| if | |
| not present.""" | |
| value = getattr(self, attr_name) | |
| if value is None: | |
| return False | |
| return value | |
| def get_by_name(self, name): | |
| """Return the `w:lsdException` child having `name`, or |None| if not found.""" | |
| found = self.xpath('w:lsdException[@w:name="%s"]' % name) | |
| if not found: | |
| return None | |
| return found[0] | |
| def set_bool_prop(self, attr_name, value): | |
| """Set the on/off attribute having `attr_name` to `value`.""" | |
| setattr(self, attr_name, bool(value)) | |
| class CT_LsdException(BaseOxmlElement): | |
| """``<w:lsdException>`` element, defining override visibility behaviors for a named | |
| latent style.""" | |
| locked = OptionalAttribute("w:locked", ST_OnOff) | |
| name = RequiredAttribute("w:name", ST_String) | |
| qFormat = OptionalAttribute("w:qFormat", ST_OnOff) | |
| semiHidden = OptionalAttribute("w:semiHidden", ST_OnOff) | |
| uiPriority = OptionalAttribute("w:uiPriority", ST_DecimalNumber) | |
| unhideWhenUsed = OptionalAttribute("w:unhideWhenUsed", ST_OnOff) | |
| def delete(self): | |
| """Remove this `w:lsdException` element from the XML document.""" | |
| self.getparent().remove(self) | |
| def on_off_prop(self, attr_name): | |
| """Return the boolean value of the attribute having `attr_name`, or |None| if | |
| not present.""" | |
| return getattr(self, attr_name) | |
| def set_on_off_prop(self, attr_name, value): | |
| """Set the on/off attribute having `attr_name` to `value`.""" | |
| setattr(self, attr_name, value) | |
| class CT_Style(BaseOxmlElement): | |
| """A ``<w:style>`` element, representing a style definition.""" | |
| _tag_seq = ( | |
| "w:name", | |
| "w:aliases", | |
| "w:basedOn", | |
| "w:next", | |
| "w:link", | |
| "w:autoRedefine", | |
| "w:hidden", | |
| "w:uiPriority", | |
| "w:semiHidden", | |
| "w:unhideWhenUsed", | |
| "w:qFormat", | |
| "w:locked", | |
| "w:personal", | |
| "w:personalCompose", | |
| "w:personalReply", | |
| "w:rsid", | |
| "w:pPr", | |
| "w:rPr", | |
| "w:tblPr", | |
| "w:trPr", | |
| "w:tcPr", | |
| "w:tblStylePr", | |
| ) | |
| name = ZeroOrOne("w:name", successors=_tag_seq[1:]) | |
| basedOn = ZeroOrOne("w:basedOn", successors=_tag_seq[3:]) | |
| next = ZeroOrOne("w:next", successors=_tag_seq[4:]) | |
| uiPriority = ZeroOrOne("w:uiPriority", successors=_tag_seq[8:]) | |
| semiHidden = ZeroOrOne("w:semiHidden", successors=_tag_seq[9:]) | |
| unhideWhenUsed = ZeroOrOne("w:unhideWhenUsed", successors=_tag_seq[10:]) | |
| qFormat = ZeroOrOne("w:qFormat", successors=_tag_seq[11:]) | |
| locked = ZeroOrOne("w:locked", successors=_tag_seq[12:]) | |
| pPr = ZeroOrOne("w:pPr", successors=_tag_seq[17:]) | |
| rPr = ZeroOrOne("w:rPr", successors=_tag_seq[18:]) | |
| del _tag_seq | |
| type: WD_STYLE_TYPE | None = OptionalAttribute( # pyright: ignore[reportAssignmentType] | |
| "w:type", WD_STYLE_TYPE | |
| ) | |
| styleId: str | None = OptionalAttribute( # pyright: ignore[reportAssignmentType] | |
| "w:styleId", ST_String | |
| ) | |
| default = OptionalAttribute("w:default", ST_OnOff) | |
| customStyle = OptionalAttribute("w:customStyle", ST_OnOff) | |
| def basedOn_val(self): | |
| """Value of `w:basedOn/@w:val` or |None| if not present.""" | |
| basedOn = self.basedOn | |
| if basedOn is None: | |
| return None | |
| return basedOn.val | |
| def basedOn_val(self, value): | |
| if value is None: | |
| self._remove_basedOn() | |
| else: | |
| self.get_or_add_basedOn().val = value | |
| def base_style(self): | |
| """Sibling CT_Style element this style is based on or |None| if no base style or | |
| base style not found.""" | |
| basedOn = self.basedOn | |
| if basedOn is None: | |
| return None | |
| styles = self.getparent() | |
| base_style = styles.get_by_id(basedOn.val) | |
| if base_style is None: | |
| return None | |
| return base_style | |
| def delete(self): | |
| """Remove this `w:style` element from its parent `w:styles` element.""" | |
| self.getparent().remove(self) | |
| def locked_val(self): | |
| """Value of `w:locked/@w:val` or |False| if not present.""" | |
| locked = self.locked | |
| if locked is None: | |
| return False | |
| return locked.val | |
| def locked_val(self, value): | |
| self._remove_locked() | |
| if bool(value) is True: | |
| locked = self._add_locked() | |
| locked.val = value | |
| def name_val(self): | |
| """Value of ``<w:name>`` child or |None| if not present.""" | |
| name = self.name | |
| if name is None: | |
| return None | |
| return name.val | |
| def name_val(self, value): | |
| self._remove_name() | |
| if value is not None: | |
| name = self._add_name() | |
| name.val = value | |
| def next_style(self): | |
| """Sibling CT_Style element identified by the value of `w:name/@w:val` or |None| | |
| if no value is present or no style with that style id is found.""" | |
| next = self.next | |
| if next is None: | |
| return None | |
| styles = self.getparent() | |
| return styles.get_by_id(next.val) # None if not found | |
| def qFormat_val(self): | |
| """Value of `w:qFormat/@w:val` or |False| if not present.""" | |
| qFormat = self.qFormat | |
| if qFormat is None: | |
| return False | |
| return qFormat.val | |
| def qFormat_val(self, value): | |
| self._remove_qFormat() | |
| if bool(value): | |
| self._add_qFormat() | |
| def semiHidden_val(self): | |
| """Value of ``<w:semiHidden>`` child or |False| if not present.""" | |
| semiHidden = self.semiHidden | |
| if semiHidden is None: | |
| return False | |
| return semiHidden.val | |
| def semiHidden_val(self, value): | |
| self._remove_semiHidden() | |
| if bool(value) is True: | |
| semiHidden = self._add_semiHidden() | |
| semiHidden.val = value | |
| def uiPriority_val(self): | |
| """Value of ``<w:uiPriority>`` child or |None| if not present.""" | |
| uiPriority = self.uiPriority | |
| if uiPriority is None: | |
| return None | |
| return uiPriority.val | |
| def uiPriority_val(self, value): | |
| self._remove_uiPriority() | |
| if value is not None: | |
| uiPriority = self._add_uiPriority() | |
| uiPriority.val = value | |
| def unhideWhenUsed_val(self): | |
| """Value of `w:unhideWhenUsed/@w:val` or |False| if not present.""" | |
| unhideWhenUsed = self.unhideWhenUsed | |
| if unhideWhenUsed is None: | |
| return False | |
| return unhideWhenUsed.val | |
| def unhideWhenUsed_val(self, value): | |
| self._remove_unhideWhenUsed() | |
| if bool(value) is True: | |
| unhideWhenUsed = self._add_unhideWhenUsed() | |
| unhideWhenUsed.val = value | |
| class CT_Styles(BaseOxmlElement): | |
| """``<w:styles>`` element, the root element of a styles part, i.e. styles.xml.""" | |
| _tag_seq = ("w:docDefaults", "w:latentStyles", "w:style") | |
| latentStyles = ZeroOrOne("w:latentStyles", successors=_tag_seq[2:]) | |
| style = ZeroOrMore("w:style", successors=()) | |
| del _tag_seq | |
| def add_style_of_type(self, name, style_type, builtin): | |
| """Return a newly added `w:style` element having `name` and `style_type`. | |
| `w:style/@customStyle` is set based on the value of `builtin`. | |
| """ | |
| style = self.add_style() | |
| style.type = style_type | |
| style.customStyle = None if builtin else True | |
| style.styleId = styleId_from_name(name) | |
| style.name_val = name | |
| return style | |
| def default_for(self, style_type): | |
| """Return `w:style[@w:type="*{style_type}*][-1]` or |None| if not found.""" | |
| default_styles_for_type = [ | |
| s for s in self._iter_styles() if s.type == style_type and s.default | |
| ] | |
| if not default_styles_for_type: | |
| return None | |
| # spec calls for last default in document order | |
| return default_styles_for_type[-1] | |
| def get_by_id(self, styleId: str) -> CT_Style | None: | |
| """`w:style` child where @styleId = `styleId`. | |
| |None| if not found. | |
| """ | |
| xpath = f'w:style[@w:styleId="{styleId}"]' | |
| return next(iter(self.xpath(xpath)), None) | |
| def get_by_name(self, name: str) -> CT_Style | None: | |
| """`w:style` child with `w:name` grandchild having value `name`. | |
| |None| if not found. | |
| """ | |
| xpath = 'w:style[w:name/@w:val="%s"]' % name | |
| return next(iter(self.xpath(xpath)), None) | |
| def _iter_styles(self): | |
| """Generate each of the `w:style` child elements in document order.""" | |
| return (style for style in self.xpath("w:style")) | |