ps-python-docx 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docx/__init__.py +68 -0
- docx/api.py +37 -0
- docx/blkcntnr.py +101 -0
- docx/comments.py +163 -0
- docx/dml/__init__.py +0 -0
- docx/dml/color.py +112 -0
- docx/document.py +275 -0
- docx/drawing/__init__.py +59 -0
- docx/enum/__init__.py +0 -0
- docx/enum/base.py +150 -0
- docx/enum/dml.py +103 -0
- docx/enum/section.py +86 -0
- docx/enum/shape.py +19 -0
- docx/enum/style.py +452 -0
- docx/enum/table.py +136 -0
- docx/enum/text.py +367 -0
- docx/exceptions.py +18 -0
- docx/image/__init__.py +23 -0
- docx/image/bmp.py +43 -0
- docx/image/constants.py +172 -0
- docx/image/exceptions.py +13 -0
- docx/image/gif.py +38 -0
- docx/image/helpers.py +86 -0
- docx/image/image.py +234 -0
- docx/image/jpeg.py +425 -0
- docx/image/png.py +253 -0
- docx/image/tiff.py +289 -0
- docx/opc/__init__.py +0 -0
- docx/opc/constants.py +306 -0
- docx/opc/coreprops.py +142 -0
- docx/opc/exceptions.py +12 -0
- docx/opc/oxml.py +247 -0
- docx/opc/package.py +219 -0
- docx/opc/packuri.py +109 -0
- docx/opc/part.py +247 -0
- docx/opc/parts/__init__.py +0 -0
- docx/opc/parts/coreprops.py +48 -0
- docx/opc/phys_pkg.py +119 -0
- docx/opc/pkgreader.py +254 -0
- docx/opc/pkgwriter.py +115 -0
- docx/opc/rel.py +153 -0
- docx/opc/shared.py +31 -0
- docx/opc/spec.py +24 -0
- docx/oxml/__init__.py +261 -0
- docx/oxml/comments.py +124 -0
- docx/oxml/coreprops.py +298 -0
- docx/oxml/document.py +88 -0
- docx/oxml/drawing.py +11 -0
- docx/oxml/exceptions.py +10 -0
- docx/oxml/ns.py +109 -0
- docx/oxml/numbering.py +109 -0
- docx/oxml/parser.py +62 -0
- docx/oxml/section.py +537 -0
- docx/oxml/settings.py +138 -0
- docx/oxml/shape.py +299 -0
- docx/oxml/shared.py +52 -0
- docx/oxml/simpletypes.py +434 -0
- docx/oxml/styles.py +341 -0
- docx/oxml/table.py +977 -0
- docx/oxml/text/__init__.py +0 -0
- docx/oxml/text/font.py +333 -0
- docx/oxml/text/hyperlink.py +45 -0
- docx/oxml/text/pagebreak.py +278 -0
- docx/oxml/text/paragraph.py +106 -0
- docx/oxml/text/parfmt.py +392 -0
- docx/oxml/text/run.py +307 -0
- docx/oxml/xmlchemy.py +696 -0
- docx/package.py +110 -0
- docx/parts/__init__.py +0 -0
- docx/parts/comments.py +51 -0
- docx/parts/document.py +182 -0
- docx/parts/hdrftr.py +53 -0
- docx/parts/image.py +80 -0
- docx/parts/numbering.py +32 -0
- docx/parts/settings.py +50 -0
- docx/parts/story.py +95 -0
- docx/parts/styles.py +42 -0
- docx/parts/theme.py +53 -0
- docx/py.typed +0 -0
- docx/section.py +479 -0
- docx/settings.py +35 -0
- docx/shape.py +103 -0
- docx/shared.py +382 -0
- docx/styles/__init__.py +40 -0
- docx/styles/latent.py +198 -0
- docx/styles/style.py +264 -0
- docx/styles/styles.py +147 -0
- docx/table.py +537 -0
- docx/templates/default-comments.xml +12 -0
- docx/templates/default-docx-template/[Content_Types].xml +17 -0
- docx/templates/default-docx-template/_rels/.rels +7 -0
- docx/templates/default-docx-template/customXml/_rels/item1.xml.rels +4 -0
- docx/templates/default-docx-template/customXml/item1.xml +2 -0
- docx/templates/default-docx-template/customXml/itemProps1.xml +6 -0
- docx/templates/default-docx-template/docProps/app.xml +36 -0
- docx/templates/default-docx-template/docProps/core.xml +13 -0
- docx/templates/default-docx-template/docProps/thumbnail.jpeg +0 -0
- docx/templates/default-docx-template/word/_rels/document.xml.rels +11 -0
- docx/templates/default-docx-template/word/document.xml +11 -0
- docx/templates/default-docx-template/word/fontTable.xml +61 -0
- docx/templates/default-docx-template/word/numbering.xml +201 -0
- docx/templates/default-docx-template/word/settings.xml +53 -0
- docx/templates/default-docx-template/word/styles.xml +11844 -0
- docx/templates/default-docx-template/word/stylesWithEffects.xml +11800 -0
- docx/templates/default-docx-template/word/theme/theme1.xml +318 -0
- docx/templates/default-docx-template/word/webSettings.xml +5 -0
- docx/templates/default-footer.xml +27 -0
- docx/templates/default-header.xml +27 -0
- docx/templates/default-settings.xml +26 -0
- docx/templates/default-styles.xml +190 -0
- docx/templates/default.docx +0 -0
- docx/text/__init__.py +0 -0
- docx/text/font.py +472 -0
- docx/text/hyperlink.py +121 -0
- docx/text/pagebreak.py +104 -0
- docx/text/paragraph.py +173 -0
- docx/text/parfmt.py +286 -0
- docx/text/run.py +257 -0
- docx/text/tabstops.py +123 -0
- docx/theme.py +67 -0
- docx/types.py +34 -0
- ps_python_docx-1.3.0.dist-info/METADATA +77 -0
- ps_python_docx-1.3.0.dist-info/RECORD +126 -0
- ps_python_docx-1.3.0.dist-info/WHEEL +5 -0
- ps_python_docx-1.3.0.dist-info/licenses/LICENSE +20 -0
- ps_python_docx-1.3.0.dist-info/top_level.txt +1 -0
docx/text/font.py
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
"""Font-related proxy objects."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
6
|
+
|
|
7
|
+
from docx.dml.color import ColorFormat
|
|
8
|
+
from docx.enum.text import WD_UNDERLINE
|
|
9
|
+
from docx.shared import ElementProxy, Emu
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from docx.enum.text import WD_COLOR_INDEX
|
|
13
|
+
from docx.oxml.text.run import CT_R
|
|
14
|
+
from docx.shared import Length
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Font(ElementProxy):
|
|
18
|
+
"""Proxy object for parent of a `<w:rPr>` element and providing access to
|
|
19
|
+
character properties such as font name, font size, bold, and subscript."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, r: CT_R, parent: Any | None = None):
|
|
22
|
+
super().__init__(r, parent)
|
|
23
|
+
self._element = r
|
|
24
|
+
self._r = r
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def all_caps(self) -> bool | None:
|
|
28
|
+
"""Read/write.
|
|
29
|
+
|
|
30
|
+
Causes text in this font to appear in capital letters.
|
|
31
|
+
"""
|
|
32
|
+
return self._get_bool_prop("caps")
|
|
33
|
+
|
|
34
|
+
@all_caps.setter
|
|
35
|
+
def all_caps(self, value: bool | None) -> None:
|
|
36
|
+
self._set_bool_prop("caps", value)
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def bold(self) -> bool | None:
|
|
40
|
+
"""Read/write.
|
|
41
|
+
|
|
42
|
+
Causes text in this font to appear in bold.
|
|
43
|
+
"""
|
|
44
|
+
return self._get_bool_prop("b")
|
|
45
|
+
|
|
46
|
+
@bold.setter
|
|
47
|
+
def bold(self, value: bool | None) -> None:
|
|
48
|
+
self._set_bool_prop("b", value)
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def color(self):
|
|
52
|
+
"""A |ColorFormat| object providing a way to get and set the text color for this
|
|
53
|
+
font."""
|
|
54
|
+
return ColorFormat(self._element)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def complex_script(self) -> bool | None:
|
|
58
|
+
"""Read/write tri-state value.
|
|
59
|
+
|
|
60
|
+
When |True|, causes the characters in the run to be treated as complex script
|
|
61
|
+
regardless of their Unicode values.
|
|
62
|
+
"""
|
|
63
|
+
return self._get_bool_prop("cs")
|
|
64
|
+
|
|
65
|
+
@complex_script.setter
|
|
66
|
+
def complex_script(self, value: bool | None) -> None:
|
|
67
|
+
self._set_bool_prop("cs", value)
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def cs_bold(self) -> bool | None:
|
|
71
|
+
"""Read/write tri-state value.
|
|
72
|
+
|
|
73
|
+
When |True|, causes the complex script characters in the run to be displayed in
|
|
74
|
+
bold typeface.
|
|
75
|
+
"""
|
|
76
|
+
return self._get_bool_prop("bCs")
|
|
77
|
+
|
|
78
|
+
@cs_bold.setter
|
|
79
|
+
def cs_bold(self, value: bool | None) -> None:
|
|
80
|
+
self._set_bool_prop("bCs", value)
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def cs_italic(self) -> bool | None:
|
|
84
|
+
"""Read/write tri-state value.
|
|
85
|
+
|
|
86
|
+
When |True|, causes the complex script characters in the run to be displayed in
|
|
87
|
+
italic typeface.
|
|
88
|
+
"""
|
|
89
|
+
return self._get_bool_prop("iCs")
|
|
90
|
+
|
|
91
|
+
@cs_italic.setter
|
|
92
|
+
def cs_italic(self, value: bool | None) -> None:
|
|
93
|
+
self._set_bool_prop("iCs", value)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def double_strike(self) -> bool | None:
|
|
97
|
+
"""Read/write tri-state value.
|
|
98
|
+
|
|
99
|
+
When |True|, causes the text in the run to appear with double strikethrough.
|
|
100
|
+
"""
|
|
101
|
+
return self._get_bool_prop("dstrike")
|
|
102
|
+
|
|
103
|
+
@double_strike.setter
|
|
104
|
+
def double_strike(self, value: bool | None) -> None:
|
|
105
|
+
self._set_bool_prop("dstrike", value)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def emboss(self) -> bool | None:
|
|
109
|
+
"""Read/write tri-state value.
|
|
110
|
+
|
|
111
|
+
When |True|, causes the text in the run to appear as if raised off the page in
|
|
112
|
+
relief.
|
|
113
|
+
"""
|
|
114
|
+
return self._get_bool_prop("emboss")
|
|
115
|
+
|
|
116
|
+
@emboss.setter
|
|
117
|
+
def emboss(self, value: bool | None) -> None:
|
|
118
|
+
self._set_bool_prop("emboss", value)
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def hidden(self) -> bool | None:
|
|
122
|
+
"""Read/write tri-state value.
|
|
123
|
+
|
|
124
|
+
When |True|, causes the text in the run to be hidden from display, unless
|
|
125
|
+
applications settings force hidden text to be shown.
|
|
126
|
+
"""
|
|
127
|
+
return self._get_bool_prop("vanish")
|
|
128
|
+
|
|
129
|
+
@hidden.setter
|
|
130
|
+
def hidden(self, value: bool | None) -> None:
|
|
131
|
+
self._set_bool_prop("vanish", value)
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def highlight_color(self) -> WD_COLOR_INDEX | None:
|
|
135
|
+
"""Color of highlighing applied or |None| if not highlighted."""
|
|
136
|
+
rPr = self._element.rPr
|
|
137
|
+
if rPr is None:
|
|
138
|
+
return None
|
|
139
|
+
return rPr.highlight_val
|
|
140
|
+
|
|
141
|
+
@highlight_color.setter
|
|
142
|
+
def highlight_color(self, value: WD_COLOR_INDEX | None):
|
|
143
|
+
rPr = self._element.get_or_add_rPr()
|
|
144
|
+
rPr.highlight_val = value
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def italic(self) -> bool | None:
|
|
148
|
+
"""Read/write tri-state value.
|
|
149
|
+
|
|
150
|
+
When |True|, causes the text of the run to appear in italics. |None| indicates
|
|
151
|
+
the effective value is inherited from the style hierarchy.
|
|
152
|
+
"""
|
|
153
|
+
return self._get_bool_prop("i")
|
|
154
|
+
|
|
155
|
+
@italic.setter
|
|
156
|
+
def italic(self, value: bool | None) -> None:
|
|
157
|
+
self._set_bool_prop("i", value)
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def imprint(self) -> bool | None:
|
|
161
|
+
"""Read/write tri-state value.
|
|
162
|
+
|
|
163
|
+
When |True|, causes the text in the run to appear as if pressed into the page.
|
|
164
|
+
"""
|
|
165
|
+
return self._get_bool_prop("imprint")
|
|
166
|
+
|
|
167
|
+
@imprint.setter
|
|
168
|
+
def imprint(self, value: bool | None) -> None:
|
|
169
|
+
self._set_bool_prop("imprint", value)
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def math(self) -> bool | None:
|
|
173
|
+
"""Read/write tri-state value.
|
|
174
|
+
|
|
175
|
+
When |True|, specifies this run contains WML that should be handled as though it
|
|
176
|
+
was Office Open XML Math.
|
|
177
|
+
"""
|
|
178
|
+
return self._get_bool_prop("oMath")
|
|
179
|
+
|
|
180
|
+
@math.setter
|
|
181
|
+
def math(self, value: bool | None) -> None:
|
|
182
|
+
self._set_bool_prop("oMath", value)
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def name(self) -> str | None:
|
|
186
|
+
"""The typeface name for this |Font|.
|
|
187
|
+
|
|
188
|
+
Causes the text it controls to appear in the named font, if a matching font is
|
|
189
|
+
found. |None| indicates the typeface is inherited from the style hierarchy.
|
|
190
|
+
"""
|
|
191
|
+
rPr = self._element.rPr
|
|
192
|
+
if rPr is None:
|
|
193
|
+
return None
|
|
194
|
+
return rPr.rFonts_ascii
|
|
195
|
+
|
|
196
|
+
@name.setter
|
|
197
|
+
def name(self, value: str | None) -> None:
|
|
198
|
+
rPr = self._element.get_or_add_rPr()
|
|
199
|
+
rPr.rFonts_ascii = value
|
|
200
|
+
rPr.rFonts_hAnsi = value
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def theme_font(self) -> Literal["major", "minor"] | None:
|
|
204
|
+
"""Latin theme family, either ``"major"`` (heading) or ``"minor"`` (body).
|
|
205
|
+
|
|
206
|
+
|None| means no uniform local theme family is set for ASCII and high ANSI.
|
|
207
|
+
This does not resolve inherited or mixed references. Assigning a family
|
|
208
|
+
removes conflicting literal Latin names. Assigning |None| removes only
|
|
209
|
+
those theme references, leaving literal names and other scripts unchanged.
|
|
210
|
+
|
|
211
|
+
To use a literal typeface, clear this property before setting ``name``.
|
|
212
|
+
The existing behavior of ``name`` is unchanged.
|
|
213
|
+
"""
|
|
214
|
+
rPr = self._element.rPr
|
|
215
|
+
if rPr is None or rPr.rFonts is None:
|
|
216
|
+
return None
|
|
217
|
+
fonts = rPr.rFonts
|
|
218
|
+
if fonts.asciiTheme in ("majorAscii", "majorHAnsi") and fonts.hAnsiTheme in (
|
|
219
|
+
"majorAscii",
|
|
220
|
+
"majorHAnsi",
|
|
221
|
+
):
|
|
222
|
+
return "major"
|
|
223
|
+
if fonts.asciiTheme in ("minorAscii", "minorHAnsi") and fonts.hAnsiTheme in (
|
|
224
|
+
"minorAscii",
|
|
225
|
+
"minorHAnsi",
|
|
226
|
+
):
|
|
227
|
+
return "minor"
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
@theme_font.setter
|
|
231
|
+
def theme_font(self, value: Literal["major", "minor"] | None) -> None:
|
|
232
|
+
if value not in (None, "major", "minor"):
|
|
233
|
+
raise ValueError("theme_font must be 'major', 'minor', or None")
|
|
234
|
+
if value is None:
|
|
235
|
+
rPr = self._element.rPr
|
|
236
|
+
if rPr is not None and rPr.rFonts is not None:
|
|
237
|
+
rPr.rFonts.asciiTheme = None
|
|
238
|
+
rPr.rFonts.hAnsiTheme = None
|
|
239
|
+
return
|
|
240
|
+
fonts = self._element.get_or_add_rPr().get_or_add_rFonts()
|
|
241
|
+
fonts.ascii = None
|
|
242
|
+
fonts.hAnsi = None
|
|
243
|
+
fonts.asciiTheme = f"{value}HAnsi"
|
|
244
|
+
fonts.hAnsiTheme = f"{value}HAnsi"
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def no_proof(self) -> bool | None:
|
|
248
|
+
"""Read/write tri-state value.
|
|
249
|
+
|
|
250
|
+
When |True|, specifies that the contents of this run should not report any
|
|
251
|
+
errors when the document is scanned for spelling and grammar.
|
|
252
|
+
"""
|
|
253
|
+
return self._get_bool_prop("noProof")
|
|
254
|
+
|
|
255
|
+
@no_proof.setter
|
|
256
|
+
def no_proof(self, value: bool | None) -> None:
|
|
257
|
+
self._set_bool_prop("noProof", value)
|
|
258
|
+
|
|
259
|
+
@property
|
|
260
|
+
def outline(self) -> bool | None:
|
|
261
|
+
"""Read/write tri-state value.
|
|
262
|
+
|
|
263
|
+
When |True| causes the characters in the run to appear as if they have an
|
|
264
|
+
outline, by drawing a one pixel wide border around the inside and outside
|
|
265
|
+
borders of each character glyph.
|
|
266
|
+
"""
|
|
267
|
+
return self._get_bool_prop("outline")
|
|
268
|
+
|
|
269
|
+
@outline.setter
|
|
270
|
+
def outline(self, value: bool | None) -> None:
|
|
271
|
+
self._set_bool_prop("outline", value)
|
|
272
|
+
|
|
273
|
+
@property
|
|
274
|
+
def rtl(self) -> bool | None:
|
|
275
|
+
"""Read/write tri-state value.
|
|
276
|
+
|
|
277
|
+
When |True| causes the text in the run to have right-to-left characteristics.
|
|
278
|
+
"""
|
|
279
|
+
return self._get_bool_prop("rtl")
|
|
280
|
+
|
|
281
|
+
@rtl.setter
|
|
282
|
+
def rtl(self, value: bool | None) -> None:
|
|
283
|
+
self._set_bool_prop("rtl", value)
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def shadow(self) -> bool | None:
|
|
287
|
+
"""Read/write tri-state value.
|
|
288
|
+
|
|
289
|
+
When |True| causes the text in the run to appear as if each character has a
|
|
290
|
+
shadow.
|
|
291
|
+
"""
|
|
292
|
+
return self._get_bool_prop("shadow")
|
|
293
|
+
|
|
294
|
+
@shadow.setter
|
|
295
|
+
def shadow(self, value: bool | None) -> None:
|
|
296
|
+
self._set_bool_prop("shadow", value)
|
|
297
|
+
|
|
298
|
+
@property
|
|
299
|
+
def size(self) -> Length | None:
|
|
300
|
+
"""Font height in English Metric Units (EMU).
|
|
301
|
+
|
|
302
|
+
|None| indicates the font size should be inherited from the style hierarchy.
|
|
303
|
+
|Length| is a subclass of |int| having properties for convenient conversion into
|
|
304
|
+
points or other length units. The :class:`docx.shared.Pt` class allows
|
|
305
|
+
convenient specification of point values::
|
|
306
|
+
|
|
307
|
+
>>> font.size = Pt(24)
|
|
308
|
+
>>> font.size
|
|
309
|
+
304800
|
|
310
|
+
>>> font.size.pt
|
|
311
|
+
24.0
|
|
312
|
+
|
|
313
|
+
"""
|
|
314
|
+
rPr = self._element.rPr
|
|
315
|
+
if rPr is None:
|
|
316
|
+
return None
|
|
317
|
+
return rPr.sz_val
|
|
318
|
+
|
|
319
|
+
@size.setter
|
|
320
|
+
def size(self, emu: int | Length | None) -> None:
|
|
321
|
+
rPr = self._element.get_or_add_rPr()
|
|
322
|
+
rPr.sz_val = None if emu is None else Emu(emu)
|
|
323
|
+
|
|
324
|
+
@property
|
|
325
|
+
def small_caps(self) -> bool | None:
|
|
326
|
+
"""Read/write tri-state value.
|
|
327
|
+
|
|
328
|
+
When |True| causes the lowercase characters in the run to appear as capital
|
|
329
|
+
letters two points smaller than the font size specified for the run.
|
|
330
|
+
"""
|
|
331
|
+
return self._get_bool_prop("smallCaps")
|
|
332
|
+
|
|
333
|
+
@small_caps.setter
|
|
334
|
+
def small_caps(self, value: bool | None) -> None:
|
|
335
|
+
self._set_bool_prop("smallCaps", value)
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def snap_to_grid(self) -> bool | None:
|
|
339
|
+
"""Read/write tri-state value.
|
|
340
|
+
|
|
341
|
+
When |True| causes the run to use the document grid characters per line settings
|
|
342
|
+
defined in the docGrid element when laying out the characters in this run.
|
|
343
|
+
"""
|
|
344
|
+
return self._get_bool_prop("snapToGrid")
|
|
345
|
+
|
|
346
|
+
@snap_to_grid.setter
|
|
347
|
+
def snap_to_grid(self, value: bool | None) -> None:
|
|
348
|
+
self._set_bool_prop("snapToGrid", value)
|
|
349
|
+
|
|
350
|
+
@property
|
|
351
|
+
def spec_vanish(self) -> bool | None:
|
|
352
|
+
"""Read/write tri-state value.
|
|
353
|
+
|
|
354
|
+
When |True|, specifies that the given run shall always behave as if it is
|
|
355
|
+
hidden, even when hidden text is being displayed in the current document. The
|
|
356
|
+
property has a very narrow, specialized use related to the table of contents.
|
|
357
|
+
Consult the spec (§17.3.2.36) for more details.
|
|
358
|
+
"""
|
|
359
|
+
return self._get_bool_prop("specVanish")
|
|
360
|
+
|
|
361
|
+
@spec_vanish.setter
|
|
362
|
+
def spec_vanish(self, value: bool | None) -> None:
|
|
363
|
+
self._set_bool_prop("specVanish", value)
|
|
364
|
+
|
|
365
|
+
@property
|
|
366
|
+
def strike(self) -> bool | None:
|
|
367
|
+
"""Read/write tri-state value.
|
|
368
|
+
|
|
369
|
+
When |True| causes the text in the run to appear with a single horizontal line
|
|
370
|
+
through the center of the line.
|
|
371
|
+
"""
|
|
372
|
+
return self._get_bool_prop("strike")
|
|
373
|
+
|
|
374
|
+
@strike.setter
|
|
375
|
+
def strike(self, value: bool | None) -> None:
|
|
376
|
+
self._set_bool_prop("strike", value)
|
|
377
|
+
|
|
378
|
+
@property
|
|
379
|
+
def subscript(self) -> bool | None:
|
|
380
|
+
"""Boolean indicating whether the characters in this |Font| appear as subscript.
|
|
381
|
+
|
|
382
|
+
|None| indicates the subscript/subscript value is inherited from the style
|
|
383
|
+
hierarchy.
|
|
384
|
+
"""
|
|
385
|
+
rPr = self._element.rPr
|
|
386
|
+
if rPr is None:
|
|
387
|
+
return None
|
|
388
|
+
return rPr.subscript
|
|
389
|
+
|
|
390
|
+
@subscript.setter
|
|
391
|
+
def subscript(self, value: bool | None) -> None:
|
|
392
|
+
rPr = self._element.get_or_add_rPr()
|
|
393
|
+
rPr.subscript = value
|
|
394
|
+
|
|
395
|
+
@property
|
|
396
|
+
def superscript(self) -> bool | None:
|
|
397
|
+
"""Boolean indicating whether the characters in this |Font| appear as
|
|
398
|
+
superscript.
|
|
399
|
+
|
|
400
|
+
|None| indicates the subscript/superscript value is inherited from the style
|
|
401
|
+
hierarchy.
|
|
402
|
+
"""
|
|
403
|
+
rPr = self._element.rPr
|
|
404
|
+
if rPr is None:
|
|
405
|
+
return None
|
|
406
|
+
return rPr.superscript
|
|
407
|
+
|
|
408
|
+
@superscript.setter
|
|
409
|
+
def superscript(self, value: bool | None) -> None:
|
|
410
|
+
rPr = self._element.get_or_add_rPr()
|
|
411
|
+
rPr.superscript = value
|
|
412
|
+
|
|
413
|
+
@property
|
|
414
|
+
def underline(self) -> bool | WD_UNDERLINE | None:
|
|
415
|
+
"""The underline style for this |Font|.
|
|
416
|
+
|
|
417
|
+
The value is one of |None|, |True|, |False|, or a member of :ref:`WdUnderline`.
|
|
418
|
+
|
|
419
|
+
|None| indicates the font inherits its underline value from the style hierarchy.
|
|
420
|
+
|False| indicates no underline. |True| indicates single underline. The values
|
|
421
|
+
from :ref:`WdUnderline` are used to specify other outline styles such as double,
|
|
422
|
+
wavy, and dotted.
|
|
423
|
+
"""
|
|
424
|
+
rPr = self._element.rPr
|
|
425
|
+
if rPr is None:
|
|
426
|
+
return None
|
|
427
|
+
val = rPr.u_val
|
|
428
|
+
return (
|
|
429
|
+
None
|
|
430
|
+
if val == WD_UNDERLINE.INHERITED
|
|
431
|
+
else True
|
|
432
|
+
if val == WD_UNDERLINE.SINGLE
|
|
433
|
+
else False
|
|
434
|
+
if val == WD_UNDERLINE.NONE
|
|
435
|
+
else val
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
@underline.setter
|
|
439
|
+
def underline(self, value: bool | WD_UNDERLINE | None) -> None:
|
|
440
|
+
rPr = self._element.get_or_add_rPr()
|
|
441
|
+
# -- works fine without these two mappings, but only because True == 1 and
|
|
442
|
+
# -- False == 0, which happen to match the mapping for WD_UNDERLINE.SINGLE
|
|
443
|
+
# -- and .NONE respectively.
|
|
444
|
+
val = (
|
|
445
|
+
WD_UNDERLINE.SINGLE if value is True else WD_UNDERLINE.NONE if value is False else value
|
|
446
|
+
)
|
|
447
|
+
rPr.u_val = val
|
|
448
|
+
|
|
449
|
+
@property
|
|
450
|
+
def web_hidden(self) -> bool | None:
|
|
451
|
+
"""Read/write tri-state value.
|
|
452
|
+
|
|
453
|
+
When |True|, specifies that the contents of this run shall be hidden when the
|
|
454
|
+
document is displayed in web page view.
|
|
455
|
+
"""
|
|
456
|
+
return self._get_bool_prop("webHidden")
|
|
457
|
+
|
|
458
|
+
@web_hidden.setter
|
|
459
|
+
def web_hidden(self, value: bool | None) -> None:
|
|
460
|
+
self._set_bool_prop("webHidden", value)
|
|
461
|
+
|
|
462
|
+
def _get_bool_prop(self, name: str) -> bool | None:
|
|
463
|
+
"""Return the value of boolean child of `w:rPr` having `name`."""
|
|
464
|
+
rPr = self._element.rPr
|
|
465
|
+
if rPr is None:
|
|
466
|
+
return None
|
|
467
|
+
return rPr._get_bool_val(name) # pyright: ignore[reportPrivateUsage]
|
|
468
|
+
|
|
469
|
+
def _set_bool_prop(self, name: str, value: bool | None):
|
|
470
|
+
"""Assign `value` to the boolean child `name` of `w:rPr`."""
|
|
471
|
+
rPr = self._element.get_or_add_rPr()
|
|
472
|
+
rPr._set_bool_val(name, value) # pyright: ignore[reportPrivateUsage]
|
docx/text/hyperlink.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Hyperlink-related proxy objects for python-docx, Hyperlink in particular.
|
|
2
|
+
|
|
3
|
+
A hyperlink occurs in a paragraph, at the same level as a Run, and a hyperlink itself
|
|
4
|
+
contains runs, which is where the visible text of the hyperlink is stored. So it's kind
|
|
5
|
+
of in-between, less than a paragraph and more than a run. So it gets its own module.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from docx.shared import Parented
|
|
13
|
+
from docx.text.run import Run
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
import docx.types as t
|
|
17
|
+
from docx.oxml.text.hyperlink import CT_Hyperlink
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Hyperlink(Parented):
|
|
21
|
+
"""Proxy object wrapping a `<w:hyperlink>` element.
|
|
22
|
+
|
|
23
|
+
A hyperlink occurs as a child of a paragraph, at the same level as a Run. A
|
|
24
|
+
hyperlink itself contains runs, which is where the visible text of the hyperlink is
|
|
25
|
+
stored.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, hyperlink: CT_Hyperlink, parent: t.ProvidesStoryPart):
|
|
29
|
+
super().__init__(parent)
|
|
30
|
+
self._parent = parent
|
|
31
|
+
self._hyperlink = self._element = hyperlink
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def address(self) -> str:
|
|
35
|
+
"""The "URL" of the hyperlink (but not necessarily a web link).
|
|
36
|
+
|
|
37
|
+
While commonly a web link like "https://google.com" the hyperlink address can
|
|
38
|
+
take a variety of forms including "internal links" to bookmarked locations
|
|
39
|
+
within the document. When this hyperlink is an internal "jump" to for example a
|
|
40
|
+
heading from the table-of-contents (TOC), the address is blank. The bookmark
|
|
41
|
+
reference (like "_Toc147925734") is stored in the `.fragment` property.
|
|
42
|
+
"""
|
|
43
|
+
rId = self._hyperlink.rId
|
|
44
|
+
return self._parent.part.rels[rId].target_ref if rId else ""
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def contains_page_break(self) -> bool:
|
|
48
|
+
"""True when the text of this hyperlink is broken across page boundaries.
|
|
49
|
+
|
|
50
|
+
This is not uncommon and can happen for example when the hyperlink text is
|
|
51
|
+
multiple words and occurs in the last line of a page. Theoretically, a hyperlink
|
|
52
|
+
can contain more than one page break but that would be extremely uncommon in
|
|
53
|
+
practice. Still, this value should be understood to mean that "one-or-more"
|
|
54
|
+
rendered page breaks are present.
|
|
55
|
+
"""
|
|
56
|
+
return bool(self._hyperlink.lastRenderedPageBreaks)
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def fragment(self) -> str:
|
|
60
|
+
"""Reference like `#glossary` at end of URL that refers to a sub-resource.
|
|
61
|
+
|
|
62
|
+
Note that this value does not include the fragment-separator character ("#").
|
|
63
|
+
|
|
64
|
+
This value is known as a "named anchor" in an HTML context and "anchor" in the
|
|
65
|
+
MS API, but an "anchor" element (`<a>`) represents a full hyperlink in HTML so
|
|
66
|
+
we avoid confusion by using the more precise RFC 3986 naming "URI fragment".
|
|
67
|
+
|
|
68
|
+
These are also used to refer to bookmarks within the same document, in which
|
|
69
|
+
case the `.address` value with be blank ("") and this property will hold a
|
|
70
|
+
value like "_Toc147925734".
|
|
71
|
+
|
|
72
|
+
To reliably get an entire web URL you will need to concatenate this with the
|
|
73
|
+
`.address` value, separated by "#" when both are present. Consider using the
|
|
74
|
+
`.url` property for that purpose.
|
|
75
|
+
|
|
76
|
+
Word sometimes stores a fragment in this property (an XML attribute) and
|
|
77
|
+
sometimes with the address, depending on how the URL is inserted, so don't
|
|
78
|
+
depend on this field being empty to indicate no fragment is present.
|
|
79
|
+
"""
|
|
80
|
+
return self._hyperlink.anchor or ""
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def runs(self) -> list[Run]:
|
|
84
|
+
"""List of |Run| instances in this hyperlink.
|
|
85
|
+
|
|
86
|
+
Together these define the visible text of the hyperlink. The text of a hyperlink
|
|
87
|
+
is typically contained in a single run will be broken into multiple runs if for
|
|
88
|
+
example part of the hyperlink is bold or the text was changed after the document
|
|
89
|
+
was saved.
|
|
90
|
+
"""
|
|
91
|
+
return [Run(r, self._parent) for r in self._hyperlink.r_lst]
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def text(self) -> str:
|
|
95
|
+
"""String formed by concatenating the text of each run in the hyperlink.
|
|
96
|
+
|
|
97
|
+
Tabs and line breaks in the XML are mapped to ``\\t`` and ``\\n`` characters
|
|
98
|
+
respectively. Note that rendered page-breaks can occur within a hyperlink but
|
|
99
|
+
they are not reflected in this text.
|
|
100
|
+
"""
|
|
101
|
+
return self._hyperlink.text
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def url(self) -> str:
|
|
105
|
+
"""Convenience property to get web URLs from hyperlinks that contain them.
|
|
106
|
+
|
|
107
|
+
This value is the empty string ("") when there is no address portion, so its
|
|
108
|
+
boolean value can also be used to distinguish external URIs from internal "jump"
|
|
109
|
+
hyperlinks like those found in a table-of-contents.
|
|
110
|
+
|
|
111
|
+
Note that this value may also be a link to a file, so if you only want web-urls
|
|
112
|
+
you'll need to check for a protocol prefix like `https://`.
|
|
113
|
+
|
|
114
|
+
When both an address and fragment are present, the return value joins the two
|
|
115
|
+
separated by the fragment-separator hash ("#"). Otherwise this value is the same
|
|
116
|
+
as that of the `.address` property.
|
|
117
|
+
"""
|
|
118
|
+
address, fragment = self.address, self.fragment
|
|
119
|
+
if not address:
|
|
120
|
+
return ""
|
|
121
|
+
return f"{address}#{fragment}" if fragment else address
|
docx/text/pagebreak.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Proxy objects related to rendered page-breaks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from docx.oxml.text.pagebreak import CT_LastRenderedPageBreak
|
|
8
|
+
from docx.shared import Parented
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
import docx.types as t
|
|
12
|
+
from docx.text.paragraph import Paragraph
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RenderedPageBreak(Parented):
|
|
16
|
+
"""A page-break inserted by Word during page-layout for print or display purposes.
|
|
17
|
+
|
|
18
|
+
This usually does not correspond to a "hard" page-break inserted by the document
|
|
19
|
+
author, rather just that Word ran out of room on one page and needed to start
|
|
20
|
+
another. The position of these can change depending on the printer and page-size, as
|
|
21
|
+
well as margins, etc. They also will change in response to edits, but not until Word
|
|
22
|
+
loads and saves the document.
|
|
23
|
+
|
|
24
|
+
Note these are never inserted by `python-docx` because it has no rendering function.
|
|
25
|
+
These are generally only useful for text-extraction of existing documents when
|
|
26
|
+
`python-docx` is being used solely as a document "reader".
|
|
27
|
+
|
|
28
|
+
NOTE: a rendered page-break can occur within a hyperlink; consider a multi-word
|
|
29
|
+
hyperlink like "excellent Wikipedia article on LLMs" that happens to fall close to
|
|
30
|
+
the end of the last line on a page such that the page breaks between "Wikipedia" and
|
|
31
|
+
"article". In such a "page-breaks-in-hyperlink" case, THESE METHODS WILL "MOVE" THE
|
|
32
|
+
PAGE-BREAK to occur after the hyperlink, such that the entire hyperlink appears in
|
|
33
|
+
the paragraph returned by `.preceding_paragraph_fragment`. While this places the
|
|
34
|
+
"tail" text of the hyperlink on the "wrong" page, it avoids having two hyperlinks
|
|
35
|
+
each with a fragment of the actual text and pointing to the same address.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
lastRenderedPageBreak: CT_LastRenderedPageBreak,
|
|
41
|
+
parent: t.ProvidesStoryPart,
|
|
42
|
+
):
|
|
43
|
+
super().__init__(parent)
|
|
44
|
+
self._element = lastRenderedPageBreak
|
|
45
|
+
self._lastRenderedPageBreak = lastRenderedPageBreak
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def preceding_paragraph_fragment(self) -> Paragraph | None:
|
|
49
|
+
"""A "loose" paragraph containing the content preceding this page-break.
|
|
50
|
+
|
|
51
|
+
Compare `.following_paragraph_fragment` as these two are intended to be used
|
|
52
|
+
together.
|
|
53
|
+
|
|
54
|
+
This value is `None` when no content precedes this page-break. This case is
|
|
55
|
+
common and occurs whenever a page breaks on an even paragraph boundary.
|
|
56
|
+
Returning `None` for this case avoids "inserting" a non-existent paragraph into
|
|
57
|
+
the content stream. Note that content can include DrawingML items like images or
|
|
58
|
+
charts.
|
|
59
|
+
|
|
60
|
+
Note the returned paragraph *is divorced from the document body*. Any changes
|
|
61
|
+
made to it will not be reflected in the document. It is intended to provide a
|
|
62
|
+
familiar container (`Paragraph`) to interrogate for the content preceding this
|
|
63
|
+
page-break in the paragraph in which it occured.
|
|
64
|
+
|
|
65
|
+
Contains the entire hyperlink when this break occurs within a hyperlink.
|
|
66
|
+
"""
|
|
67
|
+
if self._lastRenderedPageBreak.precedes_all_content:
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
from docx.text.paragraph import Paragraph
|
|
71
|
+
|
|
72
|
+
return Paragraph(self._lastRenderedPageBreak.preceding_fragment_p, self._parent)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def following_paragraph_fragment(self) -> Paragraph | None:
|
|
76
|
+
"""A "loose" paragraph containing the content following this page-break.
|
|
77
|
+
|
|
78
|
+
HAS POTENTIALLY SURPRISING BEHAVIORS so read carefully to be sure this is what
|
|
79
|
+
you want. This is primarily targeted toward text-extraction use-cases for which
|
|
80
|
+
precisely associating text with the page it occurs on is important.
|
|
81
|
+
|
|
82
|
+
Compare `.preceding_paragraph_fragment` as these two are intended to be used
|
|
83
|
+
together.
|
|
84
|
+
|
|
85
|
+
This value is `None` when no content follows this page-break. This case is
|
|
86
|
+
unlikely to occur in practice because Word places even-paragraph-boundary
|
|
87
|
+
page-breaks on the paragraph *following* the page-break. Still, it is possible
|
|
88
|
+
and must be checked for. Returning `None` for this case avoids "inserting" an
|
|
89
|
+
extra, non-existent paragraph into the content stream. Note that content can
|
|
90
|
+
include DrawingML items like images or charts, not just text.
|
|
91
|
+
|
|
92
|
+
The returned paragraph *is divorced from the document body*. Any changes made to
|
|
93
|
+
it will not be reflected in the document. It is intended to provide a container
|
|
94
|
+
(`Paragraph`) with familiar properties and methods that can be used to
|
|
95
|
+
characterize the paragraph content following a mid-paragraph page-break.
|
|
96
|
+
|
|
97
|
+
Contains no portion of the hyperlink when this break occurs within a hyperlink.
|
|
98
|
+
"""
|
|
99
|
+
if self._lastRenderedPageBreak.follows_all_content:
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
from docx.text.paragraph import Paragraph
|
|
103
|
+
|
|
104
|
+
return Paragraph(self._lastRenderedPageBreak.following_fragment_p, self._parent)
|