Skip to content

Commit afc60c1

Browse files
author
Steve Canny
committed
reorg: extract docx.oxml.text.run module
1 parent 78f9107 commit afc60c1

File tree

5 files changed

+297
-286
lines changed

5 files changed

+297
-286
lines changed

docx/oxml/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,13 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
134134
register_element_cls('w:tr', CT_Row)
135135
register_element_cls('w:vMerge', CT_VMerge)
136136

137-
from .text import (
138-
CT_Br, CT_Jc, CT_P, CT_PPr, CT_R, CT_RPr, CT_Text, CT_Underline
139-
)
137+
from .text import CT_Jc, CT_P, CT_PPr
138+
register_element_cls('w:jc', CT_Jc)
139+
register_element_cls('w:p', CT_P)
140+
register_element_cls('w:pPr', CT_PPr)
141+
register_element_cls('w:pStyle', CT_String)
142+
143+
from .text.run import CT_Br, CT_R, CT_RPr, CT_Text, CT_Underline
140144
register_element_cls('w:b', CT_OnOff)
141145
register_element_cls('w:bCs', CT_OnOff)
142146
register_element_cls('w:br', CT_Br)
@@ -147,13 +151,9 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
147151
register_element_cls('w:i', CT_OnOff)
148152
register_element_cls('w:iCs', CT_OnOff)
149153
register_element_cls('w:imprint', CT_OnOff)
150-
register_element_cls('w:jc', CT_Jc)
151154
register_element_cls('w:noProof', CT_OnOff)
152155
register_element_cls('w:oMath', CT_OnOff)
153156
register_element_cls('w:outline', CT_OnOff)
154-
register_element_cls('w:p', CT_P)
155-
register_element_cls('w:pPr', CT_PPr)
156-
register_element_cls('w:pStyle', CT_String)
157157
register_element_cls('w:r', CT_R)
158158
register_element_cls('w:rPr', CT_RPr)
159159
register_element_cls('w:rStyle', CT_String)

docx/oxml/text/__init__.py

