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.
Files changed (126) hide show
  1. docx/__init__.py +68 -0
  2. docx/api.py +37 -0
  3. docx/blkcntnr.py +101 -0
  4. docx/comments.py +163 -0
  5. docx/dml/__init__.py +0 -0
  6. docx/dml/color.py +112 -0
  7. docx/document.py +275 -0
  8. docx/drawing/__init__.py +59 -0
  9. docx/enum/__init__.py +0 -0
  10. docx/enum/base.py +150 -0
  11. docx/enum/dml.py +103 -0
  12. docx/enum/section.py +86 -0
  13. docx/enum/shape.py +19 -0
  14. docx/enum/style.py +452 -0
  15. docx/enum/table.py +136 -0
  16. docx/enum/text.py +367 -0
  17. docx/exceptions.py +18 -0
  18. docx/image/__init__.py +23 -0
  19. docx/image/bmp.py +43 -0
  20. docx/image/constants.py +172 -0
  21. docx/image/exceptions.py +13 -0
  22. docx/image/gif.py +38 -0
  23. docx/image/helpers.py +86 -0
  24. docx/image/image.py +234 -0
  25. docx/image/jpeg.py +425 -0
  26. docx/image/png.py +253 -0
  27. docx/image/tiff.py +289 -0
  28. docx/opc/__init__.py +0 -0
  29. docx/opc/constants.py +306 -0
  30. docx/opc/coreprops.py +142 -0
  31. docx/opc/exceptions.py +12 -0
  32. docx/opc/oxml.py +247 -0
  33. docx/opc/package.py +219 -0
  34. docx/opc/packuri.py +109 -0
  35. docx/opc/part.py +247 -0
  36. docx/opc/parts/__init__.py +0 -0
  37. docx/opc/parts/coreprops.py +48 -0
  38. docx/opc/phys_pkg.py +119 -0
  39. docx/opc/pkgreader.py +254 -0
  40. docx/opc/pkgwriter.py +115 -0
  41. docx/opc/rel.py +153 -0
  42. docx/opc/shared.py +31 -0
  43. docx/opc/spec.py +24 -0
  44. docx/oxml/__init__.py +261 -0
  45. docx/oxml/comments.py +124 -0
  46. docx/oxml/coreprops.py +298 -0
  47. docx/oxml/document.py +88 -0
  48. docx/oxml/drawing.py +11 -0
  49. docx/oxml/exceptions.py +10 -0
  50. docx/oxml/ns.py +109 -0
  51. docx/oxml/numbering.py +109 -0
  52. docx/oxml/parser.py +62 -0
  53. docx/oxml/section.py +537 -0
  54. docx/oxml/settings.py +138 -0
  55. docx/oxml/shape.py +299 -0
  56. docx/oxml/shared.py +52 -0
  57. docx/oxml/simpletypes.py +434 -0
  58. docx/oxml/styles.py +341 -0
  59. docx/oxml/table.py +977 -0
  60. docx/oxml/text/__init__.py +0 -0
  61. docx/oxml/text/font.py +333 -0
  62. docx/oxml/text/hyperlink.py +45 -0
  63. docx/oxml/text/pagebreak.py +278 -0
  64. docx/oxml/text/paragraph.py +106 -0
  65. docx/oxml/text/parfmt.py +392 -0
  66. docx/oxml/text/run.py +307 -0
  67. docx/oxml/xmlchemy.py +696 -0
  68. docx/package.py +110 -0
  69. docx/parts/__init__.py +0 -0
  70. docx/parts/comments.py +51 -0
  71. docx/parts/document.py +182 -0
  72. docx/parts/hdrftr.py +53 -0
  73. docx/parts/image.py +80 -0
  74. docx/parts/numbering.py +32 -0
  75. docx/parts/settings.py +50 -0
  76. docx/parts/story.py +95 -0
  77. docx/parts/styles.py +42 -0
  78. docx/parts/theme.py +53 -0
  79. docx/py.typed +0 -0
  80. docx/section.py +479 -0
  81. docx/settings.py +35 -0
  82. docx/shape.py +103 -0
  83. docx/shared.py +382 -0
  84. docx/styles/__init__.py +40 -0
  85. docx/styles/latent.py +198 -0
  86. docx/styles/style.py +264 -0
  87. docx/styles/styles.py +147 -0
  88. docx/table.py +537 -0
  89. docx/templates/default-comments.xml +12 -0
  90. docx/templates/default-docx-template/[Content_Types].xml +17 -0
  91. docx/templates/default-docx-template/_rels/.rels +7 -0
  92. docx/templates/default-docx-template/customXml/_rels/item1.xml.rels +4 -0
  93. docx/templates/default-docx-template/customXml/item1.xml +2 -0
  94. docx/templates/default-docx-template/customXml/itemProps1.xml +6 -0
  95. docx/templates/default-docx-template/docProps/app.xml +36 -0
  96. docx/templates/default-docx-template/docProps/core.xml +13 -0
  97. docx/templates/default-docx-template/docProps/thumbnail.jpeg +0 -0
  98. docx/templates/default-docx-template/word/_rels/document.xml.rels +11 -0
  99. docx/templates/default-docx-template/word/document.xml +11 -0
  100. docx/templates/default-docx-template/word/fontTable.xml +61 -0
  101. docx/templates/default-docx-template/word/numbering.xml +201 -0
  102. docx/templates/default-docx-template/word/settings.xml +53 -0
  103. docx/templates/default-docx-template/word/styles.xml +11844 -0
  104. docx/templates/default-docx-template/word/stylesWithEffects.xml +11800 -0
  105. docx/templates/default-docx-template/word/theme/theme1.xml +318 -0
  106. docx/templates/default-docx-template/word/webSettings.xml +5 -0
  107. docx/templates/default-footer.xml +27 -0
  108. docx/templates/default-header.xml +27 -0
  109. docx/templates/default-settings.xml +26 -0
  110. docx/templates/default-styles.xml +190 -0
  111. docx/templates/default.docx +0 -0
  112. docx/text/__init__.py +0 -0
  113. docx/text/font.py +472 -0
  114. docx/text/hyperlink.py +121 -0
  115. docx/text/pagebreak.py +104 -0
  116. docx/text/paragraph.py +173 -0
  117. docx/text/parfmt.py +286 -0
  118. docx/text/run.py +257 -0
  119. docx/text/tabstops.py +123 -0
  120. docx/theme.py +67 -0
  121. docx/types.py +34 -0
  122. ps_python_docx-1.3.0.dist-info/METADATA +77 -0
  123. ps_python_docx-1.3.0.dist-info/RECORD +126 -0
  124. ps_python_docx-1.3.0.dist-info/WHEEL +5 -0
  125. ps_python_docx-1.3.0.dist-info/licenses/LICENSE +20 -0
  126. ps_python_docx-1.3.0.dist-info/top_level.txt +1 -0
