[gen] First draft of using POD ODS (Calc) templates.

This commit is contained in:
Gaetan Delannay 2013-01-31 00:11:24 +01:00
parent 47bcf87a5c
commit ad94fee755
8 changed files with 674 additions and 584 deletions

View file

@ -139,9 +139,10 @@ class Buffer:
def getLength(self): pass # To be overridden def getLength(self): pass # To be overridden
def dumpStartElement(self, elem, attrs={}): def dumpStartElement(self, elem, attrs={}, ignoreAttrs=()):
self.write('<%s' % elem) self.write('<%s' % elem)
for name, value in attrs.items(): for name, value in attrs.items():
if ignoreAttrs and (name in ignoreAttrs): continue
self.write(' %s=%s' % (name, quoteattr(value))) self.write(' %s=%s' % (name, quoteattr(value)))
self.write('>') self.write('>')

View file

@ -108,6 +108,8 @@ class PodEnvironment(OdfEnvironment):
self.ifActions = [] self.ifActions = []
# Currently walked named "if" actions # Currently walked named "if" actions
self.namedIfActions = {} #~{s_statementName: IfAction}~ self.namedIfActions = {} #~{s_statementName: IfAction}~
# Currently parsed expression within an ODS template
self.currentOdsExpression = None
def getTable(self): def getTable(self):
'''Gets the currently parsed table.''' '''Gets the currently parsed table.'''
@ -208,14 +210,36 @@ class PodParser(OdfParser):
ns = e.onStartElement() ns = e.onStartElement()
officeNs = ns[e.NS_OFFICE] officeNs = ns[e.NS_OFFICE]
textNs = ns[e.NS_TEXT] textNs = ns[e.NS_TEXT]
tableNs = ns[e.NS_TABLE]
if elem in e.ignorableElements: if elem in e.ignorableElements:
e.state = e.IGNORING e.state = e.IGNORING
elif elem == ('%s:annotation' % officeNs): elif elem == ('%s:annotation' % officeNs):
# Be it in an ODT or ODS template, an annotation is considered to
# contain a POD statement.
e.state = e.READING_STATEMENT e.state = e.READING_STATEMENT
elif (elem == ('%s:change-start' % textNs)) or \ elif (elem == ('%s:change-start' % textNs)) or \
(elem == ('%s:conditional-text' % textNs)): (elem == ('%s:conditional-text' % textNs)):
# In an ODT template, any text in track-changes or any conditional
# field is considered to contain a POD expression.
e.state = e.READING_EXPRESSION e.state = e.READING_EXPRESSION
e.exprHasStyle = False e.exprHasStyle = False
elif (elem == ('%s:table-cell' % tableNs)) and \
attrs.has_key('%s:formula' % tableNs) and \
(attrs['%s:value-type' % officeNs] == 'string'):
# In an ODS template, any cell containing a formula of type "string"
# is considered to contain a POD expression. But here it is a
# special case: we need to dump the cell; the expression is not
# directly contained within this cell; the expression will be
# contained in the next inner paragraph. So we must here dump the
# cell, but without some attributes, because the "formula" will be
# converted to the result of evaluating the POD expression.
if e.mode == e.ADD_IN_SUBBUFFER:
e.addSubBuffer()
e.currentBuffer.addElement(e.currentElem.name)
e.currentBuffer.dumpStartElement(elem, attrs,
ignoreAttrs=('%s:formula'%tableNs, '%s:string-value'%officeNs))
# We already have the POD expression: remember it on the env.
e.currentOdsExpression = attrs['%s:string-value' % officeNs]
else: else:
if e.state == e.IGNORING: if e.state == e.IGNORING:
pass pass
@ -258,6 +282,11 @@ class PodParser(OdfParser):
if e.state == e.IGNORING: if e.state == e.IGNORING:
pass pass
elif e.state == e.READING_CONTENT: elif e.state == e.READING_CONTENT:
# Dump the ODS POD expression if any
if e.currentOdsExpression:
e.currentBuffer.addExpression(e.currentOdsExpression)
e.currentOdsExpression = None
# Dump the ending tag
e.currentBuffer.dumpEndElement(elem) e.currentBuffer.dumpEndElement(elem)
if elem in e.impactableElements: if elem in e.impactableElements:
if isinstance(e.currentBuffer, MemoryBuffer): if isinstance(e.currentBuffer, MemoryBuffer):
@ -302,6 +331,11 @@ class PodParser(OdfParser):
if e.state == e.IGNORING: if e.state == e.IGNORING:
pass pass
elif e.state == e.READING_CONTENT: elif e.state == e.READING_CONTENT:
if e.currentOdsExpression:
# Do not write content if we have encountered an ODS expression:
# we will replace this content with the expression's result.
pass
else:
e.currentBuffer.dumpContent(content) e.currentBuffer.dumpContent(content)
elif e.state == e.READING_STATEMENT: elif e.state == e.READING_STATEMENT:
if e.currentElem.elem.startswith(e.namespaces[e.NS_TEXT]): if e.currentElem.elem.startswith(e.namespaces[e.NS_TEXT]):

View file

