[pod] Added param Renderer.raiseOnError (False by default), that, if True, will force the Renderer to raise an error instead of dumping it into a note in the pod result.

This commit is contained in:
Gaetan Delannay 2014-06-23 12:54:32 +02:00
parent 114223a114
commit f8f3c0e865
6 changed files with 75 additions and 61 deletions

View file

@ -450,6 +450,9 @@ class BaseMixin:
if isNew and initiator: if isNew and initiator:
return self.goto(initiator.getUrl(page=initiatorPage, nav='')) return self.goto(initiator.getUrl(page=initiatorPage, nav=''))
return self.goto(obj.getUrl()) return self.goto(obj.getUrl())
# Get the current page name. We keep it in "pageName" because rq['page']
# can be changed by m_getAppyPhases called below.
pageName = rq['page']
if buttonClicked == 'previous': if buttonClicked == 'previous':
# Go to the previous page for this object. # Go to the previous page for this object.
# We recompute the list of phases and pages because things # We recompute the list of phases and pages because things
@ -459,7 +462,7 @@ class BaseMixin:
# pages may not be available in "edit" mode, so we return the edit # pages may not be available in "edit" mode, so we return the edit
# or view pages depending on page.show. # or view pages depending on page.show.
phaseObj = self.getAppyPhases(currentOnly=True, layoutType='edit') phaseObj = self.getAppyPhases(currentOnly=True, layoutType='edit')
pageName, pageInfo = phaseObj.getPreviousPage(rq['page']) pageName, pageInfo = phaseObj.getPreviousPage(pageName)
if pageName: if pageName:
# Return to the edit or view page? # Return to the edit or view page?
if pageInfo.showOnEdit: if pageInfo.showOnEdit:
@ -476,10 +479,8 @@ class BaseMixin:
return self.goto(obj.getUrl(inPopup=inPopup)) return self.goto(obj.getUrl(inPopup=inPopup))
if buttonClicked == 'next': if buttonClicked == 'next':
# Go to the next page for this object. # Go to the next page for this object.
# We remember page name, because the next method may set a new
# current page if the current one is not visible anymore.
phaseObj = self.getAppyPhases(currentOnly=True, layoutType='edit') phaseObj = self.getAppyPhases(currentOnly=True, layoutType='edit')
pageName, pageInfo = phaseObj.getNextPage(rq['page']) pageName, pageInfo = phaseObj.getNextPage(pageName)
if pageName: if pageName:
# Return to the edit or view page? # Return to the edit or view page?
if pageInfo.showOnEdit: if pageInfo.showOnEdit:

View file

@ -46,8 +46,6 @@ class BufferAction:
# content. If 'from', we must dump what comes from the 'from' part of # content. If 'from', we must dump what comes from the 'from' part of
# the action (='fromExpr') # the action (='fromExpr')
self.fromExpr = fromExpr self.fromExpr = fromExpr
# When an error occurs, must we raise it or write it into the buffer?
self.raiseErrors = not self.buffer.pod
# Several actions may co-exist for the same buffer, as a chain of # Several actions may co-exist for the same buffer, as a chain of
# BufferAction instances, defined via the following attribute. # BufferAction instances, defined via the following attribute.
self.subAction = None self.subAction = None
@ -59,8 +57,8 @@ class BufferAction:
def manageError(self, result, context, errorMessage, dumpTb=True): def manageError(self, result, context, errorMessage, dumpTb=True):
'''Manage the encountered error: dump it into the buffer or raise an '''Manage the encountered error: dump it into the buffer or raise an
exception if self.raiseErrors is True.''' exception.'''
if self.raiseErrors: if self.buffer.env.raiseOnError:
if not self.buffer.pod: if not self.buffer.pod:
# Add in the error message the line nb where the errors occurs # Add in the error message the line nb where the errors occurs
# within the PX. # within the PX.

View file