Lines changed: 2 additions & 277 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,13 @@
55
(CT_R).
66
"""
77

8-
from ...enum.text import WD_ALIGN_PARAGRAPH, WD_UNDERLINE
8+
from ...enum.text import WD_ALIGN_PARAGRAPH
99
from ..ns import qn
10-
from ..simpletypes import ST_BrClear, ST_BrType
1110
from ..xmlchemy import (
12-
BaseOxmlElement, OptionalAttribute, OxmlElement, RequiredAttribute,
13-
ZeroOrMore, ZeroOrOne
11+
BaseOxmlElement, OxmlElement, RequiredAttribute, ZeroOrMore, ZeroOrOne
1412
)
1513

1614

17-
class CT_Br(BaseOxmlElement):
18-
"""
19-
``<w:br>`` element, indicating a line, page, or column break in a run.
20-
"""
21-
type = OptionalAttribute('w:type', ST_BrType)
22-
clear = OptionalAttribute('w:clear', ST_BrClear)
23-
24-
2515
class CT_Jc(BaseOxmlElement):
2616
"""
2717
``<w:jc>`` element, specifying paragraph justification.
@@ -164,268 +154,3 @@ def style(self, style):
164154
return
165155
pStyle = self.get_or_add_pStyle()
166156
pStyle.val = style
167-
168-
169-
class CT_R(BaseOxmlElement):
170-
"""
171-
``<w:r>`` element, containing the properties and text for a run.
172-
"""
173-
rPr = ZeroOrOne('w:rPr')
174-
t = ZeroOrMore('w:t')
175-
br = ZeroOrMore('w:br')
176-
cr = ZeroOrMore('w:cr')
177-
tab = ZeroOrMore('w:tab')
178-
drawing = ZeroOrMore('w:drawing')
179-
180-
def _insert_rPr(self, rPr):
181-
self.insert(0, rPr)
182-
return rPr
183-
184-
def add_t(self, text):
185-
"""
186-
Return a newly added ``<w:t>`` element containing *text*.
187-
"""
188-
t = self._add_t(text=text)
189-
if len(text.strip()) < len(text):
190-
t.set(qn('xml:space'), 'preserve')
191-
return t
192-
193-
def add_drawing(self, inline_or_anchor):
194-
"""
195-
Return a newly appended ``CT_Drawing`` (``<w:drawing>``) child
196-
element having *inline_or_anchor* as its child.
197-
"""
198-
drawing = self._add_drawing()
199-
drawing.append(inline_or_anchor)
200-
return drawing
201-
202-
def clear_content(self):
203-
"""
204-
Remove all child elements except the ``<w:rPr>`` element if present.
205-
"""
206-
content_child_elms = self[1:] if self.rPr is not None else self[:]
207-
for child in content_child_elms:
208-
self.remove(child)
209-
210-
@property
211-
def style(self):
212-
"""
213-
String contained in w:val attribute of <w:rStyle> grandchild, or
214-
|None| if that element is not present.
215-
"""
216-
rPr = self.rPr
217-
if rPr is None:
218-
return None
219-
return rPr.style
220-
221-
@style.setter
222-
def style(self, style):
223-
"""
224-
Set the character style of this <w:r> element to *style*. If *style*
225-
is None, remove the style element.
226-
"""
227-
rPr = self.get_or_add_rPr()
228-
rPr.style = style
229-
230-
@property
231-
def text(self):
232-
"""
233-
A string representing the textual content of this run, with content
234-
child elements like ``<w:tab/>`` translated to their Python
235-
equivalent.
236-
"""
237-
text = ''
238-
for child in self:
239-
if child.tag == qn('w:t'):
240-
t_text = child.text
241-
text += t_text if t_text is not None else ''
242-
elif child.tag == qn('w:tab'):
243-
text += '\t'
244-
elif child.tag in (qn('w:br'), qn('w:cr')):
245-
text += '\n'
246-
return text
247-
248-
@text.setter
249-
def text(self, text):
250-
self.clear_content()
251-
_RunContentAppender.append_to_run_from_text(self, text)
252-
253-
@property
254-
def underline(self):
255-
"""
256-
String contained in w:val attribute of ./w:rPr/w:u grandchild, or
257-
|None| if not present.
258-
"""
259-
rPr = self.rPr
260-
if rPr is None:
261-
return None
262-
return rPr.underline
263-
264-
@underline.setter
265-
def underline(self, value):
266-
rPr = self.get_or_add_rPr()
267-
rPr.underline = value
268-
269-
270-
class CT_RPr(BaseOxmlElement):
271-
"""
272-
``<w:rPr>`` element, containing the properties for a run.
273-
"""
274-
rStyle = ZeroOrOne('w:rStyle', successors=('w:rPrChange',))
275-
b = ZeroOrOne('w:b', successors=('w:rPrChange',))
276-
bCs = ZeroOrOne('w:bCs', successors=('w:rPrChange',))
277-
caps = ZeroOrOne('w:caps', successors=('w:rPrChange',))
278-
cs = ZeroOrOne('w:cs', successors=('w:rPrChange',))
279-
dstrike = ZeroOrOne('w:dstrike', successors=('w:rPrChange',))
280-
emboss = ZeroOrOne('w:emboss', successors=('w:rPrChange',))
281-
i = ZeroOrOne('w:i', successors=('w:rPrChange',))
282-
iCs = ZeroOrOne('w:iCs', successors=('w:rPrChange',))
283-
imprint = ZeroOrOne('w:imprint', successors=('w:rPrChange',))
284-
noProof = ZeroOrOne('w:noProof', successors=('w:rPrChange',))
285-
oMath = ZeroOrOne('w:oMath', successors=('w:rPrChange',))
286-
outline = ZeroOrOne('w:outline', successors=('w:rPrChange',))
287-
rtl = ZeroOrOne('w:rtl', successors=('w:rPrChange',))
288-
shadow = ZeroOrOne('w:shadow', successors=('w:rPrChange',))
289-
smallCaps = ZeroOrOne('w:smallCaps', successors=('w:rPrChange',))
290-
snapToGrid = ZeroOrOne('w:snapToGrid', successors=('w:rPrChange',))
291-
specVanish = ZeroOrOne('w:specVanish', successors=('w:rPrChange',))
292-
strike = ZeroOrOne('w:strike', successors=('w:rPrChange',))
293-
u = ZeroOrOne('w:u', successors=('w:rPrChange',))
294-
vanish = ZeroOrOne('w:vanish', successors=('w:rPrChange',))
295-
webHidden = ZeroOrOne('w:webHidden', successors=('w:rPrChange',))
296-
297-
@property
298-
def style(self):
299-
"""
300-
String contained in <w:rStyle> child, or None if that element is not
301-
present.
302-
"""
303-
rStyle = self.rStyle
304-
if rStyle is None:
305-
return None
306-
return rStyle.val
307-
308-
@style.setter
309-
def style(self, style):
310-
"""
311-
Set val attribute of <w:rStyle> child element to *style*, adding a
312-
new element if necessary. If *style* is |None|, remove the <w:rStyle>
313-
element if present.
314-
"""
315-
if style is None:
316-
self._remove_rStyle()
317-
elif self.rStyle is None:
318-
self._add_rStyle(val=style)
319-
else:
320-
self.rStyle.val = style
321-
322-
@property
323-
def underline(self):
324-
"""
325-
Underline type specified in <w:u> child, or None if that element is
326-
not present.
327-
"""
328-
u = self.u
329-
if u is None:
330-
return None
331-
return u.val
332-
333-
@underline.setter
334-
def underline(self, value):
335-
self._remove_u()
336-
if value is not None:
337-
u = self._add_u()
338-
u.val = value
339-
340-
341-
class CT_Text(BaseOxmlElement):
342-
"""
343-
``<w:t>`` element, containing a sequence of characters within a run.
344-
"""
345-
346-
347-
class CT_Underline(BaseOxmlElement):
348-
"""
349-
``<w:u>`` element, specifying the underlining style for a run.
350-
"""
351-
@property
352-
def val(self):
353-
"""
354-
The underline type corresponding to the ``w:val`` attribute value.
355-
"""
356-
val = self.get(qn('w:val'))
357-
underline = WD_UNDERLINE.from_xml(val)
358-
if underline == WD_UNDERLINE.SINGLE:
359-
return True
360-
if underline == WD_UNDERLINE.NONE:
361-
return False
362-
return underline
363-
364-
@val.setter
365-
def val(self, value):
366-
# works fine without these two mappings, but only because True == 1
367-
# and False == 0, which happen to match the mapping for WD_UNDERLINE
368-
# .SINGLE and .NONE respectively.
369-
if value is True:
370-
value = WD_UNDERLINE.SINGLE
371-
elif value is False:
372-
value = WD_UNDERLINE.NONE
373-
374-
val = WD_UNDERLINE.to_xml(value)
375-
self.set(qn('w:val'), val)
376-
377-
378-
class _RunContentAppender(object):
379-
"""
380-
Service object that knows how to translate a Python string into run
381-
content elements appended to a specified ``<w:r>`` element. Contiguous
382-
sequences of regular characters are appended in a single ``<w:t>``
383-
element. Each tab character ('\t') causes a ``<w:tab/>`` element to be
384-
appended. Likewise a newline or carriage return character ('\n', '\r')
385-
causes a ``<w:cr>`` element to be appended.
386-
"""
387-
def __init__(self, r):
388-
self._r = r
389-
self._bfr = []
390-
391-
@classmethod
392-
def append_to_run_from_text(cls, r, text):
393-
"""
394-
Create a "one-shot" ``_RunContentAppender`` instance and use it to
395-
append the run content elements corresponding to *text* to the
396-
``<w:r>`` element *r*.
397-
"""
398-
appender = cls(r)
399-
appender.add_text(text)
400-
401-
def add_text(self, text):
402-
"""
403-
Append the run content elements corresponding to *text* to the
404-
``<w:r>`` element of this instance.
405-
"""
406-
for char in text:
407-
self.add_char(char)
408-
self.flush()
409-
410-
def add_char(self, char):
411-
"""
412-
Process the next character of input through the translation finite
413-
state maching (FSM). There are two possible states, buffer pending
414-
and not pending, but those are hidden behind the ``.flush()`` method
415-
which must be called at the end of text to ensure any pending
416-
``<w:t>`` element is written.
417-
"""
418-
if char == '\t':
419-
self.flush()
420-
self._r.add_tab()
421-
elif char in '\r\n':
422-
self.flush()
423-
self._r.add_br()
424-
else:
425-
self._bfr.append(char)
426-
427-
def flush(self):
428-
text = ''.join(self._bfr)
429-
if text:
430-
self._r.add_t(text)
431-
del self._bfr[:]

0 commit comments

Comments
 (0)