docxrender 0.1.0__tar.gz → 0.1.1__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.
- {docxrender-0.1.0 → docxrender-0.1.1}/PKG-INFO +171 -23
- {docxrender-0.1.0 → docxrender-0.1.1}/README.md +170 -22
- {docxrender-0.1.0 → docxrender-0.1.1}/pyproject.toml +1 -1
- docxrender-0.1.1/src/docxrender/__init__.py +50 -0
- docxrender-0.1.1/src/docxrender/api.py +149 -0
- docxrender-0.1.1/src/docxrender/contracts.py +625 -0
- docxrender-0.1.1/src/docxrender/docx/assets.py +146 -0
- docxrender-0.1.1/src/docxrender/docx/body.py +686 -0
- docxrender-0.1.1/src/docxrender/markdown.py +310 -0
- {docxrender-0.1.0 → docxrender-0.1.1}/src/docxrender/pdf_uno.py +8 -0
- docxrender-0.1.1/src/docxrender/renderer.py +789 -0
- docxrender-0.1.1/src/docxrender/template.py +148 -0
- docxrender-0.1.1/tests/test_public_contract.py +2063 -0
- docxrender-0.1.0/src/docxrender/__init__.py +0 -30
- docxrender-0.1.0/src/docxrender/api.py +0 -82
- docxrender-0.1.0/src/docxrender/contracts.py +0 -256
- docxrender-0.1.0/src/docxrender/docx/body.py +0 -369
- docxrender-0.1.0/src/docxrender/markdown.py +0 -177
- docxrender-0.1.0/src/docxrender/writer.py +0 -423
- docxrender-0.1.0/tests/test_public_contract.py +0 -979
- {docxrender-0.1.0 → docxrender-0.1.1}/src/docxrender/docx/__init__.py +0 -0
- {docxrender-0.1.0 → docxrender-0.1.1}/src/docxrender/docx/fields.py +0 -0
- {docxrender-0.1.0 → docxrender-0.1.1}/src/docxrender/docx/refresh.py +0 -0
- {docxrender-0.1.0 → docxrender-0.1.1}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: docxrender
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Minimal DOCX rendering core for template, markdown, field refresh, and PDF conversion workflows
|
|
5
5
|
Author-Email: FuqingZhang <fuqin.zhang@proton.me>
|
|
6
6
|
License: MIT
|
|
@@ -25,15 +25,17 @@ eventual LibreOffice-based PDF conversion. Product repositories own report
|
|
|
25
25
|
content, workflow resource layout, section rendering, manifest schemas, figure
|
|
26
26
|
selection, captions, and delivery directory semantics.
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Capabilities
|
|
29
29
|
|
|
30
|
-
Current
|
|
30
|
+
Current package surface:
|
|
31
31
|
|
|
32
32
|
- Public style/options/result dataclasses are available.
|
|
33
33
|
- `write_docx(...)` can create a minimal DOCX from a DOCX template, context,
|
|
34
34
|
markdown body, image assets, and `DocxStyle`.
|
|
35
|
-
- Markdown support currently covers
|
|
36
|
-
|
|
35
|
+
- Markdown support currently covers a CommonMark-ish shared subset: headings,
|
|
36
|
+
paragraphs, hard line breaks, unordered lists, ordered lists, pipe tables,
|
|
37
|
+
images, inline bold, inline code text cleanup, link-text reduction, page
|
|
38
|
+
breaks, and spacers.
|
|
37
39
|
- Basic Word styling is applied from caller-provided `DocxStyle`.
|
|
38
40
|
- DOCX field update/freeze behavior is implemented through DOCX XML rewriting.
|
|
39
41
|
- `write_docx(...)` can optionally refresh TOC/page fields through LibreOffice
|
|
@@ -41,7 +43,7 @@ Current implementation:
|
|
|
41
43
|
- `convert_docx_to_pdf(...)` converts through LibreOffice UNO when the external
|
|
42
44
|
LibreOffice/UNO runtime is available.
|
|
43
45
|
|
|
44
|
-
## Install
|
|
46
|
+
## Install
|
|
45
47
|
|
|
46
48
|
```bash
|
|
47
49
|
pdm install
|
|
@@ -53,8 +55,7 @@ Runtime dependencies are declared in `pyproject.toml`:
|
|
|
53
55
|
- `python-docx`
|
|
54
56
|
|
|
55
57
|
PDF conversion and DOCX field refresh are optional runtime features. They do
|
|
56
|
-
|
|
57
|
-
external LibreOffice/UNO runtime.
|
|
58
|
+
require an external LibreOffice/UNO runtime.
|
|
58
59
|
|
|
59
60
|
```bash
|
|
60
61
|
libreoffice --headless --version
|
|
@@ -67,32 +68,56 @@ On Debian or Ubuntu, that runtime is typically installed outside Python:
|
|
|
67
68
|
sudo apt install libreoffice python3-uno
|
|
68
69
|
```
|
|
69
70
|
|
|
70
|
-
`
|
|
71
|
-
|
|
72
|
-
administrator privileges. Base DOCX writing with `field_refresh=None` does not
|
|
73
|
-
import UNO and works without LibreOffice.
|
|
71
|
+
Base DOCX writing with `field_refresh=None` does not import UNO and works
|
|
72
|
+
without LibreOffice.
|
|
74
73
|
|
|
75
74
|
## Public API
|
|
76
75
|
|
|
77
76
|
The stable public API is exported from the package root. Product repositories
|
|
78
|
-
should prefer `
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
should prefer `DocxRenderer` for normal use. The dataclasses and module-level
|
|
78
|
+
functions remain public for advanced callers that want explicit contracts,
|
|
79
|
+
configuration adapters, or focused tests. Implementation modules such as
|
|
80
|
+
`docxrender.markdown` and `docxrender.docx` are technical layers and are not
|
|
81
|
+
compatibility-stable public contracts.
|
|
82
|
+
|
|
83
|
+
`DocxRenderer` follows value semantics. Every `with_*` call returns a new
|
|
84
|
+
renderer object and leaves the original unchanged. Runtime `docxtpl` objects,
|
|
85
|
+
including inline images, are materialized only by terminal methods such as
|
|
86
|
+
`write_docx_template(...)`, `write_docx(...)`, and `write_pdf()`.
|
|
81
87
|
|
|
82
88
|
```python
|
|
83
89
|
from docxrender import (
|
|
84
|
-
|
|
90
|
+
DocxRenderer,
|
|
91
|
+
DocxBodyAnchorOptions,
|
|
92
|
+
DocxBodyRenderPolicy,
|
|
93
|
+
DocxFieldMarkerOptions,
|
|
85
94
|
DocxFieldRefreshOptions,
|
|
86
95
|
DocxFontStyle,
|
|
96
|
+
DocxHeaderFooterImageOptions,
|
|
97
|
+
DocxMarkdownOptions,
|
|
87
98
|
DocxParagraphStyle,
|
|
88
99
|
DocxSizeStyle,
|
|
89
100
|
DocxStyle,
|
|
90
101
|
DocxTableStyle,
|
|
102
|
+
DocxTemplateContextPolicy,
|
|
103
|
+
DocxTemplateImageSpec,
|
|
104
|
+
DocxTemplateRenderOptions,
|
|
91
105
|
DocxWriteOptions,
|
|
106
|
+
write_docx_template,
|
|
92
107
|
write_docx,
|
|
93
108
|
)
|
|
94
109
|
```
|
|
95
110
|
|
|
111
|
+
`DocxFieldMarkerOptions` controls DOCX field update markers and field freezing
|
|
112
|
+
without LibreOffice or UNO:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
DocxRenderer(file_docx=Path("report.docx")).with_field_update_markers(
|
|
116
|
+
should_update_fields=True,
|
|
117
|
+
should_freeze_fields=False,
|
|
118
|
+
).write_docx()
|
|
119
|
+
```
|
|
120
|
+
|
|
96
121
|
`DocxFieldRefreshOptions` is optional. Use it only when the caller has provided
|
|
97
122
|
a LibreOffice/UNO runtime and wants a DOCX whose TOC, page fields, or other
|
|
98
123
|
Word fields have been refreshed by LibreOffice:
|
|
@@ -109,15 +134,52 @@ DocxWriteOptions(
|
|
|
109
134
|
)
|
|
110
135
|
```
|
|
111
136
|
|
|
112
|
-
|
|
137
|
+
`write_docx_template(...)` is the generic `docxtpl` technical boundary. It
|
|
138
|
+
renders a DOCX template with caller context, optional inline images, and
|
|
139
|
+
optional default injections. It does not insert markdown bodies, apply DOCX
|
|
140
|
+
body styling, or run field/PDF post-processing:
|
|
113
141
|
|
|
114
142
|
```python
|
|
115
143
|
from pathlib import Path
|
|
116
144
|
|
|
117
|
-
from docxrender import
|
|
145
|
+
from docxrender import DocxTemplateRenderOptions, write_docx_template
|
|
146
|
+
|
|
147
|
+
result = write_docx_template(
|
|
148
|
+
DocxTemplateRenderOptions(
|
|
149
|
+
file_template=Path("template.docx"),
|
|
150
|
+
file_out_docx=Path("template-rendered.docx"),
|
|
151
|
+
context={"report_title": "Example Report"},
|
|
152
|
+
context_defaults={"body_anchor": "__REPORT_BODY_ANCHOR__"},
|
|
153
|
+
context_policy=DocxTemplateContextPolicy(
|
|
154
|
+
rule_conflict="caller_wins",
|
|
155
|
+
required_keys=("report_title",),
|
|
156
|
+
),
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
print(result.file_docx)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`DocxTemplateContextPolicy` controls:
|
|
163
|
+
|
|
164
|
+
- merge behavior between caller context and default injections
|
|
165
|
+
- conflict priority: `caller_wins` or `defaults_win`
|
|
166
|
+
- required keys that must exist after merge and before render
|
|
167
|
+
|
|
168
|
+
Minimal `DocxRenderer` DOCX write example:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from pathlib import Path
|
|
172
|
+
|
|
173
|
+
from docxrender import DocxRenderer
|
|
118
174
|
|
|
119
175
|
result = (
|
|
120
|
-
|
|
176
|
+
DocxRenderer()
|
|
177
|
+
.with_template(
|
|
178
|
+
file_template=Path("template.docx"),
|
|
179
|
+
context={"report_title": "Example Report"},
|
|
180
|
+
rule_conflict="caller_wins",
|
|
181
|
+
required_keys=("report_title",),
|
|
182
|
+
)
|
|
121
183
|
.with_fonts(
|
|
122
184
|
font_name_latin="Times New Roman",
|
|
123
185
|
font_name_body_east_asia="宋体",
|
|
@@ -144,11 +206,28 @@ result = (
|
|
|
144
206
|
line_spacing_note=1.2,
|
|
145
207
|
first_line_indent_cm=0.74,
|
|
146
208
|
)
|
|
209
|
+
.with_header_footer_images(
|
|
210
|
+
file_header_image=Path("header.png"),
|
|
211
|
+
file_footer_image=Path("footer.png"),
|
|
212
|
+
idx_section_start=1,
|
|
213
|
+
)
|
|
214
|
+
.with_markdown(
|
|
215
|
+
should_parse_inline_bold=True,
|
|
216
|
+
should_parse_inline_code=True,
|
|
217
|
+
should_parse_links_as_text=True,
|
|
218
|
+
should_parse_image_width_attr=True,
|
|
219
|
+
default_image_width_pct=90.0,
|
|
220
|
+
)
|
|
221
|
+
.with_body_render_policy(
|
|
222
|
+
should_number_headings=False,
|
|
223
|
+
rule_ordered_list="word_style",
|
|
224
|
+
rule_unordered_list="word_style",
|
|
225
|
+
should_stripe_table_rows=False,
|
|
226
|
+
)
|
|
227
|
+
.with_body_anchor(rule_match="equals", rule_missing="raise")
|
|
147
228
|
.write_docx(
|
|
148
|
-
file_template=Path("template.docx"),
|
|
149
229
|
file_out_docx=Path("report.docx"),
|
|
150
|
-
|
|
151
|
-
markdown_body="# Summary\n\nBody text.",
|
|
230
|
+
markdown_body="# Summary **Bold**\n\nBody text with [link](https://example.com).",
|
|
152
231
|
dir_base=Path("."),
|
|
153
232
|
)
|
|
154
233
|
)
|
|
@@ -159,7 +238,76 @@ print(result.file_docx)
|
|
|
159
238
|
template. `dir_base` is the base directory used to resolve relative image paths
|
|
160
239
|
inside that Markdown body.
|
|
161
240
|
|
|
162
|
-
|
|
241
|
+
`DocxMarkdownOptions` only covers the shared CommonMark-ish subset. Product
|
|
242
|
+
repositories should keep custom markdown dialects outside `docxrender`, either
|
|
243
|
+
through caller-side preprocessing or explicit higher-level options in their own
|
|
244
|
+
repo.
|
|
245
|
+
|
|
246
|
+
`DocxBodyRenderPolicy` controls structural rendering choices such as heading
|
|
247
|
+
numbering, Word-style versus plain-text lists, and striped table body rows. It
|
|
248
|
+
does not classify product-specific paragraphs.
|
|
249
|
+
|
|
250
|
+
`DocxBodyAnchorOptions` controls where the Markdown body is inserted. The search
|
|
251
|
+
is limited to top-level body paragraphs in the DOCX main document. `equals`
|
|
252
|
+
matches `paragraph.text.strip() == anchor_token`; `contains` matches templates
|
|
253
|
+
where the token is embedded in a larger paragraph. Missing anchors can either
|
|
254
|
+
append content or raise a template error.
|
|
255
|
+
|
|
256
|
+
`DocxRenderer` can also start from an existing DOCX and run only later
|
|
257
|
+
technical steps:
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
from pathlib import Path
|
|
261
|
+
|
|
262
|
+
from docxrender import DocxRenderer
|
|
263
|
+
|
|
264
|
+
DocxRenderer(file_docx=Path("report.docx")).with_field_refresh(
|
|
265
|
+
exe_libreoffice=Path("/usr/bin/libreoffice"),
|
|
266
|
+
dir_user_profile=Path("tmp/lo-profile"),
|
|
267
|
+
should_require_toc=True,
|
|
268
|
+
).write_docx()
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Generic `docxtpl` inline-image binding is also supported through the same
|
|
272
|
+
template entrypoint:
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
from pathlib import Path
|
|
276
|
+
|
|
277
|
+
from docxrender import DocxRenderer, DocxTemplateImageSpec
|
|
278
|
+
|
|
279
|
+
renderer = DocxRenderer().with_template(
|
|
280
|
+
file_template=Path("template.docx"),
|
|
281
|
+
context={"report_title": "Example Report"},
|
|
282
|
+
inline_images={
|
|
283
|
+
"cover_image": DocxTemplateImageSpec(
|
|
284
|
+
file_image=Path("cover.png"),
|
|
285
|
+
width_mm=120,
|
|
286
|
+
),
|
|
287
|
+
},
|
|
288
|
+
)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The same renderer can convert the current DOCX to PDF:
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
from pathlib import Path
|
|
295
|
+
|
|
296
|
+
from docxrender import DocxRenderer
|
|
297
|
+
|
|
298
|
+
result = (
|
|
299
|
+
DocxRenderer(file_docx=Path("report.docx"))
|
|
300
|
+
.with_pdf_conversion(
|
|
301
|
+
exe_libreoffice=Path("/usr/bin/libreoffice"),
|
|
302
|
+
dir_user_profile=Path("tmp/lo-profile"),
|
|
303
|
+
file_out_pdf=Path("report.pdf"),
|
|
304
|
+
)
|
|
305
|
+
.write_pdf()
|
|
306
|
+
)
|
|
307
|
+
print(result.file_pdf)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Advanced explicit dataclass DOCX write example:
|
|
163
311
|
|
|
164
312
|
```python
|
|
165
313
|
from pathlib import Path
|
|
@@ -14,15 +14,17 @@ eventual LibreOffice-based PDF conversion. Product repositories own report
|
|
|
14
14
|
content, workflow resource layout, section rendering, manifest schemas, figure
|
|
15
15
|
selection, captions, and delivery directory semantics.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Capabilities
|
|
18
18
|
|
|
19
|
-
Current
|
|
19
|
+
Current package surface:
|
|
20
20
|
|
|
21
21
|
- Public style/options/result dataclasses are available.
|
|
22
22
|
- `write_docx(...)` can create a minimal DOCX from a DOCX template, context,
|
|
23
23
|
markdown body, image assets, and `DocxStyle`.
|
|
24
|
-
- Markdown support currently covers
|
|
25
|
-
|
|
24
|
+
- Markdown support currently covers a CommonMark-ish shared subset: headings,
|
|
25
|
+
paragraphs, hard line breaks, unordered lists, ordered lists, pipe tables,
|
|
26
|
+
images, inline bold, inline code text cleanup, link-text reduction, page
|
|
27
|
+
breaks, and spacers.
|
|
26
28
|
- Basic Word styling is applied from caller-provided `DocxStyle`.
|
|
27
29
|
- DOCX field update/freeze behavior is implemented through DOCX XML rewriting.
|
|
28
30
|
- `write_docx(...)` can optionally refresh TOC/page fields through LibreOffice
|
|
@@ -30,7 +32,7 @@ Current implementation:
|
|
|
30
32
|
- `convert_docx_to_pdf(...)` converts through LibreOffice UNO when the external
|
|
31
33
|
LibreOffice/UNO runtime is available.
|
|
32
34
|
|
|
33
|
-
## Install
|
|
35
|
+
## Install
|
|
34
36
|
|
|
35
37
|
```bash
|
|
36
38
|
pdm install
|
|
@@ -42,8 +44,7 @@ Runtime dependencies are declared in `pyproject.toml`:
|
|
|
42
44
|
- `python-docx`
|
|
43
45
|
|
|
44
46
|
PDF conversion and DOCX field refresh are optional runtime features. They do
|
|
45
|
-
|
|
46
|
-
external LibreOffice/UNO runtime.
|
|
47
|
+
require an external LibreOffice/UNO runtime.
|
|
47
48
|
|
|
48
49
|
```bash
|
|
49
50
|
libreoffice --headless --version
|
|
@@ -56,32 +57,56 @@ On Debian or Ubuntu, that runtime is typically installed outside Python:
|
|
|
56
57
|
sudo apt install libreoffice python3-uno
|
|
57
58
|
```
|
|
58
59
|
|
|
59
|
-
`
|
|
60
|
-
|
|
61
|
-
administrator privileges. Base DOCX writing with `field_refresh=None` does not
|
|
62
|
-
import UNO and works without LibreOffice.
|
|
60
|
+
Base DOCX writing with `field_refresh=None` does not import UNO and works
|
|
61
|
+
without LibreOffice.
|
|
63
62
|
|
|
64
63
|
## Public API
|
|
65
64
|
|
|
66
65
|
The stable public API is exported from the package root. Product repositories
|
|
67
|
-
should prefer `
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
should prefer `DocxRenderer` for normal use. The dataclasses and module-level
|
|
67
|
+
functions remain public for advanced callers that want explicit contracts,
|
|
68
|
+
configuration adapters, or focused tests. Implementation modules such as
|
|
69
|
+
`docxrender.markdown` and `docxrender.docx` are technical layers and are not
|
|
70
|
+
compatibility-stable public contracts.
|
|
71
|
+
|
|
72
|
+
`DocxRenderer` follows value semantics. Every `with_*` call returns a new
|
|
73
|
+
renderer object and leaves the original unchanged. Runtime `docxtpl` objects,
|
|
74
|
+
including inline images, are materialized only by terminal methods such as
|
|
75
|
+
`write_docx_template(...)`, `write_docx(...)`, and `write_pdf()`.
|
|
70
76
|
|
|
71
77
|
```python
|
|
72
78
|
from docxrender import (
|
|
73
|
-
|
|
79
|
+
DocxRenderer,
|
|
80
|
+
DocxBodyAnchorOptions,
|
|
81
|
+
DocxBodyRenderPolicy,
|
|
82
|
+
DocxFieldMarkerOptions,
|
|
74
83
|
DocxFieldRefreshOptions,
|
|
75
84
|
DocxFontStyle,
|
|
85
|
+
DocxHeaderFooterImageOptions,
|
|
86
|
+
DocxMarkdownOptions,
|
|
76
87
|
DocxParagraphStyle,
|
|
77
88
|
DocxSizeStyle,
|
|
78
89
|
DocxStyle,
|
|
79
90
|
DocxTableStyle,
|
|
91
|
+
DocxTemplateContextPolicy,
|
|
92
|
+
DocxTemplateImageSpec,
|
|
93
|
+
DocxTemplateRenderOptions,
|
|
80
94
|
DocxWriteOptions,
|
|
95
|
+
write_docx_template,
|
|
81
96
|
write_docx,
|
|
82
97
|
)
|
|
83
98
|
```
|
|
84
99
|
|
|
100
|
+
`DocxFieldMarkerOptions` controls DOCX field update markers and field freezing
|
|
101
|
+
without LibreOffice or UNO:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
DocxRenderer(file_docx=Path("report.docx")).with_field_update_markers(
|
|
105
|
+
should_update_fields=True,
|
|
106
|
+
should_freeze_fields=False,
|
|
107
|
+
).write_docx()
|
|
108
|
+
```
|
|
109
|
+
|
|
85
110
|
`DocxFieldRefreshOptions` is optional. Use it only when the caller has provided
|
|
86
111
|
a LibreOffice/UNO runtime and wants a DOCX whose TOC, page fields, or other
|
|
87
112
|
Word fields have been refreshed by LibreOffice:
|
|
@@ -98,15 +123,52 @@ DocxWriteOptions(
|
|
|
98
123
|
)
|
|
99
124
|
```
|
|
100
125
|
|
|
101
|
-
|
|
126
|
+
`write_docx_template(...)` is the generic `docxtpl` technical boundary. It
|
|
127
|
+
renders a DOCX template with caller context, optional inline images, and
|
|
128
|
+
optional default injections. It does not insert markdown bodies, apply DOCX
|
|
129
|
+
body styling, or run field/PDF post-processing:
|
|
102
130
|
|
|
103
131
|
```python
|
|
104
132
|
from pathlib import Path
|
|
105
133
|
|
|
106
|
-
from docxrender import
|
|
134
|
+
from docxrender import DocxTemplateRenderOptions, write_docx_template
|
|
135
|
+
|
|
136
|
+
result = write_docx_template(
|
|
137
|
+
DocxTemplateRenderOptions(
|
|
138
|
+
file_template=Path("template.docx"),
|
|
139
|
+
file_out_docx=Path("template-rendered.docx"),
|
|
140
|
+
context={"report_title": "Example Report"},
|
|
141
|
+
context_defaults={"body_anchor": "__REPORT_BODY_ANCHOR__"},
|
|
142
|
+
context_policy=DocxTemplateContextPolicy(
|
|
143
|
+
rule_conflict="caller_wins",
|
|
144
|
+
required_keys=("report_title",),
|
|
145
|
+
),
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
print(result.file_docx)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`DocxTemplateContextPolicy` controls:
|
|
152
|
+
|
|
153
|
+
- merge behavior between caller context and default injections
|
|
154
|
+
- conflict priority: `caller_wins` or `defaults_win`
|
|
155
|
+
- required keys that must exist after merge and before render
|
|
156
|
+
|
|
157
|
+
Minimal `DocxRenderer` DOCX write example:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from pathlib import Path
|
|
161
|
+
|
|
162
|
+
from docxrender import DocxRenderer
|
|
107
163
|
|
|
108
164
|
result = (
|
|
109
|
-
|
|
165
|
+
DocxRenderer()
|
|
166
|
+
.with_template(
|
|
167
|
+
file_template=Path("template.docx"),
|
|
168
|
+
context={"report_title": "Example Report"},
|
|
169
|
+
rule_conflict="caller_wins",
|
|
170
|
+
required_keys=("report_title",),
|
|
171
|
+
)
|
|
110
172
|
.with_fonts(
|
|
111
173
|
font_name_latin="Times New Roman",
|
|
112
174
|
font_name_body_east_asia="宋体",
|
|
@@ -133,11 +195,28 @@ result = (
|
|
|
133
195
|
line_spacing_note=1.2,
|
|
134
196
|
first_line_indent_cm=0.74,
|
|
135
197
|
)
|
|
198
|
+
.with_header_footer_images(
|
|
199
|
+
file_header_image=Path("header.png"),
|
|
200
|
+
file_footer_image=Path("footer.png"),
|
|
201
|
+
idx_section_start=1,
|
|
202
|
+
)
|
|
203
|
+
.with_markdown(
|
|
204
|
+
should_parse_inline_bold=True,
|
|
205
|
+
should_parse_inline_code=True,
|
|
206
|
+
should_parse_links_as_text=True,
|
|
207
|
+
should_parse_image_width_attr=True,
|
|
208
|
+
default_image_width_pct=90.0,
|
|
209
|
+
)
|
|
210
|
+
.with_body_render_policy(
|
|
211
|
+
should_number_headings=False,
|
|
212
|
+
rule_ordered_list="word_style",
|
|
213
|
+
rule_unordered_list="word_style",
|
|
214
|
+
should_stripe_table_rows=False,
|
|
215
|
+
)
|
|
216
|
+
.with_body_anchor(rule_match="equals", rule_missing="raise")
|
|
136
217
|
.write_docx(
|
|
137
|
-
file_template=Path("template.docx"),
|
|
138
218
|
file_out_docx=Path("report.docx"),
|
|
139
|
-
|
|
140
|
-
markdown_body="# Summary\n\nBody text.",
|
|
219
|
+
markdown_body="# Summary **Bold**\n\nBody text with [link](https://example.com).",
|
|
141
220
|
dir_base=Path("."),
|
|
142
221
|
)
|
|
143
222
|
)
|
|
@@ -148,7 +227,76 @@ print(result.file_docx)
|
|
|
148
227
|
template. `dir_base` is the base directory used to resolve relative image paths
|
|
149
228
|
inside that Markdown body.
|
|
150
229
|
|
|
151
|
-
|
|
230
|
+
`DocxMarkdownOptions` only covers the shared CommonMark-ish subset. Product
|
|
231
|
+
repositories should keep custom markdown dialects outside `docxrender`, either
|
|
232
|
+
through caller-side preprocessing or explicit higher-level options in their own
|
|
233
|
+
repo.
|
|
234
|
+
|
|
235
|
+
`DocxBodyRenderPolicy` controls structural rendering choices such as heading
|
|
236
|
+
numbering, Word-style versus plain-text lists, and striped table body rows. It
|
|
237
|
+
does not classify product-specific paragraphs.
|
|
238
|
+
|
|
239
|
+
`DocxBodyAnchorOptions` controls where the Markdown body is inserted. The search
|
|
240
|
+
is limited to top-level body paragraphs in the DOCX main document. `equals`
|
|
241
|
+
matches `paragraph.text.strip() == anchor_token`; `contains` matches templates
|
|
242
|
+
where the token is embedded in a larger paragraph. Missing anchors can either
|
|
243
|
+
append content or raise a template error.
|
|
244
|
+
|
|
245
|
+
`DocxRenderer` can also start from an existing DOCX and run only later
|
|
246
|
+
technical steps:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
from pathlib import Path
|
|
250
|
+
|
|
251
|
+
from docxrender import DocxRenderer
|
|
252
|
+
|
|
253
|
+
DocxRenderer(file_docx=Path("report.docx")).with_field_refresh(
|
|
254
|
+
exe_libreoffice=Path("/usr/bin/libreoffice"),
|
|
255
|
+
dir_user_profile=Path("tmp/lo-profile"),
|
|
256
|
+
should_require_toc=True,
|
|
257
|
+
).write_docx()
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Generic `docxtpl` inline-image binding is also supported through the same
|
|
261
|
+
template entrypoint:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
from pathlib import Path
|
|
265
|
+
|
|
266
|
+
from docxrender import DocxRenderer, DocxTemplateImageSpec
|
|
267
|
+
|
|
268
|
+
renderer = DocxRenderer().with_template(
|
|
269
|
+
file_template=Path("template.docx"),
|
|
270
|
+
context={"report_title": "Example Report"},
|
|
271
|
+
inline_images={
|
|
272
|
+
"cover_image": DocxTemplateImageSpec(
|
|
273
|
+
file_image=Path("cover.png"),
|
|
274
|
+
width_mm=120,
|
|
275
|
+
),
|
|
276
|
+
},
|
|
277
|
+
)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The same renderer can convert the current DOCX to PDF:
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
from pathlib import Path
|
|
284
|
+
|
|
285
|
+
from docxrender import DocxRenderer
|
|
286
|
+
|
|
287
|
+
result = (
|
|
288
|
+
DocxRenderer(file_docx=Path("report.docx"))
|
|
289
|
+
.with_pdf_conversion(
|
|
290
|
+
exe_libreoffice=Path("/usr/bin/libreoffice"),
|
|
291
|
+
dir_user_profile=Path("tmp/lo-profile"),
|
|
292
|
+
file_out_pdf=Path("report.pdf"),
|
|
293
|
+
)
|
|
294
|
+
.write_pdf()
|
|
295
|
+
)
|
|
296
|
+
print(result.file_pdf)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Advanced explicit dataclass DOCX write example:
|
|
152
300
|
|
|
153
301
|
```python
|
|
154
302
|
from pathlib import Path
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from docxrender.api import convert_docx_to_pdf, write_docx
|
|
2
|
+
from docxrender.contracts import (
|
|
3
|
+
DocxBodyAnchorOptions,
|
|
4
|
+
DocxBodyRenderPolicy,
|
|
5
|
+
DocxFieldMarkerOptions,
|
|
6
|
+
DocxFieldRefreshOptions,
|
|
7
|
+
DocxFontStyle,
|
|
8
|
+
DocxHeaderFooterImageOptions,
|
|
9
|
+
DocxMarkdownOptions,
|
|
10
|
+
DocxParagraphStyle,
|
|
11
|
+
DocxSizeStyle,
|
|
12
|
+
DocxStyle,
|
|
13
|
+
DocxTableStyle,
|
|
14
|
+
DocxTemplateContextPolicy,
|
|
15
|
+
DocxTemplateImageSpec,
|
|
16
|
+
DocxTemplateRenderOptions,
|
|
17
|
+
DocxTemplateRenderResult,
|
|
18
|
+
DocxToPdfOptions,
|
|
19
|
+
DocxToPdfResult,
|
|
20
|
+
DocxWriteOptions,
|
|
21
|
+
DocxWriteResult,
|
|
22
|
+
)
|
|
23
|
+
from docxrender.renderer import DocxRenderer
|
|
24
|
+
from docxrender.template import write_docx_template
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"DocxRenderer",
|
|
28
|
+
"DocxBodyAnchorOptions",
|
|
29
|
+
"DocxBodyRenderPolicy",
|
|
30
|
+
"DocxFieldMarkerOptions",
|
|
31
|
+
"DocxFieldRefreshOptions",
|
|
32
|
+
"DocxFontStyle",
|
|
33
|
+
"DocxHeaderFooterImageOptions",
|
|
34
|
+
"DocxMarkdownOptions",
|
|
35
|
+
"DocxParagraphStyle",
|
|
36
|
+
"DocxSizeStyle",
|
|
37
|
+
"DocxStyle",
|
|
38
|
+
"DocxTableStyle",
|
|
39
|
+
"DocxTemplateContextPolicy",
|
|
40
|
+
"DocxTemplateImageSpec",
|
|
41
|
+
"DocxTemplateRenderOptions",
|
|
42
|
+
"DocxTemplateRenderResult",
|
|
43
|
+
"DocxToPdfOptions",
|
|
44
|
+
"DocxToPdfResult",
|
|
45
|
+
"DocxWriteOptions",
|
|
46
|
+
"DocxWriteResult",
|
|
47
|
+
"convert_docx_to_pdf",
|
|
48
|
+
"write_docx_template",
|
|
49
|
+
"write_docx",
|
|
50
|
+
]
|