docx/shape.py ADDED
@@ -0,0 +1,103 @@
1
+ """Objects related to shapes.
2
+
3
+ A shape is a visual object that appears on the drawing layer of a document.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from typing import TYPE_CHECKING
9
+
10
+ from docx.enum.shape import WD_INLINE_SHAPE
11
+ from docx.oxml.ns import nsmap
12
+ from docx.shared import Parented
13
+
14
+ if TYPE_CHECKING:
15
+ from docx.oxml.document import CT_Body
16
+ from docx.oxml.shape import CT_Inline
17
+ from docx.parts.story import StoryPart
18
+ from docx.shared import Length
19
+
20
+
21
+ class InlineShapes(Parented):
22
+ """Sequence of |InlineShape| instances, supporting len(), iteration, and indexed access."""
23
+
24
+ def __init__(self, body_elm: CT_Body, parent: StoryPart):
25
+ super(InlineShapes, self).__init__(parent)
26
+ self._body = body_elm
27
+
28
+ def __getitem__(self, idx: int):
29
+ """Provide indexed access, e.g. 'inline_shapes[idx]'."""
30
+ try:
31
+ inline = self._inline_lst[idx]
32
+ except IndexError:
33
+ msg = "inline shape index [%d] out of range" % idx
34
+ raise IndexError(msg)
35
+
36
+ return InlineShape(inline)
37
+
38
+ def __iter__(self):
39
+ return (InlineShape(inline) for inline in self._inline_lst)
40
+
41
+ def __len__(self):
42
+ return len(self._inline_lst)
43
+
44
+ @property
45
+ def _inline_lst(self):
46
+ body = self._body
47
+ xpath = "//w:p/w:r/w:drawing/wp:inline"
48
+ return body.xpath(xpath)
49
+
50
+
51
+ class InlineShape:
52
+ """Proxy for an ``<wp:inline>`` element, representing the container for an inline
53
+ graphical object."""
54
+
55
+ def __init__(self, inline: CT_Inline):
56
+ super(InlineShape, self).__init__()
57
+ self._inline = inline
58
+
59
+ @property
60
+ def height(self) -> Length:
61
+ """Read/write.
62
+
63
+ The display height of this inline shape as an |Emu| instance.
64
+ """
65
+ return self._inline.extent.cy
66
+
67
+ @height.setter
68
+ def height(self, cy: Length):
69
+ self._inline.extent.cy = cy
70
+ self._inline.graphic.graphicData.pic.spPr.cy = cy
71
+
72
+ @property
73
+ def type(self):
74
+ """The type of this inline shape as a member of
75
+ ``docx.enum.shape.WD_INLINE_SHAPE``, e.g. ``LINKED_PICTURE``.
76
+
77
+ Read-only.
78
+ """
79
+ graphicData = self._inline.graphic.graphicData
80
+ uri = graphicData.uri
81
+ if uri == nsmap["pic"]:
82
+ blip = graphicData.pic.blipFill.blip
83
+ if blip.link is not None:
84
+ return WD_INLINE_SHAPE.LINKED_PICTURE
85
+ return WD_INLINE_SHAPE.PICTURE
86
+ if uri == nsmap["c"]:
87
+ return WD_INLINE_SHAPE.CHART
88
+ if uri == nsmap["dgm"]:
89
+ return WD_INLINE_SHAPE.SMART_ART
90
+ return WD_INLINE_SHAPE.NOT_IMPLEMENTED
91
+
92
+ @property
93
+ def width(self):
94
+ """Read/write.
95
+
96
+ The display width of this inline shape as an |Emu| instance.
97
+ """
98
+ return self._inline.extent.cx
99
+
100
+ @width.setter
101
+ def width(self, cx: Length):
102
+ self._inline.extent.cx = cx
103
+ self._inline.graphic.graphicData.pic.spPr.cx = cx
docx/shared.py ADDED
@@ -0,0 +1,382 @@
1
+ """Objects shared by docx modules."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ from typing import (
7
+ TYPE_CHECKING,
8
+ Any,
9
+ Callable,
10
+ Generic,
11
+ Iterator,
12
+ List,
13
+ Tuple,
14
+ TypeVar,
15
+ cast,
16
+ )
17
+
18
+ if TYPE_CHECKING:
19
+ import docx.types as t
20
+ from docx.opc.part import XmlPart
21
+ from docx.oxml.xmlchemy import BaseOxmlElement
22
+ from docx.parts.story import StoryPart
23
+
24
+
25
+ class Length(int):
26
+ """Base class for length constructor classes Inches, Cm, Mm, Px, and Emu.
27
+
28
+ Behaves as an int count of English Metric Units, 914,400 to the inch, 36,000 to the
29
+ mm. Provides convenience unit conversion methods in the form of read-only
30
+ properties. Immutable.
31
+ """
32
+
33
+ _EMUS_PER_INCH = 914400
34
+ _EMUS_PER_CM = 360000
35
+ _EMUS_PER_MM = 36000
36
+ _EMUS_PER_PT = 12700
37
+ _EMUS_PER_TWIP = 635
38
+
39
+ def __new__(cls, emu: int):
40
+ return int.__new__(cls, emu)
41
+
42
+ @property
43
+ def cm(self):
44
+ """The equivalent length expressed in centimeters (float)."""
45
+ return self / float(self._EMUS_PER_CM)
46
+
47
+ @property
48
+ def emu(self):
49
+ """The equivalent length expressed in English Metric Units (int)."""
50
+ return self
51
+
52
+ @property
53
+ def inches(self):
54
+ """The equivalent length expressed in inches (float)."""
55
+ return self / float(self._EMUS_PER_INCH)
56
+
57
+ @property
58
+ def mm(self):
59
+ """The equivalent length expressed in millimeters (float)."""
60
+ return self / float(self._EMUS_PER_MM)
61
+
62
+ @property
63
+ def pt(self):
64
+ """Floating point length in points."""
65
+ return self / float(self._EMUS_PER_PT)
66
+
67
+ @property
68
+ def twips(self):
69
+ """The equivalent length expressed in twips (int)."""
70
+ return int(round(self / float(self._EMUS_PER_TWIP)))
71
+
72
+
73
+ class Inches(Length):
74
+ """Convenience constructor for length in inches, e.g. ``width = Inches(0.5)``."""
75
+
76
+ def __new__(cls, inches: float):
77
+ emu = int(inches * Length._EMUS_PER_INCH)
78
+ return Length.__new__(cls, emu)
79
+
80
+
81
+ class Cm(Length):
82
+ """Convenience constructor for length in centimeters, e.g. ``height = Cm(12)``."""
83
+
84
+ def __new__(cls, cm: float):
85
+ emu = int(cm * Length._EMUS_PER_CM)
86
+ return Length.__new__(cls, emu)
87
+
88
+
89
+ class Emu(Length):
90
+ """Convenience constructor for length in English Metric Units, e.g. ``width =
91
+ Emu(457200)``."""
92
+
93
+ def __new__(cls, emu: int):
94
+ return Length.__new__(cls, int(emu))
95
+
96
+
97
+ class Mm(Length):
98
+ """Convenience constructor for length in millimeters, e.g. ``width = Mm(240.5)``."""
99
+
100
+ def __new__(cls, mm: float):
101
+ emu = int(mm * Length._EMUS_PER_MM)
102
+ return Length.__new__(cls, emu)
103
+
104
+
105
+ class Pt(Length):
106
+ """Convenience value class for specifying a length in points."""
107
+
108
+ def __new__(cls, points: float):
109
+ emu = int(points * Length._EMUS_PER_PT)
110
+ return Length.__new__(cls, emu)
111
+
112
+
113
+ class Twips(Length):
114
+ """Convenience constructor for length in twips, e.g. ``width = Twips(42)``.
115
+
116
+ A twip is a twentieth of a point, 635 EMU.
117
+ """
118
+
119
+ def __new__(cls, twips: float):
120
+ emu = int(twips * Length._EMUS_PER_TWIP)
121
+ return Length.__new__(cls, emu)
122
+
123
+
124
+ class RGBColor(Tuple[int, int, int]):
125
+ """Immutable value object defining a particular RGB color."""
126
+
127
+ def __new__(cls, r: int, g: int, b: int):
128
+ msg = "RGBColor() takes three integer values 0-255"
129
+ for val in (r, g, b):
130
+ if not isinstance(val, int): # pyright: ignore[reportUnnecessaryIsInstance]
131
+ raise TypeError(msg)
132
+ if val < 0 or val > 255:
133
+ raise ValueError(msg)
134
+ return super(RGBColor, cls).__new__(cls, (r, g, b))
135
+
136
+ def __repr__(self):
137
+ return "RGBColor(0x%02x, 0x%02x, 0x%02x)" % self
138
+
139
+ def __str__(self):
140
+ """Return a hex string rgb value, like '3C2F80'."""
141
+ return "%02X%02X%02X" % self
142
+
143
+ @classmethod
144
+ def from_string(cls, rgb_hex_str: str) -> RGBColor:
145
+ """Return a new instance from an RGB color hex string like ``'3C2F80'``."""
146
+ r = int(rgb_hex_str[:2], 16)
147
+ g = int(rgb_hex_str[2:4], 16)
148
+ b = int(rgb_hex_str[4:], 16)
149
+ return cls(r, g, b)
150
+
151
+
152
+ T = TypeVar("T")
153
+
154
+
155
+ class lazyproperty(Generic[T]):
156
+ """Decorator like @property, but evaluated only on first access.
157
+
158
+ Like @property, this can only be used to decorate methods having only a `self`
159
+ parameter, and is accessed like an attribute on an instance, i.e. trailing
160
+ parentheses are not used. Unlike @property, the decorated method is only evaluated
161
+ on first access; the resulting value is cached and that same value returned on
162
+ second and later access without re-evaluation of the method.
163
+
164
+ Like @property, this class produces a *data descriptor* object, which is stored in
165
+ the __dict__ of the *class* under the name of the decorated method ('fget'
166
+ nominally). The cached value is stored in the __dict__ of the *instance* under that
167
+ same name.
168
+
169
+ Because it is a data descriptor (as opposed to a *non-data descriptor*), its
170
+ `__get__()` method is executed on each access of the decorated attribute; the
171
+ __dict__ item of the same name is "shadowed" by the descriptor.
172
+
173
+ While this may represent a performance improvement over a property, its greater
174
+ benefit may be its other characteristics. One common use is to construct
175
+ collaborator objects, removing that "real work" from the constructor, while still
176
+ only executing once. It also de-couples client code from any sequencing
177
+ considerations; if it's accessed from more than one location, it's assured it will
178
+ be ready whenever needed.
179
+
180
+ Loosely based on: https://stackoverflow.com/a/6849299/1902513.
181
+
182
+ A lazyproperty is read-only. There is no counterpart to the optional "setter" (or
183
+ deleter) behavior of an @property. This is critically important to maintaining its
184
+ immutability and idempotence guarantees. Attempting to assign to a lazyproperty
185
+ raises AttributeError unconditionally.
186
+
187
+ The parameter names in the methods below correspond to this usage example::
188
+
189
+ class Obj(object)
190
+
191
+ @lazyproperty
192
+ def fget(self):
193
+ return 'some result'
194
+
195
+ obj = Obj()
196
+
197
+ Not suitable for wrapping a function (as opposed to a method) because it is not
198
+ callable."""
199
+
200
+ def __init__(self, fget: Callable[..., T]) -> None:
201
+ """*fget* is the decorated method (a "getter" function).
202
+
203
+ A lazyproperty is read-only, so there is only an *fget* function (a regular
204
+ @property can also have an fset and fdel function). This name was chosen for
205
+ consistency with Python's `property` class which uses this name for the
206
+ corresponding parameter.
207
+ """
208
+ # --- maintain a reference to the wrapped getter method
209
+ self._fget = fget
210
+ # --- and store the name of that decorated method
211
+ self._name = fget.__name__
212
+ # --- adopt fget's __name__, __doc__, and other attributes
213
+ functools.update_wrapper(self, fget) # pyright: ignore
214
+
215
+ def __get__(self, obj: Any, type: Any = None) -> T:
216
+ """Called on each access of 'fget' attribute on class or instance.
217
+
218
+ *self* is this instance of a lazyproperty descriptor "wrapping" the property
219
+ method it decorates (`fget`, nominally).
220
+
221
+ *obj* is the "host" object instance when the attribute is accessed from an
222
+ object instance, e.g. `obj = Obj(); obj.fget`. *obj* is None when accessed on
223
+ the class, e.g. `Obj.fget`.
224
+
225
+ *type* is the class hosting the decorated getter method (`fget`) on both class
226
+ and instance attribute access.
227
+ """
228
+ # --- when accessed on class, e.g. Obj.fget, just return this descriptor
229
+ # --- instance (patched above to look like fget).
230
+ if obj is None:
231
+ return self # type: ignore
232
+
233
+ # --- when accessed on instance, start by checking instance __dict__ for
234
+ # --- item with key matching the wrapped function's name
235
+ value = obj.__dict__.get(self._name)
236
+ if value is None:
237
+ # --- on first access, the __dict__ item will be absent. Evaluate fget()
238
+ # --- and store that value in the (otherwise unused) host-object
239
+ # --- __dict__ value of same name ('fget' nominally)
240
+ value = self._fget(obj)
241
+ obj.__dict__[self._name] = value
242
+ return cast(T, value)
243
+
244
+ def __set__(self, obj: Any, value: Any) -> None:
245
+ """Raises unconditionally, to preserve read-only behavior.
246
+
247
+ This decorator is intended to implement immutable (and idempotent) object
248
+ attributes. For that reason, assignment to this property must be explicitly
249
+ prevented.
250
+
251
+ If this __set__ method was not present, this descriptor would become a
252
+ *non-data descriptor*. That would be nice because the cached value would be
253
+ accessed directly once set (__dict__ attrs have precedence over non-data
254
+ descriptors on instance attribute lookup). The problem is, there would be
255
+ nothing to stop assignment to the cached value, which would overwrite the result
256
+ of `fget()` and break both the immutability and idempotence guarantees of this
257
+ decorator.
258
+
259
+ The performance with this __set__() method in place was roughly 0.4 usec per
260
+ access when measured on a 2.8GHz development machine; so quite snappy and
261
+ probably not a rich target for optimization efforts.
262
+ """
263
+ raise AttributeError("can't set attribute")
264
+
265
+
266
+ def write_only_property(f: Callable[[Any, Any], None]):
267
+ """@write_only_property decorator.
268
+
269
+ Creates a property (descriptor attribute) that accepts assignment, but not getattr
270
+ (use in an expression).
271
+ """
272
+ docstring = f.__doc__
273
+
274
+ return property(fset=f, doc=docstring)
275
+
276
+
277
+ class ElementProxy:
278
+ """Base class for lxml element proxy classes.
279
+
280
+ An element proxy class is one whose primary responsibilities are fulfilled by
281
+ manipulating the attributes and child elements of an XML element. They are the most
282
+ common type of class in python-docx other than custom element (oxml) classes.
283
+ """
284
+
285
+ def __init__(self, element: BaseOxmlElement, parent: t.ProvidesXmlPart | None = None):
286
+ self._element = element
287
+ self._parent = parent
288
+
289
+ def __eq__(self, other: object):
290
+ """Return |True| if this proxy object refers to the same oxml element as does
291
+ `other`.
292
+
293
+ ElementProxy objects are value objects and should maintain no mutable local
294
+ state. Equality for proxy objects is defined as referring to the same XML
295
+ element, whether or not they are the same proxy object instance.
296
+ """
297
+ if not isinstance(other, ElementProxy):
298
+ return False
299
+ return self._element is other._element
300
+
301
+ def __ne__(self, other: object):
302
+ if not isinstance(other, ElementProxy):
303
+ return True
304
+ return self._element is not other._element
305
+
306
+ @property
307
+ def element(self):
308
+ """The lxml element proxied by this object."""
309
+ return self._element
310
+
311
+ @property
312
+ def part(self) -> XmlPart:
313
+ """The package part containing this object."""
314
+ if self._parent is None:
315
+ raise ValueError("part is not accessible from this element")
316
+ return self._parent.part
317
+
318
+
319
+ class Parented:
320
+ """Provides common services for document elements that occur below a part but may
321
+ occasionally require an ancestor object to provide a service, such as add or drop a
322
+ relationship.
323
+
324
+ Provides ``self._parent`` attribute to subclasses.
325
+ """
326
+
327
+ def __init__(self, parent: t.ProvidesXmlPart):
328
+ self._parent = parent
329
+
330
+ @property
331
+ def part(self) -> XmlPart:
332
+ """The package part containing this object."""
333
+ return self._parent.part
334
+
335
+
336
+ class StoryChild:
337
+ """A document element within a story part.
338
+
339
+ Story parts include DocumentPart and Header/FooterPart and can contain block items
340
+ (paragraphs and tables). Items from the block-item subtree occasionally require an
341
+ ancestor object to provide access to part-level or package-level items like styles
342
+ or images or to add or drop a relationship.
343
+
344
+ Provides `self._parent` attribute to subclasses.
345
+ """
346
+
347
+ def __init__(self, parent: t.ProvidesStoryPart):
348
+ self._parent = parent
349
+
350
+ @property
351
+ def part(self) -> StoryPart:
352
+ """The package part containing this object."""
353
+ return self._parent.part
354
+
355
+
356
+ class TextAccumulator:
357
+ """Accepts `str` fragments and joins them together, in order, on `.pop().
358
+
359
+ Handy when text in a stream is broken up arbitrarily and you want to join it back
360
+ together within certain bounds. The optional `separator` argument determines how
361
+ the text fragments are punctuated, defaulting to the empty string.
362
+ """
363
+
364
+ def __init__(self, separator: str = ""):
365
+ self._separator = separator
366
+ self._texts: List[str] = []
367
+
368
+ def push(self, text: str) -> None:
369
+ """Add a text fragment to the accumulator."""
370
+ self._texts.append(text)
371
+
372
+ def pop(self) -> Iterator[str]:
373
+ """Generate sero-or-one str from those accumulated.
374
+
375
+ Using `yield from accum.pop()` in a generator setting avoids producing an empty
376
+ string when no text is in the accumulator.
377
+ """
378
+ if not self._texts:
379
+ return
380
+ text = self._separator.join(self._texts)
381
+ self._texts.clear()
382
+ yield text
@@ -0,0 +1,40 @@
1
+ """Sub-package module for docx.styles sub-package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Dict
6
+
7
+
8
+ class BabelFish:
9
+ """Translates special-case style names from UI name (e.g. Heading 1) to
10
+ internal/styles.xml name (e.g. heading 1) and back."""
11
+
12
+ style_aliases = (
13
+ ("Caption", "caption"),
14
+ ("Footer", "footer"),
15
+ ("Header", "header"),
16
+ ("Heading 1", "heading 1"),
17
+ ("Heading 2", "heading 2"),
18
+ ("Heading 3", "heading 3"),
19
+ ("Heading 4", "heading 4"),
20
+ ("Heading 5", "heading 5"),
21
+ ("Heading 6", "heading 6"),
22
+ ("Heading 7", "heading 7"),
23
+ ("Heading 8", "heading 8"),
24
+ ("Heading 9", "heading 9"),
25
+ )
26
+
27
+ internal_style_names: Dict[str, str] = dict(style_aliases)
28
+ ui_style_names = {item[1]: item[0] for item in style_aliases}
29
+
30
+ @classmethod
31
+ def ui2internal(cls, ui_style_name: str) -> str:
32
+ """Return the internal style name corresponding to `ui_style_name`, such as
33
+ 'heading 1' for 'Heading 1'."""
34
+ return cls.internal_style_names.get(ui_style_name, ui_style_name)
35
+
36
+ @classmethod
37
+ def internal2ui(cls, internal_style_name: str) -> str:
38
+ """Return the user interface style name corresponding to `internal_style_name`,
39
+ such as 'Heading 1' for 'heading 1'."""
40
+ return cls.ui_style_names.get(internal_style_name, internal_style_name)