Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 19111 → Rev 19110

/trunk/Scribus/codegen/cheetah/CHANGES
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/CacheRegion.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/CacheStore.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/CheetahWrapper.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/Compiler.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/DirectiveAnalyzer.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/Django.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/DummyTransaction.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/ErrorCatchers.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/FileUtils.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/Filters.py
File deleted
/trunk/Scribus/codegen/cheetah/Cheetah/ImportHooks.py
File deleted
Property changes:
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Index: cheetah/Cheetah/ImportManager.py
===================================================================
--- cheetah/Cheetah/ImportManager.py (revision 19111)
+++ cheetah/Cheetah/ImportManager.py (nonexistent)
@@ -1,541 +0,0 @@
-"""
-Provides an emulator/replacement for Python's standard import system.
-
-@@TR: Be warned that Import Hooks are in the deepest, darkest corner of Python's
-jungle. If you need to start hacking with this, be prepared to get lost for a
-while. Also note, this module predates the newstyle import hooks in Python 2.3
-http://www.python.org/peps/pep-0302.html.
-
-
-This is a hacked/documented version of Gordon McMillan's iu.py. I have:
-
- - made it a little less terse
-
- - added docstrings and explanatations
-
- - standardized the variable naming scheme
-
- - reorganized the code layout to enhance readability
-
-"""
-
-import sys
-import imp
-import marshal
-
-_installed = False
-
-# _globalOwnerTypes is defined at the bottom of this file
-
-_os_stat = _os_path_join = _os_getcwd = _os_path_dirname = None
-
-##################################################
-## FUNCTIONS
-
-def _os_bootstrap():
- """Set up 'os' module replacement functions for use during import bootstrap."""
-
- names = sys.builtin_module_names
-
- join = dirname = None
- if 'posix' in names:
- sep = '/'
- from posix import stat, getcwd
- elif 'nt' in names:
- sep = '\\'
- from nt import stat, getcwd
- elif 'dos' in names:
- sep = '\\'
- from dos import stat, getcwd
- elif 'os2' in names:
- sep = '\\'
- from os2 import stat, getcwd
- elif 'mac' in names:
- from mac import stat, getcwd
- def join(a, b):
- if a == '':
- return b
- if ':' not in a:
- a = ':' + a
- if a[-1:] != ':':
- a = a + ':'
- return a + b
- else:
- raise ImportError('no os specific module found')
-
- if join is None:
- def join(a, b, sep=sep):
- if a == '':
- return b
- lastchar = a[-1:]
- if lastchar == '/' or lastchar == sep:
- return a + b
- return a + sep + b
-
- if dirname is None:
- def dirname(a, sep=sep):
- for i in range(len(a)-1, -1, -1):
- c = a[i]
- if c == '/' or c == sep:
- return a[:i]
- return ''
-
- global _os_stat
- _os_stat = stat
-
- global _os_path_join
- _os_path_join = join
-
- global _os_path_dirname
- _os_path_dirname = dirname
-
- global _os_getcwd
- _os_getcwd = getcwd
-
-_os_bootstrap()
-
-def packageName(s):
- for i in range(len(s)-1, -1, -1):
- if s[i] == '.':
- break
- else:
- return ''
- return s[:i]
-
-def nameSplit(s):
- rslt = []
- i = j = 0
- for j in range(len(s)):
- if s[j] == '.':
- rslt.append(s[i:j])
- i = j+1
- if i < len(s):
- rslt.append(s[i:])
- return rslt
-
-def getPathExt(fnm):
- for i in range(len(fnm)-1, -1, -1):
- if fnm[i] == '.':
- return fnm[i:]
- return ''
-
-def pathIsDir(pathname):
- "Local replacement for os.path.isdir()."
- try:
- s = _os_stat(pathname)
- except OSError:
- return None
- return (s[0] & 0170000) == 0040000
-
-def getDescr(fnm):
- ext = getPathExt(fnm)
- for (suffix, mode, typ) in imp.get_suffixes():
- if suffix == ext:
- return (suffix, mode, typ)
-
-##################################################
-## CLASSES
-
-class Owner:
-
- """An Owner does imports from a particular piece of turf That is, there's
- an Owner for each thing on sys.path There are owners for directories and
- .pyz files. There could be owners for zip files, or even URLs. A
- shadowpath (a dictionary mapping the names in sys.path to their owners) is
- used so that sys.path (or a package's __path__) is still a bunch of strings,
- """
-
- def __init__(self, path):
- self.path = path
-
- def __str__(self):
- return self.path
-
- def getmod(self, nm):
- return None
-
-class DirOwner(Owner):
-
- def __init__(self, path):
- if path == '':
- path = _os_getcwd()
- if not pathIsDir(path):
- raise ValueError("%s is not a directory" % path)
- Owner.__init__(self, path)
-
- def getmod(self, nm,
- getsuffixes=imp.get_suffixes, loadco=marshal.loads, newmod=imp.new_module):
-
- pth = _os_path_join(self.path, nm)
-
- possibles = [(pth, 0, None)]
- if pathIsDir(pth):
- possibles.insert(0, (_os_path_join(pth, '__init__'), 1, pth))
- py = pyc = None
- for pth, ispkg, pkgpth in possibles:
- for ext, mode, typ in getsuffixes():
- attempt = pth+ext
- try:
- st = _os_stat(attempt)
- except:
- pass
- else:
- if typ == imp.C_EXTENSION:
- fp = open(attempt, 'rb')
- mod = imp.load_module(nm, fp, attempt, (ext, mode, typ))
- mod.__file__ = attempt
- return mod
- elif typ == imp.PY_SOURCE:
- py = (attempt, st)
- else:
- pyc = (attempt, st)
- if py or pyc:
- break
- if py is None and pyc is None:
- return None
- while True:
- if pyc is None or py and pyc[1][8] < py[1][8]:
- try:
- co = compile(open(py[0], 'r').read()+'\n', py[0], 'exec')
- break
- except SyntaxError, e:
- print("Invalid syntax in %s" % py[0])
- print(e.args)
- raise
- elif pyc:
- stuff = open(pyc[0], 'rb').read()
- try:
- co = loadco(stuff[8:])
- break
- except (ValueError, EOFError):
- pyc = None
- else:
- return None
- mod = newmod(nm)
- mod.__file__ = co.co_filename
- if ispkg:
- mod.__path__ = [pkgpth]
- subimporter = PathImportDirector(mod.__path__)
- mod.__importsub__ = subimporter.getmod
- mod.__co__ = co
- return mod
-
-
-class ImportDirector(Owner):
- """ImportDirectors live on the metapath There's one for builtins, one for
- frozen modules, and one for sys.path Windows gets one for modules gotten
- from the Registry Mac would have them for PY_RESOURCE modules etc. A
- generalization of Owner - their concept of 'turf' is broader"""
-
- pass
-
-class BuiltinImportDirector(ImportDirector):
- """Directs imports of builtin modules"""
- def __init__(self):
- self.path = 'Builtins'
-
- def getmod(self, nm, isbuiltin=imp.is_builtin):
- if isbuiltin(nm):
- mod = imp.load_module(nm, None, nm, ('', '', imp.C_BUILTIN))
- return mod
- return None
-
-class FrozenImportDirector(ImportDirector):
- """Directs imports of frozen modules"""
-
- def __init__(self):
- self.path = 'FrozenModules'
-
- def getmod(self, nm,
- isFrozen=imp.is_frozen, loadMod=imp.load_module):
- if isFrozen(nm):
- mod = loadMod(nm, None, nm, ('', '', imp.PY_FROZEN))
- if hasattr(mod, '__path__'):
- mod.__importsub__ = lambda name, pname=nm, owner=self: owner.getmod(pname+'.'+name)
- return mod
- return None
-
-
-class RegistryImportDirector(ImportDirector):
- """Directs imports of modules stored in the Windows Registry"""
-
- def __init__(self):
- self.path = "WindowsRegistry"
- self.map = {}
- try:
- import win32api
- ## import win32con
- except ImportError:
- pass
- else:
- HKEY_CURRENT_USER = -2147483647
- HKEY_LOCAL_MACHINE = -2147483646
- KEY_ALL_ACCESS = 983103
- subkey = r"Software\Python\PythonCore\%s\Modules" % sys.winver
- for root in (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE):
- try:
- hkey = win32api.RegOpenKeyEx(root, subkey, 0, KEY_ALL_ACCESS)
- except:
- pass
- else:
- numsubkeys, numvalues, lastmodified = win32api.RegQueryInfoKey(hkey)
- for i in range(numsubkeys):
- subkeyname = win32api.RegEnumKey(hkey, i)
- hskey = win32api.RegOpenKeyEx(hkey, subkeyname, 0, KEY_ALL_ACCESS)
- val = win32api.RegQueryValueEx(hskey, '')
- desc = getDescr(val[0])
- self.map[subkeyname] = (val[0], desc)
- hskey.Close()
- hkey.Close()
- break
-
- def getmod(self, nm):
- stuff = self.map.get(nm)
- if stuff:
- fnm, desc = stuff
- fp = open(fnm, 'rb')
- mod = imp.load_module(nm, fp, fnm, desc)
- mod.__file__ = fnm
- return mod
- return None
-
-class PathImportDirector(ImportDirector):
- """Directs imports of modules stored on the filesystem."""
-
- def __init__(self, pathlist=None, importers=None, ownertypes=None):
- if pathlist is None:
- self.path = sys.path
- else:
- self.path = pathlist
- if ownertypes == None:
- self._ownertypes = _globalOwnerTypes
- else:
- self._ownertypes = ownertypes
- if importers:
- self._shadowPath = importers
- else:
- self._shadowPath = {}
- self._inMakeOwner = False
- self._building = {}
-
- def getmod(self, nm):
- mod = None
- for thing in self.path:
- if isinstance(thing, basestring):
- owner = self._shadowPath.get(thing, -1)
- if owner == -1:
- owner = self._shadowPath[thing] = self._makeOwner(thing)
- if owner:
- mod = owner.getmod(nm)
- else:
- mod = thing.getmod(nm)
- if mod:
- break
- return mod
-
- def _makeOwner(self, path):
- if self._building.get(path):
- return None
- self._building[path] = 1
- owner = None
- for klass in self._ownertypes:
- try:
- # this may cause an import, which may cause recursion
- # hence the protection
- owner = klass(path)
- except:
- pass
- else:
- break
- del self._building[path]
- return owner
-
-#=================ImportManager============================#
-# The one-and-only ImportManager
-# ie, the builtin import
-
-UNTRIED = -1
-
-class ImportManager:
- # really the equivalent of builtin import
- def __init__(self):
- self.metapath = [
- BuiltinImportDirector(),
- FrozenImportDirector(),
- RegistryImportDirector(),
- PathImportDirector()
- ]
- self.threaded = 0
- self.rlock = None
- self.locker = None
- self.setThreaded()
-
- def setThreaded(self):
- thread = sys.modules.get('thread', None)
- if thread and not self.threaded:
- self.threaded = 1
- self.rlock = thread.allocate_lock()
- self._get_ident = thread.get_ident
-
- def install(self):
- import __builtin__
- __builtin__.__import__ = self.importHook
- __builtin__.reload = self.reloadHook
-
- def importHook(self, name, globals=None, locals=None, fromlist=None, level=-1):
- '''
- NOTE: Currently importHook will accept the keyword-argument "level"
- but it will *NOT* use it (currently). Details about the "level" keyword
- argument can be found here: http://www.python.org/doc/2.5.2/lib/built-in-funcs.html
- '''
- # first see if we could be importing a relative name
- #print "importHook(%s, %s, locals, %s)" % (name, globals['__name__'], fromlist)
- _sys_modules_get = sys.modules.get
- contexts = [None]
- if globals:
- importernm = globals.get('__name__', '')
- if importernm:
- if hasattr(_sys_modules_get(importernm), '__path__'):
- contexts.insert(0, importernm)
- else:
- pkgnm = packageName(importernm)
- if pkgnm:
- contexts.insert(0, pkgnm)
- # so contexts is [pkgnm, None] or just [None]
- # now break the name being imported up so we get:
- # a.b.c -> [a, b, c]
- nmparts = nameSplit(name)
- _self_doimport = self.doimport
- threaded = self.threaded
- for context in contexts:
- ctx = context
- for i in range(len(nmparts)):
- nm = nmparts[i]
- #print " importHook trying %s in %s" % (nm, ctx)
- if ctx:
- fqname = ctx + '.' + nm
- else:
- fqname = nm
- if threaded:
- self._acquire()
- mod = _sys_modules_get(fqname, UNTRIED)
- if mod is UNTRIED:
- mod = _self_doimport(nm, ctx, fqname)
- if threaded:
- self._release()
- if mod:
- ctx = fqname
- else:
- break
- else:
- # no break, point i beyond end
- i = i + 1
- if i:
- break
-
- if i<len(nmparts):
- if ctx and hasattr(sys.modules[ctx], nmparts[i]):
- #print "importHook done with %s %s %s (case 1)" % (name, globals['__name__'], fromlist)
- return sys.modules[nmparts[0]]
- del sys.modules[fqname]
- raise ImportError("No module named %s" % fqname)
- if fromlist is None:
- #print "importHook done with %s %s %s (case 2)" % (name, globals['__name__'], fromlist)
- if context:
- return sys.modules[context+'.'+nmparts[0]]
- return sys.modules[nmparts[0]]
- bottommod = sys.modules[ctx]
- if hasattr(bottommod, '__path__'):
- fromlist = list(fromlist)
- i = 0
- while i < len(fromlist):
- nm = fromlist[i]
- if nm == '*':
- fromlist[i:i+1] = list(getattr(bottommod, '__all__', []))
- if i >= len(fromlist):
- break
- nm = fromlist[i]
- i = i + 1
- if not hasattr(bottommod, nm):
- if self.threaded:
- self._acquire()
- mod = self.doimport(nm, ctx, ctx+'.'+nm)
- if self.threaded:
- self._release()
- if not mod:
- raise ImportError("%s not found in %s" % (nm, ctx))
- #print "importHook done with %s %s %s (case 3)" % (name, globals['__name__'], fromlist)
- return bottommod
-
- def doimport(self, nm, parentnm, fqname):
- # Not that nm is NEVER a dotted name at this point
- #print "doimport(%s, %s, %s)" % (nm, parentnm, fqname)
- if parentnm:
- parent = sys.modules[parentnm]
- if hasattr(parent, '__path__'):
- importfunc = getattr(parent, '__importsub__', None)
- if not importfunc:
- subimporter = PathImportDirector(parent.__path__)
- importfunc = parent.__importsub__ = subimporter.getmod
- mod = importfunc(nm)
- if mod:
- setattr(parent, nm, mod)
- else:
- #print "..parent not a package"
- return None
- else:
- # now we're dealing with an absolute import
- for director in self.metapath:
- mod = director.getmod(nm)
- if mod:
- break
- if mod:
- mod.__name__ = fqname
- sys.modules[fqname] = mod
- if hasattr(mod, '__co__'):
- co = mod.__co__
- del mod.__co__
- exec(co, mod.__dict__)
- if fqname == 'thread' and not self.threaded:
-## print "thread detected!"
- self.setThreaded()
- else:
- sys.modules[fqname] = None
- #print "..found %s" % mod
- return mod
-
- def reloadHook(self, mod):
- fqnm = mod.__name__
- nm = nameSplit(fqnm)[-1]
- parentnm = packageName(fqnm)
- newmod = self.doimport(nm, parentnm, fqnm)
- mod.__dict__.update(newmod.__dict__)
-## return newmod
-
- def _acquire(self):
- if self.rlock.locked():
- if self.locker == self._get_ident():
- self.lockcount = self.lockcount + 1
-## print "_acquire incrementing lockcount to", self.lockcount
- return
- self.rlock.acquire()
- self.locker = self._get_ident()
- self.lockcount = 0
-## print "_acquire first time!"
-
- def _release(self):
- if self.lockcount:
- self.lockcount = self.lockcount - 1
-## print "_release decrementing lockcount to", self.lockcount
- else:
- self.rlock.release()
-## print "_release releasing lock!"
-
-
-##################################################
-## MORE CONSTANTS & GLOBALS
-
-_globalOwnerTypes = [
- DirOwner,
- Owner,
-]
/cheetah/Cheetah/ImportManager.py
Property changes:
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Index: cheetah/Cheetah/Macros/I18n.py
===================================================================
--- cheetah/Cheetah/Macros/I18n.py (revision 19111)
+++ cheetah/Cheetah/Macros/I18n.py (nonexistent)
@@ -1,67 +0,0 @@
-import gettext
-_ = gettext.gettext
-class I18n(object):
- def __init__(self, parser):
- pass
-
-## junk I'm playing with to test the macro framework
-# def parseArgs(self, parser, startPos):
-# parser.getWhiteSpace()
-# args = parser.getExpression(useNameMapper=False,
-# pyTokensToBreakAt=[':']).strip()
-# return args
-#
-# def convertArgStrToDict(self, args, parser=None, startPos=None):
-# def getArgs(*pargs, **kws):
-# return pargs, kws
-# exec 'positionalArgs, kwArgs = getArgs(%(args)s)'%locals()
-# return kwArgs
-
- def __call__(self,
- src, # aka message,
- plural=None,
- n=None, # should be a string representing the name of the
- # '$var' rather than $var itself
- id=None,
- domain=None,
- source=None,
- target=None,
- comment=None,
-
- # args that are automatically supplied by the parser when the
- # macro is called:
- parser=None,
- macros=None,
- isShortForm=False,
- EOLCharsInShortForm=None,
- startPos=None,
- endPos=None,
- ):
- """This is just a stub at this time.
-
- plural = the plural form of the message
- n = a sized argument to distinguish between single and plural forms
-
- id = msgid in the translation catalog
- domain = translation domain
- source = source lang
- target = a specific target lang
- comment = a comment to the translation team
-
- See the following for some ideas
- http://www.zope.org/DevHome/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport
-
- Other notes:
- - There is no need to replicate the i18n:name attribute from plone / PTL,
- as cheetah placeholders serve the same purpose
-
-
- """
-
- #print macros['i18n']
- src = _(src)
- if isShortForm and endPos<len(parser):
- return src+EOLCharsInShortForm
- else:
- return src
-
Index: cheetah/Cheetah/Macros/__init__.py
===================================================================
--- cheetah/Cheetah/Macros/__init__.py (revision 19111)
+++ cheetah/Cheetah/Macros/__init__.py (nonexistent)
@@ -1 +0,0 @@
-#
Index: cheetah/Cheetah/NameMapper.py
===================================================================
--- cheetah/Cheetah/NameMapper.py (revision 19111)
+++ cheetah/Cheetah/NameMapper.py (nonexistent)
@@ -1,366 +0,0 @@
-#!/usr/bin/env python
-"""This module supports Cheetah's optional NameMapper syntax.
-
-Overview
-================================================================================
-
-NameMapper provides a simple syntax for accessing Python data structures,
-functions, and methods from Cheetah. It's called NameMapper because it 'maps'
-simple 'names' in Cheetah templates to possibly more complex syntax in Python.
-
-Its purpose is to make working with Cheetah easy for non-programmers.
-Specifically, non-programmers using Cheetah should NOT need to be taught (a)
-what the difference is between an object and a dictionary, (b) what functions
-and methods are, and (c) what 'self' is. A further aim (d) is to buffer the
-code in Cheetah templates from changes in the implementation of the Python data
-structures behind them.
-
-Consider this scenario:
-
-You are building a customer information system. The designers with you want to
-use information from your system on the client's website --AND-- they want to
-understand the display code and so they can maintian it themselves.
-
-You write a UI class with a 'customers' method that returns a dictionary of all
-the customer objects. Each customer object has an 'address' method that returns
-the a dictionary with information about the customer's address. The designers
-want to be able to access that information.
-
-Using PSP, the display code for the website would look something like the
-following, assuming your servlet subclasses the class you created for managing
-customer information:
-
- <%= self.customer()[ID].address()['city'] %> (42 chars)
-
-Using Cheetah's NameMapper syntax it could be any of the following:
-
- $self.customers()[$ID].address()['city'] (39 chars)
- --OR--
- $customers()[$ID].address()['city']
- --OR--
- $customers()[$ID].address().city
- --OR--
- $customers()[$ID].address.city
- --OR--
- $customers()[$ID].address.city
- --OR--
- $customers[$ID].address.city (27 chars)
-
-
-Which of these would you prefer to explain to the designers, who have no
-programming experience? The last form is 15 characters shorter than the PSP
-and, conceptually, is far more accessible. With PHP or ASP, the code would be
-even messier than the PSP
-
-This is a rather extreme example and, of course, you could also just implement
-'$getCustomer($ID).city' and obey the Law of Demeter (search Google for more on that).
-But good object orientated design isn't the point here.
-
-Details
-================================================================================
-The parenthesized letters below correspond to the aims in the second paragraph.
-
-DICTIONARY ACCESS (a)
----------------------
-
-NameMapper allows access to items in a dictionary using the same dotted notation
-used to access object attributes in Python. This aspect of NameMapper is known
-as 'Unified Dotted Notation'.
-
-For example, with Cheetah it is possible to write:
- $customers()['kerr'].address() --OR-- $customers().kerr.address()
-where the second form is in NameMapper syntax.
-
-This only works with dictionary keys that are also valid python identifiers:
- regex = '[a-zA-Z_][a-zA-Z_0-9]*'
-
-
-AUTOCALLING (b,d)
------------------
-
-NameMapper automatically detects functions and methods in Cheetah $vars and calls
-them if the parentheses have been left off.
-
-For example if 'a' is an object, 'b' is a method
- $a.b
-is equivalent to
- $a.b()
-
-If b returns a dictionary, then following variations are possible
- $a.b.c --OR-- $a.b().c --OR-- $a.b()['c']
-where 'c' is a key in the dictionary that a.b() returns.
-
-Further notes:
-* NameMapper autocalls the function or method without any arguments. Thus
-autocalling can only be used with functions or methods that either have no
-arguments or have default values for all arguments.
-
-* NameMapper only autocalls functions and methods. Classes and callable object instances
-will not be autocalled.
-
-* Autocalling can be disabled using Cheetah's 'useAutocalling' setting.
-
-LEAVING OUT 'self' (c,d)
-------------------------
-
-NameMapper makes it possible to access the attributes of a servlet in Cheetah
-without needing to include 'self' in the variable names. See the NAMESPACE
-CASCADING section below for details.
-
-NAMESPACE CASCADING (d)
---------------------
-...
-
-Implementation details
-================================================================================
-
-* NameMapper's search order is dictionary keys then object attributes
-
-* NameMapper.NotFound is raised if a value can't be found for a name.
-
-Performance and the C version
-================================================================================
-
-Cheetah comes with both a C version and a Python version of NameMapper. The C
-version is significantly faster and the exception tracebacks are much easier to
-read. It's still slower than standard Python syntax, but you won't notice the
-difference in realistic usage scenarios.
-
-Cheetah uses the optimized C version (_namemapper.c) if it has
-been compiled or falls back to the Python version if not.
-"""
-
-__author__ = "Tavis Rudd <tavis@damnsimple.com>," +\
- "\nChuck Esterbrook <echuck@mindspring.com>"
-from pprint import pformat
-import inspect
-
-_INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS = False
-_ALLOW_WRAPPING_OF_NOTFOUND_EXCEPTIONS = True
-__all__ = ['NotFound',
- 'hasKey',
- 'valueForKey',
- 'valueForName',
- 'valueFromSearchList',
- 'valueFromFrameOrSearchList',
- 'valueFromFrame',
- ]
-
-if not hasattr(inspect.imp, 'get_suffixes'):
- # This is to fix broken behavior of the inspect module under the
- # Google App Engine, see the following issue:
- # http://bugs.communitycheetah.org/view.php?id=10
- setattr(inspect.imp, 'get_suffixes', lambda: [('.py', 'U', 1)])
-
-## N.B. An attempt is made at the end of this module to import C versions of
-## these functions. If _namemapper.c has been compiled succesfully and the
-## import goes smoothly, the Python versions defined here will be replaced with
-## the C versions.
-
-class NotFound(LookupError):
- pass
-
-def _raiseNotFoundException(key, namespace):
- excString = "cannot find '%s'"%key
- if _INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS:
- excString += ' in the namespace %s'%pformat(namespace)
- raise NotFound(excString)
-
-def _wrapNotFoundException(exc, fullName, namespace):
- if not _ALLOW_WRAPPING_OF_NOTFOUND_EXCEPTIONS:
- raise
- else:
- excStr = exc.args[0]
- if excStr.find('while searching')==-1: # only wrap once!
- excStr +=" while searching for '%s'"%fullName
- if _INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS:
- excStr += ' in the namespace %s'%pformat(namespace)
- exc.args = (excStr,)
- raise
-
-def _isInstanceOrClass(obj):
- if isinstance(obj, type):
- # oldstyle
- return True
-
- if hasattr(obj, "__class__"):
- # newstyle
- if hasattr(obj, 'mro'):
- # type/class
- return True
- elif (hasattr(obj, 'im_func') or hasattr(obj, 'func_code') or hasattr(obj, '__self__')):
- # method, func, or builtin func
- return False
- elif hasattr(obj, '__init__'):
- # instance
- return True
- return False
-
-def hasKey(obj, key):
- """Determine if 'obj' has 'key' """
- if hasattr(obj, 'has_key') and key in obj:
- return True
- elif hasattr(obj, key):
- return True
- else:
- return False
-
-def valueForKey(obj, key):
- if hasattr(obj, 'has_key') and key in obj:
- return obj[key]
- elif hasattr(obj, key):
- return getattr(obj, key)
- else:
- _raiseNotFoundException(key, obj)
-
-def _valueForName(obj, name, executeCallables=False):
- nameChunks=name.split('.')
- for i in range(len(nameChunks)):
- key = nameChunks[i]
- if hasattr(obj, 'has_key') and key in obj:
- nextObj = obj[key]
- else:
- try:
- nextObj = getattr(obj, key)
- except AttributeError:
- _raiseNotFoundException(key, obj)
-
- if executeCallables and hasattr(nextObj, '__call__') and not _isInstanceOrClass(nextObj):
- obj = nextObj()
- else:
- obj = nextObj
- return obj
-
-def valueForName(obj, name, executeCallables=False):
- try:
- return _valueForName(obj, name, executeCallables)
- except NotFound, e:
- _wrapNotFoundException(e, fullName=name, namespace=obj)
-
-def valueFromSearchList(searchList, name, executeCallables=False):
- key = name.split('.')[0]
- for namespace in searchList:
- if hasKey(namespace, key):
- return _valueForName(namespace, name,
- executeCallables=executeCallables)
- _raiseNotFoundException(key, searchList)
-
-def _namespaces(callerFrame, searchList=None):
- yield callerFrame.f_locals
- if searchList:
- for namespace in searchList:
- yield namespace
- yield callerFrame.f_globals
- yield __builtins__
-
-def valueFromFrameOrSearchList(searchList, name, executeCallables=False,
- frame=None):
- def __valueForName():
- try:
- return _valueForName(namespace, name, executeCallables=executeCallables)
- except NotFound, e:
- _wrapNotFoundException(e, fullName=name, namespace=searchList)
- try:
- if not frame:
- frame = inspect.stack()[1][0]
- key = name.split('.')[0]
- for namespace in _namespaces(frame, searchList):
- if hasKey(namespace, key):
- return __valueForName()
- _raiseNotFoundException(key, searchList)
- finally:
- del frame
-
-def valueFromFrame(name, executeCallables=False, frame=None):
- # @@TR consider implementing the C version the same way
- # at the moment it provides a seperate but mirror implementation
- # to valueFromFrameOrSearchList
- try:
- if not frame:
- frame = inspect.stack()[1][0]
- return valueFromFrameOrSearchList(searchList=None,
- name=name,
- executeCallables=executeCallables,
- frame=frame)
- finally:
- del frame
-
-def hasName(obj, name):
- #Not in the C version
- """Determine if 'obj' has the 'name' """
- key = name.split('.')[0]
- if not hasKey(obj, key):
- return False
- try:
- valueForName(obj, name)
- return True
- except NotFound:
- return False
-try:
- from Cheetah._namemapper import NotFound, valueForKey, valueForName, \
- valueFromSearchList, valueFromFrameOrSearchList, valueFromFrame
- # it is possible with Jython or Windows, for example, that _namemapper.c hasn't been compiled
- C_VERSION = True
-except:
- C_VERSION = False
-
-##################################################
-## CLASSES
-
-class Mixin:
- """@@ document me"""
- def valueForName(self, name):
- return valueForName(self, name)
-
- def valueForKey(self, key):
- return valueForKey(self, key)
-
-##################################################
-## if run from the command line ##
-
-def example():
- class A(Mixin):
- classVar = 'classVar val'
- def method(self,arg='method 1 default arg'):
- return arg
-
- def method2(self, arg='meth 2 default arg'):
- return {'item1':arg}
-
- def method3(self, arg='meth 3 default'):
- return arg
-
- class B(A):
- classBvar = 'classBvar val'
-
- a = A()
- a.one = 'valueForOne'
- def function(whichOne='default'):
- values = {
- 'default': 'default output',
- 'one': 'output option one',
- 'two': 'output option two'
- }
- return values[whichOne]
-
- a.dic = {
- 'func': function,
- 'method': a.method3,
- 'item': 'itemval',
- 'subDict': {'nestedMethod':a.method3}
- }
- b = 'this is local b'
-
- print(valueForKey(a.dic, 'subDict'))
- print(valueForName(a, 'dic.item'))
- print(valueForName(vars(), 'b'))
- print(valueForName(__builtins__, 'dir')())
- print(valueForName(vars(), 'a.classVar'))
- print(valueForName(vars(), 'a.dic.func', executeCallables=True))
- print(valueForName(vars(), 'a.method2.item1', executeCallables=True))
-
-if __name__ == '__main__':
- example()
-
-
-
Index: cheetah/Cheetah/Parser.py
===================================================================
--- cheetah/Cheetah/Parser.py (revision 19111)
+++ cheetah/Cheetah/Parser.py (nonexistent)
@@ -1,2661 +0,0 @@
-#!/usr/bin/env python
-"""
-Parser classes for Cheetah's Compiler
-
-Classes:
- ParseError( Exception )
- _LowLevelParser( Cheetah.SourceReader.SourceReader ), basically a lexer
- _HighLevelParser( _LowLevelParser )
- Parser === _HighLevelParser (an alias)
-"""
-
-import os
-import sys
-import re
-from re import DOTALL, MULTILINE
-import types
-import time
-from tokenize import pseudoprog
-import inspect
-import traceback
-
-from Cheetah.SourceReader import SourceReader
-from Cheetah import Filters
-from Cheetah import ErrorCatchers
-from Cheetah.Unspecified import Unspecified
-from Cheetah.Macros.I18n import I18n
-
-# re tools
-_regexCache = {}
-def cachedRegex(pattern):
- if pattern not in _regexCache:
- _regexCache[pattern] = re.compile(pattern)
- return _regexCache[pattern]
-
-def escapeRegexChars(txt,
- escapeRE=re.compile(r'([\$\^\*\+\.\?\{\}\[\]\(\)\|\\])')):
-
- """Return a txt with all special regular expressions chars escaped."""
-
- return escapeRE.sub(r'\\\1', txt)
-
-def group(*choices): return '(' + '|'.join(choices) + ')'
-def nongroup(*choices): return '(?:' + '|'.join(choices) + ')'
-def namedGroup(name, *choices): return '(P:<' + name +'>' + '|'.join(choices) + ')'
-def any(*choices): return group(*choices) + '*'
-def maybe(*choices): return group(*choices) + '?'
-
-##################################################
-## CONSTANTS & GLOBALS ##
-
-NO_CACHE = 0
-STATIC_CACHE = 1
-REFRESH_CACHE = 2
-
-SET_LOCAL = 0
-SET_GLOBAL = 1
-SET_MODULE = 2
-
-##################################################
-## Tokens for the parser ##
-
-#generic
-identchars = "abcdefghijklmnopqrstuvwxyz" \
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
-namechars = identchars + "0123456789"
-
-#operators
-powerOp = '**'
-unaryArithOps = ('+', '-', '~')
-binaryArithOps = ('+', '-', '/', '//', '%')
-shiftOps = ('>>', '<<')
-bitwiseOps = ('&', '|', '^')
-assignOp = '='
-augAssignOps = ('+=', '-=', '/=', '*=', '**=', '^=', '%=',
- '>>=', '<<=', '&=', '|=', )
-assignmentOps = (assignOp,) + augAssignOps
-
-compOps = ('<', '>', '==', '!=', '<=', '>=', '<>', 'is', 'in',)
-booleanOps = ('and', 'or', 'not')
-operators = (powerOp,) + unaryArithOps + binaryArithOps \
- + shiftOps + bitwiseOps + assignmentOps \
- + compOps + booleanOps
-
-delimeters = ('(', ')', '{', '}', '[', ']',
- ',', '.', ':', ';', '=', '`') + augAssignOps
-
-
-keywords = ('and', 'del', 'for', 'is', 'raise',
- 'assert', 'elif', 'from', 'lambda', 'return',
- 'break', 'else', 'global', 'not', 'try',
- 'class', 'except', 'if', 'or', 'while',
- 'continue', 'exec', 'import', 'pass',
- 'def', 'finally', 'in', 'print',
- )
-
-single3 = "'''"
-double3 = '"""'
-
-tripleQuotedStringStarts = ("'''", '"""',
- "r'''", 'r"""', "R'''", 'R"""',
- "u'''", 'u"""', "U'''", 'U"""',
- "ur'''", 'ur"""', "Ur'''", 'Ur"""',
- "uR'''", 'uR"""', "UR'''", 'UR"""')
-
-tripleQuotedStringPairs = {"'''": single3, '"""': double3,
- "r'''": single3, 'r"""': double3,
- "u'''": single3, 'u"""': double3,
- "ur'''": single3, 'ur"""': double3,
- "R'''": single3, 'R"""': double3,
- "U'''": single3, 'U"""': double3,
- "uR'''": single3, 'uR"""': double3,
- "Ur'''": single3, 'Ur"""': double3,
- "UR'''": single3, 'UR"""': double3,
- }
-
-closurePairs= {')':'(',']':'[','}':'{'}
-closurePairsRev= {'(':')','[':']','{':'}'}
-
-##################################################
-## Regex chunks for the parser ##
-
-tripleQuotedStringREs = {}
-def makeTripleQuoteRe(start, end):
- start = escapeRegexChars(start)
- end = escapeRegexChars(end)
- return re.compile(r'(?:' + start + r').*?' + r'(?:' + end + r')', re.DOTALL)
-
-for start, end in tripleQuotedStringPairs.items():
- tripleQuotedStringREs[start] = makeTripleQuoteRe(start, end)
-
-WS = r'[ \f\t]*'
-EOL = r'\r\n|\n|\r'
-EOLZ = EOL + r'|\Z'
-escCharLookBehind = nongroup(r'(?<=\A)', r'(?<!\\)')
-nameCharLookAhead = r'(?=[A-Za-z_])'
-identRE=re.compile(r'[a-zA-Z_][a-zA-Z_0-9]*')
-EOLre=re.compile(r'(?:\r\n|\r|\n)')
-
-specialVarRE=re.compile(r'([a-zA-z_]+)@') # for matching specialVar comments
-# e.g. ##author@ Tavis Rudd
-
-unicodeDirectiveRE = re.compile(
- r'(?:^|\r\n|\r|\n)\s*#\s{0,5}unicode[:\s]*([-\w.]*)\s*(?:\r\n|\r|\n)', re.MULTILINE)
-encodingDirectiveRE = re.compile(
- r'(?:^|\r\n|\r|\n)\s*#\s{0,5}encoding[:\s]*([-\w.]*)\s*(?:\r\n|\r|\n)', re.MULTILINE)
-
-escapedNewlineRE = re.compile(r'(?<!\\)((\\\\)*)\\(n|012)')
-
-directiveNamesAndParsers = {
- # importing and inheritance
- 'import': None,
- 'from': None,
- 'extends': 'eatExtends',
- 'implements': 'eatImplements',
- 'super': 'eatSuper',
-
- # output, filtering, and caching
- 'slurp': 'eatSlurp',
- 'raw': 'eatRaw',
- 'include': 'eatInclude',
- 'cache': 'eatCache',
- 'filter': 'eatFilter',
- 'echo': None,
- 'silent': None,
- 'transform': 'eatTransform',
-
- 'call': 'eatCall',
- 'arg': 'eatCallArg',
-
- 'capture': 'eatCapture',
-
- # declaration, assignment, and deletion
- 'attr': 'eatAttr',
- 'def': 'eatDef',
- 'block': 'eatBlock',
- '@': 'eatDecorator',
- 'defmacro': 'eatDefMacro',
-
- 'closure': 'eatClosure',
-
- 'set': 'eatSet',
- 'del': None,
-
- # flow control
- 'if': 'eatIf',
- 'while': None,
- 'for': None,
- 'else': None,
- 'elif': None,
- 'pass': None,
- 'break': None,
- 'continue': None,
- 'stop': None,
- 'return': None,
- 'yield': None,
-
- # little wrappers
- 'repeat': None,
- 'unless': None,
-
- # error handling
- 'assert': None,
- 'raise': None,
- 'try': None,
- 'except': None,
- 'finally': None,
- 'errorCatcher': 'eatErrorCatcher',
-
- # intructions to the parser and compiler
- 'breakpoint': 'eatBreakPoint',
- 'compiler': 'eatCompiler',
- 'compiler-settings': 'eatCompilerSettings',
-
- # misc
- 'shBang': 'eatShbang',
- 'encoding': 'eatEncoding',
-
- 'end': 'eatEndDirective',
- }
-
-endDirectiveNamesAndHandlers = {
- 'def': 'handleEndDef', # has short-form
- 'block': None, # has short-form
- 'closure': None, # has short-form
- 'cache': None, # has short-form
- 'call': None, # has short-form
- 'capture': None, # has short-form
- 'filter': None,
- 'errorCatcher': None,
- 'while': None, # has short-form
- 'for': None, # has short-form
- 'if': None, # has short-form
- 'try': None, # has short-form
- 'repeat': None, # has short-form
- 'unless': None, # has short-form
- }
-
-##################################################
-## CLASSES ##
-
-# @@TR: SyntaxError doesn't call exception.__str__ for some reason!
-#class ParseError(SyntaxError):
-class ParseError(ValueError):
- def __init__(self, stream, msg='Invalid Syntax', extMsg='', lineno=None, col=None):
- self.stream = stream
- if stream.pos() >= len(stream):
- stream.setPos(len(stream) -1)
- self.msg = msg
- self.extMsg = extMsg
- self.lineno = lineno
- self.col = col
-
- def __str__(self):
- return self.report()
-
- def report(self):
- stream = self.stream
- if stream.filename():
- f = " in file %s" % stream.filename()
- else:
- f = ''
- report = ''
- if self.lineno:
- lineno = self.lineno
- row, col, line = (lineno, (self.col or 0),
- self.stream.splitlines()[lineno-1])
- else:
- row, col, line = self.stream.getRowColLine()
-
- ## get the surrounding lines
- lines = stream.splitlines()
- prevLines = [] # (rowNum, content)
- for i in range(1, 4):
- if row-1-i <=0:
- break
- prevLines.append( (row-i, lines[row-1-i]) )
-
- nextLines = [] # (rowNum, content)
- for i in range(1, 4):
- if not row-1+i < len(lines):
- break
- nextLines.append( (row+i, lines[row-1+i]) )
- nextLines.reverse()
-
- ## print the main message
- report += "\n\n%s\n" %self.msg
- report += "Line %i, column %i%s\n\n" % (row, col, f)
- report += 'Line|Cheetah Code\n'
- report += '----|-------------------------------------------------------------\n'
- while prevLines:
- lineInfo = prevLines.pop()
- report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]}
- report += "%(row)-4d|%(line)s\n"% {'row':row, 'line':line}
- report += ' '*5 +' '*(col-1) + "^\n"
-
- while nextLines:
- lineInfo = nextLines.pop()
- report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]}
- ## add the extra msg
- if self.extMsg:
- report += self.extMsg + '\n'
-
- return report
-
-class ForbiddenSyntax(ParseError):
- pass
-class ForbiddenExpression(ForbiddenSyntax):
- pass
-class ForbiddenDirective(ForbiddenSyntax):
- pass
-
-class CheetahVariable(object):
- def __init__(self, nameChunks, useNameMapper=True, cacheToken=None,
- rawSource=None):
- self.nameChunks = nameChunks
- self.useNameMapper = useNameMapper
- self.cacheToken = cacheToken
- self.rawSource = rawSource
-
-class Placeholder(CheetahVariable):
- pass
-
-class ArgList(object):
- """Used by _LowLevelParser.getArgList()"""
-
- def __init__(self):
- self.arguments = []
- self.defaults = []
- self.count = 0
-
- def add_argument(self, name):
- self.arguments.append(name)
- self.defaults.append(None)
-
- def next(self):
- self.count += 1
-
- def add_default(self, token):
- count = self.count
- if self.defaults[count] is None:
- self.defaults[count] = ''
- self.defaults[count] += token
-
- def merge(self):
- defaults = (isinstance(d, basestring) and d.strip() or None for d in self.defaults)
- return list(map(None, (a.strip() for a in self.arguments), defaults))
-
- def __str__(self):
- return str(self.merge())
-
-class _LowLevelParser(SourceReader):
- """This class implements the methods to match or extract ('get*') the basic
- elements of Cheetah's grammar. It does NOT handle any code generation or
- state management.
- """
-
- _settingsManager = None
-
- def setSettingsManager(self, settingsManager):
- self._settingsManager = settingsManager
-
- def setting(self, key, default=Unspecified):
- if default is Unspecified:
- return self._settingsManager.setting(key)
- else:
- return self._settingsManager.setting(key, default=default)
-
- def setSetting(self, key, val):
- self._settingsManager.setSetting(key, val)
-
- def settings(self):
- return self._settingsManager.settings()
-
- def updateSettings(self, settings):
- self._settingsManager.updateSettings(settings)
-
- def _initializeSettings(self):
- self._settingsManager._initializeSettings()
-
- def configureParser(self):
- """Is called by the Compiler instance after the parser has had a
- settingsManager assigned with self.setSettingsManager()
- """
- self._makeCheetahVarREs()
- self._makeCommentREs()
- self._makeDirectiveREs()
- self._makePspREs()
- self._possibleNonStrConstantChars = (
- self.setting('commentStartToken')[0] +
- self.setting('multiLineCommentStartToken')[0] +
- self.setting('cheetahVarStartToken')[0] +
- self.setting('directiveStartToken')[0] +
- self.setting('PSPStartToken')[0])
- self._nonStrConstMatchers = [
- self.matchCommentStartToken,
- self.matchMultiLineCommentStartToken,
- self.matchVariablePlaceholderStart,
- self.matchExpressionPlaceholderStart,
- self.matchDirective,
- self.matchPSPStartToken,
- self.matchEOLSlurpToken,
- ]
-
- ## regex setup ##
-
- def _makeCheetahVarREs(self):
-
- """Setup the regexs for Cheetah $var parsing."""
-
- num = r'[0-9\.]+'
- interval = (r'(?P<interval>' +
- num + r's|' +
- num + r'm|' +
- num + r'h|' +
- num + r'd|' +
- num + r'w|' +
- num + ')'
- )
-
- cacheToken = (r'(?:' +
- r'(?P<REFRESH_CACHE>\*' + interval + '\*)'+
- '|' +
- r'(?P<STATIC_CACHE>\*)' +
- '|' +
- r'(?P<NO_CACHE>)' +
- ')')
- self.cacheTokenRE = cachedRegex(cacheToken)
-
- silentPlaceholderToken = (r'(?:' +
- r'(?P<SILENT>' +escapeRegexChars('!')+')'+
- '|' +
- r'(?P<NOT_SILENT>)' +
- ')')
- self.silentPlaceholderTokenRE = cachedRegex(silentPlaceholderToken)
-
- self.cheetahVarStartRE = cachedRegex(
- escCharLookBehind +
- r'(?P<startToken>'+escapeRegexChars(self.setting('cheetahVarStartToken'))+')'+
- r'(?P<silenceToken>'+silentPlaceholderToken+')'+
- r'(?P<cacheToken>'+cacheToken+')'+
- r'(?P<enclosure>|(?:(?:\{|\(|\[)[ \t\f]*))' + # allow WS after enclosure
- r'(?=[A-Za-z_])')
- validCharsLookAhead = r'(?=[A-Za-z_\*!\{\(\[])'
- self.cheetahVarStartToken = self.setting('cheetahVarStartToken')
- self.cheetahVarStartTokenRE = cachedRegex(
- escCharLookBehind +
- escapeRegexChars(self.setting('cheetahVarStartToken'))
- +validCharsLookAhead
- )
-
- self.cheetahVarInExpressionStartTokenRE = cachedRegex(
- escapeRegexChars(self.setting('cheetahVarStartToken'))
- +r'(?=[A-Za-z_])'
- )
-
- self.expressionPlaceholderStartRE = cachedRegex(
- escCharLookBehind +
- r'(?P<startToken>' + escapeRegexChars(self.setting('cheetahVarStartToken')) + ')' +
- r'(?P<cacheToken>' + cacheToken + ')' +
- #r'\[[ \t\f]*'
- r'(?:\{|\(|\[)[ \t\f]*'
- + r'(?=[^\)\}\]])'
- )
-
- if self.setting('EOLSlurpToken'):
- self.EOLSlurpRE = cachedRegex(
- escapeRegexChars(self.setting('EOLSlurpToken'))
- + r'[ \t\f]*'
- + r'(?:'+EOL+')'
- )
- else:
- self.EOLSlurpRE = None
-
-
- def _makeCommentREs(self):
- """Construct the regex bits that are used in comment parsing."""
- startTokenEsc = escapeRegexChars(self.setting('commentStartToken'))
- self.commentStartTokenRE = cachedRegex(escCharLookBehind + startTokenEsc)
- del startTokenEsc
-
- startTokenEsc = escapeRegexChars(
- self.setting('multiLineCommentStartToken'))
- endTokenEsc = escapeRegexChars(
- self.setting('multiLineCommentEndToken'))
- self.multiLineCommentTokenStartRE = cachedRegex(escCharLookBehind +
- startTokenEsc)
- self.multiLineCommentEndTokenRE = cachedRegex(escCharLookBehind +
- endTokenEsc)
-
- def _makeDirectiveREs(self):
- """Construct the regexs that are used in directive parsing."""
- startToken = self.setting('directiveStartToken')
- endToken = self.setting('directiveEndToken')
- startTokenEsc = escapeRegexChars(startToken)
- endTokenEsc = escapeRegexChars(endToken)
- validSecondCharsLookAhead = r'(?=[A-Za-z_@])'
- reParts = [escCharLookBehind, startTokenEsc]
- if self.setting('allowWhitespaceAfterDirectiveStartToken'):
- reParts.append('[ \t]*')
- reParts.append(validSecondCharsLookAhead)
- self.directiveStartTokenRE = cachedRegex(''.join(reParts))
- self.directiveEndTokenRE = cachedRegex(escCharLookBehind + endTokenEsc)
-
- def _makePspREs(self):
- """Setup the regexs for PSP parsing."""
- startToken = self.setting('PSPStartToken')
- startTokenEsc = escapeRegexChars(startToken)
- self.PSPStartTokenRE = cachedRegex(escCharLookBehind + startTokenEsc)
- endToken = self.setting('PSPEndToken')
- endTokenEsc = escapeRegexChars(endToken)
- self.PSPEndTokenRE = cachedRegex(escCharLookBehind + endTokenEsc)
-
- def _unescapeCheetahVars(self, theString):
- """Unescape any escaped Cheetah \$vars in the string.
- """
-
- token = self.setting('cheetahVarStartToken')
- return theString.replace('\\' + token, token)
-
- def _unescapeDirectives(self, theString):
- """Unescape any escaped Cheetah directives in the string.
- """
-
- token = self.setting('directiveStartToken')
- return theString.replace('\\' + token, token)
-
- def isLineClearToStartToken(self, pos=None):
- return self.isLineClearToPos(pos)
-
- def matchTopLevelToken(self):
- """Returns the first match found from the following methods:
- self.matchCommentStartToken
- self.matchMultiLineCommentStartToken
- self.matchVariablePlaceholderStart
- self.matchExpressionPlaceholderStart
- self.matchDirective
- self.matchPSPStartToken
- self.matchEOLSlurpToken
-
- Returns None if no match.
- """
- match = None
- if self.peek() in self._possibleNonStrConstantChars:
- for matcher in self._nonStrConstMatchers:
- match = matcher()
- if match:
- break
- return match
-
- def matchPyToken(self):
- match = pseudoprog.match(self.src(), self.pos())
-
- if match and match.group() in tripleQuotedStringStarts:
- TQSmatch = tripleQuotedStringREs[match.group()].match(self.src(), self.pos())
- if TQSmatch:
- return TQSmatch
- return match
-
- def getPyToken(self):
- match = self.matchPyToken()
- if match is None:
- raise ParseError(self)
- elif match.group() in tripleQuotedStringStarts:
- raise ParseError(self, msg='Malformed triple-quoted string')
- return self.readTo(match.end())
-
- def matchEOLSlurpToken(self):
- if self.EOLSlurpRE:
- return self.EOLSlurpRE.match(self.src(), self.pos())
-
- def getEOLSlurpToken(self):
- match = self.matchEOLSlurpToken()
- if not match:
- raise ParseError(self, msg='Invalid EOL slurp token')
- return self.readTo(match.end())
-
- def matchCommentStartToken(self):
- return self.commentStartTokenRE.match(self.src(), self.pos())
-
- def getCommentStartToken(self):
- match = self.matchCommentStartToken()
- if not match:
- raise ParseError(self, msg='Invalid single-line comment start token')
- return self.readTo(match.end())
-
- def matchMultiLineCommentStartToken(self):
- return self.multiLineCommentTokenStartRE.match(self.src(), self.pos())
-
- def getMultiLineCommentStartToken(self):
- match = self.matchMultiLineCommentStartToken()
- if not match:
- raise ParseError(self, msg='Invalid multi-line comment start token')
- return self.readTo(match.end())
-
- def matchMultiLineCommentEndToken(self):
- return self.multiLineCommentEndTokenRE.match(self.src(), self.pos())
-
- def getMultiLineCommentEndToken(self):
- match = self.matchMultiLineCommentEndToken()
- if not match:
- raise ParseError(self, msg='Invalid multi-line comment end token')
- return self.readTo(match.end())
-
- def getCommaSeparatedSymbols(self):
- """
- Loosely based on getDottedName to pull out comma separated
- named chunks
- """
- srcLen = len(self)
- pieces = []
- nameChunks = []
-
- if not self.peek() in identchars:
- raise ParseError(self)
-
- while self.pos() < srcLen:
- c = self.peek()
- if c in namechars:
- nameChunk = self.getIdentifier()
- nameChunks.append(nameChunk)
- elif c == '.':
- if self.pos()+1 <srcLen and self.peek(1) in identchars:
- nameChunks.append(self.getc())
- else:
- break
- elif c == ',':
- self.getc()
- pieces.append(''.join(nameChunks))
- nameChunks = []
- elif c in (' ', '\t'):
- self.getc()
- else:
- break
-
- if nameChunks:
- pieces.append(''.join(nameChunks))
-
- return pieces
-
- def getDottedName(self):
- srcLen = len(self)
- nameChunks = []
-
- if not self.peek() in identchars:
- raise ParseError(self)
-
- while self.pos() < srcLen:
- c = self.peek()
- if c in namechars:
- nameChunk = self.getIdentifier()
- nameChunks.append(nameChunk)
- elif c == '.':
- if self.pos()+1 <srcLen and self.peek(1) in identchars:
- nameChunks.append(self.getc())
- else:
- break
- else:
- break
-
- return ''.join(nameChunks)
-
- def matchIdentifier(self):
- return identRE.match(self.src(), self.pos())
-
- def getIdentifier(self):
- match = self.matchIdentifier()
- if not match:
- raise ParseError(self, msg='Invalid identifier')
- return self.readTo(match.end())
-
- def matchOperator(self):
- match = self.matchPyToken()
- if match and match.group() not in operators:
- match = None
- return match
-
- def getOperator(self):
- match = self.matchOperator()
- if not match:
- raise ParseError(self, msg='Expected operator')
- return self.readTo( match.end() )
-
- def matchAssignmentOperator(self):
- match = self.matchPyToken()
- if match and match.group() not in assignmentOps:
- match = None
- return match
-
- def getAssignmentOperator(self):
- match = self.matchAssignmentOperator()
- if not match:
- raise ParseError(self, msg='Expected assignment operator')
- return self.readTo( match.end() )
-
- def matchDirective(self):
- """Returns False or the name of the directive matched.
- """
- startPos = self.pos()
- if not self.matchDirectiveStartToken():
- return False
- self.getDirectiveStartToken()
- directiveName = self.matchDirectiveName()
- self.setPos(startPos)
- return directiveName
-
- def matchDirectiveName(self, directiveNameChars=identchars+'0123456789-@'):
- startPos = self.pos()
- possibleMatches = self._directiveNamesAndParsers.keys()
- name = ''
- match = None
-
- while not self.atEnd():
- c = self.getc()
- if not c in directiveNameChars:
- break
- name += c
- if name == '@':
- if not self.atEnd() and self.peek() in identchars:
- match = '@'
- break
- possibleMatches = [dn for dn in possibleMatches if dn.startswith(name)]
- if not possibleMatches:
- break
- elif (name in possibleMatches and (self.atEnd() or self.peek() not in directiveNameChars)):
- match = name
- break
-
- self.setPos(startPos)
- return match
-
- def matchDirectiveStartToken(self):
- return self.directiveStartTokenRE.match(self.src(), self.pos())
-
- def getDirectiveStartToken(self):
- match = self.matchDirectiveStartToken()
- if not match:
- raise ParseError(self, msg='Invalid directive start token')
- return self.readTo(match.end())
-
- def matchDirectiveEndToken(self):
- return self.directiveEndTokenRE.match(self.src(), self.pos())
-
- def getDirectiveEndToken(self):
- match = self.matchDirectiveEndToken()
- if not match:
- raise ParseError(self, msg='Invalid directive end token')
- return self.readTo(match.end())
-
-
- def matchColonForSingleLineShortFormDirective(self):
- if not self.atEnd() and self.peek()==':':
- restOfLine = self[self.pos()+1:self.findEOL()]
- restOfLine = restOfLine.strip()
- if not restOfLine:
- return False
- elif self.commentStartTokenRE.match(restOfLine):
- return False
- else: # non-whitespace, non-commment chars found
- return True
- return False
-
- def matchPSPStartToken(self):
- return self.PSPStartTokenRE.match(self.src(), self.pos())
-
- def matchPSPEndToken(self):
- return self.PSPEndTokenRE.match(self.src(), self.pos())
-
- def getPSPStartToken(self):
- match = self.matchPSPStartToken()
- if not match:
- raise ParseError(self, msg='Invalid psp start token')
- return self.readTo(match.end())
-
- def getPSPEndToken(self):
- match = self.matchPSPEndToken()
- if not match:
- raise ParseError(self, msg='Invalid psp end token')
- return self.readTo(match.end())
-
- def matchCheetahVarStart(self):
- """includes the enclosure and cache token"""
- return self.cheetahVarStartRE.match(self.src(), self.pos())
-
- def matchCheetahVarStartToken(self):
- """includes the enclosure and cache token"""
- return self.cheetahVarStartTokenRE.match(self.src(), self.pos())
-
- def matchCheetahVarInExpressionStartToken(self):
- """no enclosures or cache tokens allowed"""
- return self.cheetahVarInExpressionStartTokenRE.match(self.src(), self.pos())
-
- def matchVariablePlaceholderStart(self):
- """includes the enclosure and cache token"""
- return self.cheetahVarStartRE.match(self.src(), self.pos())
-
- def matchExpressionPlaceholderStart(self):
- """includes the enclosure and cache token"""
- return self.expressionPlaceholderStartRE.match(self.src(), self.pos())
-
- def getCheetahVarStartToken(self):
- """just the start token, not the enclosure or cache token"""
- match = self.matchCheetahVarStartToken()
- if not match:
- raise ParseError(self, msg='Expected Cheetah $var start token')
- return self.readTo( match.end() )
-
-
- def getCacheToken(self):
- try:
- token = self.cacheTokenRE.match(self.src(), self.pos())
- self.setPos( token.end() )
- return token.group()
- except:
- raise ParseError(self, msg='Expected cache token')
-
- def getSilentPlaceholderToken(self):
- try:
- token = self.silentPlaceholderTokenRE.match(self.src(), self.pos())
- self.setPos( token.end() )
- return token.group()
- except:
- raise ParseError(self, msg='Expected silent placeholder token')
-
-
-
- def getTargetVarsList(self):
- varnames = []
- while not self.atEnd():
- if self.peek() in ' \t\f':
- self.getWhiteSpace()
- elif self.peek() in '\r\n':
- break
- elif self.startswith(','):
- self.advance()
- elif self.startswith('in ') or self.startswith('in\t'):
- break
- #elif self.matchCheetahVarStart():
- elif self.matchCheetahVarInExpressionStartToken():
- self.getCheetahVarStartToken()
- self.getSilentPlaceholderToken()
- self.getCacheToken()
- varnames.append( self.getDottedName() )
- elif self.matchIdentifier():
- varnames.append( self.getDottedName() )
- else:
- break
- return varnames
-
- def getCheetahVar(self, plain=False, skipStartToken=False):
- """This is called when parsing inside expressions. Cache tokens are only
- valid in placeholders so this method discards any cache tokens found.
- """
- if not skipStartToken:
- self.getCheetahVarStartToken()
- self.getSilentPlaceholderToken()
- self.getCacheToken()
- return self.getCheetahVarBody(plain=plain)
-
- def getCheetahVarBody(self, plain=False):
- # @@TR: this should be in the compiler
- return self._compiler.genCheetahVar(self.getCheetahVarNameChunks(), plain=plain)
-
- def getCheetahVarNameChunks(self):
-
- """
- nameChunks = list of Cheetah $var subcomponents represented as tuples
- [ (namemapperPart,autoCall,restOfName),
- ]
- where:
- namemapperPart = the dottedName base
- autocall = where NameMapper should use autocalling on namemapperPart
- restOfName = any arglist, index, or slice
-
- If restOfName contains a call arglist (e.g. '(1234)') then autocall is
- False, otherwise it defaults to True.
-
- EXAMPLE
- ------------------------------------------------------------------------
-
- if the raw CheetahVar is
- $a.b.c[1].d().x.y.z
-
- nameChunks is the list
- [ ('a.b.c',True,'[1]'),
- ('d',False,'()'),
- ('x.y.z',True,''),
- ]
-
- """
-
- chunks = []
- while self.pos() < len(self):
- rest = ''
- autoCall = True
- if not self.peek() in identchars + '.':
- break
- elif self.peek() == '.':
-
- if self.pos()+1 < len(self) and self.peek(1) in identchars:
- self.advance() # discard the period as it isn't needed with NameMapper
- else:
- break
-
- dottedName = self.getDottedName()
- if not self.atEnd() and self.peek() in '([':
- if self.peek() == '(':
- rest = self.getCallArgString()
- else:
- rest = self.getExpression(enclosed=True)
-
- period = max(dottedName.rfind('.'), 0)
- if period:
- chunks.append( (dottedName[:period], autoCall, '') )
- dottedName = dottedName[period+1:]
- if rest and rest[0]=='(':
- autoCall = False
- chunks.append( (dottedName, autoCall, rest) )
-
- return chunks
-
-
- def getCallArgString(self,
- enclosures=[], # list of tuples (char, pos), where char is ({ or [
- useNameMapper=Unspecified):
-
- """ Get a method/function call argument string.
-
- This method understands *arg, and **kw
- """
-
- # @@TR: this settings mangling should be removed
- if useNameMapper is not Unspecified:
- useNameMapper_orig = self.setting('useNameMapper')
- self.setSetting('useNameMapper', useNameMapper)
-
- if enclosures:
- pass
- else:
- if not self.peek() == '(':
- raise ParseError(self, msg="Expected '('")
- startPos = self.pos()
- self.getc()
- enclosures = [('(', startPos),
- ]
-
- argStringBits = ['(']
- addBit = argStringBits.append
-
- while True:
- if self.atEnd():
- open = enclosures[-1][0]
- close = closurePairsRev[open]
- self.setPos(enclosures[-1][1])
- raise ParseError(
- self, msg="EOF was reached before a matching '" + close +
- "' was found for the '" + open + "'")
-
- c = self.peek()
- if c in ")}]": # get the ending enclosure and break
- if not enclosures:
- raise ParseError(self)
- c = self.getc()
- open = closurePairs[c]
- if enclosures[-1][0] == open:
- enclosures.pop()
- addBit(')')
- break
- else:
- raise ParseError(self)
- elif c in " \t\f\r\n":
- addBit(self.getc())
- elif self.matchCheetahVarInExpressionStartToken():
- startPos = self.pos()
- codeFor1stToken = self.getCheetahVar()
- WS = self.getWhiteSpace()
- if not self.atEnd() and self.peek() == '=':
- nextToken = self.getPyToken()
- if nextToken == '=':
- endPos = self.pos()
- self.setPos(startPos)
- codeFor1stToken = self.getCheetahVar(plain=True)
- self.setPos(endPos)
-
- ## finally
- addBit( codeFor1stToken + WS + nextToken )
- else:
- addBit( codeFor1stToken + WS)
- elif self.matchCheetahVarStart():
- # it has syntax that is only valid at the top level
- self._raiseErrorAboutInvalidCheetahVarSyntaxInExpr()
- else:
- beforeTokenPos = self.pos()
- token = self.getPyToken()
- if token in ('{', '(', '['):
- self.rev()
- token = self.getExpression(enclosed=True)
- token = self.transformToken(token, beforeTokenPos)
- addBit(token)
-
- if useNameMapper is not Unspecified:
- self.setSetting('useNameMapper', useNameMapper_orig) # @@TR: see comment above
-
- return ''.join(argStringBits)
-
- def getDefArgList(self, exitPos=None, useNameMapper=False):
-
- """ Get an argument list. Can be used for method/function definition
- argument lists or for #directive argument lists. Returns a list of
- tuples in the form (argName, defVal=None) with one tuple for each arg
- name.
-
- These defVals are always strings, so (argName, defVal=None) is safe even
- with a case like (arg1, arg2=None, arg3=1234*2), which would be returned as
- [('arg1', None),
- ('arg2', 'None'),
- ('arg3', '1234*2'),
- ]
-
- This method understands *arg, and **kw
-
- """
-
- if self.peek() == '(':
- self.advance()
- else:
- exitPos = self.findEOL() # it's a directive so break at the EOL
- argList = ArgList()
- onDefVal = False
-
- # @@TR: this settings mangling should be removed
- useNameMapper_orig = self.setting('useNameMapper')
- self.setSetting('useNameMapper', useNameMapper)
-
- while True:
- if self.atEnd():
- raise ParseError(
- self, msg="EOF was reached before a matching ')'"+
- " was found for the '('")
-
- if self.pos() == exitPos:
- break
-
- c = self.peek()
- if c == ")" or self.matchDirectiveEndToken():
- break
- elif c == ":":
- break
- elif c in " \t\f\r\n":
- if onDefVal:
- argList.add_default(c)
- self.advance()
- elif c == '=':
- onDefVal = True
- self.advance()
- elif c == ",":
- argList.next()
- onDefVal = False
- self.advance()
- elif self.startswith(self.cheetahVarStartToken) and not onDefVal:
- self.advance(len(self.cheetahVarStartToken))
- elif self.matchIdentifier() and not onDefVal:
- argList.add_argument( self.getIdentifier() )
- elif onDefVal:
- if self.matchCheetahVarInExpressionStartToken():
- token = self.getCheetahVar()
- elif self.matchCheetahVarStart():
- # it has syntax that is only valid at the top level
- self._raiseErrorAboutInvalidCheetahVarSyntaxInExpr()
- else:
- beforeTokenPos = self.pos()
- token = self.getPyToken()
- if token in ('{', '(', '['):
- self.rev()
- token = self.getExpression(enclosed=True)
- token = self.transformToken(token, beforeTokenPos)
- argList.add_default(token)
- elif c == '*' and not onDefVal:
- varName = self.getc()
- if self.peek() == '*':
- varName += self.getc()
- if not self.matchIdentifier():
- raise ParseError(self)
- varName += self.getIdentifier()
- argList.add_argument(varName)
- else:
- raise ParseError(self)
-
-
- self.setSetting('useNameMapper', useNameMapper_orig) # @@TR: see comment above
- return argList.merge()
-
- def getExpressionParts(self,
- enclosed=False,
- enclosures=None, # list of tuples (char, pos), where char is ({ or [
- pyTokensToBreakAt=None, # only works if not enclosed
- useNameMapper=Unspecified,
- ):
-
- """ Get a Cheetah expression that includes $CheetahVars and break at
- directive end tokens, the end of an enclosure, or at a specified
- pyToken.
- """
-
- if useNameMapper is not Unspecified:
- useNameMapper_orig = self.setting('useNameMapper')
- self.setSetting('useNameMapper', useNameMapper)
-
- if enclosures is None:
- enclosures = []
-
- srcLen = len(self)
- exprBits = []
- while True:
- if self.atEnd():
- if enclosures:
- open = enclosures[-1][0]
- close = closurePairsRev[open]
- self.setPos(enclosures[-1][1])
- raise ParseError(
- self, msg="EOF was reached before a matching '" + close +
- "' was found for the '" + open + "'")
- else:
- break
-
- c = self.peek()
- if c in "{([":
- exprBits.append(c)
- enclosures.append( (c, self.pos()) )
- self.advance()
- elif enclosed and not enclosures:
- break
- elif c in "])}":
- if not enclosures:
- raise ParseError(self)
- open = closurePairs[c]
- if enclosures[-1][0] == open:
- enclosures.pop()
- exprBits.append(c)
- else:
- open = enclosures[-1][0]
- close = closurePairsRev[open]
- row, col = self.getRowCol()
- self.setPos(enclosures[-1][1])
- raise ParseError(
- self, msg= "A '" + c + "' was found at line " + str(row) +
- ", col " + str(col) +
- " before a matching '" + close +
- "' was found\nfor the '" + open + "'")
- self.advance()
-
- elif c in " \f\t":
- exprBits.append(self.getWhiteSpace())
- elif self.matchDirectiveEndToken() and not enclosures:
- break
- elif c == "\\" and self.pos()+1 < srcLen:
- eolMatch = EOLre.match(self.src(), self.pos()+1)
- if not eolMatch:
- self.advance()
- raise ParseError(self, msg='Line ending expected')
- self.setPos( eolMatch.end() )
- elif c in '\r\n':
- if enclosures:
- self.advance()
- else:
- break
- elif self.matchCheetahVarInExpressionStartToken():
- expr = self.getCheetahVar()
- exprBits.append(expr)
- elif self.matchCheetahVarStart():
- # it has syntax that is only valid at the top level
- self._raiseErrorAboutInvalidCheetahVarSyntaxInExpr()
- else:
- beforeTokenPos = self.pos()
- token = self.getPyToken()
- if (not enclosures
- and pyTokensToBreakAt
- and token in pyTokensToBreakAt):
-
- self.setPos(beforeTokenPos)
- break
-
- token = self.transformToken(token, beforeTokenPos)
-
- exprBits.append(token)
- if identRE.match(token):
- if token == 'for':
- expr = self.getExpression(useNameMapper=False, pyTokensToBreakAt=['in'])
- exprBits.append(expr)
- else:
- exprBits.append(self.getWhiteSpace())
- if not self.atEnd() and self.peek() == '(':
- exprBits.append(self.getCallArgString())
- ##
- if useNameMapper is not Unspecified:
- self.setSetting('useNameMapper', useNameMapper_orig) # @@TR: see comment above
- return exprBits
-
- def getExpression(self,
- enclosed=False,
- enclosures=None, # list of tuples (char, pos), where # char is ({ or [
- pyTokensToBreakAt=None,
- useNameMapper=Unspecified,
- ):
- """Returns the output of self.getExpressionParts() as a concatenated
- string rather than as a list.
- """
- return ''.join(self.getExpressionParts(
- enclosed=enclosed, enclosures=enclosures,
- pyTokensToBreakAt=pyTokensToBreakAt,
- useNameMapper=useNameMapper))
-
-
- def transformToken(self, token, beforeTokenPos):
- """Takes a token from the expression being parsed and performs and
- special transformations required by Cheetah.
-
- At the moment only Cheetah's c'$placeholder strings' are transformed.
- """
- if token=='c' and not self.atEnd() and self.peek() in '\'"':
- nextToken = self.getPyToken()
- token = nextToken.upper()
- theStr = eval(token)
- endPos = self.pos()
- if not theStr:
- return
-
- if token.startswith(single3) or token.startswith(double3):
- startPosIdx = 3
- else:
- startPosIdx = 1
- self.setPos(beforeTokenPos+startPosIdx+1)
- outputExprs = []
- strConst = ''
- while self.pos() < (endPos-startPosIdx):
- if self.matchCheetahVarStart() or self.matchExpressionPlaceholderStart():
- if strConst:
- outputExprs.append(repr(strConst))
- strConst = ''
- placeholderExpr = self.getPlaceholder()
- outputExprs.append('str('+placeholderExpr+')')
- else:
- strConst += self.getc()
- self.setPos(endPos)
- if strConst:
- outputExprs.append(repr(strConst))
- token = "''.join(["+','.join(outputExprs)+"])"
- return token
-
- def _raiseErrorAboutInvalidCheetahVarSyntaxInExpr(self):
- match = self.matchCheetahVarStart()
- groupdict = match.groupdict()
- if groupdict.get('cacheToken'):
- raise ParseError(
- self,
- msg='Cache tokens are not valid inside expressions. '
- 'Use them in top-level $placeholders only.')
- elif groupdict.get('enclosure'):
- raise ParseError(
- self,
- msg='Long-form placeholders - ${}, $(), $[], etc. are not valid inside expressions. '
- 'Use them in top-level $placeholders only.')
- else:
- raise ParseError(
- self,
- msg='This form of $placeholder syntax is not valid here.')
-
-
- def getPlaceholder(self, allowCacheTokens=False, plain=False, returnEverything=False):
- # filtered
- for callback in self.setting('preparsePlaceholderHooks'):
- callback(parser=self)
-
- startPos = self.pos()
- lineCol = self.getRowCol(startPos)
- startToken = self.getCheetahVarStartToken()
- silentPlaceholderToken = self.getSilentPlaceholderToken()
- if silentPlaceholderToken:
- isSilentPlaceholder = True
- else:
- isSilentPlaceholder = False
-
-
- if allowCacheTokens:
- cacheToken = self.getCacheToken()
- cacheTokenParts = self.cacheTokenRE.match(cacheToken).groupdict()
- else:
- cacheTokenParts = {}
-
- if self.peek() in '({[':
- pos = self.pos()
- enclosureOpenChar = self.getc()
- enclosures = [ (enclosureOpenChar, pos) ]
- self.getWhiteSpace()
- else:
- enclosures = []
-
- filterArgs = None
- if self.matchIdentifier():
- nameChunks = self.getCheetahVarNameChunks()
- expr = self._compiler.genCheetahVar(nameChunks[:], plain=plain)
- restOfExpr = None
- if enclosures:
- WS = self.getWhiteSpace()
- expr += WS
- if self.setting('allowPlaceholderFilterArgs') and self.peek()==',':
- filterArgs = self.getCallArgString(enclosures=enclosures)[1:-1]
- else:
- if self.peek()==closurePairsRev[enclosureOpenChar]:
- self.getc()
- else:
- restOfExpr = self.getExpression(enclosed=True, enclosures=enclosures)
- if restOfExpr[-1] == closurePairsRev[enclosureOpenChar]:
- restOfExpr = restOfExpr[:-1]
- expr += restOfExpr
- rawPlaceholder = self[startPos: self.pos()]
- else:
- expr = self.getExpression(enclosed=True, enclosures=enclosures)
- if expr[-1] == closurePairsRev[enclosureOpenChar]:
- expr = expr[:-1]
- rawPlaceholder=self[startPos: self.pos()]
-
- expr = self._applyExpressionFilters(expr, 'placeholder',
- rawExpr=rawPlaceholder, startPos=startPos)
- for callback in self.setting('postparsePlaceholderHooks'):
- callback(parser=self)
-
- if returnEverything:
- return (expr, rawPlaceholder, lineCol, cacheTokenParts,
- filterArgs, isSilentPlaceholder)
- else:
- return expr
-
-
-class _HighLevelParser(_LowLevelParser):
- """This class is a StateMachine for parsing Cheetah source and
- sending state dependent code generation commands to
- Cheetah.Compiler.Compiler.
- """
- def __init__(self, src, filename=None, breakPoint=None, compiler=None):
- super(_HighLevelParser, self).__init__(src, filename=filename, breakPoint=breakPoint)
- self.setSettingsManager(compiler)
- self._compiler = compiler
- self.setupState()
- self.configureParser()
-
- def setupState(self):
- self._macros = {}
- self._macroDetails = {}
- self._openDirectivesStack = []
-
- def cleanup(self):
- """Cleanup to remove any possible reference cycles
- """
- self._macros.clear()
- for macroname, macroDetails in self._macroDetails.items():
- macroDetails.template.shutdown()
- del macroDetails.template
- self._macroDetails.clear()
-
- def configureParser(self):
- super(_HighLevelParser, self).configureParser()
- self._initDirectives()
-
- def _initDirectives(self):
- def normalizeParserVal(val):
- if isinstance(val, (str, unicode)):
- handler = getattr(self, val)
- elif isinstance(val, type):
- handler = val(self)
- elif hasattr(val, '__call__'):
- handler = val
- elif val is None:
- handler = val
- else:
- raise Exception('Invalid parser/handler value %r for %s'%(val, name))
- return handler
-
- normalizeHandlerVal = normalizeParserVal
-
- _directiveNamesAndParsers = directiveNamesAndParsers.copy()
- customNamesAndParsers = self.setting('directiveNamesAndParsers', {})
- _directiveNamesAndParsers.update(customNamesAndParsers)
-
- _endDirectiveNamesAndHandlers = endDirectiveNamesAndHandlers.copy()
- customNamesAndHandlers = self.setting('endDirectiveNamesAndHandlers', {})
- _endDirectiveNamesAndHandlers.update(customNamesAndHandlers)
-
- self._directiveNamesAndParsers = {}
- for name, val in _directiveNamesAndParsers.items():
- if val in (False, 0):
- continue
- self._directiveNamesAndParsers[name] = normalizeParserVal(val)
-
- self._endDirectiveNamesAndHandlers = {}
- for name, val in _endDirectiveNamesAndHandlers.items():
- if val in (False, 0):
- continue
- self._endDirectiveNamesAndHandlers[name] = normalizeHandlerVal(val)
-
- self._closeableDirectives = ['def', 'block', 'closure', 'defmacro',
- 'call',
- 'capture',
- 'cache',
- 'filter',
- 'if', 'unless',
- 'for', 'while', 'repeat',
- 'try',
- ]
- for directiveName in self.setting('closeableDirectives', []):
- self._closeableDirectives.append(directiveName)
-
-
-
- macroDirectives = self.setting('macroDirectives', {})
- macroDirectives['i18n'] = I18n
-
-
- for macroName, callback in macroDirectives.items():
- if isinstance(callback, type):
- callback = callback(parser=self)
- assert callback
- self._macros[macroName] = callback
- self._directiveNamesAndParsers[macroName] = self.eatMacroCall
-
- def _applyExpressionFilters(self, expr, exprType, rawExpr=None, startPos=None):
- """Pipes cheetah expressions through a set of optional filter hooks.
-
- The filters are functions which may modify the expressions or raise
- a ForbiddenExpression exception if the expression is not allowed. They
- are defined in the compiler setting 'expressionFilterHooks'.
-
- Some intended use cases:
-
- - to implement 'restricted execution' safeguards in cases where you
- can't trust the author of the template.
-
- - to enforce style guidelines
-
- filter call signature: (parser, expr, exprType, rawExpr=None, startPos=None)
- - parser is the Cheetah parser
- - expr is the expression to filter. In some cases the parser will have
- already modified it from the original source code form. For example,
- placeholders will have been translated into namemapper calls. If you
- need to work with the original source, see rawExpr.
- - exprType is the name of the directive, 'psp', or 'placeholder'. All
- lowercase. @@TR: These will eventually be replaced with a set of
- constants.
- - rawExpr is the original source string that Cheetah parsed. This
- might be None in some cases.
- - startPos is the character position in the source string/file
- where the parser started parsing the current expression.
-
- @@TR: I realize this use of the term 'expression' is a bit wonky as many
- of the 'expressions' are actually statements, but I haven't thought of
- a better name yet. Suggestions?
- """
- for callback in self.setting('expressionFilterHooks'):
- expr = callback(parser=self, expr=expr, exprType=exprType,
- rawExpr=rawExpr, startPos=startPos)
- return expr
-
- def _filterDisabledDirectives(self, directiveName):
- directiveName = directiveName.lower()
- if (directiveName in self.setting('disabledDirectives')
- or (self.setting('enabledDirectives')
- and directiveName not in self.setting('enabledDirectives'))):
- for callback in self.setting('disabledDirectiveHooks'):
- callback(parser=self, directiveName=directiveName)
- raise ForbiddenDirective(self, msg='This %r directive is disabled'%directiveName)
-
- ## main parse loop
-
- def parse(self, breakPoint=None, assertEmptyStack=True):
- if breakPoint:
- origBP = self.breakPoint()
- self.setBreakPoint(breakPoint)
- assertEmptyStack = False
-
- while not self.atEnd():
- if self.matchCommentStartToken():
- self.eatComment()
- elif self.matchMultiLineCommentStartToken():
- self.eatMultiLineComment()
- elif self.matchVariablePlaceholderStart():
- self.eatPlaceholder()
- elif self.matchExpressionPlaceholderStart():
- self.eatPlaceholder()
- elif self.matchDirective():
- self.eatDirective()
- elif self.matchPSPStartToken():
- self.eatPSP()
- elif self.matchEOLSlurpToken():
- self.eatEOLSlurpToken()
- else:
- self.eatPlainText()
- if assertEmptyStack:
- self.assertEmptyOpenDirectivesStack()
- if breakPoint:
- self.setBreakPoint(origBP)
-
- ## non-directive eat methods
-
- def eatPlainText(self):
- startPos = self.pos()
- match = None
- while not self.atEnd():
- match = self.matchTopLevelToken()
- if match:
- break
- else:
- self.advance()
- strConst = self.readTo(self.pos(), start=startPos)
- strConst = self._unescapeCheetahVars(strConst)
- strConst = self._unescapeDirectives(strConst)
- self._compiler.addStrConst(strConst)
- return match
-
- def eatComment(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- if isLineClearToStartToken:
- self._compiler.handleWSBeforeDirective()
- self.getCommentStartToken()
- comm = self.readToEOL(gobble=isLineClearToStartToken)
- self._compiler.addComment(comm)
-
- def eatMultiLineComment(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
-
- self.getMultiLineCommentStartToken()
- endPos = startPos = self.pos()
- level = 1
- while True:
- endPos = self.pos()
- if self.atEnd():
- break
- if self.matchMultiLineCommentStartToken():
- self.getMultiLineCommentStartToken()
- level += 1
- elif self.matchMultiLineCommentEndToken():
- self.getMultiLineCommentEndToken()
- level -= 1
- if not level:
- break
- self.advance()
- comm = self.readTo(endPos, start=startPos)
-
- if not self.atEnd():
- self.getMultiLineCommentEndToken()
-
- if (not self.atEnd()) and self.setting('gobbleWhitespaceAroundMultiLineComments'):
- restOfLine = self[self.pos():self.findEOL()]
- if not restOfLine.strip(): # WS only to EOL
- self.readToEOL(gobble=isLineClearToStartToken)
-
- if isLineClearToStartToken and (self.atEnd() or self.pos() > endOfFirstLine):
- self._compiler.handleWSBeforeDirective()
-
- self._compiler.addComment(comm)
-
- def eatPlaceholder(self):
- (expr, rawPlaceholder,
- lineCol, cacheTokenParts,
- filterArgs, isSilentPlaceholder) = self.getPlaceholder(
- allowCacheTokens=True, returnEverything=True)
-
- self._compiler.addPlaceholder(
- expr,
- filterArgs=filterArgs,
- rawPlaceholder=rawPlaceholder,
- cacheTokenParts=cacheTokenParts,
- lineCol=lineCol,
- silentMode=isSilentPlaceholder)
- return
-
- def eatPSP(self):
- # filtered
- self._filterDisabledDirectives(directiveName='psp')
- self.getPSPStartToken()
- endToken = self.setting('PSPEndToken')
- startPos = self.pos()
- while not self.atEnd():
- if self.peek() == endToken[0]:
- if self.matchPSPEndToken():
- break
- self.advance()
- pspString = self.readTo(self.pos(), start=startPos).strip()
- pspString = self._applyExpressionFilters(pspString, 'psp', startPos=startPos)
- self._compiler.addPSP(pspString)
- self.getPSPEndToken()
-
- ## generic directive eat methods
- _simpleIndentingDirectives = '''
- else elif for while repeat unless try except finally'''.split()
- _simpleExprDirectives = '''
- pass continue stop return yield break
- del assert raise
- silent echo
- import from'''.split()
- _directiveHandlerNames = {'import': 'addImportStatement',
- 'from': 'addImportStatement', }
- def eatDirective(self):
- directiveName = self.matchDirective()
- self._filterDisabledDirectives(directiveName)
-
- for callback in self.setting('preparseDirectiveHooks'):
- callback(parser=self, directiveName=directiveName)
-
- # subclasses can override the default behaviours here by providing an
- # eater method in self._directiveNamesAndParsers[directiveName]
- directiveParser = self._directiveNamesAndParsers.get(directiveName)
- if directiveParser:
- directiveParser()
- elif directiveName in self._simpleIndentingDirectives:
- handlerName = self._directiveHandlerNames.get(directiveName)
- if not handlerName:
- handlerName = 'add'+directiveName.capitalize()
- handler = getattr(self._compiler, handlerName)
- self.eatSimpleIndentingDirective(directiveName, callback=handler)
- elif directiveName in self._simpleExprDirectives:
- handlerName = self._directiveHandlerNames.get(directiveName)
- if not handlerName:
- handlerName = 'add'+directiveName.capitalize()
- handler = getattr(self._compiler, handlerName)
- if directiveName in ('silent', 'echo'):
- includeDirectiveNameInExpr = False
- else:
- includeDirectiveNameInExpr = True
- expr = self.eatSimpleExprDirective(
- directiveName,
- includeDirectiveNameInExpr=includeDirectiveNameInExpr)
- handler(expr)
- ##
- for callback in self.setting('postparseDirectiveHooks'):
- callback(parser=self, directiveName=directiveName)
-
- def _eatRestOfDirectiveTag(self, isLineClearToStartToken, endOfFirstLinePos):
- foundComment = False
- if self.matchCommentStartToken():
- pos = self.pos()
- self.advance()
- if not self.matchDirective():
- self.setPos(pos)
- foundComment = True
- self.eatComment() # this won't gobble the EOL
- else:
- self.setPos(pos)
-
- if not foundComment and self.matchDirectiveEndToken():
- self.getDirectiveEndToken()
- elif isLineClearToStartToken and (not self.atEnd()) and self.peek() in '\r\n':
- # still gobble the EOL if a comment was found.
- self.readToEOL(gobble=True)
-
- if isLineClearToStartToken and (self.atEnd() or self.pos() > endOfFirstLinePos):
- self._compiler.handleWSBeforeDirective()
-
- def _eatToThisEndDirective(self, directiveName):
- finalPos = endRawPos = startPos = self.pos()
- directiveChar = self.setting('directiveStartToken')[0]
- isLineClearToStartToken = False
- while not self.atEnd():
- if self.peek() == directiveChar:
- if self.matchDirective() == 'end':
- endRawPos = self.pos()
- self.getDirectiveStartToken()
- self.advance(len('end'))
- self.getWhiteSpace()
- if self.startswith(directiveName):
- if self.isLineClearToStartToken(endRawPos):
- isLineClearToStartToken = True
- endRawPos = self.findBOL(endRawPos)
- self.advance(len(directiveName)) # to end of directiveName
- self.getWhiteSpace()
- finalPos = self.pos()
- break
- self.advance()
- finalPos = endRawPos = self.pos()
-
- textEaten = self.readTo(endRawPos, start=startPos)
- self.setPos(finalPos)
-
- endOfFirstLinePos = self.findEOL()
-
- if self.matchDirectiveEndToken():
- self.getDirectiveEndToken()
- elif isLineClearToStartToken and (not self.atEnd()) and self.peek() in '\r\n':
- self.readToEOL(gobble=True)
-
- if isLineClearToStartToken and self.pos() > endOfFirstLinePos:
- self._compiler.handleWSBeforeDirective()
- return textEaten
-
-
- def eatSimpleExprDirective(self, directiveName, includeDirectiveNameInExpr=True):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
- self.getDirectiveStartToken()
- if not includeDirectiveNameInExpr:
- self.advance(len(directiveName))
- startPos = self.pos()
- expr = self.getExpression().strip()
- directiveName = expr.split()[0]
- expr = self._applyExpressionFilters(expr, directiveName, startPos=startPos)
- if directiveName in self._closeableDirectives:
- self.pushToOpenDirectivesStack(directiveName)
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
- return expr
-
- def eatSimpleIndentingDirective(self, directiveName, callback,
- includeDirectiveNameInExpr=False):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- lineCol = self.getRowCol()
- self.getDirectiveStartToken()
- if directiveName not in 'else elif for while try except finally'.split():
- self.advance(len(directiveName))
- startPos = self.pos()
-
- self.getWhiteSpace()
-
- expr = self.getExpression(pyTokensToBreakAt=[':'])
- expr = self._applyExpressionFilters(expr, directiveName, startPos=startPos)
- if self.matchColonForSingleLineShortFormDirective():
- self.advance() # skip over :
- if directiveName in 'else elif except finally'.split():
- callback(expr, dedent=False, lineCol=lineCol)
- else:
- callback(expr, lineCol=lineCol)
-
- self.getWhiteSpace(max=1)
- self.parse(breakPoint=self.findEOL(gobble=True))
- self._compiler.commitStrConst()
- self._compiler.dedent()
- else:
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- if directiveName in self._closeableDirectives:
- self.pushToOpenDirectivesStack(directiveName)
- callback(expr, lineCol=lineCol)
-
- def eatEndDirective(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- self.getDirectiveStartToken()
- self.advance(3) # to end of 'end'
- self.getWhiteSpace()
- pos = self.pos()
- directiveName = False
- for key in self._endDirectiveNamesAndHandlers.keys():
- if self.find(key, pos) == pos:
- directiveName = key
- break
- if not directiveName:
- raise ParseError(self, msg='Invalid end directive')
-
- endOfFirstLinePos = self.findEOL()
- self.getExpression() # eat in any extra comment-like crap
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- if directiveName in self._closeableDirectives:
- self.popFromOpenDirectivesStack(directiveName)
-
- # subclasses can override the default behaviours here by providing an
- # end-directive handler in self._endDirectiveNamesAndHandlers[directiveName]
- if self._endDirectiveNamesAndHandlers.get(directiveName):
- handler = self._endDirectiveNamesAndHandlers[directiveName]
- handler()
- elif directiveName in 'block capture cache call filter errorCatcher'.split():
- if key == 'block':
- self._compiler.closeBlock()
- elif key == 'capture':
- self._compiler.endCaptureRegion()
- elif key == 'cache':
- self._compiler.endCacheRegion()
- elif key == 'call':
- self._compiler.endCallRegion()
- elif key == 'filter':
- self._compiler.closeFilterBlock()
- elif key == 'errorCatcher':
- self._compiler.turnErrorCatcherOff()
- elif directiveName in 'while for if try repeat unless'.split():
- self._compiler.commitStrConst()
- self._compiler.dedent()
- elif directiveName=='closure':
- self._compiler.commitStrConst()
- self._compiler.dedent()
- # @@TR: temporary hack of useSearchList
- self.setSetting('useSearchList', self._useSearchList_orig)
-
- ## specific directive eat methods
-
- def eatBreakPoint(self):
- """Tells the parser to stop parsing at this point and completely ignore
- everything else.
-
- This is a debugging tool.
- """
- self.setBreakPoint(self.pos())
-
- def eatShbang(self):
- # filtered
- self.getDirectiveStartToken()
- self.advance(len('shBang'))
- self.getWhiteSpace()
- startPos = self.pos()
- shBang = self.readToEOL()
- shBang = self._applyExpressionFilters(shBang, 'shbang', startPos=startPos)
- self._compiler.setShBang(shBang.strip())
-
- def eatEncoding(self):
- # filtered
- self.getDirectiveStartToken()
- self.advance(len('encoding'))
- self.getWhiteSpace()
- startPos = self.pos()
- encoding = self.readToEOL()
- encoding = self._applyExpressionFilters(encoding, 'encoding', startPos=startPos)
- self._compiler.setModuleEncoding(encoding.strip())
-
- def eatCompiler(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
- startPos = self.pos()
- self.getDirectiveStartToken()
- self.advance(len('compiler')) # to end of 'compiler'
- self.getWhiteSpace()
-
- startPos = self.pos()
- settingName = self.getIdentifier()
-
- if settingName.lower() == 'reset':
- self.getExpression() # gobble whitespace & junk
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
- self._initializeSettings()
- self.configureParser()
- return
-
- self.getWhiteSpace()
- if self.peek() == '=':
- self.advance()
- else:
- raise ParseError(self)
- valueExpr = self.getExpression()
- endPos = self.pos()
-
- # @@TR: it's unlikely that anyone apply filters would have left this
- # directive enabled:
- # @@TR: fix up filtering, regardless
- self._applyExpressionFilters('%s=%r'%(settingName, valueExpr),
- 'compiler', startPos=startPos)
-
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
- try:
- self._compiler.setCompilerSetting(settingName, valueExpr)
- except:
- sys.stderr.write('An error occurred while processing the following #compiler directive.\n')
- sys.stderr.write('----------------------------------------------------------------------\n')
- sys.stderr.write('%s\n' % self[startPos:endPos])
- sys.stderr.write('----------------------------------------------------------------------\n')
- sys.stderr.write('Please check the syntax of these settings.\n\n')
- raise
-
-
- def eatCompilerSettings(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(len('compiler-settings')) # to end of 'settings'
-
- keywords = self.getTargetVarsList()
- self.getExpression() # gobble any garbage
-
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
-
- if 'reset' in keywords:
- self._compiler._initializeSettings()
- self.configureParser()
- # @@TR: this implies a single-line #compiler-settings directive, and
- # thus we should parse forward for an end directive.
- # Subject to change in the future
- return
- startPos = self.pos()
- settingsStr = self._eatToThisEndDirective('compiler-settings')
- settingsStr = self._applyExpressionFilters(settingsStr, 'compilerSettings',
- startPos=startPos)
- try:
- self._compiler.setCompilerSettings(keywords=keywords, settingsStr=settingsStr)
- except:
- sys.stderr.write('An error occurred while processing the following compiler settings.\n')
- sys.stderr.write('----------------------------------------------------------------------\n')
- sys.stderr.write('%s\n' % settingsStr.strip())
- sys.stderr.write('----------------------------------------------------------------------\n')
- sys.stderr.write('Please check the syntax of these settings.\n\n')
- raise
-
- def eatAttr(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- startPos = self.pos()
- self.getDirectiveStartToken()
- self.advance(len('attr'))
- self.getWhiteSpace()
- startPos = self.pos()
- if self.matchCheetahVarStart():
- self.getCheetahVarStartToken()
- attribName = self.getIdentifier()
- self.getWhiteSpace()
- self.getAssignmentOperator()
- expr = self.getExpression()
- expr = self._applyExpressionFilters(expr, 'attr', startPos=startPos)
- self._compiler.addAttribute(attribName, expr)
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
-
- def eatDecorator(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- startPos = self.pos()
- self.getDirectiveStartToken()
- #self.advance() # eat @
- startPos = self.pos()
- decoratorExpr = self.getExpression()
- decoratorExpr = self._applyExpressionFilters(decoratorExpr, 'decorator', startPos=startPos)
- self._compiler.addDecorator(decoratorExpr)
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- self.getWhiteSpace()
-
- directiveName = self.matchDirective()
- if not directiveName or directiveName not in ('def', 'block', 'closure', '@'):
- raise ParseError(
- self, msg='Expected #def, #block, #closure or another @decorator')
- self.eatDirective()
-
- def eatDef(self):
- # filtered
- self._eatDefOrBlock('def')
-
- def eatBlock(self):
- # filtered
- startPos = self.pos()
- methodName, rawSignature = self._eatDefOrBlock('block')
- self._compiler._blockMetaData[methodName] = {
- 'raw': rawSignature,
- 'lineCol': self.getRowCol(startPos),
- }
-
- def eatClosure(self):
- # filtered
- self._eatDefOrBlock('closure')
-
- def _eatDefOrBlock(self, directiveName):
- # filtered
- assert directiveName in ('def', 'block', 'closure')
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- startPos = self.pos()
- self.getDirectiveStartToken()
- self.advance(len(directiveName))
- self.getWhiteSpace()
- if self.matchCheetahVarStart():
- self.getCheetahVarStartToken()
- methodName = self.getIdentifier()
- self.getWhiteSpace()
- if self.peek() == '(':
- argsList = self.getDefArgList()
- self.advance() # past the closing ')'
- if argsList and argsList[0][0] == 'self':
- del argsList[0]
- else:
- argsList=[]
-
- def includeBlockMarkers():
- if self.setting('includeBlockMarkers'):
- startMarker = self.setting('blockMarkerStart')
- self._compiler.addStrConst(startMarker[0] + methodName + startMarker[1])
-
- # @@TR: fix up filtering
- self._applyExpressionFilters(self[startPos:self.pos()], 'def', startPos=startPos)
-
- if self.matchColonForSingleLineShortFormDirective():
- isNestedDef = (self.setting('allowNestedDefScopes')
- and [name for name in self._openDirectivesStack if name=='def'])
- self.getc()
- rawSignature = self[startPos:endOfFirstLinePos]
- self._eatSingleLineDef(directiveName=directiveName,
- methodName=methodName,
- argsList=argsList,
- startPos=startPos,
- endPos=endOfFirstLinePos)
- if directiveName == 'def' and not isNestedDef:
- #@@TR: must come before _eatRestOfDirectiveTag ... for some reason
- self._compiler.closeDef()
- elif directiveName == 'block':
- includeBlockMarkers()
- self._compiler.closeBlock()
- elif directiveName == 'closure' or isNestedDef:
- self._compiler.dedent()
-
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- else:
- if self.peek()==':':
- self.getc()
- self.pushToOpenDirectivesStack(directiveName)
- rawSignature = self[startPos:self.pos()]
- self._eatMultiLineDef(directiveName=directiveName,
- methodName=methodName,
- argsList=argsList,
- startPos=startPos,
- isLineClearToStartToken=isLineClearToStartToken)
- if directiveName == 'block':
- includeBlockMarkers()
-
- return methodName, rawSignature
-
- def _eatMultiLineDef(self, directiveName, methodName, argsList, startPos,
- isLineClearToStartToken=False):
- # filtered in calling method
- self.getExpression() # slurp up any garbage left at the end
- signature = self[startPos:self.pos()]
- endOfFirstLinePos = self.findEOL()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- signature = ' '.join([line.strip() for line in signature.splitlines()])
- parserComment = ('## CHEETAH: generated from ' + signature +
- ' at line %s, col %s' % self.getRowCol(startPos)
- + '.')
-
- isNestedDef = (self.setting('allowNestedDefScopes')
- and len([name for name in self._openDirectivesStack if name=='def'])>1)
- if directiveName=='block' or (directiveName=='def' and not isNestedDef):
- self._compiler.startMethodDef(methodName, argsList, parserComment)
- else: #closure
- self._useSearchList_orig = self.setting('useSearchList')
- self.setSetting('useSearchList', False)
- self._compiler.addClosure(methodName, argsList, parserComment)
-
- return methodName
-
- def _eatSingleLineDef(self, directiveName, methodName, argsList, startPos, endPos):
- # filtered in calling method
- fullSignature = self[startPos:endPos]
- parserComment = ('## Generated from ' + fullSignature +
- ' at line %s, col %s' % self.getRowCol(startPos)
- + '.')
- isNestedDef = (self.setting('allowNestedDefScopes')
- and [name for name in self._openDirectivesStack if name=='def'])
- if directiveName=='block' or (directiveName=='def' and not isNestedDef):
- self._compiler.startMethodDef(methodName, argsList, parserComment)
- else: #closure
- # @@TR: temporary hack of useSearchList
- useSearchList_orig = self.setting('useSearchList')
- self.setSetting('useSearchList', False)
- self._compiler.addClosure(methodName, argsList, parserComment)
-
- self.getWhiteSpace(max=1)
- self.parse(breakPoint=endPos)
- if directiveName=='closure' or isNestedDef: # @@TR: temporary hack of useSearchList
- self.setSetting('useSearchList', useSearchList_orig)
-
- def eatExtends(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(len('extends'))
- self.getWhiteSpace()
- startPos = self.pos()
- if self.setting('allowExpressionsInExtendsDirective'):
- baseName = self.getExpression()
- else:
- baseName = self.getCommaSeparatedSymbols()
- baseName = ', '.join(baseName)
-
- baseName = self._applyExpressionFilters(baseName, 'extends', startPos=startPos)
- self._compiler.setBaseClass(baseName) # in compiler
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
-
- def eatImplements(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(len('implements'))
- self.getWhiteSpace()
- startPos = self.pos()
- methodName = self.getIdentifier()
- if not self.atEnd() and self.peek() == '(':
- argsList = self.getDefArgList()
- self.advance() # past the closing ')'
- if argsList and argsList[0][0] == 'self':
- del argsList[0]
- else:
- argsList=[]
-
- # @@TR: need to split up filtering of the methodname and the args
- #methodName = self._applyExpressionFilters(methodName, 'implements', startPos=startPos)
- self._applyExpressionFilters(self[startPos:self.pos()], 'implements', startPos=startPos)
-
- self._compiler.setMainMethodName(methodName)
- self._compiler.setMainMethodArgs(argsList)
-
- self.getExpression() # throw away and unwanted crap that got added in
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
-
- def eatSuper(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(len('super'))
- self.getWhiteSpace()
- startPos = self.pos()
- if not self.atEnd() and self.peek() == '(':
- argsList = self.getDefArgList()
- self.advance() # past the closing ')'
- if argsList and argsList[0][0] == 'self':
- del argsList[0]
- else:
- argsList=[]
-
- self._applyExpressionFilters(self[startPos:self.pos()], 'super', startPos=startPos)
-
- #parserComment = ('## CHEETAH: generated from ' + signature +
- # ' at line %s, col %s' % self.getRowCol(startPos)
- # + '.')
-
- self.getExpression() # throw away and unwanted crap that got added in
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
- self._compiler.addSuper(argsList)
-
- def eatSet(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(3)
- self.getWhiteSpace()
- style = SET_LOCAL
- if self.startswith('local'):
- self.getIdentifier()
- self.getWhiteSpace()
- elif self.startswith('global'):
- self.getIdentifier()
- self.getWhiteSpace()
- style = SET_GLOBAL
- elif self.startswith('module'):
- self.getIdentifier()
- self.getWhiteSpace()
- style = SET_MODULE
-
- startsWithDollar = self.matchCheetahVarStart()
- startPos = self.pos()
- LVALUE = self.getExpression(pyTokensToBreakAt=assignmentOps, useNameMapper=False).strip()
- OP = self.getAssignmentOperator()
- RVALUE = self.getExpression()
- expr = LVALUE + ' ' + OP + ' ' + RVALUE.strip()
-
- expr = self._applyExpressionFilters(expr, 'set', startPos=startPos)
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
-
- class Components: pass # used for 'set global'
- exprComponents = Components()
- exprComponents.LVALUE = LVALUE
- exprComponents.OP = OP
- exprComponents.RVALUE = RVALUE
- self._compiler.addSet(expr, exprComponents, style)
-
- def eatSlurp(self):
- if self.isLineClearToStartToken():
- self._compiler.handleWSBeforeDirective()
- self._compiler.commitStrConst()
- self.readToEOL(gobble=True)
-
- def eatEOLSlurpToken(self):
- if self.isLineClearToStartToken():
- self._compiler.handleWSBeforeDirective()
- self._compiler.commitStrConst()
- self.readToEOL(gobble=True)
-
- def eatRaw(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(len('raw'))
- self.getWhiteSpace()
- if self.matchColonForSingleLineShortFormDirective():
- self.advance() # skip over :
- self.getWhiteSpace(max=1)
- rawBlock = self.readToEOL(gobble=False)
- else:
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- rawBlock = self._eatToThisEndDirective('raw')
- self._compiler.addRawText(rawBlock)
-
- def eatInclude(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(len('include'))
-
- self.getWhiteSpace()
- includeFrom = 'file'
- isRaw = False
- if self.startswith('raw'):
- self.advance(3)
- isRaw=True
-
- self.getWhiteSpace()
- if self.startswith('source'):
- self.advance(len('source'))
- includeFrom = 'str'
- self.getWhiteSpace()
- if not self.peek() == '=':
- raise ParseError(self)
- self.advance()
- startPos = self.pos()
- sourceExpr = self.getExpression()
- sourceExpr = self._applyExpressionFilters(sourceExpr, 'include', startPos=startPos)
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- self._compiler.addInclude(sourceExpr, includeFrom, isRaw)
-
-
- def eatDefMacro(self):
- # @@TR: not filtered yet
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(len('defmacro'))
-
- self.getWhiteSpace()
- if self.matchCheetahVarStart():
- self.getCheetahVarStartToken()
- macroName = self.getIdentifier()
- self.getWhiteSpace()
- if self.peek() == '(':
- argsList = self.getDefArgList(useNameMapper=False)
- self.advance() # past the closing ')'
- if argsList and argsList[0][0] == 'self':
- del argsList[0]
- else:
- argsList=[]
-
- assert macroName not in self._directiveNamesAndParsers
- argsList.insert(0, ('src', None))
- argsList.append(('parser', 'None'))
- argsList.append(('macros', 'None'))
- argsList.append(('compilerSettings', 'None'))
- argsList.append(('isShortForm', 'None'))
- argsList.append(('EOLCharsInShortForm', 'None'))
- argsList.append(('startPos', 'None'))
- argsList.append(('endPos', 'None'))
-
- if self.matchColonForSingleLineShortFormDirective():
- self.advance() # skip over :
- self.getWhiteSpace(max=1)
- macroSrc = self.readToEOL(gobble=False)
- self.readToEOL(gobble=True)
- else:
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- macroSrc = self._eatToThisEndDirective('defmacro')
-
- #print argsList
- normalizedMacroSrc = ''.join(
- ['%def callMacro('+','.join([defv and '%s=%s'%(n, defv) or n
- for n, defv in argsList])
- +')\n',
- macroSrc,
- '%end def'])
-
-
- from Cheetah.Template import Template
- templateAPIClass = self.setting('templateAPIClassForDefMacro', default=Template)
- compilerSettings = self.setting('compilerSettingsForDefMacro', default={})
- searchListForMacros = self.setting('searchListForDefMacro', default=[])
- searchListForMacros = list(searchListForMacros) # copy to avoid mutation bugs
- searchListForMacros.append({'macros': self._macros,
- 'parser': self,
- 'compilerSettings': self.settings(),
- })
-
- templateAPIClass._updateSettingsWithPreprocessTokens(
- compilerSettings, placeholderToken='@', directiveToken='%')
- macroTemplateClass = templateAPIClass.compile(source=normalizedMacroSrc,
- compilerSettings=compilerSettings)
- #print normalizedMacroSrc
- #t = macroTemplateClass()
- #print t.callMacro('src')
- #print t.generatedClassCode()
-
- class MacroDetails: pass
- macroDetails = MacroDetails()
- macroDetails.macroSrc = macroSrc
- macroDetails.argsList = argsList
- macroDetails.template = macroTemplateClass(searchList=searchListForMacros)
-
- self._macroDetails[macroName] = macroDetails
- self._macros[macroName] = macroDetails.template.callMacro
- self._directiveNamesAndParsers[macroName] = self.eatMacroCall
-
- def eatMacroCall(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- startPos = self.pos()
- self.getDirectiveStartToken()
- macroName = self.getIdentifier()
- macro = self._macros[macroName]
- if hasattr(macro, 'parse'):
- return macro.parse(parser=self, startPos=startPos)
-
- if hasattr(macro, 'parseArgs'):
- args = macro.parseArgs(parser=self, startPos=startPos)
- else:
- self.getWhiteSpace()
- args = self.getExpression(useNameMapper=False,
- pyTokensToBreakAt=[':']).strip()
-
- if self.matchColonForSingleLineShortFormDirective():
- isShortForm = True
- self.advance() # skip over :
- self.getWhiteSpace(max=1)
- srcBlock = self.readToEOL(gobble=False)
- EOLCharsInShortForm = self.readToEOL(gobble=True)
- #self.readToEOL(gobble=False)
- else:
- isShortForm = False
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- srcBlock = self._eatToThisEndDirective(macroName)
-
-
- if hasattr(macro, 'convertArgStrToDict'):
- kwArgs = macro.convertArgStrToDict(args, parser=self, startPos=startPos)
- else:
- def getArgs(*pargs, **kws):
- return pargs, kws
- exec('positionalArgs, kwArgs = getArgs(%(args)s)'%locals())
-
- assert 'src' not in kwArgs
- kwArgs['src'] = srcBlock
-
- if isinstance(macro, types.MethodType):
- co = macro.im_func.func_code
- elif (hasattr(macro, '__call__')
- and hasattr(macro.__call__, 'im_func')):
- co = macro.__call__.im_func.func_code
- else:
- co = macro.func_code
- availableKwArgs = inspect.getargs(co)[0]
-
- if 'parser' in availableKwArgs:
- kwArgs['parser'] = self
- if 'macros' in availableKwArgs:
- kwArgs['macros'] = self._macros
- if 'compilerSettings' in availableKwArgs:
- kwArgs['compilerSettings'] = self.settings()
- if 'isShortForm' in availableKwArgs:
- kwArgs['isShortForm'] = isShortForm
- if isShortForm and 'EOLCharsInShortForm' in availableKwArgs:
- kwArgs['EOLCharsInShortForm'] = EOLCharsInShortForm
-
- if 'startPos' in availableKwArgs:
- kwArgs['startPos'] = startPos
- if 'endPos' in availableKwArgs:
- kwArgs['endPos'] = self.pos()
-
- srcFromMacroOutput = macro(**kwArgs)
-
- origParseSrc = self._src
- origBreakPoint = self.breakPoint()
- origPos = self.pos()
- # add a comment to the output about the macro src that is being parsed
- # or add a comment prefix to all the comments added by the compiler
- self._src = srcFromMacroOutput
- self.setPos(0)
- self.setBreakPoint(len(srcFromMacroOutput))
-
- self.parse(assertEmptyStack=False)
-
- self._src = origParseSrc
- self.setBreakPoint(origBreakPoint)
- self.setPos(origPos)
-
-
- #self._compiler.addRawText('end')
-
- def eatCache(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- lineCol = self.getRowCol()
- self.getDirectiveStartToken()
- self.advance(len('cache'))
-
- startPos = self.pos()
- argList = self.getDefArgList(useNameMapper=True)
- argList = self._applyExpressionFilters(argList, 'cache', startPos=startPos)
-
- def startCache():
- cacheInfo = self._compiler.genCacheInfoFromArgList(argList)
- self._compiler.startCacheRegion(cacheInfo, lineCol)
-
- if self.matchColonForSingleLineShortFormDirective():
- self.advance() # skip over :
- self.getWhiteSpace(max=1)
- startCache()
- self.parse(breakPoint=self.findEOL(gobble=True))
- self._compiler.endCacheRegion()
- else:
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- self.pushToOpenDirectivesStack('cache')
- startCache()
-
- def eatCall(self):
- # @@TR: need to enable single line version of this
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- lineCol = self.getRowCol()
- self.getDirectiveStartToken()
- self.advance(len('call'))
- startPos = self.pos()
-
- useAutocallingOrig = self.setting('useAutocalling')
- self.setSetting('useAutocalling', False)
- self.getWhiteSpace()
- if self.matchCheetahVarStart():
- functionName = self.getCheetahVar()
- else:
- functionName = self.getCheetahVar(plain=True, skipStartToken=True)
- self.setSetting('useAutocalling', useAutocallingOrig)
- # @@TR: fix up filtering
- self._applyExpressionFilters(self[startPos:self.pos()], 'call', startPos=startPos)
-
- self.getWhiteSpace()
- args = self.getExpression(pyTokensToBreakAt=[':']).strip()
- if self.matchColonForSingleLineShortFormDirective():
- self.advance() # skip over :
- self._compiler.startCallRegion(functionName, args, lineCol)
- self.getWhiteSpace(max=1)
- self.parse(breakPoint=self.findEOL(gobble=False))
- self._compiler.endCallRegion()
- else:
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self.pushToOpenDirectivesStack("call")
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- self._compiler.startCallRegion(functionName, args, lineCol)
-
- def eatCallArg(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- lineCol = self.getRowCol()
- self.getDirectiveStartToken()
-
- self.advance(len('arg'))
- startPos = self.pos()
- self.getWhiteSpace()
- argName = self.getIdentifier()
- self.getWhiteSpace()
- argName = self._applyExpressionFilters(argName, 'arg', startPos=startPos)
- self._compiler.setCallArg(argName, lineCol)
- if self.peek() == ':':
- self.getc()
- else:
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
-
- def eatFilter(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
-
- self.getDirectiveStartToken()
- self.advance(len('filter'))
- self.getWhiteSpace()
- startPos = self.pos()
- if self.matchCheetahVarStart():
- isKlass = True
- theFilter = self.getExpression(pyTokensToBreakAt=[':'])
- else:
- isKlass = False
- theFilter = self.getIdentifier()
- self.getWhiteSpace()
- theFilter = self._applyExpressionFilters(theFilter, 'filter', startPos=startPos)
-
- if self.matchColonForSingleLineShortFormDirective():
- self.advance() # skip over :
- self.getWhiteSpace(max=1)
- self._compiler.setFilter(theFilter, isKlass)
- self.parse(breakPoint=self.findEOL(gobble=False))
- self._compiler.closeFilterBlock()
- else:
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self.pushToOpenDirectivesStack("filter")
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- self._compiler.setFilter(theFilter, isKlass)
-
- def eatTransform(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
-
- self.getDirectiveStartToken()
- self.advance(len('transform'))
- self.getWhiteSpace()
- startPos = self.pos()
- if self.matchCheetahVarStart():
- isKlass = True
- transformer = self.getExpression(pyTokensToBreakAt=[':'])
- else:
- isKlass = False
- transformer = self.getIdentifier()
- self.getWhiteSpace()
- transformer = self._applyExpressionFilters(transformer, 'transform', startPos=startPos)
-
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- self._compiler.setTransform(transformer, isKlass)
-
-
- def eatErrorCatcher(self):
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- self.getDirectiveStartToken()
- self.advance(len('errorCatcher'))
- self.getWhiteSpace()
- startPos = self.pos()
- errorCatcherName = self.getIdentifier()
- errorCatcherName = self._applyExpressionFilters(
- errorCatcherName, 'errorcatcher', startPos=startPos)
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- self._compiler.setErrorCatcher(errorCatcherName)
-
- def eatCapture(self):
- # @@TR: this could be refactored to use the code in eatSimpleIndentingDirective
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLinePos = self.findEOL()
- lineCol = self.getRowCol()
-
- self.getDirectiveStartToken()
- self.advance(len('capture'))
- startPos = self.pos()
- self.getWhiteSpace()
-
- expr = self.getExpression(pyTokensToBreakAt=[':'])
- expr = self._applyExpressionFilters(expr, 'capture', startPos=startPos)
- if self.matchColonForSingleLineShortFormDirective():
- self.advance() # skip over :
- self._compiler.startCaptureRegion(assignTo=expr, lineCol=lineCol)
- self.getWhiteSpace(max=1)
- self.parse(breakPoint=self.findEOL(gobble=False))
- self._compiler.endCaptureRegion()
- else:
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
- self.pushToOpenDirectivesStack("capture")
- self._compiler.startCaptureRegion(assignTo=expr, lineCol=lineCol)
-
-
- def eatIf(self):
- # filtered
- isLineClearToStartToken = self.isLineClearToStartToken()
- endOfFirstLine = self.findEOL()
- lineCol = self.getRowCol()
- self.getDirectiveStartToken()
- startPos = self.pos()
-
- expressionParts = self.getExpressionParts(pyTokensToBreakAt=[':'])
- expr = ''.join(expressionParts).strip()
- expr = self._applyExpressionFilters(expr, 'if', startPos=startPos)
-
- isTernaryExpr = ('then' in expressionParts and 'else' in expressionParts)
- if isTernaryExpr:
- conditionExpr = []
- trueExpr = []
- falseExpr = []
- currentExpr = conditionExpr
- for part in expressionParts:
- if part.strip()=='then':
- currentExpr = trueExpr
- elif part.strip()=='else':
- currentExpr = falseExpr
- else:
- currentExpr.append(part)
-
- conditionExpr = ''.join(conditionExpr)
- trueExpr = ''.join(trueExpr)
- falseExpr = ''.join(falseExpr)
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
- self._compiler.addTernaryExpr(conditionExpr, trueExpr, falseExpr, lineCol=lineCol)
- elif self.matchColonForSingleLineShortFormDirective():
- self.advance() # skip over :
- self._compiler.addIf(expr, lineCol=lineCol)
- self.getWhiteSpace(max=1)
- self.parse(breakPoint=self.findEOL(gobble=True))
- self._compiler.commitStrConst()
- self._compiler.dedent()
- else:
- if self.peek()==':':
- self.advance()
- self.getWhiteSpace()
- self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
- self.pushToOpenDirectivesStack('if')
- self._compiler.addIf(expr, lineCol=lineCol)
-
- ## end directive handlers
- def handleEndDef(self):
- isNestedDef = (self.setting('allowNestedDefScopes')
- and [name for name in self._openDirectivesStack if name=='def'])
- if not isNestedDef:
- self._compiler.closeDef()
- else:
- # @@TR: temporary hack of useSearchList
- self.setSetting('useSearchList', self._useSearchList_orig)
- self._compiler.commitStrConst()
- self._compiler.dedent()
- ###
-
- def pushToOpenDirectivesStack(self, directiveName):
- assert directiveName in self._closeableDirectives
- self._openDirectivesStack.append(directiveName)
-
- def popFromOpenDirectivesStack(self, directiveName):
- if not self._openDirectivesStack:
- raise ParseError(self, msg="#end found, but nothing to end")
-
- if self._openDirectivesStack[-1] == directiveName:
- del self._openDirectivesStack[-1]
- else:
- raise ParseError(self, msg="#end %s found, expected #end %s" %(
- directiveName, self._openDirectivesStack[-1]))
-
- def assertEmptyOpenDirectivesStack(self):
- if self._openDirectivesStack:
- errorMsg = (
- "Some #directives are missing their corresponding #end ___ tag: %s" %(
- ', '.join(self._openDirectivesStack)))
- raise ParseError(self, msg=errorMsg)
-
-##################################################
-## Make an alias to export
-Parser = _HighLevelParser
Index: cheetah/Cheetah/Servlet.py
===================================================================
--- cheetah/Cheetah/Servlet.py (revision 19111)
+++ cheetah/Cheetah/Servlet.py (nonexistent)
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-'''
-Provides an abstract Servlet baseclass for Cheetah's Template class
-'''
-
-import sys
-import os.path
-
-class Servlet(object):
- """
- This class is an abstract baseclass for Cheetah.Template.Template.
- """
-
- transaction = None
- application = None
- request = None
- session = None
-
- def respond(self, trans=None):
- raise NotImplementedError("""\
-couldn't find the template's main method. If you are using #extends
-without #implements, try adding '#implements respond' to your template
-definition.""")
-
- def sleep(self, transaction):
- super(Servlet, self).sleep(transaction)
- self.session = None
- self.request = None
- self._request = None
- self.response = None
- self.transaction = None
-
- def shutdown(self):
- pass
-
- def serverSidePath(self, path=None,
- normpath=os.path.normpath,
- abspath=os.path.abspath
- ):
-
- if path:
- return normpath(abspath(path.replace("\\", '/')))
- elif hasattr(self, '_filePath') and self._filePath:
- return normpath(abspath(self._filePath))
- else:
- return None
-
-# vim: shiftwidth=4 tabstop=4 expandtab
Index: cheetah/Cheetah/SettingsManager.py
===================================================================
--- cheetah/Cheetah/SettingsManager.py (revision 19111)
+++ cheetah/Cheetah/SettingsManager.py (nonexistent)
@@ -1,284 +0,0 @@
-import sys
-import os.path
-import copy as copyModule
-from ConfigParser import ConfigParser
-import re
-from tokenize import Intnumber, Floatnumber, Number
-import types
-import time
-from StringIO import StringIO # not cStringIO because of unicode support
-import imp # used by SettingsManager.updateSettingsFromPySrcFile()
-
-
-numberRE = re.compile(Number)
-complexNumberRE = re.compile('[\(]*' +Number + r'[ \t]*\+[ \t]*' + Number + '[\)]*')
-
-##################################################
-## FUNCTIONS ##
-
-def mergeNestedDictionaries(dict1, dict2, copy=False, deepcopy=False):
- """Recursively merge the values of dict2 into dict1.
-
- This little function is very handy for selectively overriding settings in a
- settings dictionary that has a nested structure.
- """
-
- if copy:
- dict1 = copyModule.copy(dict1)
- elif deepcopy:
- dict1 = copyModule.deepcopy(dict1)
-
- for key, val in dict2.iteritems():
- if key in dict1 and isinstance(val, dict) and isinstance(dict1[key], dict):
- dict1[key] = mergeNestedDictionaries(dict1[key], val)
- else:
- dict1[key] = val
- return dict1
-
-def stringIsNumber(S):
- """Return True if theString represents a Python number, False otherwise.
- This also works for complex numbers and numbers with +/- in front."""
-
- S = S.strip()
-
- if S[0] in '-+' and len(S) > 1:
- S = S[1:].strip()
-
- match = complexNumberRE.match(S)
- if not match:
- match = numberRE.match(S)
- if not match or (match.end() != len(S)):
- return False
- else:
- return True
-
-def convStringToNum(theString):
- """Convert a string representation of a Python number to the Python version"""
-
- if not stringIsNumber(theString):
- raise Error(theString + ' cannot be converted to a Python number')
- return eval(theString, {}, {})
-
-
-class Error(Exception):
- pass
-
-class NoDefault(object):
- pass
-
-class ConfigParserCaseSensitive(ConfigParser):
- """A case sensitive version of the standard Python ConfigParser."""
-
- def optionxform(self, optionstr):
- """Don't change the case as is done in the default implemenation."""
- return optionstr
-
-class _SettingsCollector(object):
- """An abstract base class that provides the methods SettingsManager uses to
- collect settings from config files and strings.
-
- This class only collects settings it doesn't modify the _settings dictionary
- of SettingsManager instances in any way.
- """
-
- _ConfigParserClass = ConfigParserCaseSensitive
-
- def readSettingsFromModule(self, mod, ignoreUnderscored=True):
- """Returns all settings from a Python module.
- """
- S = {}
- attrs = vars(mod)
- for k, v in attrs.iteritems():
- if (ignoreUnderscored and k.startswith('_')):
- continue
- else:
- S[k] = v
- return S
-
- def readSettingsFromPySrcStr(self, theString):
- """Return a dictionary of the settings in a Python src string."""
-
- globalsDict = {'True': (1==1),
- 'False': (0==1),
- }
- newSettings = {'self':self}
- exec((theString+os.linesep), globalsDict, newSettings)
- del newSettings['self']
- module = types.ModuleType('temp_settings_module')
- module.__dict__.update(newSettings)
- return self.readSettingsFromModule(module)
-
- def readSettingsFromConfigFileObj(self, inFile, convert=True):
- """Return the settings from a config file that uses the syntax accepted by
- Python's standard ConfigParser module (like Windows .ini files).
-
- NOTE:
- this method maintains case unlike the ConfigParser module, unless this
- class was initialized with the 'caseSensitive' keyword set to False.
-
- All setting values are initially parsed as strings. However, If the
- 'convert' arg is True this method will do the following value
- conversions:
-
- * all Python numeric literals will be coverted from string to number
-
- * The string 'None' will be converted to the Python value None
-
- * The string 'True' will be converted to a Python truth value
-
- * The string 'False' will be converted to a Python false value
-
- * Any string starting with 'python:' will be treated as a Python literal
- or expression that needs to be eval'd. This approach is useful for
- declaring lists and dictionaries.
-
- If a config section titled 'Globals' is present the options defined
- under it will be treated as top-level settings.
- """
-
- p = self._ConfigParserClass()
- p.readfp(inFile)
- sects = p.sections()
- newSettings = {}
-
- sects = p.sections()
- newSettings = {}
-
- for s in sects:
- newSettings[s] = {}
- for o in p.options(s):
- if o != '__name__':
- newSettings[s][o] = p.get(s, o)
-
- ## loop through new settings -> deal with global settings, numbers,
- ## booleans and None ++ also deal with 'importSettings' commands
-
- for sect, subDict in newSettings.items():
- for key, val in subDict.items():
- if convert:
- if val.lower().startswith('python:'):
- subDict[key] = eval(val[7:], {}, {})
- if val.lower() == 'none':
- subDict[key] = None
- if val.lower() == 'true':
- subDict[key] = True
- if val.lower() == 'false':
- subDict[key] = False
- if stringIsNumber(val):
- subDict[key] = convStringToNum(val)
-
- ## now deal with any 'importSettings' commands
- if key.lower() == 'importsettings':
- if val.find(';') < 0:
- importedSettings = self.readSettingsFromPySrcFile(val)
- else:
- path = val.split(';')[0]
- rest = ''.join(val.split(';')[1:]).strip()
- parentDict = self.readSettingsFromPySrcFile(path)
- importedSettings = eval('parentDict["' + rest + '"]')
-
- subDict.update(mergeNestedDictionaries(subDict,
- importedSettings))
-
- if sect.lower() == 'globals':
- newSettings.update(newSettings[sect])
- del newSettings[sect]
-
- return newSettings
-
-
-class SettingsManager(_SettingsCollector):
- """A mixin class that provides facilities for managing application settings.
-
- SettingsManager is designed to work well with nested settings dictionaries
- of any depth.
- """
-
- def __init__(self):
- super(SettingsManager, self).__init__()
- self._settings = {}
- self._initializeSettings()
-
- def _defaultSettings(self):
- return {}
-
- def _initializeSettings(self):
- """A hook that allows for complex setting initialization sequences that
- involve references to 'self' or other settings. For example:
- self._settings['myCalcVal'] = self._settings['someVal'] * 15
- This method should be called by the class' __init__() method when needed.
- The dummy implementation should be reimplemented by subclasses.
- """
-
- pass
-
- ## core post startup methods
-
- def setting(self, name, default=NoDefault):
- """Get a setting from self._settings, with or without a default value."""
-
- if default is NoDefault:
- return self._settings[name]
- else:
- return self._settings.get(name, default)
-
-
- def hasSetting(self, key):
- """True/False"""
- return key in self._settings
-
- def setSetting(self, name, value):
- """Set a setting in self._settings."""
- self._settings[name] = value
-
- def settings(self):
- """Return a reference to the settings dictionary"""
- return self._settings
-
- def copySettings(self):
- """Returns a shallow copy of the settings dictionary"""
- return copyModule.copy(self._settings)
-
- def deepcopySettings(self):
- """Returns a deep copy of the settings dictionary"""
- return copyModule.deepcopy(self._settings)
-
- def updateSettings(self, newSettings, merge=True):
- """Update the settings with a selective merge or a complete overwrite."""
-
- if merge:
- mergeNestedDictionaries(self._settings, newSettings)
- else:
- self._settings.update(newSettings)
-
-
- ## source specific update methods
-
- def updateSettingsFromPySrcStr(self, theString, merge=True):
- """Update the settings from a code in a Python src string."""
-
- newSettings = self.readSettingsFromPySrcStr(theString)
- self.updateSettings(newSettings,
- merge=newSettings.get('mergeSettings', merge) )
-
-
- def updateSettingsFromConfigFileObj(self, inFile, convert=True, merge=True):
- """See the docstring for .updateSettingsFromConfigFile()
-
- The caller of this method is responsible for closing the inFile file
- object."""
-
- newSettings = self.readSettingsFromConfigFileObj(inFile, convert=convert)
- self.updateSettings(newSettings,
- merge=newSettings.get('mergeSettings', merge))
-
- def updateSettingsFromConfigStr(self, configStr, convert=True, merge=True):
- """See the docstring for .updateSettingsFromConfigFile()
- """
-
- configStr = '[globals]\n' + configStr
- inFile = StringIO(configStr)
- newSettings = self.readSettingsFromConfigFileObj(inFile, convert=convert)
- self.updateSettings(newSettings,
- merge=newSettings.get('mergeSettings', merge))
-
Index: cheetah/Cheetah/SourceReader.py
===================================================================
--- cheetah/Cheetah/SourceReader.py (revision 19111)
+++ cheetah/Cheetah/SourceReader.py (nonexistent)
@@ -1,267 +0,0 @@
-"""SourceReader class for Cheetah's Parser and CodeGenerator
-"""
-import re
-import sys
-
-EOLre = re.compile(r'[ \f\t]*(?:\r\n|\r|\n)')
-EOLZre = re.compile(r'(?:\r\n|\r|\n|\Z)')
-ENCODINGsearch = re.compile("coding[=:]\s*([-\w.]+)").search
-
-class Error(Exception):
- pass
-
-class SourceReader(object):
- def __init__(self, src, filename=None, breakPoint=None, encoding=None):
- self._src = src
- self._filename = filename
- self._srcLen = len(src)
- if breakPoint == None:
- self._breakPoint = self._srcLen
- else:
- self.setBreakPoint(breakPoint)
- self._pos = 0
- self._bookmarks = {}
- self._posTobookmarkMap = {}
-
- ## collect some meta-information
- self._EOLs = []
- pos = 0
- while pos < len(self):
- EOLmatch = EOLZre.search(src, pos)
- self._EOLs.append(EOLmatch.start())
- pos = EOLmatch.end()
-
- self._BOLs = []
- for pos in self._EOLs:
- BOLpos = self.findBOL(pos)
- self._BOLs.append(BOLpos)
-
- def src(self):
- return self._src
-
- def filename(self):
- return self._filename
-
- def __len__(self):
- return self._breakPoint
-
- def __getitem__(self, i):
- if not isinstance(i, int):
- self.checkPos(i.stop)
- else:
- self.checkPos(i)
- return self._src[i]
-
- def __getslice__(self, i, j):
- i = max(i, 0); j = max(j, 0)
- return self._src[i:j]
-
- def splitlines(self):
- if not hasattr(self, '_srcLines'):
- self._srcLines = self._src.splitlines()
- return self._srcLines
-
- def lineNum(self, pos=None):
- if pos == None:
- pos = self._pos
-
- for i in range(len(self._BOLs)):
- if pos >= self._BOLs[i] and pos <= self._EOLs[i]:
- return i
-
- def getRowCol(self, pos=None):
- if pos == None:
- pos = self._pos
- lineNum = self.lineNum(pos)
- BOL, EOL = self._BOLs[lineNum], self._EOLs[lineNum]
- return lineNum+1, pos-BOL+1
-
- def getRowColLine(self, pos=None):
- if pos == None:
- pos = self._pos
- row, col = self.getRowCol(pos)
- return row, col, self.splitlines()[row-1]
-
- def getLine(self, pos):
- if pos == None:
- pos = self._pos
- lineNum = self.lineNum(pos)
- return self.splitlines()[lineNum]
-
- def pos(self):
- return self._pos
-
- def setPos(self, pos):
- self.checkPos(pos)
- self._pos = pos
-
-
- def validPos(self, pos):
- return pos <= self._breakPoint and pos >=0
-
- def checkPos(self, pos):
- if not pos <= self._breakPoint:
- raise Error("pos (" + str(pos) + ") is invalid: beyond the stream's end (" +
- str(self._breakPoint-1) + ")" )
- elif not pos >=0:
- raise Error("pos (" + str(pos) + ") is invalid: less than 0" )
-
- def breakPoint(self):
- return self._breakPoint
-
- def setBreakPoint(self, pos):
- if pos > self._srcLen:
- raise Error("New breakpoint (" + str(pos) +
- ") is invalid: beyond the end of stream's source string (" +
- str(self._srcLen) + ")" )
- elif not pos >= 0:
- raise Error("New breakpoint (" + str(pos) + ") is invalid: less than 0" )
-
- self._breakPoint = pos
-
- def setBookmark(self, name):
- self._bookmarks[name] = self._pos
- self._posTobookmarkMap[self._pos] = name
-
- def hasBookmark(self, name):
- return name in self._bookmarks
-
- def gotoBookmark(self, name):
- if not self.hasBookmark(name):
- raise Error("Invalid bookmark (" + name + ") is invalid: does not exist")
- pos = self._bookmarks[name]
- if not self.validPos(pos):
- raise Error("Invalid bookmark (" + name + ', '+
- str(pos) + ") is invalid: pos is out of range" )
- self._pos = pos
-
- def atEnd(self):
- return self._pos >= self._breakPoint
-
- def atStart(self):
- return self._pos == 0
-
- def peek(self, offset=0):
- self.checkPos(self._pos+offset)
- pos = self._pos + offset
- return self._src[pos]
-
- def getc(self):
- pos = self._pos
- if self.validPos(pos+1):
- self._pos += 1
- return self._src[pos]
-
- def ungetc(self, c=None):
- if not self.atStart():
- raise Error('Already at beginning of stream')
-
- self._pos -= 1
- if not c==None:
- self._src[self._pos] = c
-
- def advance(self, offset=1):
- self.checkPos(self._pos + offset)
- self._pos += offset
-
- def rev(self, offset=1):
- self.checkPos(self._pos - offset)
- self._pos -= offset
-
- def read(self, offset):
- self.checkPos(self._pos + offset)
- start = self._pos
- self._pos += offset
- return self._src[start:self._pos]
-
- def readTo(self, to, start=None):
- self.checkPos(to)
- if start == None:
- start = self._pos
- self._pos = to
- return self._src[start:to]
-
-
- def readToEOL(self, start=None, gobble=True):
- EOLmatch = EOLZre.search(self.src(), self.pos())
- if gobble:
- pos = EOLmatch.end()
- else:
- pos = EOLmatch.start()
- return self.readTo(to=pos, start=start)
-
-
- def find(self, it, pos=None):
- if pos == None:
- pos = self._pos
- return self._src.find(it, pos )
-
- def startswith(self, it, pos=None):
- if self.find(it, pos) == self.pos():
- return True
- else:
- return False
-
- def rfind(self, it, pos):
- if pos == None:
- pos = self._pos
- return self._src.rfind(it, pos)
-
- def findBOL(self, pos=None):
- if pos == None:
- pos = self._pos
- src = self.src()
- return max(src.rfind('\n', 0, pos)+1, src.rfind('\r', 0, pos)+1, 0)
-
- def findEOL(self, pos=None, gobble=False):
- if pos == None:
- pos = self._pos
-
- match = EOLZre.search(self.src(), pos)
- if gobble:
- return match.end()
- else:
- return match.start()
-
- def isLineClearToPos(self, pos=None):
- if pos == None:
- pos = self.pos()
- self.checkPos(pos)
- src = self.src()
- BOL = self.findBOL()
- return BOL == pos or src[BOL:pos].isspace()
-
- def matches(self, strOrRE):
- if isinstance(strOrRE, (str, unicode)):
- return self.startswith(strOrRE, pos=self.pos())
- else: # assume an re object
- return strOrRE.match(self.src(), self.pos())
-
- def matchWhiteSpace(self, WSchars=' \f\t'):
- return (not self.atEnd()) and self.peek() in WSchars
-
- def getWhiteSpace(self, max=None, WSchars=' \f\t'):
- if not self.matchWhiteSpace(WSchars):
- return ''
- start = self.pos()
- breakPoint = self.breakPoint()
- if max is not None:
- breakPoint = min(breakPoint, self.pos()+max)
- while self.pos() < breakPoint:
- self.advance()
- if not self.matchWhiteSpace(WSchars):
- break
- return self.src()[start:self.pos()]
-
- def matchNonWhiteSpace(self, WSchars=' \f\t\n\r'):
- return self.atEnd() or not self.peek() in WSchars
-
- def getNonWhiteSpace(self, WSchars=' \f\t\n\r'):
- if not self.matchNonWhiteSpace(WSchars):
- return ''
- start = self.pos()
- while self.pos() < self.breakPoint():
- self.advance()
- if not self.matchNonWhiteSpace(WSchars):
- break
- return self.src()[start:self.pos()]
Index: cheetah/Cheetah/Template.py
===================================================================
--- cheetah/Cheetah/Template.py (revision 19111)
+++ cheetah/Cheetah/Template.py (nonexistent)
@@ -1,1941 +0,0 @@
-'''
-Provides the core API for Cheetah.
-
-See the docstring in the Template class and the Users' Guide for more information
-'''
-
-################################################################################
-## DEPENDENCIES
-import sys # used in the error handling code
-import re # used to define the internal delims regex
-import logging
-import string
-import os.path
-import time # used in the cache refresh code
-from random import randrange
-import imp
-import inspect
-import StringIO
-import traceback
-import pprint
-import cgi # Used by .webInput() if the template is a CGI script.
-import types
-
-try:
- from threading import Lock
-except ImportError:
- class Lock:
- def acquire(self):
- pass
- def release(self):
- pass
-
-filetype = None
-
-if isinstance(sys.version_info[:], tuple):
- # Python 2.xx
- filetype = types.FileType
- def createMethod(func, cls):
- return types.MethodType(func, None, cls)
-else:
- import io
- filetype = io.IOBase
- def createMethod(func, cls):
- return types.MethodType(func, cls)
-
-
-
-from Cheetah.Version import convertVersionStringToTuple, MinCompatibleVersionTuple
-from Cheetah.Version import MinCompatibleVersion
-# Base classes for Template
-from Cheetah.Servlet import Servlet
-# More intra-package imports ...
-from Cheetah.Parser import ParseError, SourceReader
-from Cheetah.Compiler import Compiler, DEFAULT_COMPILER_SETTINGS
-from Cheetah import ErrorCatchers # for placeholder tags
-from Cheetah import Filters # the output filters
-from Cheetah.convertTmplPathToModuleName import convertTmplPathToModuleName
-
-from Cheetah.Utils.Misc import checkKeywords # Used in Template.__init__
-from Cheetah.Utils.Indenter import Indenter # Used in Template.__init__ and for
- # placeholders
-from Cheetah.NameMapper import NotFound, valueFromSearchList
-from Cheetah.CacheStore import MemoryCacheStore, MemcachedCacheStore
-from Cheetah.CacheRegion import CacheRegion
-from Cheetah.Utils.WebInputMixin import _Converter, _lookup, NonNumericInputError
-
-from Cheetah.Unspecified import Unspecified
-
-# Decide whether to use the file modification time in file's cache key
-__checkFileMtime = True
-def checkFileMtime(value):
- globals()['__checkFileMtime'] = value
-
-class Error(Exception):
- pass
-class PreprocessError(Error):
- pass
-
-def hashList(l):
- hashedList = []
- for v in l:
- if isinstance(v, dict):
- v = hashDict(v)
- elif isinstance(v, list):
- v = hashList(v)
- hashedList.append(v)
- return hash(tuple(hashedList))
-
-def hashDict(d):
- items = sorted(d.items())
- hashedList = []
- for k, v in items:
- if isinstance(v, dict):
- v = hashDict(v)
- elif isinstance(v, list):
- v = hashList(v)
- hashedList.append((k, v))
- return hash(tuple(hashedList))
-
-
-################################################################################
-## MODULE GLOBALS AND CONSTANTS
-
-def _genUniqueModuleName(baseModuleName):
- """The calling code is responsible for concurrency locking.
- """
- if baseModuleName not in sys.modules:
- finalName = baseModuleName
- else:
- finalName = ('cheetah_%s_%s_%s'%(baseModuleName,
- str(time.time()).replace('.', '_'),
- str(randrange(10000, 99999))))
- return finalName
-
-# Cache of a cgi.FieldStorage() instance, maintained by .webInput().
-# This is only relavent to templates used as CGI scripts.
-_formUsedByWebInput = None
-
-def updateLinecache(filename, src):
- import linecache
- size = len(src)
- mtime = time.time()
- lines = src.splitlines()
- fullname = filename
- linecache.cache[filename] = size, mtime, lines, fullname
-
-class CompileCacheItem(object):
- pass
-
-class TemplatePreprocessor(object):
- '''
- This is used with the preprocessors argument to Template.compile().
-
- See the docstring for Template.compile
-
- ** Preprocessors are an advanced topic **
- '''
-
- def __init__(self, settings):
- self._settings = settings
-
- def preprocess(self, source, file):
- """Create an intermediate template and return the source code
- it outputs
- """
- settings = self._settings
- if not source: # @@TR: this needs improving
- if isinstance(file, (str, unicode)): # it's a filename.
- f = open(file)
- source = f.read()
- f.close()
- elif hasattr(file, 'read'):
- source = file.read()
- file = None
-
- templateAPIClass = settings.templateAPIClass
- possibleKwArgs = [
- arg for arg in
- inspect.getargs(templateAPIClass.compile.im_func.func_code)[0]
- if arg not in ('klass', 'source', 'file',)]
-
- compileKwArgs = {}
- for arg in possibleKwArgs:
- if hasattr(settings, arg):
- compileKwArgs[arg] = getattr(settings, arg)
-
- tmplClass = templateAPIClass.compile(source=source, file=file, **compileKwArgs)
- tmplInstance = tmplClass(**settings.templateInitArgs)
- outputSource = settings.outputTransformer(tmplInstance)
- outputFile = None
- return outputSource, outputFile
-
-class Template(Servlet):
- '''
- This class provides a) methods used by templates at runtime and b)
- methods for compiling Cheetah source code into template classes.
-
- This documentation assumes you already know Python and the basics of object
- oriented programming. If you don't know Python, see the sections of the
- Cheetah Users' Guide for non-programmers. It also assumes you have read
- about Cheetah's syntax in the Users' Guide.
-
- The following explains how to use Cheetah from within Python programs or via
- the interpreter. If you statically compile your templates on the command
- line using the 'cheetah' script, this is not relevant to you. Statically
- compiled Cheetah template modules/classes (e.g. myTemplate.py:
- MyTemplateClasss) are just like any other Python module or class. Also note,
- most Python web frameworks (Webware, Aquarium, mod_python, Turbogears,
- CherryPy, Quixote, etc.) provide plugins that handle Cheetah compilation for
- you.
-
- There are several possible usage patterns:
- 1) tclass = Template.compile(src)
- t1 = tclass() # or tclass(namespaces=[namespace,...])
- t2 = tclass() # or tclass(namespaces=[namespace2,...])
- outputStr = str(t1) # or outputStr = t1.aMethodYouDefined()
-
- Template.compile provides a rich and very flexible API via its
- optional arguments so there are many possible variations of this
- pattern. One example is:
- tclass = Template.compile('hello $name from $caller', baseclass=dict)
- print tclass(name='world', caller='me')
- See the Template.compile() docstring for more details.
-
- 2) tmplInstance = Template(src)
- # or Template(src, namespaces=[namespace,...])
- outputStr = str(tmplInstance) # or outputStr = tmplInstance.aMethodYouDefined(...args...)
-
- Notes on the usage patterns:
-
- usage pattern 1)
- This is the most flexible, but it is slightly more verbose unless you
- write a wrapper function to hide the plumbing. Under the hood, all
- other usage patterns are based on this approach. Templates compiled
- this way can #extend (subclass) any Python baseclass: old-style or
- new-style (based on object or a builtin type).
-
- usage pattern 2)
- This was Cheetah's original usage pattern. It returns an instance,
- but you can still access the generated class via
- tmplInstance.__class__. If you want to use several different
- namespace 'searchLists' with a single template source definition,
- you're better off with Template.compile (1).
-
- Limitations (use pattern 1 instead):
- - Templates compiled this way can only #extend subclasses of the
- new-style 'object' baseclass. Cheetah.Template is a subclass of
- 'object'. You also can not #extend dict, list, or other builtin
- types.
- - If your template baseclass' __init__ constructor expects args there
- is currently no way to pass them in.
-
- If you need to subclass a dynamically compiled Cheetah class, do something like this:
- from Cheetah.Template import Template
- T1 = Template.compile('$meth1 #def meth1: this is meth1 in T1')
- T2 = Template.compile('#implements meth1\nthis is meth1 redefined in T2', baseclass=T1)
- print T1, T1()
- print T2, T2()
-
-
- Note about class and instance attribute names:
- Attributes used by Cheetah have a special prefix to avoid confusion with
- the attributes of the templates themselves or those of template
- baseclasses.
-
- Class attributes which are used in class methods look like this:
- klass._CHEETAH_useCompilationCache (_CHEETAH_xxx)
-
- Instance attributes look like this:
- klass._CHEETAH__globalSetVars (_CHEETAH__xxx with 2 underscores)
- '''
-
- # this is used by ._addCheetahPlumbingCodeToClass()
- _CHEETAH_requiredCheetahMethods = (
- '_initCheetahInstance',
- 'searchList',
- 'errorCatcher',
- 'getVar',
- 'varExists',
- 'getFileContents',
- 'i18n',
- 'runAsMainProgram',
- 'respond',
- 'shutdown',
- 'webInput',
- 'serverSidePath',
- 'generatedClassCode',
- 'generatedModuleCode',
-
- '_getCacheStore',
- '_getCacheStoreIdPrefix',
- '_createCacheRegion',
- 'getCacheRegion',
- 'getCacheRegions',
- 'refreshCache',
-
- '_handleCheetahInclude',
- '_getTemplateAPIClassForIncludeDirectiveCompilation',
- )
- _CHEETAH_requiredCheetahClassMethods = ('subclass',)
- _CHEETAH_requiredCheetahClassAttributes = ('cacheRegionClass', 'cacheStore',
- 'cacheStoreIdPrefix', 'cacheStoreClass')
-
- ## the following are used by .compile(). Most are documented in its docstring.
- _CHEETAH_cacheModuleFilesForTracebacks = False
- _CHEETAH_cacheDirForModuleFiles = None # change to a dirname
-
- _CHEETAH_compileCache = dict() # cache store for compiled code and classes
- # To do something other than simple in-memory caching you can create an
- # alternative cache store. It just needs to support the basics of Python's
- # mapping/dict protocol. E.g.:
- # class AdvCachingTemplate(Template):
- # _CHEETAH_compileCache = MemoryOrFileCache()
- _CHEETAH_compileLock = Lock() # used to prevent race conditions
- _CHEETAH_defaultMainMethodName = None
- _CHEETAH_compilerSettings = None
- _CHEETAH_compilerClass = Compiler
- _CHEETAH_compilerInstance = None
- _CHEETAH_cacheCompilationResults = True
- _CHEETAH_useCompilationCache = True
- _CHEETAH_keepRefToGeneratedCode = True
- _CHEETAH_defaultBaseclassForTemplates = None
- _CHEETAH_defaultClassNameForTemplates = None
- # defaults to DEFAULT_COMPILER_SETTINGS['mainMethodName']:
- _CHEETAH_defaultMainMethodNameForTemplates = None
- _CHEETAH_defaultModuleNameForTemplates = 'DynamicallyCompiledCheetahTemplate'
- _CHEETAH_defaultModuleGlobalsForTemplates = None
- _CHEETAH_preprocessors = None
- _CHEETAH_defaultPreprocessorClass = TemplatePreprocessor
-
- ## The following attributes are used by instance methods:
- _CHEETAH_generatedModuleCode = None
- NonNumericInputError = NonNumericInputError
- _CHEETAH_cacheRegionClass = CacheRegion
- _CHEETAH_cacheStoreClass = MemoryCacheStore
- #_CHEETAH_cacheStoreClass = MemcachedCacheStore
- _CHEETAH_cacheStore = None
- _CHEETAH_cacheStoreIdPrefix = None
-
- @classmethod
- def _getCompilerClass(klass, source=None, file=None):
- return klass._CHEETAH_compilerClass
-
- @classmethod
- def _getCompilerSettings(klass, source=None, file=None):
- return klass._CHEETAH_compilerSettings
-
- @classmethod
- def compile(klass, source=None, file=None,
- returnAClass=True,
-
- compilerSettings=Unspecified,
- compilerClass=Unspecified,
- moduleName=None,
- className=Unspecified,
- mainMethodName=Unspecified,
- baseclass=Unspecified,
- moduleGlobals=Unspecified,
- cacheCompilationResults=Unspecified,
- useCache=Unspecified,
- preprocessors=Unspecified,
- cacheModuleFilesForTracebacks=Unspecified,
- cacheDirForModuleFiles=Unspecified,
- commandlineopts=None,
- keepRefToGeneratedCode=Unspecified,
- ):
-
- """
- The core API for compiling Cheetah source code into template classes.
-
- This class method compiles Cheetah source code and returns a python
- class. You then create template instances using that class. All
- Cheetah's other compilation API's use this method under the hood.
-
- Internally, this method a) parses the Cheetah source code and generates
- Python code defining a module with a single class in it, b) dynamically
- creates a module object with a unique name, c) execs the generated code
- in that module's namespace then inserts the module into sys.modules, and
- d) returns a reference to the generated class. If you want to get the
- generated python source code instead, pass the argument
- returnAClass=False.
-
- It caches generated code and classes. See the descriptions of the
- arguments'cacheCompilationResults' and 'useCache' for details. This
- doesn't mean that templates will automatically recompile themselves when
- the source file changes. Rather, if you call Template.compile(src) or
- Template.compile(file=path) repeatedly it will attempt to return a
- cached class definition instead of recompiling.
-
- Hooks are provided template source preprocessing. See the notes on the
- 'preprocessors' arg.
-
- If you are an advanced user and need to customize the way Cheetah parses
- source code or outputs Python code, you should check out the
- compilerSettings argument.
-
- Arguments:
- You must provide either a 'source' or 'file' arg, but not both:
- - source (string or None)
- - file (string path, file-like object, or None)
-
- The rest of the arguments are strictly optional. All but the first
- have defaults in attributes of the Template class which can be
- overridden in subclasses of this class. Working with most of these is
- an advanced topic.
-
- - returnAClass=True
- If false, return the generated module code rather than a class.
-
- - compilerSettings (a dict)
- Default: Template._CHEETAH_compilerSettings=None
-
- a dictionary of settings to override those defined in
- DEFAULT_COMPILER_SETTINGS. These can also be overridden in your
- template source code with the #compiler or #compiler-settings
- directives.
-
- - compilerClass (a class)
- Default: Template._CHEETAH_compilerClass=Cheetah.Compiler.Compiler
-
- a subclass of Cheetah.Compiler.Compiler. Mucking with this is a
- very advanced topic.
-
- - moduleName (a string)
- Default:
- Template._CHEETAH_defaultModuleNameForTemplates
- ='DynamicallyCompiledCheetahTemplate'
-
- What to name the generated Python module. If the provided value is
- None and a file arg was given, the moduleName is created from the
- file path. In all cases if the moduleName provided is already in
- sys.modules it is passed through a filter that generates a unique
- variant of the name.
-
-
- - className (a string)
- Default: Template._CHEETAH_defaultClassNameForTemplates=None
-
- What to name the generated Python class. If the provided value is
- None, the moduleName is use as the class name.
-
- - mainMethodName (a string)
- Default:
- Template._CHEETAH_defaultMainMethodNameForTemplates
- =None (and thus DEFAULT_COMPILER_SETTINGS['mainMethodName'])
-
- What to name the main output generating method in the compiled
- template class.
-
- - baseclass (a string or a class)
- Default: Template._CHEETAH_defaultBaseclassForTemplates=None
-
- Specifies the baseclass for the template without manually
- including an #extends directive in the source. The #extends
- directive trumps this arg.
-
- If the provided value is a string you must make sure that a class
- reference by that name is available to your template, either by
- using an #import directive or by providing it in the arg
- 'moduleGlobals'.
-
- If the provided value is a class, Cheetah will handle all the
- details for you.
-
- - moduleGlobals (a dict)
- Default: Template._CHEETAH_defaultModuleGlobalsForTemplates=None
-
- A dict of vars that will be added to the global namespace of the
- module the generated code is executed in, prior to the execution
- of that code. This should be Python values, not code strings!
-
- - cacheCompilationResults (True/False)
- Default: Template._CHEETAH_cacheCompilationResults=True
-
- Tells Cheetah to cache the generated code and classes so that they
- can be reused if Template.compile() is called multiple times with
- the same source and options.
-
- - useCache (True/False)
- Default: Template._CHEETAH_useCompilationCache=True
-
- Should the compilation cache be used? If True and a previous
- compilation created a cached template class with the same source
- code, compiler settings and other options, the cached template
- class will be returned.
-
- - cacheModuleFilesForTracebacks (True/False)
- Default: Template._CHEETAH_cacheModuleFilesForTracebacks=False
-
- In earlier versions of Cheetah tracebacks from exceptions that
- were raised inside dynamically compiled Cheetah templates were
- opaque because Python didn't have access to a python source file
- to use in the traceback:
-
- File "xxxx.py", line 192, in getTextiledContent
- content = str(template(searchList=searchList))
- File "cheetah_yyyy.py", line 202, in __str__
- File "cheetah_yyyy.py", line 187, in respond
- File "cheetah_yyyy.py", line 139, in writeBody
- ZeroDivisionError: integer division or modulo by zero
-
- It is now possible to keep those files in a cache dir and allow
- Python to include the actual source lines in tracebacks and makes
- them much easier to understand:
-
- File "xxxx.py", line 192, in getTextiledContent
- content = str(template(searchList=searchList))
- File "/tmp/CheetahCacheDir/cheetah_yyyy.py", line 202, in __str__
- def __str__(self): return self.respond()
- File "/tmp/CheetahCacheDir/cheetah_yyyy.py", line 187, in respond
- self.writeBody(trans=trans)
- File "/tmp/CheetahCacheDir/cheetah_yyyy.py", line 139, in writeBody
- __v = 0/0 # $(0/0)
- ZeroDivisionError: integer division or modulo by zero
-
- - cacheDirForModuleFiles (a string representing a dir path)
- Default: Template._CHEETAH_cacheDirForModuleFiles=None
-
- See notes on cacheModuleFilesForTracebacks.
-
- - preprocessors
- Default: Template._CHEETAH_preprocessors=None
-
- ** THIS IS A VERY ADVANCED TOPIC **
-
- These are used to transform the source code prior to compilation.
- They provide a way to use Cheetah as a code generator for Cheetah
- code. In other words, you use one Cheetah template to output the
- source code for another Cheetah template.
-
- The major expected use cases are:
-
- a) 'compile-time caching' aka 'partial template binding',
- wherein an intermediate Cheetah template is used to output
- the source for the final Cheetah template. The intermediate
- template is a mix of a modified Cheetah syntax (the
- 'preprocess syntax') and standard Cheetah syntax. The
- preprocessor syntax is executed at compile time and outputs
- Cheetah code which is then compiled in turn. This approach
- allows one to completely soft-code all the elements in the
- template which are subject to change yet have it compile to
- extremely efficient Python code with everything but the
- elements that must be variable at runtime (per browser
- request, etc.) compiled as static strings. Examples of this
- usage pattern will be added to the Cheetah Users' Guide.
-
- The'preprocess syntax' is just Cheetah's standard one with
- alternatives for the $ and # tokens:
-
- e.g. '@' and '%' for code like this
- @aPreprocessVar $aRuntimeVar
- %if aCompileTimeCondition then yyy else zzz
- %% preprocessor comment
-
- #if aRunTimeCondition then aaa else bbb
- ## normal comment
- $aRuntimeVar
-
- b) adding #import and #extends directives dynamically based on
- the source
-
- If preprocessors are provided, Cheetah pipes the source code
- through each one in the order provided. Each preprocessor should
- accept the args (source, file) and should return a tuple (source,
- file).
-
- The argument value should be a list, but a single non-list value
- is acceptable and will automatically be converted into a list.
- Each item in the list will be passed through
- Template._normalizePreprocessor(). The items should either match
- one of the following forms:
-
- - an object with a .preprocess(source, file) method
- - a callable with the following signature:
- source, file = f(source, file)
-
- or one of the forms below:
-
- - a single string denoting the 2 'tokens' for the preprocess
- syntax. The tokens should be in the order (placeholderToken,
- directiveToken) and should separated with a space:
- e.g. '@ %'
- klass = Template.compile(src, preprocessors='@ %')
- # or
- klass = Template.compile(src, preprocessors=['@ %'])
-
- - a dict with the following keys or an object with the
- following attributes (all are optional, but nothing will
- happen if you don't provide at least one):
- - tokens: same as the single string described above. You can
- also provide a tuple of 2 strings.
- - searchList: the searchList used for preprocess $placeholders
- - compilerSettings: used in the compilation of the intermediate
- template
- - templateAPIClass: an optional subclass of `Template`
- - outputTransformer: a simple hook for passing in a callable
- which can do further transformations of the preprocessor
- output, or do something else like debug logging. The
- default is str().
- + any keyword arguments to Template.compile which you want to
- provide for the compilation of the intermediate template.
-
- klass = Template.compile(src,
- preprocessors=[ dict(tokens='@ %', searchList=[...]) ] )
-
- """
- errmsg = "arg '%s' must be %s"
-
- if not isinstance(source, (types.NoneType, basestring)):
- raise TypeError(errmsg % ('source', 'string or None'))
-
- if not isinstance(file, (types.NoneType, basestring, filetype)):
- raise TypeError(errmsg %
- ('file', 'string, file-like object, or None'))
-
- if baseclass is Unspecified:
- baseclass = klass._CHEETAH_defaultBaseclassForTemplates
- if isinstance(baseclass, Template):
- baseclass = baseclass.__class__
-
- if not isinstance(baseclass, (types.NoneType, basestring, type)):
- raise TypeError(errmsg % ('baseclass', 'string, class or None'))
-
- if cacheCompilationResults is Unspecified:
- cacheCompilationResults = klass._CHEETAH_cacheCompilationResults
-
- if not isinstance(cacheCompilationResults, (int, bool)):
- raise TypeError(errmsg % ('cacheCompilationResults', 'boolean'))
-
- if useCache is Unspecified:
- useCache = klass._CHEETAH_useCompilationCache
-
- if not isinstance(useCache, (int, bool)):
- raise TypeError(errmsg % ('useCache', 'boolean'))
-
- if compilerSettings is Unspecified:
- compilerSettings = klass._getCompilerSettings(source, file) or {}
- if not isinstance(compilerSettings, dict):
- raise TypeError(errmsg % ('compilerSettings', 'dictionary'))
-
- if compilerClass is Unspecified:
- compilerClass = klass._getCompilerClass(source, file)
- if preprocessors is Unspecified:
- preprocessors = klass._CHEETAH_preprocessors
-
- if keepRefToGeneratedCode is Unspecified:
- keepRefToGeneratedCode = klass._CHEETAH_keepRefToGeneratedCode
-
- if not isinstance(keepRefToGeneratedCode, (int, bool)):
- raise TypeError(errmsg % ('keepReftoGeneratedCode', 'boolean'))
-
- if not isinstance(moduleName, (types.NoneType, basestring)):
- raise TypeError(errmsg % ('moduleName', 'string or None'))
- __orig_file__ = None
- if not moduleName:
- if file and isinstance(file, basestring):
- moduleName = convertTmplPathToModuleName(file)
- __orig_file__ = file
- else:
- moduleName = klass._CHEETAH_defaultModuleNameForTemplates
-
- if className is Unspecified:
- className = klass._CHEETAH_defaultClassNameForTemplates
-
- if not isinstance(className, (types.NoneType, basestring)):
- raise TypeError(errmsg % ('className', 'string or None'))
- className = re.sub(r'^_+','', className or moduleName)
-
- if mainMethodName is Unspecified:
- mainMethodName = klass._CHEETAH_defaultMainMethodNameForTemplates
-
- if not isinstance(mainMethodName, (types.NoneType, basestring)):
- raise TypeError(errmsg % ('mainMethodName', 'string or None'))
-
- if moduleGlobals is Unspecified:
- moduleGlobals = klass._CHEETAH_defaultModuleGlobalsForTemplates
-
- if cacheModuleFilesForTracebacks is Unspecified:
- cacheModuleFilesForTracebacks = klass._CHEETAH_cacheModuleFilesForTracebacks
-
- if not isinstance(cacheModuleFilesForTracebacks, (int, bool)):
- raise TypeError(errmsg %
- ('cacheModuleFilesForTracebacks', 'boolean'))
-
- if cacheDirForModuleFiles is Unspecified:
- cacheDirForModuleFiles = klass._CHEETAH_cacheDirForModuleFiles
-
- if not isinstance(cacheDirForModuleFiles, (types.NoneType, basestring)):
- raise TypeError(errmsg %
- ('cacheDirForModuleFiles', 'string or None'))
-
- ##################################################
- ## handle any preprocessors
- if preprocessors:
- origSrc = source
- source, file = klass._preprocessSource(source, file, preprocessors)
-
- ##################################################
- ## compilation, using cache if requested/possible
- baseclassValue = None
- baseclassName = None
- if baseclass:
- if isinstance(baseclass, basestring):
- baseclassName = baseclass
- elif isinstance(baseclass, type):
- # @@TR: should soft-code this
- baseclassName = 'CHEETAH_dynamicallyAssignedBaseClass_'+baseclass.__name__
- baseclassValue = baseclass
-
-
- cacheHash = None
- cacheItem = None
- if source or isinstance(file, basestring):
- compilerSettingsHash = None
- if compilerSettings:
- compilerSettingsHash = hashDict(compilerSettings)
-
- moduleGlobalsHash = None
- if moduleGlobals:
- moduleGlobalsHash = hashDict(moduleGlobals)
-
- fileHash = None
- if file:
- fileHash = str(hash(file))
- if globals()['__checkFileMtime']:
- fileHash += str(os.path.getmtime(file))
-
- try:
- # @@TR: find some way to create a cacheHash that is consistent
- # between process restarts. It would allow for caching the
- # compiled module on disk and thereby reduce the startup time
- # for applications that use a lot of dynamically compiled
- # templates.
- cacheHash = ''.join([str(v) for v in
- [hash(source),
- fileHash,
- className,
- moduleName,
- mainMethodName,
- hash(compilerClass),
- hash(baseclass),
- compilerSettingsHash,
- moduleGlobalsHash,
- hash(cacheDirForModuleFiles),
- ]])
- except:
- #@@TR: should add some logging to this
- pass
- outputEncoding = 'ascii'
- compiler = None
- if useCache and cacheHash and cacheHash in klass._CHEETAH_compileCache:
- cacheItem = klass._CHEETAH_compileCache[cacheHash]
- generatedModuleCode = cacheItem.code
- else:
- compiler = compilerClass(source, file,
- moduleName=moduleName,
- mainClassName=className,
- baseclassName=baseclassName,
- mainMethodName=mainMethodName,
- settings=(compilerSettings or {}))
- if commandlineopts:
- compiler.setShBang(commandlineopts.shbang)
- compiler.compile()
- generatedModuleCode = compiler.getModuleCode()
- outputEncoding = compiler.getModuleEncoding()
-
- if not returnAClass:
- # This is a bit of a hackish solution to make sure we're setting the proper
- # encoding on generated code that is destined to be written to a file
- if not outputEncoding == 'ascii':
- generatedModuleCode = generatedModuleCode.split('\n')
- generatedModuleCode.insert(1, '# -*- coding: %s -*-' % outputEncoding)
- generatedModuleCode = '\n'.join(generatedModuleCode)
- return generatedModuleCode.encode(outputEncoding)
- else:
- if cacheItem:
- cacheItem.lastCheckoutTime = time.time()
- return cacheItem.klass
-
- try:
- klass._CHEETAH_compileLock.acquire()
- uniqueModuleName = _genUniqueModuleName(moduleName)
- __file__ = uniqueModuleName+'.py' # relative file path with no dir part
-
- if cacheModuleFilesForTracebacks:
- if not os.path.exists(cacheDirForModuleFiles):
- raise Exception('%s does not exist'%cacheDirForModuleFiles)
-
- __file__ = os.path.join(cacheDirForModuleFiles, __file__)
- # @@TR: might want to assert that it doesn't already exist
- open(__file__, 'w').write(generatedModuleCode)
- # @@TR: should probably restrict the perms, etc.
-
- mod = types.ModuleType(str(uniqueModuleName))
- if moduleGlobals:
- for k, v in moduleGlobals.items():
- setattr(mod, k, v)
- mod.__file__ = __file__
- if __orig_file__ and os.path.exists(__orig_file__):
- # this is used in the WebKit filemonitoring code
- mod.__orig_file__ = __orig_file__
-
- if baseclass and baseclassValue:
- setattr(mod, baseclassName, baseclassValue)
- ##
- try:
- co = compile(generatedModuleCode, __file__, 'exec')
- exec(co, mod.__dict__)
- except SyntaxError, e:
- try:
- parseError = genParserErrorFromPythonException(
- source, file, generatedModuleCode, exception=e)
- except:
- updateLinecache(__file__, generatedModuleCode)
- e.generatedModuleCode = generatedModuleCode
- raise e
- else:
- raise parseError
- except Exception, e:
- updateLinecache(__file__, generatedModuleCode)
- e.generatedModuleCode = generatedModuleCode
- raise
- ##
- sys.modules[uniqueModuleName] = mod
- finally:
- klass._CHEETAH_compileLock.release()
-
- templateClass = getattr(mod, className)
-
- if (cacheCompilationResults
- and cacheHash
- and cacheHash not in klass._CHEETAH_compileCache):
-
- cacheItem = CompileCacheItem()
- cacheItem.cacheTime = cacheItem.lastCheckoutTime = time.time()
- cacheItem.code = generatedModuleCode
- cacheItem.klass = templateClass
- templateClass._CHEETAH_isInCompilationCache = True
- klass._CHEETAH_compileCache[cacheHash] = cacheItem
- else:
- templateClass._CHEETAH_isInCompilationCache = False
-
- if keepRefToGeneratedCode or cacheCompilationResults:
- templateClass._CHEETAH_generatedModuleCode = generatedModuleCode
-
- # If we have a compiler object, let's set it to the compiler class
- # to help the directive analyzer code
- if compiler:
- templateClass._CHEETAH_compilerInstance = compiler
- return templateClass
-
- @classmethod
- def subclass(klass, *args, **kws):
- """Takes the same args as the .compile() classmethod and returns a
- template that is a subclass of the template this method is called from.
-
- T1 = Template.compile(' foo - $meth1 - bar\n#def meth1: this is T1.meth1')
- T2 = T1.subclass('#implements meth1\n this is T2.meth1')
- """
- kws['baseclass'] = klass
- if isinstance(klass, Template):
- templateAPIClass = klass
- else:
- templateAPIClass = Template
- return templateAPIClass.compile(*args, **kws)
-
- @classmethod
- def _preprocessSource(klass, source, file, preprocessors):
- """Iterates through the .compile() classmethod's preprocessors argument
- and pipes the source code through each each preprocessor.
-
- It returns the tuple (source, file) which is then used by
- Template.compile to finish the compilation.
- """
- if not isinstance(preprocessors, (list, tuple)):
- preprocessors = [preprocessors]
- for preprocessor in preprocessors:
- preprocessor = klass._normalizePreprocessorArg(preprocessor)
- source, file = preprocessor.preprocess(source, file)
- return source, file
-
- @classmethod
- def _normalizePreprocessorArg(klass, arg):
- """Used to convert the items in the .compile() classmethod's
- preprocessors argument into real source preprocessors. This permits the
- use of several shortcut forms for defining preprocessors.
- """
-
- if hasattr(arg, 'preprocess'):
- return arg
- elif hasattr(arg, '__call__'):
- class WrapperPreprocessor:
- def preprocess(self, source, file):
- return arg(source, file)
- return WrapperPreprocessor()
- else:
- class Settings(object):
- placeholderToken = None
- directiveToken = None
- settings = Settings()
- if isinstance(arg, str) or isinstance(arg, (list, tuple)):
- settings.tokens = arg
- elif isinstance(arg, dict):
- for k, v in arg.items():
- setattr(settings, k, v)
- else:
- settings = arg
-
- settings = klass._normalizePreprocessorSettings(settings)
- return klass._CHEETAH_defaultPreprocessorClass(settings)
-
-
- @classmethod
- def _normalizePreprocessorSettings(klass, settings):
- settings.keepRefToGeneratedCode = True
-
- def normalizeSearchList(searchList):
- if not isinstance(searchList, (list, tuple)):
- searchList = [searchList]
- return searchList
-
- def normalizeTokens(tokens):
- if isinstance(tokens, str):
- return tokens.split() # space delimited string e.g.'@ %'
- elif isinstance(tokens, (list, tuple)):
- return tokens
- else:
- raise PreprocessError('invalid tokens argument: %r'%tokens)
-
- if hasattr(settings, 'tokens'):
- (settings.placeholderToken,
- settings.directiveToken) = normalizeTokens(settings.tokens)
-
- if (not getattr(settings, 'compilerSettings', None)
- and not getattr(settings, 'placeholderToken', None) ):
-
- raise TypeError(
- 'Preprocessor requires either a "tokens" or a "compilerSettings" arg.'
- ' Neither was provided.')
-
- if not hasattr(settings, 'templateInitArgs'):
- settings.templateInitArgs = {}
- if 'searchList' not in settings.templateInitArgs:
- if not hasattr(settings, 'searchList') and hasattr(settings, 'namespaces'):
- settings.searchList = settings.namespaces
- elif not hasattr(settings, 'searchList'):
- settings.searchList = []
- settings.templateInitArgs['searchList'] = settings.searchList
- settings.templateInitArgs['searchList'] = (
- normalizeSearchList(settings.templateInitArgs['searchList']))
-
- if not hasattr(settings, 'outputTransformer'):
- settings.outputTransformer = unicode
-
- if not hasattr(settings, 'templateAPIClass'):
- class PreprocessTemplateAPIClass(klass): pass
- settings.templateAPIClass = PreprocessTemplateAPIClass
-
- if not hasattr(settings, 'compilerSettings'):
- settings.compilerSettings = {}
-
- klass._updateSettingsWithPreprocessTokens(
- compilerSettings=settings.compilerSettings,
- placeholderToken=settings.placeholderToken,
- directiveToken=settings.directiveToken
- )
- return settings
-
- @classmethod
- def _updateSettingsWithPreprocessTokens(
- klass, compilerSettings, placeholderToken, directiveToken):
-
- if (placeholderToken and 'cheetahVarStartToken' not in compilerSettings):
- compilerSettings['cheetahVarStartToken'] = placeholderToken
- if directiveToken:
- if 'directiveStartToken' not in compilerSettings:
- compilerSettings['directiveStartToken'] = directiveToken
- if 'directiveEndToken' not in compilerSettings:
- compilerSettings['directiveEndToken'] = directiveToken
- if 'commentStartToken' not in compilerSettings:
- compilerSettings['commentStartToken'] = directiveToken*2
- if 'multiLineCommentStartToken' not in compilerSettings:
- compilerSettings['multiLineCommentStartToken'] = (
- directiveToken+'*')
- if 'multiLineCommentEndToken' not in compilerSettings:
- compilerSettings['multiLineCommentEndToken'] = (
- '*'+directiveToken)
- if 'EOLSlurpToken' not in compilerSettings:
- compilerSettings['EOLSlurpToken'] = directiveToken
-
- @classmethod
- def _addCheetahPlumbingCodeToClass(klass, concreteTemplateClass):
- """If concreteTemplateClass is not a subclass of Cheetah.Template, add
- the required cheetah methods and attributes to it.
-
- This is called on each new template class after it has been compiled.
- If concreteTemplateClass is not a subclass of Cheetah.Template but
- already has method with the same name as one of the required cheetah
- methods, this will skip that method.
- """
- for methodname in klass._CHEETAH_requiredCheetahMethods:
- if not hasattr(concreteTemplateClass, methodname):
- method = getattr(Template, methodname)
- newMethod = createMethod(method.im_func, concreteTemplateClass)
- setattr(concreteTemplateClass, methodname, newMethod)
-
- for classMethName in klass._CHEETAH_requiredCheetahClassMethods:
- if not hasattr(concreteTemplateClass, classMethName):
- meth = getattr(klass, classMethName)
- setattr(concreteTemplateClass, classMethName, classmethod(meth.im_func))
-
- for attrname in klass._CHEETAH_requiredCheetahClassAttributes:
- attrname = '_CHEETAH_'+attrname
- if not hasattr(concreteTemplateClass, attrname):
- attrVal = getattr(klass, attrname)
- setattr(concreteTemplateClass, attrname, attrVal)
-
- if (not hasattr(concreteTemplateClass, '__str__')
- or concreteTemplateClass.__str__ is object.__str__):
-
- mainMethNameAttr = '_mainCheetahMethod_for_'+concreteTemplateClass.__name__
- mainMethName = getattr(concreteTemplateClass, mainMethNameAttr, None)
- if mainMethName:
- def __str__(self):
- rc = getattr(self, mainMethName)()
- if isinstance(rc, unicode):
- return rc.encode('utf-8')
- return rc
- def __unicode__(self):
- return getattr(self, mainMethName)()
- elif (hasattr(concreteTemplateClass, 'respond')
- and concreteTemplateClass.respond!=Servlet.respond):
- def __str__(self):
- rc = self.respond()
- if isinstance(rc, unicode):
- return rc.encode('utf-8')
- return rc
- def __unicode__(self):
- return self.respond()
- else:
- def __str__(self):
- rc = None
- if hasattr(self, mainMethNameAttr):
- rc = getattr(self, mainMethNameAttr)()
- elif hasattr(self, 'respond'):
- rc = self.respond()
- else:
- rc = super(self.__class__, self).__str__()
- if isinstance(rc, unicode):
- return rc.encode('utf-8')
- return rc
- def __unicode__(self):
- if hasattr(self, mainMethNameAttr):
- return getattr(self, mainMethNameAttr)()
- elif hasattr(self, 'respond'):
- return self.respond()
- else:
- return super(self.__class__, self).__unicode__()
-
- __str__ = createMethod(__str__, concreteTemplateClass)
- __unicode__ = createMethod(__unicode__, concreteTemplateClass)
- setattr(concreteTemplateClass, '__str__', __str__)
- setattr(concreteTemplateClass, '__unicode__', __unicode__)
-
-
- def __init__(self, source=None,
-
- namespaces=None, searchList=None,
- # use either or. They are aliases for the same thing.
-
- file=None,
- filter='RawOrEncodedUnicode', # which filter from Cheetah.Filters
- filtersLib=Filters,
- errorCatcher=None,
-
- compilerSettings=Unspecified, # control the behaviour of the compiler
- _globalSetVars=None, # used internally for #include'd templates
- _preBuiltSearchList=None # used internally for #include'd templates
- ):
- """a) compiles a new template OR b) instantiates an existing template.
-
- Read this docstring carefully as there are two distinct usage patterns.
- You should also read this class' main docstring.
-
- a) to compile a new template:
- t = Template(source=aSourceString)
- # or
- t = Template(file='some/path')
- # or
- t = Template(file=someFileObject)
- # or
- namespaces = [{'foo':'bar'}]
- t = Template(source=aSourceString, namespaces=namespaces)
- # or
- t = Template(file='some/path', namespaces=namespaces)
-
- print t
-
- b) to create an instance of an existing, precompiled template class:
- ## i) first you need a reference to a compiled template class:
- tclass = Template.compile(source=src) # or just Template.compile(src)
- # or
- tclass = Template.compile(file='some/path')
- # or
- tclass = Template.compile(file=someFileObject)
- # or
- # if you used the command line compiler or have Cheetah's ImportHooks
- # installed your template class is also available via Python's
- # standard import mechanism:
- from ACompileTemplate import AcompiledTemplate as tclass
-
- ## ii) then you create an instance
- t = tclass(namespaces=namespaces)
- # or
- t = tclass(namespaces=namespaces, filter='RawOrEncodedUnicode')
- print t
-
- Arguments:
- for usage pattern a)
- If you are compiling a new template, you must provide either a
- 'source' or 'file' arg, but not both:
- - source (string or None)
- - file (string path, file-like object, or None)
-
- Optional args (see below for more) :
- - compilerSettings
- Default: Template._CHEETAH_compilerSettings=None
-
- a dictionary of settings to override those defined in
- DEFAULT_COMPILER_SETTINGS. See
- Cheetah.Template.DEFAULT_COMPILER_SETTINGS and the Users' Guide
- for details.
-
- You can pass the source arg in as a positional arg with this usage
- pattern. Use keywords for all other args.
-
- for usage pattern b)
- Do not use positional args with this usage pattern, unless your
- template subclasses something other than Cheetah.Template and you
- want to pass positional args to that baseclass. E.g.:
- dictTemplate = Template.compile('hello $name from $caller', baseclass=dict)
- tmplvars = dict(name='world', caller='me')
- print dictTemplate(tmplvars)
- This usage requires all Cheetah args to be passed in as keyword args.
-
- optional args for both usage patterns:
-
- - namespaces (aka 'searchList')
- Default: None
-
- an optional list of namespaces (dictionaries, objects, modules,
- etc.) which Cheetah will search through to find the variables
- referenced in $placeholders.
-
- If you provide a single namespace instead of a list, Cheetah will
- automatically convert it into a list.
-
- NOTE: Cheetah does NOT force you to use the namespaces search list
- and related features. It's on by default, but you can turn if off
- using the compiler settings useSearchList=False or
- useNameMapper=False.
-
- - filter
- Default: 'EncodeUnicode'
-
- Which filter should be used for output filtering. This should
- either be a string which is the name of a filter in the
- 'filtersLib' or a subclass of Cheetah.Filters.Filter. . See the
- Users' Guide for more details.
-
- - filtersLib
- Default: Cheetah.Filters
-
- A module containing subclasses of Cheetah.Filters.Filter. See the
- Users' Guide for more details.
-
- - errorCatcher
- Default: None
-
- This is a debugging tool. See the Users' Guide for more details.
- Do not use this or the #errorCatcher diretive with live
- production systems.
-
- Do NOT mess with the args _globalSetVars or _preBuiltSearchList!
-
-
- """
- errmsg = "arg '%s' must be %s"
- errmsgextra = errmsg + "\n%s"
-
- if not isinstance(source, (types.NoneType, basestring)):
- raise TypeError(errmsg % ('source', 'string or None'))
-
- if not isinstance(source, (types.NoneType, basestring, filetype)):
- raise TypeError(errmsg %
- ('file', 'string, file open for reading, or None'))
-
- if not isinstance(filter, (basestring, types.TypeType)) and not \
- (isinstance(filter, type) and issubclass(filter, Filters.Filter)):
- raise TypeError(errmsgextra %
- ('filter', 'string or class',
- '(if class, must be subclass of Cheetah.Filters.Filter)'))
- if not isinstance(filtersLib, (basestring, types.ModuleType)):
- raise TypeError(errmsgextra %
- ('filtersLib', 'string or module',
- '(if module, must contain subclasses of Cheetah.Filters.Filter)'))
-
- if not errorCatcher is None:
- err = True
- if isinstance(errorCatcher, (basestring, types.TypeType)):
- err = False
- if isinstance(errorCatcher, type) and \
- issubclass(errorCatcher, ErrorCatchers.ErrorCatcher):
- err = False
- if err:
- raise TypeError(errmsgextra %
- ('errorCatcher', 'string, class or None',
- '(if class, must be subclass of Cheetah.ErrorCatchers.ErrorCatcher)'))
- if compilerSettings is not Unspecified:
- if not isinstance(compilerSettings, types.DictType):
- raise TypeError(errmsg %
- ('compilerSettings', 'dictionary'))
-
- if source is not None and file is not None:
- raise TypeError("you must supply either a source string or the" +
- " 'file' keyword argument, but not both")
-
- ##################################################
- ## Do superclass initialization.
- super(Template, self).__init__()
-
- ##################################################
- ## Do required version check
- if not hasattr(self, '_CHEETAH_versionTuple'):
- try:
- mod = sys.modules[self.__class__.__module__]
- compiledVersion = mod.__CHEETAH_version__
- compiledVersionTuple = convertVersionStringToTuple(compiledVersion)
- if compiledVersionTuple < MinCompatibleVersionTuple:
- raise AssertionError(
- 'This template was compiled with Cheetah version'
- ' %s. Templates compiled before version %s must be recompiled.'%(
- compiledVersion, MinCompatibleVersion))
- except AssertionError:
- raise
- except:
- pass
-
- ##################################################
- ## Setup instance state attributes used during the life of template
- ## post-compile
- if searchList:
- for namespace in searchList:
- if isinstance(namespace, dict):
- intersection = self.Reserved_SearchList & set(namespace.keys())
- warn = False
- if intersection:
- warn = True
- if isinstance(compilerSettings, dict) and compilerSettings.get('prioritizeSearchListOverSelf'):
- warn = False
- if warn:
- logging.info(''' The following keys are members of the Template class and will result in NameMapper collisions! ''')
- logging.info(''' > %s ''' % ', '.join(list(intersection)))
- logging.info(''' Please change the key's name or use the compiler setting "prioritizeSearchListOverSelf=True" to prevent the NameMapper from using ''')
- logging.info(''' the Template member in place of your searchList variable ''')
-
-
- self._initCheetahInstance(
- searchList=searchList, namespaces=namespaces,
- filter=filter, filtersLib=filtersLib,
- errorCatcher=errorCatcher,
- _globalSetVars=_globalSetVars,
- compilerSettings=compilerSettings,
- _preBuiltSearchList=_preBuiltSearchList)
-
- ##################################################
- ## Now, compile if we're meant to
- if (source is not None) or (file is not None):
- self._compile(source, file, compilerSettings=compilerSettings)
-
- def generatedModuleCode(self):
- """Return the module code the compiler generated, or None if no
- compilation took place.
- """
-
- return self._CHEETAH_generatedModuleCode
-
- def generatedClassCode(self):
- """Return the class code the compiler generated, or None if no
- compilation took place.
- """
-
- return self._CHEETAH_generatedModuleCode[
- self._CHEETAH_generatedModuleCode.find('\nclass '):
- self._CHEETAH_generatedModuleCode.find('\n## END CLASS DEFINITION')]
-
- def searchList(self):
- """Return a reference to the searchlist
- """
- return self._CHEETAH__searchList
-
- def errorCatcher(self):
- """Return a reference to the current errorCatcher
- """
- return self._CHEETAH__errorCatcher
-
- ## cache methods ##
- def _getCacheStore(self):
- if not self._CHEETAH__cacheStore:
- if self._CHEETAH_cacheStore is not None:
- self._CHEETAH__cacheStore = self._CHEETAH_cacheStore
- else:
- # @@TR: might want to provide a way to provide init args
- self._CHEETAH__cacheStore = self._CHEETAH_cacheStoreClass()
-
- return self._CHEETAH__cacheStore
-
- def _getCacheStoreIdPrefix(self):
- if self._CHEETAH_cacheStoreIdPrefix is not None:
- return self._CHEETAH_cacheStoreIdPrefix
- else:
- return str(id(self))
-
- def _createCacheRegion(self, regionID):
- return self._CHEETAH_cacheRegionClass(
- regionID=regionID,
- templateCacheIdPrefix=self._getCacheStoreIdPrefix(),
- cacheStore=self._getCacheStore())
-
- def getCacheRegion(self, regionID, cacheInfo=None, create=True):
- cacheRegion = self._CHEETAH__cacheRegions.get(regionID)
- if not cacheRegion and create:
- cacheRegion = self._createCacheRegion(regionID)
- self._CHEETAH__cacheRegions[regionID] = cacheRegion
- return cacheRegion
-
- def getCacheRegions(self):
- """Returns a dictionary of the 'cache regions' initialized in a
- template.
-
- Each #cache directive block or $*cachedPlaceholder is a separate 'cache
- region'.
- """
- # returns a copy to prevent users mucking it up
- return self._CHEETAH__cacheRegions.copy()
-
- def refreshCache(self, cacheRegionId=None, cacheItemId=None):
- """Refresh a cache region or a specific cache item within a region.
- """
-
- if not cacheRegionId:
- for cacheRegion in self.getCacheRegions().itervalues():
- cacheRegion.clear()
- else:
- cregion = self._CHEETAH__cacheRegions.get(cacheRegionId)
- if not cregion:
- return
- if not cacheItemId: # clear the desired region and all its cacheItems
- cregion.clear()
- else: # clear one specific cache of a specific region
- cache = cregion.getCacheItem(cacheItemId)
- if cache:
- cache.clear()
-
- ## end cache methods ##
-
- def shutdown(self):
- """Break reference cycles before discarding a servlet.
- """
- try:
- Servlet.shutdown(self)
- except:
- pass
- self._CHEETAH__searchList = None
- self.__dict__ = {}
-
- ## utility functions ##
-
- def getVar(self, varName, default=Unspecified, autoCall=True):
- """Get a variable from the searchList. If the variable can't be found
- in the searchList, it returns the default value if one was given, or
- raises NameMapper.NotFound.
- """
-
- try:
- return valueFromSearchList(self.searchList(), varName.replace('$', ''), autoCall)
- except NotFound:
- if default is not Unspecified:
- return default
- else:
- raise
-
- def varExists(self, varName, autoCall=True):
- """Test if a variable name exists in the searchList.
- """
- try:
- valueFromSearchList(self.searchList(), varName.replace('$', ''), autoCall)
- return True
- except NotFound:
- return False
-
-
- hasVar = varExists
-
-
- def i18n(self, message,
- plural=None,
- n=None,
-
- id=None,
- domain=None,
- source=None,
- target=None,
- comment=None
- ):
- """This is just a stub at this time.
-
- plural = the plural form of the message
- n = a sized argument to distinguish between single and plural forms
-
- id = msgid in the translation catalog
- domain = translation domain
- source = source lang
- target = a specific target lang
- comment = a comment to the translation team
-
- See the following for some ideas
- http://www.zope.org/DevHome/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport
-
- Other notes:
- - There is no need to replicate the i18n:name attribute from plone / PTL,
- as cheetah placeholders serve the same purpose
-
-
- """
-
- return message
-
- def getFileContents(self, path):
- """A hook for getting the contents of a file. The default
- implementation just uses the Python open() function to load local files.
- This method could be reimplemented to allow reading of remote files via
- various protocols, as PHP allows with its 'URL fopen wrapper'
- """
-
- fp = open(path, 'r')
- output = fp.read()
- fp.close()
- return output
-
- def runAsMainProgram(self):
- """Allows the Template to function as a standalone command-line program
- for static page generation.
-
- Type 'python yourtemplate.py --help to see what it's capabable of.
- """
-
- from TemplateCmdLineIface import CmdLineIface
- CmdLineIface(templateObj=self).run()
-
- ##################################################
- ## internal methods -- not to be called by end-users
-
- def _initCheetahInstance(self,
- searchList=None,
- namespaces=None,
- filter='RawOrEncodedUnicode', # which filter from Cheetah.Filters
- filtersLib=Filters,
- errorCatcher=None,
- _globalSetVars=None,
- compilerSettings=None,
- _preBuiltSearchList=None):
- """Sets up the instance attributes that cheetah templates use at
- run-time.
-
- This is automatically called by the __init__ method of compiled
- templates.
-
- Note that the names of instance attributes used by Cheetah are prefixed
- with '_CHEETAH__' (2 underscores), where class attributes are prefixed
- with '_CHEETAH_' (1 underscore).
- """
- if getattr(self, '_CHEETAH__instanceInitialized', False):
- return
-
- if namespaces is not None:
- assert searchList is None, (
- 'Provide "namespaces" or "searchList", not both!')
- searchList = namespaces
- if searchList is not None and not isinstance(searchList, (list, tuple)):
- searchList = [searchList]
-
- self._CHEETAH__globalSetVars = {}
- if _globalSetVars is not None:
- # this is intended to be used internally by Nested Templates in #include's
- self._CHEETAH__globalSetVars = _globalSetVars
-
- if _preBuiltSearchList is not None:
- # happens with nested Template obj creation from #include's
- self._CHEETAH__searchList = list(_preBuiltSearchList)
- self._CHEETAH__searchList.append(self)
- else:
- # create our own searchList
- self._CHEETAH__searchList = [self._CHEETAH__globalSetVars, self]
- if searchList is not None:
- if isinstance(compilerSettings, dict) and compilerSettings.get('prioritizeSearchListOverSelf'):
- self._CHEETAH__searchList = searchList + self._CHEETAH__searchList
- else:
- self._CHEETAH__searchList.extend(list(searchList))
- self._CHEETAH__cheetahIncludes = {}
- self._CHEETAH__cacheRegions = {}
- self._CHEETAH__indenter = Indenter()
-
- # @@TR: consider allowing simple callables as the filter argument
- self._CHEETAH__filtersLib = filtersLib
- self._CHEETAH__filters = {}
- if isinstance(filter, basestring):
- filterName = filter
- klass = getattr(self._CHEETAH__filtersLib, filterName)
- else:
- klass = filter
- filterName = klass.__name__
- self._CHEETAH__currentFilter = self._CHEETAH__filters[filterName] = klass(self).filter
- self._CHEETAH__initialFilter = self._CHEETAH__currentFilter
-
- self._CHEETAH__errorCatchers = {}
- if errorCatcher:
- if isinstance(errorCatcher, basestring):
- errorCatcherClass = getattr(ErrorCatchers, errorCatcher)
- elif isinstance(errorCatcher, type):
- errorCatcherClass = errorCatcher
-
- self._CHEETAH__errorCatcher = ec = errorCatcherClass(self)
- self._CHEETAH__errorCatchers[errorCatcher.__class__.__name__] = ec
-
- else:
- self._CHEETAH__errorCatcher = None
- self._CHEETAH__initErrorCatcher = self._CHEETAH__errorCatcher
-
- if not hasattr(self, 'transaction'):
- self.transaction = None
- self._CHEETAH__instanceInitialized = True
- self._CHEETAH__isBuffering = False
- self._CHEETAH__isControlledByWebKit = False
-
- self._CHEETAH__cacheStore = None
- if self._CHEETAH_cacheStore is not None:
- self._CHEETAH__cacheStore = self._CHEETAH_cacheStore
-
- def _compile(self, source=None, file=None, compilerSettings=Unspecified,
- moduleName=None, mainMethodName=None):
- """Compile the template. This method is automatically called by
- Template.__init__ it is provided with 'file' or 'source' args.
-
- USERS SHOULD *NEVER* CALL THIS METHOD THEMSELVES. Use Template.compile
- instead.
- """
- if compilerSettings is Unspecified:
- compilerSettings = self._getCompilerSettings(source, file) or {}
- mainMethodName = mainMethodName or self._CHEETAH_defaultMainMethodName
- self._fileMtime = None
- self._fileDirName = None
- self._fileBaseName = None
- if file and isinstance(file, basestring):
- file = self.serverSidePath(file)
- self._fileMtime = os.path.getmtime(file)
- self._fileDirName, self._fileBaseName = os.path.split(file)
- self._filePath = file
- templateClass = self.compile(source, file,
- moduleName=moduleName,
- mainMethodName=mainMethodName,
- compilerSettings=compilerSettings,
- keepRefToGeneratedCode=True)
-
- if not self.__class__ == Template:
- # Only propogate attributes if we're in a subclass of
- # Template
- for k, v in self.__class__.__dict__.iteritems():
- if not v or k.startswith('__'):
- continue
- ## Propogate the class attributes to the instance
- ## since we're about to obliterate self.__class__
- ## (see: cheetah.Tests.Tepmlate.SubclassSearchListTest)
- setattr(self, k, v)
-
- self.__class__ = templateClass
- # must initialize it so instance attributes are accessible
- templateClass.__init__(self,
- #_globalSetVars=self._CHEETAH__globalSetVars,
- #_preBuiltSearchList=self._CHEETAH__searchList
- )
- if not hasattr(self, 'transaction'):
- self.transaction = None
-
- def _handleCheetahInclude(self, srcArg, trans=None, includeFrom='file', raw=False):
- """Called at runtime to handle #include directives.
- """
- _includeID = srcArg
- if _includeID not in self._CHEETAH__cheetahIncludes:
- if not raw:
- if includeFrom == 'file':
- source = None
- if isinstance(srcArg, basestring):
- if hasattr(self, 'serverSidePath'):
- file = path = self.serverSidePath(srcArg)
- else:
- file = path = os.path.normpath(srcArg)
- else:
- file = srcArg ## a file-like object
- else:
- source = srcArg
- file = None
- # @@TR: might want to provide some syntax for specifying the
- # Template class to be used for compilation so compilerSettings
- # can be changed.
- compiler = self._getTemplateAPIClassForIncludeDirectiveCompilation(source, file)
- nestedTemplateClass = compiler.compile(source=source, file=file)
- nestedTemplate = nestedTemplateClass(_preBuiltSearchList=self.searchList(),
- _globalSetVars=self._CHEETAH__globalSetVars)
- # Set the inner template filters to the initial filter of the
- # outer template:
- # this is the only really safe way to use
- # filter='WebSafe'.
- nestedTemplate._CHEETAH__initialFilter = self._CHEETAH__initialFilter
- nestedTemplate._CHEETAH__currentFilter = self._CHEETAH__initialFilter
- self._CHEETAH__cheetahIncludes[_includeID] = nestedTemplate
- else:
- if includeFrom == 'file':
- path = self.serverSidePath(srcArg)
- self._CHEETAH__cheetahIncludes[_includeID] = self.getFileContents(path)
- else:
- self._CHEETAH__cheetahIncludes[_includeID] = srcArg
- ##
- if not raw:
- self._CHEETAH__cheetahIncludes[_includeID].respond(trans)
- else:
- trans.response().write(self._CHEETAH__cheetahIncludes[_includeID])
-
- def _getTemplateAPIClassForIncludeDirectiveCompilation(self, source, file):
- """Returns the subclass of Template which should be used to compile
- #include directives.
-
- This abstraction allows different compiler settings to be used in the
- included template than were used in the parent.
- """
- if issubclass(self.__class__, Template):
- return self.__class__
- else:
- return Template
-
- ## functions for using templates as CGI scripts
- def webInput(self, names, namesMulti=(), default='', src='f',
- defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False):
- """Method for importing web transaction variables in bulk.
-
- This works for GET/POST fields both in Webware servlets and in CGI
- scripts, and for cookies and session variables in Webware servlets. If
- you try to read a cookie or session variable in a CGI script, you'll get
- a RuntimeError. 'In a CGI script' here means 'not running as a Webware
- servlet'. If the CGI environment is not properly set up, Cheetah will
- act like there's no input.
-
- The public method provided is:
-
- def webInput(self, names, namesMulti=(), default='', src='f',
- defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False):
-
- This method places the specified GET/POST fields, cookies or session
- variables into a dictionary, which is both returned and put at the
- beginning of the searchList. It handles:
-
- * single vs multiple values
- * conversion to integer or float for specified names
- * default values/exceptions for missing or bad values
- * printing a snapshot of all values retrieved for debugging
-
- All the 'default*' and 'bad*' arguments have 'use or raise' behavior,
- meaning that if they're a subclass of Exception, they're raised. If
- they're anything else, that value is substituted for the missing/bad
- value.
-
-
- The simplest usage is:
-
- #silent $webInput(['choice'])
- $choice
-
- dic = self.webInput(['choice'])
- write(dic['choice'])
-
- Both these examples retrieves the GET/POST field 'choice' and print it.
- If you leave off the'#silent', all the values would be printed too. But
- a better way to preview the values is
-
- #silent $webInput(['name'], $debug=1)
-
- because this pretty-prints all the values inside HTML <PRE> tags.
-
- ** KLUDGE: 'debug' is supposed to insert into the template output, but it
- wasn't working so I changed it to a'print' statement. So the debugging
- output will appear wherever standard output is pointed, whether at the
- terminal, in a Webware log file, or whatever. ***
-
- Since we didn't specify any coversions, the value is a string. It's a
- 'single' value because we specified it in 'names' rather than
- 'namesMulti'. Single values work like this:
-
- * If one value is found, take it.
- * If several values are found, choose one arbitrarily and ignore the rest.
- * If no values are found, use or raise the appropriate 'default*' value.
-
- Multi values work like this:
- * If one value is found, put it in a list.
- * If several values are found, leave them in a list.
- * If no values are found, use the empty list ([]). The 'default*'
- arguments are *not* consulted in this case.
-
- Example: assume 'days' came from a set of checkboxes or a multiple combo
- box on a form, and the user chose'Monday', 'Tuesday' and 'Thursday'.
-
- #silent $webInput([], ['days'])
- The days you chose are: #slurp
- #for $day in $days
- $day #slurp
- #end for
-
- dic = self.webInput([], ['days'])
- write('The days you chose are: ')
- for day in dic['days']:
- write(day + ' ')
-
- Both these examples print: 'The days you chose are: Monday Tuesday Thursday'.
-
- By default, missing strings are replaced by '' and missing/bad numbers
- by zero. (A'bad number' means the converter raised an exception for
- it, usually because of non-numeric characters in the value.) This
- mimics Perl/PHP behavior, and simplifies coding for many applications
- where missing/bad values *should* be blank/zero. In those relatively
- few cases where you must distinguish between empty-string/zero on the
- one hand and missing/bad on the other, change the appropriate
- 'default*' and 'bad*' arguments to something like:
-
- * None
- * another constant value
- * $NonNumericInputError/self.NonNumericInputError
- * $ValueError/ValueError
-
- (NonNumericInputError is defined in this class and is useful for
- distinguishing between bad input vs a TypeError/ValueError thrown for
- some other rason.)
-
- Here's an example using multiple values to schedule newspaper
- deliveries. 'checkboxes' comes from a form with checkboxes for all the
- days of the week. The days the user previously chose are preselected.
- The user checks/unchecks boxes as desired and presses Submit. The value
- of 'checkboxes' is a list of checkboxes that were checked when Submit
- was pressed. Our task now is to turn on the days the user checked, turn
- off the days he unchecked, and leave on or off the days he didn't
- change.
-
- dic = self.webInput([], ['dayCheckboxes'])
- wantedDays = dic['dayCheckboxes'] # The days the user checked.
- for day, on in self.getAllValues():
- if not on and wantedDays.has_key(day):
- self.TurnOn(day)
- # ... Set a flag or insert a database record ...
- elif on and not wantedDays.has_key(day):
- self.TurnOff(day)
- # ... Unset a flag or delete a database record ...
-
- 'source' allows you to look up the variables from a number of different
- sources:
- 'f' fields (CGI GET/POST parameters)
- 'c' cookies
- 's' session variables
- 'v' 'values', meaning fields or cookies
-
- In many forms, you're dealing only with strings, which is why the
- 'default' argument is third and the numeric arguments are banished to
- the end. But sometimes you want automatic number conversion, so that
- you can do numeric comparisions in your templates without having to
- write a bunch of conversion/exception handling code. Example:
-
- #silent $webInput(['name', 'height:int'])
- $name is $height cm tall.
- #if $height >= 300
- Wow, you're tall!
- #else
- Pshaw, you're short.
- #end if
-
- dic = self.webInput(['name', 'height:int'])
- name = dic[name]
- height = dic[height]
- write('%s is %s cm tall.' % (name, height))
- if height > 300:
- write('Wow, you're tall!')
- else:
- write('Pshaw, you're short.')
-
- To convert a value to a number, suffix ':int' or ':float' to the name.
- The method will search first for a 'height:int' variable and then for a
- 'height' variable. (It will be called 'height' in the final
- dictionary.) If a numeric conversion fails, use or raise 'badInt' or
- 'badFloat'. Missing values work the same way as for strings, except the
- default is 'defaultInt' or 'defaultFloat' instead of 'default'.
-
- If a name represents an uploaded file, the entire file will be read into
- memory. For more sophistocated file-upload handling, leave that name
- out of the list and do your own handling, or wait for
- Cheetah.Utils.UploadFileMixin.
-
- This only in a subclass that also inherits from Webware's Servlet or
- HTTPServlet. Otherwise you'll get an AttributeError on 'self.request'.
-
- EXCEPTIONS: ValueError if 'source' is not one of the stated characters.
- TypeError if a conversion suffix is not ':int' or ':float'.
-
- FUTURE EXPANSION: a future version of this method may allow source
- cascading; e.g., 'vs' would look first in 'values' and then in session
- variables.
-
- Meta-Data
- ================================================================================
- Author: Mike Orr <iron@mso.oz.net>
- License: This software is released for unlimited distribution under the
- terms of the MIT license. See the LICENSE file.
- Version: $Revision: 1.186 $
- Start Date: 2002/03/17
- Last Revision Date: $Date: 2008/03/10 04:48:11 $
- """
- src = src.lower()
- isCgi = not self._CHEETAH__isControlledByWebKit
- if isCgi and src in ('f', 'v'):
- global _formUsedByWebInput
- if _formUsedByWebInput is None:
- _formUsedByWebInput = cgi.FieldStorage()
- source, func = 'field', _formUsedByWebInput.getvalue
- elif isCgi and src == 'c':
- raise RuntimeError("can't get cookies from a CGI script")
- elif isCgi and src == 's':
- raise RuntimeError("can't get session variables from a CGI script")
- elif isCgi and src == 'v':
- source, func = 'value', self.request().value
- elif isCgi and src == 's':
- source, func = 'session', self.request().session().value
- elif src == 'f':
- source, func = 'field', self.request().field
- elif src == 'c':
- source, func = 'cookie', self.request().cookie
- elif src == 'v':
- source, func = 'value', self.request().value
- elif src == 's':
- source, func = 'session', self.request().session().value
- else:
- raise TypeError("arg 'src' invalid")
- sources = source + 's'
- converters = {
- '': _Converter('string', None, default, default ),
- 'int': _Converter('int', int, defaultInt, badInt ),
- 'float': _Converter('float', float, defaultFloat, badFloat), }
- #pprint.pprint(locals()); return {}
- dic = {} # Destination.
- for name in names:
- k, v = _lookup(name, func, False, converters)
- dic[k] = v
- for name in namesMulti:
- k, v = _lookup(name, func, True, converters)
- dic[k] = v
- # At this point, 'dic' contains all the keys/values we want to keep.
- # We could split the method into a superclass
- # method for Webware/WebwareExperimental and a subclass for Cheetah.
- # The superclass would merely 'return dic'. The subclass would
- # 'dic = super(ThisClass, self).webInput(names, namesMulti, ...)'
- # and then the code below.
- if debug:
- print("<PRE>\n" + pprint.pformat(dic) + "\n</PRE>\n\n")
- self.searchList().insert(0, dic)
- return dic
-
-T = Template # Short and sweet for debugging at the >>> prompt.
-Template.Reserved_SearchList = set(dir(Template))
-
-def genParserErrorFromPythonException(source, file, generatedPyCode, exception):
-
- #print dir(exception)
-
- filename = isinstance(file, (str, unicode)) and file or None
-
- sio = StringIO.StringIO()
- traceback.print_exc(1, sio)
- formatedExc = sio.getvalue()
-
- if hasattr(exception, 'lineno'):
- pyLineno = exception.lineno
- else:
- pyLineno = int(re.search('[ \t]*File.*line (\d+)', formatedExc).group(1))
-
- lines = generatedPyCode.splitlines()
-
- prevLines = [] # (i, content)
- for i in range(1, 4):
- if pyLineno-i <=0:
- break
- prevLines.append( (pyLineno+1-i, lines[pyLineno-i]) )
-
- nextLines = [] # (i, content)
- for i in range(1, 4):
- if not pyLineno+i < len(lines):
- break
- nextLines.append( (pyLineno+i, lines[pyLineno+i]) )
- nextLines.reverse()
- report = 'Line|Python Code\n'
- report += '----|-------------------------------------------------------------\n'
- while prevLines:
- lineInfo = prevLines.pop()
- report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]}
-
- if hasattr(exception, 'offset'):
- report += ' '*(3+(exception.offset or 0)) + '^\n'
-
- while nextLines:
- lineInfo = nextLines.pop()
- report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]}
-
-
- message = [
- "Error in the Python code which Cheetah generated for this template:",
- '='*80,
- '',
- str(exception),
- '',
- report,
- '='*80,
- ]
- cheetahPosMatch = re.search('line (\d+), col (\d+)', formatedExc)
- if cheetahPosMatch:
- lineno = int(cheetahPosMatch.group(1))
- col = int(cheetahPosMatch.group(2))
- #if hasattr(exception, 'offset'):
- # col = exception.offset
- message.append('\nHere is the corresponding Cheetah code:\n')
- else:
- lineno = None
- col = None
- cheetahPosMatch = re.search('line (\d+), col (\d+)',
- '\n'.join(lines[max(pyLineno-2, 0):]))
- if cheetahPosMatch:
- lineno = int(cheetahPosMatch.group(1))
- col = int(cheetahPosMatch.group(2))
- message.append('\nHere is the corresponding Cheetah code.')
- message.append('** I had to guess the line & column numbers,'
- ' so they are probably incorrect:\n')
-
-
- message = '\n'.join(message)
- reader = SourceReader(source, filename=filename)
- return ParseError(reader, message, lineno=lineno, col=col)
-
-
-# vim: shiftwidth=4 tabstop=4 expandtab
Index: cheetah/Cheetah/TemplateCmdLineIface.py
===================================================================
--- cheetah/Cheetah/TemplateCmdLineIface.py (revision 19111)
+++ cheetah/Cheetah/TemplateCmdLineIface.py (nonexistent)
@@ -1,107 +0,0 @@
-# $Id: TemplateCmdLineIface.py,v 1.13 2006/01/10 20:34:35 tavis_rudd Exp $
-
-"""Provides a command line interface to compiled Cheetah template modules.
-
-Meta-Data
-================================================================================
-Author: Tavis Rudd <tavis@damnsimple.com>
-Version: $Revision: 1.13 $
-Start Date: 2001/12/06
-Last Revision Date: $Date: 2006/01/10 20:34:35 $
-"""
-__author__ = "Tavis Rudd <tavis@damnsimple.com>"
-__revision__ = "$Revision: 1.13 $"[11:-2]
-
-import sys
-import os
-import getopt
-import os.path
-try:
- from cPickle import load
-except ImportError:
- from pickle import load
-
-from Cheetah.Version import Version
-
-class Error(Exception):
- pass
-
-class CmdLineIface:
- """A command line interface to compiled Cheetah template modules."""
-
- def __init__(self, templateObj,
- scriptName=os.path.basename(sys.argv[0]),
- cmdLineArgs=sys.argv[1:]):
-
- self._template = templateObj
- self._scriptName = scriptName
- self._cmdLineArgs = cmdLineArgs
-
- def run(self):
- """The main program controller."""
-
- self._processCmdLineArgs()
- print(self._template)
-
- def _processCmdLineArgs(self):
- try:
- self._opts, self._args = getopt.getopt(
- self._cmdLineArgs, 'h', ['help',
- 'env',
- 'pickle=',
- ])
-
- except getopt.GetoptError, v:
- # print help information and exit:
- print(v)
- print(self.usage())
- sys.exit(2)
-
- for o, a in self._opts:
- if o in ('-h', '--help'):
- print(self.usage())
- sys.exit()
- if o == '--env':
- self._template.searchList().insert(0, os.environ)
- if o == '--pickle':
- if a == '-':
- unpickled = load(sys.stdin)
- self._template.searchList().insert(0, unpickled)
- else:
- f = open(a)
- unpickled = load(f)
- f.close()
- self._template.searchList().insert(0, unpickled)
-
- def usage(self):
- return """Cheetah %(Version)s template module command-line interface
-
-Usage
------
- %(scriptName)s [OPTION]
-
-Options
--------
- -h, --help Print this help information
-
- --env Use shell ENVIRONMENT variables to fill the
- $placeholders in the template.
-
- --pickle <file> Use a variables from a dictionary stored in Python
- pickle file to fill $placeholders in the template.
- If <file> is - stdin is used:
- '%(scriptName)s --pickle -'
-
-Description
------------
-
-This interface allows you to execute a Cheetah template from the command line
-and collect the output. It can prepend the shell ENVIRONMENT or a pickled
-Python dictionary to the template's $placeholder searchList, overriding the
-defaults for the $placeholders.
-
-""" % {'scriptName': self._scriptName,
- 'Version': Version,
- }
-
-# vim: shiftwidth=4 tabstop=4 expandtab
Index: cheetah/Cheetah/Templates/SkeletonPage.py
===================================================================
--- cheetah/Cheetah/Templates/SkeletonPage.py (revision 19111)
+++ cheetah/Cheetah/Templates/SkeletonPage.py (nonexistent)
@@ -1,272 +0,0 @@
-
-
-"""A Skeleton HTML page template, that provides basic structure and utility methods.
-"""
-
-
-##################################################
-## DEPENDENCIES
-import sys
-import os
-import os.path
-from os.path import getmtime, exists
-import time
-import types
-import __builtin__
-from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
-from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
-from Cheetah.Template import Template
-from Cheetah.DummyTransaction import DummyTransaction
-from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
-from Cheetah.CacheRegion import CacheRegion
-import Cheetah.Filters as Filters
-import Cheetah.ErrorCatchers as ErrorCatchers
-from Cheetah.Templates._SkeletonPage import _SkeletonPage
-
-##################################################
-## MODULE CONSTANTS
-try:
- True, False
-except NameError:
- True, False = (1==1), (1==0)
-VFFSL=valueFromFrameOrSearchList
-VFSL=valueFromSearchList
-VFN=valueForName
-currentTime=time.time
-__CHEETAH_version__ = '2.0rc6'
-__CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 6)
-__CHEETAH_genTime__ = 1139107954.3640411
-__CHEETAH_genTimestamp__ = 'Sat Feb 4 18:52:34 2006'
-__CHEETAH_src__ = 'src/Templates/SkeletonPage.tmpl'
-__CHEETAH_srcLastModified__ = 'Mon Oct 7 11:37:30 2002'
-__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
-
-if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
- raise AssertionError(
- 'This template was compiled with Cheetah version'
- ' %s. Templates compiled before version %s must be recompiled.'%(
- __CHEETAH_version__, RequiredCheetahVersion))
-
-##################################################
-## CLASSES
-
-class SkeletonPage(_SkeletonPage):
-
- ##################################################
- ## CHEETAH GENERATED METHODS
-
-
- def __init__(self, *args, **KWs):
-
- _SkeletonPage.__init__(self, *args, **KWs)
- if not self._CHEETAH__instanceInitialized:
- cheetahKWArgs = {}
- allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
- for k, v in KWs.items():
- if k in allowedKWs: cheetahKWArgs[k] = v
- self._initCheetahInstance(**cheetahKWArgs)
-
-
- def writeHeadTag(self, **KWS):
-
-
-
- ## CHEETAH: generated from #block writeHeadTag at line 22, col 1.
- trans = KWS.get("trans")
- if (not trans and not self._CHEETAH__isBuffering and not hasattr(self.transaction, '__call__')):
- trans = self.transaction # is None unless self.awake() was called
- if not trans:
- trans = DummyTransaction()
- _dummyTrans = True
- else: _dummyTrans = False
- write = trans.response().write
- SL = self._CHEETAH__searchList
- _filter = self._CHEETAH__currentFilter
-
- ########################################
- ## START - generated method body
-
- write('<head>\n<title>')
- _v = VFFSL(SL, "title", True) # '$title' on line 24, col 8
- if _v is not None: write(_filter(_v, rawExpr='$title')) # from line 24, col 8.
- write('</title>\n')
- _v = VFFSL(SL, "metaTags", True) # '$metaTags' on line 25, col 1
- if _v is not None: write(_filter(_v, rawExpr='$metaTags')) # from line 25, col 1.
- write(' \n')
- _v = VFFSL(SL, "stylesheetTags", True) # '$stylesheetTags' on line 26, col 1
- if _v is not None: write(_filter(_v, rawExpr='$stylesheetTags')) # from line 26, col 1.
- write(' \n')
- _v = VFFSL(SL, "javascriptTags", True) # '$javascriptTags' on line 27, col 1
- if _v is not None: write(_filter(_v, rawExpr='$javascriptTags')) # from line 27, col 1.
- write('\n</head>\n')
-
- ########################################
- ## END - generated method body
-
- return _dummyTrans and trans.response().getvalue() or ""
-
-
- def writeBody(self, **KWS):
-
-
-
- ## CHEETAH: generated from #block writeBody at line 36, col 1.
- trans = KWS.get("trans")
- if (not trans and not self._CHEETAH__isBuffering and not hasattr(self.transaction, '__call__')):
- trans = self.transaction # is None unless self.awake() was called
- if not trans:
- trans = DummyTransaction()
- _dummyTrans = True
- else: _dummyTrans = False
- write = trans.response().write
- SL = self._CHEETAH__searchList
- _filter = self._CHEETAH__currentFilter
-
- ########################################
- ## START - generated method body
-
- write('This skeleton page has no flesh. Its body needs to be implemented.\n')
-
- ########################################
- ## END - generated method body
-
- return _dummyTrans and trans.response().getvalue() or ""
-
-
- def respond(self, trans=None):
-
-
-
- ## CHEETAH: main method generated for this template
- if (not trans and not self._CHEETAH__isBuffering and not hasattr(self.transaction, '__call__')):
- trans = self.transaction # is None unless self.awake() was called
- if not trans:
- trans = DummyTransaction()
- _dummyTrans = True
- else: _dummyTrans = False
- write = trans.response().write
- SL = self._CHEETAH__searchList
- _filter = self._CHEETAH__currentFilter
-
- ########################################
- ## START - generated method body
-
-
- ## START CACHE REGION: ID=header. line 6, col 1 in the source.
- _RECACHE_header = False
- _cacheRegion_header = self.getCacheRegion(regionID='header', cacheInfo={'type': 2, 'id': 'header'})
- if _cacheRegion_header.isNew():
- _RECACHE_header = True
- _cacheItem_header = _cacheRegion_header.getCacheItem('header')
- if _cacheItem_header.hasExpired():
- _RECACHE_header = True
- if (not _RECACHE_header) and _cacheItem_header.getRefreshTime():
- try:
- _output = _cacheItem_header.renderOutput()
- except KeyError:
- _RECACHE_header = True
- else:
- write(_output)
- del _output
- if _RECACHE_header or not _cacheItem_header.getRefreshTime():
- _orig_transheader = trans
- trans = _cacheCollector_header = DummyTransaction()
- write = _cacheCollector_header.response().write
- _v = VFFSL(SL, "docType", True) # '$docType' on line 7, col 1
- if _v is not None: write(_filter(_v, rawExpr='$docType')) # from line 7, col 1.
- write('\n')
- _v = VFFSL(SL, "htmlTag", True) # '$htmlTag' on line 8, col 1
- if _v is not None: write(_filter(_v, rawExpr='$htmlTag')) # from line 8, col 1.
- write('''
-<!-- This document was autogenerated by Cheetah(http://CheetahTemplate.org).
-Do not edit it directly!
-
-Copyright ''')
- _v = VFFSL(SL, "currentYr", True) # '$currentYr' on line 12, col 11
- if _v is not None: write(_filter(_v, rawExpr='$currentYr')) # from line 12, col 11.
- write(' - ')
- _v = VFFSL(SL, "siteCopyrightName", True) # '$siteCopyrightName' on line 12, col 24
- if _v is not None: write(_filter(_v, rawExpr='$siteCopyrightName')) # from line 12, col 24.
- write(' - All Rights Reserved.\nFeel free to copy any javascript or html you like on this site,\nprovided you remove all links and/or references to ')
- _v = VFFSL(SL, "siteDomainName", True) # '$siteDomainName' on line 14, col 52
- if _v is not None: write(_filter(_v, rawExpr='$siteDomainName')) # from line 14, col 52.
- write('''
-However, please do not copy any content or images without permission.
-
-''')
- _v = VFFSL(SL, "siteCredits", True) # '$siteCredits' on line 17, col 1
- if _v is not None: write(_filter(_v, rawExpr='$siteCredits')) # from line 17, col 1.
- write('''
-
--->
-
-
-''')
- self.writeHeadTag(trans=trans)
- write('\n')
- trans = _orig_transheader
- write = trans.response().write
- _cacheData = _cacheCollector_header.response().getvalue()
- _cacheItem_header.setData(_cacheData)
- write(_cacheData)
- del _cacheData
- del _cacheCollector_header
- del _orig_transheader
- ## END CACHE REGION: header
-
- write('\n')
- _v = VFFSL(SL, "bodyTag", True) # '$bodyTag' on line 34, col 1
- if _v is not None: write(_filter(_v, rawExpr='$bodyTag')) # from line 34, col 1.
- write('\n\n')
- self.writeBody(trans=trans)
- write('''
-</body>
-</html>
-
-
-
-''')
-
- ########################################
- ## END - generated method body
-
- return _dummyTrans and trans.response().getvalue() or ""
-
- ##################################################
- ## CHEETAH GENERATED ATTRIBUTES
-
-
- _CHEETAH__instanceInitialized = False
-
- _CHEETAH_version = __CHEETAH_version__
-
- _CHEETAH_versionTuple = __CHEETAH_versionTuple__
-
- _CHEETAH_genTime = __CHEETAH_genTime__
-
- _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
-
- _CHEETAH_src = __CHEETAH_src__
-
- _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
-
- _mainCheetahMethod_for_SkeletonPage= 'respond'
-
-## END CLASS DEFINITION
-
-if not hasattr(SkeletonPage, '_initCheetahAttributes'):
- templateAPIClass = getattr(SkeletonPage, '_CHEETAH_templateClass', Template)
- templateAPIClass._addCheetahPlumbingCodeToClass(SkeletonPage)
-
-
-# CHEETAH was developed by Tavis Rudd and Mike Orr
-# with code, advice and input from many other volunteers.
-# For more information visit http://www.CheetahTemplate.org/
-
-##################################################
-## if run from command line:
-if __name__ == '__main__':
- from Cheetah.TemplateCmdLineIface import CmdLineIface
- CmdLineIface(templateObj=SkeletonPage()).run()
-
-
Index: cheetah/Cheetah/Templates/SkeletonPage.tmpl
===================================================================
--- cheetah/Cheetah/Templates/SkeletonPage.tmpl (revision 19111)
+++ cheetah/Cheetah/Templates/SkeletonPage.tmpl (nonexistent)
@@ -1,44 +0,0 @@
-##doc-module: A Skeleton HTML page template, that provides basic structure and utility methods.
-################################################################################
-#extends Cheetah.Templates._SkeletonPage
-#implements respond
-################################################################################
-#cache id='header'
-$docType
-$htmlTag
-<!-- This document was autogenerated by Cheetah(http://CheetahTemplate.org).
-Do not edit it directly!
-
-Copyright $currentYr - $siteCopyrightName - All Rights Reserved.
-Feel free to copy any javascript or html you like on this site,
-provided you remove all links and/or references to $siteDomainName
-However, please do not copy any content or images without permission.
-
-$siteCredits
-
--->
-
-
-#block writeHeadTag
-<head>
-<title>$title</title>
-$metaTags
-$stylesheetTags
-$javascriptTags
-</head>
-#end block writeHeadTag
-
-#end cache header
-#################
-
-$bodyTag
-
-#block writeBody
-This skeleton page has no flesh. Its body needs to be implemented.
-#end block writeBody
-
-</body>
-</html>
-
-
-
Index: cheetah/Cheetah/Templates/_SkeletonPage.py
===================================================================
--- cheetah/Cheetah/Templates/_SkeletonPage.py (revision 19111)
+++ cheetah/Cheetah/Templates/_SkeletonPage.py (nonexistent)
@@ -1,215 +0,0 @@
-# $Id: _SkeletonPage.py,v 1.13 2002/10/01 17:52:02 tavis_rudd Exp $
-"""A baseclass for the SkeletonPage template
-
-Meta-Data
-==========
-Author: Tavis Rudd <tavis@damnsimple.com>,
-Version: $Revision: 1.13 $
-Start Date: 2001/04/05
-Last Revision Date: $Date: 2002/10/01 17:52:02 $
-"""
-__author__ = "Tavis Rudd <tavis@damnsimple.com>"
-__revision__ = "$Revision: 1.13 $"[11:-2]
-
-##################################################
-## DEPENDENCIES ##
-
-import time, types, os, sys
-
-# intra-package imports ...
-from Cheetah.Template import Template
-
-
-##################################################
-## GLOBALS AND CONSTANTS ##
-
-True = (1==1)
-False = (0==1)
-
-##################################################
-## CLASSES ##
-
-class _SkeletonPage(Template):
- """A baseclass for the SkeletonPage template"""
-
- docType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ' + \
- '"http://www.w3.org/TR/html4/loose.dtd">'
-
- # docType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ' + \
- #'"http://www.w3.org/TR/xhtml1l/DTD/transitional.dtd">'
-
- title = ''
- siteDomainName = 'www.example.com'
- siteCredits = 'Designed & Implemented by Tavis Rudd'
- siteCopyrightName = "Tavis Rudd"
- htmlTag = '<html>'
-
- def __init__(self, *args, **KWs):
- Template.__init__(self, *args, **KWs)
- self._metaTags = {'HTTP-EQUIV':{'keywords': 'Cheetah',
- 'Content-Type': 'text/html; charset=iso-8859-1',
- },
- 'NAME':{'generator':'Cheetah: The Python-Powered Template Engine'}
- }
- # metaTags = {'HTTP_EQUIV':{'test':1234}, 'NAME':{'test':1234,'test2':1234} }
- self._stylesheets = {}
- # stylesheets = {'.cssClassName':'stylesheetCode'}
- self._stylesheetsOrder = []
- # stylesheetsOrder = ['.cssClassName',]
- self._stylesheetLibs = {}
- # stylesheetLibs = {'libName':'libSrcPath'}
- self._javascriptLibs = {}
- self._javascriptTags = {}
- # self._javascriptLibs = {'libName':'libSrcPath'}
- self._bodyTagAttribs = {}
-
- def metaTags(self):
- """Return a formatted vesion of the self._metaTags dictionary, using the
- formatMetaTags function from Cheetah.Macros.HTML"""
-
- return self.formatMetaTags(self._metaTags)
-
- def stylesheetTags(self):
- """Return a formatted version of the self._stylesheetLibs and
- self._stylesheets dictionaries. The keys in self._stylesheets must
- be listed in the order that they should appear in the list
- self._stylesheetsOrder, to ensure that the style rules are defined in
- the correct order."""
-
- stylesheetTagsTxt = ''
- for title, src in self._stylesheetLibs.items():
- stylesheetTagsTxt += '<link rel="stylesheet" type="text/css" href="' + str(src) + '" />\n'
-
- if not self._stylesheetsOrder:
- return stylesheetTagsTxt
-
- stylesheetTagsTxt += '<style type="text/css"><!--\n'
- for identifier in self._stylesheetsOrder:
- if identifier not in self._stylesheets:
- warning = '# the identifier ' + identifier + \
- 'was in stylesheetsOrder, but not in stylesheets'
- print(warning)
- stylesheetTagsTxt += warning
- continue
-
- attribsDict = self._stylesheets[identifier]
- cssCode = ''
- attribCode = ''
- for k, v in attribsDict.items():
- attribCode += str(k) + ': ' + str(v) + '; '
- attribCode = attribCode[:-2] # get rid of the last semicolon
-
- cssCode = '\n' + identifier + ' {' + attribCode + '}'
- stylesheetTagsTxt += cssCode
-
- stylesheetTagsTxt += '\n//--></style>\n'
-
- return stylesheetTagsTxt
-
- def javascriptTags(self):
- """Return a formatted version of the javascriptTags and
- javascriptLibs dictionaries. Each value in javascriptTags
- should be a either a code string to include, or a list containing the
- JavaScript version number and the code string. The keys can be anything.
- The same applies for javascriptLibs, but the string should be the
- SRC filename rather than a code string."""
-
- javascriptTagsTxt = []
- for key, details in self._javascriptTags.iteritems():
- if not isinstance(details, (list, tuple)):
- details = ['', details]
-
- javascriptTagsTxt += ['<script language="JavaScript', str(details[0]),
- '" type="text/javascript"><!--\n',
- str(details[0]), '\n//--></script>\n']
-
-
- for key, details in self._javascriptLibs.iteritems():
- if not isinstance(details, (list, tuple)):
- details = ['', details]
-
- javascriptTagsTxt += ['<script language="JavaScript', str(details[0]),
- '" type="text/javascript" src="',
- str(details[1]), '" />\n']
- return ''.join(javascriptTagsTxt)
-
- def bodyTag(self):
- """Create a body tag from the entries in the dict bodyTagAttribs."""
- return self.formHTMLTag('body', self._bodyTagAttribs)
-
-
- def imgTag(self, src, alt='', width=None, height=None, border=0):
-
- """Dynamically generate an image tag. Cheetah will try to convert the
- src argument to a WebKit serverSidePath relative to the servlet's
- location. If width and height aren't specified they are calculated using
- PIL or ImageMagick if available."""
-
- src = self.normalizePath(src)
-
-
- if not width or not height:
- try: # see if the dimensions can be calc'd with PIL
- import Image
- im = Image.open(src)
- calcWidth, calcHeight = im.size
- del im
- if not width: width = calcWidth
- if not height: height = calcHeight
-
- except:
- try: # try imageMagick instead
- calcWidth, calcHeight = os.popen(
- 'identify -format "%w,%h" ' + src).read().split(',')
- if not width: width = calcWidth
- if not height: height = calcHeight
-
- except:
- pass
-
- if width and height:
- return ''.join(['<img src="', src, '" width="', str(width), '" height="', str(height),
- '" alt="', alt, '" border="', str(border), '" />'])
- elif width:
- return ''.join(['<img src="', src, '" width="', str(width),
- '" alt="', alt, '" border="', str(border), '" />'])
- elif height:
- return ''.join(['<img src="', src, '" height="', str(height),
- '" alt="', alt, '" border="', str(border), '" />'])
- else:
- return ''.join(['<img src="', src, '" alt="', alt, '" border="', str(border), '" />'])
-
-
- def currentYr(self):
- """Return a string representing the current yr."""
- return time.strftime("%Y", time.localtime(time.time()))
-
- def currentDate(self, formatString="%b %d, %Y"):
- """Return a string representing the current localtime."""
- return time.strftime(formatString, time.localtime(time.time()))
-
- def spacer(self, width=1,height=1):
- return '<img src="spacer.gif" width="%s" height="%s" alt="" />'% (str(width), str(height))
-
- def formHTMLTag(self, tagName, attributes={}):
- """returns a string containing an HTML <tag> """
- tagTxt = ['<', tagName.lower()]
- for name, val in attributes.items():
- tagTxt += [' ', name.lower(), '="', str(val), '"']
- tagTxt.append('>')
- return ''.join(tagTxt)
-
- def formatMetaTags(self, metaTags):
- """format a dict of metaTag definitions into an HTML version"""
- metaTagsTxt = []
- if 'HTTP-EQUIV' in metaTags:
- for http_equiv, contents in metaTags['HTTP-EQUIV'].items():
- metaTagsTxt += ['<meta http-equiv="', str(http_equiv), '" content="',
- str(contents), '" />\n']
-
- if 'NAME' in metaTags:
- for name, contents in metaTags['NAME'].items():
- metaTagsTxt += ['<meta name="', str(name), '" content="', str(contents),
- '" />\n']
- return ''.join(metaTagsTxt)
-
Index: cheetah/Cheetah/Templates/__init__.py
===================================================================
--- cheetah/Cheetah/Templates/__init__.py (revision 19111)
+++ cheetah/Cheetah/Templates/__init__.py (nonexistent)
@@ -1 +0,0 @@
-
Index: cheetah/Cheetah/Tests/Analyzer.py
===================================================================
--- cheetah/Cheetah/Tests/Analyzer.py (revision 19111)
+++ cheetah/Cheetah/Tests/Analyzer.py (nonexistent)
@@ -1,29 +0,0 @@
-#!/usr/bin/env python
-
-import unittest
-
-from Cheetah import DirectiveAnalyzer
-
-
-class AnalyzerTests(unittest.TestCase):
- def test_set(self):
- template = '''
- #set $foo = "bar"
- Hello ${foo}!
- '''
- calls = DirectiveAnalyzer.analyze(template)
- self.assertEquals(1, calls.get('set'))
-
- def test_compilersettings(self):
- template = '''
-#compiler-settings
-useNameMapper = False
-#end compiler-settings
- '''
- calls = DirectiveAnalyzer.analyze(template)
- self.assertEquals(1, calls.get('compiler-settings'))
-
-
-if __name__ == '__main__':
- unittest.main()
-
Index: cheetah/Cheetah/Tests/CheetahWrapper.py
===================================================================
--- cheetah/Cheetah/Tests/CheetahWrapper.py (revision 19111)
+++ cheetah/Cheetah/Tests/CheetahWrapper.py (nonexistent)
@@ -1,579 +0,0 @@
-#!/usr/bin/env python
-'''
-Tests for the 'cheetah' command.
-
-Besides unittest usage, recognizes the following command-line options:
- --list CheetahWrapper.py
- List all scenarios that are tested. The argument is the path
- of this script.
- --nodelete
- Don't delete scratch directory at end.
- --output
- Show the output of each subcommand. (Normally suppressed.)
-'''
-import os
-import os.path
-import pdb
-import re # Used by listTests.
-import shutil
-import sys
-import tempfile
-import unittest
-
-from optparse import OptionParser
-from Cheetah.CheetahWrapper import CheetahWrapper # Used by NoBackup.
-
-try:
- from subprocess import Popen, PIPE, STDOUT
- class Popen4(Popen):
- def __init__(self, cmd, bufsize=-1, shell=True, close_fds=True,
- stdin=PIPE, stdout=PIPE, stderr=STDOUT, **kwargs):
-
- super(Popen4, self).__init__(cmd, bufsize=bufsize, shell=shell,
- close_fds=close_fds, stdin=stdin, stdout=stdout,
- stderr=stderr, **kwargs)
-
- self.tochild = self.stdin
- self.fromchild = self.stdout
- self.childerr = self.stderr
-except ImportError:
- from popen2 import Popen4
-
-DELETE = True # True to clean up after ourselves, False for debugging.
-OUTPUT = False # Normally False, True for debugging.
-
-BACKUP_SUFFIX = CheetahWrapper.BACKUP_SUFFIX
-
-def warn(msg):
- sys.stderr.write(msg + '\n')
-
-class CFBase(unittest.TestCase):
- """Base class for "cheetah compile" and "cheetah fill" unit tests.
- """
- srcDir = '' # Nonblank to create source directory.
- subdirs = ('child', 'child/grandkid') # Delete in reverse order.
- srcFiles = ('a.tmpl', 'child/a.tmpl', 'child/grandkid/a.tmpl')
- expectError = False # Used by --list option.
-
- def inform(self, message):
- if self.verbose:
- print(message)
-
- def setUp(self):
- """Create the top-level directories, subdirectories and .tmpl
- files.
- """
- self.cmd = self.locate_cheetah('cheetah')
- pythonPath = os.getcwd()
- if not os.environ.get('PYTHONPATH'):
- os.environ['PYTHONPATH'] = pythonPath
- else:
- os.environ['PYTHONPATH'] = '%s:%s' % (os.environ['PYTHONPATH'], pythonPath)
- I = self.inform
- # Step 1: Create the scratch directory and chdir into it.
- self.scratchDir = scratchDir = tempfile.mktemp()
- os.mkdir(scratchDir)
- self.origCwd = os.getcwd()
- os.chdir(scratchDir)
- if self.srcDir:
- os.mkdir(self.srcDir)
- # Step 2: Create source subdirectories.
- for dir in self.subdirs:
- os.mkdir(dir)
- # Step 3: Create the .tmpl files, each in its proper directory.
- for fil in self.srcFiles:
- f = open(fil, 'w')
- f.write("Hello, world!\n")
- f.close()
-
- def tearDown(self):
- os.chdir(self.origCwd)
- if DELETE:
- shutil.rmtree(self.scratchDir, True) # Ignore errors.
- if os.path.exists(self.scratchDir):
- warn("Warning: unable to delete scratch directory %s")
- else:
- warn("Warning: not deleting scratch directory %s" % self.scratchDir)
-
-
- def _checkDestFileHelper(self, path, expected,
- allowSurroundingText, errmsg):
- """Low-level helper to check a destination file.
-
- in : path, string, the destination path.
- expected, string, the expected contents.
- allowSurroundingtext, bool, allow the result to contain
- additional text around the 'expected' substring?
- errmsg, string, the error message. It may contain the
- following "%"-operator keys: path, expected, result.
- out: None
- """
- path = os.path.abspath(path)
- exists = os.path.exists(path)
- msg = "destination file missing: %s" % path
- self.failUnless(exists, msg)
- f = open(path, 'r')
- result = f.read()
- f.close()
- if allowSurroundingText:
- success = result.find(expected) != -1
- else:
- success = result == expected
- msg = errmsg % locals()
- self.failUnless(success, msg)
-
-
- def checkCompile(self, path):
- # Raw string to prevent "\n" from being converted to a newline.
- #expected = R"write('Hello, world!\n')"
- expected = "Hello, world!" # might output a u'' string
- errmsg = """\
-destination file %(path)s doesn't contain expected substring:
-%(expected)r"""
- self._checkDestFileHelper(path, expected, True, errmsg)
-
-
- def checkFill(self, path):
- expected = "Hello, world!\n"
- errmsg = """\
-destination file %(path)s contains wrong result.
-Expected %(expected)r
-Found %(result)r"""
- self._checkDestFileHelper(path, expected, False, errmsg)
-
-
- def checkSubdirPyInit(self, path):
- """Verify a destination subdirectory exists and contains an
- __init__.py file.
- """
- exists = os.path.exists(path)
- msg = "destination subdirectory %s misssing" % path
- self.failUnless(exists, msg)
- initPath = os.path.join(path, "__init__.py")
- exists = os.path.exists(initPath)
- msg = "destination init file missing: %s" % initPath
- self.failUnless(exists, msg)
-
-
- def checkNoBackup(self, path):
- """Verify 'path' does not exist. (To check --nobackup.)
- """
- exists = os.path.exists(path)
- msg = "backup file exists in spite of --nobackup: %s" % path
- self.failIf(exists, msg)
-
- def locate_cheetah(self, cmd):
- paths = os.getenv('PATH')
- if not paths:
- return cmd
- parts = cmd.split(' ')
- paths = paths.split(':')
- for p in paths:
- p = os.path.join(p, cmd)
- p = os.path.abspath(p)
- if os.path.isfile(p):
- return p
- return cmd
-
- def assertWin32Subprocess(self, cmd):
- _in, _out = os.popen4(cmd)
- _in.close()
- output = _out.read()
- rc = _out.close()
- if rc is None:
- rc = 0
- return rc, output
-
- def assertPosixSubprocess(self, cmd):
- cmd = cmd.replace('cheetah', self.cmd)
- process = Popen4(cmd, env=os.environ)
- process.tochild.close()
- output = process.fromchild.read()
- status = process.wait()
- process.fromchild.close()
- return status, output
-
- def assertSubprocess(self, cmd, nonzero=False):
- status, output = None, None
- if sys.platform == 'win32':
- status, output = self.assertWin32Subprocess(cmd)
- else:
- status, output = self.assertPosixSubprocess(cmd)
-
- if not nonzero:
- self.failUnlessEqual(status, 0, '''Subprocess exited with a non-zero status (%d)
- %s''' % (status, output))
- else:
- self.failIfEqual(status, 0, '''Subprocess exited with a zero status (%d)
- %s''' % (status, output))
- return output
-
- def go(self, cmd, expectedStatus=0, expectedOutputSubstring=None):
- """Run a "cheetah compile" or "cheetah fill" subcommand.
-
- in : cmd, string, the command to run.
- expectedStatus, int, subcommand's expected output status.
- 0 if the subcommand is expected to succeed, 1-255 otherwise.
- expectedOutputSubstring, string, substring which much appear
- in the standard output or standard error. None to skip this
- test.
- out: None.
- """
- output = self.assertSubprocess(cmd)
- if expectedOutputSubstring is not None:
- msg = "substring %r not found in subcommand output: %s" % \
- (expectedOutputSubstring, cmd)
- substringTest = output.find(expectedOutputSubstring) != -1
- self.failUnless(substringTest, msg)
-
-
-class CFIdirBase(CFBase):
- """Subclass for tests with --idir.
- """
- srcDir = 'SRC'
- subdirs = ('SRC/child', 'SRC/child/grandkid') # Delete in reverse order.
- srcFiles = ('SRC/a.tmpl', 'SRC/child/a.tmpl', 'SRC/child/grandkid/a.tmpl')
-
-
-
-##################################################
-## TEST CASE CLASSES
-
-class OneFile(CFBase):
- def testCompile(self):
- self.go("cheetah compile a.tmpl")
- self.checkCompile("a.py")
-
- def testFill(self):
- self.go("cheetah fill a.tmpl")
- self.checkFill("a.html")
-
- def testText(self):
- self.go("cheetah fill --oext txt a.tmpl")
- self.checkFill("a.txt")
-
-
-class OneFileNoExtension(CFBase):
- def testCompile(self):
- self.go("cheetah compile a")
- self.checkCompile("a.py")
-
- def testFill(self):
- self.go("cheetah fill a")
- self.checkFill("a.html")
-
- def testText(self):
- self.go("cheetah fill --oext txt a")
- self.checkFill("a.txt")
-
-
-class SplatTmpl(CFBase):
- def testCompile(self):
- self.go("cheetah compile *.tmpl")
- self.checkCompile("a.py")
-
- def testFill(self):
- self.go("cheetah fill *.tmpl")
- self.checkFill("a.html")
-
- def testText(self):
- self.go("cheetah fill --oext txt *.tmpl")
- self.checkFill("a.txt")
-
-class ThreeFilesWithSubdirectories(CFBase):
- def testCompile(self):
- self.go("cheetah compile a.tmpl child/a.tmpl child/grandkid/a.tmpl")
- self.checkCompile("a.py")
- self.checkCompile("child/a.py")
- self.checkCompile("child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill a.tmpl child/a.tmpl child/grandkid/a.tmpl")
- self.checkFill("a.html")
- self.checkFill("child/a.html")
- self.checkFill("child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill --oext txt a.tmpl child/a.tmpl child/grandkid/a.tmpl")
- self.checkFill("a.txt")
- self.checkFill("child/a.txt")
- self.checkFill("child/grandkid/a.txt")
-
-
-class ThreeFilesWithSubdirectoriesNoExtension(CFBase):
- def testCompile(self):
- self.go("cheetah compile a child/a child/grandkid/a")
- self.checkCompile("a.py")
- self.checkCompile("child/a.py")
- self.checkCompile("child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill a child/a child/grandkid/a")
- self.checkFill("a.html")
- self.checkFill("child/a.html")
- self.checkFill("child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill --oext txt a child/a child/grandkid/a")
- self.checkFill("a.txt")
- self.checkFill("child/a.txt")
- self.checkFill("child/grandkid/a.txt")
-
-
-class SplatTmplWithSubdirectories(CFBase):
- def testCompile(self):
- self.go("cheetah compile *.tmpl child/*.tmpl child/grandkid/*.tmpl")
- self.checkCompile("a.py")
- self.checkCompile("child/a.py")
- self.checkCompile("child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill *.tmpl child/*.tmpl child/grandkid/*.tmpl")
- self.checkFill("a.html")
- self.checkFill("child/a.html")
- self.checkFill("child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill --oext txt *.tmpl child/*.tmpl child/grandkid/*.tmpl")
- self.checkFill("a.txt")
- self.checkFill("child/a.txt")
- self.checkFill("child/grandkid/a.txt")
-
-
-class OneFileWithOdir(CFBase):
- def testCompile(self):
- self.go("cheetah compile --odir DEST a.tmpl")
- self.checkSubdirPyInit("DEST")
- self.checkCompile("DEST/a.py")
-
- def testFill(self):
- self.go("cheetah fill --odir DEST a.tmpl")
- self.checkFill("DEST/a.html")
-
- def testText(self):
- self.go("cheetah fill --odir DEST --oext txt a.tmpl")
- self.checkFill("DEST/a.txt")
-
-
-class VarietyWithOdir(CFBase):
- def testCompile(self):
- self.go("cheetah compile --odir DEST a.tmpl child/a child/grandkid/*.tmpl")
- self.checkSubdirPyInit("DEST")
- self.checkSubdirPyInit("DEST/child")
- self.checkSubdirPyInit("DEST/child/grandkid")
- self.checkCompile("DEST/a.py")
- self.checkCompile("DEST/child/a.py")
- self.checkCompile("DEST/child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill --odir DEST a.tmpl child/a child/grandkid/*.tmpl")
- self.checkFill("DEST/a.html")
- self.checkFill("DEST/child/a.html")
- self.checkFill("DEST/child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill --odir DEST --oext txt a.tmpl child/a child/grandkid/*.tmpl")
- self.checkFill("DEST/a.txt")
- self.checkFill("DEST/child/a.txt")
- self.checkFill("DEST/child/grandkid/a.txt")
-
-
-class RecurseExplicit(CFBase):
- def testCompile(self):
- self.go("cheetah compile -R child")
- self.checkCompile("child/a.py")
- self.checkCompile("child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill -R child")
- self.checkFill("child/a.html")
- self.checkFill("child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill -R --oext txt child")
- self.checkFill("child/a.txt")
- self.checkFill("child/grandkid/a.txt")
-
-
-class RecurseImplicit(CFBase):
- def testCompile(self):
- self.go("cheetah compile -R")
- self.checkCompile("child/a.py")
- self.checkCompile("child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill -R")
- self.checkFill("a.html")
- self.checkFill("child/a.html")
- self.checkFill("child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill -R --oext txt")
- self.checkFill("a.txt")
- self.checkFill("child/a.txt")
- self.checkFill("child/grandkid/a.txt")
-
-
-class RecurseExplicitWIthOdir(CFBase):
- def testCompile(self):
- self.go("cheetah compile -R --odir DEST child")
- self.checkSubdirPyInit("DEST/child")
- self.checkSubdirPyInit("DEST/child/grandkid")
- self.checkCompile("DEST/child/a.py")
- self.checkCompile("DEST/child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill -R --odir DEST child")
- self.checkFill("DEST/child/a.html")
- self.checkFill("DEST/child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill -R --odir DEST --oext txt child")
- self.checkFill("DEST/child/a.txt")
- self.checkFill("DEST/child/grandkid/a.txt")
-
-
-class Flat(CFBase):
- def testCompile(self):
- self.go("cheetah compile --flat child/a.tmpl")
- self.checkCompile("a.py")
-
- def testFill(self):
- self.go("cheetah fill --flat child/a.tmpl")
- self.checkFill("a.html")
-
- def testText(self):
- self.go("cheetah fill --flat --oext txt child/a.tmpl")
- self.checkFill("a.txt")
-
-
-class FlatRecurseCollision(CFBase):
- expectError = True
-
- def testCompile(self):
- self.assertSubprocess("cheetah compile -R --flat", nonzero=True)
-
- def testFill(self):
- self.assertSubprocess("cheetah fill -R --flat", nonzero=True)
-
- def testText(self):
- self.assertSubprocess("cheetah fill -R --flat", nonzero=True)
-
-
-class IdirRecurse(CFIdirBase):
- def testCompile(self):
- self.go("cheetah compile -R --idir SRC child")
- self.checkSubdirPyInit("child")
- self.checkSubdirPyInit("child/grandkid")
- self.checkCompile("child/a.py")
- self.checkCompile("child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill -R --idir SRC child")
- self.checkFill("child/a.html")
- self.checkFill("child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill -R --idir SRC --oext txt child")
- self.checkFill("child/a.txt")
- self.checkFill("child/grandkid/a.txt")
-
-
-class IdirOdirRecurse(CFIdirBase):
- def testCompile(self):
- self.go("cheetah compile -R --idir SRC --odir DEST child")
- self.checkSubdirPyInit("DEST/child")
- self.checkSubdirPyInit("DEST/child/grandkid")
- self.checkCompile("DEST/child/a.py")
- self.checkCompile("DEST/child/grandkid/a.py")
-
- def testFill(self):
- self.go("cheetah fill -R --idir SRC --odir DEST child")
- self.checkFill("DEST/child/a.html")
- self.checkFill("DEST/child/grandkid/a.html")
-
- def testText(self):
- self.go("cheetah fill -R --idir SRC --odir DEST --oext txt child")
- self.checkFill("DEST/child/a.txt")
- self.checkFill("DEST/child/grandkid/a.txt")
-
-
-class IdirFlatRecurseCollision(CFIdirBase):
- expectError = True
-
- def testCompile(self):
- self.assertSubprocess("cheetah compile -R --flat --idir SRC", nonzero=True)
-
- def testFill(self):
- self.assertSubprocess("cheetah fill -R --flat --idir SRC", nonzero=True)
-
- def testText(self):
- self.assertSubprocess("cheetah fill -R --flat --idir SRC --oext txt", nonzero=True)
-
-
-class NoBackup(CFBase):
- """Run the command twice each time and verify a backup file is
- *not* created.
- """
- def testCompile(self):
- self.go("cheetah compile --nobackup a.tmpl")
- self.go("cheetah compile --nobackup a.tmpl")
- self.checkNoBackup("a.py" + BACKUP_SUFFIX)
-
- def testFill(self):
- self.go("cheetah fill --nobackup a.tmpl")
- self.go("cheetah fill --nobackup a.tmpl")
- self.checkNoBackup("a.html" + BACKUP_SUFFIX)
-
- def testText(self):
- self.go("cheetah fill --nobackup --oext txt a.tmpl")
- self.go("cheetah fill --nobackup --oext txt a.tmpl")
- self.checkNoBackup("a.txt" + BACKUP_SUFFIX)
-
-def listTests(cheetahWrapperFile):
- """cheetahWrapperFile, string, path of this script.
-
- XXX TODO: don't print test where expectError is true.
- """
- rx = re.compile( R'self\.go\("(.*?)"\)' )
- f = open(cheetahWrapperFile)
- while True:
- lin = f.readline()
- if not lin:
- break
- m = rx.search(lin)
- if m:
- print(m.group(1))
- f.close()
-
-def main():
- global DELETE, OUTPUT
- parser = OptionParser()
- parser.add_option("--list", action="store", dest="listTests")
- parser.add_option("--nodelete", action="store_true")
- parser.add_option("--output", action="store_true")
- # The following options are passed to unittest.
- parser.add_option("-e", "--explain", action="store_true")
- parser.add_option("-v", "--verbose", action="store_true")
- parser.add_option("-q", "--quiet", action="store_true")
- opts, files = parser.parse_args()
- if opts.nodelete:
- DELETE = False
- if opts.output:
- OUTPUT = True
- if opts.listTests:
- listTests(opts.listTests)
- else:
- # Eliminate script-specific command-line arguments to prevent
- # errors in unittest.
- del sys.argv[1:]
- for opt in ("explain", "verbose", "quiet"):
- if getattr(opts, opt):
- sys.argv.append("--" + opt)
- sys.argv.extend(files)
- unittest.main()
-
-if __name__ == '__main__':
- main()
-
-# vim: sw=4 ts=4 expandtab
Index: cheetah/Cheetah/Tests/Cheps.py
===================================================================
--- cheetah/Cheetah/Tests/Cheps.py (revision 19111)
+++ cheetah/Cheetah/Tests/Cheps.py (nonexistent)
@@ -1,39 +0,0 @@
-#!/usr/bin/env python
-
-import unittest
-
-import Cheetah
-import Cheetah.Parser
-import Cheetah.Template
-
-class Chep_2_Conditionalized_Import_Behavior(unittest.TestCase):
- def test_ModuleLevelImport(self):
- ''' Verify module level (traditional) import behavior '''
- pass
-
- def test_InlineImport(self):
- ''' Verify (new) inline import behavior works '''
- template = '''
- #def funky($s)
- #try
- #import urllib
- #except ImportError
- #pass
- #end try
- #return urllib.quote($s)
- #end def
- '''
- try:
- template = Cheetah.Template.Template.compile(template)
- except Cheetah.Parser.ParseError, ex:
- self.fail('Failed to properly generate code %s' % ex)
- template = template()
- rc = tepmlate.funky('abc def')
- assert rc == 'abc+def'
-
- def test_LegacyMode(self):
- ''' Verify disabling of CHEP #2 works '''
- pass
-
-if __name__ == '__main__':
- unittest.main()
Index: cheetah/Cheetah/Tests/Filters.py
===================================================================
--- cheetah/Cheetah/Tests/Filters.py (revision 19111)
+++ cheetah/Cheetah/Tests/Filters.py (nonexistent)
@@ -1,70 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import unittest
-
-import Cheetah.Template
-import Cheetah.Filters
-
-majorVer, minorVer = sys.version_info[0], sys.version_info[1]
-versionTuple = (majorVer, minorVer)
-
-class BasicMarkdownFilterTest(unittest.TestCase):
- '''
- Test that our markdown filter works
- '''
- def test_BasicHeader(self):
- template = '''
-#from Cheetah.Filters import Markdown
-#transform Markdown
-$foo
-
-Header
-======
- '''
- expected = '''<p>bar</p>
-<h1>Header</h1>'''
- try:
- template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}])
- template = str(template)
- assert template == expected
- except ImportError, ex:
- print('>>> We probably failed to import markdown, bummer %s' % ex)
- return
- except Exception, ex:
- if ex.__class__.__name__ == 'MarkdownException' and majorVer == 2 and minorVer < 5:
- print('>>> NOTE: Support for the Markdown filter will be broken for you. Markdown says: %s' % ex)
- return
- raise
-
-
-class BasicCodeHighlighterFilterTest(unittest.TestCase):
- '''
- Test that our code highlighter filter works
- '''
- def test_Python(self):
- template = '''
-#from Cheetah.Filters import CodeHighlighter
-#transform CodeHighlighter
-
-def foo(self):
- return '$foo'
- '''
- template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}])
- template = str(template)
- assert template, (template, 'We should have some content here...')
-
- def test_Html(self):
- template = '''
-#from Cheetah.Filters import CodeHighlighter
-#transform CodeHighlighter
-
-<html><head></head><body>$foo</body></html>
- '''
- template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}])
- template = str(template)
- assert template, (template, 'We should have some content here...')
-
-
-if __name__ == '__main__':
- unittest.main()
Index: cheetah/Cheetah/Tests/Misc.py
===================================================================
--- cheetah/Cheetah/Tests/Misc.py (revision 19111)
+++ cheetah/Cheetah/Tests/Misc.py (nonexistent)
@@ -1,20 +0,0 @@
-#!/usr/bin/env python
-
-import unittest
-
-from Cheetah import SettingsManager
-
-
-class SettingsManagerTests(unittest.TestCase):
- def test_mergeDictionaries(self):
- left = {'foo' : 'bar', 'abc' : {'a' : 1, 'b' : 2, 'c' : (3,)}}
- right = {'xyz' : (10, 9)}
- expect = {'xyz': (10, 9), 'foo': 'bar', 'abc': {'a': 1, 'c': (3,), 'b': 2}}
-
- result = SettingsManager.mergeNestedDictionaries(left, right)
- self.assertEquals(result, expect)
-
-
-if __name__ == '__main__':
- unittest.main()
-
Index: cheetah/Cheetah/Tests/NameMapper.py
===================================================================
--- cheetah/Cheetah/Tests/NameMapper.py (revision 19111)
+++ cheetah/Cheetah/Tests/NameMapper.py (nonexistent)
@@ -1,548 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import types
-import os
-import os.path
-
-import unittest
-from Cheetah.NameMapper import NotFound, valueForKey, \
- valueForName, valueFromSearchList, valueFromFrame, valueFromFrameOrSearchList
-
-
-class DummyClass(object):
- classVar1 = 123
-
- def __init__(self):
- self.instanceVar1 = 123
-
- def __str__(self):
- return 'object'
-
- def meth(self, arg="arff"):
- return str(arg)
-
- def meth1(self, arg="doo"):
- return arg
-
- def meth2(self, arg1="a1", arg2="a2"):
- raise ValueError
-
- def meth3(self):
- """Tests a bug that Jeff Johnson reported on Oct 1, 2001"""
-
- x = 'A string'
- try:
- for i in [1, 2, 3, 4]:
- if x == 2:
- pass
-
- if x == 'xx':
- pass
- return x
- except:
- raise
-
-class DummyClassGetAttrRaises(object):
- def __getattr__(self, name):
- raise ValueError
-
-
-def dummyFunc(arg="Scooby"):
- return arg
-
-def funcThatRaises():
- raise ValueError
-
-
-testNamespace = {
- 'aStr': 'blarg',
- 'anInt': 1,
- 'aFloat': 1.5,
- 'aDict': {'one': 'item1',
- 'two': 'item2',
- 'nestedDict': {'one': 'nestedItem1',
- 'two': 'nestedItem2',
- 'funcThatRaises': funcThatRaises,
- 'aClass': DummyClass,
- },
- 'nestedFunc': dummyFunc,
- },
- 'aClass': DummyClass,
- 'aFunc': dummyFunc,
- 'anObj': DummyClass(),
- 'anObjThatRaises': DummyClassGetAttrRaises(),
- 'aMeth': DummyClass().meth1,
- 'none': None,
- 'emptyString': '',
- 'funcThatRaises': funcThatRaises,
- }
-
-autoCallResults = {'aFunc': 'Scooby',
- 'aMeth': 'doo',
- }
-
-results = testNamespace.copy()
-results.update({'anObj.meth1': 'doo',
- 'aDict.one': 'item1',
- 'aDict.nestedDict': testNamespace['aDict']['nestedDict'],
- 'aDict.nestedDict.one': 'nestedItem1',
- 'aDict.nestedDict.aClass': DummyClass,
- 'aDict.nestedFunc': 'Scooby',
- 'aClass.classVar1': 123,
- 'anObj.instanceVar1': 123,
- 'anObj.meth3': 'A string',
- })
-
-for k in testNamespace.keys():
- # put them in the globals for the valueFromFrame tests
- exec('%s = testNamespace[k]'%k)
-
-##################################################
-## TEST BASE CLASSES
-
-class NameMapperTest(unittest.TestCase):
- failureException = NotFound
- _testNamespace = testNamespace
- _results = results
-
- def namespace(self):
- return self._testNamespace
-
- def VFN(self, name, autocall=True):
- return valueForName(self.namespace(), name, autocall)
-
- def VFS(self, searchList, name, autocall=True):
- return valueFromSearchList(searchList, name, autocall)
-
-
- # alias to be overriden later
- get = VFN
-
- def check(self, name):
- got = self.get(name)
- if name in autoCallResults:
- expected = autoCallResults[name]
- else:
- expected = self._results[name]
- assert got == expected
-
-
-##################################################
-## TEST CASE CLASSES
-
-class VFN(NameMapperTest):
-
- def test1(self):
- """string in dict lookup"""
- self.check('aStr')
-
- def test2(self):
- """string in dict lookup in a loop"""
- for i in range(10):
- self.check('aStr')
-
- def test3(self):
- """int in dict lookup"""
- self.check('anInt')
-
- def test4(self):
- """int in dict lookup in a loop"""
- for i in range(10):
- self.check('anInt')
-
- def test5(self):
- """float in dict lookup"""
- self.check('aFloat')
-
- def test6(self):
- """float in dict lookup in a loop"""
- for i in range(10):
- self.check('aFloat')
-
- def test7(self):
- """class in dict lookup"""
- self.check('aClass')
-
- def test8(self):
- """class in dict lookup in a loop"""
- for i in range(10):
- self.check('aClass')
-
- def test9(self):
- """aFunc in dict lookup"""
- self.check('aFunc')
-
- def test10(self):
- """aFunc in dict lookup in a loop"""
- for i in range(10):
- self.check('aFunc')
-
- def test11(self):
- """aMeth in dict lookup"""
- self.check('aMeth')
-
- def test12(self):
- """aMeth in dict lookup in a loop"""
- for i in range(10):
- self.check('aMeth')
-
- def test13(self):
- """aMeth in dict lookup"""
- self.check('aMeth')
-
- def test14(self):
- """aMeth in dict lookup in a loop"""
- for i in range(10):
- self.check('aMeth')
-
- def test15(self):
- """anObj in dict lookup"""
- self.check('anObj')
-
- def test16(self):
- """anObj in dict lookup in a loop"""
- for i in range(10):
- self.check('anObj')
-
- def test17(self):
- """aDict in dict lookup"""
- self.check('aDict')
-
- def test18(self):
- """aDict in dict lookup in a loop"""
- for i in range(10):
- self.check('aDict')
-
- def test17(self):
- """aDict in dict lookup"""
- self.check('aDict')
-
- def test18(self):
- """aDict in dict lookup in a loop"""
- for i in range(10):
- self.check('aDict')
-
- def test19(self):
- """aClass.classVar1 in dict lookup"""
- self.check('aClass.classVar1')
-
- def test20(self):
- """aClass.classVar1 in dict lookup in a loop"""
- for i in range(10):
- self.check('aClass.classVar1')
-
-
- def test23(self):
- """anObj.instanceVar1 in dict lookup"""
- self.check('anObj.instanceVar1')
-
- def test24(self):
- """anObj.instanceVar1 in dict lookup in a loop"""
- for i in range(10):
- self.check('anObj.instanceVar1')
-
- ## tests 22, 25, and 26 removed when the underscored lookup was removed
-
- def test27(self):
- """anObj.meth1 in dict lookup"""
- self.check('anObj.meth1')
-
- def test28(self):
- """anObj.meth1 in dict lookup in a loop"""
- for i in range(10):
- self.check('anObj.meth1')
-
- def test29(self):
- """aDict.one in dict lookup"""
- self.check('aDict.one')
-
- def test30(self):
- """aDict.one in dict lookup in a loop"""
- for i in range(10):
- self.check('aDict.one')
-
- def test31(self):
- """aDict.nestedDict in dict lookup"""
- self.check('aDict.nestedDict')
-
- def test32(self):
- """aDict.nestedDict in dict lookup in a loop"""
- for i in range(10):
- self.check('aDict.nestedDict')
-
- def test33(self):
- """aDict.nestedDict.one in dict lookup"""
- self.check('aDict.nestedDict.one')
-
- def test34(self):
- """aDict.nestedDict.one in dict lookup in a loop"""
- for i in range(10):
- self.check('aDict.nestedDict.one')
-
- def test35(self):
- """aDict.nestedFunc in dict lookup"""
- self.check('aDict.nestedFunc')
-
- def test36(self):
- """aDict.nestedFunc in dict lookup in a loop"""
- for i in range(10):
- self.check('aDict.nestedFunc')
-
- def test37(self):
- """aDict.nestedFunc in dict lookup - without autocalling"""
- assert self.get('aDict.nestedFunc', False) == dummyFunc
-
- def test38(self):
- """aDict.nestedFunc in dict lookup in a loop - without autocalling"""
- for i in range(10):
- assert self.get('aDict.nestedFunc', False) == dummyFunc
-
- def test39(self):
- """aMeth in dict lookup - without autocalling"""
- assert self.get('aMeth', False) == self.namespace()['aMeth']
-
- def test40(self):
- """aMeth in dict lookup in a loop - without autocalling"""
- for i in range(10):
- assert self.get('aMeth', False) == self.namespace()['aMeth']
-
- def test41(self):
- """anObj.meth3 in dict lookup"""
- self.check('anObj.meth3')
-
- def test42(self):
- """aMeth in dict lookup in a loop"""
- for i in range(10):
- self.check('anObj.meth3')
-
- def test43(self):
- """NotFound test"""
-
- def test(self=self):
- self.get('anObj.methX')
- self.assertRaises(NotFound, test)
-
- def test44(self):
- """NotFound test in a loop"""
- def test(self=self):
- self.get('anObj.methX')
-
- for i in range(10):
- self.assertRaises(NotFound, test)
-
- def test45(self):
- """Other exception from meth test"""
-
- def test(self=self):
- self.get('anObj.meth2')
- self.assertRaises(ValueError, test)
-
- def test46(self):
- """Other exception from meth test in a loop"""
- def test(self=self):
- self.get('anObj.meth2')
-
- for i in range(10):
- self.assertRaises(ValueError, test)
-
- def test47(self):
- """None in dict lookup"""
- self.check('none')
-
- def test48(self):
- """None in dict lookup in a loop"""
- for i in range(10):
- self.check('none')
-
- def test49(self):
- """EmptyString in dict lookup"""
- self.check('emptyString')
-
- def test50(self):
- """EmptyString in dict lookup in a loop"""
- for i in range(10):
- self.check('emptyString')
-
- def test51(self):
- """Other exception from func test"""
-
- def test(self=self):
- self.get('funcThatRaises')
- self.assertRaises(ValueError, test)
-
- def test52(self):
- """Other exception from func test in a loop"""
- def test(self=self):
- self.get('funcThatRaises')
-
- for i in range(10):
- self.assertRaises(ValueError, test)
-
-
- def test53(self):
- """Other exception from func test"""
-
- def test(self=self):
- self.get('aDict.nestedDict.funcThatRaises')
- self.assertRaises(ValueError, test)
-
- def test54(self):
- """Other exception from func test in a loop"""
- def test(self=self):
- self.get('aDict.nestedDict.funcThatRaises')
-
- for i in range(10):
- self.assertRaises(ValueError, test)
-
- def test55(self):
- """aDict.nestedDict.aClass in dict lookup"""
- self.check('aDict.nestedDict.aClass')
-
- def test56(self):
- """aDict.nestedDict.aClass in dict lookup in a loop"""
- for i in range(10):
- self.check('aDict.nestedDict.aClass')
-
- def test57(self):
- """aDict.nestedDict.aClass in dict lookup - without autocalling"""
- assert self.get('aDict.nestedDict.aClass', False) == DummyClass
-
- def test58(self):
- """aDict.nestedDict.aClass in dict lookup in a loop - without autocalling"""
- for i in range(10):
- assert self.get('aDict.nestedDict.aClass', False) == DummyClass
-
- def test59(self):
- """Other exception from func test -- but without autocalling shouldn't raise"""
-
- self.get('aDict.nestedDict.funcThatRaises', False)
-
- def test60(self):
- """Other exception from func test in a loop -- but without autocalling shouldn't raise"""
-
- for i in range(10):
- self.get('aDict.nestedDict.funcThatRaises', False)
-
- def test61(self):
- """Accessing attribute where __getattr__ raises shouldn't segfault if something follows it"""
-
- def test(self=self):
- self.get('anObjThatRaises.willraise.anything')
- self.assertRaises(ValueError, test)
-
-
-class VFS(VFN):
- _searchListLength = 1
-
- def searchList(self):
- lng = self._searchListLength
- if lng == 1:
- return [self.namespace()]
- elif lng == 2:
- return [self.namespace(), {'dummy':1234}]
- elif lng == 3:
- # a tuple for kicks
- return ({'dummy':1234}, self.namespace(), {'dummy':1234})
- elif lng == 4:
- # a generator for more kicks
- return self.searchListGenerator()
-
- def searchListGenerator(self):
- class Test:
- pass
- for i in [Test(), {'dummy':1234}, self.namespace(), {'dummy':1234}]:
- yield i
-
- def get(self, name, autocall=True):
- return self.VFS(self.searchList(), name, autocall)
-
-class VFS_2namespaces(VFS):
- _searchListLength = 2
-
-class VFS_3namespaces(VFS):
- _searchListLength = 3
-
-class VFS_4namespaces(VFS):
- _searchListLength = 4
-
-class VFF(VFN):
- def get(self, name, autocall=True):
- ns = self._testNamespace
- aStr = ns['aStr']
- aFloat = ns['aFloat']
- none = 'some'
- return valueFromFrame(name, autocall)
-
- def setUp(self):
- """Mod some of the data
- """
- self._testNamespace = ns = self._testNamespace.copy()
- self._results = res = self._results.copy()
- ns['aStr'] = res['aStr'] = 'BLARG'
- ns['aFloat'] = res['aFloat'] = 0.1234
- res['none'] = 'some'
- res['True'] = True
- res['False'] = False
- res['None'] = None
- res['eval'] = eval
-
- def test_VFF_1(self):
- """Builtins"""
- self.check('True')
- self.check('None')
- self.check('False')
- assert self.get('eval', False)==eval
- assert self.get('range', False)==range
-
-class VFFSL(VFS):
- _searchListLength = 1
-
- def setUp(self):
- """Mod some of the data
- """
- self._testNamespace = ns = self._testNamespace.copy()
- self._results = res = self._results.copy()
- ns['aStr'] = res['aStr'] = 'BLARG'
- ns['aFloat'] = res['aFloat'] = 0.1234
- res['none'] = 'some'
-
- del ns['anInt'] # will be picked up by globals
-
- def VFFSL(self, searchList, name, autocall=True):
- anInt = 1
- none = 'some'
- return valueFromFrameOrSearchList(searchList, name, autocall)
-
- def get(self, name, autocall=True):
- return self.VFFSL(self.searchList(), name, autocall)
-
-class VFFSL_2(VFFSL):
- _searchListLength = 2
-
-class VFFSL_3(VFFSL):
- _searchListLength = 3
-
-class VFFSL_4(VFFSL):
- _searchListLength = 4
-
-if sys.platform.startswith('java'):
- del VFF, VFFSL, VFFSL_2, VFFSL_3, VFFSL_4
-
-
-class MapBuiltins(unittest.TestCase):
- def test_int(self):
- from Cheetah.Template import Template
- t = Template('''
- #def intify(val)
- #return $int(val)
- #end def''', compilerSettings={'useStackFrames' : False})
- self.assertEquals(5, t.intify('5'))
-
-
-
-##################################################
-## if run from the command line ##
-
-if __name__ == '__main__':
- unittest.main()
Index: cheetah/Cheetah/Tests/Parser.py
===================================================================
--- cheetah/Cheetah/Tests/Parser.py (revision 19111)
+++ cheetah/Cheetah/Tests/Parser.py (nonexistent)
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-
-import unittest
-
-from Cheetah import Parser
-
-class ArgListTest(unittest.TestCase):
- def setUp(self):
- super(ArgListTest, self).setUp()
- self.al = Parser.ArgList()
-
- def test_merge1(self):
- '''
- Testing the ArgList case results from Template.Preprocessors.test_complexUsage
- '''
- self.al.add_argument('arg')
- expect = [('arg', None)]
-
- self.assertEquals(expect, self.al.merge())
-
- def test_merge2(self):
- '''
- Testing the ArgList case results from SyntaxAndOutput.BlockDirective.test4
- '''
- self.al.add_argument('a')
- self.al.add_default('999')
- self.al.next()
- self.al.add_argument('b')
- self.al.add_default('444')
-
- expect = [(u'a', u'999'), (u'b', u'444')]
-
- self.assertEquals(expect, self.al.merge())
-
-
-
- def test_merge3(self):
- '''
- Testing the ArgList case results from SyntaxAndOutput.BlockDirective.test13
- '''
- self.al.add_argument('arg')
- self.al.add_default("'This is my block'")
- expect = [('arg', "'This is my block'")]
-
- self.assertEquals(expect, self.al.merge())
-
-if __name__ == '__main__':
- unittest.main()
-
Index: cheetah/Cheetah/Tests/Performance.py
===================================================================
--- cheetah/Cheetah/Tests/Performance.py (revision 19111)
+++ cheetah/Cheetah/Tests/Performance.py (nonexistent)
@@ -1,243 +0,0 @@
-#!/usr/bin/env python
-
-import hotshot
-import hotshot.stats
-import os
-import sys
-import unittest
-
-from test import pystone
-import time
-
-import Cheetah.NameMapper
-import Cheetah.Template
-
-# This can be turned on with the `--debug` flag when running the test
-# and will cause the tests to all just dump out how long they took
-# insteasd of asserting on duration
-DEBUG = False
-
-# TOLERANCE in Pystones
-kPS = 1000
-TOLERANCE = 0.5*kPS
-
-class DurationError(AssertionError):
- pass
-
-_pystone_calibration_mark = None
-def _pystone_calibration():
- global _pystone_calibration_mark
- if not _pystone_calibration_mark:
- _pystone_calibration_mark = pystone.pystones(loops=pystone.LOOPS)
- return _pystone_calibration_mark
-
-def perftest(max_num_pystones, current_pystone=None):
- '''
- Performance test decorator based off the 'timedtest'
- decorator found in this Active State recipe:
- http://code.activestate.com/recipes/440700/
- '''
- if not isinstance(max_num_pystones, float):
- max_num_pystones = float(max_num_pystones)
-
- if not current_pystone:
- current_pystone = _pystone_calibration()
-
- def _test(function):
- def wrapper(*args, **kw):
- start_time = time.time()
- try:
- return function(*args, **kw)
- finally:
- total_time = time.time() - start_time
- if total_time == 0:
- pystone_total_time = 0
- else:
- pystone_rate = current_pystone[0] / current_pystone[1]
- pystone_total_time = total_time / pystone_rate
- global DEBUG
- if DEBUG:
- print('The test "%s" took: %s pystones' % (function.func_name,
- pystone_total_time))
- else:
- if pystone_total_time > (max_num_pystones + TOLERANCE):
- raise DurationError((('Test too long (%.2f Ps, '
- 'need at most %.2f Ps)')
- % (pystone_total_time,
- max_num_pystones)))
- return wrapper
- return _test
-
-
-class DynamicTemplatePerformanceTest(unittest.TestCase):
- loops = 10
- #@perftest(1200)
- def test_BasicDynamic(self):
- template = '''
- #def foo(arg1, arg2)
- #pass
- #end def
- '''
- for i in range(self.loops):
- klass = Cheetah.Template.Template.compile(template)
- assert klass
- test_BasicDynamic = perftest(1200)(test_BasicDynamic)
-
-class PerformanceTest(unittest.TestCase):
- iterations = 100000
- display = False
- save = False
-
- def runTest(self):
- self.prof = hotshot.Profile('%s.prof' % self.__class__.__name__)
- self.prof.start()
- for i in range(self.iterations):
- if hasattr(self, 'performanceSample'):
- self.display = True
- self.performanceSample()
- self.prof.stop()
- self.prof.close()
- if self.display:
- print('>>> %s (%d iterations) ' % (self.__class__.__name__,
- self.iterations))
- stats = hotshot.stats.load('%s.prof' % self.__class__.__name__)
- #stats.strip_dirs()
- stats.sort_stats('time', 'calls')
- stats.print_stats(50)
-
- if not self.save:
- os.unlink('%s.prof' % self.__class__.__name__)
-
-class DynamicMethodCompilationTest(PerformanceTest):
- def performanceSample(self):
- template = '''
- #import sys
- #import os
- #def testMethod()
- #set foo = [1, 2, 3, 4]
- #return $foo[0]
- #end def
- '''
- template = Cheetah.Template.Template.compile(template,
- keepRefToGeneratedCode=False)
- template = template()
- value = template.testMethod()
-
-
-class BunchOfWriteCalls(PerformanceTest):
- iterations = 1000
- def performanceSample(self):
- template = '''
- #import sys
- #import os
- #for i in range(1000)
- $i
- #end for
- '''
- template = Cheetah.Template.Template.compile(template,
- keepRefToGeneratedCode=False)
- template = template()
- value = template.respond()
- del value
-
-class DynamicSimpleCompilationTest(PerformanceTest):
- def performanceSample(self):
- template = '''
- #import sys
- #import os
- #set foo = [1,2,3,4]
-
- Well hello there! This is basic.
-
- Here's an array too: $foo
- '''
- template = Cheetah.Template.Template.compile(template,
- keepRefToGeneratedCode=False)
- template = template()
- template = unicode(template)
-
-
-class FilterTest(PerformanceTest):
- template = None
- def setUp(self):
- super(FilterTest, self).setUp()
- template = '''
- #import sys
- #import os
- #set foo = [1, 2, 3, 4]
-
- $foo, $foo, $foo
- '''
- template = Cheetah.Template.Template.compile(template,
- keepRefToGeneratedCode=False)
- self.template = template()
-
- def performanceSample(self):
- value = unicode(self.template)
-
-
-class LongCompileTest(PerformanceTest):
- ''' Test the compilation on a sufficiently large template '''
- def compile(self, template):
- return Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False)
-
- def performanceSample(self):
- template = '''
- #import sys
- #import Cheetah.Template
-
- #extends Cheetah.Template.Template
-
- #def header()
- <center><h2>This is my header</h2></center>
- #end def
-
- #def footer()
- #return "Huzzah"
- #end def
-
- #def scripts()
- #pass
- #end def
-
- #def respond()
- <html>
- <head>
- <title>${title}</title>
-
- $scripts()
- </head>
- <body>
- $header()
-
- #for $i in $range(10)
- This is just some stupid page!
- <br/>
- #end for
-
- <br/>
- $footer()
- </body>
- </html>
- #end def
-
- '''
- return self.compile(template)
-
-class LongCompile_CompilerSettingsTest(LongCompileTest):
- def compile(self, template):
- return Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False,
- compilerSettings={'useStackFrames' : True, 'useAutocalling' : True})
-
-class LongCompileAndRun(LongCompileTest):
- def performanceSample(self):
- template = super(LongCompileAndRun, self).performanceSample()
- template = template(searchList=[{'title' : 'foo'}])
- template = template.respond()
-
-
-if __name__ == '__main__':
- if '--debug' in sys.argv:
- DEBUG = True
- sys.argv = [arg for arg in sys.argv if not arg == '--debug']
- unittest.main()
Index: cheetah/Cheetah/Tests/Regressions.py
===================================================================
--- cheetah/Cheetah/Tests/Regressions.py (revision 19111)
+++ cheetah/Cheetah/Tests/Regressions.py (nonexistent)
@@ -1,247 +0,0 @@
-#!/usr/bin/env python
-
-import Cheetah.NameMapper
-import Cheetah.Template
-
-import sys
-import unittest
-
-
-majorVer, minorVer = sys.version_info[0], sys.version_info[1]
-versionTuple = (majorVer, minorVer)
-
-def isPython23():
- ''' Python 2.3 is still supported by Cheetah, but doesn't support decorators '''
- return majorVer == 2 and minorVer < 4
-
-class GetAttrException(Exception):
- pass
-
-class CustomGetAttrClass(object):
- def __getattr__(self, name):
- raise GetAttrException('FAIL, %s' % name)
-
-class GetAttrTest(unittest.TestCase):
- '''
- Test for an issue occurring when __getatttr__() raises an exception
- causing NameMapper to raise a NotFound exception
- '''
- def test_ValidException(self):
- o = CustomGetAttrClass()
- try:
- print(o.attr)
- except GetAttrException, e:
- # expected
- return
- except:
- self.fail('Invalid exception raised: %s' % e)
- self.fail('Should have had an exception raised')
-
- def test_NotFoundException(self):
- template = '''
- #def raiseme()
- $obj.attr
- #end def'''
-
- template = Cheetah.Template.Template.compile(template, compilerSettings={}, keepRefToGeneratedCode=True)
- template = template(searchList=[{'obj' : CustomGetAttrClass()}])
- assert template, 'We should have a valid template object by now'
-
- self.failUnlessRaises(GetAttrException, template.raiseme)
-
-
-class InlineImportTest(unittest.TestCase):
- def test_FromFooImportThing(self):
- '''
- Verify that a bug introduced in v2.1.0 where an inline:
- #from module import class
- would result in the following code being generated:
- import class
- '''
- template = '''
- #def myfunction()
- #if True
- #from os import path
- #return 17
- Hello!
- #end if
- #end def
- '''
- template = Cheetah.Template.Template.compile(template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True)
- template = template(searchList=[{}])
-
- assert template, 'We should have a valid template object by now'
-
- rc = template.myfunction()
- assert rc == 17, (template, 'Didn\'t get a proper return value')
-
- def test_ImportFailModule(self):
- template = '''
- #try
- #import invalidmodule
- #except
- #set invalidmodule = dict(FOO='BAR!')
- #end try
-
- $invalidmodule.FOO
- '''
- template = Cheetah.Template.Template.compile(template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True)
- template = template(searchList=[{}])
-
- assert template, 'We should have a valid template object by now'
- assert str(template), 'We weren\'t able to properly generate the result from the template'
-
- def test_ProperImportOfBadModule(self):
- template = '''
- #from invalid import fail
-
- This should totally $fail
- '''
- self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True)
-
- def test_AutoImporting(self):
- template = '''
- #extends FakeyTemplate
-
- Boo!
- '''
- self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template)
-
- def test_StuffBeforeImport_Legacy(self):
- template = '''
-###
-### I like comments before import
-###
-#extends Foo
-Bar
-'''
- self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template, compilerSettings={'useLegacyImportMode' : True}, keepRefToGeneratedCode=True)
-
-
-class Mantis_Issue_11_Regression_Test(unittest.TestCase):
- '''
- Test case for bug outlined in Mantis issue #11:
-
- Output:
- Traceback (most recent call last):
- File "test.py", line 12, in <module>
- t.respond()
- File "DynamicallyCompiledCheetahTemplate.py", line 86, in respond
- File "/usr/lib64/python2.6/cgi.py", line 1035, in escape
- s = s.replace("&", "&") # Must be done first!
- '''
- def test_FailingBehavior(self):
- import cgi
- template = Cheetah.Template.Template("$escape($request)", searchList=[{'escape' : cgi.escape, 'request' : 'foobar'}])
- assert template
- self.failUnlessRaises(AttributeError, template.respond)
-
-
- def test_FailingBehaviorWithSetting(self):
- import cgi
- template = Cheetah.Template.Template("$escape($request)",
- searchList=[{'escape' : cgi.escape, 'request' : 'foobar'}],
- compilerSettings={'prioritizeSearchListOverSelf' : True})
- assert template
- assert template.respond()
-
-class Mantis_Issue_21_Regression_Test(unittest.TestCase):
- '''
- Test case for bug outlined in issue #21
-
- Effectively @staticmethod and @classmethod
- decorated methods in templates don't
- properly define the _filter local, which breaks
- when using the NameMapper
- '''
- def runTest(self):
- if isPython23():
- return
- template = '''
- #@staticmethod
- #def testMethod()
- This is my $output
- #end def
- '''
- template = Cheetah.Template.Template.compile(template)
- assert template
- assert template.testMethod(output='bug') # raises a NameError: global name '_filter' is not defined
-
-
-class Mantis_Issue_22_Regression_Test(unittest.TestCase):
- '''
- Test case for bug outlined in issue #22
-
- When using @staticmethod and @classmethod
- in conjunction with the #filter directive
- the generated code for the #filter is reliant
- on the `self` local, breaking the function
- '''
- def test_NoneFilter(self):
- # XXX: Disabling this test for now
- return
- if isPython23():
- return
- template = '''
- #@staticmethod
- #def testMethod()
- #filter None
- This is my $output
- #end filter
- #end def
- '''
- template = Cheetah.Template.Template.compile(template)
- assert template
- assert template.testMethod(output='bug')
-
- def test_DefinedFilter(self):
- # XXX: Disabling this test for now
- return
- if isPython23():
- return
- template = '''
- #@staticmethod
- #def testMethod()
- #filter Filter
- This is my $output
- #end filter
- #end def
- '''
- # The generated code for the template's testMethod() should look something
- # like this in the 'error' case:
- '''
- @staticmethod
- def testMethod(**KWS):
- ## CHEETAH: generated from #def testMethod() at line 3, col 13.
- trans = DummyTransaction()
- _dummyTrans = True
- write = trans.response().write
- SL = [KWS]
- _filter = lambda x, **kwargs: unicode(x)
-
- ########################################
- ## START - generated method body
-
- _orig_filter_18517345 = _filter
- filterName = u'Filter'
- if self._CHEETAH__filters.has_key("Filter"):
- _filter = self._CHEETAH__currentFilter = self._CHEETAH__filters[filterName]
- else:
- _filter = self._CHEETAH__currentFilter = \
- self._CHEETAH__filters[filterName] = getattr(self._CHEETAH__filtersLib, filterName)(self).filter
- write(u' This is my ')
- _v = VFFSL(SL,"output",True) # u'$output' on line 5, col 32
- if _v is not None: write(_filter(_v, rawExpr=u'$output')) # from line 5, col 32.
-
- ########################################
- ## END - generated method body
-
- return _dummyTrans and trans.response().getvalue() or ""
- '''
- template = Cheetah.Template.Template.compile(template)
- assert template
- assert template.testMethod(output='bug')
-
-
-if __name__ == '__main__':
- unittest.main()
Index: cheetah/Cheetah/Tests/SyntaxAndOutput.py
===================================================================
--- cheetah/Cheetah/Tests/SyntaxAndOutput.py (revision 19111)
+++ cheetah/Cheetah/Tests/SyntaxAndOutput.py (nonexistent)
@@ -1,3253 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: latin-1 -*-
-
-'''
-Syntax and Output tests.
-
-TODO
-- #finally
-- #filter
-- #errorCatcher
-- #echo
-- #silent
-'''
-
-
-##################################################
-## DEPENDENCIES ##
-
-import sys
-import types
-import re
-from copy import deepcopy
-import os
-import os.path
-import warnings
-import unittest
-
-from Cheetah.NameMapper import NotFound
-from Cheetah.NameMapper import C_VERSION as NameMapper_C_VERSION
-from Cheetah.Template import Template
-from Cheetah.Parser import ParseError
-from Cheetah.Compiler import Compiler, DEFAULT_COMPILER_SETTINGS
-
-class Unspecified(object):
- pass
-
-majorVer, minorVer = sys.version_info[0], sys.version_info[1]
-versionTuple = (majorVer, minorVer)
-
-def testdecorator(func):
- return func
-
-class DummyClass:
- _called = False
- def __str__(self):
- return 'object'
-
- def meth(self, arg="arff"):
- return str(arg)
-
- def meth1(self, arg="doo"):
- return arg
-
- def meth2(self, arg1="a1", arg2="a2"):
- return str(arg1) + str(arg2)
-
- def methWithPercentSignDefaultArg(self, arg1="110%"):
- return str(arg1)
-
- def callIt(self, arg=1234):
- self._called = True
- self._callArg = arg
-
-
-def dummyFunc(arg="Scooby"):
- return arg
-
-defaultTestNameSpace = {
- 'aStr': 'blarg',
- 'anInt': 1,
- 'aFloat': 1.5,
- 'aList': ['item0', 'item1', 'item2'],
- 'aDict': {'one': 'item1',
- 'two': 'item2',
- 'nestedDict': {1:'nestedItem1',
- 'two':'nestedItem2'
- },
- 'nestedFunc': dummyFunc,
- },
- 'aFunc': dummyFunc,
- 'anObj': DummyClass(),
- 'aMeth': DummyClass().meth1,
- 'aStrToBeIncluded': "$aStr $anInt",
- 'none': None,
- 'emptyString': '',
- 'numOne': 1,
- 'numTwo': 2,
- 'zero': 0,
- 'tenDigits': 1234567890,
- 'webSafeTest': 'abc <=> &',
- 'strip1': ' \t strippable whitespace \t\t \n',
- 'strip2': ' \t strippable whitespace \t\t ',
- 'strip3': ' \t strippable whitespace \t\t\n1 2 3\n',
-
- 'blockToBeParsed': """$numOne $numTwo""",
- 'includeBlock2': """$numOne $numTwo $aSetVar""",
-
- 'includeFileName': 'parseTest.txt',
- 'listOfLambdas': [lambda x: x, lambda x: x, lambda x: x,],
- 'list': [
- {'index': 0, 'numOne': 1, 'numTwo': 2},
- {'index': 1, 'numOne': 1, 'numTwo': 2},
- ],
- 'nameList': [('john', 'doe'), ('jane', 'smith')],
- 'letterList': ['a', 'b', 'c'],
- '_': lambda x: 'Translated: ' + x,
- 'unicodeData': u'aoeu12345\u1234',
- }
-
-
-##################################################
-## TEST BASE CLASSES
-
-class OutputTest(unittest.TestCase):
- report = '''
-Template output mismatch:
-
- Input Template =
-%(template)s%(end)s
-
- Expected Output =
-%(expected)s%(end)s
-
- Actual Output =
-%(actual)s%(end)s'''
-
- convertEOLs = True
- _EOLreplacement = None
- _debugEOLReplacement = False
-
- DEBUGLEV = 0
- _searchList = [defaultTestNameSpace]
-
- _useNewStyleCompilation = True
- #_useNewStyleCompilation = False
-
- _extraCompileKwArgs = None
-
- def searchList(self):
- return self._searchList
-
- def verify(self, input, expectedOutput,
- inputEncoding=None,
- outputEncoding=None,
- convertEOLs=Unspecified):
- if self._EOLreplacement:
- if convertEOLs is Unspecified:
- convertEOLs = self.convertEOLs
- if convertEOLs:
- input = input.replace('\n', self._EOLreplacement)
- expectedOutput = expectedOutput.replace('\n', self._EOLreplacement)
-
- self._input = input
- if self._useNewStyleCompilation:
- extraKwArgs = self._extraCompileKwArgs or {}
-
- templateClass = Template.compile(
- source=input,
- compilerSettings=self._getCompilerSettings(),
- keepRefToGeneratedCode=True,
- **extraKwArgs
- )
- moduleCode = templateClass._CHEETAH_generatedModuleCode
- searchList = self.searchList() or self._searchList
- self.template = templateObj = templateClass(searchList=searchList)
- else:
- self.template = templateObj = Template(
- input,
- searchList=self.searchList(),
- compilerSettings=self._getCompilerSettings(),
- )
- moduleCode = templateObj._CHEETAH_generatedModuleCode
- if self.DEBUGLEV >= 1:
- print(moduleCode)
- try:
- output = templateObj.respond() # rather than __str__, because of unicode
- assert output==expectedOutput, self._outputMismatchReport(output, expectedOutput)
- finally:
- templateObj.shutdown()
-
- def _getCompilerSettings(self):
- return {}
-
- def _outputMismatchReport(self, output, expectedOutput):
- if self._debugEOLReplacement and self._EOLreplacement:
- EOLrepl = self._EOLreplacement
- marker = '*EOL*'
- return self.report % {'template': self._input.replace(EOLrepl, marker),
- 'expected': expectedOutput.replace(EOLrepl, marker),
- 'actual': output.replace(EOLrepl, marker),
- 'end': '(end)'}
- else:
- return self.report % {'template': self._input,
- 'expected': expectedOutput,
- 'actual': output,
- 'end': '(end)'}
-
- def genClassCode(self):
- if hasattr(self, 'template'):
- return self.template.generatedClassCode()
-
- def genModuleCode(self):
- if hasattr(self, 'template'):
- return self.template.generatedModuleCode()
-
-##################################################
-## TEST CASE CLASSES
-
-class EmptyTemplate(OutputTest):
- convertEOLs = False
- def test1(self):
- """an empty string for the template"""
-
- warnings.filterwarnings('error',
- 'You supplied an empty string for the source!',
- UserWarning)
- try:
- self.verify("", "")
- except UserWarning:
- pass
- else:
- self.fail("Should warn about empty source strings.")
-
- try:
- self.verify("#implements foo", "")
- except NotImplementedError:
- pass
- else:
- self.fail("This should barf about respond() not being implemented.")
-
- self.verify("#implements respond", "")
-
- self.verify("#implements respond(foo=1234)", "")
-
-
-class Backslashes(OutputTest):
- convertEOLs = False
-
- def setUp(self):
- fp = open('backslashes.txt', 'w')
- fp.write(r'\ #LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n')
- fp.flush()
- fp.close
-
- def tearDown(self):
- if os.path.exists('backslashes.txt'):
- os.remove('backslashes.txt')
-
- def test1(self):
- """ a single \\ using rawstrings"""
- self.verify(r"\ ",
- r"\ ")
-
- def test2(self):
- """ a single \\ using rawstrings and lots of lines"""
- self.verify(r"\ " + "\n\n\n\n\n\n\n\n\n",
- r"\ " + "\n\n\n\n\n\n\n\n\n")
-
- def test3(self):
- """ a single \\ without using rawstrings"""
- self.verify("\ \ ",
- "\ \ ")
-
- def test4(self):
- """ single line from an apache conf file"""
- self.verify(r'#LogFormat "%h %l %u %t \"%r\" %>s %b"',
- r'#LogFormat "%h %l %u %t \"%r\" %>s %b"')
-
- def test5(self):
- """ single line from an apache conf file with many NEWLINES
-
- The NEWLINES are used to make sure that MethodCompiler.commitStrConst()
- is handling long and short strings in the same fashion. It uses
- triple-quotes for strings with lots of \\n in them and repr(theStr) for
- shorter strings with only a few newlines."""
-
- self.verify(r'#LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n',
- r'#LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n')
-
- def test6(self):
- """ test backslash handling in an included file"""
- self.verify(r'#include "backslashes.txt"',
- r'\ #LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n')
-
- def test7(self):
- """ a single \\ without using rawstrings plus many NEWLINES"""
- self.verify("\ \ " + "\n\n\n\n\n\n\n\n\n",
- "\ \ " + "\n\n\n\n\n\n\n\n\n")
-
- def test8(self):
- """ single line from an apache conf file with single quotes and many NEWLINES
- """
-
- self.verify(r"""#LogFormat '%h %l %u %t \"%r\" %>s %b'""" + '\n\n\n\n\n\n\n',
- r"""#LogFormat '%h %l %u %t \"%r\" %>s %b'""" + '\n\n\n\n\n\n\n')
-
-class NonTokens(OutputTest):
- def test1(self):
- """dollar signs not in Cheetah $vars"""
- self.verify("$ $$ $5 $. $ test",
- "$ $$ $5 $. $ test")
-
- def test2(self):
- """hash not in #directives"""
- self.verify("# \# #5 ",
- "# # #5 ")
-
- def test3(self):
- """escapted comments"""
- self.verify(" \##escaped comment ",
- " ##escaped comment ")
-
- def test4(self):
- """escapted multi-line comments"""
- self.verify(" \#*escaped comment \n*# ",
- " #*escaped comment \n*# ")
-
- def test5(self):
- """1 dollar sign"""
- self.verify("$",
- "$")
- def _X_test6(self):
- """1 dollar sign followed by hash"""
- self.verify("\n$#\n",
- "\n$#\n")
-
- def test6(self):
- """1 dollar sign followed by EOL Slurp Token"""
- if DEFAULT_COMPILER_SETTINGS['EOLSlurpToken']:
- self.verify("\n$%s\n"%DEFAULT_COMPILER_SETTINGS['EOLSlurpToken'],
- "\n$")
- else:
- self.verify("\n$#\n",
- "\n$#\n")
-
-class Comments_SingleLine(OutputTest):
- def test1(self):
- """## followed by WS"""
- self.verify("## ",
- "")
-
- def test2(self):
- """## followed by NEWLINE"""
- self.verify("##\n",
- "")
-
- def test3(self):
- """## followed by text then NEWLINE"""
- self.verify("## oeuao aoe uaoe \n",
- "")
- def test4(self):
- """## gobbles leading WS"""
- self.verify(" ## oeuao aoe uaoe \n",
- "")
-
- def test5(self):
- """## followed by text then NEWLINE, + leading WS"""
- self.verify(" ## oeuao aoe uaoe \n",
- "")
-
- def test6(self):
- """## followed by EOF"""
- self.verify("##",
- "")
-
- def test7(self):
- """## followed by EOF with leading WS"""
- self.verify(" ##",
- "")
-
- def test8(self):
- """## gobble line
- with text on previous and following lines"""
- self.verify("line1\n ## aoeu 1234 \nline2",
- "line1\nline2")
-
- def test9(self):
- """## don't gobble line
- with text on previous and following lines"""
- self.verify("line1\n 12 ## aoeu 1234 \nline2",
- "line1\n 12 \nline2")
-
- def test10(self):
- """## containing $placeholders
- """
- self.verify("##$a$b $c($d)",
- "")
-
- def test11(self):
- """## containing #for directive
- """
- self.verify("##for $i in range(15)",
- "")
-
-
-class Comments_MultiLine_NoGobble(OutputTest):
- """
- Multiline comments used to not gobble whitespace. They do now, but this can
- be turned off with a compilerSetting
- """
-
- def _getCompilerSettings(self):
- return {'gobbleWhitespaceAroundMultiLineComments':False}
-
- def test1(self):
- """#* *# followed by WS
- Shouldn't gobble WS
- """
- self.verify("#* blarg *# ",
- " ")
-
- def test2(self):
- """#* *# preceded and followed by WS
- Shouldn't gobble WS
- """
- self.verify(" #* blarg *# ",
- " ")
-
- def test3(self):
- """#* *# followed by WS, with NEWLINE
- Shouldn't gobble WS
- """
- self.verify("#* \nblarg\n *# ",
- " ")
-
- def test4(self):
- """#* *# preceded and followed by WS, with NEWLINE
- Shouldn't gobble WS
- """
- self.verify(" #* \nblarg\n *# ",
- " ")
-
-class Comments_MultiLine(OutputTest):
- """
- Note: Multiline comments don't gobble whitespace!
- """
-
- def test1(self):
- """#* *# followed by WS
- Should gobble WS
- """
- self.verify("#* blarg *# ",
- "")
-
- def test2(self):
- """#* *# preceded and followed by WS
- Should gobble WS
- """
- self.verify(" #* blarg *# ",
- "")
-
- def test3(self):
- """#* *# followed by WS, with NEWLINE
- Shouldn't gobble WS
- """
- self.verify("#* \nblarg\n *# ",
- "")
-
- def test4(self):
- """#* *# preceded and followed by WS, with NEWLINE
- Shouldn't gobble WS
- """
- self.verify(" #* \nblarg\n *# ",
- "")
-
- def test5(self):
- """#* *# containing nothing
- """
- self.verify("#**#",
- "")
-
- def test6(self):
- """#* *# containing only NEWLINES
- """
- self.verify(" #*\n\n\n\n\n\n\n\n*# ",
- "")
-
- def test7(self):
- """#* *# containing $placeholders
- """
- self.verify("#* $var $var(1234*$c) *#",
- "")
-
- def test8(self):
- """#* *# containing #for directive
- """
- self.verify("#* #for $i in range(15) *#",
- "")
-
- def test9(self):
- """ text around #* *# containing #for directive
- """
- self.verify("foo\nfoo bar #* #for $i in range(15) *# foo\n",
- "foo\nfoo bar foo\n")
-
- def test9(self):
- """ text around #* *# containing #for directive and trailing whitespace
- which should be gobbled
- """
- self.verify("foo\nfoo bar #* #for $i in range(15) *# \ntest",
- "foo\nfoo bar \ntest")
-
- def test10(self):
- """ text around #* *# containing #for directive and newlines: trailing whitespace
- which should be gobbled.
- """
- self.verify("foo\nfoo bar #* \n\n#for $i in range(15) \n\n*# \ntest",
- "foo\nfoo bar \ntest")
-
-class Placeholders(OutputTest):
- def test1(self):
- """1 placeholder"""
- self.verify("$aStr", "blarg")
-
- def test2(self):
- """2 placeholders"""
- self.verify("$aStr $anInt", "blarg 1")
-
- def test3(self):
- """2 placeholders, back-to-back"""
- self.verify("$aStr$anInt", "blarg1")
-
- def test4(self):
- """1 placeholder enclosed in ()"""
- self.verify("$(aStr)", "blarg")
-
- def test5(self):
- """1 placeholder enclosed in {}"""
- self.verify("${aStr}", "blarg")
-
- def test6(self):
- """1 placeholder enclosed in []"""
- self.verify("$[aStr]", "blarg")
-
- def test7(self):
- """1 placeholder enclosed in () + WS
-
- Test to make sure that $(<WS><identifier>.. matches
- """
- self.verify("$( aStr )", "blarg")
-
- def test8(self):
- """1 placeholder enclosed in {} + WS"""
- self.verify("${ aStr }", "blarg")
-
- def test9(self):
- """1 placeholder enclosed in [] + WS"""
- self.verify("$[ aStr ]", "blarg")
-
- def test10(self):
- """1 placeholder enclosed in () + WS + * cache
-
- Test to make sure that $*(<WS><identifier>.. matches
- """
- self.verify("$*( aStr )", "blarg")
-
- def test11(self):
- """1 placeholder enclosed in {} + WS + *cache"""
- self.verify("$*{ aStr }", "blarg")
-
- def test12(self):
- """1 placeholder enclosed in [] + WS + *cache"""
- self.verify("$*[ aStr ]", "blarg")
-
- def test13(self):
- """1 placeholder enclosed in {} + WS + *<int>*cache"""
- self.verify("$*5*{ aStr }", "blarg")
-
- def test14(self):
- """1 placeholder enclosed in [] + WS + *<int>*cache"""
- self.verify("$*5*[ aStr ]", "blarg")
-
- def test15(self):
- """1 placeholder enclosed in {} + WS + *<float>*cache"""
- self.verify("$*0.5d*{ aStr }", "blarg")
-
- def test16(self):
- """1 placeholder enclosed in [] + WS + *<float>*cache"""
- self.verify("$*.5*[ aStr ]", "blarg")
-
- def test17(self):
- """1 placeholder + *<int>*cache"""
- self.verify("$*5*aStr", "blarg")
-
- def test18(self):
- """1 placeholder *<float>*cache"""
- self.verify("$*0.5h*aStr", "blarg")
-
- def test19(self):
- """1 placeholder surrounded by single quotes and multiple newlines"""
- self.verify("""'\n\n\n\n'$aStr'\n\n\n\n'""",
- """'\n\n\n\n'blarg'\n\n\n\n'""")
-
- def test20(self):
- """silent mode $!placeholders """
- self.verify("$!aStr$!nonExistant$!*nonExistant$!{nonExistant}", "blarg")
-
- try:
- self.verify("$!aStr$nonExistant",
- "blarg")
- except NotFound:
- pass
- else:
- self.fail('should raise NotFound exception')
-
- def test21(self):
- """Make sure that $*caching is actually working"""
- namesStr = 'You Me Them Everyone'
- names = namesStr.split()
-
- tmpl = Template.compile('#for name in $names: $name ', baseclass=dict)
- assert str(tmpl({'names':names})).strip()==namesStr
-
- tmpl = tmpl.subclass('#for name in $names: $*name ')
- assert str(tmpl({'names':names}))=='You '*len(names)
-
- tmpl = tmpl.subclass('#for name in $names: $*1*name ')
- assert str(tmpl({'names':names}))=='You '*len(names)
-
- tmpl = tmpl.subclass('#for name in $names: $*1*(name) ')
- assert str(tmpl({'names':names}))=='You '*len(names)
-
- if versionTuple > (2, 2):
- tmpl = tmpl.subclass('#for name in $names: $*1*(name) ')
- assert str(tmpl(names=names))=='You '*len(names)
-
-class Placeholders_Vals(OutputTest):
- convertEOLs = False
- def test1(self):
- """string"""
- self.verify("$aStr", "blarg")
-
- def test2(self):
- """string - with whitespace"""
- self.verify(" $aStr ", " blarg ")
-
- def test3(self):
- """empty string - with whitespace"""
- self.verify("$emptyString", "")
-
- def test4(self):
- """int"""
- self.verify("$anInt", "1")
-
- def test5(self):
- """float"""
- self.verify("$aFloat", "1.5")
-
- def test6(self):
- """list"""
- self.verify("$aList", "['item0', 'item1', 'item2']")
-
- def test7(self):
- """None
-
- The default output filter is ReplaceNone.
- """
- self.verify("$none", "")
-
- def test8(self):
- """True, False
- """
- self.verify("$True $False", "%s %s"%(repr(True), repr(False)))
-
- def test9(self):
- """$_
- """
- self.verify("$_('foo')", "Translated: foo")
-
-class PlaceholderStrings(OutputTest):
- def test1(self):
- """some c'text $placeholder text' strings"""
- self.verify("$str(c'$aStr')", "blarg")
-
- def test2(self):
- """some c'text $placeholder text' strings"""
- self.verify("$str(c'$aStr.upper')", "BLARG")
-
- def test3(self):
- """some c'text $placeholder text' strings"""
- self.verify("$str(c'$(aStr.upper.replace(c\"A$str()\",\"\"))')", "BLRG")
-
- def test4(self):
- """some c'text $placeholder text' strings"""
- self.verify("#echo $str(c'$(aStr.upper)')", "BLARG")
-
- def test5(self):
- """some c'text $placeholder text' strings"""
- self.verify("#if 1 then $str(c'$(aStr.upper)') else 0", "BLARG")
-
- def test6(self):
- """some c'text $placeholder text' strings"""
- self.verify("#if 1\n$str(c'$(aStr.upper)')#slurp\n#else\n0#end if", "BLARG")
-
- def test7(self):
- """some c'text $placeholder text' strings"""
- self.verify("#def foo(arg=c'$(\"BLARG\")')\n"
- "$arg#slurp\n"
- "#end def\n"
- "$foo()$foo(c'$anInt')#slurp",
-
- "BLARG1")
-
-
-
-class UnicodeStrings(OutputTest):
- def test1(self):
- """unicode data in placeholder
- """
- #self.verify(u"$unicodeData", defaultTestNameSpace['unicodeData'], outputEncoding='utf8')
- self.verify(u"$unicodeData", defaultTestNameSpace['unicodeData'])
-
- def test2(self):
- """unicode data in body
- """
- self.verify(u"aoeu12345\u1234", u"aoeu12345\u1234")
- #self.verify(u"#encoding utf8#aoeu12345\u1234", u"aoeu12345\u1234")
-
-class EncodingDirective(OutputTest):
- def test1(self):
- """basic #encoding """
- self.verify("#encoding utf-8\n1234",
- "1234")
-
- def test2(self):
- """basic #encoding """
- self.verify("#encoding ascii\n1234",
- "1234")
-
- def test3(self):
- """basic #encoding """
- self.verify("#encoding utf-8\n\xe1\x88\xb4",
- u'\u1234', outputEncoding='utf8')
-
- def test4(self):
- """basic #encoding """
- self.verify("#encoding latin-1\n\xe1\x88\xb4",
- u"\xe1\x88\xb4")
-
- def test5(self):
- """basic #encoding """
- self.verify("#encoding latin-1\nAndr\202",
- u'Andr\202')
-
- def test6(self):
- '''Using #encoding on the second line'''
- self.verify("""### Comments on the first line
-#encoding utf-8\n\xe1\x88\xb4""",
- u'\u1234', outputEncoding='utf8')
-
-class UnicodeDirective(OutputTest):
- def test1(self):
- """basic #unicode """
- self.verify("#unicode utf-8\n1234",
- u"1234")
-
- self.verify("#unicode ascii\n1234",
- u"1234")
-
- self.verify("#unicode latin-1\n1234",
- u"1234")
-
- self.verify("#unicode latin-1\n1234ü",
- u"1234ü")
- self.verify("#unicode: latin-1\n1234ü",
- u"1234ü")
- self.verify("# unicode : latin-1\n1234ü",
- u"1234ü")
-
- self.verify(u"#unicode latin-1\n1234ü",
- u"1234ü")
-
- self.verify("#encoding latin-1\n1234ü",
- u"1234ü")
-
-class Placeholders_Esc(OutputTest):
- convertEOLs = False
- def test1(self):
- """1 escaped placeholder"""
- self.verify("\$var",
- "$var")
-
- def test2(self):
- """2 escaped placeholders"""
- self.verify("\$var \$_",
- "$var $_")
-
- def test3(self):
- """2 escaped placeholders - back to back"""
- self.verify("\$var\$_",
- "$var$_")
-
- def test4(self):
- """2 escaped placeholders - nested"""
- self.verify("\$var(\$_)",
- "$var($_)")
-
- def test5(self):
- """2 escaped placeholders - nested and enclosed"""
- self.verify("\$(var(\$_)",
- "$(var($_)")
-
-
-class Placeholders_Calls(OutputTest):
- def test1(self):
- """func placeholder - no ()"""
- self.verify("$aFunc",
- "Scooby")
-
- def test2(self):
- """func placeholder - with ()"""
- self.verify("$aFunc()",
- "Scooby")
-
- def test3(self):
- r"""func placeholder - with (\n\n)"""
- self.verify("$aFunc(\n\n)",
- "Scooby", convertEOLs=False)
-
- def test4(self):
- r"""func placeholder - with (\n\n) and $() enclosure"""
- self.verify("$(aFunc(\n\n))",
- "Scooby", convertEOLs=False)
-
- def test5(self):
- r"""func placeholder - with (\n\n) and ${} enclosure"""
- self.verify("${aFunc(\n\n)}",
- "Scooby", convertEOLs=False)
-
- def test6(self):
- """func placeholder - with (int)"""
- self.verify("$aFunc(1234)",
- "1234")
-
- def test7(self):
- r"""func placeholder - with (\nint\n)"""
- self.verify("$aFunc(\n1234\n)",
- "1234", convertEOLs=False)
- def test8(self):
- """func placeholder - with (string)"""
- self.verify("$aFunc('aoeu')",
- "aoeu")
-
- def test9(self):
- """func placeholder - with ('''string''')"""
- self.verify("$aFunc('''aoeu''')",
- "aoeu")
- def test10(self):
- r"""func placeholder - with ('''\nstring\n''')"""
- self.verify("$aFunc('''\naoeu\n''')",
- "\naoeu\n", convertEOLs=False)
-
- def test11(self):
- r"""func placeholder - with ('''\nstring'\n''')"""
- self.verify("$aFunc('''\naoeu'\n''')",
- "\naoeu'\n", convertEOLs=False)
-
- def test12(self):
- r'''func placeholder - with ("""\nstring\n""")'''
- self.verify('$aFunc("""\naoeu\n""")',
- "\naoeu\n", convertEOLs=False)
-
- def test13(self):
- """func placeholder - with (string*int)"""
- self.verify("$aFunc('aoeu'*2)",
- "aoeuaoeu")
-
- def test14(self):
- """func placeholder - with (int*int)"""
- self.verify("$aFunc(2*2)",
- "4")
-
- def test15(self):
- """func placeholder - with (int*float)"""
- self.verify("$aFunc(2*2.0)",
- "4.0")
-
- def test16(self):
- r"""func placeholder - with (int\n*\nfloat)"""
- self.verify("$aFunc(2\n*\n2.0)",
- "4.0", convertEOLs=False)
-
- def test17(self):
- """func placeholder - with ($arg=float)"""
- self.verify("$aFunc($arg=4.0)",
- "4.0")
-
- def test18(self):
- """func placeholder - with (arg=float)"""
- self.verify("$aFunc(arg=4.0)",
- "4.0")
-
- def test19(self):
- """deeply nested argstring, no enclosure"""
- self.verify("$aFunc($arg=$aMeth($arg=$aFunc(1)))",
- "1")
-
- def test20(self):
- """deeply nested argstring, no enclosure + with WS"""
- self.verify("$aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) )",
- "1")
- def test21(self):
- """deeply nested argstring, () enclosure + with WS"""
- self.verify("$(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )",
- "1")
-
- def test22(self):
- """deeply nested argstring, {} enclosure + with WS"""
- self.verify("${aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) }",
- "1")
-
- def test23(self):
- """deeply nested argstring, [] enclosure + with WS"""
- self.verify("$[aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) ]",
- "1")
-
- def test24(self):
- """deeply nested argstring, () enclosure + *cache"""
- self.verify("$*(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )",
- "1")
- def test25(self):
- """deeply nested argstring, () enclosure + *15*cache"""
- self.verify("$*15*(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )",
- "1")
-
- def test26(self):
- """a function call with the Python None kw."""
- self.verify("$aFunc(None)",
- "")
-
-class NameMapper(OutputTest):
- def test1(self):
- """autocalling"""
- self.verify("$aFunc! $aFunc().",
- "Scooby! Scooby.")
-
- def test2(self):
- """nested autocalling"""
- self.verify("$aFunc($aFunc).",
- "Scooby.")
-
- def test3(self):
- """list subscription"""
- self.verify("$aList[0]",
- "item0")
-
- def test4(self):
- """list slicing"""
- self.verify("$aList[:2]",
- "['item0', 'item1']")
-
- def test5(self):
- """list slicing and subcription combined"""
- self.verify("$aList[:2][0]",
- "item0")
-
- def test6(self):
- """dictionary access - NameMapper style"""
- self.verify("$aDict.one",
- "item1")
-
- def test7(self):
- """dictionary access - Python style"""
- self.verify("$aDict['one']",
- "item1")
-
- def test8(self):
- """dictionary access combined with autocalled string method"""
- self.verify("$aDict.one.upper",
- "ITEM1")
-
- def test9(self):
- """dictionary access combined with string method"""
- self.verify("$aDict.one.upper()",
- "ITEM1")
-
- def test10(self):
- """nested dictionary access - NameMapper style"""
- self.verify("$aDict.nestedDict.two",
- "nestedItem2")
-
- def test11(self):
- """nested dictionary access - Python style"""
- self.verify("$aDict['nestedDict']['two']",
- "nestedItem2")
-
- def test12(self):
- """nested dictionary access - alternating style"""
- self.verify("$aDict['nestedDict'].two",
- "nestedItem2")
-
- def test13(self):
- """nested dictionary access using method - alternating style"""
- self.verify("$aDict.get('nestedDict').two",
- "nestedItem2")
-
- def test14(self):
- """nested dictionary access - NameMapper style - followed by method"""
- self.verify("$aDict.nestedDict.two.upper",
- "NESTEDITEM2")
-
- def test15(self):
- """nested dictionary access - alternating style - followed by method"""
- self.verify("$aDict['nestedDict'].two.upper",
- "NESTEDITEM2")
-
- def test16(self):
- """nested dictionary access - NameMapper style - followed by method, then slice"""
- self.verify("$aDict.nestedDict.two.upper[:4]",
- "NEST")
-
- def test17(self):
- """nested dictionary access - Python style using a soft-coded key"""
- self.verify("$aDict[$anObj.meth('nestedDict')].two",
- "nestedItem2")
-
- def test18(self):
- """object method access"""
- self.verify("$anObj.meth1",
- "doo")
-
- def test19(self):
- """object method access, followed by complex slice"""
- self.verify("$anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ]",
- "do")
-
- def test20(self):
- """object method access, followed by a very complex slice
- If it can pass this one, it's safe to say it works!!"""
- self.verify("$( anObj.meth1[0:\n (\n(4/4*2)*2)/$anObj.meth1(2)\n ] )",
- "do")
-
- def test21(self):
- """object method access with % in the default arg for the meth.
-
- This tests a bug that Jeff Johnson found and submitted a patch to SF
- for."""
-
- self.verify("$anObj.methWithPercentSignDefaultArg",
- "110%")
-
-
-#class NameMapperDict(OutputTest):
-#
-# _searchList = [{"update": "Yabba dabba doo!"}]
-#
-# def test1(self):
-# if NameMapper_C_VERSION:
-# return # This feature is not in the C version yet.
-# self.verify("$update", "Yabba dabba doo!")
-#
-
-class CacheDirective(OutputTest):
-
- def test1(self):
- r"""simple #cache """
- self.verify("#cache:$anInt",
- "1")
-
- def test2(self):
- r"""simple #cache + WS"""
- self.verify(" #cache \n$anInt#end cache",
- "1")
-
- def test3(self):
- r"""simple #cache ... #end cache"""
- self.verify("""#cache id='cache1', timer=150m
-$anInt
-#end cache
-$aStr""",
- "1\nblarg")
-
- def test4(self):
- r"""2 #cache ... #end cache blocks"""
- self.verify("""#slurp
-#def foo
-#cache ID='cache1', timer=150m
-$anInt
-#end cache
-#cache id='cache2', timer=15s
- #for $i in range(5)
-$i#slurp
- #end for
-#end cache
-$aStr#slurp
-#end def
-$foo$foo$foo$foo$foo""",
- "1\n01234blarg"*5)
-
-
- def test5(self):
- r"""nested #cache blocks"""
- self.verify("""#slurp
-#def foo
-#cache ID='cache1', timer=150m
-$anInt
-#cache id='cache2', timer=15s
- #for $i in range(5)
-$i#slurp
- #end for
-$*(6)#slurp
-#end cache
-#end cache
-$aStr#slurp
-#end def
-$foo$foo$foo$foo$foo""",
- "1\n012346blarg"*5)
-
- def test6(self):
- r"""Make sure that partial directives don't match"""
- self.verify("#cache_foo",
- "#cache_foo")
- self.verify("#cached",
- "#cached")
-
-class CallDirective(OutputTest):
-
- def test1(self):
- r"""simple #call """
- self.verify("#call int\n$anInt#end call",
- "1")
- # single line version
- self.verify("#call int: $anInt",
- "1")
- self.verify("#call int: 10\n$aStr",
- "10\nblarg")
-
- def test2(self):
- r"""simple #call + WS"""
- self.verify("#call int\n$anInt #end call",
- "1")
-
- def test3(self):
- r"""a longer #call"""
- self.verify('''\
-#def meth(arg)
-$arg.upper()#slurp
-#end def
-#call $meth
-$(1234+1) foo#slurp
-#end call''',
- "1235 FOO")
-
- def test4(self):
- r"""#call with keyword #args"""
- self.verify('''\
-#def meth(arg1, arg2)
-$arg1.upper() - $arg2.lower()#slurp
-#end def
-#call self.meth
-#arg arg1
-$(1234+1) foo#slurp
-#arg arg2
-UPPER#slurp
-#end call''',
- "1235 FOO - upper")
-
- def test5(self):
- r"""#call with single-line keyword #args """
- self.verify('''\
-#def meth(arg1, arg2)
-$arg1.upper() - $arg2.lower()#slurp
-#end def
-#call self.meth
-#arg arg1:$(1234+1) foo#slurp
-#arg arg2:UPPER#slurp
-#end call''',
- "1235 FOO - upper")
-
- def test6(self):
- """#call with python kwargs and cheetah output for the 1s positional
- arg"""
-
- self.verify('''\
-#def meth(arg1, arg2)
-$arg1.upper() - $arg2.lower()#slurp
-#end def
-#call self.meth arg2="UPPER"
-$(1234+1) foo#slurp
-#end call''',
- "1235 FOO - upper")
-
- def test7(self):
- """#call with python kwargs and #args"""
- self.verify('''\
-#def meth(arg1, arg2, arg3)
-$arg1.upper() - $arg2.lower() - $arg3#slurp
-#end def
-#call self.meth arg2="UPPER", arg3=999
-#arg arg1:$(1234+1) foo#slurp
-#end call''',
- "1235 FOO - upper - 999")
-
- def test8(self):
- """#call with python kwargs and #args, and using a function to get the
- function that will be called"""
- self.verify('''\
-#def meth(arg1, arg2, arg3)
-$arg1.upper() - $arg2.lower() - $arg3#slurp
-#end def
-#call getattr(self, "meth") arg2="UPPER", arg3=999
-#arg arg1:$(1234+1) foo#slurp
-#end call''',
- "1235 FOO - upper - 999")
-
- def test9(self):
- """nested #call directives"""
- self.verify('''\
-#def meth(arg1)
-$arg1#slurp
-#end def
-#def meth2(x,y)
-$x$y#slurp
-#end def
-##
-#call self.meth
-1#slurp
-#call self.meth
-2#slurp
-#call self.meth
-3#slurp
-#end call 3
-#set two = 2
-#call self.meth2 y=c"$(10/$two)"
-#arg x
-4#slurp
-#end call 4
-#end call 2
-#end call 1''',
- "12345")
-
-
-
-class I18nDirective(OutputTest):
- def test1(self):
- r"""simple #call """
- self.verify("#i18n \n$anInt#end i18n",
- "1")
-
- # single line version
- self.verify("#i18n: $anInt",
- "1")
- self.verify("#i18n: 10\n$aStr",
- "10\nblarg")
-
-
-class CaptureDirective(OutputTest):
- def test1(self):
- r"""simple #capture"""
- self.verify('''\
-#capture cap1
-$(1234+1) foo#slurp
-#end capture
-$cap1#slurp
-''',
- "1235 foo")
-
-
- def test2(self):
- r"""slightly more complex #capture"""
- self.verify('''\
-#def meth(arg)
-$arg.upper()#slurp
-#end def
-#capture cap1
-$(1234+1) $anInt $meth("foo")#slurp
-#end capture
-$cap1#slurp
-''',
- "1235 1 FOO")
-
-
-class SlurpDirective(OutputTest):
- def test1(self):
- r"""#slurp with 1 \n """
- self.verify("#slurp\n",
- "")
-
- def test2(self):
- r"""#slurp with 1 \n, leading whitespace
- Should gobble"""
- self.verify(" #slurp\n",
- "")
-
- def test3(self):
- r"""#slurp with 1 \n, leading content
- Shouldn't gobble"""
- self.verify(" 1234 #slurp\n",
- " 1234 ")
-
- def test4(self):
- r"""#slurp with WS then \n, leading content
- Shouldn't gobble"""
- self.verify(" 1234 #slurp \n",
- " 1234 ")
-
- def test5(self):
- r"""#slurp with garbage chars then \n, leading content
- Should eat the garbage"""
- self.verify(" 1234 #slurp garbage \n",
- " 1234 ")
-
-
-
-class EOLSlurpToken(OutputTest):
- _EOLSlurpToken = DEFAULT_COMPILER_SETTINGS['EOLSlurpToken']
- def test1(self):
- r"""#slurp with 1 \n """
- self.verify("%s\n"%self._EOLSlurpToken,
- "")
-
- def test2(self):
- r"""#slurp with 1 \n, leading whitespace
- Should gobble"""
- self.verify(" %s\n"%self._EOLSlurpToken,
- "")
- def test3(self):
- r"""#slurp with 1 \n, leading content
- Shouldn't gobble"""
- self.verify(" 1234 %s\n"%self._EOLSlurpToken,
- " 1234 ")
-
- def test4(self):
- r"""#slurp with WS then \n, leading content
- Shouldn't gobble"""
- self.verify(" 1234 %s \n"%self._EOLSlurpToken,
- " 1234 ")
-
- def test5(self):
- r"""#slurp with garbage chars then \n, leading content
- Should NOT eat the garbage"""
- self.verify(" 1234 %s garbage \n"%self._EOLSlurpToken,
- " 1234 %s garbage \n"%self._EOLSlurpToken)
-
-if not DEFAULT_COMPILER_SETTINGS['EOLSlurpToken']:
- del EOLSlurpToken
-
-class RawDirective(OutputTest):
- def test1(self):
- """#raw till EOF"""
- self.verify("#raw\n$aFunc().\n\n",
- "$aFunc().\n\n")
-
- def test2(self):
- """#raw till #end raw"""
- self.verify("#raw\n$aFunc().\n#end raw\n$anInt",
- "$aFunc().\n1")
-
- def test3(self):
- """#raw till #end raw gobble WS"""
- self.verify(" #raw \n$aFunc().\n #end raw \n$anInt",
- "$aFunc().\n1")
-
- def test4(self):
- """#raw till #end raw using explicit directive closure
- Shouldn't gobble"""
- self.verify(" #raw #\n$aFunc().\n #end raw #\n$anInt",
- " \n$aFunc().\n\n1")
-
- def test5(self):
- """single-line short form #raw: """
- self.verify("#raw: $aFunc().\n\n",
- "$aFunc().\n\n")
-
- self.verify("#raw: $aFunc().\n$anInt",
- "$aFunc().\n1")
-
- def test6(self):
- """ Escape characters in a #raw block """
- self.verify( """#raw: This escape should be preserved: \\$unexpanded So should this one: \\#blah The string "\\012" should not disappear.""",
- r"""This escape should be preserved: \$unexpanded So should this one: \#blah The string "\012" should not disappear.""")
-
-
-class BreakpointDirective(OutputTest):
- def test1(self):
- """#breakpoint part way through source code"""
- self.verify("$aFunc(2).\n#breakpoint\n$anInt",
- "2.\n")
-
- def test2(self):
- """#breakpoint at BOF"""
- self.verify("#breakpoint\n$anInt",
- "")
-
- def test3(self):
- """#breakpoint at EOF"""
- self.verify("$anInt\n#breakpoint",
- "1\n")
-
-
-class StopDirective(OutputTest):
- def test1(self):
- """#stop part way through source code"""
- self.verify("$aFunc(2).\n#stop\n$anInt",
- "2.\n")
-
- def test2(self):
- """#stop at BOF"""
- self.verify("#stop\n$anInt",
- "")
-
- def test3(self):
- """#stop at EOF"""
- self.verify("$anInt\n#stop",
- "1\n")
-
- def test4(self):
- """#stop in pos test block"""
- self.verify("""$anInt
-#if 1
-inside the if block
-#stop
-#end if
-blarg""",
- "1\ninside the if block\n")
-
- def test5(self):
- """#stop in neg test block"""
- self.verify("""$anInt
-#if 0
-inside the if block
-#stop
-#end if
-blarg""",
- "1\nblarg")
-
-
-class ReturnDirective(OutputTest):
-
- def test1(self):
- """#return'ing an int """
- self.verify("""1
-$str($test-6)
-3
-#def test
-#if 1
-#return (3 *2) \
- + 2
-#else
-aoeuoaeu
-#end if
-#end def
-""",
- "1\n2\n3\n")
-
- def test2(self):
- """#return'ing an string """
- self.verify("""1
-$str($test[1])
-3
-#def test
-#if 1
-#return '123'
-#else
-aoeuoaeu
-#end if
-#end def
-""",
- "1\n2\n3\n")
-
- def test3(self):
- """#return'ing an string AND streaming other output via the transaction"""
- self.verify("""1
-$str($test(trans=trans)[1])
-3
-#def test
-1.5
-#if 1
-#return '123'
-#else
-aoeuoaeu
-#end if
-#end def
-""",
- "1\n1.5\n2\n3\n")
-
-
-class YieldDirective(OutputTest):
- convertEOLs = False
- def test1(self):
- """simple #yield """
-
- src1 = """#for i in range(10)\n#yield i\n#end for"""
- src2 = """#for i in range(10)\n$i#slurp\n#yield\n#end for"""
- src3 = ("#def iterator\n"
- "#for i in range(10)\n#yield i\n#end for\n"
- "#end def\n"
- "#for i in $iterator\n$i#end for"
- )
-
-
- for src in (src1, src2, src3):
- klass = Template.compile(src, keepRefToGeneratedCode=True)
- #print klass._CHEETAH_generatedModuleCode
- iter = klass().respond()
- output = [str(i) for i in iter]
- assert ''.join(output)=='0123456789'
- #print ''.join(output)
-
- # @@TR: need to expand this to cover error conditions etc.
-
-if versionTuple < (2, 3):
- del YieldDirective
-
-class ForDirective(OutputTest):
-
- def test1(self):
- """#for loop with one local var"""
- self.verify("#for $i in range(5)\n$i\n#end for",
- "0\n1\n2\n3\n4\n")
-
- self.verify("#for $i in range(5):\n$i\n#end for",
- "0\n1\n2\n3\n4\n")
-
- self.verify("#for $i in range(5): ##comment\n$i\n#end for",
- "0\n1\n2\n3\n4\n")
-
- self.verify("#for $i in range(5) ##comment\n$i\n#end for",
- "0\n1\n2\n3\n4\n")
-
-
- def test2(self):
- """#for loop with WS in loop"""
- self.verify("#for $i in range(5)\n$i \n#end for",
- "0 \n1 \n2 \n3 \n4 \n")
-
- def test3(self):
- """#for loop gobble WS"""
- self.verify(" #for $i in range(5) \n$i \n #end for ",
- "0 \n1 \n2 \n3 \n4 \n")
-
- def test4(self):
- """#for loop over list"""
- self.verify("#for $i, $j in [(0,1),(2,3)]\n$i,$j\n#end for",
- "0,1\n2,3\n")
-
- def test5(self):
- """#for loop over list, with #slurp"""
- self.verify("#for $i, $j in [(0,1),(2,3)]\n$i,$j#slurp\n#end for",
- "0,12,3")
-
- def test6(self):
- """#for loop with explicit closures"""
- self.verify("#for $i in range(5)#$i#end for#",
- "01234")
-
- def test7(self):
- """#for loop with explicit closures and WS"""
- self.verify(" #for $i in range(5)#$i#end for# ",
- " 01234 ")
-
- def test8(self):
- """#for loop using another $var"""
- self.verify(" #for $i in range($aFunc(5))#$i#end for# ",
- " 01234 ")
-
- def test9(self):
- """test methods in for loops"""
- self.verify("#for $func in $listOfLambdas\n$func($anInt)\n#end for",
- "1\n1\n1\n")
-
-
- def test10(self):
- """#for loop over list, using methods of the items"""
- self.verify("#for i, j in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for",
- "AA,BB\nCC,DD\n")
- self.verify("#for $i, $j in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for",
- "AA,BB\nCC,DD\n")
-
- def test11(self):
- """#for loop over list, using ($i,$j) style target list"""
- self.verify("#for (i, j) in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for",
- "AA,BB\nCC,DD\n")
- self.verify("#for ($i, $j) in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for",
- "AA,BB\nCC,DD\n")
-
- def test12(self):
- """#for loop over list, using i, (j,k) style target list"""
- self.verify("#for i, (j, k) in enumerate([('aa','bb'),('cc','dd')])\n$j.upper,$k.upper\n#end for",
- "AA,BB\nCC,DD\n")
- self.verify("#for $i, ($j, $k) in enumerate([('aa','bb'),('cc','dd')])\n$j.upper,$k.upper\n#end for",
- "AA,BB\nCC,DD\n")
-
- def test13(self):
- """single line #for"""
- self.verify("#for $i in range($aFunc(5)): $i",
- "01234")
-
- def test14(self):
- """single line #for with 1 extra leading space"""
- self.verify("#for $i in range($aFunc(5)): $i",
- " 0 1 2 3 4")
-
- def test15(self):
- """2 times single line #for"""
- self.verify("#for $i in range($aFunc(5)): $i#slurp\n"*2,
- "01234"*2)
-
- def test16(self):
- """false single line #for """
- self.verify("#for $i in range(5): \n$i\n#end for",
- "0\n1\n2\n3\n4\n")
-
-if versionTuple < (2, 3):
- del ForDirective.test12
-
-class RepeatDirective(OutputTest):
-
- def test1(self):
- """basic #repeat"""
- self.verify("#repeat 3\n1\n#end repeat",
- "1\n1\n1\n")
- self.verify("#repeat 3: \n1\n#end repeat",
- "1\n1\n1\n")
-
- self.verify("#repeat 3 ##comment\n1\n#end repeat",
- "1\n1\n1\n")
-
- self.verify("#repeat 3: ##comment\n1\n#end repeat",
- "1\n1\n1\n")
-
- def test2(self):
- """#repeat with numeric expression"""
- self.verify("#repeat 3*3/3\n1\n#end repeat",
- "1\n1\n1\n")
-
- def test3(self):
- """#repeat with placeholder"""
- self.verify("#repeat $numTwo\n1\n#end repeat",
- "1\n1\n")
-
- def test4(self):
- """#repeat with placeholder * num"""
- self.verify("#repeat $numTwo*1\n1\n#end repeat",
- "1\n1\n")
-
- def test5(self):
- """#repeat with placeholder and WS"""
- self.verify(" #repeat $numTwo \n1\n #end repeat ",
- "1\n1\n")
-
- def test6(self):
- """single-line #repeat"""
- self.verify("#repeat $numTwo: 1",
- "11")
- self.verify("#repeat $numTwo: 1\n"*2,
- "1\n1\n"*2)
-
- #false single-line
- self.verify("#repeat 3: \n1\n#end repeat",
- "1\n1\n1\n")
-
-
-class AttrDirective(OutputTest):
-
- def test1(self):
- """#attr with int"""
- self.verify("#attr $test = 1234\n$test",
- "1234")
-
- def test2(self):
- """#attr with string"""
- self.verify("#attr $test = 'blarg'\n$test",
- "blarg")
-
- def test3(self):
- """#attr with expression"""
- self.verify("#attr $test = 'blarg'.upper()*2\n$test",
- "BLARGBLARG")
-
- def test4(self):
- """#attr with string + WS
- Should gobble"""
- self.verify(" #attr $test = 'blarg' \n$test",
- "blarg")
-
- def test5(self):
- """#attr with string + WS + leading text
- Shouldn't gobble"""
- self.verify(" -- #attr $test = 'blarg' \n$test",
- " -- \nblarg")
-
-
-class DefDirective(OutputTest):
-
- def test1(self):
- """#def without argstring"""
- self.verify("#def testMeth\n1234\n#end def\n$testMeth",
- "1234\n")
-
- self.verify("#def testMeth ## comment\n1234\n#end def\n$testMeth",
- "1234\n")
-
- self.verify("#def testMeth: ## comment\n1234\n#end def\n$testMeth",
- "1234\n")
-
- def test2(self):
- """#def without argstring, gobble WS"""
- self.verify(" #def testMeth \n1234\n #end def \n$testMeth",
- "1234\n")
-
- def test3(self):
- """#def with argstring, gobble WS"""
- self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth",
- "1234-999\n")
-
- def test4(self):
- """#def with argstring, gobble WS, string used in call"""
- self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth('ABC')",
- "1234-ABC\n")
-
- def test5(self):
- """#def with argstring, gobble WS, list used in call"""
- self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth([1,2,3])",
- "1234-[1, 2, 3]\n")
-
- def test6(self):
- """#def with 2 args, gobble WS, list used in call"""
- self.verify(" #def testMeth($a, $b='default') \n1234-$a$b\n #end def\n$testMeth([1,2,3])",
- "1234-[1, 2, 3]default\n")
-
- def test7(self):
- """#def with *args, gobble WS"""
- self.verify(" #def testMeth($*args) \n1234-$args\n #end def\n$testMeth",
- "1234-()\n")
-
- def test8(self):
- """#def with **KWs, gobble WS"""
- self.verify(" #def testMeth($**KWs) \n1234-$KWs\n #end def\n$testMeth",
- "1234-{}\n")
-
- def test9(self):
- """#def with *args + **KWs, gobble WS"""
- self.verify(" #def testMeth($*args, $**KWs) \n1234-$args-$KWs\n #end def\n$testMeth",
- "1234-()-{}\n")
-
- def test10(self):
- """#def with *args + **KWs, gobble WS"""
- self.verify(
- " #def testMeth($*args, $**KWs) \n1234-$args-$KWs.a\n #end def\n$testMeth(1,2, a=1)",
- "1234-(1, 2)-1\n")
-
-
- def test11(self):
- """single line #def with extra WS"""
- self.verify(
- "#def testMeth: aoeuaoeu\n- $testMeth -",
- "- aoeuaoeu -")
-
- def test12(self):
- """single line #def with extra WS and nested $placeholders"""
- self.verify(
- "#def testMeth: $anInt $aFunc(1234)\n- $testMeth -",
- "- 1 1234 -")
-
- def test13(self):
- """single line #def escaped $placeholders"""
- self.verify(
- "#def testMeth: \$aFunc(\$anInt)\n- $testMeth -",
- "- $aFunc($anInt) -")
-
- def test14(self):
- """single line #def 1 escaped $placeholders"""
- self.verify(
- "#def testMeth: \$aFunc($anInt)\n- $testMeth -",
- "- $aFunc(1) -")
-
- def test15(self):
- """single line #def 1 escaped $placeholders + more WS"""
- self.verify(
- "#def testMeth : \$aFunc($anInt)\n- $testMeth -",
- "- $aFunc(1) -")
-
- def test16(self):
- """multiline #def with $ on methodName"""
- self.verify("#def $testMeth\n1234\n#end def\n$testMeth",
- "1234\n")
-
- def test17(self):
- """single line #def with $ on methodName"""
- self.verify("#def $testMeth:1234\n$testMeth",
- "1234")
-
- def test18(self):
- """single line #def with an argument"""
- self.verify("#def $testMeth($arg=1234):$arg\n$testMeth",
- "1234")
-
- def test19(self):
- """#def that extends over two lines with arguments"""
- self.verify("#def $testMeth($arg=1234,\n"
- +" $arg2=5678)\n"
- +"$arg $arg2\n"
- +"#end def\n"
- +"$testMeth",
- "1234 5678\n")
-
-class DecoratorDirective(OutputTest):
- def test1(self):
- """single line #def with decorator"""
-
- self.verify("#@ blah", "#@ blah")
- self.verify("#@23 blah", "#@23 blah")
- self.verify("#@@TR: comment", "#@@TR: comment")
-
- self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n"
- +"#@testdecorator"
- +"\n#def $testMeth():1234\n$testMeth",
-
- "1234")
-
- self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n"
- +"#@testdecorator"
- +"\n#block $testMeth():1234",
-
- "1234")
-
- try:
- self.verify(
- "#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n"
- +"#@testdecorator\n sdf"
- +"\n#def $testMeth():1234\n$testMeth",
-
- "1234")
- except ParseError:
- pass
- else:
- self.fail('should raise a ParseError')
-
- def test2(self):
- """#def with multiple decorators"""
- self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n"
- +"#@testdecorator\n"
- +"#@testdecorator\n"
- +"#def testMeth\n"
- +"1234\n"
- "#end def\n"
- "$testMeth",
- "1234\n")
-
-if versionTuple < (2, 4):
- del DecoratorDirective
-
-class BlockDirective(OutputTest):
-
- def test1(self):
- """#block without argstring"""
- self.verify("#block testBlock\n1234\n#end block",
- "1234\n")
-
- self.verify("#block testBlock ##comment\n1234\n#end block",
- "1234\n")
-
- def test2(self):
- """#block without argstring, gobble WS"""
- self.verify(" #block testBlock \n1234\n #end block ",
- "1234\n")
-
- def test3(self):
- """#block with argstring, gobble WS
-
- Because blocks can be reused in multiple parts of the template arguments
- (!!with defaults!!) can be given."""
-
- self.verify(" #block testBlock($a=999) \n1234-$a\n #end block ",
- "1234-999\n")
-
- def test4(self):
- """#block with 2 args, gobble WS"""
- self.verify(" #block testBlock($a=999, $b=444) \n1234-$a$b\n #end block ",
- "1234-999444\n")
-
-
- def test5(self):
- """#block with 2 nested blocks
-
- Blocks can be nested to any depth and the name of the block is optional
- for the #end block part: #end block OR #end block [name] """
-
- self.verify("""#block testBlock
-this is a test block
-#block outerNest
-outer
-#block innerNest
-inner
-#end block innerNest
-#end block outerNest
----
-#end block testBlock
-""",
- "this is a test block\nouter\ninner\n---\n")
-
-
- def test6(self):
- """single line #block """
- self.verify(
- "#block testMeth: This is my block",
- "This is my block")
-
- def test7(self):
- """single line #block with WS"""
- self.verify(
- "#block testMeth: This is my block",
- "This is my block")
-
- def test8(self):
- """single line #block 1 escaped $placeholders"""
- self.verify(
- "#block testMeth: \$aFunc($anInt)",
- "$aFunc(1)")
-
- def test9(self):
- """single line #block 1 escaped $placeholders + WS"""
- self.verify(
- "#block testMeth: \$aFunc( $anInt )",
- "$aFunc( 1 )")
-
- def test10(self):
- """single line #block 1 escaped $placeholders + more WS"""
- self.verify(
- "#block testMeth : \$aFunc( $anInt )",
- "$aFunc( 1 )")
-
- def test11(self):
- """multiline #block $ on argstring"""
- self.verify("#block $testBlock\n1234\n#end block",
- "1234\n")
-
- def test12(self):
- """single line #block with $ on methodName """
- self.verify(
- "#block $testMeth: This is my block",
- "This is my block")
-
- def test13(self):
- """single line #block with an arg """
- self.verify(
- "#block $testMeth($arg='This is my block'): $arg",
- "This is my block")
-
- def test14(self):
- """single line #block with None for content"""
- self.verify(
- """#block $testMeth: $None\ntest $testMeth-""",
- "test -")
-
- def test15(self):
- """single line #block with nothing for content"""
- self.verify(
- """#block $testMeth: \nfoo\n#end block\ntest $testMeth-""",
- "foo\ntest foo\n-")
-
-class IncludeDirective(OutputTest):
-
- def setUp(self):
- fp = open('parseTest.txt', 'w')
- fp.write("$numOne $numTwo")
- fp.flush()
- fp.close
-
- def tearDown(self):
- if os.path.exists('parseTest.txt'):
- os.remove('parseTest.txt')
-
- def test1(self):
- """#include raw of source $emptyString"""
- self.verify("#include raw source=$emptyString",
- "")
-
- def test2(self):
- """#include raw of source $blockToBeParsed"""
- self.verify("#include raw source=$blockToBeParsed",
- "$numOne $numTwo")
-
- def test3(self):
- """#include raw of 'parseTest.txt'"""
- self.verify("#include raw 'parseTest.txt'",
- "$numOne $numTwo")
-
- def test4(self):
- """#include raw of $includeFileName"""
- self.verify("#include raw $includeFileName",
- "$numOne $numTwo")
-
- def test5(self):
- """#include raw of $includeFileName, with WS"""
- self.verify(" #include raw $includeFileName ",
- "$numOne $numTwo")
-
- def test6(self):
- """#include raw of source= , with WS"""
- self.verify(" #include raw source='This is my $Source '*2 ",
- "This is my $Source This is my $Source ")
-
- def test7(self):
- """#include of $blockToBeParsed"""
- self.verify("#include source=$blockToBeParsed",
- "1 2")
-
- def test8(self):
- """#include of $blockToBeParsed, with WS"""
- self.verify(" #include source=$blockToBeParsed ",
- "1 2")
-
- def test9(self):
- """#include of 'parseTest.txt', with WS"""
- self.verify(" #include source=$blockToBeParsed ",
- "1 2")
-
- def test10(self):
- """#include of "parseTest.txt", with WS"""
- self.verify(" #include source=$blockToBeParsed ",
- "1 2")
-
- def test11(self):
- """#include of 'parseTest.txt', with WS and surrounding text"""
- self.verify("aoeu\n #include source=$blockToBeParsed \naoeu",
- "aoeu\n1 2aoeu")
-
- def test12(self):
- """#include of 'parseTest.txt', with WS and explicit closure"""
- self.verify(" #include source=$blockToBeParsed# ",
- " 1 2 ")
-
-
-class SilentDirective(OutputTest):
-
- def test1(self):
- """simple #silent"""
- self.verify("#silent $aFunc",
- "")
-
- def test2(self):
- """simple #silent"""
- self.verify("#silent $anObj.callIt\n$anObj.callArg",
- "1234")
-
- self.verify("#silent $anObj.callIt ##comment\n$anObj.callArg",
- "1234")
-
- def test3(self):
- """simple #silent"""
- self.verify("#silent $anObj.callIt(99)\n$anObj.callArg",
- "99")
-
-class SetDirective(OutputTest):
-
- def test1(self):
- """simple #set"""
- self.verify("#set $testVar = 'blarg'\n$testVar",
- "blarg")
- self.verify("#set testVar = 'blarg'\n$testVar",
- "blarg")
-
-
- self.verify("#set testVar = 'blarg'##comment\n$testVar",
- "blarg")
-
- def test2(self):
- """simple #set with no WS between operands"""
- self.verify("#set $testVar='blarg'",
- "")
- def test3(self):
- """#set + use of var"""
- self.verify("#set $testVar = 'blarg'\n$testVar",
- "blarg")
-
- def test4(self):
- """#set + use in an #include"""
- self.verify("#set global $aSetVar = 1234\n#include source=$includeBlock2",
- "1 2 1234")
-
- def test5(self):
- """#set with a dictionary"""
- self.verify( """#set $testDict = {'one':'one1','two':'two2','three':'three3'}
-$testDict.one
-$testDict.two""",
- "one1\ntwo2")
-
- def test6(self):
- """#set with string, then used in #if block"""
-
- self.verify("""#set $test='a string'\n#if $test#blarg#end if""",
- "blarg")
-
- def test7(self):
- """simple #set, gobble WS"""
- self.verify(" #set $testVar = 'blarg' ",
- "")
-
- def test8(self):
- """simple #set, don't gobble WS"""
- self.verify(" #set $testVar = 'blarg'#---",
- " ---")
-
- def test9(self):
- """simple #set with a list"""
- self.verify(" #set $testVar = [1, 2, 3] \n$testVar",
- "[1, 2, 3]")
-
- def test10(self):
- """simple #set global with a list"""
- self.verify(" #set global $testVar = [1, 2, 3] \n$testVar",
- "[1, 2, 3]")
-
- def test11(self):
- """simple #set global with a list and *cache
-
- Caching only works with global #set vars. Local vars are not accesible
- to the cache namespace.
- """
-
- self.verify(" #set global $testVar = [1, 2, 3] \n$*testVar",
- "[1, 2, 3]")
-
- def test12(self):
- """simple #set global with a list and *<int>*cache"""
- self.verify(" #set global $testVar = [1, 2, 3] \n$*5*testVar",
- "[1, 2, 3]")
-
- def test13(self):
- """simple #set with a list and *<float>*cache"""
- self.verify(" #set global $testVar = [1, 2, 3] \n$*.5*testVar",
- "[1, 2, 3]")
-
- def test14(self):
- """simple #set without NameMapper on"""
- self.verify("""#compiler useNameMapper = 0\n#set $testVar = 1 \n$testVar""",
- "1")
-
- def test15(self):
- """simple #set without $"""
- self.verify("""#set testVar = 1 \n$testVar""",
- "1")
-
- def test16(self):
- """simple #set global without $"""
- self.verify("""#set global testVar = 1 \n$testVar""",
- "1")
-
- def test17(self):
- """simple #set module without $"""
- self.verify("""#set module __foo__ = 'bar'\n$__foo__""",
- "bar")
-
- def test18(self):
- """#set with i,j=list style assignment"""
- self.verify("""#set i,j = [1,2]\n$i$j""",
- "12")
- self.verify("""#set $i,$j = [1,2]\n$i$j""",
- "12")
-
- def test19(self):
- """#set with (i,j)=list style assignment"""
- self.verify("""#set (i,j) = [1,2]\n$i$j""",
- "12")
- self.verify("""#set ($i,$j) = [1,2]\n$i$j""",
- "12")
-
- def test20(self):
- """#set with i, (j,k)=list style assignment"""
- self.verify("""#set i, (j,k) = [1,(2,3)]\n$i$j$k""",
- "123")
- self.verify("""#set $i, ($j,$k) = [1,(2,3)]\n$i$j$k""",
- "123")
-
-
-class IfDirective(OutputTest):
-
- def test1(self):
- """simple #if block"""
- self.verify("#if 1\n$aStr\n#end if\n",
- "blarg\n")
-
- self.verify("#if 1:\n$aStr\n#end if\n",
- "blarg\n")
-
- self.verify("#if 1: \n$aStr\n#end if\n",
- "blarg\n")
-
- self.verify("#if 1: ##comment \n$aStr\n#end if\n",
- "blarg\n")
-
- self.verify("#if 1 ##comment \n$aStr\n#end if\n",
- "blarg\n")
-
- self.verify("#if 1##for i in range(10)#$i#end for##end if",
- '0123456789')
-
- self.verify("#if 1: #for i in range(10)#$i#end for",
- '0123456789')
-
- self.verify("#if 1: #for i in range(10):$i",
- '0123456789')
-
- def test2(self):
- """simple #if block, with WS"""
- self.verify(" #if 1\n$aStr\n #end if \n",
- "blarg\n")
- def test3(self):
- """simple #if block, with WS and explicit closures"""
- self.verify(" #if 1#\n$aStr\n #end if #--\n",
- " \nblarg\n --\n")
-
- def test4(self):
- """#if block using $numOne"""
- self.verify("#if $numOne\n$aStr\n#end if\n",
- "blarg\n")
-
- def test5(self):
- """#if block using $zero"""
- self.verify("#if $zero\n$aStr\n#end if\n",
- "")
- def test6(self):
- """#if block using $emptyString"""
- self.verify("#if $emptyString\n$aStr\n#end if\n",
- "")
- def test7(self):
- """#if ... #else ... block using a $emptyString"""
- self.verify("#if $emptyString\n$anInt\n#else\n$anInt - $anInt\n#end if",
- "1 - 1\n")
-
- def test8(self):
- """#if ... #elif ... #else ... block using a $emptyString"""
- self.verify("#if $emptyString\n$c\n#elif $numOne\n$numOne\n#else\n$c - $c\n#end if",
- "1\n")
-
- def test9(self):
- """#if 'not' test, with #slurp"""
- self.verify("#if not $emptyString\n$aStr#slurp\n#end if\n",
- "blarg")
-
- def test10(self):
- """#if block using $*emptyString
-
- This should barf
- """
- try:
- self.verify("#if $*emptyString\n$aStr\n#end if\n",
- "")
- except ParseError:
- pass
- else:
- self.fail('This should barf')
-
- def test11(self):
- """#if block using invalid top-level $(placeholder) syntax - should barf"""
-
- for badSyntax in ("#if $*5*emptyString\n$aStr\n#end if\n",
- "#if ${emptyString}\n$aStr\n#end if\n",
- "#if $(emptyString)\n$aStr\n#end if\n",
- "#if $[emptyString]\n$aStr\n#end if\n",
- "#if $!emptyString\n$aStr\n#end if\n",
- ):
- try:
- self.verify(badSyntax, "")
- except ParseError:
- pass
- else:
- self.fail('This should barf')
-
- def test12(self):
- """#if ... #else if ... #else ... block using a $emptyString
- Same as test 8 but using else if instead of elif"""
- self.verify("#if $emptyString\n$c\n#else if $numOne\n$numOne\n#else\n$c - $c\n#end if",
- "1\n")
-
-
- def test13(self):
- """#if# ... #else # ... block using a $emptyString with """
- self.verify("#if $emptyString# $anInt#else#$anInt - $anInt#end if",
- "1 - 1")
-
- def test14(self):
- """single-line #if: simple"""
- self.verify("#if $emptyString then 'true' else 'false'",
- "false")
-
- def test15(self):
- """single-line #if: more complex"""
- self.verify("#if $anInt then 'true' else 'false'",
- "true")
-
- def test16(self):
- """single-line #if: with the words 'else' and 'then' in the output """
- self.verify("#if ($anInt and not $emptyString==''' else ''') then $str('then') else 'else'",
- "then")
-
- def test17(self):
- """single-line #if: """
- self.verify("#if 1: foo\n#if 0: bar\n#if 1: foo",
- "foo\nfoo")
-
-
- self.verify("#if 1: foo\n#if 0: bar\n#if 1: foo",
- "foo\nfoo")
-
- def test18(self):
- """single-line #if: \n#else: """
- self.verify("#if 1: foo\n#elif 0: bar",
- "foo\n")
-
- self.verify("#if 1: foo\n#elif 0: bar\n#else: blarg\n",
- "foo\n")
-
- self.verify("#if 0: foo\n#elif 0: bar\n#else: blarg\n",
- "blarg\n")
-
-class UnlessDirective(OutputTest):
-
- def test1(self):
- """#unless 1"""
- self.verify("#unless 1\n 1234 \n#end unless",
- "")
-
- self.verify("#unless 1:\n 1234 \n#end unless",
- "")
-
- self.verify("#unless 1: ##comment\n 1234 \n#end unless",
- "")
-
- self.verify("#unless 1 ##comment\n 1234 \n#end unless",
- "")
-
-
- def test2(self):
- """#unless 0"""
- self.verify("#unless 0\n 1234 \n#end unless",
- " 1234 \n")
-
- def test3(self):
- """#unless $none"""
- self.verify("#unless $none\n 1234 \n#end unless",
- " 1234 \n")
-
- def test4(self):
- """#unless $numTwo"""
- self.verify("#unless $numTwo\n 1234 \n#end unless",
- "")
-
- def test5(self):
- """#unless $numTwo with WS"""
- self.verify(" #unless $numTwo \n 1234 \n #end unless ",
- "")
-
- def test6(self):
- """single-line #unless"""
- self.verify("#unless 1: 1234", "")
- self.verify("#unless 0: 1234", "1234")
- self.verify("#unless 0: 1234\n"*2, "1234\n"*2)
-
-class PSP(OutputTest):
- def searchList(self):
- return None
-
- def test1(self):
- """simple <%= [int] %>"""
- self.verify("<%= 1234 %>", "1234")
-
- def test2(self):
- """simple <%= [string] %>"""
- self.verify("<%= 'blarg' %>", "blarg")
-
- def test3(self):
- """simple <%= None %>"""
- self.verify("<%= None %>", "")
- def test4(self):
- """simple <%= [string] %> + $anInt"""
- self.verify("<%= 'blarg' %>$anInt", "blarg1")
-
- def test5(self):
- """simple <%= [EXPR] %> + $anInt"""
- self.verify("<%= ('blarg'*2).upper() %>$anInt", "BLARGBLARG1")
-
- def test6(self):
- """for loop in <%%>"""
- self.verify("<% for i in range(5):%>1<%end%>", "11111")
-
- def test7(self):
- """for loop in <%%> and using <%=i%>"""
- self.verify("<% for i in range(5):%><%=i%><%end%>", "01234")
-
- def test8(self):
- """for loop in <% $%> and using <%=i%>"""
- self.verify("""<% for i in range(5):
- i=i*2$%><%=i%><%end%>""", "02468")
-
- def test9(self):
- """for loop in <% $%> and using <%=i%> plus extra text"""
- self.verify("""<% for i in range(5):
- i=i*2$%><%=i%>-<%end%>""", "0-2-4-6-8-")
-
- def test10(self):
- """ Using getVar and write within a PSP """
- self._searchList = [{'me' : 1}]
- template = '''This is my template
-<%
-me = self.getVar('me')
-if isinstance(me, int):
- write('Bork')
-else:
- write('Nork')
-%>'''
- self.verify(template, 'This is my template\nBork')
-
-
-class WhileDirective(OutputTest):
- def test1(self):
- """simple #while with a counter"""
- self.verify("#set $i = 0\n#while $i < 5\n$i#slurp\n#set $i += 1\n#end while",
- "01234")
-
-class ContinueDirective(OutputTest):
- def test1(self):
- """#continue with a #while"""
- self.verify("""#set $i = 0
-#while $i < 5
-#if $i == 3
- #set $i += 1
- #continue
-#end if
-$i#slurp
-#set $i += 1
-#end while""",
- "0124")
-
- def test2(self):
- """#continue with a #for"""
- self.verify("""#for $i in range(5)
-#if $i == 3
- #continue
-#end if
-$i#slurp
-#end for""",
- "0124")
-
-class BreakDirective(OutputTest):
- def test1(self):
- """#break with a #while"""
- self.verify("""#set $i = 0
-#while $i < 5
-#if $i == 3
- #break
-#end if
-$i#slurp
-#set $i += 1
-#end while""",
- "012")
-
- def test2(self):
- """#break with a #for"""
- self.verify("""#for $i in range(5)
-#if $i == 3
- #break
-#end if
-$i#slurp
-#end for""",
- "012")
-
-
-class TryDirective(OutputTest):
-
- def test1(self):
- """simple #try
- """
- self.verify("#try\n1234\n#except\nblarg\n#end try",
- "1234\n")
-
- def test2(self):
- """#try / #except with #raise
- """
- self.verify("#try\n#raise ValueError\n#except\nblarg\n#end try",
- "blarg\n")
-
- def test3(self):
- """#try / #except with #raise + WS
-
- Should gobble
- """
- self.verify(" #try \n #raise ValueError \n #except \nblarg\n #end try",
- "blarg\n")
-
-
- def test4(self):
- """#try / #except with #raise + WS and leading text
-
- Shouldn't gobble
- """
- self.verify("--#try \n #raise ValueError \n #except \nblarg\n #end try#--",
- "--\nblarg\n --")
-
- def test5(self):
- """nested #try / #except with #raise
- """
- self.verify(
-"""#try
- #raise ValueError
-#except
- #try
- #raise ValueError
- #except
-blarg
- #end try
-#end try""",
- "blarg\n")
-
-class PassDirective(OutputTest):
- def test1(self):
- """#pass in a #try / #except block
- """
- self.verify("#try\n#raise ValueError\n#except\n#pass\n#end try",
- "")
-
- def test2(self):
- """#pass in a #try / #except block + WS
- """
- self.verify(" #try \n #raise ValueError \n #except \n #pass \n #end try",
- "")
-
-
-class AssertDirective(OutputTest):
- def test1(self):
- """simple #assert
- """
- self.verify("#set $x = 1234\n#assert $x == 1234",
- "")
-
- def test2(self):
- """simple #assert that fails
- """
- def test(self=self):
- self.verify("#set $x = 1234\n#assert $x == 999",
- ""),
- self.failUnlessRaises(AssertionError, test)
-
- def test3(self):
- """simple #assert with WS
- """
- self.verify("#set $x = 1234\n #assert $x == 1234 ",
- "")
-
-
-class RaiseDirective(OutputTest):
- def test1(self):
- """simple #raise ValueError
-
- Should raise ValueError
- """
- def test(self=self):
- self.verify("#raise ValueError",
- ""),
- self.failUnlessRaises(ValueError, test)
-
- def test2(self):
- """#raise ValueError in #if block
-
- Should raise ValueError
- """
- def test(self=self):
- self.verify("#if 1\n#raise ValueError\n#end if\n",
- "")
- self.failUnlessRaises(ValueError, test)
-
-
- def test3(self):
- """#raise ValueError in #if block
-
- Shouldn't raise ValueError
- """
- self.verify("#if 0\n#raise ValueError\n#else\nblarg#end if\n",
- "blarg\n")
-
-
-
-class ImportDirective(OutputTest):
- def test1(self):
- """#import math
- """
- self.verify("#import math",
- "")
-
- def test2(self):
- """#import math + WS
-
- Should gobble
- """
- self.verify(" #import math ",
- "")
-
- def test3(self):
- """#import math + WS + leading text
-
- Shouldn't gobble
- """
- self.verify(" -- #import math ",
- " -- ")
-
- def test4(self):
- """#from math import syn
- """
- self.verify("#from math import cos",
- "")
-
- def test5(self):
- """#from math import cos + WS
- Should gobble
- """
- self.verify(" #from math import cos ",
- "")
-
- def test6(self):
- """#from math import cos + WS + leading text
- Shouldn't gobble
- """
- self.verify(" -- #from math import cos ",
- " -- ")
-
- def test7(self):
- """#from math import cos -- use it
- """
- self.verify("#from math import cos\n$cos(0)",
- "1.0")
-
- def test8(self):
- """#from math import cos,tan,sin -- and use them
- """
- self.verify("#from math import cos, tan, sin\n$cos(0)-$tan(0)-$sin(0)",
- "1.0-0.0-0.0")
-
- def test9(self):
- """#import os.path -- use it
- """
-
- self.verify("#import os.path\n$os.path.exists('.')",
- repr(True))
-
- def test10(self):
- """#import os.path -- use it with NameMapper turned off
- """
- self.verify("""##
-#compiler-settings
-useNameMapper=False
-#end compiler-settings
-#import os.path
-$os.path.exists('.')""",
- repr(True))
-
- def test11(self):
- """#from math import *
- """
-
- self.verify("#from math import *\n$pow(1,2) $log10(10)",
- "1.0 1.0")
-
-class CompilerDirective(OutputTest):
- def test1(self):
- """overriding the commentStartToken
- """
- self.verify("""$anInt##comment
-#compiler commentStartToken = '//'
-$anInt//comment
-""",
- "1\n1\n")
-
- def test2(self):
- """overriding and resetting the commentStartToken
- """
- self.verify("""$anInt##comment
-#compiler commentStartToken = '//'
-$anInt//comment
-#compiler reset
-$anInt//comment
-""",
- "1\n1\n1//comment\n")
-
-
-class CompilerSettingsDirective(OutputTest):
-
- def test1(self):
- """overriding the cheetahVarStartToken
- """
- self.verify("""$anInt
-#compiler-settings
-cheetahVarStartToken = @
-#end compiler-settings
-@anInt
-#compiler-settings reset
-$anInt
-""",
- "1\n1\n1\n")
-
- def test2(self):
- """overriding the directiveStartToken
- """
- self.verify("""#set $x = 1234
-$x
-#compiler-settings
-directiveStartToken = @
-#end compiler-settings
-@set $x = 1234
-$x
-""",
- "1234\n1234\n")
-
- def test3(self):
- """overriding the commentStartToken
- """
- self.verify("""$anInt##comment
-#compiler-settings
-commentStartToken = //
-#end compiler-settings
-$anInt//comment
-""",
- "1\n1\n")
-
-if sys.platform.startswith('java'):
- del CompilerDirective
- del CompilerSettingsDirective
-
-class ExtendsDirective(OutputTest):
-
- def test1(self):
- """#extends Cheetah.Templates._SkeletonPage"""
- self.verify("""#from Cheetah.Templates._SkeletonPage import _SkeletonPage
-#extends _SkeletonPage
-#implements respond
-$spacer()
-""",
- '<img src="spacer.gif" width="1" height="1" alt="" />\n')
-
-
- self.verify("""#from Cheetah.Templates._SkeletonPage import _SkeletonPage
-#extends _SkeletonPage
-#implements respond(foo=1234)
-$spacer()$foo
-""",
- '<img src="spacer.gif" width="1" height="1" alt="" />1234\n')
-
- def test2(self):
- """#extends Cheetah.Templates.SkeletonPage without #import"""
- self.verify("""#extends Cheetah.Templates.SkeletonPage
-#implements respond
-$spacer()
-""",
- '<img src="spacer.gif" width="1" height="1" alt="" />\n')
-
- def test3(self):
- """#extends Cheetah.Templates.SkeletonPage.SkeletonPage without #import"""
- self.verify("""#extends Cheetah.Templates.SkeletonPage.SkeletonPage
-#implements respond
-$spacer()
-""",
- '<img src="spacer.gif" width="1" height="1" alt="" />\n')
-
- def test4(self):
- """#extends with globals and searchList test"""
- self.verify("""#extends Cheetah.Templates.SkeletonPage
-#set global g="Hello"
-#implements respond
-$g $numOne
-""",
- 'Hello 1\n')
-
-
-class SuperDirective(OutputTest):
- def test1(self):
- tmpl1 = Template.compile('''$foo $bar(99)
- #def foo: this is base foo
- #def bar(arg): super-$arg''')
-
- tmpl2 = tmpl1.subclass('''
- #implements dummy
- #def foo
- #super
- This is child foo
- #super(trans=trans)
- $bar(1234)
- #end def
- #def bar(arg): #super($arg)
- ''')
- expected = ('this is base foo '
- 'This is child foo\nthis is base foo '
- 'super-1234\n super-99')
- assert str(tmpl2()).strip()==expected
-
-
-class ImportantExampleCases(OutputTest):
- def test1(self):
- """how to make a comma-delimited list"""
- self.verify("""#set $sep = ''
-#for $letter in $letterList
-$sep$letter#slurp
-#set $sep = ', '
-#end for
-""",
- "a, b, c")
-
-class FilterDirective(OutputTest):
- convertEOLs=False
-
- def _getCompilerSettings(self):
- return {'useFilterArgsInPlaceholders':True}
-
- def test1(self):
- """#filter Filter
- """
- self.verify("#filter Filter\n$none#end filter",
- "")
-
- self.verify("#filter Filter: $none",
- "")
-
- def test2(self):
- """#filter ReplaceNone with WS
- """
- self.verify("#filter Filter \n$none#end filter",
- "")
-
- def test3(self):
- """#filter MaxLen -- maxlen of 5"""
-
- self.verify("#filter MaxLen \n${tenDigits, $maxlen=5}#end filter",
- "12345")
-
- def test4(self):
- """#filter MaxLen -- no maxlen
- """
- self.verify("#filter MaxLen \n${tenDigits}#end filter",
- "1234567890")
-
- def test5(self):
- """#filter WebSafe -- basic usage
- """
- self.verify("#filter WebSafe \n$webSafeTest#end filter",
- "abc &lt;=&gt; &amp;")
-
- def test6(self):
- """#filter WebSafe -- also space
- """
- self.verify("#filter WebSafe \n${webSafeTest, $also=' '}#end filter",
- "abc&nbsp;&lt;=&gt;&nbsp;&amp;")
-
- def test7(self):
- """#filter WebSafe -- also space, without $ on the args
- """
- self.verify("#filter WebSafe \n${webSafeTest, also=' '}#end filter",
- "abc&nbsp;&lt;=&gt;&nbsp;&amp;")
-
- def test8(self):
- """#filter Strip -- trailing newline
- """
- self.verify("#filter Strip\n$strip1#end filter",
- "strippable whitespace\n")
-
- def test9(self):
- """#filter Strip -- no trailing newine
- """
- self.verify("#filter Strip\n$strip2#end filter",
- "strippable whitespace")
-
- def test10(self):
- """#filter Strip -- multi-line
- """
- self.verify("#filter Strip\n$strip3#end filter",
- "strippable whitespace\n1 2 3\n")
-
- def test11(self):
- """#filter StripSqueeze -- canonicalize all whitespace to ' '
- """
- self.verify("#filter StripSqueeze\n$strip3#end filter",
- "strippable whitespace 1 2 3")
-
-
-class EchoDirective(OutputTest):
- def test1(self):
- """#echo 1234
- """
- self.verify("#echo 1234",
- "1234")
-
-class SilentDirective(OutputTest):
- def test1(self):
- """#silent 1234
- """
- self.verify("#silent 1234",
- "")
-
-class ErrorCatcherDirective(OutputTest):
- pass
-
-
-class VarExists(OutputTest): # Template.varExists()
-
- def test1(self):
- """$varExists('$anInt')
- """
- self.verify("$varExists('$anInt')",
- repr(True))
-
- def test2(self):
- """$varExists('anInt')
- """
- self.verify("$varExists('anInt')",
- repr(True))
-
- def test3(self):
- """$varExists('$anInt')
- """
- self.verify("$varExists('$bogus')",
- repr(False))
-
- def test4(self):
- """$varExists('$anInt') combined with #if false
- """
- self.verify("#if $varExists('$bogus')\n1234\n#else\n999\n#end if",
- "999\n")
-
- def test5(self):
- """$varExists('$anInt') combined with #if true
- """
- self.verify("#if $varExists('$anInt')\n1234\n#else\n999#end if",
- "1234\n")
-
-class GetVar(OutputTest): # Template.getVar()
- def test1(self):
- """$getVar('$anInt')
- """
- self.verify("$getVar('$anInt')",
- "1")
-
- def test2(self):
- """$getVar('anInt')
- """
- self.verify("$getVar('anInt')",
- "1")
-
- def test3(self):
- """$self.getVar('anInt')
- """
- self.verify("$self.getVar('anInt')",
- "1")
-
- def test4(self):
- """$getVar('bogus', 1234)
- """
- self.verify("$getVar('bogus', 1234)",
- "1234")
-
- def test5(self):
- """$getVar('$bogus', 1234)
- """
- self.verify("$getVar('$bogus', 1234)",
- "1234")
-
-
-class MiscComplexSyntax(OutputTest):
- def test1(self):
- """Complex use of {},[] and () in a #set expression
- ----
- #set $c = {'A':0}[{}.get('a', {'a' : 'A'}['a'])]
- $c
- """
- self.verify("#set $c = {'A':0}[{}.get('a', {'a' : 'A'}['a'])]\n$c",
- "0")
-
-
-class CGI(OutputTest):
- """CGI scripts with(out) the CGI environment and with(out) GET variables.
- """
- convertEOLs=False
-
- def _beginCGI(self):
- os.environ['REQUEST_METHOD'] = "GET"
- def _endCGI(self):
- try:
- del os.environ['REQUEST_METHOD']
- except KeyError:
- pass
- _guaranteeNoCGI = _endCGI
-
-
- def test1(self):
- """A regular template."""
- self._guaranteeNoCGI()
- source = "#extends Cheetah.Tools.CGITemplate\n" + \
- "#implements respond\n" + \
- "$cgiHeaders#slurp\n" + \
- "Hello, world!"
- self.verify(source, "Hello, world!")
-
-
- def test2(self):
- """A CGI script."""
- self._beginCGI()
- source = "#extends Cheetah.Tools.CGITemplate\n" + \
- "#implements respond\n" + \
- "$cgiHeaders#slurp\n" + \
- "Hello, world!"
- self.verify(source, "Content-type: text/html\n\nHello, world!")
- self._endCGI()
-
-
- def test3(self):
- """A (pseudo) Webware servlet.
-
- This uses the Python syntax escape to set
- self._CHEETAH__isControlledByWebKit.
- We could instead do '#silent self._CHEETAH__isControlledByWebKit = True',
- taking advantage of the fact that it will compile unchanged as long
- as there's no '$' in the statement. (It won't compile with an '$'
- because that would convert to a function call, and you can't assign
- to a function call.) Because this isn't really being called from
- Webware, we'd better not use any Webware services! Likewise, we'd
- better not call $cgiImport() because it would be misled.
- """
- self._beginCGI()
- source = "#extends Cheetah.Tools.CGITemplate\n" + \
- "#implements respond\n" + \
- "<% self._CHEETAH__isControlledByWebKit = True %>#slurp\n" + \
- "$cgiHeaders#slurp\n" + \
- "Hello, world!"
- self.verify(source, "Hello, world!")
- self._endCGI()
-
-
- def test4(self):
- """A CGI script with a GET variable."""
- self._beginCGI()
- os.environ['QUERY_STRING'] = "cgiWhat=world"
- source = "#extends Cheetah.Tools.CGITemplate\n" + \
- "#implements respond\n" + \
- "$cgiHeaders#slurp\n" + \
- "#silent $webInput(['cgiWhat'])##slurp\n" + \
- "Hello, $cgiWhat!"
- self.verify(source,
- "Content-type: text/html\n\nHello, world!")
- del os.environ['QUERY_STRING']
- self._endCGI()
-
-
-
-class WhitespaceAfterDirectiveTokens(OutputTest):
- def _getCompilerSettings(self):
- return {'allowWhitespaceAfterDirectiveStartToken':True}
-
- def test1(self):
- self.verify("# for i in range(10): $i",
- "0123456789")
- self.verify("# for i in range(10)\n$i# end for",
- "0123456789")
- self.verify("# for i in range(10)#$i#end for",
- "0123456789")
-
-
-
-class DefmacroDirective(OutputTest):
- def _getCompilerSettings(self):
- def aMacro(src):
- return '$aStr'
-
- return {'macroDirectives':{'aMacro':aMacro
- }}
-
- def test1(self):
- self.verify("""\
-#defmacro inc: #set @src +=1
-#set i = 1
-#inc: $i
-$i""",
- "2")
-
-
-
- self.verify("""\
-#defmacro test
-#for i in range(10): @src
-#end defmacro
-#test: $i-foo#slurp
-#for i in range(3): $i""",
- "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo012")
-
- self.verify("""\
-#defmacro test
-#for i in range(10): @src
-#end defmacro
-#test: $i-foo
-#for i in range(3): $i""",
- "0-foo\n1-foo\n2-foo\n3-foo\n4-foo\n5-foo\n6-foo\n7-foo\n8-foo\n9-foo\n012")
-
-
- self.verify("""\
-#defmacro test: #for i in range(10): @src
-#test: $i-foo#slurp
--#for i in range(3): $i""",
- "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
-
- self.verify("""\
-#defmacro test##for i in range(10): @src#end defmacro##slurp
-#test: $i-foo#slurp
--#for i in range(3): $i""",
- "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
-
- self.verify("""\
-#defmacro testFoo: nothing
-#defmacro test(foo=1234): #for i in range(10): @src
-#test foo=234: $i-foo#slurp
--#for i in range(3): $i""",
- "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
-
- self.verify("""\
-#defmacro testFoo: nothing
-#defmacro test(foo=1234): #for i in range(10): @src@foo
-#test foo='-foo'#$i#end test#-#for i in range(3): $i""",
- "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
-
- self.verify("""\
-#defmacro testFoo: nothing
-#defmacro test(foo=1234): #for i in range(10): @src.strip()@foo
-#test foo='-foo': $i
--#for i in range(3): $i""",
- "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
-
- def test2(self):
- self.verify("#aMacro: foo",
- "blarg")
- self.verify("#defmacro nested: @macros.aMacro(@src)\n#nested: foo",
- "blarg")
-
-
-class Indenter(OutputTest):
- convertEOLs=False
-
- source = """
-public class X
-{
- #for $method in $methods
- $getMethod($method)
-
- #end for
-}
-//end of class
-
-#def getMethod($method)
- #indent ++
- public $getType($method) ${method.Name}($getParams($method.Params));
- #indent --
-#end def
-
-#def getParams($params)
- #indent off
-
- #for $counter in $range($len($params))
- #if $counter == len($params) - 1
- $params[$counter]#slurp
- #else:
- $params[$counter],
- #end if
- #end for
- #indent on
-#end def
-
-#def getType($method)
- #indent push
- #indent=0
- #if $method.Type == "VT_VOID"
- void#slurp
- #elif $method.Type == "VT_INT"
- int#slurp
- #elif $method.Type == "VT_VARIANT"
- Object#slurp
- #end if
- #indent pop
-#end def
-"""
-
- control = """
-public class X
-{
- public void Foo(
- _input,
- _output);
-
-
- public int Bar(
- _str1,
- str2,
- _str3);
-
-
- public Object Add(
- value1,
- value);
-
-
-}
-//end of class
-
-
-
-"""
- def _getCompilerSettings(self):
- return {'useFilterArgsInPlaceholders':True}
-
- def searchList(self): # Inside Indenter class.
- class Method:
- def __init__(self, _name, _type, *_params):
- self.Name = _name
- self.Type = _type
- self.Params = _params
- methods = [Method("Foo", "VT_VOID", "_input", "_output"),
- Method("Bar", "VT_INT", "_str1", "str2", "_str3"),
- Method("Add", "VT_VARIANT", "value1", "value")]
- return [{"methods": methods}]
-
- def test1(self): # Inside Indenter class.
- self.verify(self.source, self.control)
-
-
-##################################################
-## CREATE CONVERTED EOL VERSIONS OF THE TEST CASES
-
-if OutputTest._useNewStyleCompilation and versionTuple >= (2, 3):
- extraCompileKwArgsForDiffBaseclass = {'baseclass':dict}
-else:
- extraCompileKwArgsForDiffBaseclass = {'baseclass':object}
-
-
-def install_eols():
- klasses = [v for v in globals().values() if isinstance(v, type) and issubclass(v, unittest.TestCase)]
- for klass in klasses:
- name = klass.__name__
- if hasattr(klass, 'convertEOLs') and klass.convertEOLs:
- win32Src = r"class %(name)s_Win32EOL(%(name)s): _EOLreplacement = '\r\n'"%locals()
- macSrc = r"class %(name)s_MacEOL(%(name)s): _EOLreplacement = '\r'"%locals()
- exec(win32Src, globals())
- exec(macSrc, globals())
-
- if versionTuple >= (2, 3):
- src = r"class %(name)s_DiffBaseClass(%(name)s): "%locals()
- src += " _extraCompileKwArgs = extraCompileKwArgsForDiffBaseclass"
- exec(src, globals())
-
- del name
- del klass
-
-##################################################
-## if run from the command line ##
-
-if __name__ == '__main__':
- install_eols()
- unittest.main()
-
-# vim: shiftwidth=4 tabstop=4 expandtab
Index: cheetah/Cheetah/Tests/Template.py
===================================================================
--- cheetah/Cheetah/Tests/Template.py (revision 19111)
+++ cheetah/Cheetah/Tests/Template.py (nonexistent)
@@ -1,363 +0,0 @@
-#!/usr/bin/env python
-
-import pdb
-import sys
-import types
-import os
-import os.path
-import tempfile
-import shutil
-import unittest
-from Cheetah.Template import Template
-
-majorVer, minorVer = sys.version_info[0], sys.version_info[1]
-versionTuple = (majorVer, minorVer)
-
-class TemplateTest(unittest.TestCase):
- pass
-
-class ClassMethods_compile(TemplateTest):
- """I am using the same Cheetah source for each test to root out clashes
- caused by the compile caching in Template.compile().
- """
-
- def test_basicUsage(self):
- klass = Template.compile(source='$foo')
- t = klass(namespaces={'foo':1234})
- assert str(t)=='1234'
-
- def test_baseclassArg(self):
- klass = Template.compile(source='$foo', baseclass=dict)
- t = klass({'foo':1234})
- assert str(t)=='1234'
-
- klass2 = Template.compile(source='$foo', baseclass=klass)
- t = klass2({'foo':1234})
- assert str(t)=='1234'
-
- klass3 = Template.compile(source='#implements dummy\n$bar', baseclass=klass2)
- t = klass3({'foo':1234})
- assert str(t)=='1234'
-
- klass4 = Template.compile(source='$foo', baseclass='dict')
- t = klass4({'foo':1234})
- assert str(t)=='1234'
-
- def test_moduleFileCaching(self):
- if versionTuple < (2, 3):
- return
- tmpDir = tempfile.mkdtemp()
- try:
- #print tmpDir
- assert os.path.exists(tmpDir)
- klass = Template.compile(source='$foo',
- cacheModuleFilesForTracebacks=True,
- cacheDirForModuleFiles=tmpDir)
- mod = sys.modules[klass.__module__]
- #print mod.__file__
- assert os.path.exists(mod.__file__)
- assert os.path.dirname(mod.__file__)==tmpDir
- finally:
- shutil.rmtree(tmpDir, True)
-
- def test_classNameArg(self):
- klass = Template.compile(source='$foo', className='foo123')
- assert klass.__name__=='foo123'
- t = klass(namespaces={'foo':1234})
- assert str(t)=='1234'
-
- def test_moduleNameArg(self):
- klass = Template.compile(source='$foo', moduleName='foo99')
- mod = sys.modules['foo99']
- assert klass.__name__=='foo99'
- t = klass(namespaces={'foo':1234})
- assert str(t)=='1234'
-
-
- klass = Template.compile(source='$foo',
- moduleName='foo1',
- className='foo2')
- mod = sys.modules['foo1']
- assert klass.__name__=='foo2'
- t = klass(namespaces={'foo':1234})
- assert str(t)=='1234'
-
-
- def test_mainMethodNameArg(self):
- klass = Template.compile(source='$foo',
- className='foo123',
- mainMethodName='testMeth')
- assert klass.__name__=='foo123'
- t = klass(namespaces={'foo':1234})
- #print t.generatedClassCode()
- assert str(t)=='1234'
- assert t.testMeth()=='1234'
-
- klass = Template.compile(source='$foo',
- moduleName='fooXXX',
- className='foo123',
- mainMethodName='testMeth',
- baseclass=dict)
- assert klass.__name__=='foo123'
- t = klass({'foo':1234})
- #print t.generatedClassCode()
- assert str(t)=='1234'
- assert t.testMeth()=='1234'
-
-
-
- def test_moduleGlobalsArg(self):
- klass = Template.compile(source='$foo',
- moduleGlobals={'foo':1234})
- t = klass()
- assert str(t)=='1234'
-
- klass2 = Template.compile(source='$foo', baseclass='Test1',
- moduleGlobals={'Test1':dict})
- t = klass2({'foo':1234})
- assert str(t)=='1234'
-
- klass3 = Template.compile(source='$foo', baseclass='Test1',
- moduleGlobals={'Test1':dict, 'foo':1234})
- t = klass3()
- assert str(t)=='1234'
-
-
- def test_keepRefToGeneratedCodeArg(self):
- klass = Template.compile(source='$foo',
- className='unique58',
- cacheCompilationResults=False,
- keepRefToGeneratedCode=False)
- t = klass(namespaces={'foo':1234})
- assert str(t)=='1234'
- assert not t.generatedModuleCode()
-
-
- klass2 = Template.compile(source='$foo',
- className='unique58',
- keepRefToGeneratedCode=True)
- t = klass2(namespaces={'foo':1234})
- assert str(t)=='1234'
- assert t.generatedModuleCode()
-
- klass3 = Template.compile(source='$foo',
- className='unique58',
- keepRefToGeneratedCode=False)
- t = klass3(namespaces={'foo':1234})
- assert str(t)=='1234'
- # still there as this class came from the cache
- assert t.generatedModuleCode()
-
-
- def test_compilationCache(self):
- klass = Template.compile(source='$foo',
- className='unique111',
- cacheCompilationResults=False)
- t = klass(namespaces={'foo':1234})
- assert str(t)=='1234'
- assert not klass._CHEETAH_isInCompilationCache
-
-
- # this time it will place it in the cache
- klass = Template.compile(source='$foo',
- className='unique111',
- cacheCompilationResults=True)
- t = klass(namespaces={'foo':1234})
- assert str(t)=='1234'
- assert klass._CHEETAH_isInCompilationCache
-
- # by default it will be in the cache
- klass = Template.compile(source='$foo',
- className='unique999099')
- t = klass(namespaces={'foo':1234})
- assert str(t)=='1234'
- assert klass._CHEETAH_isInCompilationCache
-
-
-class ClassMethods_subclass(TemplateTest):
-
- def test_basicUsage(self):
- klass = Template.compile(source='$foo', baseclass=dict)
- t = klass({'foo':1234})
- assert str(t)=='1234'
-
- klass2 = klass.subclass(source='$foo')
- t = klass2({'foo':1234})
- assert str(t)=='1234'
-
- klass3 = klass2.subclass(source='#implements dummy\n$bar')
- t = klass3({'foo':1234})
- assert str(t)=='1234'
-
-
-class Preprocessors(TemplateTest):
-
- def test_basicUsage1(self):
- src='''\
- %set foo = @a
- $(@foo*10)
- @a'''
- src = '\n'.join([ln.strip() for ln in src.splitlines()])
- preprocessors = {'tokens':'@ %',
- 'namespaces':{'a':99}
- }
- klass = Template.compile(src, preprocessors=preprocessors)
- assert str(klass())=='990\n99'
-
- def test_normalizePreprocessorArgVariants(self):
- src='%set foo = 12\n%%comment\n$(@foo*10)'
-
- class Settings1: tokens = '@ %'
- Settings1 = Settings1()
-
- from Cheetah.Template import TemplatePreprocessor
- settings = Template._normalizePreprocessorSettings(Settings1)
- preprocObj = TemplatePreprocessor(settings)
-
- def preprocFunc(source, file):
- return '$(12*10)', None
-
- class TemplateSubclass(Template):
- pass
-
- compilerSettings = {'cheetahVarStartToken': '@',
- 'directiveStartToken': '%',
- 'commentStartToken': '%%',
- }
-
- for arg in ['@ %',
- {'tokens':'@ %'},
- {'compilerSettings':compilerSettings},
- {'compilerSettings':compilerSettings,
- 'templateInitArgs':{}},
- {'tokens':'@ %',
- 'templateAPIClass':TemplateSubclass},
- Settings1,
- preprocObj,
- preprocFunc,
- ]:
-
- klass = Template.compile(src, preprocessors=arg)
- assert str(klass())=='120'
-
-
- def test_complexUsage(self):
- src='''\
- %set foo = @a
- %def func1: #def func(arg): $arg("***")
- %% comment
- $(@foo*10)
- @func1
- $func(lambda x:c"--$x--@a")'''
- src = '\n'.join([ln.strip() for ln in src.splitlines()])
-
-
- for arg in [{'tokens':'@ %', 'namespaces':{'a':99} },
- {'tokens':'@ %', 'namespaces':{'a':99} },
- ]:
- klass = Template.compile(src, preprocessors=arg)
- t = klass()
- assert str(t)=='990\n--***--99'
-
-
-
- def test_i18n(self):
- src='''\
- %i18n: This is a $string that needs translation
- %i18n id="foo", domain="root": This is a $string that needs translation
- '''
- src = '\n'.join([ln.strip() for ln in src.splitlines()])
- klass = Template.compile(src, preprocessors='@ %', baseclass=dict)
- t = klass({'string':'bit of text'})
- #print str(t), repr(str(t))
- assert str(t)==('This is a bit of text that needs translation\n'*2)[:-1]
-
-
-class TryExceptImportTest(TemplateTest):
- def test_FailCase(self):
- ''' Test situation where an inline #import statement will get relocated '''
- source = '''
- #def myFunction()
- Ahoy!
- #try
- #import sys
- #except ImportError
- $print "This will never happen!"
- #end try
- #end def
- '''
- # This should raise an IndentationError (if the bug exists)
- klass = Template.compile(source=source, compilerSettings={'useLegacyImportMode' : False})
- t = klass(namespaces={'foo' : 1234})
-
-class ClassMethodSupport(TemplateTest):
- def test_BasicDecorator(self):
- if sys.version_info[0] == 2 and sys.version_info[1] == 3:
- print('This version of Python doesn\'t support decorators, skipping tests')
- return
- template = '''
- #@classmethod
- #def myClassMethod()
- #return '$foo = %s' % $foo
- #end def
- '''
- template = Template.compile(source=template)
- try:
- rc = template.myClassMethod(foo='bar')
- assert rc == '$foo = bar', (rc, 'Template class method didn\'t return what I expected')
- except AttributeError, ex:
- self.fail(ex)
-
-class StaticMethodSupport(TemplateTest):
- def test_BasicDecorator(self):
- if sys.version_info[0] == 2 and sys.version_info[1] == 3:
- print('This version of Python doesn\'t support decorators, skipping tests')
- return
- template = '''
- #@staticmethod
- #def myStaticMethod()
- #return '$foo = %s' % $foo
- #end def
- '''
- template = Template.compile(source=template)
- try:
- rc = template.myStaticMethod(foo='bar')
- assert rc == '$foo = bar', (rc, 'Template class method didn\'t return what I expected')
- except AttributeError, ex:
- self.fail(ex)
-
-class Useless(object):
- def boink(self):
- return [1, 2, 3]
-
-class MultipleInheritanceSupport(TemplateTest):
- def runTest(self):
- template = '''
- #extends Template, Useless
- #def foo()
- #return [4,5] + $boink()
- #end def
- '''
- template = Template.compile(template,
- moduleGlobals={'Useless' : Useless},
- compilerSettings={'autoImportForExtendsDirective' : False})
- template = template()
- result = template.foo()
- assert result == [4, 5, 1, 2, 3], (result, 'Unexpected result')
-
-class SubclassSearchListTest(TemplateTest):
- '''
- Verify that if we subclass Template, we can still
- use attributes on that subclass in the searchList
- '''
- def runTest(self):
- class Sub(Template):
- greeting = 'Hola'
- tmpl = Sub('''When we meet, I say "${greeting}"''')
- self.assertEquals(unicode(tmpl), 'When we meet, I say "Hola"')
-
-##################################################
-## if run from the command line ##
-
-if __name__ == '__main__':
- unittest.main()
Index: cheetah/Cheetah/Tests/Test.py
===================================================================
--- cheetah/Cheetah/Tests/Test.py (revision 19111)
+++ cheetah/Cheetah/Tests/Test.py (nonexistent)
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-'''
-Core module of Cheetah's Unit-testing framework
-
-TODO
-================================================================================
-# combo tests
-# negative test cases for expected exceptions
-# black-box vs clear-box testing
-# do some tests that run the Template for long enough to check that the refresh code works
-'''
-
-import sys
-import unittest
-
-from Cheetah.Tests import SyntaxAndOutput
-from Cheetah.Tests import NameMapper
-from Cheetah.Tests import Misc
-from Cheetah.Tests import Filters
-from Cheetah.Tests import Template
-from Cheetah.Tests import Cheps
-from Cheetah.Tests import Parser
-from Cheetah.Tests import Regressions
-from Cheetah.Tests import Unicode
-from Cheetah.Tests import CheetahWrapper
-from Cheetah.Tests import Analyzer
-
-SyntaxAndOutput.install_eols()
-
-suites = [
- unittest.findTestCases(SyntaxAndOutput),
- unittest.findTestCases(NameMapper),
- unittest.findTestCases(Filters),
- unittest.findTestCases(Template),
- #unittest.findTestCases(Cheps),
- unittest.findTestCases(Regressions),
- unittest.findTestCases(Unicode),
- unittest.findTestCases(Misc),
- unittest.findTestCases(Parser),
- unittest.findTestCases(Analyzer),
-]
-
-if not sys.platform.startswith('java'):
- suites.append(unittest.findTestCases(CheetahWrapper))
-
-if __name__ == '__main__':
- runner = unittest.TextTestRunner()
- if 'xml' in sys.argv:
- import xmlrunner
- runner = xmlrunner.XMLTestRunner(filename='Cheetah-Tests.xml')
-
- results = runner.run(unittest.TestSuite(suites))
-
/cheetah/Cheetah/Tests/Test.py
Property changes:
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Index: cheetah/Cheetah/Tests/Unicode.py
===================================================================
--- cheetah/Cheetah/Tests/Unicode.py (revision 19111)
+++ cheetah/Cheetah/Tests/Unicode.py (nonexistent)
@@ -1,237 +0,0 @@
-#!/usr/bin/env python
-# -*- encoding: utf8 -*-
-
-from Cheetah.Template import Template
-from Cheetah import CheetahWrapper
-from Cheetah import DummyTransaction
-import imp
-import os
-import sys
-import tempfile
-import unittest
-
-class CommandLineTest(unittest.TestCase):
- def createAndCompile(self, source):
- sourcefile = '-'
- while sourcefile.find('-') != -1:
- sourcefile = tempfile.mktemp()
-
- fd = open('%s.tmpl' % sourcefile, 'w')
- fd.write(source)
- fd.close()
-
- wrap = CheetahWrapper.CheetahWrapper()
- wrap.main(['cheetah', 'compile', '--quiet', '--nobackup', sourcefile])
- module_path, module_name = os.path.split(sourcefile)
- module = loadModule(module_name, [module_path])
- template = getattr(module, module_name)
- return template
-
-class JBQ_UTF8_Test1(unittest.TestCase):
- def runTest(self):
- t = Template.compile(source="""Main file with |$v|
-
- $other""")
-
- otherT = Template.compile(source="Other template with |$v|")
- other = otherT()
- t.other = other
-
- t.v = u'Unicode String'
- t.other.v = u'Unicode String'
-
- assert unicode(t())
-
-class JBQ_UTF8_Test2(unittest.TestCase):
- def runTest(self):
- t = Template.compile(source="""Main file with |$v|
-
- $other""")
-
- otherT = Template.compile(source="Other template with |$v|")
- other = otherT()
- t.other = other
-
- t.v = u'Unicode String with eacute é'
- t.other.v = u'Unicode String'
-
- assert unicode(t())
-
-
-class JBQ_UTF8_Test3(unittest.TestCase):
- def runTest(self):
- t = Template.compile(source="""Main file with |$v|
-
- $other""")
-
- otherT = Template.compile(source="Other template with |$v|")
- other = otherT()
- t.other = other
-
- t.v = u'Unicode String with eacute é'
- t.other.v = u'Unicode String and an eacute é'
-
- assert unicode(t())
-
-class JBQ_UTF8_Test4(unittest.TestCase):
- def runTest(self):
- t = Template.compile(source="""#encoding utf-8
- Main file with |$v| and eacute in the template é""")
-
- t.v = 'Unicode String'
-
- assert unicode(t())
-
-class JBQ_UTF8_Test5(unittest.TestCase):
- def runTest(self):
- t = Template.compile(source="""#encoding utf-8
- Main file with |$v| and eacute in the template é""")
-
- t.v = u'Unicode String'
-
- assert unicode(t())
-
-def loadModule(moduleName, path=None):
- if path:
- assert isinstance(path, list)
- try:
- mod = sys.modules[moduleName]
- except KeyError:
- fp = None
-
- try:
- fp, pathname, description = imp.find_module(moduleName, path)
- mod = imp.load_module(moduleName, fp, pathname, description)
- finally:
- if fp:
- fp.close()
- return mod
-
-class JBQ_UTF8_Test6(unittest.TestCase):
- def runTest(self):
- source = """#encoding utf-8
- #set $someUnicodeString = u"Bébé"
- Main file with |$v| and eacute in the template é"""
- t = Template.compile(source=source)
-
- t.v = u'Unicode String'
-
- assert unicode(t())
-
-class JBQ_UTF8_Test7(CommandLineTest):
- def runTest(self):
- source = """#encoding utf-8
- #set $someUnicodeString = u"Bébé"
- Main file with |$v| and eacute in the template é"""
-
- template = self.createAndCompile(source)
- template.v = u'Unicode String'
-
- assert unicode(template())
-
-class JBQ_UTF8_Test8(CommandLineTest):
- def testStaticCompile(self):
- source = """#encoding utf-8
-#set $someUnicodeString = u"Bébé"
-$someUnicodeString"""
-
- template = self.createAndCompile(source)()
-
- a = unicode(template).encode("utf-8")
- self.assertEquals("Bébé", a)
-
- def testDynamicCompile(self):
- source = """#encoding utf-8
-#set $someUnicodeString = u"Bébé"
-$someUnicodeString"""
-
- template = Template(source = source)
-
- a = unicode(template).encode("utf-8")
- self.assertEquals("Bébé", a)
-
-class EncodeUnicodeCompatTest(unittest.TestCase):
- """
- Taken initially from Red Hat's bugzilla #529332
- https://bugzilla.redhat.com/show_bug.cgi?id=529332
- """
- def runTest(self):
- t = Template("""Foo ${var}""", filter='EncodeUnicode')
- t.var = u"Text with some non-ascii characters: åäö"
-
- rc = t.respond()
- assert isinstance(rc, unicode), ('Template.respond() should return unicode', rc)
-
- rc = str(t)
- assert isinstance(rc, str), ('Template.__str__() should return a UTF-8 encoded string', rc)
-
-
-class Unicode_in_SearchList_Test(CommandLineTest):
- def test_BasicASCII(self):
- source = '''This is $adjective'''
-
- template = self.createAndCompile(source)
- assert template and issubclass(template, Template)
- template = template(searchList=[{'adjective' : u'neat'}])
- assert template.respond()
-
- def test_Thai(self):
- # The string is something in Thai
- source = '''This is $foo $adjective'''
- template = self.createAndCompile(source)
- assert template and issubclass(template, Template)
- template = template(searchList=[{'foo' : 'bar',
- 'adjective' : u'\u0e22\u0e34\u0e19\u0e14\u0e35\u0e15\u0e49\u0e2d\u0e19\u0e23\u0e31\u0e1a'}])
- assert template.respond()
-
- def test_Thai_utf8(self):
- utf8 = '\xe0\xb8\xa2\xe0\xb8\xb4\xe0\xb8\x99\xe0\xb8\x94\xe0\xb8\xb5\xe0\xb8\x95\xe0\xb9\x89\xe0\xb8\xad\xe0\xb8\x99\xe0\xb8\xa3\xe0\xb8\xb1\xe0\xb8\x9a'
-
- source = '''This is $adjective'''
- template = self.createAndCompile(source)
- assert template and issubclass(template, Template)
- template = template(searchList=[{'adjective' : utf8}])
- assert template.respond()
-
-
-class InlineSpanishTest(unittest.TestCase):
- def setUp(self):
- super(InlineSpanishTest, self).setUp()
- self.template = '''
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Pagina del vendedor</title>
- </head>
- <body>
- $header
- <h2>Bienvenido $nombre.</h2>
- <br /><br /><br />
- <center>
- Usted tiene $numpedidos_noconf <a href="">pedidós</a> sin confirmar.
- <br /><br />
- Bodega tiene fecha para $numpedidos_bodega <a href="">pedidos</a>.
- </center>
- </body>
-</html>
- '''
-
- def test_failure(self):
- """ Test a template lacking a proper #encoding tag """
- self.failUnlessRaises(UnicodeDecodeError, Template, self.template, searchList=[{'header' : '',
- 'nombre' : '', 'numpedidos_bodega' : '',
- 'numpedidos_noconf' : ''}])
-
- def test_success(self):
- """ Test a template with a proper #encoding tag """
- template = '#encoding utf-8\n%s' % self.template
- template = Template(template, searchList=[{'header' : '',
- 'nombre' : '', 'numpedidos_bodega' : '',
- 'numpedidos_noconf' : ''}])
- self.assertTrue(unicode(template))
-
-
-
-if __name__ == '__main__':
- unittest.main()
Index: cheetah/Cheetah/Tests/__init__.py
===================================================================
--- cheetah/Cheetah/Tests/__init__.py (revision 19111)
+++ cheetah/Cheetah/Tests/__init__.py (nonexistent)
@@ -1 +0,0 @@
-#
Index: cheetah/Cheetah/Tests/xmlrunner.py
===================================================================
--- cheetah/Cheetah/Tests/xmlrunner.py (revision 19111)
+++ cheetah/Cheetah/Tests/xmlrunner.py (nonexistent)
@@ -1,381 +0,0 @@
-"""
-XML Test Runner for PyUnit
-"""
-
-# Written by Sebastian Rittau <srittau@jroger.in-berlin.de> and placed in
-# the Public Domain. With contributions by Paolo Borelli.
-
-__revision__ = "$Id: /private/python/stdlib/xmlrunner.py 16654 2007-11-12T12:46:35.368945Z srittau $"
-
-import os.path
-import re
-import sys
-import time
-import traceback
-import unittest
-from StringIO import StringIO
-from xml.sax.saxutils import escape
-
-from StringIO import StringIO
-
-
-
-class _TestInfo(object):
-
- """Information about a particular test.
-
- Used by _XMLTestResult.
-
- """
-
- def __init__(self, test, time):
- _pieces = test.id().split('.')
- (self._class, self._method) = ('.'.join(_pieces[:-1]), _pieces[-1])
- self._time = time
- self._error = None
- self._failure = None
-
-
- def print_report(self, stream):
- """Print information about this test case in XML format to the
- supplied stream.
-
- """
- stream.write(' <testcase classname="%(class)s" name="%(method)s" time="%(time).4f">' % \
- {
- "class": self._class,
- "method": self._method,
- "time": self._time,
- })
- if self._failure != None:
- self._print_error(stream, 'failure', self._failure)
- if self._error != None:
- self._print_error(stream, 'error', self._error)
- stream.write('</testcase>\n')
-
- def _print_error(self, stream, tagname, error):
- """Print information from a failure or error to the supplied stream."""
- text = escape(str(error[1]))
- stream.write('\n')
- stream.write(' <%s type="%s">%s\n' \
- % (tagname, issubclass(error[0], Exception) and error[0].__name__ or str(error[0]), text))
- tb_stream = StringIO()
- traceback.print_tb(error[2], None, tb_stream)
- stream.write(escape(tb_stream.getvalue()))
- stream.write(' </%s>\n' % tagname)
- stream.write(' ')
-
-# Module level functions since Python 2.3 doesn't grok decorators
-def create_success(test, time):
- """Create a _TestInfo instance for a successful test."""
- return _TestInfo(test, time)
-
-def create_failure(test, time, failure):
- """Create a _TestInfo instance for a failed test."""
- info = _TestInfo(test, time)
- info._failure = failure
- return info
-
-def create_error(test, time, error):
- """Create a _TestInfo instance for an erroneous test."""
- info = _TestInfo(test, time)
- info._error = error
- return info
-
-class _XMLTestResult(unittest.TestResult):
-
- """A test result class that stores result as XML.
-
- Used by XMLTestRunner.
-
- """
-
- def __init__(self, classname):
- unittest.TestResult.__init__(self)
- self._test_name = classname
- self._start_time = None
- self._tests = []
- self._error = None
- self._failure = None
-
- def startTest(self, test):
- unittest.TestResult.startTest(self, test)
- self._error = None
- self._failure = None
- self._start_time = time.time()
-
- def stopTest(self, test):
- time_taken = time.time() - self._start_time
- unittest.TestResult.stopTest(self, test)
- if self._error:
- info = create_error(test, time_taken, self._error)
- elif self._failure:
- info = create_failure(test, time_taken, self._failure)
- else:
- info = create_success(test, time_taken)
- self._tests.append(info)
-
- def addError(self, test, err):
- unittest.TestResult.addError(self, test, err)
- self._error = err
-
- def addFailure(self, test, err):
- unittest.TestResult.addFailure(self, test, err)
- self._failure = err
-
- def print_report(self, stream, time_taken, out, err):
- """Prints the XML report to the supplied stream.
-
- The time the tests took to perform as well as the captured standard
- output and standard error streams must be passed in.a
-
- """
- stream.write('<testsuite errors="%(e)d" failures="%(f)d" ' % \
- { "e": len(self.errors), "f": len(self.failures) })
- stream.write('name="%(n)s" tests="%(t)d" time="%(time).3f">\n' % \
- {
- "n": self._test_name,
- "t": self.testsRun,
- "time": time_taken,
- })
- for info in self._tests:
- info.print_report(stream)
- stream.write(' <system-out><![CDATA[%s]]></system-out>\n' % out)
- stream.write(' <system-err><![CDATA[%s]]></system-err>\n' % err)
- stream.write('</testsuite>\n')
-
-
-class XMLTestRunner(object):
-
- """A test runner that stores results in XML format compatible with JUnit.
-
- XMLTestRunner(stream=None) -> XML test runner
-
- The XML file is written to the supplied stream. If stream is None, the
- results are stored in a file called TEST-<module>.<class>.xml in the
- current working directory (if not overridden with the path property),
- where <module> and <class> are the module and class name of the test class.
-
- """
-
- def __init__(self, *args, **kwargs):
- self._stream = kwargs.get('stream')
- self._filename = kwargs.get('filename')
- self._path = "."
-
- def run(self, test):
- """Run the given test case or test suite."""
- class_ = test.__class__
- classname = class_.__module__ + "." + class_.__name__
- if self._stream == None:
- filename = "TEST-%s.xml" % classname
- if self._filename:
- filename = self._filename
- stream = file(os.path.join(self._path, filename), "w")
- stream.write('<?xml version="1.0" encoding="utf-8"?>\n')
- else:
- stream = self._stream
-
- result = _XMLTestResult(classname)
- start_time = time.time()
-
- # TODO: Python 2.5: Use the with statement
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- sys.stdout = StringIO()
- sys.stderr = StringIO()
-
- try:
- test(result)
- try:
- out_s = sys.stdout.getvalue()
- except AttributeError:
- out_s = ""
- try:
- err_s = sys.stderr.getvalue()
- except AttributeError:
- err_s = ""
- finally:
- sys.stdout = old_stdout
- sys.stderr = old_stderr
-
- time_taken = time.time() - start_time
- result.print_report(stream, time_taken, out_s, err_s)
- if self._stream == None:
- stream.close()
-
- return result
-
- def _set_path(self, path):
- self._path = path
-
- path = property(lambda self: self._path, _set_path, None,
- """The path where the XML files are stored.
-
- This property is ignored when the XML file is written to a file
- stream.""")
-
-
-class XMLTestRunnerTest(unittest.TestCase):
- def setUp(self):
- self._stream = StringIO()
-
- def _try_test_run(self, test_class, expected):
-
- """Run the test suite against the supplied test class and compare the
- XML result against the expected XML string. Fail if the expected
- string doesn't match the actual string. All time attribute in the
- expected string should have the value "0.000". All error and failure
- messages are reduced to "Foobar".
-
- """
-
- runner = XMLTestRunner(self._stream)
- runner.run(unittest.makeSuite(test_class))
-
- got = self._stream.getvalue()
- # Replace all time="X.YYY" attributes by time="0.000" to enable a
- # simple string comparison.
- got = re.sub(r'time="\d+\.\d+"', 'time="0.000"', got)
- # Likewise, replace all failure and error messages by a simple "Foobar"
- # string.
- got = re.sub(r'(?s)<failure (.*?)>.*?</failure>', r'<failure \1>Foobar</failure>', got)
- got = re.sub(r'(?s)<error (.*?)>.*?</error>', r'<error \1>Foobar</error>', got)
-
- self.assertEqual(expected, got)
-
- def test_no_tests(self):
- """Regression test: Check whether a test run without any tests
- matches a previous run.
-
- """
- class TestTest(unittest.TestCase):
- pass
- self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="0" time="0.000">
- <system-out><![CDATA[]]></system-out>
- <system-err><![CDATA[]]></system-err>
-</testsuite>
-""")
-
- def test_success(self):
- """Regression test: Check whether a test run with a successful test
- matches a previous run.
-
- """
- class TestTest(unittest.TestCase):
- def test_foo(self):
- pass
- self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
- <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
- <system-out><![CDATA[]]></system-out>
- <system-err><![CDATA[]]></system-err>
-</testsuite>
-""")
-
- def test_failure(self):
- """Regression test: Check whether a test run with a failing test
- matches a previous run.
-
- """
- class TestTest(unittest.TestCase):
- def test_foo(self):
- self.assert_(False)
- self._try_test_run(TestTest, """<testsuite errors="0" failures="1" name="unittest.TestSuite" tests="1" time="0.000">
- <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
- <failure type="exceptions.AssertionError">Foobar</failure>
- </testcase>
- <system-out><![CDATA[]]></system-out>
- <system-err><![CDATA[]]></system-err>
-</testsuite>
-""")
-
- def test_error(self):
- """Regression test: Check whether a test run with a erroneous test
- matches a previous run.
-
- """
- class TestTest(unittest.TestCase):
- def test_foo(self):
- raise IndexError()
- self._try_test_run(TestTest, """<testsuite errors="1" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
- <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
- <error type="exceptions.IndexError">Foobar</error>
- </testcase>
- <system-out><![CDATA[]]></system-out>
- <system-err><![CDATA[]]></system-err>
-</testsuite>
-""")
-
- def test_stdout_capture(self):
- """Regression test: Check whether a test run with output to stdout
- matches a previous run.
-
- """
- class TestTest(unittest.TestCase):
- def test_foo(self):
- print("Test")
- self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
- <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
- <system-out><![CDATA[Test
-]]></system-out>
- <system-err><![CDATA[]]></system-err>
-</testsuite>
-""")
-
- def test_stderr_capture(self):
- """Regression test: Check whether a test run with output to stderr
- matches a previous run.
-
- """
- class TestTest(unittest.TestCase):
- def test_foo(self):
- sys.stderr.write('Test\n')
- self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
- <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
- <system-out><![CDATA[]]></system-out>
- <system-err><![CDATA[Test
-]]></system-err>
-</testsuite>
-""")
-
- class NullStream(object):
- """A file-like object that discards everything written to it."""
- def write(self, buffer):
- pass
-
- def test_unittests_changing_stdout(self):
- """Check whether the XMLTestRunner recovers gracefully from unit tests
- that change stdout, but don't change it back properly.
-
- """
- class TestTest(unittest.TestCase):
- def test_foo(self):
- sys.stdout = XMLTestRunnerTest.NullStream()
-
- runner = XMLTestRunner(self._stream)
- runner.run(unittest.makeSuite(TestTest))
-
- def test_unittests_changing_stderr(self):
- """Check whether the XMLTestRunner recovers gracefully from unit tests
- that change stderr, but don't change it back properly.
-
- """
- class TestTest(unittest.TestCase):
- def test_foo(self):
- sys.stderr = XMLTestRunnerTest.NullStream()
-
- runner = XMLTestRunner(self._stream)
- runner.run(unittest.makeSuite(TestTest))
-
-
-class XMLTestProgram(unittest.TestProgram):
- def runTests(self):
- if self.testRunner is None:
- self.testRunner = XMLTestRunner()
- unittest.TestProgram.runTests(self)
-
-main = XMLTestProgram
-
-
-if __name__ == "__main__":
- main(module=None)
Index: cheetah/Cheetah/Tools/CGITemplate.py
===================================================================
--- cheetah/Cheetah/Tools/CGITemplate.py (revision 19111)
+++ cheetah/Cheetah/Tools/CGITemplate.py (nonexistent)
@@ -1,77 +0,0 @@
-# $Id: CGITemplate.py,v 1.6 2006/01/29 02:09:59 tavis_rudd Exp $
-"""A subclass of Cheetah.Template for use in CGI scripts.
-
-Usage in a template:
- #extends Cheetah.Tools.CGITemplate
- #implements respond
- $cgiHeaders#slurp
-
-Usage in a template inheriting a Python class:
-1. The template
- #extends MyPythonClass
- #implements respond
- $cgiHeaders#slurp
-
-2. The Python class
- from Cheetah.Tools import CGITemplate
- class MyPythonClass(CGITemplate):
- def cgiHeadersHook(self):
- return "Content-Type: text/html; charset=koi8-r\n\n"
-
-To read GET/POST variables, use the .webInput method defined in
-Cheetah.Utils.WebInputMixin (available in all templates without importing
-anything), use Python's 'cgi' module, or make your own arrangements.
-
-This class inherits from Cheetah.Template to make it usable in Cheetah's
-single-inheritance model.
-
-
-Meta-Data
-================================================================================
-Author: Mike Orr <iron@mso.oz.net>
-License: This software is released for unlimited distribution under the
- terms of the MIT license. See the LICENSE file.
-Version: $Revision: 1.6 $
-Start Date: 2001/10/03
-Last Revision Date: $Date: 2006/01/29 02:09:59 $
-"""
-__author__ = "Mike Orr <iron@mso.oz.net>"
-__revision__ = "$Revision: 1.6 $"[11:-2]
-
-import os
-from Cheetah.Template import Template
-
-class CGITemplate(Template):
- """Methods useful in CGI scripts.
-
- Any class that inherits this mixin must also inherit Cheetah.Servlet.
- """
-
-
- def cgiHeaders(self):
- """Outputs the CGI headers if this is a CGI script.
-
- Usage: $cgiHeaders#slurp
- Override .cgiHeadersHook() if you want to customize the headers.
- """
- if self.isCgi():
- return self.cgiHeadersHook()
-
-
-
- def cgiHeadersHook(self):
- """Override if you want to customize the CGI headers.
- """
- return "Content-type: text/html\n\n"
-
-
- def isCgi(self):
- """Is this a CGI script?
- """
- env = 'REQUEST_METHOD' in os.environ
- wk = self._CHEETAH__isControlledByWebKit
- return env and not wk
-
-
-
-# vim: shiftwidth=4 tabstop=4 expandtab
Index: cheetah/Cheetah/Tools/MondoReport.py
===================================================================
--- cheetah/Cheetah/Tools/MondoReport.py (revision 19111)
+++ cheetah/Cheetah/Tools/MondoReport.py (nonexistent)
@@ -1,464 +0,0 @@
-"""
-@@TR: This code is pretty much unsupported.
-
-MondoReport.py -- Batching module for Python and Cheetah.
-
-Version 2001-Nov-18. Doesn't do much practical yet, but the companion
-testMondoReport.py passes all its tests.
--Mike Orr (Iron)
-
-TODO: BatchRecord.prev/next/prev_batches/next_batches/query, prev.query,
-next.query.
-
-How about Report: .page(), .all(), .summary()? Or PageBreaker.
-"""
-import operator
-try:
- from functools import reduce
-except ImportError:
- # If functools doesn't exist, we must be on an old
- # enough version that has reduce() in builtins
- pass
-
-try:
- from Cheetah.NameMapper import valueForKey as lookup_func
-except ImportError:
- def lookup_func(obj, name):
- if hasattr(obj, name):
- return getattr(obj, name)
- else:
- return obj[name] # Raises KeyError.
-
-########## PUBLIC GENERIC FUNCTIONS ##############################
-
-class NegativeError(ValueError):
- pass
-
-def isNumeric(v):
- return isinstance(v, (int, float))
-
-def isNonNegative(v):
- ret = isNumeric(v)
- if ret and v < 0:
- raise NegativeError(v)
-
-def isNotNone(v):
- return v is not None
-
-def Roman(n):
- n = int(n) # Raises TypeError.
- if n < 1:
- raise ValueError("roman numeral for zero or negative undefined: " + n)
- roman = ''
- while n >= 1000:
- n = n - 1000
- roman = roman + 'M'
- while n >= 500:
- n = n - 500
- roman = roman + 'D'
- while n >= 100:
- n = n - 100
- roman = roman + 'C'
- while n >= 50:
- n = n - 50
- roman = roman + 'L'
- while n >= 10:
- n = n - 10
- roman = roman + 'X'
- while n >= 5:
- n = n - 5
- roman = roman + 'V'
- while n < 5 and n >= 1:
- n = n - 1
- roman = roman + 'I'
- roman = roman.replace('DCCCC', 'CM')
- roman = roman.replace('CCCC', 'CD')
- roman = roman.replace('LXXXX', 'XC')
- roman = roman.replace('XXXX', 'XL')
- roman = roman.replace('VIIII', 'IX')
- roman = roman.replace('IIII', 'IV')
- return roman
-
-
-def sum(lis):
- return reduce(operator.add, lis, 0)
-
-def mean(lis):
- """Always returns a floating-point number.
- """
- lis_len = len(lis)
- if lis_len == 0:
- return 0.00 # Avoid ZeroDivisionError (not raised for floats anyway)
- total = float( sum(lis) )
- return total / lis_len
-
-def median(lis):
- lis = sorted(lis[:])
- return lis[int(len(lis)/2)]
-
-
-def variance(lis):
- raise NotImplementedError()
-
-def variance_n(lis):
- raise NotImplementedError()
-
-def standardDeviation(lis):
- raise NotImplementedError()
-
-def standardDeviation_n(lis):
- raise NotImplementedError()
-
-
-
-class IndexFormats:
- """Eight ways to display a subscript index.
- ("Fifty ways to leave your lover....")
- """
- def __init__(self, index, item=None):
- self._index = index
- self._number = index + 1
- self._item = item
-
- def index(self):
- return self._index
-
- __call__ = index
-
- def number(self):
- return self._number
-
- def even(self):
- return self._number % 2 == 0
-
- def odd(self):
- return not self.even()
-
- def even_i(self):
- return self._index % 2 == 0
-
- def odd_i(self):
- return not self.even_i()
-
- def letter(self):
- return self.Letter().lower()
-
- def Letter(self):
- n = ord('A') + self._index
- return chr(n)
-
- def roman(self):
- return self.Roman().lower()
-
- def Roman(self):
- return Roman(self._number)
-
- def item(self):
- return self._item
-
-
-
-########## PRIVATE CLASSES ##############################
-
-class ValuesGetterMixin:
- def __init__(self, origList):
- self._origList = origList
-
- def _getValues(self, field=None, criteria=None):
- if field:
- ret = [lookup_func(elm, field) for elm in self._origList]
- else:
- ret = self._origList
- if criteria:
- ret = list(filter(criteria, ret))
- return ret
-
-
-class RecordStats(IndexFormats, ValuesGetterMixin):
- """The statistics that depend on the current record.
- """
- def __init__(self, origList, index):
- record = origList[index] # Raises IndexError.
- IndexFormats.__init__(self, index, record)
- ValuesGetterMixin.__init__(self, origList)
-
- def length(self):
- return len(self._origList)
-
- def first(self):
- return self._index == 0
-
- def last(self):
- return self._index >= len(self._origList) - 1
-
- def _firstOrLastValue(self, field, currentIndex, otherIndex):
- currentValue = self._origList[currentIndex] # Raises IndexError.
- try:
- otherValue = self._origList[otherIndex]
- except IndexError:
- return True
- if field:
- currentValue = lookup_func(currentValue, field)
- otherValue = lookup_func(otherValue, field)
- return currentValue != otherValue
-
- def firstValue(self, field=None):
- return self._firstOrLastValue(field, self._index, self._index - 1)
-
- def lastValue(self, field=None):
- return self._firstOrLastValue(field, self._index, self._index + 1)
-
- # firstPage and lastPage not implemented. Needed?
-
- def percentOfTotal(self, field=None, suffix='%', default='N/A', decimals=2):
- rec = self._origList[self._index]
- if field:
- val = lookup_func(rec, field)
- else:
- val = rec
- try:
- lis = self._getValues(field, isNumeric)
- except NegativeError:
- return default
- total = sum(lis)
- if total == 0.00: # Avoid ZeroDivisionError.
- return default
- val = float(val)
- try:
- percent = (val / total) * 100
- except ZeroDivisionError:
- return default
- if decimals == 0:
- percent = int(percent)
- else:
- percent = round(percent, decimals)
- if suffix:
- return str(percent) + suffix # String.
- else:
- return percent # Numeric.
-
- def __call__(self): # Overrides IndexFormats.__call__
- """This instance is not callable, so we override the super method.
- """
- raise NotImplementedError()
-
- def prev(self):
- if self._index == 0:
- return None
- else:
- length = self.length()
- start = self._index - length
- return PrevNextPage(self._origList, length, start)
-
- def next(self):
- if self._index + self.length() == self.length():
- return None
- else:
- length = self.length()
- start = self._index + length
- return PrevNextPage(self._origList, length, start)
-
- def prevPages(self):
- raise NotImplementedError()
-
- def nextPages(self):
- raise NotImplementedError()
-
- prev_batches = prevPages
- next_batches = nextPages
-
- def summary(self):
- raise NotImplementedError()
-
-
-
- def _prevNextHelper(self, start, end, size, orphan, sequence):
- """Copied from Zope's DT_InSV.py's "opt" function.
- """
- if size < 1:
- if start > 0 and end > 0 and end >= start:
- size=end+1-start
- else: size=7
-
- if start > 0:
-
- try: sequence[start-1]
- except: start=len(sequence)
- # if start > l: start=l
-
- if end > 0:
- if end < start: end=start
- else:
- end=start+size-1
- try: sequence[end+orphan-1]
- except: end=len(sequence)
- # if l - end < orphan: end=l
- elif end > 0:
- try: sequence[end-1]
- except: end=len(sequence)
- # if end > l: end=l
- start=end+1-size
- if start - 1 < orphan: start=1
- else:
- start=1
- end=start+size-1
- try: sequence[end+orphan-1]
- except: end=len(sequence)
- # if l - end < orphan: end=l
- return start, end, size
-
-
-
-class Summary(ValuesGetterMixin):
- """The summary statistics, that don't depend on the current record.
- """
- def __init__(self, origList):
- ValuesGetterMixin.__init__(self, origList)
-
- def sum(self, field=None):
- lis = self._getValues(field, isNumeric)
- return sum(lis)
-
- total = sum
-
- def count(self, field=None):
- lis = self._getValues(field, isNotNone)
- return len(lis)
-
- def min(self, field=None):
- lis = self._getValues(field, isNotNone)
- return min(lis) # Python builtin function min.
-
- def max(self, field=None):
- lis = self._getValues(field, isNotNone)
- return max(lis) # Python builtin function max.
-
- def mean(self, field=None):
- """Always returns a floating point number.
- """
- lis = self._getValues(field, isNumeric)
- return mean(lis)
-
- average = mean
-
- def median(self, field=None):
- lis = self._getValues(field, isNumeric)
- return median(lis)
-
- def variance(self, field=None):
- raiseNotImplementedEr