@ -494,7 +494,8 @@ class Renderer:
except Exception, e: except Exception, e:
print WARNING_FINALIZE_ERROR % str(e) print WARNING_FINALIZE_ERROR % str(e)
# Re-zip the result. # Re-zip the result.
resultOdtName = os.path.join(self.tempFolder, 'result.odt') resExt = os.path.splitext(self.template)[1]
resultOdtName = os.path.join(self.tempFolder, 'result%s' % resExt)
try: try:
resultOdt = zipfile.ZipFile(resultOdtName,'w', zipfile.ZIP_DEFLATED) resultOdt = zipfile.ZipFile(resultOdtName,'w', zipfile.ZIP_DEFLATED)
except RuntimeError: except RuntimeError:

View file

@ -78,6 +78,7 @@ class AnnotationsRemover(OdfParser):
class Test(appy.shared.test.Test): class Test(appy.shared.test.Test):
'''Abstract test class.''' '''Abstract test class.'''
interestingOdtContent = ('content.xml', 'styles.xml') interestingOdtContent = ('content.xml', 'styles.xml')
def __init__(self, testData, testDescription, testFolder, config, flavour): def __init__(self, testData, testDescription, testFolder, config, flavour):
appy.shared.test.Test.__init__(self, testData, testDescription, appy.shared.test.Test.__init__(self, testData, testDescription,
testFolder, config, flavour) testFolder, config, flavour)
@ -85,6 +86,7 @@ class Test(appy.shared.test.Test):
self.contextsFolder = os.path.join(self.testFolder, 'contexts') self.contextsFolder = os.path.join(self.testFolder, 'contexts')
self.resultsFolder = os.path.join(self.testFolder, 'results') self.resultsFolder = os.path.join(self.testFolder, 'results')
self.result = None self.result = None
def getContext(self, contextName): def getContext(self, contextName):
'''Gets the objects that are in the context.''' '''Gets the objects that are in the context.'''
contextPy = os.path.join(self.contextsFolder, contextName + '.py') contextPy = os.path.join(self.contextsFolder, contextName + '.py')
@ -98,13 +100,20 @@ class Test(appy.shared.test.Test):
if not elem.startswith('__'): if not elem.startswith('__'):
exec 'res[elem] = %s.%s' % (contextPkg, elem) exec 'res[elem] = %s.%s' % (contextPkg, elem)
return res return res
def do(self): def do(self):
self.result = os.path.join( self.result = os.path.join(
self.tempFolder, '%s.%s' % ( self.tempFolder, '%s.%s' % (
self.data['Name'], self.data['Result'])) self.data['Name'], self.data['Result']))
# Get the path to the template to use for this test # Get the path to the template to use for this test
if self.data['Template'].endswith('.ods'):
suffix = ''
else:
# For ODT, which is the most frequent case, no need to specify the
# file extension.
suffix = '.odt'
template = os.path.join(self.templatesFolder, template = os.path.join(self.templatesFolder,
self.data['Template'] + '.odt') self.data['Template'] + suffix)
if not os.path.exists(template): if not os.path.exists(template):
raise TesterError(TEMPLATE_NOT_FOUND % template) raise TesterError(TEMPLATE_NOT_FOUND % template)
# Get the context # Get the context
@ -127,6 +136,7 @@ class Test(appy.shared.test.Test):
# os.mkdir(tempFolder2) # os.mkdir(tempFolder2)
#print 'Result is', self.result, 'temp folder 2 is', tempFolder2 #print 'Result is', self.result, 'temp folder 2 is', tempFolder2
#shutil.copy(self.result, tempFolder2) #shutil.copy(self.result, tempFolder2)
def getOdtContent(self, odtFile): def getOdtContent(self, odtFile):
'''Creates in the temp folder content.xml and styles.xml extracted '''Creates in the temp folder content.xml and styles.xml extracted
from p_odtFile.''' from p_odtFile.'''
@ -151,9 +161,13 @@ class Test(appy.shared.test.Test):
OdfEnvironment(), self) OdfEnvironment(), self)
annotationsRemover.parse(fileContent) annotationsRemover.parse(fileContent)
fileContent = annotationsRemover.getResult() fileContent = annotationsRemover.getResult()
try:
f.write(fileContent.encode('utf-8')) f.write(fileContent.encode('utf-8'))
except UnicodeDecodeError:
f.write(fileContent)
f.close() f.close()
zipFile.close() zipFile.close()
def checkResult(self): def checkResult(self):
'''r_ is False if the test succeeded.''' '''r_ is False if the test succeeded.'''
# Get styles.xml and content.xml from the actual result # Get styles.xml and content.xml from the actual result
@ -161,7 +175,7 @@ class Test(appy.shared.test.Test):
self.getOdtContent(self.result) self.getOdtContent(self.result)
# Get styles.xml and content.xml from the expected result # Get styles.xml and content.xml from the expected result
expectedResult = os.path.join(self.resultsFolder, expectedResult = os.path.join(self.resultsFolder,
self.data['Name'] + '.odt') self.data['Name'] + '.' + self.data['Result'])
if not os.path.exists(expectedResult): if not os.path.exists(expectedResult):
raise TesterError(EXPECTED_RESULT_NOT_FOUND % expectedResult) raise TesterError(EXPECTED_RESULT_NOT_FOUND % expectedResult)
self.getOdtContent(expectedResult) self.getOdtContent(expectedResult)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
data = [ \
['1', 2, 'three'],
['A', 'BB', 'CCC']
]

Binary file not shown.

Binary file not shown.