-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathparagraph.py
177 lines (144 loc) · 6.73 KB
/
paragraph.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
"""Paragraph-related proxy types."""
from __future__ import annotations
from typing import TYPE_CHECKING, Iterator, List, cast
from docx.enum.style import WD_STYLE_TYPE
from docx.oxml.text.run import CT_R
from docx.shared import StoryChild
from docx.styles.style import ParagraphStyle
from docx.text.hyperlink import Hyperlink
from docx.text.pagebreak import RenderedPageBreak
from docx.text.parfmt import ParagraphFormat
from docx.text.run import Run
if TYPE_CHECKING:
import docx.types as t
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.text.paragraph import CT_P
from docx.styles.style import CharacterStyle
class Paragraph(StoryChild):
"""Proxy object wrapping a `<w:p>` element."""
def __init__(self, p: CT_P, parent: t.ProvidesStoryPart):
super(Paragraph, self).__init__(parent)
self._p = self._element = p
def add_run(self, text: str | None = None, style: str | CharacterStyle | None = None) -> Run:
"""Append run containing `text` and having character-style `style`.
`text` can contain tab (``\\t``) characters, which are converted to the
appropriate XML form for a tab. `text` can also include newline (``\\n``) or
carriage return (``\\r``) characters, each of which is converted to a line
break. When `text` is `None`, the new run is empty.
"""
r = self._p.add_r()
run = Run(r, self)
if text:
run.text = text
if style:
run.style = style
return run
@property
def alignment(self) -> WD_PARAGRAPH_ALIGNMENT | None:
"""A member of the :ref:`WdParagraphAlignment` enumeration specifying the
justification setting for this paragraph.
A value of |None| indicates the paragraph has no directly-applied alignment
value and will inherit its alignment value from its style hierarchy. Assigning
|None| to this property removes any directly-applied alignment value.
"""
return self._p.alignment
@alignment.setter
def alignment(self, value: WD_PARAGRAPH_ALIGNMENT):
self._p.alignment = value
def clear(self):
"""Return this same paragraph after removing all its content.
Paragraph-level formatting, such as style, is preserved.
"""
self._p.clear_content()
return self
@property
def contains_page_break(self) -> bool:
"""`True` when one or more rendered page-breaks occur in this paragraph."""
return bool(self._p.lastRenderedPageBreaks)
@property
def hyperlinks(self) -> List[Hyperlink]:
"""A |Hyperlink| instance for each hyperlink in this paragraph."""
return [Hyperlink(hyperlink, self) for hyperlink in self._p.hyperlink_lst]
def insert_paragraph_before(
self, text: str | None = None, style: str | ParagraphStyle | None = None
) -> Paragraph:
"""Return a newly created paragraph, inserted directly before this paragraph.
If `text` is supplied, the new paragraph contains that text in a single run. If
`style` is provided, that style is assigned to the new paragraph.
"""
paragraph = self._insert_paragraph_before()
if text:
paragraph.add_run(text)
if style is not None:
paragraph.style = style
return paragraph
def iter_inner_content(self) -> Iterator[Run | Hyperlink]:
"""Generate the runs and hyperlinks in this paragraph, in the order they appear.
The content in a paragraph consists of both runs and hyperlinks. This method
allows accessing each of those separately, in document order, for when the
precise position of the hyperlink within the paragraph text is important. Note
that a hyperlink itself contains runs.
"""
for r_or_hlink in self._p.inner_content_elements:
yield (
Run(r_or_hlink, self)
if isinstance(r_or_hlink, CT_R)
else Hyperlink(r_or_hlink, self)
)
@property
def paragraph_format(self):
"""The |ParagraphFormat| object providing access to the formatting properties
for this paragraph, such as line spacing and indentation."""
return ParagraphFormat(self._element)
@property
def rendered_page_breaks(self) -> List[RenderedPageBreak]:
"""All rendered page-breaks in this paragraph.
Most often an empty list, sometimes contains one page-break, but can contain
more than one is rare or contrived cases.
"""
return [RenderedPageBreak(lrpb, self) for lrpb in self._p.lastRenderedPageBreaks]
@property
def runs(self) -> List[Run]:
"""Sequence of |Run| instances corresponding to the <w:r> elements in this
paragraph."""
return [Run(r, self) for r in self._p.r_lst]
@property
def style(self) -> ParagraphStyle | None:
"""Read/Write.
|_ParagraphStyle| object representing the style assigned to this paragraph. If
no explicit style is assigned to this paragraph, its value is the default
paragraph style for the document. A paragraph style name can be assigned in lieu
of a paragraph style object. Assigning |None| removes any applied style, making
its effective value the default paragraph style for the document.
"""
style_id = self._p.style
style = self.part.get_style(style_id, WD_STYLE_TYPE.PARAGRAPH)
return cast(ParagraphStyle, style)
@style.setter
def style(self, style_or_name: str | ParagraphStyle | None):
style_id = self.part.get_style_id(style_or_name, WD_STYLE_TYPE.PARAGRAPH)
self._p.style = style_id
@property
def text(self) -> str:
"""The textual content of this paragraph.
The text includes the visible-text portion of any hyperlinks in the paragraph.
Tabs and line breaks in the XML are mapped to ``\\t`` and ``\\n`` characters
respectively.
Assigning text to this property causes all existing paragraph content to be
replaced with a single run containing the assigned text. A ``\\t`` character in
the text is mapped to a ``<w:tab/>`` element and each ``\\n`` or ``\\r``
character is mapped to a line break. Paragraph-level formatting, such as style,
is preserved. All run-level formatting, such as bold or italic, is removed.
"""
return self._p.text
@text.setter
def text(self, text: str | None):
self.clear()
self.add_run(text)
def _insert_paragraph_before(self):
"""Return a newly created paragraph, inserted directly before this paragraph."""
p = self._p.add_p_before()
return Paragraph(p, self._parent)
@property
def element(self):
return self._element