@ -224,7 +224,11 @@ class FileBuffer(Buffer):
if escape: self.dumpContent(res) if escape: self.dumpContent(res)
else: self.write(res) else: self.write(res)
except Exception, e: except Exception, e:
PodError.dump(self, EVAL_EXPR_ERROR % (expression, e), dumpTb=False) if not self.env.raiseOnError:
PodError.dump(self, EVAL_EXPR_ERROR % (expression, e),
dumpTb=False)
else:
raise Exception(EVAL_EXPR_ERROR % (expression, e))
def addAttributes(self): def addAttributes(self):
# Into a FileBuffer, it is not possible to insert Attributes. Every # Into a FileBuffer, it is not possible to insert Attributes. Every
@ -666,10 +670,10 @@ class MemoryBuffer(Buffer):
if escape: result.dumpContent(res) if escape: result.dumpContent(res)
else: result.write(res) else: result.write(res)
except Exception, e: except Exception, e:
if self.pod: if not self.env.raiseOnError:
PodError.dump(result, EVAL_EXPR_ERROR % ( PodError.dump(result, EVAL_EXPR_ERROR % (
evalEntry.expr, e), dumpTb=False) evalEntry.expr, e), dumpTb=False)
else: # px else:
raise Exception(EVAL_EXPR_ERROR %(evalEntry.expr,e)) raise Exception(EVAL_EXPR_ERROR %(evalEntry.expr,e))
elif isinstance(evalEntry, Attributes) or \ elif isinstance(evalEntry, Attributes) or \
isinstance(evalEntry, Attribute): isinstance(evalEntry, Attribute):

View file

@ -107,6 +107,9 @@ class PodEnvironment(OdfEnvironment):
self.currentOdsHook = None self.currentOdsHook = None
# Names of some tags, that we will compute after namespace propagation # Names of some tags, that we will compute after namespace propagation
self.tags = None self.tags = None
# When an error occurs, must we raise it or write it into he current
# buffer?
self.raiseOnError = None # Will be initialized by PodParser.__init__
def getTable(self): def getTable(self):
'''Gets the currently parsed table.''' '''Gets the currently parsed table.'''
@ -219,6 +222,7 @@ class PodEnvironment(OdfEnvironment):
class PodParser(OdfParser): class PodParser(OdfParser):
def __init__(self, env, caller): def __init__(self, env, caller):
OdfParser.__init__(self, env, caller) OdfParser.__init__(self, env, caller)
env.raiseOnError = caller.raiseOnError
def endDocument(self): def endDocument(self):
self.env.currentBuffer.content.close() self.env.currentBuffer.content.close()

View file

