From 1483bae331a3fe84d2da9a43a0a0f8451067485f Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Thu, 26 Mar 2015 11:23:05 +0100 Subject: [PATCH] Update RichText --- .settings/org.eclipse.core.resources.prefs | 1 + docxtpl/__init__.py | 93 +++++++++++---------- tests/cellbg.py | 14 ++-- tests/richtext.py | 36 ++++++++ tests/test_files/cellbg.docx | Bin 8267 -> 8311 bytes tests/test_files/cellbg_tpl.docx | Bin 11082 -> 11154 bytes tests/test_files/richtext.docx | Bin 0 -> 8927 bytes tests/test_files/richtext_tpl.docx | Bin 0 -> 11440 bytes 8 files changed, 94 insertions(+), 50 deletions(-) create mode 100644 tests/richtext.py create mode 100644 tests/test_files/richtext.docx create mode 100644 tests/test_files/richtext_tpl.docx diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index 0e5c50a..80bd8f5 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -2,4 +2,5 @@ eclipse.preferences.version=1 encoding//docxtpl/__init__.py=utf-8 encoding//tests/cellbg.py=utf-8 encoding//tests/order.py=utf-8 +encoding//tests/richtext.py=utf-8 encoding//tests/subdoc.py=utf-8 diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 20a659c..9895a93 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -10,6 +10,7 @@ __version__ = '0.1.1' from lxml import etree from docx import Document from jinja2 import Template +from cgi import escape import copy import re @@ -17,27 +18,27 @@ class DocxTemplate(object): """ Class for managing docx files as they were jinja2 templates """ def __init__(self, docx): self.docx = Document(docx) - - def __getattr__(self, name): + + def __getattr__(self, name): return getattr(self.docx, name) - + def get_docx(self): return self.docx - + def get_xml(self): return etree.tostring(self.docx._element.body, pretty_print=True) def write_xml(self,filename): with open(filename,'w') as fh: fh.write(self.get_xml()) - + def patch_xml(self,src_xml): # strip all xml tags inside {% %} and {{ }} # that Microsoft word can insert into xml code for this part of the document def striptags(m): return re.sub('.*?(|]*>)','',m.group(0),flags=re.DOTALL) src_xml = re.sub(r'{%(?:(?!%}).)*|{{(?:(?!}}).)*',striptags,src_xml,flags=re.DOTALL) - + # manage table cell background color def cellbg(m): cell_xml = m.group(1) + m.group(3) @@ -45,19 +46,20 @@ class DocxTemplate(object): cell_xml = re.sub(r'','', cell_xml, count=1) return re.sub(r'(]*>)',r'\1' % m.group(2), cell_xml) src_xml = re.sub(r'(](?:(?!]).)*){%\s*cellbg\s+([^%]*)\s*%}(.*?)',cellbg,src_xml,flags=re.DOTALL) - + for y in ['tr', 'p', 'r']: - # replace into xml code the row/paragraph/run containing {%y xxx %} or {{y xxx}} template tag + # replace into xml code the row/paragraph/run containing {%y xxx %} or {{y xxx}} template tag # by {% xxx %} or {{ xx }} without any surronding xml tags : # This is mandatory to have jinja2 generating correct xml code pat = r'](?:(?!]).)*({%%|{{)%(y)s ([^}%%]*(?:%%}|}})).*?' % {'y':y} src_xml = re.sub(pat, r'\1 \2',src_xml,flags=re.DOTALL) - + return src_xml def render_xml(self,src_xml,context): template = Template(src_xml) - dst_xml = template.render(context) + dst_xml = template.render(context) + dst_xml = dst_xml.replace('{_{','{{').replace('}_}','}}').replace('{_%','{%').replace('%_}','%}') return dst_xml def build_xml(self,context): @@ -65,7 +67,7 @@ class DocxTemplate(object): xml = self.patch_xml(xml) xml = self.render_xml(xml, context) return xml - + def map_xml(self,xml): root = self.docx._element body = root.body @@ -74,7 +76,7 @@ class DocxTemplate(object): def render(self,context): xml = self.build_xml(context) self.map_xml(xml) - + def new_subdoc(self): return Subdoc(self) @@ -86,66 +88,71 @@ class Subdoc(object): self.subdocx = Document() self.subdocx._part = self.docx._part - def __getattr__(self, name): + def __getattr__(self, name): return getattr(self.subdocx, name) - + def __unicode__(self): xml = '' for p in self.paragraphs: xml += '\n' + re.sub(r'^.*\n', '', etree.tostring(p._element,pretty_print=True)) return xml - - + + class RichText(object): """ class to generate Rich Text when using templates variables - - This is much faster than using Subdoc class, but this only for texts INSIDE an existing paragraph. + + This is much faster than using Subdoc class, but this only for texts INSIDE an existing paragraph. """ def __init__(self, text=None, **text_prop): self.xml = '' if text: - self.add_run(text, **text_prop) - - def add(self, text, style=None, - color=None, - highlight=None, - size=None, - bold=False, - italic=False, - underline=False, + self.add(text, **text_prop) + + def add(self, text, style=None, + color=None, + highlight=None, + size=None, + bold=False, + italic=False, + underline=False, strike=False): - - prop = '' + + + if not isinstance(text, unicode): + text = text.decode('utf-8',errors='ignore') + text = escape(text).replace('\n','') + + prop = u'' if style: - prop += '' % style + prop += u'' % style if color: if color[0] == '#': color = color[1:] - prop += '' % color + prop += u'' % color if highlight: if highlight[0] == '#': highlight = highlight[1:] - prop += '' % highlight + prop += u'' % highlight if size: - prop += '' % size - prop += '' % size + prop += u'' % size + prop += u'' % size if bold: - prop += '' + prop += u'' if italic: - prop += '' + prop += u'' if underline: if underline not in ['single','double']: underline = 'single' - prop += '' % underline + prop += u'' % underline if strike: - prop += '' - - self.xml += '' + prop += u'' + + self.xml += u'' if prop: - self.xml += '%s' % prop - self.xml += '%s\n' % text + self.xml += u'%s' % prop + self.xml += u'%s\n' % text def __unicode__(self): - return xml + return self.xml diff --git a/tests/cellbg.py b/tests/cellbg.py index d42ffc9..3e63b55 100644 --- a/tests/cellbg.py +++ b/tests/cellbg.py @@ -5,17 +5,17 @@ Created : 2015-03-12 @author: Eric Lapouyade ''' -from docxtpl import DocxTemplate +from docxtpl import DocxTemplate, RichText tpl=DocxTemplate('test_files/cellbg_tpl.docx') -context = { +context = { 'alerts' : [ - {'date' : '2015-03-10', 'desc' : 'Very critical alert', 'type' : 'CRITICAL', 'bg': 'FF0000' }, - {'date' : '2015-03-11', 'desc' : 'Just a warning', 'type' : 'WARNING', 'bg': 'FFDD00' }, - {'date' : '2015-03-12', 'desc' : 'Information', 'type' : 'INFO', 'bg': '8888FF' }, - {'date' : '2015-03-13', 'desc' : 'Debug trace', 'type' : 'DEBUG', 'bg': 'FF00FF' }, - ], + {'date' : '2015-03-10', 'desc' : RichText('Very critical alert',color='FF0000', bold=True), 'type' : 'CRITICAL', 'bg': 'FF0000' }, + {'date' : '2015-03-11', 'desc' : RichText('Just a warning'), 'type' : 'WARNING', 'bg': 'FFDD00' }, + {'date' : '2015-03-12', 'desc' : RichText('Information'), 'type' : 'INFO', 'bg': '8888FF' }, + {'date' : '2015-03-13', 'desc' : RichText('Debug trace'), 'type' : 'DEBUG', 'bg': 'FF00FF' }, + ], } tpl.render(context) diff --git a/tests/richtext.py b/tests/richtext.py new file mode 100644 index 0000000..781e0e7 --- /dev/null +++ b/tests/richtext.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +''' +Created : 2015-03-26 + +@author: Eric Lapouyade +''' + +from docxtpl import DocxTemplate, RichText + +tpl=DocxTemplate('test_files/richtext_tpl.docx') + +rt = RichText('an exemple of ') +rt.add('a rich text', style='myrichtextstyle') +rt.add(' with ') +rt.add('some italic', italic=True) +rt.add(' and ') +rt.add('some violet', color='#ff00ff') +rt.add(' and ') +rt.add('some striked', strike=True) +rt.add(' and ') +rt.add('some small', size=14) +rt.add(' or ') +rt.add('big', size=60) +rt.add(' text.') +rt.add(' Et voilĂ  ! ') +rt.add('\n1st line') +rt.add('\n2nd line') +rt.add('\n3rd line') +rt.add('\n\n') + +context = { + 'example' : rt, +} + +tpl.render(context) +tpl.save('test_files/richtext.docx') diff --git a/tests/test_files/cellbg.docx b/tests/test_files/cellbg.docx index 478ab71be9d45c2a8e16db500d46427ffa5b4f58..2512c6bcdcc5683ade9315d46a94673622a9caa5 100644 GIT binary patch delta 2764 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 GBKmL0jK|>s diff --git a/tests/test_files/cellbg_tpl.docx b/tests/test_files/cellbg_tpl.docx index 1b63f8c8dcd317e8fe604ee5253c4969d80cd49f..7347855c91a03e15bc972209b29f16370817bb20 100644 GIT binary patch delta 2723 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 d0000000000QiUlN)Sn6$Jjcyeny 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 F0044o;UfS5 diff --git a/tests/test_files/richtext.docx b/tests/test_files/richtext.docx new file mode 100644 index 0000000000000000000000000000000000000000..d100cf660fa48cb217d74b765299fb65abeb9698 GIT binary patch literal 8927 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 B4uk*z literal 0 HcmV?d00001