feat: make patch_xml respect custom Jinja2 delimiters - #651
Conversation
patch_xml() had hardcoded regex patterns for {{ }}, {% %}, and {# #},
ignoring any custom delimiters set via jinja_env. This caused template
variables to be silently left unreplaced when using non-default delimiters
(like single braces { }) because XML tags split by Word were never stripped
from inside the custom blocks.
Changes:
- Added jinja_env parameter to patch_xml() and all its call sites
- Dynamic regex patterns for stripping XML tags inside Jinja2 blocks (pattern ②)
- Dynamic regex patterns for HTML entity cleanup inside Jinja2 tags (pattern ⑥)
- Default behavior unchanged when jinja_env is None
- Added test with intentionally split XML runs and custom { } delimiters
Co-Authored-By: Claude <noreply@anthropic.com>
|
Nice to see test runner compatibility work. For CLI command validation, a quick matrix of Python versions used would help with confidence. |
|
Thanks for the review, @arturict!
Python Version Compatibility MatrixI've tested this PR across all Python versions supported by the project (
The 4 skipped tests on 3.7/3.8 ( Regarding CLI Command ValidationThe custom delimiter feature is exercised through the Python API (via the
The current CLI ( Let me know if there's anything else you'd like me to address! |
JackSpiece
left a comment
There was a problem hiding this comment.
Two things block this as written:
- The custom-delimiter handling still misses a split inside a multi-character opening delimiter. For example:
env = Environment(variable_start_string="[[", variable_end_string="]]" )
xml = "<w:t>[</w:t></w:r><w:r><w:t>[name]]</w:t>"
patched = tpl.patch_xml(xml, env)
assert "Alice" in env.from_string(patched).render(name="Alice")At 44cba6b, patched and the rendered result still contain the split [[name]] markup. This is the same class of split that the existing first regex handles for {{, {%, and {#. Please make that delimiter-joining pass respect the configured delimiters too, and add a regression case with the opening delimiter split across runs.
- The repository's exact CI lint command currently reports 8 errors in the changed files: two E401 errors, three E402 errors, and three E501 errors.
flake8 . --count --max-line-length=127 --show-source --statisticsThe existing focused tests and all 37 script tests pass under CPython 3.12.13, so the core direction looks good. I am happy to recheck after these are addressed.
Problem
patch_xml()has hardcoded regex patterns that only recognize default Jinja2 delimiters ({{ }},{% %},{# #}). When users configure custom delimiters viajinja_env:…the
patch_xmlpreprocessing step silently skips over their template variables. Specifically:Pattern ② (striptags — the core issue): Strips XML tags from inside
{{...}}/{%...%}/{#...#}blocks. Hardcoded regex only matches default delimiters, so custom{var}blocks retain Word XML fragments and Jinja2 cannot parse them.Pattern ⑥ (clean_tags): HTML entity cleanup inside Jinja2 tags. Same hardcoded pattern.
This causes variables to be silently left unreplaced when Word happens to split the variable text across multiple
<w:r>elements — a common occurrence in .docx files.Root Cause
Changes
patch_xml: Addedjinja_env=Noneparameter. When provided, dynamically builds regex patterns from the configured delimiters instead of using hardcoded{{/}}/{%/%}/{#/#}.build_xml,build_headers_footers_xml,render_footnotes,get_undeclared_template_variables: Now passjinja_envthrough topatch_xml.jinja_env=None, falls back to standard delimiters — fully backward compatible.tests/custom_delimiters.py: New test with intentionally split XML runs and custom{ }delimiters.Scope
This PR handles the two patterns that directly affect user template variables (② striptags, ⑥ clean_tags). docxtpl's own DSL tags (
colspan,cellbg,vm,hm,{{y ...}},{%y ... %},{%-,-%},{{r) intentionally remain hardcoded — they are part of docxtpl's API, not user-configurable Jinja2 syntax.A future PR could extend additional patterns for full custom delimiter support.
Co-Authored-By: Claude noreply@anthropic.com