-
Notifications
You must be signed in to change notification settings - Fork 553
/
Copy pathtext.py
744 lines (601 loc) · 27 KB
/
text.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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
"""Text-related objects such as TextFrame and Paragraph."""
from __future__ import annotations
from typing import TYPE_CHECKING, Iterator, cast
from pptx.dml.fill import FillFormat
from pptx.enum.dml import MSO_FILL
from pptx.enum.lang import MSO_LANGUAGE_ID
from pptx.enum.text import MSO_AUTO_SIZE, MSO_UNDERLINE, MSO_VERTICAL_ANCHOR
from pptx.opc.constants import RELATIONSHIP_TYPE as RT
from pptx.oxml.simpletypes import ST_TextWrappingType
from pptx.shapes import Subshape
from pptx.text.fonts import FontFiles
from pptx.text.layout import TextFitter
from pptx.util import Centipoints, Emu, Length, Pt, lazyproperty
if TYPE_CHECKING:
from pptx.dml.color import ColorFormat
from pptx.enum.text import (
MSO_TEXT_UNDERLINE_TYPE,
MSO_VERTICAL_ANCHOR,
PP_PARAGRAPH_ALIGNMENT,
)
from pptx.oxml.action import CT_Hyperlink
from pptx.oxml.text import (
CT_RegularTextRun,
CT_TextBody,
CT_TextCharacterProperties,
CT_TextParagraph,
CT_TextParagraphProperties,
)
from pptx.types import ProvidesExtents, ProvidesPart
class TextFrame(Subshape):
"""The part of a shape that contains its text.
Not all shapes have a text frame. Corresponds to the `p:txBody` element that can
appear as a child element of `p:sp`. Not intended to be constructed directly.
"""
def __init__(self, txBody: CT_TextBody, parent: ProvidesPart):
super(TextFrame, self).__init__(parent)
self._element = self._txBody = txBody
self._parent = parent
def add_paragraph(self):
"""
Return new |_Paragraph| instance appended to the sequence of
paragraphs contained in this text frame.
"""
p = self._txBody.add_p()
return _Paragraph(p, self)
@property
def auto_size(self) -> MSO_AUTO_SIZE | None:
"""Resizing strategy used to fit text within this shape.
Determins the type of automatic resizing used to fit the text of this shape within its
bounding box when the text would otherwise extend beyond the shape boundaries. May be
|None|, `MSO_AUTO_SIZE.NONE`, `MSO_AUTO_SIZE.SHAPE_TO_FIT_TEXT`, or
`MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE`.
"""
return self._bodyPr.autofit
@auto_size.setter
def auto_size(self, value: MSO_AUTO_SIZE | None):
self._bodyPr.autofit = value
def clear(self):
"""Remove all paragraphs except one empty one."""
for p in self._txBody.p_lst[1:]:
self._txBody.remove(p)
p = self.paragraphs[0]
p.clear()
def fit_text(
self,
font_family: str = "Calibri",
max_size: int = 18,
bold: bool = False,
italic: bool = False,
font_file: str | None = None,
):
"""Fit text-frame text entirely within bounds of its shape.
Make the text in this text frame fit entirely within the bounds of its shape by setting
word wrap on and applying the "best-fit" font size to all the text it contains.
:attr:`TextFrame.auto_size` is set to :attr:`MSO_AUTO_SIZE.NONE`. The font size will not
be set larger than `max_size` points. If the path to a matching TrueType font is provided
as `font_file`, that font file will be used for the font metrics. If `font_file` is |None|,
best efforts are made to locate a font file with matchhing `font_family`, `bold`, and
`italic` installed on the current system (usually succeeds if the font is installed).
"""
# ---no-op when empty as fit behavior not defined for that case---
if self.text == "":
return # pragma: no cover
font_size = self._best_fit_font_size(font_family, max_size, bold, italic, font_file)
self._apply_fit(font_family, font_size, bold, italic)
@property
def margin_bottom(self) -> Length:
"""|Length| value representing the inset of text from the bottom text frame border.
:meth:`pptx.util.Inches` provides a convenient way of setting the value, e.g.
`text_frame.margin_bottom = Inches(0.05)`.
"""
return self._bodyPr.bIns
@margin_bottom.setter
def margin_bottom(self, emu: Length):
self._bodyPr.bIns = emu
@property
def margin_left(self) -> Length:
"""Inset of text from left text frame border as |Length| value."""
return self._bodyPr.lIns
@margin_left.setter
def margin_left(self, emu: Length):
self._bodyPr.lIns = emu
@property
def margin_right(self) -> Length:
"""Inset of text from right text frame border as |Length| value."""
return self._bodyPr.rIns
@margin_right.setter
def margin_right(self, emu: Length):
self._bodyPr.rIns = emu
@property
def margin_top(self) -> Length:
"""Inset of text from top text frame border as |Length| value."""
return self._bodyPr.tIns
@margin_top.setter
def margin_top(self, emu: Length):
self._bodyPr.tIns = emu
@property
def paragraphs(self) -> tuple[_Paragraph, ...]:
"""Sequence of paragraphs in this text frame.
A text frame always contains at least one paragraph.
"""
return tuple([_Paragraph(p, self) for p in self._txBody.p_lst])
@property
def text(self) -> str:
"""All text in this text-frame as a single string.
Read/write. The return value contains all text in this text-frame. A line-feed character
(`"\\n"`) separates the text for each paragraph. A vertical-tab character (`"\\v"`) appears
for each line break (aka. soft carriage-return) encountered.
The vertical-tab character is how PowerPoint represents a soft carriage return in clipboard
text, which is why that encoding was chosen.
Assignment replaces all text in the text frame. A new paragraph is added for each line-feed
character (`"\\n"`) encountered. A line-break (soft carriage-return) is inserted for each
vertical-tab character (`"\\v"`) encountered.
Any control character other than newline, tab, or vertical-tab are escaped as plain-text
like "_x001B_" (for ESC (ASCII 32) in this example).
"""
return "\n".join(paragraph.text for paragraph in self.paragraphs)
@text.setter
def text(self, text: str):
txBody = self._txBody
txBody.clear_content()
for p_text in text.split("\n"):
p = txBody.add_p()
p.append_text(p_text)
@property
def vertical_anchor(self) -> MSO_VERTICAL_ANCHOR | None:
"""Represents the vertical alignment of text in this text frame.
|None| indicates the effective value should be inherited from this object's style hierarchy.
"""
return self._txBody.bodyPr.anchor
@vertical_anchor.setter
def vertical_anchor(self, value: MSO_VERTICAL_ANCHOR | None):
bodyPr = self._txBody.bodyPr
bodyPr.anchor = value
@property
def word_wrap(self) -> bool | None:
"""`True` when lines of text in this shape are wrapped to fit within the shape's width.
Read-write. Valid values are True, False, or None. True and False turn word wrap on and
off, respectively. Assigning None to word wrap causes any word wrap setting to be removed
from the text frame, causing it to inherit this setting from its style hierarchy.
"""
return {
ST_TextWrappingType.SQUARE: True,
ST_TextWrappingType.NONE: False,
None: None,
}[self._txBody.bodyPr.wrap]
@word_wrap.setter
def word_wrap(self, value: bool | None):
if value not in (True, False, None):
raise ValueError( # pragma: no cover
"assigned value must be True, False, or None, got %s" % value
)
self._txBody.bodyPr.wrap = {
True: ST_TextWrappingType.SQUARE,
False: ST_TextWrappingType.NONE,
None: None,
}[value]
def _apply_fit(self, font_family: str, font_size: int, is_bold: bool, is_italic: bool):
"""Arrange text in this text frame to fit inside its extents.
This is accomplished by setting auto size off, wrap on, and setting the font of
all its text to `font_family`, `font_size`, `is_bold`, and `is_italic`.
"""
self.auto_size = MSO_AUTO_SIZE.NONE
self.word_wrap = True
self._set_font(font_family, font_size, is_bold, is_italic)
def _best_fit_font_size(
self, family: str, max_size: int, bold: bool, italic: bool, font_file: str | None
) -> int:
"""Return font-size in points that best fits text in this text-frame.
The best-fit font size is the largest integer point size not greater than `max_size` that
allows all the text in this text frame to fit inside its extents when rendered using the
font described by `family`, `bold`, and `italic`. If `font_file` is specified, it is used
to calculate the fit, whether or not it matches `family`, `bold`, and `italic`.
"""
if font_file is None:
font_file = FontFiles.find(family, bold, italic)
return TextFitter.best_fit_font_size(self.text, self._extents, max_size, font_file)
@property
def _bodyPr(self):
return self._txBody.bodyPr
@property
def _extents(self) -> tuple[Length, Length]:
"""(cx, cy) 2-tuple representing the effective rendering area of this text-frame.
Margins are taken into account.
"""
parent = cast("ProvidesExtents", self._parent)
return (
Length(parent.width - self.margin_left - self.margin_right),
Length(parent.height - self.margin_top - self.margin_bottom),
)
def _set_font(self, family: str, size: int, bold: bool, italic: bool):
"""Set the font properties of all the text in this text frame."""
def iter_rPrs(txBody: CT_TextBody) -> Iterator[CT_TextCharacterProperties]:
for p in txBody.p_lst:
for elm in p.content_children:
yield elm.get_or_add_rPr()
# generate a:endParaRPr for each <a:p> element
yield p.get_or_add_endParaRPr()
def set_rPr_font(
rPr: CT_TextCharacterProperties, name: str, size: int, bold: bool, italic: bool
):
f = Font(rPr)
f.name, f.size, f.bold, f.italic = family, Pt(size), bold, italic
txBody = self._element
for rPr in iter_rPrs(txBody):
set_rPr_font(rPr, family, size, bold, italic)
class Font(object):
"""Character properties object, providing font size, font name, bold, italic, etc.
Corresponds to `a:rPr` child element of a run. Also appears as `a:defRPr` and
`a:endParaRPr` in paragraph and `a:defRPr` in list style elements.
"""
def __init__(self, rPr: CT_TextCharacterProperties):
super(Font, self).__init__()
self._element = self._rPr = rPr
@property
def bold(self) -> bool | None:
"""Get or set boolean bold value of |Font|, e.g. `paragraph.font.bold = True`.
If set to |None|, the bold setting is cleared and is inherited from an enclosing shape's
setting, or a setting in a style or master. Returns None if no bold attribute is present,
meaning the effective bold value is inherited from a master or the theme.
"""
return self._rPr.b
@bold.setter
def bold(self, value: bool | None):
self._rPr.b = value
@lazyproperty
def color(self) -> ColorFormat:
"""The |ColorFormat| instance that provides access to the color settings for this font."""
if self.fill.type != MSO_FILL.SOLID:
self.fill.solid()
return self.fill.fore_color
@lazyproperty
def fill(self) -> FillFormat:
"""|FillFormat| instance for this font.
Provides access to fill properties such as fill color.
"""
return FillFormat.from_fill_parent(self._rPr)
@property
def italic(self) -> bool | None:
"""Get or set boolean italic value of |Font| instance.
Has the same behaviors as bold with respect to None values.
"""
return self._rPr.i
@italic.setter
def italic(self, value: bool | None):
self._rPr.i = value
@property
def language_id(self) -> MSO_LANGUAGE_ID | None:
"""Get or set the language id of this |Font| instance.
The language id is a member of the :ref:`MsoLanguageId` enumeration. Assigning |None|
removes any language setting, the same behavior as assigning `MSO_LANGUAGE_ID.NONE`.
"""
lang = self._rPr.lang
if lang is None:
return MSO_LANGUAGE_ID.NONE
return self._rPr.lang
@language_id.setter
def language_id(self, value: MSO_LANGUAGE_ID | None):
if value == MSO_LANGUAGE_ID.NONE:
value = None
self._rPr.lang = value
@property
def name(self) -> str | None:
"""Get or set the typeface name for this |Font| instance.
Causes the text it controls to appear in the named font, if a matching font is found.
Returns |None| if the typeface is currently inherited from the theme. Setting it to |None|
removes any override of the theme typeface.
"""
latin = self._rPr.latin
if latin is None:
return None
return latin.typeface
@name.setter
def name(self, value: str | None):
if value is None:
self._rPr._remove_latin() # pyright: ignore[reportPrivateUsage]
else:
latin = self._rPr.get_or_add_latin()
latin.typeface = value
@property
def size(self) -> Length | None:
"""Indicates the font height in English Metric Units (EMU).
Read/write. |None| indicates the font size should be inherited from its style hierarchy,
such as a placeholder or document defaults (usually 18pt). |Length| is a subclass of |int|
having properties for convenient conversion into points or other length units. Likewise,
the :class:`pptx.util.Pt` class allows convenient specification of point values::
>>> font.size = Pt(24)
>>> font.size
304800
>>> font.size.pt
24.0
"""
sz = self._rPr.sz
if sz is None:
return None
return Centipoints(sz)
@size.setter
def size(self, emu: Length | None):
if emu is None:
self._rPr.sz = None
else:
sz = Emu(emu).centipoints
self._rPr.sz = sz
@property
def superscript(self) -> int | None:
"""
Return the superscript baseline offset if set, otherwise None.
A positive integer represents the text's upward shift relative to the baseline.
The default superscript offset is `30000` (when set via `True`).
"""
if self._rPr.baseline and self._rPr.baseline > 0 :
return self._rPr.baseline
return None
@superscript.setter
def superscript(self, value: bool | int | None):
"""
Set or remove superscript formatting.
- `True` sets the baseline to `30000` (default superscript offset).
- An `int` value explicitly sets the baseline to that amount.
- `False` or `None` removes superscript formatting.
"""
if value is True:
self._rPr.baseline = 30000
elif value is False:
self._rPr.baseline = None
elif isinstance(value, int) and value >= 0:
self._rPr.baseline = value
else:
self._rPr.baseline = None
@property
def subscript(self) -> int | None:
"""
Return the subscript baseline offset if set, otherwise None.
A negative integer represents the text's downward shift relative to the baseline.
The default subscript offset is `-15000` (when set via `True`).
"""
if self._rPr.baseline and self._rPr.baseline < 0:
return self._rPr.baseline
return None
@subscript.setter
def subscript(self, value: bool | int | None):
"""
Set or remove subscript formatting.
- `True` sets the baseline to `-15000` (default subscript offset).
- An `int` value explicitly sets the baseline to that amount.
- `False` or `None` removes subscript formatting.
"""
if value is True:
self._rPr.baseline = -15000
elif value is False:
self._rPr.baseline = None
elif isinstance(value, int) and value <= 0:
self._rPr.baseline = value
else:
self._rPr.baseline = None
@property
def underline(self) -> bool | MSO_TEXT_UNDERLINE_TYPE | None:
"""Indicaties the underline setting for this font.
Value is |True|, |False|, |None|, or a member of the :ref:`MsoTextUnderlineType`
enumeration. |None| is the default and indicates the underline setting should be inherited
from the style hierarchy, such as from a placeholder. |True| indicates single underline.
|False| indicates no underline. Other settings such as double and wavy underlining are
indicated with members of the :ref:`MsoTextUnderlineType` enumeration.
"""
u = self._rPr.u
if u is MSO_UNDERLINE.NONE:
return False
if u is MSO_UNDERLINE.SINGLE_LINE:
return True
return u
@underline.setter
def underline(self, value: bool | MSO_TEXT_UNDERLINE_TYPE | None):
if value is True:
value = MSO_UNDERLINE.SINGLE_LINE
elif value is False:
value = MSO_UNDERLINE.NONE
self._element.u = value
class _Hyperlink(Subshape):
"""Text run hyperlink object.
Corresponds to `a:hlinkClick` child element of the run's properties element (`a:rPr`).
"""
def __init__(self, rPr: CT_TextCharacterProperties, parent: ProvidesPart):
super(_Hyperlink, self).__init__(parent)
self._rPr = rPr
@property
def address(self) -> str | None:
"""The URL of the hyperlink.
Read/write. URL can be on http, https, mailto, or file scheme; others may work.
"""
if self._hlinkClick is None:
return None
return self.part.target_ref(self._hlinkClick.rId)
@address.setter
def address(self, url: str | None):
# implements all three of add, change, and remove hyperlink
if self._hlinkClick is not None:
self._remove_hlinkClick()
if url:
self._add_hlinkClick(url)
def _add_hlinkClick(self, url: str):
rId = self.part.relate_to(url, RT.HYPERLINK, is_external=True)
self._rPr.add_hlinkClick(rId)
@property
def _hlinkClick(self) -> CT_Hyperlink | None:
return self._rPr.hlinkClick
def _remove_hlinkClick(self):
assert self._hlinkClick is not None
self.part.drop_rel(self._hlinkClick.rId)
self._rPr._remove_hlinkClick() # pyright: ignore[reportPrivateUsage]
class _Paragraph(Subshape):
"""Paragraph object. Not intended to be constructed directly."""
def __init__(self, p: CT_TextParagraph, parent: ProvidesPart):
super(_Paragraph, self).__init__(parent)
self._element = self._p = p
def add_line_break(self):
"""Add line break at end of this paragraph."""
self._p.add_br()
def add_run(self) -> _Run:
"""Return a new run appended to the runs in this paragraph."""
r = self._p.add_r()
return _Run(r, self)
@property
def alignment(self) -> PP_PARAGRAPH_ALIGNMENT | None:
"""Horizontal alignment of this paragraph.
The value |None| indicates the paragraph should 'inherit' its effective value from its
style hierarchy. Assigning |None| removes any explicit setting, causing its inherited
value to be used.
"""
return self._pPr.algn
@alignment.setter
def alignment(self, value: PP_PARAGRAPH_ALIGNMENT | None):
self._pPr.algn = value
def clear(self):
"""Remove all content from this paragraph.
Paragraph properties are preserved. Content includes runs, line breaks, and fields.
"""
for elm in self._element.content_children:
self._element.remove(elm)
return self
@property
def font(self) -> Font:
"""|Font| object containing default character properties for the runs in this paragraph.
These character properties override default properties inherited from parent objects such
as the text frame the paragraph is contained in and they may be overridden by character
properties set at the run level.
"""
return Font(self._defRPr)
@property
def level(self) -> int:
"""Indentation level of this paragraph.
Read-write. Integer in range 0..8 inclusive. 0 represents a top-level paragraph and is the
default value. Indentation level is most commonly encountered in a bulleted list, as is
found on a word bullet slide.
"""
return self._pPr.lvl
@level.setter
def level(self, level: int):
self._pPr.lvl = level
@property
def line_spacing(self) -> int | float | Length | None:
"""The space between baselines in successive lines of this paragraph.
A value of |None| indicates no explicit value is assigned and its effective value is
inherited from the paragraph's style hierarchy. A numeric value, e.g. `2` or `1.5`,
indicates spacing is applied in multiples of line heights. A |Length| value such as
`Pt(12)` indicates spacing is a fixed height. The |Pt| value class is a convenient way to
apply line spacing in units of points.
"""
pPr = self._p.pPr
if pPr is None:
return None
return pPr.line_spacing
@line_spacing.setter
def line_spacing(self, value: int | float | Length | None):
pPr = self._p.get_or_add_pPr()
pPr.line_spacing = value
@property
def runs(self) -> tuple[_Run, ...]:
"""Sequence of runs in this paragraph."""
return tuple(_Run(r, self) for r in self._element.r_lst)
@property
def space_after(self) -> Length | None:
"""The spacing to appear between this paragraph and the subsequent paragraph.
A value of |None| indicates no explicit value is assigned and its effective value is
inherited from the paragraph's style hierarchy. |Length| objects provide convenience
properties, such as `.pt` and `.inches`, that allow easy conversion to various length
units.
"""
pPr = self._p.pPr
if pPr is None:
return None
return pPr.space_after
@space_after.setter
def space_after(self, value: Length | None):
pPr = self._p.get_or_add_pPr()
pPr.space_after = value
@property
def space_before(self) -> Length | None:
"""The spacing to appear between this paragraph and the prior paragraph.
A value of |None| indicates no explicit value is assigned and its effective value is
inherited from the paragraph's style hierarchy. |Length| objects provide convenience
properties, such as `.pt` and `.cm`, that allow easy conversion to various length units.
"""
pPr = self._p.pPr
if pPr is None:
return None
return pPr.space_before
@space_before.setter
def space_before(self, value: Length | None):
pPr = self._p.get_or_add_pPr()
pPr.space_before = value
@property
def text(self) -> str:
"""Text of paragraph as a single string.
Read/write. This value is formed by concatenating the text in each run and field making up
the paragraph, adding a vertical-tab character (`"\\v"`) for each line-break element
(`<a:br>`, soft carriage-return) encountered.
While the encoding of line-breaks as a vertical tab might be surprising at first, doing so
is consistent with PowerPoint's clipboard copy behavior and allows a line-break to be
distinguished from a paragraph boundary within the str return value.
Assignment causes all content in the paragraph to be replaced. Each vertical-tab character
(`"\\v"`) in the assigned str is translated to a line-break, as is each line-feed
character (`"\\n"`). Contrast behavior of line-feed character in `TextFrame.text` setter.
If line-feed characters are intended to produce new paragraphs, use `TextFrame.text`
instead. Any other control characters in the assigned string are escaped as a hex
representation like "_x001B_" (for ESC (ASCII 27) in this example).
"""
return "".join(elm.text for elm in self._element.content_children)
@text.setter
def text(self, text: str):
self.clear()
self._element.append_text(text)
@property
def _defRPr(self) -> CT_TextCharacterProperties:
"""The element that defines the default run properties for runs in this paragraph.
Causes the element to be added if not present.
"""
return self._pPr.get_or_add_defRPr()
@property
def _pPr(self) -> CT_TextParagraphProperties:
"""Contains the properties for this paragraph.
Causes the element to be added if not present.
"""
return self._p.get_or_add_pPr()
class _Run(Subshape):
"""Text run object. Corresponds to `a:r` child element in a paragraph."""
def __init__(self, r: CT_RegularTextRun, parent: ProvidesPart):
super(_Run, self).__init__(parent)
self._r = r
@property
def font(self):
"""|Font| instance containing run-level character properties for the text in this run.
Character properties can be and perhaps most often are inherited from parent objects such
as the paragraph and slide layout the run is contained in. Only those specifically
overridden at the run level are contained in the font object.
"""
rPr = self._r.get_or_add_rPr()
return Font(rPr)
@lazyproperty
def hyperlink(self) -> _Hyperlink:
"""Proxy for any `a:hlinkClick` element under the run properties element.
Created on demand, the hyperlink object is available whether an `a:hlinkClick` element is
present or not, and creates or deletes that element as appropriate in response to actions
on its methods and attributes.
"""
rPr = self._r.get_or_add_rPr()
return _Hyperlink(rPr, self)
@property
def text(self):
"""Read/write. A unicode string containing the text in this run.
Assignment replaces all text in the run. The assigned value can be a 7-bit ASCII
string, a UTF-8 encoded 8-bit string, or unicode. String values are converted to
unicode assuming UTF-8 encoding.
Any other control characters in the assigned string other than tab or newline
are escaped as a hex representation. For example, ESC (ASCII 27) is escaped as
"_x001B_". Contrast the behavior of `TextFrame.text` and `_Paragraph.text` with
respect to line-feed and vertical-tab characters.
"""
return self._r.text
@text.setter
def text(self, text: str):
self._r.text = text