Skip to content

Commit

Permalink
Docx changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jpn-- committed Mar 8, 2017
1 parent 7c99333 commit 42f8165
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 78 deletions.
45 changes: 45 additions & 0 deletions py/model_reporter/art.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,51 @@ def to_xlsx(self, workbook, worksheet_name=None, r_top=0, c_left=0,







def to_docx(self, title_level=2, **format):

number_of_rows, number_of_columns = self.df.shape

from .docx import docx_table
table = docx_table(rows=number_of_rows, cols=number_of_columns, style='Table Body Text',
header_text=self.title, header_level=title_level)

in_head = True

# Content
for r,rvalue in enumerate(self.df.index):
if (~pandas.isnull(self.df.iloc[r,1:])).sum()==0:
catflag = True
else:
catflag = False
if r==self.n_thead_rows:
# Have now completed header rows
in_head = False
startline = True
for c,cvalue in enumerate(self.df.columns):
cellspan = self.cellspan_iloc(r,c)
if cellspan != (0,0):
# This is a cell with real content
if cellspan == (1,1):
cell = table.cell(r,c)
else:
cell = table.cell(r,c).merge(table.cell(r+cellspan[0]-1,c+cellspan[1]-1))
cell.text = self.get_text_iloc(r,c)
if in_head:
cell.paragraphs[0].runs[0].bold = True
else:
startline = False

return table






def cellspan_iloc(self,r,c):
try:
if pandas.isnull(self.df.iloc[r,c]):
Expand Down
150 changes: 93 additions & 57 deletions py/model_reporter/docx.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

class DocxModelReporter():
def docx_params(self, groups=None, display_inital=False, **format):
raise ImportError()
import docx
from docx.enum.style import WD_STYLE_TYPE
from docx.enum.text import WD_ALIGN_PARAGRAPH


else:
Expand All @@ -19,7 +21,7 @@ def _append_to_document(self, other_doc):
while not isinstance(other_doc, docx.document.Document) and hasattr(other_doc, '_parent'):
other_doc = other_doc._parent
if not isinstance(other_doc, docx.document.Document):
raise larch.LarchError('other_doc is not a docx.Document or a part thereof')
raise TypeError('other_doc is not a docx.Document or a part thereof, it is a {}'.format(type(other_doc)))
for element in other_doc._body._element:
self._body._element.append(element)
return self
Expand Down Expand Up @@ -50,10 +52,12 @@ def document_larchstyle():

table_body_text = document.styles.add_style('Table Body Text',WD_STYLE_TYPE.TABLE)
table_body_text.base_style = document.styles['Body Text']
table_body_text.font.name = 'Arial Narrow'
table_body_text.font.name = 'Arial'
table_body_text.font.size = docx.shared.Pt(9)
table_body_text.paragraph_format.space_before = docx.shared.Pt(1)
table_body_text.paragraph_format.space_after = docx.shared.Pt(1)
table_body_text.paragraph_format.left_indent = docx.shared.Pt(2)
table_body_text.paragraph_format.right_indent = docx.shared.Pt(2)
table_body_text.paragraph_format.line_spacing = 1.0


Expand All @@ -80,34 +84,31 @@ class DocxManager:
def __init__(self, model):
self._model = model

# def _get_item(self, key, html_processor=True):
# candidate = None
# if isinstance(key,str):
# try:
# art_obj = getattr(self._model, "art_{}".format(key.casefold()))
# candidate = lambda *arg,**kwarg: art_obj(*arg,**kwarg).__xml__()
# except AttributeError:
# pass
# try:
# candidate = getattr(self._model, "xhtml_{}".format(key.casefold()))
# except AttributeError:
# pass
# try:
# candidate = self._model._user_defined_xhtml[key.casefold()]
# except (AttributeError, KeyError):
# pass
# if candidate is None:
# #raise TypeError("xml builder for '{}' not found".format(key.casefold()))
# import warnings
# warnings.warn("xml builder for '{}' not found".format(key.casefold()))
# x = XML_Builder("div", {'class':"no_builder"})
# x.start('pre', {'class':'error_report', 'style':'padding:10px;background-color:#fff693;color:#c90000;'})
# x.data("xml builder for '{}' not found".format(key.casefold()))
# x.end('pre')
# candidate = x.close()
# else:
# raise TypeError("invalid item")
# return candidate
def _get_item(self, key, html_processor=True):
candidate = None
if isinstance(key,str):
try:
art_obj = getattr(self._model, "art_{}".format(key.casefold()))
candidate = lambda *arg,**kwarg: art_obj(*arg,**kwarg).to_docx()
except AttributeError:
pass
try:
candidate = getattr(self._model, "docx_{}".format(key.casefold()))
except AttributeError:
pass
try:
candidate = self._model._user_defined_docx[key.casefold()]
except (AttributeError, KeyError):
pass
if candidate is None:
import warnings
warnings.warn("docx builder for '{}' not found".format(key.casefold()))
candidate = document_larchstyle()
paragraph = candidate.add_paragraph(style="Body Text")
paragraph.add_run("docx builder for '{}' not found".format(key.casefold())).bold = True
else:
raise TypeError("invalid item")
return candidate

def __getitem__(self, key):
return self._get_item(key, True)
Expand Down Expand Up @@ -153,29 +154,23 @@ def __dir__(self):
# else:
# self._model.new_docx_section(val, key)

# def __call__(self, *args, force_Elem=False, filename=None, view_on_exit=False, return_html=False, **kwarg):
# div = Elem('div')
# for arg in self._model.iter_cats(args):
# if isinstance(arg, Elem):
# div << arg
# elif isinstance(arg, str):
# div << self._get_item(arg, False)()
# elif inspect.ismethod(arg):
# div << arg()
# elif isinstance(arg, list):
# div << self( *(self._model._inflate_cats(arg)), force_Elem=True )
# if filename is not None or return_html:
# with XHTML(quickhead=self._model, view_on_exit=view_on_exit, filename=filename or None, **kwarg) as f:
# f << div
# if return_html or self._return_xhtml:
# temphtml = f.dump()
# else:
# temphtml = None
# if temphtml is not None:
# return temphtml
# if not force_Elem and self._return_xhtml:
# return ElementTree.tostring(div, encoding="utf8", method="html")
# return div
def __call__(self, *args, filename=None, view_on_exit=False, **kwarg):
top_doc = document_larchstyle()
for arg in args:
if isinstance(arg, docx.document.Document):
top_doc.append(arg)
elif isinstance(arg, str):
top_doc.append(self._get_item(arg)())
elif inspect.ismethod(arg):
top_doc.append(arg())
if filename is not None:
top_doc.save(filename)
if view_on_exit:
try:
os.system("open "+filename)
except:
pass
return top_doc


@property
Expand All @@ -202,11 +197,11 @@ def docx(self):
-------
Document
"""
return XhtmlModelReporter.XmlManager(self)
return DocxModelReporter.DocxManager(self)



def docx_params(self, groups=None, display_inital=False, **format):
def docx_params_v0(self, groups=None, display_inital=False, **format):

# keys fix
existing_format_keys = list(format.keys())
Expand Down Expand Up @@ -351,8 +346,49 @@ def write_param_row(p, *, force=False):
for p in unlisted_parameters:
write_param_row(p)
return table
docx_param = docx_parameters = docx_params
docx_param_v0 = docx_parameters_v0 = docx_params_v0


def _docx_blurb_n(self, h_stepdown=2, n='', **format):
try:
blurb_rst = getattr(self, 'blurb'+str(n))
except AttributeError:
return None
if isinstance(blurb_rst, bytes):
blurb_rst = blurb_rst.decode()
if not isinstance(blurb_rst, str):
raise TypeError('blurb must be reStructuredText as str ot bytes')
from ..util.rst_to_docx import render_docx
return render_docx(blurb_rst, h_stepdown=h_stepdown)

def docx_blurb(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, **format)

def docx_blurb1(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=1, **format)

def docx_blurb2(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=2, **format)

def docx_blurb3(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=3, **format)

def docx_blurb4(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=4, **format)

def docx_blurb5(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=5, **format)

def docx_blurb6(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=6, **format)

def docx_blurb7(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=7, **format)

def docx_blurb8(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=8, **format)

def docx_blurb9(self, h_stepdown=2, **format):
return self._docx_blurb_n(h_stepdown=h_stepdown, n=9, **format)


41 changes: 20 additions & 21 deletions py/util/rst_to_docx.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def xhtml_blurb(blurb_rst, h_stepdown=2, **format):


def cut_extra_whitespace(x):
if x is None: return ""
x = x.replace('\t',' ').replace('\n',' ')
x1 = x.replace(' ',' ')
while x1!=x:
Expand Down Expand Up @@ -55,7 +56,8 @@ def render(self, h_stepdown=2):
and italic runs within block elements.
"""
t = xhtml_blurb(self._rst, h_stepdown=h_stepdown)
#print(ElementTree.tostring(t).decode())
# from pprint import pprint
# pprint(ElementTree.tostring(t).decode())
self._render_container(t)

@property
Expand Down Expand Up @@ -100,24 +102,8 @@ def _render_container(self, container):
self._render_container(element)
elif tag == 'title':
self._render_paragraph(element, self._styles['h1'])
elif tag == 'h1':
self._render_paragraph(element, self._styles['h1'])
elif tag == 'h2':
self._render_paragraph(element, self._styles['h2'])
elif tag == 'h3':
self._render_paragraph(element, self._styles['h3'])
elif tag == 'h4':
self._render_paragraph(element, self._styles['h4'])
elif tag == 'h5':
self._render_paragraph(element, self._styles['h5'])
elif tag == 'h6':
self._render_paragraph(element, self._styles['h6'])
elif tag == 'h7':
self._render_paragraph(element, self._styles['h7'])
elif tag == 'h8':
self._render_paragraph(element, self._styles['h8'])
elif tag == 'p':
self._render_paragraph(element, self._styles['p'])
elif tag in set('h{}'.format(z) for z in range(1,9)) or tag in ('p', 'i', 'b'):
self._render_paragraph(element, self._styles[tag])
elif tag == 'paragraph':
self._render_paragraph(element, self._styles['p'])
elif tag == 'transition':
Expand Down Expand Up @@ -171,6 +157,7 @@ def _render_paragraph(self, para, style, depth=None):
`paragraph` element *para*. Create appropriate runs for text having
strong and emphasis inline formatting.
"""
# print("RENDER PARAG style",style)
if depth and depth>1:
paragraph = self._blkcntnr.add_paragraph(style=style+" {}".format(depth))
else:
Expand All @@ -179,7 +166,7 @@ def _render_paragraph(self, para, style, depth=None):
paragraph.add_run(cut_extra_whitespace(para.text))
for child in para:
# print("child.tag",child.tag,child.text,child.tail)
if child.tag=='p':
if child.tag in ('p',):
paragraph.add_run(cut_extra_whitespace(child.text)+" ")
paragraph.add_run(cut_extra_whitespace(child.tail)+ " ")
elif child.tag in ('strong','b','em','i'):
Expand All @@ -188,6 +175,10 @@ def _render_paragraph(self, para, style, depth=None):
paragraph.add_run(cut_extra_whitespace(child.text), self._styles[style_key])
if child.tail is not None:
paragraph.add_run(cut_extra_whitespace(child.tail))
elif child.tag=='span':
for sub_item in child:
self._render_span(paragraph, sub_item, {'strong': 'b', 'em':'i','b':'b', 'i':'i', 'sub':'i', }.get(sub_item.tag))
paragraph.add_run(cut_extra_whitespace(child.tail)+ " ")
else:
self._depth += 1
try:
Expand All @@ -196,7 +187,15 @@ def _render_paragraph(self, para, style, depth=None):
finally:
self._depth -= 1


def _render_span(self, paragraph, span, style):
# print("RENDER SPAN style",style, ":", span.text, span.tail)
if style=='b':
paragraph.add_run(span.text).bold = True
elif style=='i':
paragraph.add_run(span.text).italic = True
else:
paragraph.add_run(span.text)
paragraph.add_run(span.tail)


def _render_transition(self, style='p'):
Expand Down

0 comments on commit 42f8165

Please sign in to comment.