wordhelpers 0.1.2__tar.gz → 0.1.4__tar.gz
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.
- wordhelpers-0.1.4/PKG-INFO +268 -0
- wordhelpers-0.1.4/README.md +252 -0
- {wordhelpers-0.1.2 → wordhelpers-0.1.4}/pyproject.toml +1 -1
- {wordhelpers-0.1.2 → wordhelpers-0.1.4}/wordhelpers/__init__.py +39 -0
- wordhelpers-0.1.4/wordhelpers/pydantic_models.py +321 -0
- wordhelpers-0.1.2/PKG-INFO +0 -217
- wordhelpers-0.1.2/README.md +0 -202
- wordhelpers-0.1.2/wordhelpers/pydantic_models.py +0 -57
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wordhelpers
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Helpers for working with python-docx
|
|
5
|
+
Author: AJ Cruz
|
|
6
|
+
Author-email: 15045766-a-cruz@users.noreply.gitlab.com
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
|
|
14
|
+
Requires-Dist: python-docx (>=1.2.0,<2.0.0)
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
[](https://img.shields.io/pypi/pyversions/wordhelpers)
|
|
18
|
+
[](https://pypi.python.org/pypi/wordhelpers)
|
|
19
|
+
[](https://github.com/ambv/black)
|
|
20
|
+
|
|
21
|
+
# wordhelpers
|
|
22
|
+
Helper functions for [python-docx](https://python-docx.readthedocs.io/en/latest/). I found myself re-learning docx every time I wanted to use it in a project, so this provides and abstraction. You represent Word tables as a properly-formatted Python dictionary or with the provided WordTableModel class and the helper function converts it to a docx table.
|
|
23
|
+
|
|
24
|
+
# Installation
|
|
25
|
+
wordhelpers can be installed via poetry with: ```poetry add wordhelpers```
|
|
26
|
+
or via pip with: ```pip install wordhelpers```
|
|
27
|
+
|
|
28
|
+
# Usage
|
|
29
|
+
For detailed documentation of the python-docx library see [python-docx](https://python-docx.readthedocs.io/en/latest/)
|
|
30
|
+
|
|
31
|
+
1. Import the python-docx library into your script with:
|
|
32
|
+
```python
|
|
33
|
+
from docx import Document
|
|
34
|
+
```
|
|
35
|
+
1. Import the helpers from this project with:
|
|
36
|
+
```python
|
|
37
|
+
from wordhelpers import WordTableModel, inject_table
|
|
38
|
+
```
|
|
39
|
+
1. Create the docx Word document object with something like:
|
|
40
|
+
```python
|
|
41
|
+
doc_obj = Document("a_word_template.docx")
|
|
42
|
+
```
|
|
43
|
+
1. Add tables to the document object as required (see the next section of this README for info on how to do that)
|
|
44
|
+
1. When all changes to your document object are complete, write them with the docx `save()` method:
|
|
45
|
+
```python
|
|
46
|
+
doc_obj.save("output_file.docx")
|
|
47
|
+
```
|
|
48
|
+
# Adding tables to the document object
|
|
49
|
+
There are two methods available for creating tables for addition to a word document:
|
|
50
|
+
1. The provided `WordTablesModel` class
|
|
51
|
+
1. A properly-formatted python dictionary
|
|
52
|
+
|
|
53
|
+
The WordTablesModel class has a number of methods available to help you build the table:
|
|
54
|
+
- ```add_row(width: int, text: list[str] = [], merge_cols: list[int] = [], background_color: str | None = None, style: str | None = None, alignment: AlignmentEnum | None = None)```
|
|
55
|
+
- ```add_text_to_row(row_index: int, text: list[str], style: str | None = None, alignment: AlignmentEnum | None = None)```
|
|
56
|
+
- ```add_text_to_cell(row_index: int, col_index: int, text: str, style: str | None = None, alignment: AlignmentEnum | None = None)```
|
|
57
|
+
- ```style_row(row_index: int, text_style: str)```
|
|
58
|
+
- ```style_cell(row_index: int, col_index: int, text_style: str)```
|
|
59
|
+
- ```color_row(row_index: int, background_color: str)```
|
|
60
|
+
- ```color_cell(row_index: int, col_index: int, background_color: str)```
|
|
61
|
+
- ```align_row(row_index: int, alignment: AlignmentEnum)```
|
|
62
|
+
- ```align_cell(row_index: int, col_index: int, alignment: AlignmentEnum)```
|
|
63
|
+
- ```add_table_to_cell(row_index: int, col_index: int, table: WordTableModel)```
|
|
64
|
+
- ```delete_row(row_index: int)```
|
|
65
|
+
- ```model_dump()```
|
|
66
|
+
- ```pretty_print()```
|
|
67
|
+
- ```write()```
|
|
68
|
+
|
|
69
|
+
If you prefer to create the tables manually via Python dictionary, the dictionary must follow a strict schema that looks something like this:
|
|
70
|
+
```python
|
|
71
|
+
{
|
|
72
|
+
"style": None,
|
|
73
|
+
"rows": [
|
|
74
|
+
{
|
|
75
|
+
"cells": [
|
|
76
|
+
{
|
|
77
|
+
"width": None,
|
|
78
|
+
"background": None,
|
|
79
|
+
"paragraphs": [{"style":None,"alignment": "center", "text":"Some Text"}],
|
|
80
|
+
"table": {optional child table}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"merge": None
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
The cell **background** attribute is optional. If supplied with a hexidecimal color code, the cell will be shaded that color.
|
|
91
|
+
|
|
92
|
+
The cell **width** attribute is optional. If supplied with a decimal number (inches), it will hard-code that column's width to the supplied value.
|
|
93
|
+
|
|
94
|
+
The cell **table** attribute is optional. It can be used to nest tables within table cells. If "table" is provided, no other keys are required (background, paragraphs, etc).
|
|
95
|
+
|
|
96
|
+
The paragraph **style** attribute is optional. If set to anything besides None it will use the Word style referenced. The style must already exist in the source/template Word document.
|
|
97
|
+
|
|
98
|
+
The paragraph **alignment** attribute is optional. If set to ```"center"``` it will center-align the text within a cell, if set to ```"right"``` it will right-align the text within a cell
|
|
99
|
+
|
|
100
|
+
The **merge** key is optional. If used the cell will be merged with the cell above (from a dictionary view, to the left from a table view). Multiple merges can be used in a row to merge multiple cells.
|
|
101
|
+
|
|
102
|
+
By default a paragraph's **text** property will create a single-line (but wrapped) entry in the cell if the value is a string. If you would like to create a multi-line cell entry, supply the value as a list instead of a string. This will instruct the module to add a line break after each list item.
|
|
103
|
+
|
|
104
|
+
Schema enforcement of the dictionary is done through Pydantic v2 validations.
|
|
105
|
+
|
|
106
|
+
Injection of the table model (either via the class or a raw dictionary) is done via the provided ```inject_table()``` function.
|
|
107
|
+
The function has the following parameters:
|
|
108
|
+
- doc_obj: _Document
|
|
109
|
+
- table: dict
|
|
110
|
+
- placeholder: str
|
|
111
|
+
- remove_leading_para: bool = True
|
|
112
|
+
- remove_placeholder: bool = True
|
|
113
|
+
|
|
114
|
+
Notice the table parameter must be a python dictionary. So if you've created the table via the provided ```WordTableModel``` class you pass it to ```inject_table()``` with: ```my_table.model_dump()```
|
|
115
|
+
|
|
116
|
+
- **<remove_leading_para>** - This is an optional argument. If not set it will default to True. MS Word tables when created automatically have an empty paragraph at the top/beginning of the table cell. This can create unwanted spacing at the top of the table. By default (value set to "True") the paragraph will be deleted. If you want to keep the paragraph (to add text to it), set this to "False".
|
|
117
|
+
- **<remove_placeholder>** - This is an optional argument. You can leave the placeholder (```remove_placeholder=False```) if you need to keep injecting tables below the placeholder before final deletion
|
|
118
|
+
|
|
119
|
+
### EXAMPLE
|
|
120
|
+
We start with a Microsoft Word template named "source-template.docx" that looks like this:
|
|
121
|
+
|
|
122
|
+

|
|
123
|
+
|
|
124
|
+
Our sample Python script looks like this:
|
|
125
|
+
```python
|
|
126
|
+
from docx import Document
|
|
127
|
+
from wordhelpers import inject_table
|
|
128
|
+
|
|
129
|
+
doc_obj = Document("source-template.docx")
|
|
130
|
+
|
|
131
|
+
my_dictionary = {
|
|
132
|
+
"style": "plain",
|
|
133
|
+
"rows": [
|
|
134
|
+
{
|
|
135
|
+
"cells": [
|
|
136
|
+
{
|
|
137
|
+
"background": "#506279",
|
|
138
|
+
"paragraphs":[{"style": "regularbold", "text": "Header 1:"}]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"background": "#506279",
|
|
142
|
+
"paragraphs":[{"style": "regularbold", "text": "Header 2:"}]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"background": "#506279",
|
|
146
|
+
"paragraphs":[{"style": "regularbold", "text": "Header 3:"}]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"cells": [
|
|
152
|
+
{
|
|
153
|
+
"background": "#D5DCE4",
|
|
154
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 1 Data 1:"}]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"background": "#D5DCE4",
|
|
158
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 1 Data 2:"}]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"background": "#D5DCE4",
|
|
162
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 1 Data 3:"}]
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"cells": [
|
|
168
|
+
{
|
|
169
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 2 Data 1:"}]
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 2 Data 2:"}]
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 2 Data 3:"}]
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"cells": [
|
|
181
|
+
{
|
|
182
|
+
"background": "#D5DCE4",
|
|
183
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 3 Data 1:"}]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"background": "#D5DCE4",
|
|
187
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 3 Data 2:"}]
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"background": "#D5DCE4",
|
|
191
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 3 Data 3:"}]
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
inject_table(doc_obj, my_dictionary, "\[py_placeholder1\]")
|
|
199
|
+
doc_obj.save("output_word_doc.docx")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Using the provided ```WordTableModel``` class instead of the raw dictionary, the python code would look like this:
|
|
203
|
+
```python
|
|
204
|
+
from docx import Document
|
|
205
|
+
from wordhelpers import WordTableModel, inject_table
|
|
206
|
+
|
|
207
|
+
doc_obj = Document("source-template.docx")
|
|
208
|
+
|
|
209
|
+
my_table = WordTableModel()
|
|
210
|
+
my_table.style = "plain"
|
|
211
|
+
my_table.add_row(
|
|
212
|
+
3,
|
|
213
|
+
text=[
|
|
214
|
+
"Header 1:",
|
|
215
|
+
"Header 2:",
|
|
216
|
+
"Header 3:",
|
|
217
|
+
],
|
|
218
|
+
background_color="#506279",
|
|
219
|
+
style="regularbold",
|
|
220
|
+
)
|
|
221
|
+
my_table.add_row(
|
|
222
|
+
3,
|
|
223
|
+
text=[
|
|
224
|
+
"Row 1 Data 1:",
|
|
225
|
+
"Row 1 Data 2:",
|
|
226
|
+
"Row 1 Data 3:",
|
|
227
|
+
],
|
|
228
|
+
background_color="#D5DCE4",
|
|
229
|
+
style="No Spacing",
|
|
230
|
+
)
|
|
231
|
+
my_table.add_row(
|
|
232
|
+
3,
|
|
233
|
+
text=[
|
|
234
|
+
"Row 2 Data 1:",
|
|
235
|
+
"Row 2 Data 2:",
|
|
236
|
+
"Row 2 Data 3:",
|
|
237
|
+
],
|
|
238
|
+
style="No Spacing",
|
|
239
|
+
)
|
|
240
|
+
my_table.add_row(
|
|
241
|
+
3,
|
|
242
|
+
text=[
|
|
243
|
+
"Row 3 Data 1:",
|
|
244
|
+
"Row 3 Data 2:",
|
|
245
|
+
"Row 3 Data 3:",
|
|
246
|
+
],
|
|
247
|
+
background_color="#D5DCE4",
|
|
248
|
+
style="No Spacing",
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
inject_table(doc_obj, my_table.model_dump(), "\[py_placeholder1\]")
|
|
252
|
+
doc_obj.save("output_word_doc.docx")
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
We run the Python script and it produces a new Word document named "output_word_doc.docx" that looks like this:
|
|
256
|
+
|
|
257
|
+

|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
The project provides some additional docx functions that may be useful to your project:
|
|
261
|
+
- ```get_para_by_string(doc_obj: _Document, search: str)```: Searches for a keyword in the docx object and returns there paragraph where the keyword is found
|
|
262
|
+
- ```insert_paragraph_after(paragraph: Paragraph, text: str = None, style: str = None)```: Searches for a keyword in the docx object and inserts a new paragraph immediately after it with the supplied text
|
|
263
|
+
- ```delete_paragraph(paragraph: Paragraph)```: Deletes a given paragraph (after you've inserted text after it for example)
|
|
264
|
+
|
|
265
|
+
As well as the following helper functions for building raw dictionary table models:
|
|
266
|
+
- ```insert_text_into_row(cell_text: list)```: Builds a row (dictionary) from a list of text where each list item is a column in the row. Supports "merge"
|
|
267
|
+
- ```insert_text_by_table_coords(table: dict, row: int, col: int, text: str)```: Inserts text into a table dictionary given the row & column numbers.
|
|
268
|
+
- ```generate_table(num_rows: int, num_cols: int, header_row: list, style: str = None)```: Generates a basic table dictionary and populates the headers from a list of text (strings).
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
[](https://img.shields.io/pypi/pyversions/wordhelpers)
|
|
2
|
+
[](https://pypi.python.org/pypi/wordhelpers)
|
|
3
|
+
[](https://github.com/ambv/black)
|
|
4
|
+
|
|
5
|
+
# wordhelpers
|
|
6
|
+
Helper functions for [python-docx](https://python-docx.readthedocs.io/en/latest/). I found myself re-learning docx every time I wanted to use it in a project, so this provides and abstraction. You represent Word tables as a properly-formatted Python dictionary or with the provided WordTableModel class and the helper function converts it to a docx table.
|
|
7
|
+
|
|
8
|
+
# Installation
|
|
9
|
+
wordhelpers can be installed via poetry with: ```poetry add wordhelpers```
|
|
10
|
+
or via pip with: ```pip install wordhelpers```
|
|
11
|
+
|
|
12
|
+
# Usage
|
|
13
|
+
For detailed documentation of the python-docx library see [python-docx](https://python-docx.readthedocs.io/en/latest/)
|
|
14
|
+
|
|
15
|
+
1. Import the python-docx library into your script with:
|
|
16
|
+
```python
|
|
17
|
+
from docx import Document
|
|
18
|
+
```
|
|
19
|
+
1. Import the helpers from this project with:
|
|
20
|
+
```python
|
|
21
|
+
from wordhelpers import WordTableModel, inject_table
|
|
22
|
+
```
|
|
23
|
+
1. Create the docx Word document object with something like:
|
|
24
|
+
```python
|
|
25
|
+
doc_obj = Document("a_word_template.docx")
|
|
26
|
+
```
|
|
27
|
+
1. Add tables to the document object as required (see the next section of this README for info on how to do that)
|
|
28
|
+
1. When all changes to your document object are complete, write them with the docx `save()` method:
|
|
29
|
+
```python
|
|
30
|
+
doc_obj.save("output_file.docx")
|
|
31
|
+
```
|
|
32
|
+
# Adding tables to the document object
|
|
33
|
+
There are two methods available for creating tables for addition to a word document:
|
|
34
|
+
1. The provided `WordTablesModel` class
|
|
35
|
+
1. A properly-formatted python dictionary
|
|
36
|
+
|
|
37
|
+
The WordTablesModel class has a number of methods available to help you build the table:
|
|
38
|
+
- ```add_row(width: int, text: list[str] = [], merge_cols: list[int] = [], background_color: str | None = None, style: str | None = None, alignment: AlignmentEnum | None = None)```
|
|
39
|
+
- ```add_text_to_row(row_index: int, text: list[str], style: str | None = None, alignment: AlignmentEnum | None = None)```
|
|
40
|
+
- ```add_text_to_cell(row_index: int, col_index: int, text: str, style: str | None = None, alignment: AlignmentEnum | None = None)```
|
|
41
|
+
- ```style_row(row_index: int, text_style: str)```
|
|
42
|
+
- ```style_cell(row_index: int, col_index: int, text_style: str)```
|
|
43
|
+
- ```color_row(row_index: int, background_color: str)```
|
|
44
|
+
- ```color_cell(row_index: int, col_index: int, background_color: str)```
|
|
45
|
+
- ```align_row(row_index: int, alignment: AlignmentEnum)```
|
|
46
|
+
- ```align_cell(row_index: int, col_index: int, alignment: AlignmentEnum)```
|
|
47
|
+
- ```add_table_to_cell(row_index: int, col_index: int, table: WordTableModel)```
|
|
48
|
+
- ```delete_row(row_index: int)```
|
|
49
|
+
- ```model_dump()```
|
|
50
|
+
- ```pretty_print()```
|
|
51
|
+
- ```write()```
|
|
52
|
+
|
|
53
|
+
If you prefer to create the tables manually via Python dictionary, the dictionary must follow a strict schema that looks something like this:
|
|
54
|
+
```python
|
|
55
|
+
{
|
|
56
|
+
"style": None,
|
|
57
|
+
"rows": [
|
|
58
|
+
{
|
|
59
|
+
"cells": [
|
|
60
|
+
{
|
|
61
|
+
"width": None,
|
|
62
|
+
"background": None,
|
|
63
|
+
"paragraphs": [{"style":None,"alignment": "center", "text":"Some Text"}],
|
|
64
|
+
"table": {optional child table}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"merge": None
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
The cell **background** attribute is optional. If supplied with a hexidecimal color code, the cell will be shaded that color.
|
|
75
|
+
|
|
76
|
+
The cell **width** attribute is optional. If supplied with a decimal number (inches), it will hard-code that column's width to the supplied value.
|
|
77
|
+
|
|
78
|
+
The cell **table** attribute is optional. It can be used to nest tables within table cells. If "table" is provided, no other keys are required (background, paragraphs, etc).
|
|
79
|
+
|
|
80
|
+
The paragraph **style** attribute is optional. If set to anything besides None it will use the Word style referenced. The style must already exist in the source/template Word document.
|
|
81
|
+
|
|
82
|
+
The paragraph **alignment** attribute is optional. If set to ```"center"``` it will center-align the text within a cell, if set to ```"right"``` it will right-align the text within a cell
|
|
83
|
+
|
|
84
|
+
The **merge** key is optional. If used the cell will be merged with the cell above (from a dictionary view, to the left from a table view). Multiple merges can be used in a row to merge multiple cells.
|
|
85
|
+
|
|
86
|
+
By default a paragraph's **text** property will create a single-line (but wrapped) entry in the cell if the value is a string. If you would like to create a multi-line cell entry, supply the value as a list instead of a string. This will instruct the module to add a line break after each list item.
|
|
87
|
+
|
|
88
|
+
Schema enforcement of the dictionary is done through Pydantic v2 validations.
|
|
89
|
+
|
|
90
|
+
Injection of the table model (either via the class or a raw dictionary) is done via the provided ```inject_table()``` function.
|
|
91
|
+
The function has the following parameters:
|
|
92
|
+
- doc_obj: _Document
|
|
93
|
+
- table: dict
|
|
94
|
+
- placeholder: str
|
|
95
|
+
- remove_leading_para: bool = True
|
|
96
|
+
- remove_placeholder: bool = True
|
|
97
|
+
|
|
98
|
+
Notice the table parameter must be a python dictionary. So if you've created the table via the provided ```WordTableModel``` class you pass it to ```inject_table()``` with: ```my_table.model_dump()```
|
|
99
|
+
|
|
100
|
+
- **<remove_leading_para>** - This is an optional argument. If not set it will default to True. MS Word tables when created automatically have an empty paragraph at the top/beginning of the table cell. This can create unwanted spacing at the top of the table. By default (value set to "True") the paragraph will be deleted. If you want to keep the paragraph (to add text to it), set this to "False".
|
|
101
|
+
- **<remove_placeholder>** - This is an optional argument. You can leave the placeholder (```remove_placeholder=False```) if you need to keep injecting tables below the placeholder before final deletion
|
|
102
|
+
|
|
103
|
+
### EXAMPLE
|
|
104
|
+
We start with a Microsoft Word template named "source-template.docx" that looks like this:
|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+
Our sample Python script looks like this:
|
|
109
|
+
```python
|
|
110
|
+
from docx import Document
|
|
111
|
+
from wordhelpers import inject_table
|
|
112
|
+
|
|
113
|
+
doc_obj = Document("source-template.docx")
|
|
114
|
+
|
|
115
|
+
my_dictionary = {
|
|
116
|
+
"style": "plain",
|
|
117
|
+
"rows": [
|
|
118
|
+
{
|
|
119
|
+
"cells": [
|
|
120
|
+
{
|
|
121
|
+
"background": "#506279",
|
|
122
|
+
"paragraphs":[{"style": "regularbold", "text": "Header 1:"}]
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"background": "#506279",
|
|
126
|
+
"paragraphs":[{"style": "regularbold", "text": "Header 2:"}]
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"background": "#506279",
|
|
130
|
+
"paragraphs":[{"style": "regularbold", "text": "Header 3:"}]
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"cells": [
|
|
136
|
+
{
|
|
137
|
+
"background": "#D5DCE4",
|
|
138
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 1 Data 1:"}]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"background": "#D5DCE4",
|
|
142
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 1 Data 2:"}]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"background": "#D5DCE4",
|
|
146
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 1 Data 3:"}]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"cells": [
|
|
152
|
+
{
|
|
153
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 2 Data 1:"}]
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 2 Data 2:"}]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 2 Data 3:"}]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"cells": [
|
|
165
|
+
{
|
|
166
|
+
"background": "#D5DCE4",
|
|
167
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 3 Data 1:"}]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"background": "#D5DCE4",
|
|
171
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 3 Data 2:"}]
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"background": "#D5DCE4",
|
|
175
|
+
"paragraphs":[{"style": "No Spacing", "text": "Row 3 Data 3:"}]
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
inject_table(doc_obj, my_dictionary, "\[py_placeholder1\]")
|
|
183
|
+
doc_obj.save("output_word_doc.docx")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Using the provided ```WordTableModel``` class instead of the raw dictionary, the python code would look like this:
|
|
187
|
+
```python
|
|
188
|
+
from docx import Document
|
|
189
|
+
from wordhelpers import WordTableModel, inject_table
|
|
190
|
+
|
|
191
|
+
doc_obj = Document("source-template.docx")
|
|
192
|
+
|
|
193
|
+
my_table = WordTableModel()
|
|
194
|
+
my_table.style = "plain"
|
|
195
|
+
my_table.add_row(
|
|
196
|
+
3,
|
|
197
|
+
text=[
|
|
198
|
+
"Header 1:",
|
|
199
|
+
"Header 2:",
|
|
200
|
+
"Header 3:",
|
|
201
|
+
],
|
|
202
|
+
background_color="#506279",
|
|
203
|
+
style="regularbold",
|
|
204
|
+
)
|
|
205
|
+
my_table.add_row(
|
|
206
|
+
3,
|
|
207
|
+
text=[
|
|
208
|
+
"Row 1 Data 1:",
|
|
209
|
+
"Row 1 Data 2:",
|
|
210
|
+
"Row 1 Data 3:",
|
|
211
|
+
],
|
|
212
|
+
background_color="#D5DCE4",
|
|
213
|
+
style="No Spacing",
|
|
214
|
+
)
|
|
215
|
+
my_table.add_row(
|
|
216
|
+
3,
|
|
217
|
+
text=[
|
|
218
|
+
"Row 2 Data 1:",
|
|
219
|
+
"Row 2 Data 2:",
|
|
220
|
+
"Row 2 Data 3:",
|
|
221
|
+
],
|
|
222
|
+
style="No Spacing",
|
|
223
|
+
)
|
|
224
|
+
my_table.add_row(
|
|
225
|
+
3,
|
|
226
|
+
text=[
|
|
227
|
+
"Row 3 Data 1:",
|
|
228
|
+
"Row 3 Data 2:",
|
|
229
|
+
"Row 3 Data 3:",
|
|
230
|
+
],
|
|
231
|
+
background_color="#D5DCE4",
|
|
232
|
+
style="No Spacing",
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
inject_table(doc_obj, my_table.model_dump(), "\[py_placeholder1\]")
|
|
236
|
+
doc_obj.save("output_word_doc.docx")
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
We run the Python script and it produces a new Word document named "output_word_doc.docx" that looks like this:
|
|
240
|
+
|
|
241
|
+

|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
The project provides some additional docx functions that may be useful to your project:
|
|
245
|
+
- ```get_para_by_string(doc_obj: _Document, search: str)```: Searches for a keyword in the docx object and returns there paragraph where the keyword is found
|
|
246
|
+
- ```insert_paragraph_after(paragraph: Paragraph, text: str = None, style: str = None)```: Searches for a keyword in the docx object and inserts a new paragraph immediately after it with the supplied text
|
|
247
|
+
- ```delete_paragraph(paragraph: Paragraph)```: Deletes a given paragraph (after you've inserted text after it for example)
|
|
248
|
+
|
|
249
|
+
As well as the following helper functions for building raw dictionary table models:
|
|
250
|
+
- ```insert_text_into_row(cell_text: list)```: Builds a row (dictionary) from a list of text where each list item is a column in the row. Supports "merge"
|
|
251
|
+
- ```insert_text_by_table_coords(table: dict, row: int, col: int, text: str)```: Inserts text into a table dictionary given the row & column numbers.
|
|
252
|
+
- ```generate_table(num_rows: int, num_cols: int, header_row: list, style: str = None)```: Generates a basic table dictionary and populates the headers from a list of text (strings).
|
|
@@ -79,6 +79,45 @@ def replace_placeholder_with_table(
|
|
|
79
79
|
delete_paragraph(paragraph)
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def inject_table(
|
|
83
|
+
doc_obj: _Document,
|
|
84
|
+
table: dict | WordTableModel,
|
|
85
|
+
placeholder: str,
|
|
86
|
+
remove_leading_para: bool = True,
|
|
87
|
+
remove_placeholder: bool = True,
|
|
88
|
+
) -> None:
|
|
89
|
+
"""
|
|
90
|
+
Function to relocate a Word table object to immediately follow a given
|
|
91
|
+
reference paragraph identified by the placeholder. Receives as input the
|
|
92
|
+
placeholder string and the Word table object (using docx module).
|
|
93
|
+
After moving the Word table after the placeholder paragraph, delete the
|
|
94
|
+
placeholder paragraph.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
# Locate the paragraph from the supplied placeholder text
|
|
98
|
+
paragraph: Paragraph = get_para_by_string(doc_obj, placeholder)
|
|
99
|
+
if not paragraph:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f'WARNING: Could not locate placeholder "{placeholder}"'
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Build the word table and add it to the end of the document
|
|
105
|
+
table = (
|
|
106
|
+
build_table(
|
|
107
|
+
doc_obj, table, remove_leading_para=remove_leading_para
|
|
108
|
+
)
|
|
109
|
+
if isinstance(table, dict)
|
|
110
|
+
else build_table(doc_obj, table.model_dump(), remove_leading_para=remove_leading_para)
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Move the Word table to a new paragraph immediately after the placeholder paragraph
|
|
114
|
+
paragraph._p.addnext(table._tbl)
|
|
115
|
+
|
|
116
|
+
if remove_placeholder:
|
|
117
|
+
# Delete the placeholder paragraph
|
|
118
|
+
delete_paragraph(paragraph)
|
|
119
|
+
|
|
120
|
+
|
|
82
121
|
def build_table(
|
|
83
122
|
docx_obj: _Document | Table, table_dict: dict, remove_leading_para: bool = True
|
|
84
123
|
) -> Table:
|