@ -101,21 +101,21 @@ class Renderer:
def __init__(self, template, context, result, pythonWithUnoPath=None, def __init__(self, template, context, result, pythonWithUnoPath=None,
ooPort=2002, stylesMapping={}, forceOoCall=False, ooPort=2002, stylesMapping={}, forceOoCall=False,
finalizeFunction=None, overwriteExisting=False, finalizeFunction=None, overwriteExisting=False,
imageResolver=None): raiseOnError=False, imageResolver=None):
'''This Python Open Document Renderer (PodRenderer) loads a document '''This Python Open Document Renderer (PodRenderer) loads a document
template (p_template) which is an ODT file with some elements template (p_template) which is an ODT file with some elements written
written in Python. Based on this template and some Python objects in Python. Based on this template and some Python objects defined in
defined in p_context, the renderer generates an ODT file p_context, the renderer generates an ODT file (p_result) that
(p_result) that instantiates the p_template and fills it with objects instantiates the p_template and fills it with objects from the
from the p_context. p_context.
- If p_result does not end with .odt, the Renderer - If p_result does not end with .odt, the Renderer will call
will call LibreOffice to perform a conversion. If p_forceOoCall is LibreOffice to perform a conversion. If p_forceOoCall is True, even
True, even if p_result ends with .odt, LibreOffice will be called, not if p_result ends with .odt, LibreOffice will be called, not for
for performing a conversion, but for updating some elements like performing a conversion, but for updating some elements like indexes
indexes (table of contents, etc) and sections containing links to (table of contents, etc) and sections containing links to externa
external files (which is the case, for example, if you use the files (which is the case, for example, if you use the default
default function "document"). function "document").
- If the Python interpreter which runs the current script is not - If the Python interpreter which runs the current script is not
UNO-enabled, this script will run, in another process, a UNO-enabled UNO-enabled, this script will run, in another process, a UNO-enabled
@ -137,6 +137,10 @@ class Renderer:
the result file. Else, an exception will be thrown if the result file the result file. Else, an exception will be thrown if the result file
already exists. already exists.
- If p_raiseOnError is False (the default value), any error encountered
during the generation of the result file will be dumped into it, as
a Python traceback within a note. Else, the error will be raised.
- p_imageResolver allows POD to retrieve images, from "img" tags within - p_imageResolver allows POD to retrieve images, from "img" tags within
XHTML content. Indeed, POD may not be able (ie, may not have the XHTML content. Indeed, POD may not be able (ie, may not have the
permission to) perform a HTTP GET on those images. Currently, the permission to) perform a HTTP GET on those images. Currently, the
@ -156,6 +160,7 @@ class Renderer:
self.forceOoCall = forceOoCall self.forceOoCall = forceOoCall
self.finalizeFunction = finalizeFunction self.finalizeFunction = finalizeFunction
self.overwriteExisting = overwriteExisting self.overwriteExisting = overwriteExisting
self.raiseOnError = raiseOnError
self.imageResolver = imageResolver self.imageResolver = imageResolver
# Remember potential files or images that will be included through # Remember potential files or images that will be included through
# "do ... from document" statements: we will need to declare them in # "do ... from document" statements: we will need to declare them in
@ -424,17 +429,20 @@ class Renderer:
# Public interface # Public interface
def run(self): def run(self):
'''Renders the result.''' '''Renders the result.'''
# Remember which parser is running try:
self.currentParser = self.contentParser # Remember which parser is running
# Create the resulting content.xml self.currentParser = self.contentParser
self.currentParser.parse(self.contentXml) # Create the resulting content.xml
self.currentParser = self.stylesParser self.currentParser.parse(self.contentXml)
# Create the resulting styles.xml self.currentParser = self.stylesParser
self.currentParser.parse(self.stylesXml) # Create the resulting styles.xml
# Patch META-INF/manifest.xml self.currentParser.parse(self.stylesXml)
self.patchManifest() # Patch META-INF/manifest.xml
# Re-zip the result self.patchManifest()
self.finalize() # Re-zip the result
self.finalize()
finally:
FolderDeleter.delete(self.tempFolder)
def getStyles(self): def getStyles(self):
'''Returns a dict of the styles that are defined into the template.''' '''Returns a dict of the styles that are defined into the template.'''
@ -582,31 +590,28 @@ class Renderer:
resultZip.writestr(zInfo, '') resultZip.writestr(zInfo, '')
resultZip.close() resultZip.close()
resultType = os.path.splitext(self.result)[1].strip('.') resultType = os.path.splitext(self.result)[1].strip('.')
try: if (resultType in self.templateTypes) and not self.forceOoCall:
if (resultType in self.templateTypes) and not self.forceOoCall: # Simply move the ODT result to the result
# Simply move the ODT result to the result os.rename(resultName, self.result)
os.rename(resultName, self.result) else:
else: if resultType not in FILE_TYPES:
if resultType not in FILE_TYPES: raise PodError(BAD_RESULT_TYPE % (
raise PodError(BAD_RESULT_TYPE % ( self.result, FILE_TYPES.keys()))
self.result, FILE_TYPES.keys())) # Call LibreOffice to perform the conversion or document update.
# Call LibreOffice to perform the conversion or document update. output = self.callLibreOffice(resultName, resultType)
output = self.callLibreOffice(resultName, resultType) # I (should) have the result. Move it to the correct name.
# I (should) have the result. Move it to the correct name. resPrefix = os.path.splitext(resultName)[0]
resPrefix = os.path.splitext(resultName)[0] if resultType in self.templateTypes:
if resultType in self.templateTypes: # converter.py has (normally!) created a second file
# converter.py has (normally!) created a second file # suffixed .res.[resultType]
# suffixed .res.[resultType] finalResultName = '%s.res.%s' % (resPrefix, resultType)
finalResultName = '%s.res.%s' % (resPrefix, resultType)
if not os.path.exists(finalResultName):
finalResultName = resultName
# In this case OO in server mode could not be called to
# update indexes, sections, etc.
else:
finalResultName = '%s.%s' % (resPrefix, resultType)
if not os.path.exists(finalResultName): if not os.path.exists(finalResultName):
raise PodError(CONVERT_ERROR % output) finalResultName = resultName
os.rename(finalResultName, self.result) # In this case OO in server mode could not be called to
finally: # update indexes, sections, etc.
FolderDeleter.delete(self.tempFolder) else:
finalResultName = '%s.%s' % (resPrefix, resultType)
if not os.path.exists(finalResultName):
raise PodError(CONVERT_ERROR % output)
os.rename(finalResultName, self.result)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -30,6 +30,8 @@ class PxEnvironment(XmlEnvironment):
# XmlParser for better performance. Indeed, the base parser and env # XmlParser for better performance. Indeed, the base parser and env
# process namespaces, and we do not need this for the PX parser. # process namespaces, and we do not need this for the PX parser.
self.currentElem = None self.currentElem = None
# Exceptions are always raised (for pod, it is not the case)
self.raiseOnError = True
def addSubBuffer(self): def addSubBuffer(self):
subBuffer = self.currentBuffer.addSubBuffer() subBuffer = self.currentBuffer.addSubBuffer()