[gen] Wrapper.reindex: allow to specify attribute 'fields' containing the list of fields that must be reindexed. If not given, all object fields are reindexed. [pod] POD ODS templates: into POD results from ODS templates, Python expressions that produce ints, floats or dates (Zope DateTime only for the moment) produce cells with typed values.
This commit is contained in:
parent
43261fde60
commit
2307a284cc
|
@ -372,14 +372,20 @@ class AbstractWrapper(object):
|
|||
exec expression
|
||||
return ctx
|
||||
|
||||
def reindex(self):
|
||||
def reindex(self, fields=None, unindex=False):
|
||||
'''Asks a direct object reindexing. In most cases you don't have to
|
||||
reindex objects "manually" with this method. When an object is
|
||||
modified after some user action has been performed, Appy reindexes
|
||||
this object automatically. But if your code modifies other objects,
|
||||
Appy may not know that they must be reindexed, too. So use this
|
||||
method in those cases.'''
|
||||
self.o.reindex()
|
||||
method in those cases.
|
||||
'''
|
||||
if fields:
|
||||
# Get names of indexes from field names.
|
||||
indexes = [Search.getIndexName(name) for name in fields]
|
||||
else:
|
||||
indexes = None
|
||||
self.o.reindex(indexes=indexes, unindex=unindex)
|
||||
|
||||
def export(self, at='string', format='xml', include=None, exclude=None):
|
||||
'''Creates an "exportable" version of this object. p_format is "xml" by
|
||||
|
|
|
@ -139,12 +139,24 @@ class Buffer:
|
|||
|
||||
def getLength(self): pass # To be overridden
|
||||
|
||||
def dumpStartElement(self, elem, attrs={}, ignoreAttrs=()):
|
||||
def dumpStartElement(self, elem, attrs={}, ignoreAttrs=(),
|
||||
insertAttributesHook=False):
|
||||
'''Inserts into this buffer the start tag p_elem, with its p_attrs,
|
||||
excepted those listed in p_ignoreAttrs. If p_insertAttributesHook
|
||||
is True (works only for MemoryBuffers), we will insert an Attributes
|
||||
instance at the end of the list of dumped attributes, in order to be
|
||||
able, when evaluating the buffer, to dump additional attributes, not
|
||||
known at this dump time.'''
|
||||
self.write('<%s' % elem)
|
||||
for name, value in attrs.items():
|
||||
if ignoreAttrs and (name in ignoreAttrs): continue
|
||||
self.write(' %s=%s' % (name, quoteattr(value)))
|
||||
if insertAttributesHook:
|
||||
res = self.addAttributes()
|
||||
else:
|
||||
res = None
|
||||
self.write('>')
|
||||
return res
|
||||
|
||||
def dumpEndElement(self, elem):
|
||||
self.write('</%s>' % elem)
|
||||
|
@ -179,12 +191,21 @@ class FileBuffer(Buffer):
|
|||
except UnicodeDecodeError:
|
||||
self.content.write(something)
|
||||
|
||||
def addExpression(self, expression):
|
||||
def addExpression(self, expression, tiedHook=None):
|
||||
# At 2013-02-06, this method was not called within the whole test suite.
|
||||
try:
|
||||
self.dumpContent(Expression(expression).evaluate(self.env.context))
|
||||
except Exception, e:
|
||||
PodError.dump(self, EVAL_EXPR_ERROR % (expression, e), dumpTb=False)
|
||||
|
||||
def addAttributes(self):
|
||||
# Into a FileBuffer, it is not possible to insert Attributes. Every
|
||||
# Attributes instance is tied to an Expression; because dumping
|
||||
# expressions directly into FileBuffer instances seems to be a rather
|
||||
# theorical case (see comment inside the previous method), it does not
|
||||
# seem to be a real problem.
|
||||
pass
|
||||
|
||||
def pushSubBuffer(self, subBuffer): pass
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -298,14 +319,21 @@ class MemoryBuffer(Buffer):
|
|||
# Remember where this cell is in the table
|
||||
newElem.colIndex = newElem.tableInfo.curColIndex
|
||||
|
||||
def addExpression(self, expression):
|
||||
def addExpression(self, expression, tiedHook=None):
|
||||
# Create the POD expression
|
||||
expr = Expression(expression)
|
||||
expr.expr = expression
|
||||
if tiedHook: tiedHook.tiedExpression = expr
|
||||
self.elements[self.getLength()] = expr
|
||||
self.content += u' '# To be sure that an expr and an elem can't be found
|
||||
# at the same index in the buffer.
|
||||
|
||||
def addAttributes(self):
|
||||
# Create the Attributes instance
|
||||
attrs = Attributes(self.env)
|
||||
self.elements[self.getLength()] = attrs
|
||||
self.content += u' '
|
||||
return attrs
|
||||
|
||||
def createAction(self, statementGroup):
|
||||
'''Tries to create an action based on p_statementGroup. If the statement
|
||||
is not correct, r_ is -1. Else, r_ is the index of the element within
|
||||
|
@ -547,6 +575,8 @@ class MemoryBuffer(Buffer):
|
|||
except Exception, e:
|
||||
PodError.dump(result, EVAL_EXPR_ERROR % (
|
||||
evalEntry.expr, e), dumpTb=False)
|
||||
elif isinstance(evalEntry, Attributes):
|
||||
result.write(evalEntry.evaluate(self.env.context))
|
||||
else: # It is a subBuffer
|
||||
if evalEntry.action:
|
||||
evalEntry.action.execute()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA.
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
from xml.sax.saxutils import quoteattr
|
||||
from appy.shared.xml_parser import XmlElement
|
||||
from appy.pod.odf_parser import OdfEnvironment as ns
|
||||
from appy.pod import PodError
|
||||
|
@ -71,11 +72,38 @@ class Table(PodElement):
|
|||
self.tableInfo = None # ~OdTable~
|
||||
|
||||
class Expression(PodElement):
|
||||
'''Instances of this class represent Python expressions that are inserted
|
||||
into a POD template.'''
|
||||
OD = None
|
||||
def __init__(self, pyExpr):
|
||||
# The Python expression
|
||||
self.expr = pyExpr
|
||||
# We will store here the expression's true result (before being
|
||||
# converted to a string)
|
||||
self.result = None
|
||||
# This boolean indicates if this Expression instance has already been
|
||||
# evaluated or not. Expressions which are tied to attribute hooks are
|
||||
# already evaluated when the tied hook is evaluated: this boolean
|
||||
# prevents the expression from being evaluated twice.
|
||||
self.evaluated = False
|
||||
|
||||
def evaluate(self, context):
|
||||
res = eval(self.expr, context)
|
||||
'''Evaluates the Python expression (self.expr) with a given
|
||||
p_context.'''
|
||||
# Evaluate the expression, or get it from self.result if it has already
|
||||
# been computed.
|
||||
if self.evaluated:
|
||||
res = self.result
|
||||
# It can happen only once, to ask to evaluate an expression that
|
||||
# was already evaluated (from the tied hook). We reset here the
|
||||
# boolean "evaluated" to allow for the next evaluation, probably
|
||||
# with another context.
|
||||
self.evaluated = False
|
||||
else:
|
||||
# Evaluates the Python expression
|
||||
res = self.result = eval(self.expr, context)
|
||||
# Converts the expression result to a string that can be inserted into
|
||||
# the POD result.
|
||||
if res == None:
|
||||
res = u''
|
||||
elif isinstance(res, str):
|
||||
|
@ -85,4 +113,53 @@ class Expression(PodElement):
|
|||
else:
|
||||
res = unicode(res)
|
||||
return res
|
||||
|
||||
class Attributes(PodElement):
|
||||
'''Represents a bunch of XML attributes that will be dumped for a given tag
|
||||
in the result.'''
|
||||
OD = None
|
||||
floatTypes = ('int', 'long', 'float')
|
||||
dateTypes = ('DateTime',)
|
||||
|
||||
def __init__(self, env):
|
||||
self.attrs = {}
|
||||
# Depending on the result of a tied expression, we will dump, for
|
||||
# another tag, the series of attrs that this instance represents.
|
||||
self.tiedExpression = None
|
||||
# We will need the env to get the full names of attributes to dump.
|
||||
self.env = env
|
||||
|
||||
def computeAttributes(self, expr):
|
||||
'''p_expr has been evaluated: its result is in expr.result. Depending
|
||||
on its type, we will dump the corresponding attributes in
|
||||
self.attrs.'''
|
||||
exprType = expr.result.__class__.__name__
|
||||
tags = self.env.tags
|
||||
attrs = self.attrs
|
||||
if exprType in self.floatTypes:
|
||||
attrs[tags['value-type']] = 'float'
|
||||
attrs[tags['value']] = str(expr.result)
|
||||
elif exprType in self.dateTypes:
|
||||
attrs[tags['value-type']] = 'date'
|
||||
attrs[tags['value']] = expr.result.strftime('%Y-%m-%d')
|
||||
else:
|
||||
attrs[tags['value-type']] = 'string'
|
||||
|
||||
def evaluate(self, context):
|
||||
# Evaluate first the tied expression, in order to determine its type.
|
||||
try:
|
||||
self.tiedExpression.evaluate(context)
|
||||
self.evaluated = True
|
||||
except Exception, e:
|
||||
# Don't set "evaluated" to True. This way, when the buffer will
|
||||
# evaluate the expression directly, we will really evaluate it, so
|
||||
# the error will be dumped into the pod result.
|
||||
pass
|
||||
# Analyse the return type of the expression.
|
||||
self.computeAttributes(self.tiedExpression)
|
||||
# Now, self.attrs has been populated. Transform it into a string.
|
||||
res = ''
|
||||
for name, value in self.attrs.iteritems():
|
||||
res += ' %s=%s' % (name, quoteattr(value))
|
||||
return res
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -110,6 +110,7 @@ class PodEnvironment(OdfEnvironment):
|
|||
self.namedIfActions = {} #~{s_statementName: IfAction}~
|
||||
# Currently parsed expression within an ODS template
|
||||
self.currentOdsExpression = None
|
||||
self.currentOdsHook = None
|
||||
# Names of some tags, that we will compute after namespace propagation
|
||||
self.tags = None
|
||||
|
||||
|
@ -204,6 +205,7 @@ class PodEnvironment(OdfEnvironment):
|
|||
'table-cell': '%s:table-cell' % ns[self.NS_TABLE],
|
||||
'formula': '%s:formula' % ns[self.NS_TABLE],
|
||||
'value-type': '%s:value-type' % ns[self.NS_OFFICE],
|
||||
'value': '%s:value' % ns[self.NS_OFFICE],
|
||||
'string-value': '%s:string-value' % ns[self.NS_OFFICE],
|
||||
'span': '%s:span' % ns[self.NS_TEXT],
|
||||
'number-columns-spanned': '%s:number-columns-spanned' % \
|
||||
|
@ -246,10 +248,12 @@ class PodParser(OdfParser):
|
|||
e.exprHasStyle = False
|
||||
elif (elem == e.tags['table-cell']) and \
|
||||
attrs.has_key(e.tags['formula']) and \
|
||||
(attrs[e.tags['value-type']] == 'string'):
|
||||
(attrs[e.tags['value-type']] == 'string') and \
|
||||
attrs[e.tags['formula']].startswith('of:="'):
|
||||
# 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
|
||||
# and whose content is expressed as a string between double quotes
|
||||
# (="...") 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
|
||||
|
@ -257,10 +261,13 @@ class PodParser(OdfParser):
|
|||
if e.mode == e.ADD_IN_SUBBUFFER:
|
||||
e.addSubBuffer()
|
||||
e.currentBuffer.addElement(e.currentElem.name)
|
||||
e.currentBuffer.dumpStartElement(elem, attrs,
|
||||
ignoreAttrs=(e.tags['formula'], e.tags['string-value']))
|
||||
hook = e.currentBuffer.dumpStartElement(elem, attrs,
|
||||
ignoreAttrs=(e.tags['formula'], e.tags['string-value'],
|
||||
e.tags['value-type']),
|
||||
insertAttributesHook=True)
|
||||
# We already have the POD expression: remember it on the env.
|
||||
e.currentOdsExpression = attrs[e.tags['string-value']]
|
||||
e.currentOdsHook = hook
|
||||
else:
|
||||
if e.state == e.IGNORING:
|
||||
pass
|
||||
|
@ -304,8 +311,10 @@ class PodParser(OdfParser):
|
|||
elif e.state == e.READING_CONTENT:
|
||||
# Dump the ODS POD expression if any
|
||||
if e.currentOdsExpression:
|
||||
e.currentBuffer.addExpression(e.currentOdsExpression)
|
||||
e.currentBuffer.addExpression(e.currentOdsExpression,
|
||||
tiedHook=e.currentOdsHook)
|
||||
e.currentOdsExpression = None
|
||||
e.currentOdsHook = None
|
||||
# Dump the ending tag
|
||||
e.currentBuffer.dumpEndElement(elem)
|
||||
if elem in e.impactableElements:
|
||||
|
|
3617
pod/test/Tests.rtf
3617
pod/test/Tests.rtf
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue