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/image/helpers.py ADDED
@@ -0,0 +1,86 @@
1
+ from struct import Struct
2
+
3
+ from .exceptions import UnexpectedEndOfFileError
4
+
5
+ BIG_ENDIAN = ">"
6
+ LITTLE_ENDIAN = "<"
7
+
8
+
9
+ class StreamReader:
10
+ """Wraps a file-like object to provide access to structured data from a binary file.
11
+
12
+ Byte-order is configurable. `base_offset` is added to any base value provided to
13
+ calculate actual location for reads.
14
+ """
15
+
16
+ def __init__(self, stream, byte_order, base_offset=0):
17
+ super(StreamReader, self).__init__()
18
+ self._stream = stream
19
+ self._byte_order = LITTLE_ENDIAN if byte_order == LITTLE_ENDIAN else BIG_ENDIAN
20
+ self._base_offset = base_offset
21
+
22
+ def read(self, count):
23
+ """Allow pass-through read() call."""
24
+ return self._stream.read(count)
25
+
26
+ def read_byte(self, base, offset=0):
27
+ """Return the int value of the byte at the file position defined by
28
+ self._base_offset + `base` + `offset`.
29
+
30
+ If `base` is None, the byte is read from the current position in the stream.
31
+ """
32
+ fmt = "B"
33
+ return self._read_int(fmt, base, offset)
34
+
35
+ def read_long(self, base, offset=0):
36
+ """Return the int value of the four bytes at the file position defined by
37
+ self._base_offset + `base` + `offset`.
38
+
39
+ If `base` is None, the long is read from the current position in the stream. The
40
+ endian setting of this instance is used to interpret the byte layout of the
41
+ long.
42
+ """
43
+ fmt = "<L" if self._byte_order is LITTLE_ENDIAN else ">L"
44
+ return self._read_int(fmt, base, offset)
45
+
46
+ def read_short(self, base, offset=0):
47
+ """Return the int value of the two bytes at the file position determined by
48
+ `base` and `offset`, similarly to ``read_long()`` above."""
49
+ fmt = b"<H" if self._byte_order is LITTLE_ENDIAN else b">H"
50
+ return self._read_int(fmt, base, offset)
51
+
52
+ def read_str(self, char_count, base, offset=0):
53
+ """Return a string containing the `char_count` bytes at the file position
54
+ determined by self._base_offset + `base` + `offset`."""
55
+
56
+ def str_struct(char_count):
57
+ format_ = "%ds" % char_count
58
+ return Struct(format_)
59
+
60
+ struct = str_struct(char_count)
61
+ chars = self._unpack_item(struct, base, offset)
62
+ unicode_str = chars.decode("UTF-8")
63
+ return unicode_str
64
+
65
+ def seek(self, base, offset=0):
66
+ location = self._base_offset + base + offset
67
+ self._stream.seek(location)
68
+
69
+ def tell(self):
70
+ """Allow pass-through tell() call."""
71
+ return self._stream.tell()
72
+
73
+ def _read_bytes(self, byte_count, base, offset):
74
+ self.seek(base, offset)
75
+ bytes_ = self._stream.read(byte_count)
76
+ if len(bytes_) < byte_count:
77
+ raise UnexpectedEndOfFileError
78
+ return bytes_
79
+
80
+ def _read_int(self, fmt, base, offset):
81
+ struct = Struct(fmt)
82
+ return self._unpack_item(struct, base, offset)
83
+
84
+ def _unpack_item(self, struct, base, offset):
85
+ bytes_ = self._read_bytes(struct.size, base, offset)
86
+ return struct.unpack(bytes_)[0]
docx/image/image.py ADDED
@@ -0,0 +1,234 @@
1
+ """Provides objects that can characterize image streams.
2
+
3
+ That characterization is as to content type and size, as a required step in including
4
+ them in a document.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import hashlib
10
+ import io
11
+ import os
12
+ from typing import IO, Tuple
13
+
14
+ from docx.image.exceptions import UnrecognizedImageError
15
+ from docx.shared import Emu, Inches, Length, lazyproperty
16
+
17
+
18
+ class Image:
19
+ """Graphical image stream such as JPEG, PNG, or GIF with properties and methods
20
+ required by ImagePart."""
21
+
22
+ def __init__(self, blob: bytes, filename: str, image_header: BaseImageHeader):
23
+ super(Image, self).__init__()
24
+ self._blob = blob
25
+ self._filename = filename
26
+ self._image_header = image_header
27
+
28
+ @classmethod
29
+ def from_blob(cls, blob: bytes) -> Image:
30
+ """Return a new |Image| subclass instance parsed from the image binary contained
31
+ in `blob`."""
32
+ stream = io.BytesIO(blob)
33
+ return cls._from_stream(stream, blob)
34
+
35
+ @classmethod
36
+ def from_file(cls, image_descriptor: str | IO[bytes]):
37
+ """Return a new |Image| subclass instance loaded from the image file identified
38
+ by `image_descriptor`, a path or file-like object."""
39
+ if isinstance(image_descriptor, str):
40
+ path = image_descriptor
41
+ with open(path, "rb") as f:
42
+ blob = f.read()
43
+ stream = io.BytesIO(blob)
44
+ filename = os.path.basename(path)
45
+ else:
46
+ stream = image_descriptor
47
+ stream.seek(0)
48
+ blob = stream.read()
49
+ filename = None
50
+ return cls._from_stream(stream, blob, filename)
51
+
52
+ @property
53
+ def blob(self):
54
+ """The bytes of the image 'file'."""
55
+ return self._blob
56
+
57
+ @property
58
+ def content_type(self) -> str:
59
+ """MIME content type for this image, e.g. ``'image/jpeg'`` for a JPEG image."""
60
+ return self._image_header.content_type
61
+
62
+ @lazyproperty
63
+ def ext(self):
64
+ """The file extension for the image.
65
+
66
+ If an actual one is available from a load filename it is used. Otherwise a
67
+ canonical extension is assigned based on the content type. Does not contain the
68
+ leading period, e.g. 'jpg', not '.jpg'.
69
+ """
70
+ return os.path.splitext(self._filename)[1][1:]
71
+
72
+ @property
73
+ def filename(self):
74
+ """Original image file name, if loaded from disk, or a generic filename if
75
+ loaded from an anonymous stream."""
76
+ return self._filename
77
+
78
+ @property
79
+ def px_width(self) -> int:
80
+ """The horizontal pixel dimension of the image."""
81
+ return self._image_header.px_width
82
+
83
+ @property
84
+ def px_height(self) -> int:
85
+ """The vertical pixel dimension of the image."""
86
+ return self._image_header.px_height
87
+
88
+ @property
89
+ def horz_dpi(self) -> int:
90
+ """Integer dots per inch for the width of this image.
91
+
92
+ Defaults to 72 when not present in the file, as is often the case.
93
+ """
94
+ return self._image_header.horz_dpi
95
+
96
+ @property
97
+ def vert_dpi(self) -> int:
98
+ """Integer dots per inch for the height of this image.
99
+
100
+ Defaults to 72 when not present in the file, as is often the case.
101
+ """
102
+ return self._image_header.vert_dpi
103
+
104
+ @property
105
+ def width(self) -> Inches:
106
+ """A |Length| value representing the native width of the image, calculated from
107
+ the values of `px_width` and `horz_dpi`."""
108
+ return Inches(self.px_width / self.horz_dpi)
109
+
110
+ @property
111
+ def height(self) -> Inches:
112
+ """A |Length| value representing the native height of the image, calculated from
113
+ the values of `px_height` and `vert_dpi`."""
114
+ return Inches(self.px_height / self.vert_dpi)
115
+
116
+ def scaled_dimensions(
117
+ self, width: int | Length | None = None, height: int | Length | None = None
118
+ ) -> Tuple[Length, Length]:
119
+ """(cx, cy) pair representing scaled dimensions of this image.
120
+
121
+ The native dimensions of the image are scaled by applying the following rules to
122
+ the `width` and `height` arguments.
123
+
124
+ * If both `width` and `height` are specified, the return value is (`width`,
125
+ `height`); no scaling is performed.
126
+ * If only one is specified, it is used to compute a scaling factor that is then
127
+ applied to the unspecified dimension, preserving the aspect ratio of the image.
128
+ * If both `width` and `height` are |None|, the native dimensions are returned.
129
+
130
+ The native dimensions are calculated using the dots-per-inch (dpi) value
131
+ embedded in the image, defaulting to 72 dpi if no value is specified, as is
132
+ often the case. The returned values are both |Length| objects.
133
+ """
134
+ if width is None and height is None:
135
+ return self.width, self.height
136
+
137
+ if width is None:
138
+ assert height is not None
139
+ scaling_factor = float(height) / float(self.height)
140
+ width = round(self.width * scaling_factor)
141
+
142
+ if height is None:
143
+ scaling_factor = float(width) / float(self.width)
144
+ height = round(self.height * scaling_factor)
145
+
146
+ return Emu(width), Emu(height)
147
+
148
+ @lazyproperty
149
+ def sha1(self):
150
+ """SHA1 hash digest of the image blob."""
151
+ return hashlib.sha1(self._blob).hexdigest()
152
+
153
+ @classmethod
154
+ def _from_stream(
155
+ cls,
156
+ stream: IO[bytes],
157
+ blob: bytes,
158
+ filename: str | None = None,
159
+ ) -> Image:
160
+ """Return an instance of the |Image| subclass corresponding to the format of the
161
+ image in `stream`."""
162
+ image_header = _ImageHeaderFactory(stream)
163
+ if filename is None:
164
+ filename = "image.%s" % image_header.default_ext
165
+ return cls(blob, filename, image_header)
166
+
167
+
168
+ def _ImageHeaderFactory(stream: IO[bytes]):
169
+ """A |BaseImageHeader| subclass instance that can parse headers of image in `stream`."""
170
+ from docx.image import SIGNATURES
171
+
172
+ def read_32(stream: IO[bytes]):
173
+ stream.seek(0)
174
+ return stream.read(32)
175
+
176
+ header = read_32(stream)
177
+ for cls, offset, signature_bytes in SIGNATURES:
178
+ end = offset + len(signature_bytes)
179
+ found_bytes = header[offset:end]
180
+ if found_bytes == signature_bytes:
181
+ return cls.from_stream(stream)
182
+ raise UnrecognizedImageError
183
+
184
+
185
+ class BaseImageHeader:
186
+ """Base class for image header subclasses like |Jpeg| and |Tiff|."""
187
+
188
+ def __init__(self, px_width: int, px_height: int, horz_dpi: int, vert_dpi: int):
189
+ self._px_width = px_width
190
+ self._px_height = px_height
191
+ self._horz_dpi = horz_dpi
192
+ self._vert_dpi = vert_dpi
193
+
194
+ @property
195
+ def content_type(self) -> str:
196
+ """Abstract property definition, must be implemented by all subclasses."""
197
+ msg = "content_type property must be implemented by all subclasses of BaseImageHeader"
198
+ raise NotImplementedError(msg)
199
+
200
+ @property
201
+ def default_ext(self) -> str:
202
+ """Default filename extension for images of this type.
203
+
204
+ An abstract property definition, must be implemented by all subclasses.
205
+ """
206
+ raise NotImplementedError(
207
+ "default_ext property must be implemented by all subclasses of BaseImageHeader"
208
+ )
209
+
210
+ @property
211
+ def px_width(self):
212
+ """The horizontal pixel dimension of the image."""
213
+ return self._px_width
214
+
215
+ @property
216
+ def px_height(self):
217
+ """The vertical pixel dimension of the image."""
218
+ return self._px_height
219
+
220
+ @property
221
+ def horz_dpi(self):
222
+ """Integer dots per inch for the width of this image.
223
+
224
+ Defaults to 72 when not present in the file, as is often the case.
225
+ """
226
+ return self._horz_dpi
227
+
228
+ @property
229
+ def vert_dpi(self):
230
+ """Integer dots per inch for the height of this image.
231
+
232
+ Defaults to 72 when not present in the file, as is often the case.
233
+ """
234
+ return self._vert_dpi