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/run.py
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"""Run-related proxy objects for python-docx, Run in particular."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import IO, TYPE_CHECKING, Iterator, cast
|
|
6
|
+
|
|
7
|
+
from docx.drawing import Drawing
|
|
8
|
+
from docx.enum.style import WD_STYLE_TYPE
|
|
9
|
+
from docx.enum.text import WD_BREAK
|
|
10
|
+
from docx.oxml.drawing import CT_Drawing
|
|
11
|
+
from docx.oxml.text.pagebreak import CT_LastRenderedPageBreak
|
|
12
|
+
from docx.shape import InlineShape
|
|
13
|
+
from docx.shared import StoryChild
|
|
14
|
+
from docx.styles.style import CharacterStyle
|
|
15
|
+
from docx.text.font import Font
|
|
16
|
+
from docx.text.pagebreak import RenderedPageBreak
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
import docx.types as t
|
|
20
|
+
from docx.enum.text import WD_UNDERLINE
|
|
21
|
+
from docx.oxml.text.run import CT_R, CT_Text
|
|
22
|
+
from docx.shared import Length
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Run(StoryChild):
|
|
26
|
+
"""Proxy object wrapping `<w:r>` element.
|
|
27
|
+
|
|
28
|
+
Several of the properties on Run take a tri-state value, |True|, |False|, or |None|.
|
|
29
|
+
|True| and |False| correspond to on and off respectively. |None| indicates the
|
|
30
|
+
property is not specified directly on the run and its effective value is taken from
|
|
31
|
+
the style hierarchy.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, r: CT_R, parent: t.ProvidesStoryPart):
|
|
35
|
+
super().__init__(parent)
|
|
36
|
+
self._r = self._element = self.element = r
|
|
37
|
+
|
|
38
|
+
def add_break(self, break_type: WD_BREAK = WD_BREAK.LINE):
|
|
39
|
+
"""Add a break element of `break_type` to this run.
|
|
40
|
+
|
|
41
|
+
`break_type` can take the values `WD_BREAK.LINE`, `WD_BREAK.PAGE`, and
|
|
42
|
+
`WD_BREAK.COLUMN` where `WD_BREAK` is imported from `docx.enum.text`.
|
|
43
|
+
`break_type` defaults to `WD_BREAK.LINE`.
|
|
44
|
+
"""
|
|
45
|
+
type_, clear = {
|
|
46
|
+
WD_BREAK.LINE: (None, None),
|
|
47
|
+
WD_BREAK.PAGE: ("page", None),
|
|
48
|
+
WD_BREAK.COLUMN: ("column", None),
|
|
49
|
+
WD_BREAK.LINE_CLEAR_LEFT: ("textWrapping", "left"),
|
|
50
|
+
WD_BREAK.LINE_CLEAR_RIGHT: ("textWrapping", "right"),
|
|
51
|
+
WD_BREAK.LINE_CLEAR_ALL: ("textWrapping", "all"),
|
|
52
|
+
}[break_type]
|
|
53
|
+
br = self._r.add_br()
|
|
54
|
+
if type_ is not None:
|
|
55
|
+
br.type = type_
|
|
56
|
+
if clear is not None:
|
|
57
|
+
br.clear = clear
|
|
58
|
+
|
|
59
|
+
def add_picture(
|
|
60
|
+
self,
|
|
61
|
+
image_path_or_stream: str | IO[bytes],
|
|
62
|
+
width: int | Length | None = None,
|
|
63
|
+
height: int | Length | None = None,
|
|
64
|
+
) -> InlineShape:
|
|
65
|
+
"""Return |InlineShape| containing image identified by `image_path_or_stream`.
|
|
66
|
+
|
|
67
|
+
The picture is added to the end of this run.
|
|
68
|
+
|
|
69
|
+
`image_path_or_stream` can be a path (a string) or a file-like object containing
|
|
70
|
+
a binary image.
|
|
71
|
+
|
|
72
|
+
If neither width nor height is specified, the picture appears at
|
|
73
|
+
its native size. If only one is specified, it is used to compute a scaling
|
|
74
|
+
factor that is then applied to the unspecified dimension, preserving the aspect
|
|
75
|
+
ratio of the image. The native size of the picture is calculated using the dots-
|
|
76
|
+
per-inch (dpi) value specified in the image file, defaulting to 72 dpi if no
|
|
77
|
+
value is specified, as is often the case.
|
|
78
|
+
"""
|
|
79
|
+
inline = self.part.new_pic_inline(image_path_or_stream, width, height)
|
|
80
|
+
self._r.add_drawing(inline)
|
|
81
|
+
return InlineShape(inline)
|
|
82
|
+
|
|
83
|
+
def add_tab(self) -> None:
|
|
84
|
+
"""Add a ``<w:tab/>`` element at the end of the run, which Word interprets as a
|
|
85
|
+
tab character."""
|
|
86
|
+
self._r.add_tab()
|
|
87
|
+
|
|
88
|
+
def add_text(self, text: str):
|
|
89
|
+
"""Returns a newly appended |_Text| object (corresponding to a new ``<w:t>``
|
|
90
|
+
child element) to the run, containing `text`.
|
|
91
|
+
|
|
92
|
+
Compare with the possibly more friendly approach of assigning text to the
|
|
93
|
+
:attr:`Run.text` property.
|
|
94
|
+
"""
|
|
95
|
+
t = self._r.add_t(text)
|
|
96
|
+
return _Text(t)
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def bold(self) -> bool | None:
|
|
100
|
+
"""Read/write tri-state value.
|
|
101
|
+
|
|
102
|
+
When |True|, causes the text of the run to appear in bold face. When |False|,
|
|
103
|
+
the text unconditionally appears non-bold. When |None| the bold setting for this
|
|
104
|
+
run is inherited from the style hierarchy.
|
|
105
|
+
"""
|
|
106
|
+
return self.font.bold
|
|
107
|
+
|
|
108
|
+
@bold.setter
|
|
109
|
+
def bold(self, value: bool | None):
|
|
110
|
+
self.font.bold = value
|
|
111
|
+
|
|
112
|
+
def clear(self):
|
|
113
|
+
"""Return reference to this run after removing all its content.
|
|
114
|
+
|
|
115
|
+
All run formatting is preserved.
|
|
116
|
+
"""
|
|
117
|
+
self._r.clear_content()
|
|
118
|
+
return self
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def contains_page_break(self) -> bool:
|
|
122
|
+
"""`True` when one or more rendered page-breaks occur in this run.
|
|
123
|
+
|
|
124
|
+
Note that "hard" page-breaks inserted by the author are not included. A hard
|
|
125
|
+
page-break gives rise to a rendered page-break in the right position so if those
|
|
126
|
+
were included that page-break would be "double-counted".
|
|
127
|
+
|
|
128
|
+
It would be very rare for multiple rendered page-breaks to occur in a single
|
|
129
|
+
run, but it is possible.
|
|
130
|
+
"""
|
|
131
|
+
return bool(self._r.lastRenderedPageBreaks)
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def font(self) -> Font:
|
|
135
|
+
"""The |Font| object providing access to the character formatting properties for
|
|
136
|
+
this run, such as font name and size."""
|
|
137
|
+
return Font(self._element)
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def italic(self) -> bool | None:
|
|
141
|
+
"""Read/write tri-state value.
|
|
142
|
+
|
|
143
|
+
When |True|, causes the text of the run to appear in italics. When |False|, the
|
|
144
|
+
text unconditionally appears non-italic. When |None| the italic setting for this
|
|
145
|
+
run is inherited from the style hierarchy.
|
|
146
|
+
"""
|
|
147
|
+
return self.font.italic
|
|
148
|
+
|
|
149
|
+
@italic.setter
|
|
150
|
+
def italic(self, value: bool | None):
|
|
151
|
+
self.font.italic = value
|
|
152
|
+
|
|
153
|
+
def iter_inner_content(self) -> Iterator[str | Drawing | RenderedPageBreak]:
|
|
154
|
+
"""Generate the content-items in this run in the order they appear.
|
|
155
|
+
|
|
156
|
+
NOTE: only content-types currently supported by `python-docx` are generated. In
|
|
157
|
+
this version, that is text and rendered page-breaks. Drawing is included but
|
|
158
|
+
currently only provides access to its XML element (CT_Drawing) on its
|
|
159
|
+
`._drawing` attribute. `Drawing` attributes and methods may be expanded in
|
|
160
|
+
future releases.
|
|
161
|
+
|
|
162
|
+
There are a number of element-types that can appear inside a run, but most of
|
|
163
|
+
those (w:br, w:cr, w:noBreakHyphen, w:t, w:tab) have a clear plain-text
|
|
164
|
+
equivalent. Any contiguous range of such elements is generated as a single
|
|
165
|
+
`str`. Rendered page-break and drawing elements are generated individually. Any
|
|
166
|
+
other elements are ignored.
|
|
167
|
+
"""
|
|
168
|
+
for item in self._r.inner_content_items:
|
|
169
|
+
if isinstance(item, str):
|
|
170
|
+
yield item
|
|
171
|
+
elif isinstance(item, CT_LastRenderedPageBreak):
|
|
172
|
+
yield RenderedPageBreak(item, self)
|
|
173
|
+
elif isinstance(item, CT_Drawing): # pyright: ignore[reportUnnecessaryIsInstance]
|
|
174
|
+
yield Drawing(item, self)
|
|
175
|
+
|
|
176
|
+
def mark_comment_range(self, last_run: Run, comment_id: int) -> None:
|
|
177
|
+
"""Mark the range of runs from this run to `last_run` (inclusive) as belonging to a comment.
|
|
178
|
+
|
|
179
|
+
`comment_id` identfies the comment that references this range.
|
|
180
|
+
"""
|
|
181
|
+
# -- insert `w:commentRangeStart` with `comment_id` before this (first) run --
|
|
182
|
+
self._r.insert_comment_range_start_above(comment_id)
|
|
183
|
+
|
|
184
|
+
# -- insert `w:commentRangeEnd` and `w:commentReference` run with `comment_id` after
|
|
185
|
+
# -- `last_run`
|
|
186
|
+
last_run._r.insert_comment_range_end_and_reference_below(comment_id)
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def style(self) -> CharacterStyle:
|
|
190
|
+
"""Read/write.
|
|
191
|
+
|
|
192
|
+
A |CharacterStyle| object representing the character style applied to this run.
|
|
193
|
+
The default character style for the document (often `Default Character Font`) is
|
|
194
|
+
returned if the run has no directly-applied character style. Setting this
|
|
195
|
+
property to |None| removes any directly-applied character style.
|
|
196
|
+
"""
|
|
197
|
+
style_id = self._r.style
|
|
198
|
+
return cast(CharacterStyle, self.part.get_style(style_id, WD_STYLE_TYPE.CHARACTER))
|
|
199
|
+
|
|
200
|
+
@style.setter
|
|
201
|
+
def style(self, style_or_name: str | CharacterStyle | None):
|
|
202
|
+
style_id = self.part.get_style_id(style_or_name, WD_STYLE_TYPE.CHARACTER)
|
|
203
|
+
self._r.style = style_id
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def text(self) -> str:
|
|
207
|
+
"""String formed by concatenating the text equivalent of each run.
|
|
208
|
+
|
|
209
|
+
Each `<w:t>` element adds the text characters it contains. A `<w:tab/>` element
|
|
210
|
+
adds a `\\t` character. A `<w:cr/>` or `<w:br>` element each add a `\\n`
|
|
211
|
+
character. Note that a `<w:br>` element can indicate a page break or column
|
|
212
|
+
break as well as a line break. Only line-break `<w:br>` elements translate to
|
|
213
|
+
a `\\n` character. Others are ignored. All other content child elements, such as
|
|
214
|
+
`<w:drawing>`, are ignored.
|
|
215
|
+
|
|
216
|
+
Assigning text to this property has the reverse effect, translating each `\\t`
|
|
217
|
+
character to a `<w:tab/>` element and each `\\n` or `\\r` character to a
|
|
218
|
+
`<w:cr/>` element. Any existing run content is replaced. Run formatting is
|
|
219
|
+
preserved.
|
|
220
|
+
"""
|
|
221
|
+
return self._r.text
|
|
222
|
+
|
|
223
|
+
@text.setter
|
|
224
|
+
def text(self, text: str):
|
|
225
|
+
self._r.text = text
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def underline(self) -> bool | WD_UNDERLINE | None:
|
|
229
|
+
"""The underline style for this |Run|.
|
|
230
|
+
|
|
231
|
+
Value is one of |None|, |True|, |False|, or a member of :ref:`WdUnderline`.
|
|
232
|
+
|
|
233
|
+
A value of |None| indicates the run has no directly-applied underline value and
|
|
234
|
+
so will inherit the underline value of its containing paragraph. Assigning
|
|
235
|
+
|None| to this property removes any directly-applied underline value.
|
|
236
|
+
|
|
237
|
+
A value of |False| indicates a directly-applied setting of no underline,
|
|
238
|
+
overriding any inherited value.
|
|
239
|
+
|
|
240
|
+
A value of |True| indicates single underline.
|
|
241
|
+
|
|
242
|
+
The values from :ref:`WdUnderline` are used to specify other outline styles such
|
|
243
|
+
as double, wavy, and dotted.
|
|
244
|
+
"""
|
|
245
|
+
return self.font.underline
|
|
246
|
+
|
|
247
|
+
@underline.setter
|
|
248
|
+
def underline(self, value: bool | WD_UNDERLINE | None):
|
|
249
|
+
self.font.underline = value
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class _Text:
|
|
253
|
+
"""Proxy object wrapping `<w:t>` element."""
|
|
254
|
+
|
|
255
|
+
def __init__(self, t_elm: CT_Text):
|
|
256
|
+
super(_Text, self).__init__()
|
|
257
|
+
self._t = t_elm
|
docx/text/tabstops.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Tabstop-related proxy types."""
|
|
2
|
+
|
|
3
|
+
from docx.enum.text import WD_TAB_ALIGNMENT, WD_TAB_LEADER
|
|
4
|
+
from docx.shared import ElementProxy
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TabStops(ElementProxy):
|
|
8
|
+
"""A sequence of |TabStop| objects providing access to the tab stops of a paragraph
|
|
9
|
+
or paragraph style.
|
|
10
|
+
|
|
11
|
+
Supports iteration, indexed access, del, and len(). It is accesed using the
|
|
12
|
+
:attr:`~.ParagraphFormat.tab_stops` property of ParagraphFormat; it is not intended
|
|
13
|
+
to be constructed directly.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, element):
|
|
17
|
+
super(TabStops, self).__init__(element, None)
|
|
18
|
+
self._pPr = element
|
|
19
|
+
|
|
20
|
+
def __delitem__(self, idx):
|
|
21
|
+
"""Remove the tab at offset `idx` in this sequence."""
|
|
22
|
+
tabs = self._pPr.tabs
|
|
23
|
+
try:
|
|
24
|
+
tabs.remove(tabs[idx])
|
|
25
|
+
except (AttributeError, IndexError):
|
|
26
|
+
raise IndexError("tab index out of range")
|
|
27
|
+
|
|
28
|
+
if len(tabs) == 0:
|
|
29
|
+
self._pPr.remove(tabs)
|
|
30
|
+
|
|
31
|
+
def __getitem__(self, idx):
|
|
32
|
+
"""Enables list-style access by index."""
|
|
33
|
+
tabs = self._pPr.tabs
|
|
34
|
+
if tabs is None:
|
|
35
|
+
raise IndexError("TabStops object is empty")
|
|
36
|
+
tab = tabs.tab_lst[idx]
|
|
37
|
+
return TabStop(tab)
|
|
38
|
+
|
|
39
|
+
def __iter__(self):
|
|
40
|
+
"""Generate a TabStop object for each of the w:tab elements, in XML document
|
|
41
|
+
order."""
|
|
42
|
+
tabs = self._pPr.tabs
|
|
43
|
+
if tabs is not None:
|
|
44
|
+
for tab in tabs.tab_lst:
|
|
45
|
+
yield TabStop(tab)
|
|
46
|
+
|
|
47
|
+
def __len__(self):
|
|
48
|
+
tabs = self._pPr.tabs
|
|
49
|
+
if tabs is None:
|
|
50
|
+
return 0
|
|
51
|
+
return len(tabs.tab_lst)
|
|
52
|
+
|
|
53
|
+
def add_tab_stop(self, position, alignment=WD_TAB_ALIGNMENT.LEFT, leader=WD_TAB_LEADER.SPACES):
|
|
54
|
+
"""Add a new tab stop at `position`, a |Length| object specifying the location
|
|
55
|
+
of the tab stop relative to the paragraph edge.
|
|
56
|
+
|
|
57
|
+
A negative `position` value is valid and appears in hanging indentation. Tab
|
|
58
|
+
alignment defaults to left, but may be specified by passing a member of the
|
|
59
|
+
:ref:`WdTabAlignment` enumeration as `alignment`. An optional leader character
|
|
60
|
+
can be specified by passing a member of the :ref:`WdTabLeader` enumeration as
|
|
61
|
+
`leader`.
|
|
62
|
+
"""
|
|
63
|
+
tabs = self._pPr.get_or_add_tabs()
|
|
64
|
+
tab = tabs.insert_tab_in_order(position, alignment, leader)
|
|
65
|
+
return TabStop(tab)
|
|
66
|
+
|
|
67
|
+
def clear_all(self):
|
|
68
|
+
"""Remove all custom tab stops."""
|
|
69
|
+
self._pPr._remove_tabs()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TabStop(ElementProxy):
|
|
73
|
+
"""An individual tab stop applying to a paragraph or style.
|
|
74
|
+
|
|
75
|
+
Accessed using list semantics on its containing |TabStops| object.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(self, element):
|
|
79
|
+
super(TabStop, self).__init__(element, None)
|
|
80
|
+
self._tab = element
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def alignment(self):
|
|
84
|
+
"""A member of :ref:`WdTabAlignment` specifying the alignment setting for this
|
|
85
|
+
tab stop.
|
|
86
|
+
|
|
87
|
+
Read/write.
|
|
88
|
+
"""
|
|
89
|
+
return self._tab.val
|
|
90
|
+
|
|
91
|
+
@alignment.setter
|
|
92
|
+
def alignment(self, value):
|
|
93
|
+
self._tab.val = value
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def leader(self):
|
|
97
|
+
"""A member of :ref:`WdTabLeader` specifying a repeating character used as a
|
|
98
|
+
"leader", filling in the space spanned by this tab.
|
|
99
|
+
|
|
100
|
+
Assigning |None| produces the same result as assigning `WD_TAB_LEADER.SPACES`.
|
|
101
|
+
Read/write.
|
|
102
|
+
"""
|
|
103
|
+
return self._tab.leader
|
|
104
|
+
|
|
105
|
+
@leader.setter
|
|
106
|
+
def leader(self, value):
|
|
107
|
+
self._tab.leader = value
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def position(self):
|
|
111
|
+
"""A |Length| object representing the distance of this tab stop from the inside
|
|
112
|
+
edge of the paragraph.
|
|
113
|
+
|
|
114
|
+
May be positive or negative. Read/write.
|
|
115
|
+
"""
|
|
116
|
+
return self._tab.pos
|
|
117
|
+
|
|
118
|
+
@position.setter
|
|
119
|
+
def position(self, value):
|
|
120
|
+
tab = self._tab
|
|
121
|
+
tabs = tab.getparent()
|
|
122
|
+
self._tab = tabs.insert_tab_in_order(value, tab.val, tab.leader)
|
|
123
|
+
tabs.remove(tab)
|
docx/theme.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Document theme font scheme."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from docx.oxml.ns import qn
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from lxml.etree import _Element # pyright: ignore[reportPrivateUsage]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ThemeFonts:
|
|
14
|
+
"""The font scheme used by theme references in a document.
|
|
15
|
+
|
|
16
|
+
Accessed through :attr:`.Document.theme_fonts`. Changing a typeface does not
|
|
17
|
+
change styles or runs. Only text already referring to that theme slot follows
|
|
18
|
+
the change. East Asian, complex-script, and supplemental fonts are preserved.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, element: _Element):
|
|
22
|
+
self._element = element
|
|
23
|
+
# Validate before any setters can partially update an incomplete scheme.
|
|
24
|
+
self._latin("major")
|
|
25
|
+
self._latin("minor")
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def name(self) -> str:
|
|
29
|
+
"""Read/write font scheme name shown in the application's theme settings."""
|
|
30
|
+
return self._element.get("name", "")
|
|
31
|
+
|
|
32
|
+
@name.setter
|
|
33
|
+
def name(self, value: str) -> None:
|
|
34
|
+
self._element.set("name", value)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def major_latin(self) -> str:
|
|
38
|
+
"""Read/write Latin typeface for the major (heading) theme font."""
|
|
39
|
+
return self._latin("major").get("typeface", "")
|
|
40
|
+
|
|
41
|
+
@major_latin.setter
|
|
42
|
+
def major_latin(self, value: str) -> None:
|
|
43
|
+
self._set_latin("major", value)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def minor_latin(self) -> str:
|
|
47
|
+
"""Read/write Latin typeface for the minor (body) theme font."""
|
|
48
|
+
return self._latin("minor").get("typeface", "")
|
|
49
|
+
|
|
50
|
+
@minor_latin.setter
|
|
51
|
+
def minor_latin(self, value: str) -> None:
|
|
52
|
+
self._set_latin("minor", value)
|
|
53
|
+
|
|
54
|
+
def _latin(self, role: str) -> _Element:
|
|
55
|
+
latin = self._element.find(f"{qn(f'a:{role}Font')}/{qn('a:latin')}")
|
|
56
|
+
if latin is None:
|
|
57
|
+
raise ValueError(f"theme font scheme is missing the {role} Latin font")
|
|
58
|
+
return latin
|
|
59
|
+
|
|
60
|
+
def _set_latin(self, role: str, value: object) -> None:
|
|
61
|
+
if not isinstance(value, str):
|
|
62
|
+
raise TypeError("theme typeface must be a string")
|
|
63
|
+
latin = self._latin(role)
|
|
64
|
+
latin.set("typeface", value)
|
|
65
|
+
# These optional metrics describe the previous typeface.
|
|
66
|
+
for attribute in ("panose", "pitchFamily", "charset"):
|
|
67
|
+
latin.attrib.pop(attribute, None)
|
docx/types.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Abstract types used by `python-docx`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from typing_extensions import Protocol
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from docx.opc.part import XmlPart
|
|
11
|
+
from docx.parts.story import StoryPart
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ProvidesStoryPart(Protocol):
|
|
15
|
+
"""An object that provides access to the StoryPart.
|
|
16
|
+
|
|
17
|
+
This type is for objects that have a story part like document or header as their
|
|
18
|
+
root part.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def part(self) -> StoryPart: ...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ProvidesXmlPart(Protocol):
|
|
26
|
+
"""An object that provides access to its XmlPart.
|
|
27
|
+
|
|
28
|
+
This type is for objects that need access to their part but it either isn't a
|
|
29
|
+
StoryPart or they don't care, possibly because they just need access to the package
|
|
30
|
+
or related parts.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def part(self) -> XmlPart: ...
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ps-python-docx
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: A maintained fork of python-docx for reading and authoring Microsoft Word documents.
|
|
5
|
+
Author-email: Steve Canny <stcanny@gmail.com>
|
|
6
|
+
Maintainer: John Paul Ellis
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Changelog, https://github.com/pseudosavant/python-docx/blob/master/HISTORY.rst
|
|
9
|
+
Project-URL: Documentation, https://python-docx.readthedocs.org/en/latest/
|
|
10
|
+
Project-URL: Homepage, https://github.com/pseudosavant/python-docx
|
|
11
|
+
Project-URL: Repository, https://github.com/pseudosavant/python-docx
|
|
12
|
+
Project-URL: Issues, https://github.com/pseudosavant/python-docx/issues
|
|
13
|
+
Project-URL: Upstream, https://github.com/python-openxml/python-docx
|
|
14
|
+
Keywords: docx,office,openxml,word
|
|
15
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
16
|
+
Classifier: Environment :: Console
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
27
|
+
Classifier: Topic :: Office/Business :: Office Suites
|
|
28
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
29
|
+
Requires-Python: >=3.9
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: lxml>=3.1.0
|
|
33
|
+
Requires-Dist: typing_extensions>=4.9.0
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# ps-python-docx
|
|
37
|
+
|
|
38
|
+
*ps-python-docx* is John Paul Ellis's fork of [python-docx](https://github.com/python-openxml/python-docx), a Python library for reading, creating, and updating Microsoft Word 2007+ (.docx) files. It is published independently and is not an official upstream release.
|
|
39
|
+
|
|
40
|
+
This fork starts from upstream 1.2.0. The packaging setup preserves the upstream API and the `docx` import name. Version 1.3.0 adds public theme font and style inheritance APIs. See the [theme API documentation](docs/api/theme.rst). The original MIT license and upstream attribution are preserved.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
pip install ps-python-docx
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Example
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
>>> from docx import Document
|
|
52
|
+
|
|
53
|
+
>>> document = Document()
|
|
54
|
+
>>> document.add_paragraph("It was a dark and stormy night.")
|
|
55
|
+
<docx.text.paragraph.Paragraph object at 0x10f19e760>
|
|
56
|
+
>>> document.save("dark-and-stormy.docx")
|
|
57
|
+
|
|
58
|
+
>>> document = Document("dark-and-stormy.docx")
|
|
59
|
+
>>> document.paragraphs[0].text
|
|
60
|
+
'It was a dark and stormy night.'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Install this distribution in place of `python-docx`. Both provide the `docx` package and should not be installed in the same environment.
|
|
64
|
+
|
|
65
|
+
More information about the inherited API is available in the [upstream documentation](https://python-docx.readthedocs.org/en/latest/). Report fork-specific issues in [this repository](https://github.com/pseudosavant/python-docx/issues).
|
|
66
|
+
|
|
67
|
+
## Development and releases
|
|
68
|
+
|
|
69
|
+
Run the unit and acceptance suites without installing the legacy documentation dependencies:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
uv sync --locked --no-dev --group test
|
|
73
|
+
uv run --locked --no-dev --group test pytest -q
|
|
74
|
+
uv run --locked --no-dev --group test behave --format progress --stop --tags=-wip
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
See [RELEASING.md](RELEASING.md) for the GitHub-to-PyPI release process.
|