Initial Hawkeye work. This contains a new template system for creating HTML, some basic admin ability, and serves as the basis for further work.

You may need to bongo-config install again, if upgrading.
This commit is contained in:
alexhudson
2007-04-29 16:48:45 +00:00
parent 811e8e4d4f
commit 331f909d09
45 changed files with 3586 additions and 709 deletions
+15 -2
View File
@@ -11,6 +11,7 @@ pkgpythonexternalemaildir = $(pythondir)/bongo/external/email
pkgpythonexternalemailmimedir = $(pythondir)/bongo/external/email/mime
pkgpythonexternaldateutilzoneinfodir = $(pythondir)/bongo/external/dateutil/zoneinfo
pkgpythonexternalsimplejsondir = $(pythondir)/bongo/external/simplejson
pkgpythonexternalsimpletaldir = $(pythondir)/bongo/external/simpletal
pkgpythonexternalvobjectdir = $(pythondir)/bongo/external/vobject
pkgpythonnmapdir = $(pythondir)/bongo/nmap
pkgpythonstoredir = $(pythondir)/bongo/store
@@ -19,10 +20,11 @@ pkgpython_PYTHON := \
src/libs/python/bongo/__init__.py \
src/libs/python/bongo/CalCmd.py \
src/libs/python/bongo/cmdparse.py \
src/libs/python/bongo/Console.py \
src/libs/python/bongo/Contact.py \
src/libs/python/bongo/Console.py \
src/libs/python/bongo/Contact.py \
src/libs/python/bongo/BongoError.py \
src/libs/python/bongo/MDB.py \
src/libs/python/bongo/Template.py \
src/libs/python/bongo/Privs.py \
src/libs/python/bongo/StreamIO.py \
src/libs/python/bongo/table.py
@@ -110,6 +112,17 @@ pkgpythonexternalsimplejson_PYTHON := \
src/libs/python/bongo/external/simplejson/jsonfilter.py \
src/libs/python/bongo/external/simplejson/scanner.py
pkgpythonexternalsimpletal_PYTHON := \
src/libs/python/bongo/external/simpletal/DummyLogger.py \
src/libs/python/bongo/external/simpletal/__init__.py \
src/libs/python/bongo/external/simpletal/simpleElementTree.py \
src/libs/python/bongo/external/simpletal/simpleTAL.py \
src/libs/python/bongo/external/simpletal/FixedHTMLParser.py \
src/libs/python/bongo/external/simpletal/sgmlentitynames.py \
src/libs/python/bongo/external/simpletal/simpleTALES.py \
src/libs/python/bongo/external/simpletal/simpleTALUtils.py
pkgpythonexternalvobject_PYTHON := \
src/libs/python/bongo/external/vobject/__init__.py \
src/libs/python/bongo/external/vobject/base.py \
+97
View File
@@ -0,0 +1,97 @@
import os, sys, copy
from bongo.external.simpletal import simpleTAL, simpleTALES
class Template:
def __init__(self, depth=0):
self._context = simpleTALES.Context()
self._depth = depth
self._templatefile = None
self._preprocessor = TemplatePreprocessor()
def Run(self, req):
if self._templatefile == None:
raise RuntimeError
self._preprocessor.setTemplateFile(self._templatefile)
template = simpleTAL.compileHTMLTemplate(self._preprocessor)
template.expand(self._context, req)
def setVariable(self, name, obj):
self._context.addGlobal(name, obj)
self._preprocessor[name] = obj
def setTemplateFile(self, filename):
self._templatefile = filename
def setTemplatePath(self, path):
self._templatepath = path
self._preprocessor.setTemplatePath(path)
def setTemplateUriRoot(self, root):
self._templateuriroot = root
self._preprocessor.setUriRoot(root)
class TemplatePreprocessor:
def __init__(self, dict={}):
self.dict = dict
def read(self):
return "%s" % self
def setTemplateFile(self, filename):
content = self._filecontent(filename)
if content != "":
self._template = content
else:
self._template = "<html><body><h1>Error</h1><p>No template %s</p></body></html>" % filename
def __str__(self):
# rely on string substitutions
return self._template % self
def __getitem__(self, key):
return self._process(key.split("|"))
def __setitem__(self, key, value):
self.dict[key] = value
def _process(self, args):
arg = args.pop(0)
if len(args) == 0:
if arg in self.dict:
return self.dict[arg]
elif hasattr(self, "call_" + arg) and callable(getattr(self, "call_" + arg)):
return getattr(self, "call_" + arg)()
else:
return "Bad attribute %s" % arg
else:
return getattr(self, "call_" + arg)(args)
def _filecontent(self, filename):
content = ""
try:
f = open (filename, "r")
content = f.read()
f.close()
except:
print "Couldn't open file %s" % filename
return content
def setTemplatePath(self, path):
self._templatepath = path
def setUriRoot(self, root):
self._uriroot = root
# template callable functions
def call_url(self, args):
# Pad out URLs with our web root, so the app can be moved in terms of
# URL and the links all still work
return self._uriroot + args[0]
def call_include(self, args):
# Include a copy of another template here. This is also processed.
template = self._templatepath + '/' + args[0]
pp = copy.copy(self)
pp.setTemplateFile(template)
return pp.read()
+66
View File
@@ -0,0 +1,66 @@
""" simpleTALES Implementation
Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
If you make any bug fixes or feature enhancements please let me know!
Dummy logging module, used when logging (http://www.red-dove.com/python_logging.html)
is not installed.
"""
class DummyLogger:
def debug (self, *args):
pass
def info (self, *args):
pass
def warn (self, *args):
pass
def error (self, *args):
pass
def critical (self, *args):
pass
def getLogger (*params):
return DummyLogger()
def debug (*args):
pass
def info (*args):
pass
def warn (*args):
pass
def error (*args):
pass
def critical (*args):
pass
@@ -0,0 +1,45 @@
""" Fixed up HTMLParser
Copyright (c) 2005 Colin Stewart (http://www.owlfish.com/)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
If you make any bug fixes or feature enhancements please let me know!
The classes in this module implement the TAL language, expanding
both XML and HTML templates.
Module Dependencies: logging, simpleTALES, simpleTALTemplates
"""
import bongo.external.simpletal
import HTMLParser
class HTMLParser (HTMLParser.HTMLParser):
def unescape(self, s):
# Just return the data - we don't partially unescaped data!
return s
+1
View File
@@ -0,0 +1 @@
__version__ = "4.1"
@@ -0,0 +1,284 @@
""" simpleTAL Implementation
Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
If you make any bug fixes or feature enhancements please let me know!
A dictionary of HTML entity names to their decimal value.
"""
htmlNameToUnicodeNumber = {"nbsp": 160
,"iexcl": 161
,"cent": 162
,"pound": 163
,"curren": 164
,"yen": 165
,"brvbar": 166
,"sect": 167
,"uml": 168
,"copy": 169
,"ordf": 170
,"laquo": 171
,"not": 172
,"shy": 173
,"reg": 174
,"macr": 175
,"deg": 176
,"plusmn": 177
,"sup2": 178
,"sup3": 179
,"acute": 180
,"micro": 181
,"para": 182
,"middot": 183
,"cedil": 184
,"sup1": 185
,"ordm": 186
,"raquo": 187
,"frac14": 188
,"frac12": 189
,"frac34": 190
,"iquest": 191
,"Agrave": 192
,"Aacute": 193
,"Acirc": 194
,"Atilde": 195
,"Auml": 196
,"Aring": 197
,"AElig": 198
,"Ccedil": 199
,"Egrave": 200
,"Eacute": 201
,"Ecirc": 202
,"Euml": 203
,"Igrave": 204
,"Iacute": 205
,"Icirc": 206
,"Iuml": 207
,"ETH": 208
,"Ntilde": 209
,"Ograve": 210
,"Oacute": 211
,"Ocirc": 212
,"Otilde": 213
,"Ouml": 214
,"times": 215
,"Oslash": 216
,"Ugrave": 217
,"Uacute": 218
,"Ucirc": 219
,"Uuml": 220
,"Yacute": 221
,"THORN": 222
,"szlig": 223
,"agrave": 224
,"aacute": 225
,"acirc": 226
,"atilde": 227
,"auml": 228
,"aring": 229
,"aelig": 230
,"ccedil": 231
,"egrave": 232
,"eacute": 233
,"ecirc": 234
,"euml": 235
,"igrave": 236
,"iacute": 237
,"icirc": 238
,"iuml": 239
,"eth": 240
,"ntilde": 241
,"ograve": 242
,"oacute": 243
,"ocirc": 244
,"otilde": 245
,"ouml": 246
,"divide": 247
,"oslash": 248
,"ugrave": 249
,"uacute": 250
,"ucirc": 251
,"uuml": 252
,"yacute": 253
,"thorn": 254
,"yuml": 255
,"fnof": 402
,"Alpha": 913
,"Beta": 914
,"Gamma": 915
,"Delta": 916
,"Epsilon": 917
,"Zeta": 918
,"Eta": 919
,"Theta": 920
,"Iota": 921
,"Kappa": 922
,"Lambda": 923
,"Mu": 924
,"Nu": 925
,"Xi": 926
,"Omicron": 927
,"Pi": 928
,"Rho": 929
,"Sigma": 931
,"Tau": 932
,"Upsilon": 933
,"Phi": 934
,"Chi": 935
,"Psi": 936
,"Omega": 937
,"alpha": 945
,"beta": 946
,"gamma": 947
,"delta": 948
,"epsilon": 949
,"zeta": 950
,"eta": 951
,"theta": 952
,"iota": 953
,"kappa": 954
,"lambda": 955
,"mu": 956
,"nu": 957
,"xi": 958
,"omicron": 959
,"pi": 960
,"rho": 961
,"sigmaf": 962
,"sigma": 963
,"tau": 964
,"upsilon": 965
,"phi": 966
,"chi": 967
,"psi": 968
,"omega": 969
,"thetasym": 977
,"upsih": 978
,"piv": 982
,"bull": 8226
,"hellip": 8230
,"prime": 8242
,"Prime": 8243
,"oline": 8254
,"frasl": 8260
,"weierp": 8472
,"image": 8465
,"real": 8476
,"trade": 8482
,"alefsym": 8501
,"larr": 8592
,"uarr": 8593
,"rarr": 8594
,"darr": 8595
,"harr": 8596
,"crarr": 8629
,"lArr": 8656
,"uArr": 8657
,"rArr": 8658
,"dArr": 8659
,"hArr": 8660
,"forall": 8704
,"part": 8706
,"exist": 8707
,"empty": 8709
,"nabla": 8711
,"isin": 8712
,"notin": 8713
,"ni": 8715
,"prod": 8719
,"sum": 8721
,"minus": 8722
,"lowast": 8727
,"radic": 8730
,"prop": 8733
,"infin": 8734
,"ang": 8736
,"and": 8743
,"or": 8744
,"cap": 8745
,"cup": 8746
,"int": 8747
,"there4": 8756
,"sim": 8764
,"cong": 8773
,"asymp": 8776
,"ne": 8800
,"equiv": 8801
,"le": 8804
,"ge": 8805
,"sub": 8834
,"sup": 8835
,"nsub": 8836
,"sube": 8838
,"supe": 8839
,"oplus": 8853
,"otimes": 8855
,"perp": 8869
,"sdot": 8901
,"lceil": 8968
,"rceil": 8969
,"lfloor": 8970
,"rfloor": 8971
,"lang": 9001
,"rang": 9002
,"loz": 9674
,"spades": 9824
,"clubs": 9827
,"hearts": 9829
,"diams": 9830
,"quot": 34
,"amp": 38
,"lt": 60
,"gt": 62
,"OElig": 338
,"oelig": 339
,"Scaron": 352
,"scaron": 353
,"Yuml": 376
,"circ": 710
,"tilde": 732
,"ensp": 8194
,"emsp": 8195
,"thinsp": 8201
,"zwnj": 8204
,"zwj": 8205
,"lrm": 8206
,"rlm": 8207
,"ndash": 8211
,"mdash": 8212
,"lsquo": 8216
,"rsquo": 8217
,"sbquo": 8218
,"ldquo": 8220
,"rdquo": 8221
,"bdquo": 8222
,"dagger": 8224
,"Dagger": 8225
,"permil": 8240
,"lsaquo": 8249
,"rsaquo": 8250
,"euro": 8364}
@@ -0,0 +1,106 @@
""" ElementTree integration for SimpleTAL
Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
If you make any bug fixes or feature enhancements please let me know!
The parseFile function in this module will return a Element object that
implements simpleTALES.ContextVariable and makes XML documents available
with the following path logic:
- Accessing Element directly returns the Element.text value
- Accessing Element/find and Element/findall passes the text
(up to attribute accessor) to the corresponding Element function
- Accessing the Element@name access the attribute "name"
- Accessing Element/anotherElement is a short-cut for
Element/find/anotherElement
Module Dependencies: simpleTALES, elementtree
"""
from bongo.external.elementtree import ElementTree
import bongo.external.simpleTALES
class SimpleElementTreeVar (ElementTree._ElementInterface, simpleTALES.ContextVariable):
def __init__(self, tag, attrib):
ElementTree._ElementInterface.__init__(self, tag, attrib)
simpleTALES.ContextVariable.__init__(self)
def value (self, pathInfo = None):
if (pathInfo is not None):
pathIndex, paths = pathInfo
ourParams = paths[pathIndex:]
attributeName = None
if (len (ourParams) > 0):
# Look for attribute index
if (ourParams[-1].startswith ('@')):
# Attribute lookup
attributeName = ourParams [-1][1:]
ourParams = ourParams [:-1]
# Do we do a find?
activeElement = self
if len (ourParams) > 0:
# Look for a find or findall first
if (ourParams [0] == 'find'):
# Find the element if possible
activeElement = self.find ("/".join (ourParams [1:]))
elif (ourParams [0] == 'findall'):
# Short cut this
raise simpleTALES.ContextVariable (self.findall ("/".join (ourParams[1:])))
else:
# Assume that we wanted to use find
activeElement = self.find ("/".join (ourParams))
# Did we find an element and are we looking for an attribute?
if (attributeName is not None and activeElement is not None):
attrValue = activeElement.attrib.get (attributeName, None)
raise simpleTALES.ContextVariable (attrValue)
# Just return the element
if (activeElement is None):
# Wrap it
raise simpleTALES.ContextVariable (None)
raise activeElement
else:
return self
def __unicode__ (self):
return self.text
def __str__ (self):
return str (self.text)
def parseFile (file):
treeBuilder = ElementTree.TreeBuilder (element_factory = SimpleElementTreeVar)
xmlTreeBuilder = ElementTree.XMLTreeBuilder (target=treeBuilder)
if (not hasattr (file, 'read')):
ourFile = open (file)
xmlTreeBuilder.feed (ourFile.read())
ourFile.close()
else:
xmlTreeBuilder.feed (file.read())
return xmlTreeBuilder.close()
File diff suppressed because it is too large Load Diff
+651
View File
@@ -0,0 +1,651 @@
""" simpleTALES Implementation
Copyright (c) 2005 Colin Stewart (http://www.owlfish.com/)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
If you make any bug fixes or feature enhancements please let me know!
The classes in this module implement the TALES specification, used
by the simpleTAL module.
Module Dependencies: logging
"""
import types, sys
try:
import logging
except:
import DummyLogger as logging
import bongo.external.simpletal as simpletal
__version__ = simpletal.__version__
DEFAULTVALUE = "This represents a Default value."
class PathNotFoundException (Exception):
pass
class ContextContentException (Exception):
""" This is raised when invalid content has been placed into the Context object.
For example using non-ascii characters instead of Unicode strings.
"""
pass
PATHNOTFOUNDEXCEPTION = PathNotFoundException()
class ContextVariable:
def __init__ (self, value = None):
self.ourValue = value
def value (self, currentPath=None):
if (callable (self.ourValue)):
return apply (self.ourValue, ())
return self.ourValue
def rawValue (self):
return self.ourValue
def __str__ (self):
return repr (self.ourValue)
class RepeatVariable (ContextVariable):
""" To be written"""
def __init__ (self, sequence):
ContextVariable.__init__ (self, 1)
self.sequence = sequence
self.position = 0
self.map = None
def value (self, currentPath=None):
if (self.map is None):
self.createMap()
return self.map
def rawValue (self):
return self.value()
def getCurrentValue (self):
return self.sequence [self.position]
def increment (self):
self.position += 1
if (self.position == len (self.sequence)):
raise IndexError ("Repeat Finished")
def createMap (self):
self.map = {}
self.map ['index'] = self.getIndex
self.map ['number'] = self.getNumber
self.map ['even'] = self.getEven
self.map ['odd'] = self.getOdd
self.map ['start'] = self.getStart
self.map ['end'] = self.getEnd
# TODO: first and last need to be implemented.
self.map ['length'] = len (self.sequence)
self.map ['letter'] = self.getLowerLetter
self.map ['Letter'] = self.getUpperLetter
self.map ['roman'] = self.getLowerRoman
self.map ['Roman'] = self.getUpperRoman
# Repeat implementation goes here
def getIndex (self):
return self.position
def getNumber (self):
return self.position + 1
def getEven (self):
if ((self.position % 2) != 0):
return 0
return 1
def getOdd (self):
if ((self.position % 2) == 0):
return 0
return 1
def getStart (self):
if (self.position == 0):
return 1
return 0
def getEnd (self):
if (self.position == len (self.sequence) - 1):
return 1
return 0
def getLowerLetter (self):
result = ""
nextCol = self.position
if (nextCol == 0):
return 'a'
while (nextCol > 0):
nextCol, thisCol = divmod (nextCol, 26)
result = chr (ord ('a') + thisCol) + result
return result
def getUpperLetter (self):
return self.getLowerLetter().upper()
def getLowerRoman (self):
romanNumeralList = (('m', 1000)
,('cm', 900)
,('d', 500)
,('cd', 400)
,('c', 100)
,('xc', 90)
,('l', 50)
,('xl', 40)
,('x', 10)
,('ix', 9)
,('v', 5)
,('iv', 4)
,('i', 1)
)
if (self.position > 3999):
# Roman numbers only supported up to 4000
return ' '
num = self.position + 1
result = ""
for roman, integer in romanNumeralList:
while (num >= integer):
result += roman
num -= integer
return result
def getUpperRoman (self):
return self.getLowerRoman().upper()
class IteratorRepeatVariable (RepeatVariable):
def __init__ (self, sequence):
RepeatVariable.__init__ (self, sequence)
self.curValue = None
self.iterStatus = 0
def getCurrentValue (self):
if (self.iterStatus == 0):
self.iterStatus = 1
try:
self.curValue = self.sequence.next()
except StopIteration, e:
self.iterStatus = 2
raise IndexError ("Repeat Finished")
return self.curValue
def increment (self):
# Need this for the repeat variable functions.
self.position += 1
try:
self.curValue = self.sequence.next()
except StopIteration, e:
self.iterStatus = 2
raise IndexError ("Repeat Finished")
def createMap (self):
self.map = {}
self.map ['index'] = self.getIndex
self.map ['number'] = self.getNumber
self.map ['even'] = self.getEven
self.map ['odd'] = self.getOdd
self.map ['start'] = self.getStart
self.map ['end'] = self.getEnd
# TODO: first and last need to be implemented.
self.map ['length'] = sys.maxint
self.map ['letter'] = self.getLowerLetter
self.map ['Letter'] = self.getUpperLetter
self.map ['roman'] = self.getLowerRoman
self.map ['Roman'] = self.getUpperRoman
def getEnd (self):
if (self.iterStatus == 2):
return 1
return 0
class PathFunctionVariable (ContextVariable):
def __init__ (self, func):
ContextVariable.__init__ (self, value = func)
self.func = func
def value (self, currentPath=None):
if (currentPath is not None):
index, paths = currentPath
result = ContextVariable (apply (self.func, ('/'.join (paths[index:]),)))
# Fast track the result
raise result
class CachedFuncResult (ContextVariable):
def value (self, currentPath=None):
try:
return self.cachedValue
except:
self.cachedValue = ContextVariable.value (self)
return self.cachedValue
def clearCache (self):
try:
del self.cachedValue
except:
pass
class PythonPathFunctions:
def __init__ (self, context):
self.context = context
def path (self, expr):
return self.context.evaluatePath (expr)
def string (self, expr):
return self.context.evaluateString (expr)
def exists (self, expr):
return self.context.evaluateExists (expr)
def nocall (self, expr):
return self.context.evaluateNoCall (expr)
def test (self, *arguments):
if (len (arguments) % 2):
# We have an odd number of arguments - which means the last one is a default
pairs = arguments[:-1]
defaultValue = arguments[-1]
else:
# No default - so use None
pairs = arguments
defaultValue = None
index = 0
while (index < len (pairs)):
test = pairs[index]
index += 1
value = pairs[index]
index += 1
if (test):
return value
return defaultValue
class Context:
def __init__ (self, options=None, allowPythonPath=0):
self.allowPythonPath = allowPythonPath
self.globals = {}
self.locals = {}
self.localStack = []
self.repeatStack = []
self.populateDefaultVariables (options)
self.log = logging.getLogger ("simpleTALES.Context")
self.true = 1
self.false = 0
self.pythonPathFuncs = PythonPathFunctions (self)
def addRepeat (self, name, var, initialValue):
# Pop the current repeat map onto the stack
self.repeatStack.append (self.repeatMap)
self.repeatMap = self.repeatMap.copy()
self.repeatMap [name] = var
# Map this repeatMap into the global space
self.addGlobal ('repeat', self.repeatMap)
# Add in the locals
self.pushLocals()
self.setLocal (name, initialValue)
def removeRepeat (self, name):
# Bring the old repeat map back
self.repeatMap = self.repeatStack.pop()
# Map this repeatMap into the global space
self.addGlobal ('repeat', self.repeatMap)
def addGlobal (self, name, value):
self.globals[name] = value
def pushLocals (self):
# Push the current locals onto a stack so that we can safely over-ride them.
self.localStack.append (self.locals)
self.locals = self.locals.copy()
def setLocal (self, name, value):
# Override the current local if present with the new one
self.locals [name] = value
def popLocals (self):
self.locals = self.localStack.pop()
def evaluate (self, expr, originalAtts = None):
# Returns a ContextVariable
#self.log.debug ("Evaluating %s" % expr)
if (originalAtts is not None):
# Call from outside
self.globals['attrs'] = originalAtts
suppressException = 1
else:
suppressException = 0
# Supports path, exists, nocall, not, and string
expr = expr.strip ()
try:
if expr.startswith ('path:'):
return self.evaluatePath (expr[5:].lstrip ())
elif expr.startswith ('exists:'):
return self.evaluateExists (expr[7:].lstrip())
elif expr.startswith ('nocall:'):
return self.evaluateNoCall (expr[7:].lstrip())
elif expr.startswith ('not:'):
return self.evaluateNot (expr[4:].lstrip())
elif expr.startswith ('string:'):
return self.evaluateString (expr[7:].lstrip())
elif expr.startswith ('python:'):
return self.evaluatePython (expr[7:].lstrip())
else:
# Not specified - so it's a path
return self.evaluatePath (expr)
except PathNotFoundException, e:
if (suppressException):
return None
raise e
def evaluatePython (self, expr):
if (not self.allowPythonPath):
self.log.warn ("Parameter allowPythonPath is false. NOT Evaluating python expression %s" % expr)
return self.false
#self.log.debug ("Evaluating python expression %s" % expr)
globals={}
for name, value in self.globals.items():
if (isinstance (value, ContextVariable)): value = value.rawValue()
globals [name] = value
globals ['path'] = self.pythonPathFuncs.path
globals ['string'] = self.pythonPathFuncs.string
globals ['exists'] = self.pythonPathFuncs.exists
globals ['nocall'] = self.pythonPathFuncs.nocall
globals ['test'] = self.pythonPathFuncs.test
locals={}
for name, value in self.locals.items():
if (isinstance (value, ContextVariable)): value = value.rawValue()
locals [name] = value
try:
result = eval(expr, globals, locals)
if (isinstance (result, ContextVariable)):
return result.value()
return result
except Exception, e:
# An exception occured evaluating the template, return the exception as text
self.log.warn ("Exception occurred evaluating python path, exception: " + str (e))
return "Exception: %s" % str (e)
def evaluatePath (self, expr):
#self.log.debug ("Evaluating path expression %s" % expr)
allPaths = expr.split ('|')
if (len (allPaths) > 1):
for path in allPaths:
# Evaluate this path
try:
return self.evaluate (path.strip ())
except PathNotFoundException, e:
# Path didn't exist, try the next one
pass
# No paths evaluated - raise exception.
raise PATHNOTFOUNDEXCEPTION
else:
# A single path - so let's evaluate it.
# This *can* raise PathNotFoundException
return self.traversePath (allPaths[0])
def evaluateExists (self, expr):
#self.log.debug ("Evaluating %s to see if it exists" % expr)
allPaths = expr.split ('|')
# The first path is for us
# Return true if this first bit evaluates, otherwise test the rest
try:
result = self.traversePath (allPaths[0], canCall = 0)
return self.true
except PathNotFoundException, e:
# Look at the rest of the paths.
pass
for path in allPaths[1:]:
# Evaluate this path
try:
pathResult = self.evaluate (path.strip ())
# If this is part of a "exists: path1 | exists: path2" path then we need to look at the actual result.
if (pathResult):
return self.true
except PathNotFoundException, e:
pass
# If we get this far then there are *no* paths that exist.
return self.false
def evaluateNoCall (self, expr):
#self.log.debug ("Evaluating %s using nocall" % expr)
allPaths = expr.split ('|')
# The first path is for us
try:
return self.traversePath (allPaths[0], canCall = 0)
except PathNotFoundException, e:
# Try the rest of the paths.
pass
for path in allPaths[1:]:
# Evaluate this path
try:
return self.evaluate (path.strip ())
except PathNotFoundException, e:
pass
# No path evaluated - raise error
raise PATHNOTFOUNDEXCEPTION
def evaluateNot (self, expr):
#self.log.debug ("Evaluating NOT value of %s" % expr)
# Evaluate what I was passed
try:
pathResult = self.evaluate (expr)
except PathNotFoundException, e:
# In SimpleTAL the result of "not: no/such/path" should be TRUE not FALSE.
return self.true
if (pathResult is None):
# Value was Nothing
return self.true
if (pathResult == DEFAULTVALUE):
return self.false
try:
resultLen = len (pathResult)
if (resultLen > 0):
return self.false
else:
return self.true
except:
# Not a sequence object.
pass
if (not pathResult):
return self.true
# Everything else is true, so we return false!
return self.false
def evaluateString (self, expr):
#self.log.debug ("Evaluating String %s" % expr)
result = ""
skipCount = 0
for position in xrange (0,len (expr)):
if (skipCount > 0):
skipCount -= 1
else:
if (expr[position] == '$'):
try:
if (expr[position + 1] == '$'):
# Escaped $ sign
result += '$'
skipCount = 1
elif (expr[position + 1] == '{'):
# Looking for a path!
endPos = expr.find ('}', position + 1)
if (endPos > 0):
path = expr[position + 2:endPos]
# Evaluate the path - missing paths raise exceptions as normal.
try:
pathResult = self.evaluate (path)
except PathNotFoundException, e:
# This part of the path didn't evaluate to anything - leave blank
pathResult = u''
if (pathResult is not None):
if (isinstance (pathResult, types.UnicodeType)):
result += pathResult
else:
# THIS IS NOT A BUG!
# Use Unicode in Context if you aren't using Ascii!
result += unicode (pathResult)
skipCount = endPos - position
else:
# It's a variable
endPos = expr.find (' ', position + 1)
if (endPos == -1):
endPos = len (expr)
path = expr [position + 1:endPos]
# Evaluate the variable - missing paths raise exceptions as normal.
try:
pathResult = self.traversePath (path)
except PathNotFoundException, e:
# This part of the path didn't evaluate to anything - leave blank
pathResult = u''
if (pathResult is not None):
if (isinstance (pathResult, types.UnicodeType)):
result += pathResult
else:
# THIS IS NOT A BUG!
# Use Unicode in Context if you aren't using Ascii!
result += unicode (pathResult)
skipCount = endPos - position - 1
except IndexError, e:
# Trailing $ sign - just suppress it
self.log.warn ("Trailing $ detected")
pass
else:
result += expr[position]
return result
def traversePath (self, expr, canCall=1):
# canCall only applies to the *final* path destination, not points down the path.
# Check for and correct for trailing/leading quotes
if (expr.startswith ('"') or expr.startswith ("'")):
if (expr.endswith ('"') or expr.endswith ("'")):
expr = expr [1:-1]
else:
expr = expr [1:]
elif (expr.endswith ('"') or expr.endswith ("'")):
expr = expr [0:-1]
pathList = expr.split ('/')
path = pathList[0]
if path.startswith ('?'):
path = path[1:]
if self.locals.has_key(path):
path = self.locals[path]
if (isinstance (path, ContextVariable)): path = path.value()
elif (callable (path)):path = apply (path, ())
elif self.globals.has_key(path):
path = self.globals[path]
if (isinstance (path, ContextVariable)): path = path.value()
elif (callable (path)):path = apply (path, ())
#self.log.debug ("Dereferenced to %s" % path)
if self.locals.has_key(path):
val = self.locals[path]
elif self.globals.has_key(path):
val = self.globals[path]
else:
# If we can't find it then raise an exception
raise PATHNOTFOUNDEXCEPTION
index = 1
for path in pathList[1:]:
#self.log.debug ("Looking for path element %s" % path)
if path.startswith ('?'):
path = path[1:]
if self.locals.has_key(path):
path = self.locals[path]
if (isinstance (path, ContextVariable)): path = path.value()
elif (callable (path)):path = apply (path, ())
elif self.globals.has_key(path):
path = self.globals[path]
if (isinstance (path, ContextVariable)): path = path.value()
elif (callable (path)):path = apply (path, ())
#self.log.debug ("Dereferenced to %s" % path)
try:
if (isinstance (val, ContextVariable)): temp = val.value((index,pathList))
elif (callable (val)):temp = apply (val, ())
else: temp = val
except ContextVariable, e:
# Fast path for those functions that return values
return e.value()
if (hasattr (temp, path)):
val = getattr (temp, path)
else:
try:
try:
val = temp[path]
except TypeError:
val = temp[int(path)]
except:
#self.log.debug ("Not found.")
raise PATHNOTFOUNDEXCEPTION
index = index + 1
#self.log.debug ("Found value %s" % str (val))
if (canCall):
try:
if (isinstance (val, ContextVariable)): result = val.value((index,pathList))
elif (callable (val)):result = apply (val, ())
else: result = val
except ContextVariable, e:
# Fast path for those functions that return values
return e.value()
else:
if (isinstance (val, ContextVariable)): result = val.realValue
else: result = val
return result
def __str__ (self):
return "Globals: " + str (self.globals) + "Locals: " + str (self.locals)
def populateDefaultVariables (self, options):
vars = {}
self.repeatMap = {}
vars['nothing'] = None
vars['default'] = DEFAULTVALUE
vars['options'] = options
# To start with there are no repeats
vars['repeat'] = self.repeatMap
vars['attrs'] = None
# Add all of these to the global context
for name in vars.keys():
self.addGlobal (name,vars[name])
# Add also under CONTEXTS
self.addGlobal ('CONTEXTS', vars)
@@ -0,0 +1,290 @@
""" simpleTALUtils
Copyright (c) 2005 Colin Stewart (http://www.owlfish.com/)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
If you make any bug fixes or feature enhancements please let me know!
This module is holds utilities that make using SimpleTAL easier.
Initially this is just the HTMLStructureCleaner class, used to clean
up HTML that can then be used as 'structure' content.
Module Dependencies: None
"""
import StringIO, os, stat, threading, sys, codecs, sgmllib, cgi, re, types
import bongo.external.simpletal, bongo.external.simpleTAL
__version__ = simpletal.__version__
# This is used to check for already escaped attributes.
ESCAPED_TEXT_REGEX=re.compile (r"\&\S+?;")
class HTMLStructureCleaner (sgmllib.SGMLParser):
""" A helper class that takes HTML content and parses it, so converting
any stray '&', '<', or '>' symbols into their respective entity references.
"""
def clean (self, content, encoding=None):
""" Takes the HTML content given, parses it, and converts stray markup.
The content can be either:
- A unicode string, in which case the encoding parameter is not required
- An ordinary string, in which case the encoding will be used
- A file-like object, in which case the encoding will be used if present
The method returns a unicode string which is suitable for addition to a
simpleTALES.Context object.
"""
if (isinstance (content, types.StringType)):
# Not unicode, convert
converter = codecs.lookup (encoding)[1]
file = StringIO.StringIO (converter (content)[0])
elif (isinstance (content, types.UnicodeType)):
file = StringIO.StringIO (content)
else:
# Treat it as a file type object - and convert it if we have an encoding
if (encoding is not None):
converterStream = codecs.lookup (encoding)[2]
file = converterStream (content)
else:
file = content
self.outputFile = StringIO.StringIO (u"")
self.feed (file.read())
self.close()
return self.outputFile.getvalue()
def unknown_starttag (self, tag, attributes):
self.outputFile.write (tagAsText (tag, attributes))
def unknown_endtag (self, tag):
self.outputFile.write ('</' + tag + '>')
def handle_data (self, data):
self.outputFile.write (cgi.escape (data))
def handle_charref (self, ref):
self.outputFile.write (u'&#%s;' % ref)
def handle_entityref (self, ref):
self.outputFile.write (u'&%s;' % ref)
class FastStringOutput:
""" A very simple StringIO replacement that only provides write() and getvalue()
and is around 6% faster than StringIO.
"""
def __init__ (self):
self.data = []
def write (self, data):
self.data.append (data)
def getvalue (self):
return "".join (self.data)
class TemplateCache:
""" A TemplateCache is a multi-thread safe object that caches compiled templates.
This cache only works with file based templates, the ctime of the file is
checked on each hit, if the file has changed the template is re-compiled.
"""
def __init__ (self):
self.templateCache = {}
self.cacheLock = threading.Lock()
self.hits = 0
self.misses = 0
def getTemplate (self, name, inputEncoding='ISO-8859-1'):
""" Name should be the path of a template file. If the path ends in 'xml' it is treated
as an XML Template, otherwise it's treated as an HTML Template. If the template file
has changed since the last cache it will be re-compiled.
inputEncoding is only used for HTML templates, and should be the encoding that the template
is stored in.
"""
if (self.templateCache.has_key (name)):
template, oldctime = self.templateCache [name]
ctime = os.stat (name)[stat.ST_MTIME]
if (oldctime == ctime):
# Cache hit!
self.hits += 1
return template
# Cache miss, let's cache this template
return self._cacheTemplate_ (name, inputEncoding)
def getXMLTemplate (self, name):
""" Name should be the path of an XML template file.
"""
if (self.templateCache.has_key (name)):
template, oldctime = self.templateCache [name]
ctime = os.stat (name)[stat.ST_MTIME]
if (oldctime == ctime):
# Cache hit!
self.hits += 1
return template
# Cache miss, let's cache this template
return self._cacheTemplate_ (name, None, xmlTemplate=1)
def _cacheTemplate_ (self, name, inputEncoding, xmlTemplate=0):
self.cacheLock.acquire ()
try:
tempFile = open (name, 'r')
if (xmlTemplate):
# We know it is XML
template = simpleTAL.compileXMLTemplate (tempFile)
else:
# We have to guess...
firstline = tempFile.readline()
tempFile.seek(0)
if (name [-3:] == "xml") or (firstline.strip ()[:5] == '<?xml') or (firstline [:9] == '<!DOCTYPE' and firstline.find('XHTML') != -1):
template = simpleTAL.compileXMLTemplate (tempFile)
else:
template = simpleTAL.compileHTMLTemplate (tempFile, inputEncoding)
tempFile.close()
self.templateCache [name] = (template, os.stat (name)[stat.ST_MTIME])
self.misses += 1
except Exception, e:
self.cacheLock.release()
raise e
self.cacheLock.release()
return template
def tagAsText (tag,atts):
result = "<" + tag
for name,value in atts:
if (ESCAPED_TEXT_REGEX.search (value) is not None):
# We already have some escaped characters in here, so assume it's all valid
result += ' %s="%s"' % (name, value)
else:
result += ' %s="%s"' % (name, cgi.escape (value))
result += ">"
return result
class MacroExpansionInterpreter (simpleTAL.TemplateInterpreter):
def __init__ (self):
simpleTAL.TemplateInterpreter.__init__ (self)
# Override the standard interpreter way of doing things.
self.macroStateStack = []
self.commandHandler [simpleTAL.TAL_DEFINE] = self.cmdNoOp
self.commandHandler [simpleTAL.TAL_CONDITION] = self.cmdNoOp
self.commandHandler [simpleTAL.TAL_REPEAT] = self.cmdNoOp
self.commandHandler [simpleTAL.TAL_CONTENT] = self.cmdNoOp
self.commandHandler [simpleTAL.TAL_ATTRIBUTES] = self.cmdNoOp
self.commandHandler [simpleTAL.TAL_OMITTAG] = self.cmdNoOp
self.commandHandler [simpleTAL.TAL_START_SCOPE] = self.cmdStartScope
self.commandHandler [simpleTAL.TAL_OUTPUT] = self.cmdOutput
self.commandHandler [simpleTAL.TAL_STARTTAG] = self.cmdOutputStartTag
self.commandHandler [simpleTAL.TAL_ENDTAG_ENDSCOPE] = self.cmdEndTagEndScope
self.commandHandler [simpleTAL.METAL_USE_MACRO] = self.cmdUseMacro
self.commandHandler [simpleTAL.METAL_DEFINE_SLOT] = self.cmdDefineSlot
self.commandHandler [simpleTAL.TAL_NOOP] = self.cmdNoOp
self.inMacro = None
self.macroArg = None
# Original cmdOutput
# Original cmdEndTagEndScope
def popProgram (self):
self.inMacro = self.macroStateStack.pop()
simpleTAL.TemplateInterpreter.popProgram (self)
def pushProgram (self):
self.macroStateStack.append (self.inMacro)
simpleTAL.TemplateInterpreter.pushProgram (self)
def cmdOutputStartTag (self, command, args):
newAtts = []
for att, value in self.originalAttributes.items():
if (self.macroArg is not None and att == "metal:define-macro"):
newAtts.append (("metal:use-macro",self.macroArg))
elif (self.inMacro and att=="metal:define-slot"):
newAtts.append (("metal:fill-slot", value))
else:
newAtts.append ((att, value))
self.macroArg = None
self.currentAttributes = newAtts
simpleTAL.TemplateInterpreter.cmdOutputStartTag (self, command, args)
def cmdUseMacro (self, command, args):
simpleTAL.TemplateInterpreter.cmdUseMacro (self, command, args)
if (self.tagContent is not None):
# We have a macro, add the args to the in-macro list
self.inMacro = 1
self.macroArg = args[0]
def cmdEndTagEndScope (self, command, args):
# Args: tagName, omitFlag
if (self.tagContent is not None):
contentType, resultVal = self.tagContent
if (contentType):
if (isinstance (resultVal, simpleTAL.Template)):
# We have another template in the context, evaluate it!
# Save our state!
self.pushProgram()
resultVal.expandInline (self.context, self.file, self)
# Restore state
self.popProgram()
# End of the macro expansion (if any) so clear the parameters
self.slotParameters = {}
# End of the macro
self.inMacro = 0
else:
if (isinstance (resultVal, types.UnicodeType)):
self.file.write (resultVal)
elif (isinstance (resultVal, types.StringType)):
self.file.write (unicode (resultVal, 'ascii'))
else:
self.file.write (unicode (str (resultVal), 'ascii'))
else:
if (isinstance (resultVal, types.UnicodeType)):
self.file.write (cgi.escape (resultVal))
elif (isinstance (resultVal, types.StringType)):
self.file.write (cgi.escape (unicode (resultVal, 'ascii')))
else:
self.file.write (cgi.escape (unicode (str (resultVal), 'ascii')))
if (self.outputTag and not args[1]):
self.file.write ('</' + args[0] + '>')
if (self.movePCBack is not None):
self.programCounter = self.movePCBack
return
if (self.localVarsDefined):
self.context.popLocals()
self.movePCForward,self.movePCBack,self.outputTag,self.originalAttributes,self.currentAttributes,self.repeatVariable,self.tagContent,self.localVarsDefined = self.scopeStack.pop()
self.programCounter += 1
def ExpandMacros (context, template, outputEncoding="ISO-8859-1"):
out = StringIO.StringIO()
interp = MacroExpansionInterpreter()
interp.initialise (context, out)
template.expand (context, out, outputEncoding=outputEncoding, interpreter=interp)
# StringIO returns unicode, so we need to turn it back into native string
result = out.getvalue()
reencoder = codecs.lookup (outputEncoding)[0]
return reencoder (result)[0]
@@ -16,6 +16,7 @@ class DocTypes:
Addressbook = 0x0004
Conversation = 0x0005
Calendar = 0x0006
Config = 0x0007
Folder = 0x1000
Shared = 0x2000