Merge pull request #155 from mx2048/master

Added compatibility with Python 2.7 as to the method `escape_values`.
This commit is contained in:
Eric Lapouyade 2018-11-08 12:12:46 +01:00 committed by GitHub
commit 01f4d16767
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 19 additions and 22 deletions

View File

@ -18,13 +18,15 @@ try:
from html import escape, unescape from html import escape, unescape
except ImportError: except ImportError:
# cgi.escape is deprecated in python 3.7 # cgi.escape is deprecated in python 3.7
# import escape and unescape methods for Python 2.7
from cgi import escape from cgi import escape
import HTMLParser
unescape = HTMLParser.HTMLParser().unescape
import re import re
import six import six
import binascii import binascii
import os import os
import zipfile import zipfile
import sys
NEWLINE_XML = '</w:t><w:br/><w:t xml:space="preserve">' NEWLINE_XML = '</w:t><w:br/><w:t xml:space="preserve">'
NEWPARAGRAPH_XML = '</w:t></w:r></w:p><w:p><w:r><w:t xml:space="preserve">' NEWPARAGRAPH_XML = '</w:t></w:r></w:p><w:p><w:r><w:t xml:space="preserve">'
@ -175,40 +177,35 @@ class DocxTemplate(object):
"""Escape strings for an XML Word document """Escape strings for an XML Word document
which may contain <, >, &, ', and ". which may contain <, >, &, ', and ".
""" """
def escape_recursively(d): def escape_recursively(d, identities):
"""Escape string values of the passed :dict: `d` in-place """Escape string values of the passed :dict: `d` in-place
including nested dictionaries. including nested dictionaries of any depth.
""" """
nonlocal hash_values for k, v in six.iteritems(d):
for k, v in d.items():
if isinstance(v, dict): if isinstance(v, dict):
hash_value = id(v) identity = id(v)
if hash_value not in hash_values: if identity not in identities:
hash_values.add(hash_value) identities.add(identity)
escape_recursively(v) escape_recursively(v, identities)
else: else:
# Avoid dict, Listing, InlineImage, RichText, etc. classes # Avoid dict, Listing, InlineImage, RichText, etc. classes
# by comparing v to str. Do not use try-except. # by comparing `v` to `str`. Do not use try-except.
if isinstance(v, str): if isinstance(v, str):
# Unescape at first to avoid secondary escaping # Unescape at first to avoid secondary escaping
d[k] = escape(unescape(v)) d[k] = escape(unescape(v))
# Avoid RecursionError (if back edges, i.e. cycles, exist) # Avoid RecursionError (if back edges, i.e. cycles, exist)
# by using a set of hash values of iterated dictionaries. # by using a set of unique identities of iterated dictionaries.
hash_values = {id(context), } initial_identities = {id(context)}
escape_recursively(context) escape_recursively(context, initial_identities)
def render(self, context, jinja_env=None, autoescape=False): def render(self, context, jinja_env=None, autoescape=False):
if sys.version_info >= (3, 0) and autoescape: if autoescape:
self.escape_values(context) self.escape_values(context)
else:
# Sorry folk, use awesome Python3 such as 3.6
pass
# Body # Body
xml_src = self.build_xml(context,jinja_env) xml_src = self.build_xml(context, jinja_env)
# fix tables if needed # fix tables if needed
tree = self.fix_tables(xml_src) tree = self.fix_tables(xml_src)

View File

@ -3,10 +3,10 @@ from docxtpl import *
tpl = DocxTemplate("test_files/escape_tpl_auto.docx") tpl = DocxTemplate("test_files/escape_tpl_auto.docx")
context = {'myvar': R('"less than" must be escaped : <, this can be done with RichText() or R()'), 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': 'It can be escaped with a "|e" jinja filter in the template too : < ',
'nlnp' : R('Here is a multiple\nlines\nstring\aand some\aother\aparagraphs\aNOTE: the current character styling is removed'), 'nlnp': R('Here is a multiple\nlines\nstring\aand some\aother\aparagraphs\aNOTE: the current character styling is removed'),
'mylisting': Listing('the listing\nwith\nsome\nlines\nand special chars : <>&'), 'mylisting': Listing('the listing\nwith\nsome\nlines\nand special chars : <>&'),
'autoescape': """These string should be auto escaped for an XML Word document which may contain <, >, &, ", and '.""" 'autoescape': """<, >, &, ", and '."""
} }
tpl.render(context, autoescape=True) tpl.render(context, autoescape=True)

Binary file not shown.