[pod] Added the possibility to define several variables, in 'with' statements, separated by ';'.
This commit is contained in:
parent
da1f2699cd
commit
d5296ba321
|
@ -53,28 +53,38 @@ class BufferAction:
|
||||||
# We store the result of evaluation of expr and fromExpr
|
# We store the result of evaluation of expr and fromExpr
|
||||||
self.exprResult = None
|
self.exprResult = None
|
||||||
self.fromExprResult = None
|
self.fromExprResult = None
|
||||||
|
|
||||||
def writeError(self, errorMessage, dumpTb=True):
|
def writeError(self, errorMessage, dumpTb=True):
|
||||||
# Empty the buffer
|
# Empty the buffer
|
||||||
self.buffer.__init__(self.buffer.env, self.buffer.parent)
|
self.buffer.__init__(self.buffer.env, self.buffer.parent)
|
||||||
PodError.dump(self.buffer, errorMessage, withinElement=self.elem,
|
PodError.dump(self.buffer, errorMessage, withinElement=self.elem,
|
||||||
dumpTb=dumpTb)
|
dumpTb=dumpTb)
|
||||||
self.buffer.evaluate()
|
self.buffer.evaluate()
|
||||||
|
|
||||||
|
def evaluateExpression(self, expr):
|
||||||
|
'''Evaluates expression p_expr with the current context. Returns a tuple
|
||||||
|
(result, errorOccurred).'''
|
||||||
|
try:
|
||||||
|
res = eval(expr, self.buffer.env.context)
|
||||||
|
error = False
|
||||||
|
except:
|
||||||
|
res = None
|
||||||
|
self.writeError(EVAL_ERROR % expr)
|
||||||
|
error = True
|
||||||
|
return res, error
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
# Check that if minus is set, we have an element which can accept it
|
# Check that if minus is set, we have an element which can accept it
|
||||||
if self.minus and isinstance(self.elem, Table) and \
|
if self.minus and isinstance(self.elem, Table) and \
|
||||||
(not self.elem.tableInfo.isOneCell()):
|
(not self.elem.tableInfo.isOneCell()):
|
||||||
self.writeError(TABLE_NOT_ONE_CELL % self.expr)
|
self.writeError(TABLE_NOT_ONE_CELL % self.expr)
|
||||||
else:
|
else:
|
||||||
errorOccurred = False
|
error = False
|
||||||
if self.expr:
|
if self.expr:
|
||||||
try:
|
self.exprResult, error = self.evaluateExpression(self.expr)
|
||||||
self.exprResult = eval(self.expr, self.buffer.env.context)
|
if not error:
|
||||||
except:
|
|
||||||
self.exprResult = None
|
|
||||||
self.writeError(EVAL_ERROR % self.expr)
|
|
||||||
errorOccurred = True
|
|
||||||
if not errorOccurred:
|
|
||||||
self.do()
|
self.do()
|
||||||
|
|
||||||
def evaluateBuffer(self):
|
def evaluateBuffer(self):
|
||||||
if self.source == 'buffer':
|
if self.source == 'buffer':
|
||||||
self.buffer.evaluate(removeMainElems = self.minus)
|
self.buffer.evaluate(removeMainElems = self.minus)
|
||||||
|
@ -243,27 +253,48 @@ class NullAction(BufferAction):
|
||||||
def do(self):
|
def do(self):
|
||||||
self.evaluateBuffer()
|
self.evaluateBuffer()
|
||||||
|
|
||||||
class VariableAction(BufferAction):
|
class VariablesAction(BufferAction):
|
||||||
'''Action that allows to define a variable somewhere in the template.'''
|
'''Action that allows to define a set of variables somewhere in the
|
||||||
def __init__(self, name, buffer, expr, elem, minus, varName, source,
|
template.'''
|
||||||
fromExpr):
|
def __init__(self, name, buffer, elem, minus, variables, source, fromExpr):
|
||||||
BufferAction.__init__(self, name, buffer, expr, elem, minus, source,
|
# We do not use the default Buffer.expr attribute for storing the Python
|
||||||
|
# expression, because here we will have several expressions, one for
|
||||||
|
# every defined variable.
|
||||||
|
BufferAction.__init__(self, name, buffer, None, elem, minus, source,
|
||||||
fromExpr)
|
fromExpr)
|
||||||
self.varName = varName # Name of the variable
|
# Definitions of variables: ~{s_name: s_expr}~
|
||||||
|
self.variables = variables
|
||||||
|
# Results of executing the variables: ~{s_name: exprResult}~
|
||||||
|
self.results = {}
|
||||||
|
|
||||||
def do(self):
|
def do(self):
|
||||||
context = self.buffer.env.context
|
context = self.buffer.env.context
|
||||||
# Remember the variable hidden by our variable definition, if any
|
# Evaluate the variables' expressions: because there are several
|
||||||
hasHiddenVariable = False
|
# expressions, we did not use the standard, single-expression-minded
|
||||||
if context.has_key(self.varName):
|
# BufferAction code for evaluating the expression.
|
||||||
hiddenVariable = context[self.varName]
|
# Also: remember the names and values of the variables that we will hide
|
||||||
hasHiddenVariable = True
|
# in the context: after execution of this buffer we will restore those
|
||||||
# Add the variable to the context
|
# values in the context.
|
||||||
context[self.varName] = self.exprResult
|
hidden = None
|
||||||
|
for name, expr in self.variables.iteritems():
|
||||||
|
# Evaluate the expression
|
||||||
|
result, error = self.evaluateExpression(expr)
|
||||||
|
if error: return
|
||||||
|
self.results[name] = result
|
||||||
|
# Remember the variable previous value if already in the context
|
||||||
|
if name in context:
|
||||||
|
if not hidden:
|
||||||
|
hidden = {name: context[name]}
|
||||||
|
else:
|
||||||
|
hidden[name] = context[name]
|
||||||
|
# Add our variables to the context
|
||||||
|
context.update(self.results)
|
||||||
# Evaluate the buffer
|
# Evaluate the buffer
|
||||||
self.evaluateBuffer()
|
self.evaluateBuffer()
|
||||||
# Restore hidden variable if any
|
# Restore hidden variables if any
|
||||||
if hasHiddenVariable:
|
if hidden: context.update(hidden)
|
||||||
context[self.varName] = hiddenVariable
|
# Delete not-hidden variables
|
||||||
else:
|
for name in self.variables.iterkeys():
|
||||||
del context[self.varName]
|
if hidden and (name in hidden): continue
|
||||||
|
del context[name]
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -23,7 +23,7 @@ from xml.sax.saxutils import quoteattr
|
||||||
from appy.shared.xml_parser import xmlPrologue, escapeXml
|
from appy.shared.xml_parser import xmlPrologue, escapeXml
|
||||||
from appy.pod import PodError
|
from appy.pod import PodError
|
||||||
from appy.pod.elements import *
|
from appy.pod.elements import *
|
||||||
from appy.pod.actions import IfAction, ElseAction, ForAction, VariableAction, \
|
from appy.pod.actions import IfAction, ElseAction, ForAction, VariablesAction, \
|
||||||
NullAction
|
NullAction
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -359,6 +359,18 @@ class MemoryBuffer(Buffer):
|
||||||
self.content += u' '
|
self.content += u' '
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
def _getVariables(self, expr):
|
||||||
|
'''Returns variable definitions in p_expr as a dict
|
||||||
|
~{s_varName: s_expr}~.'''
|
||||||
|
exprs = expr.strip().split(';')
|
||||||
|
res = {}
|
||||||
|
for sub in exprs:
|
||||||
|
varRes = MemoryBuffer.varRex.match(sub)
|
||||||
|
if not varRes:
|
||||||
|
raise ParsingError(BAD_VAR_EXPRESSION % sub)
|
||||||
|
res[varRes.group(1)] = varRes.group(2)
|
||||||
|
return res
|
||||||
|
|
||||||
def createAction(self, statementGroup):
|
def createAction(self, statementGroup):
|
||||||
'''Tries to create an action based on p_statementGroup. If the statement
|
'''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
|
is not correct, r_ is -1. Else, r_ is the index of the element within
|
||||||
|
@ -432,12 +444,9 @@ class MemoryBuffer(Buffer):
|
||||||
self.action = ForAction(statementName, self, subExpr, podElem,
|
self.action = ForAction(statementName, self, subExpr, podElem,
|
||||||
minus, iter, source, fromClause)
|
minus, iter, source, fromClause)
|
||||||
elif actionType == 'with':
|
elif actionType == 'with':
|
||||||
varRes = MemoryBuffer.varRex.match(subExpr.strip())
|
variables = self._getVariables(subExpr)
|
||||||
if not varRes:
|
self.action = VariablesAction(statementName, self, podElem,
|
||||||
raise ParsingError(BAD_VAR_EXPRESSION % subExpr)
|
minus, variables, source, fromClause)
|
||||||
varName, subExpr = varRes.groups()
|
|
||||||
self.action = VariableAction(statementName, self, subExpr,
|
|
||||||
podElem, minus, varName, source, fromClause)
|
|
||||||
else: # null action
|
else: # null action
|
||||||
if not fromClause:
|
if not fromClause:
|
||||||
raise ParsingError(NULL_ACTION_ERROR)
|
raise ParsingError(NULL_ACTION_ERROR)
|
||||||
|
@ -460,6 +469,10 @@ class MemoryBuffer(Buffer):
|
||||||
elif actionType == 'if':
|
elif actionType == 'if':
|
||||||
self.action = IfAction('if', self, statement, elem, False,
|
self.action = IfAction('if', self, statement, elem, False,
|
||||||
'buffer', None)
|
'buffer', None)
|
||||||
|
elif actionType == 'var':
|
||||||
|
variables = self._getVariables(statement)
|
||||||
|
self.action = VariablesAction('var', self, elem, False, variables,
|
||||||
|
'buffer', None)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def cut(self, index, keepFirstPart):
|
def cut(self, index, keepFirstPart):
|
||||||
|
|
|
@ -3,9 +3,7 @@
|
||||||
Python and XML.'''
|
Python and XML.'''
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from UserDict import UserDict
|
|
||||||
from px_parser import PxParser, PxEnvironment
|
from px_parser import PxParser, PxEnvironment
|
||||||
from appy.pod.renderer import BAD_CONTEXT
|
|
||||||
|
|
||||||
# Exception class --------------------------------------------------------------
|
# Exception class --------------------------------------------------------------
|
||||||
class PxError(Exception): pass
|
class PxError(Exception): pass
|
||||||
|
@ -37,16 +35,8 @@ class Px:
|
||||||
self.parser.parse(self.content)
|
self.parser.parse(self.content)
|
||||||
|
|
||||||
def __call__(self, context):
|
def __call__(self, context):
|
||||||
# Get the context in a standardized form.
|
# p_context must be a dict. Store it in the PX environment.
|
||||||
evalContext = {}
|
self.parser.env.context = context
|
||||||
if hasattr(context, '__dict__'):
|
|
||||||
evalContext.update(context.__dict__)
|
|
||||||
elif isinstance(context, dict) or isinstance(context, UserDict):
|
|
||||||
evalContext.update(context)
|
|
||||||
else:
|
|
||||||
raise PxError(BAD_CONTEXT)
|
|
||||||
# Store the context on the PX environment
|
|
||||||
self.parser.env.context = evalContext
|
|
||||||
# Render the PX result and return it
|
# Render the PX result and return it
|
||||||
env = self.parser.env
|
env = self.parser.env
|
||||||
env.ast.evaluate()
|
env.ast.evaluate()
|
||||||
|
|
|
@ -56,6 +56,8 @@ class PxEnvironment(XmlEnvironment):
|
||||||
class PxParser(XmlParser):
|
class PxParser(XmlParser):
|
||||||
'''PX parser that is specific for parsing PX data.'''
|
'''PX parser that is specific for parsing PX data.'''
|
||||||
|
|
||||||
|
pxAttributes = ('var', 'for', 'if')
|
||||||
|
|
||||||
def __init__(self, env, caller=None):
|
def __init__(self, env, caller=None):
|
||||||
XmlParser.__init__(self, env, caller)
|
XmlParser.__init__(self, env, caller)
|
||||||
|
|
||||||
|
@ -63,14 +65,14 @@ class PxParser(XmlParser):
|
||||||
'''A start p_elem with p_attrs is encountered in the PX.'''
|
'''A start p_elem with p_attrs is encountered in the PX.'''
|
||||||
e = self.env
|
e = self.env
|
||||||
self.currentElem = elem
|
self.currentElem = elem
|
||||||
if attrs.has_key('for'):
|
# See if we have a PX attribute among p_attrs.
|
||||||
# Dump the element in a new sub-buffer
|
for name in self.pxAttributes:
|
||||||
e.addSubBuffer()
|
if attrs.has_key(name):
|
||||||
# Create the action for this buffer
|
# Dump the element in a new sub-buffer
|
||||||
e.currentBuffer.createPxAction(elem, 'for', attrs['for'])
|
e.addSubBuffer()
|
||||||
elif attrs.has_key('if'):
|
# Create the action for this buffer
|
||||||
e.addSubBuffer()
|
e.currentBuffer.createPxAction(elem, name, attrs[name])
|
||||||
e.currentBuffer.createPxAction(elem, 'if', attrs['if'])
|
break
|
||||||
if e.isActionElem(elem):
|
if e.isActionElem(elem):
|
||||||
# Add a temp element in the buffer (that will be unreferenced
|
# Add a temp element in the buffer (that will be unreferenced
|
||||||
# later). This way, when encountering the corresponding end element,
|
# later). This way, when encountering the corresponding end element,
|
||||||
|
|
Loading…
Reference in a new issue