[px] PXs can be called by other PXs.

This commit is contained in:
Gaetan Delannay 2013-03-22 12:52:24 +01:00
parent bfbf9bea82
commit 2a145ac890
5 changed files with 52 additions and 23 deletions

View file

@ -1,4 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!DOCTYPE html>
<html metal:define-macro="main"
tal:define="user tool/getUser;
isAnon tool/userIsAnon;

View file

@ -69,7 +69,12 @@ class BufferAction:
if self.buffer.caller() == 'px':
# Add in the error message the line nb where the errors occurs
# within the PX.
import pdb; pdb.set_trace()
locator = self.buffer.env.parser.locator
# The column number may not be given.
col = locator.getColumnNumber()
if col == None: col = ''
else: col = ', column %d' % col
errorMessage += ' (line %s%s)' % (locator.getLineNumber(), col)
raise Exception(errorMessage)
# Empty the buffer
self.buffer.__init__(self.buffer.env, self.buffer.parent)
@ -274,7 +279,7 @@ class VariablesAction(BufferAction):
# every defined variable.
BufferAction.__init__(self, name, buffer, None, elem, minus, source,
fromExpr)
# Definitions of variables: ~{s_name: s_expr}~
# Definitions of variables: ~[(s_name, s_expr)]~
self.variables = variables
def do(self):
@ -286,7 +291,7 @@ class VariablesAction(BufferAction):
# hide in the context: after execution of this buffer we will restore
# those values.
hidden = None
for name, expr in self.variables.iteritems():
for name, expr in self.variables:
# Evaluate the expression
result, error = self.evaluateExpression(expr)
if error: return
@ -303,7 +308,7 @@ class VariablesAction(BufferAction):
# Restore hidden variables if any
if hidden: context.update(hidden)
# Delete not-hidden variables
for name in self.variables.iterkeys():
for name, expr in self.variables:
if hidden and (name in hidden): continue
del context[name]
# ------------------------------------------------------------------------------

View file

@ -140,7 +140,7 @@ class Buffer:
def getLength(self): pass # To be overridden
def dumpStartElement(self, elem, attrs={}, ignoreAttrs=(),
insertAttributesHook=False):
insertAttributesHook=False, noEndTag=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
@ -162,7 +162,12 @@ class Buffer:
res = self.addAttributes()
else:
res = None
self.write('>')
# Close the tag
if noEndTag:
suffix = '/>'
else:
suffix = '>'
self.write(suffix)
return res
def dumpEndElement(self, elem):
@ -201,7 +206,9 @@ class FileBuffer(Buffer):
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))
res, escape = Expression(expression).evaluate(self.env.context)
if escape: self.dumpContent(res)
else: self.write(res)
except Exception, e:
PodError.dump(self, EVAL_EXPR_ERROR % (expression, e), dumpTb=False)
@ -360,15 +367,15 @@ class MemoryBuffer(Buffer):
return attrs
def _getVariables(self, expr):
'''Returns variable definitions in p_expr as a dict
~{s_varName: s_expr}~.'''
'''Returns variable definitions in p_expr as a list
~[(s_varName, s_expr)]~.'''
exprs = expr.strip().split(';')
res = {}
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)
res.append(varRes.groups())
return res
def createAction(self, statementGroup):
@ -624,7 +631,9 @@ class MemoryBuffer(Buffer):
currentIndex = index + 1
if isinstance(evalEntry, Expression):
try:
result.dumpContent(evalEntry.evaluate(self.env.context))
res, escape = evalEntry.evaluate(self.env.context)
if escape: result.dumpContent(res)
else: result.write(res)
except Exception, e:
if self.caller() == 'pod':
PodError.dump(result, EVAL_EXPR_ERROR % (

View file

@ -89,7 +89,13 @@ class Expression(PodElement):
def evaluate(self, context):
'''Evaluates the Python expression (self.expr) with a given
p_context.'''
p_context, and returns the result. More precisely, it returns a
tuple (result, escapeXml). Boolean escapeXml indicates if XML chars
must be escaped or not. For example, if the expression's result is a
PX, the result of evaluating it (a chunk of XHTML) must be inserted
as is, unescaped, into the buffer. In most situations, XML escaping
will be enabled.'''
escapeXml = True
# Evaluate the expression, or get it from self.result if it has already
# been computed.
if self.evaluated:
@ -103,16 +109,22 @@ class Expression(PodElement):
# 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:
# the POD/PX result.
resultType = res.__class__.__name__
if resultType == 'NoneType':
res = u''
elif isinstance(res, str):
res = unicode(res.decode('utf-8'))
elif isinstance(res, unicode):
pass
elif resultType == 'str':
res = res.decode('utf-8')
elif resultType == 'unicode':
pass # Don't perform any conversion, unicode is the target type.
elif resultType == 'Px':
# A PX that must be called within the current PX. Call it with the
# current context.
res = res(context)
escapeXml = False
else:
res = unicode(res)
return res
return res, escapeXml
class Attributes(PodElement):
'''Represents a bunch of XML attributes that will be dumped for a given tag

View file

@ -54,6 +54,8 @@ class PxEnvironment(XmlEnvironment):
class PxParser(XmlParser):
'''PX parser that is specific for parsing PX data.'''
pxAttributes = ('var', 'for', 'if')
# No-end tags
noEndTags = ('br', 'img')
def __init__(self, env, caller=None):
XmlParser.__init__(self, env, caller)
@ -78,7 +80,7 @@ class PxParser(XmlParser):
e.currentBuffer.addElement(elem, elemType='px')
if elem != 'x':
e.currentBuffer.dumpStartElement(elem, attrs,
ignoreAttrs=self.pxAttributes)
ignoreAttrs=self.pxAttributes, noEndTag=elem in self.noEndTags)
def endElement(self, elem):
e = self.env
@ -88,7 +90,8 @@ class PxParser(XmlParser):
e.currentBuffer.addExpression(e.currentContent)
e.currentContent = ''
# Dump the end element into the current buffer
if elem != 'x': e.currentBuffer.dumpEndElement(elem)
if (elem != 'x') and (elem not in self.noEndTags):
e.currentBuffer.dumpEndElement(elem)
# If this element is the main element of the current buffer, we must
# pop it and continue to work in the parent buffer.
if e.isActionElem(elem):