From 9946c74fdc1c265afa3b9e21bdf0f69c93d438ea Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Thu, 15 Oct 2020 08:57:03 +0200 Subject: [PATCH] PR #307 + #312 --- CHANGES.rst | 4 ++++ docxtpl/__init__.py | 28 +++++++++++++++++++++++++++- tests/escape.py | 7 ++++++- tests/templates/escape_tpl.docx | Bin 9506 -> 9622 bytes 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 9ae35c1..1c53a79 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,7 @@ +0.10.3 (2020-10-15) +------------------- +- \n \t and \f are now accepted in simple context string (#307, #312) + 0.10.1 (2020-08-23) ------------------- - Remove extension testing (#297) diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index aa1b1ee..4adb459 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -7,7 +7,7 @@ Created : 2015-03-12 import functools import io -__version__ = '0.10.2' +__version__ = '0.10.3' from lxml import etree from docx import Document @@ -27,6 +27,7 @@ import six import binascii import os import zipfile +from functools import partial NEWLINE_XML = '' NEWPARAGRAPH_XML = '' @@ -234,8 +235,33 @@ class DocxTemplate(object): .replace('}_}', '}}') .replace('{_%', '{%') .replace('%_}', '%}')) + dst_xml = self.resolve_listing(dst_xml) return dst_xml + def resolve_listing(self, xml): + xml = xml.replace('\n', NEWLINE_XML) + xml = xml.replace('\f', PAGE_BREAK) + + def resolve_run(paragraph_properties, m): + run_properties = re.search(r'.*', m[0]) + run_properties = run_properties[0] if run_properties else '' + xml = m[0].replace('\t', '' + '%s' + '%s' % (run_properties, run_properties)) + return xml.replace('\a', '%s%s' % (paragraph_properties, run_properties)) + + def resolve_paragraph(m): + paragraph_properties = re.search(r'.*', m[0]) + paragraph_properties = paragraph_properties[0] if paragraph_properties else '' + + p_resolve_run = partial(resolve_run, paragraph_properties) + + return re.sub(r']*)?>.*?', p_resolve_run, m[0]) + + xml = re.sub(r']*)?>.*?', resolve_paragraph, xml) + + return xml + def build_xml(self, context, jinja_env=None): xml = self.get_xml() xml = self.patch_xml(xml) diff --git a/tests/escape.py b/tests/escape.py index a18b926..c3d03fc 100644 --- a/tests/escape.py +++ b/tests/escape.py @@ -6,7 +6,7 @@ context = { 'myvar': R( '"less than" must be escaped : <, this can be done with RichText() or R()' ), - 'myescvar': 'It can be escaped with a "|e" jinja filter in the template too : < ', + 'myescvar': 'Without using Richtext, you can simply escape text with a "|e" jinja filter in the template : < ', 'nlnp': R( 'Here is a multiple\nlines\nstring\aand some\aother\aparagraphs\aNOTE: the current character styling is removed' ), @@ -14,6 +14,11 @@ context = { 'the listing\nwith\nsome\nlines\nand special chars : <>&\f ... and a page break' ), 'page_break': R('\f'), + 'new_listing': """With the latest version of docxtpl, +there is no need to use Listing objects anymore. +Just use \\n for newline,\n\\t\t for tabulation and \\f for ...\f...page break +One can also use special chars : <>& but you have then to add "|e" jinja filter in the template +""", } tpl.render(context) diff --git a/tests/templates/escape_tpl.docx b/tests/templates/escape_tpl.docx index d676492f352ecd382a311cb9cfad367f9311dfa5..62592e48aeff6700308d162bd1aad421a8910d58 100644 GIT binary patch delta 5882 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 delta 5848 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 kzpr43HZvItH9f?h`B!njEB