PKӤ2L`Z Cheetah/CacheRegion.py# $Id: CacheRegion.py,v 1.1 2005/07/10 18:38:39 tavis_rudd Exp $ """Cache holder classes for Cheetah: Cache regions are defined using the #cache Cheetah directive. Each cache region can be viewed as a dictionnary (keyed by cacheID) handling at least one cache (the default one). It's possible to add caches in a region by using the `varyBy` #cache directive parameter as in the following example:: #cache varyBy=$getArticleID() #def getArticle this is the article content. #end def #end cache The code above will generate a CacheRegion, and depending on the article id value, add some new sub-caches ad-hoc. Meta-Data ================================================================================ Author: Philippe Normand Version: $Revision: 1.1 $ Start Date: 2005/06/20 Last Revision Date: $Date: 2005/07/10 18:38:39 $ """ __author__ = "Philippe Normand " __revision__ = "$Revision: 1.1 $"[11:-2] import md5 class CacheRegion: """ A `CacheRegion` stores some `Cache` instances. """ def __init__(self): self.clear() def clear(self): " drop all the caches stored in this cache region " self.caches = {} def getCache(self, cacheID): """ Lazy access to a cache Try to find a cache in the stored caches. If it doesn't exist, it's created. Returns a `Cache` instance. """ cacheID = md5.new(str(cacheID)).hexdigest() if not self.caches.has_key(cacheID): cache = Cache(cacheID) self.caches[cacheID] = cache return self.caches.get(cacheID) class Cache: """ Cache class. A Cache is a container storing: - cacheID (string) - refreshTime (timestamp or None) : last time the cache was refreshed - data (string) : the content of the cache """ def __init__(self, cacheID): self.setID(cacheID) self.clear() def clear(self): self.setData("") self.setRefreshTime(None) def getID(self): return self.cacheID def setID(self, cacheID): self.cacheID = cacheID def setData(self, data): self.data = data def getData(self): return self.data def setRefreshTime(self, time): self.refreshTime = time def getRefreshTime(self): return self.refreshTime PKt95y'OOCheetah/CacheRegion.pyc; /kBc@sLdZdZddd!ZdkZdfdYZdfd YZdS( s#Cache holder classes for Cheetah: Cache regions are defined using the #cache Cheetah directive. Each cache region can be viewed as a dictionnary (keyed by cacheID) handling at least one cache (the default one). It's possible to add caches in a region by using the `varyBy` #cache directive parameter as in the following example:: #cache varyBy=$getArticleID() #def getArticle this is the article content. #end def #end cache The code above will generate a CacheRegion, and depending on the article id value, add some new sub-caches ad-hoc. Meta-Data ================================================================================ Author: Philippe Normand Version: $Revision: 1.1 $ Start Date: 2005/06/20 Last Revision Date: $Date: 2005/07/10 18:38:39 $ s$Philippe Normand s$Revision: 1.1 $i iNs CacheRegioncBs)tZdZdZdZdZRS(s4 A `CacheRegion` stores some `Cache` instances. cCs|idS(N(sselfsclear(sself((s8build/bdist.darwin-8.7.1-i386/egg/Cheetah/CacheRegion.pys__init__#scCs h|_dS(s1 drop all the caches stored in this cache region N(sselfscaches(sself((s8build/bdist.darwin-8.7.1-i386/egg/Cheetah/CacheRegion.pysclear&scCs`tit|i}|ii| ot|}||i| and Mike Orr Version: $Revision: 1.18 $ Start Date: 2001/03/30 Last Revision Date: $Date: 2005/01/03 19:57:24 $ """ __author__ = "Tavis Rudd and Mike Orr " __revision__ = "$Revision: 1.18 $"[11:-2] import getopt, glob, os, pprint, re, shutil, sys import cPickle as pickle from Cheetah.Version import Version from Cheetah.Compiler import Compiler from Cheetah.Template import Template from Cheetah.Utils.Misc import mkdirsWithPyInitFiles from Cheetah.Utils.optik import OptionParser optionDashesRE = re.compile( R"^-{1,2}" ) moduleNameRE = re.compile( R"^[a-zA-Z_][a-zA-Z_0-9]*$" ) def fprintfMessage(stream, format, *args): if format[-1:] == '^': format = format[:-1] else: format += '\n' if args: message = format % args else: message = format stream.write(message) class Error(Exception): pass class Bundle: """Wrap the source, destination and backup paths in one neat little class. Used by CheetahWrapper.getBundles(). """ def __init__(self, **kw): self.__dict__.update(kw) def __repr__(self): return "" % self.__dict__ class MyOptionParser(OptionParser): standard_option_list = [] # We use commands for Optik's standard options. def error(self, msg): """Print our usage+error page.""" usage(HELP_PAGE2, msg) def print_usage(self, file=None): """Our usage+error page already has this.""" pass ################################################## ## USAGE FUNCTION & MESSAGES def usage(usageMessage, errorMessage="", out=sys.stderr): """Write help text, an optional error message, and abort the program. """ out.write(WRAPPER_TOP) out.write(usageMessage) exitStatus = 0 if errorMessage: out.write('\n') out.write("*** USAGE ERROR ***: %s\n" % errorMessage) exitStatus = 1 sys.exit(exitStatus) WRAPPER_TOP = """\ __ ____________ __ \ \/ \/ / \/ * * \/ CHEETAH %(Version)s Command-Line Tool \ | / \ ==----== / by Tavis Rudd \__________/ and Mike Orr """ % globals() HELP_PAGE1 = """\ USAGE: ------ cheetah compile [options] [FILES ...] : Compile template definitions cheetah fill [options] [FILES ...] : Fill template definitions cheetah help : Print this help message cheetah options : Print options help message cheetah test [options] : Run Cheetah's regression tests : (same as for unittest) cheetah version : Print Cheetah version number You may abbreviate the command to the first letter; e.g., 'h' == 'help'. If FILES is a single "-", read standard input and write standard output. Run "cheetah options" for the list of valid options. """ HELP_PAGE2 = """\ OPTIONS FOR "compile" AND "fill": --------------------------------- --idir DIR, --odir DIR : input/output directories (default: current dir) --iext EXT, --oext EXT : input/output filename extensions (default for compile: tmpl/py, fill: tmpl/html) -R : recurse subdirectories looking for input files --debug : print lots of diagnostic output to standard error --env : put the environment in the searchList --flat : no destination subdirectories --nobackup : don't make backups --pickle FILE : unpickle FILE and put that object in the searchList --stdout, -p : output to standard output (pipe) Run "cheetah help" for the main help screen. """ ################################################## ## CheetahWrapper CLASS class CheetahWrapper: MAKE_BACKUPS = True BACKUP_SUFFIX = ".bak" def __init__(self): self.progName = None self.command = None self.opts = None self.files = None self.sourceFiles = [] self.searchList = [] ################################################## ## VERBOSITY METHODS def chatter(self, format, *args): """Print a verbose message to stdout. But don't if .opts.stdout is true or .opts.verbose is false. """ if self.opts.stdout or not self.opts.verbose: return fprintfMessage(sys.stdout, format, *args) def debug(self, format, *args): """Print a debugging message to stderr, but don't if .debug is false. """ if self.opts.debug: fprintfMessage(sys.stderr, format, *args) def warn(self, format, *args): """Always print a warning message to stderr. """ fprintfMessage(sys.stderr, format, *args) ################################################## ## HELPER METHODS def _fixExts(self): assert self.opts.oext, "oext is empty!" iext, oext = self.opts.iext, self.opts.oext if iext and not iext.startswith("."): self.opts.iext = "." + iext if oext and not oext.startswith("."): self.opts.oext = "." + oext def parseOpts(self, args): C, D, W = self.chatter, self.debug, self.warn self.isCompile = isCompile = self.command[0] == 'c' defaultOext = isCompile and ".py" or ".html" parser = MyOptionParser() pao = parser.add_option pao("--idir", action="store", dest="idir", default="") pao("--odir", action="store", dest="odir", default="") pao("--iext", action="store", dest="iext", default=".tmpl") pao("--oext", action="store", dest="oext", default=defaultOext) pao("-R", action="store_true", dest="recurse", default=False) pao("--stdout", "-p", action="store_true", dest="stdout", default=False) pao("--debug", action="store_true", dest="debug", default=False) pao("--env", action="store_true", dest="env", default=False) pao("--pickle", action="store", dest="pickle", default="") pao("--flat", action="store_true", dest="flat", default=False) pao("--nobackup", action="store_true", dest="nobackup", default=False) self.opts, self.files = opts, files = parser.parse_args(args) D("""\ cheetah compile %s Options are %s Files are %s""", args, pprint.pformat(vars(opts)), files) self._fixExts() if opts.env: self.searchList.append(os.environ) if opts.pickle: f = open(opts.pickle, 'rb') unpickled = pickle.load(f) f.close() self.searchList.append(unpickled) opts.verbose = not opts.stdout def compileOrFillStdin(self): if self.isCompile: output = Compiler(file=sys.stdin) else: output = Template(file=sys.stdin) output = str(output) sys.stdout.write(output) def compileOrFillBundle(self, b): C, D, W = self.chatter, self.debug, self.warn src = b.src dst = b.dst base = b.base basename = b.basename dstDir = os.path.dirname(dst) what = self.isCompile and "Compiling" or "Filling" C("%s %s -> %s^", what, src, dst) # No trailing newline. if os.path.exists(dst) and not self.opts.nobackup: bak = b.bak C(" (backup %s)", bak) # On same line as previous message. else: bak = None C("") if self.isCompile: if not moduleNameRE.match(basename): tup = basename, src raise Error("""\ %s: base name %s contains invalid characters. It must be named according to the same rules as Python modules.""" % tup) obj = Compiler(file=src, \ moduleName=basename, mainClassName=basename) else: obj = Template(file=src, searchList=self.searchList) output = str(obj) if bak: shutil.copyfile(dst, bak) if dstDir and not os.path.exists(dstDir): if self.isCompile: mkdirsWithPyInitFiles(dstDir) else: os.makedirs(dstDir) if self.opts.stdout: sys.stdout.write(output) else: f = open(dst, 'w') f.write(output) f.close() def _checkForCollisions(self, bundles): """Check for multiple source paths writing to the same destination path. """ C, D, W = self.chatter, self.debug, self.warn isError = False dstSources = {} for b in bundles: if dstSources.has_key(b.dst): dstSources[b.dst].append(b.src) else: dstSources[b.dst] = [b.src] keys = dstSources.keys() keys.sort() for dst in keys: sources = dstSources[dst] if len(sources) > 1: isError = True sources.sort() fmt = \ "Collision: multiple source files %s map to one destination file %s" W(fmt, sources, dst) if isError: what = self.isCompile and "Compilation" or "Filling" sys.exit("%s aborted due to collisions" % what) def getBundles(self, sourceFiles): flat = self.opts.flat idir = self.opts.idir iext = self.opts.iext nobackup = self.opts.nobackup odir = self.opts.odir oext = self.opts.oext idirSlash = idir + os.sep bundles = [] for src in sourceFiles: # 'base' is the subdirectory plus basename. base = src if idir and src.startswith(idirSlash): base = src[len(idirSlash):] if iext and base.endswith(iext): base = base[:-len(iext)] basename = os.path.basename(base) if flat: dst = os.path.join(odir, basename + oext) else: dbn = basename if odir and base.startswith(os.sep): odd = odir while odd != '': i = base.find(odd) if i == 0: dbn = base[len(odd):] if dbn[0] == '/': dbn = dbn[1:] break odd = os.path.dirname(odd) if odd == '/': break dst = os.path.join(odir, dbn + oext) else: dst = os.path.join(odir, base + oext) bak = dst + self.BACKUP_SUFFIX b = Bundle(src=src, dst=dst, bak=bak, base=base, basename=basename) bundles.append(b) return bundles def _expandSourceFilesWalk(self, arg, dir, files): """Recursion extension for .expandSourceFiles(). This method is a callback for os.path.walk(). 'arg' is a list to which successful paths will be appended. """ iext = self.opts.iext for fil in files: path = os.path.join(dir, fil) if path.endswith(iext) and os.path.isfile(path): arg.append(path) elif os.path.islink(path) and os.path.isdir(path): os.path.walk(path, self._expandSourceFilesWalk, arg) # If is directory, do nothing; 'walk' will eventually get it. def expandSourceFiles(self, files, recurse, addIextIfMissing): """Calculate source paths from 'files' by applying the command-line options. """ C, D, W = self.chatter, self.debug, self.warn idir = self.opts.idir iext = self.opts.iext ret = [] for fil in self.files: oldRetLen = len(ret) D("Expanding %s", fil) path = os.path.join(idir, fil) pathWithExt = path + iext # May or may not be valid. if os.path.isdir(path): if recurse: os.path.walk(path, self._expandSourceFilesWalk, ret) else: raise Error("source file '%s' is a directory" % path) elif os.path.isfile(path): ret.append(path) elif addIextIfMissing and not path.endswith(iext) and \ os.path.isfile(pathWithExt): ret.append(pathWithExt) # Do not recurse directories discovered by iext appending. elif os.path.exists(path): W("Skipping source file '%s', not a plain file.", path) else: W("Skipping source file '%s', not found.", path) if len(ret) > oldRetLen: D(" ... found %s", ret[oldRetLen:]) return ret def compileOrFill(self): C, D, W = self.chatter, self.debug, self.warn opts, files = self.opts, self.files if files == ["-"]: self.compileOrFillStdin() return elif not files and opts.recurse: which = opts.idir and "idir" or "current" C("Drilling down recursively from %s directory.", which) sourceFiles = [] dir = os.path.join(self.opts.idir, os.curdir) os.path.walk(dir, self._expandSourceFilesWalk, sourceFiles) elif not files: usage(HELP_PAGE1, "Neither files nor -R specified!") else: sourceFiles = self.expandSourceFiles(files, opts.recurse, True) sourceFiles = [os.path.normpath(x) for x in sourceFiles] D("All source files found: %s", sourceFiles) bundles = self.getBundles(sourceFiles) D("All bundles: %s", pprint.pformat(bundles)) if self.opts.flat: self._checkForCollisions(bundles) for b in bundles: self.compileOrFillBundle(b) ################################################## ## COMMAND METHODS def compile(self): self.compileOrFill() def fill(self): self.compileOrFill() def help(self): usage(HELP_PAGE1, "", sys.stdout) def options(self): usage(HELP_PAGE2, "", sys.stdout) def test(self): # @@MO: Ugly kludge. TEST_WRITE_FILENAME = 'cheetah_test_file_creation_ability.tmp' try: f = open(TEST_WRITE_FILENAME, 'w') except: sys.exit("""\ Cannot run the tests because you don't have write permission in the current directory. The tests need to create temporary files. Change to a directory you do have write permission to and re-run the tests.""") else: f.close() os.remove(TEST_WRITE_FILENAME) # @@MO: End ugly kludge. from Cheetah.Tests import Test import Cheetah.Tests.unittest_local_copy as unittest del sys.argv[1:] # Prevent unittest from misinterpreting options. sys.argv.extend(self.testOpts) #unittest.main(testSuite=Test.testSuite) #unittest.main(testSuite=Test.testSuite) unittest.main(module=Test) def version(self): print Version # If you add a command, also add it to the 'meths' variable in main(). ################################################## ## MAIN ROUTINE def main(self, argv=None): """The main program controller.""" if argv is None: argv = sys.argv # Step 1: Determine the command and arguments. try: self.progName = progName = os.path.basename(argv[0]) self.command = command = optionDashesRE.sub("", argv[1]) if command == 'test': self.testOpts = argv[2:] else: self.parseOpts(argv[2:]) except IndexError: usage(HELP_PAGE1, "not enough command-line arguments") # Step 2: Call the command meths = (self.compile, self.fill, self.help, self.options, self.test, self.version) for meth in meths: methName = meth.__name__ # Or meth.im_func.func_name # Or meth.func_name (Python >= 2.1 only, sometimes works on 2.0) methInitial = methName[0] if command in (methName, methInitial): sys.argv[0] += (" " + methName) # @@MO: I don't necessarily agree sys.argv[0] should be # modified. meth() return # If none of the commands matched. usage(HELP_PAGE1, "unknown command '%s'" % command) #run = main ################################################## ## if run from the command line if __name__ == '__main__': CheetahWrapper().main() # vim: shiftwidth=4 tabstop=4 expandtab PKt95SSCheetah/CheetahWrapper.pyc; Ac@shdZdZddd!ZdkZdkZdkZdkZdkZdkZdk Z dk Z dk l Z dklZdklZd klZd klZeid Zeid Zd ZdefdYZdfdYZdefdYZde idZde Z!dZ"dZ#dfdYZ$e%djoe$i&ndS(sCheetah command-line interface. 2002-09-03 MSO: Total rewrite. 2002-09-04 MSO: Bugfix, compile command was using wrong output ext. 2002-11-08 MSO: Another rewrite. Meta-Data ================================================================================ Author: Tavis Rudd and Mike Orr Version: $Revision: 1.18 $ Start Date: 2001/03/30 Last Revision Date: $Date: 2005/01/03 19:57:24 $ s@Tavis Rudd and Mike Orr s$Revision: 1.18 $i iN(sVersion(sCompiler(sTemplate(smkdirsWithPyInitFiles(s OptionParsers^-{1,2}s^[a-zA-Z_][a-zA-Z_0-9]*$cGsU|ddjo|d }n |d7}|o||}n|}|i|dS(Nis^s (sformatsargssmessagesstreamswrite(sstreamsformatsargssmessage((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pysfprintfMessages sErrorcBstZRS(N(s__name__s __module__(((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pysError*ssBundlecBs tZdZdZdZRS(sxWrap the source, destination and backup paths in one neat little class. Used by CheetahWrapper.getBundles(). cKs|ii|dS(N(sselfs__dict__supdateskw(sselfskw((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pys__init__2scCsd|iSdS(Ns (sselfs__dict__(sself((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pys__repr__5s(s__name__s __module__s__doc__s__init__s__repr__(((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pysBundle.s  sMyOptionParsercBs#tZgZdZedZRS(NcCstt|dS(sPrint our usage+error page.N(susages HELP_PAGE2smsg(sselfsmsg((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pyserror<scCsdS(s&Our usage+error page already has this.N((sselfsfile((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pys print_usage@s(s__name__s __module__sstandard_option_listserrorsNones print_usage(((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pysMyOptionParser9s scCs`|it|i|d}|o(|id|id|d}nti|dS(sGWrite help text, an optional error message, and abort the program. is s*** USAGE ERROR ***: %s iN(soutswrites WRAPPER_TOPs usageMessages exitStatuss errorMessagessyssexit(s usageMessages errorMessagesouts exitStatus((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pysusageHs    s2 __ ____________ __ \ \/ \/ / \/ * * \/ CHEETAH %(Version)s Command-Line Tool \ | / \ ==----== / by Tavis Rudd \__________/ and Mike Orr sUSAGE: ------ cheetah compile [options] [FILES ...] : Compile template definitions cheetah fill [options] [FILES ...] : Fill template definitions cheetah help : Print this help message cheetah options : Print options help message cheetah test [options] : Run Cheetah's regression tests : (same as for unittest) cheetah version : Print Cheetah version number You may abbreviate the command to the first letter; e.g., 'h' == 'help'. If FILES is a single "-", read standard input and write standard output. Run "cheetah options" for the list of valid options. sOPTIONS FOR "compile" AND "fill": --------------------------------- --idir DIR, --odir DIR : input/output directories (default: current dir) --iext EXT, --oext EXT : input/output filename extensions (default for compile: tmpl/py, fill: tmpl/html) -R : recurse subdirectories looking for input files --debug : print lots of diagnostic output to standard error --env : put the environment in the searchList --flat : no destination subdirectories --nobackup : don't make backups --pickle FILE : unpickle FILE and put that object in the searchList --stdout, -p : output to standard output (pipe) Run "cheetah help" for the main help screen. sCheetahWrappercBstZeZdZdZdZdZdZdZ dZ dZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZedZRS(Ns.bakcCs:t|_t|_t|_t|_g|_g|_dS(N(sNonesselfsprogNamescommandsoptssfiless sourceFiless searchList(sself((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pys__init__s      cGs:|iip |ii odSntti||dS(stPrint a verbose message to stdout. But don't if .opts.stdout is true or .opts.verbose is false. N(sselfsoptssstdoutsverbosesfprintfMessagessyssformatsargs(sselfsformatsargs((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pyschatterscGs(|iiotti||ndS(sVPrint a debugging message to stderr, but don't if .debug is false. N(sselfsoptssdebugsfprintfMessagessyssstderrsformatsargs(sselfsformatsargs((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pysdebugs cGstti||dS(s2Always print a warning message to stderr. N(sfprintfMessagessyssstderrsformatsargs(sselfsformatsargs((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pyswarnscCs|iip td|ii|iif\}}|o|id od||i_n|o|id od||i_ndS(Nsoext is empty!s.(sselfsoptssoextsAssertionErrorsiexts startswith(sselfsoextsiext((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pys_fixExtss c Csd|i|i|if\}}} |iddj|_}|odpd}t }|i } | ddddd d d | d dddd d d | dddddd d| dddddd || dddddd t| ddddddd t| dddddd t| dddddd t| dddddd d | ddddd d t| d!dddd"d t|i|\|_|_\} }|d#|tit| ||i| io|iitin| io?t| id$}ti|} |i!|ii| n| i" | _#dS(%Niscs.pys.htmls--idirsactionsstoresdestsidirsdefaultss--odirsodirs--iextsiexts.tmpls--oextsoexts-Rs store_truesrecurses--stdouts-psstdouts--debugsdebugs--envsenvs--picklespickles--flatsflats --nobackupsnobackups.cheetah compile %s Options are %s Files are %ssrb($sselfschattersdebugswarnsCsDsWscommands isCompiles defaultOextsMyOptionParsersparsers add_optionspaosFalses parse_argssargssoptssfilesspprintspformatsvarss_fixExtssenvs searchListsappendsossenvironspicklesopensfsloads unpickledsclosesstdoutsverbose( sselfsargssfilessCsparsersDs isCompilesfs defaultOextsoptssWs unpickledspao((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pys parseOptss6!  %"    cCsR|iotdti}ntdti}t|}tii |dS(Nsfile( sselfs isCompilesCompilerssyssstdinsoutputsTemplatesstrsstdoutswrite(sselfsoutput((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pyscompileOrFillStdins   cCs|i|i|if\}}} |i} |i }|i } |i }t i i|}|iodpd}|d|| |t i i|o |ii o|i}|d|nt}|d|ioPti| o || f}td|ntd| d|d |} ntd| d |i} t| }|ot!i"||n|ot i i| o)|iot#|qt i$|n|ii%ot&i%i'|n't(|d } | i'|| i*dS( Ns CompilingsFillings %s %s -> %s^s (backup %s)ssn%s: base name %s contains invalid characters. It must be named according to the same rules as Python modules.sfiles moduleNames mainClassNames searchListsw(+sselfschattersdebugswarnsCsDsWsbssrcsdstsbasesbasenamesosspathsdirnamesdstDirs isCompileswhatsexistssoptssnobackupsbaksNones moduleNameREsmatchstupsErrorsCompilersobjsTemplates searchListsstrsoutputsshutilscopyfilesmkdirsWithPyInitFilessmakedirssstdoutssysswritesopensfsclose(sselfsbsdstsdstDirsbasenameswhatsCsDstupsbasesWssrcsobjsfsoutputsbak((s;build/bdist.darwin-8.7.1-i386/egg/Cheetah/CheetahWrapper.pyscompileOrFillBundles@!    !         c Cs$|i|i|if\}}} t} h}xO|D]G}|i |i o||i i|iq4|ig||i Version: $Revision: 1.77 $ Start Date: 2001/09/19 Last Revision Date: $Date: 2005/11/27 03:37:22 $ """ __author__ = "Tavis Rudd " __revision__ = "$Revision: 1.77 $"[11:-2] import sys import os import os.path from os.path import getmtime, exists import re import types import time import random import warnings from Cheetah.Version import Version from Cheetah.SettingsManager import SettingsManager from Cheetah.Parser import Parser, ParseError, specialVarRE, STATIC_CACHE, REFRESH_CACHE from Cheetah.Utils.Indenter import indentize # an undocumented preprocessor from Cheetah import ErrorCatchers from Cheetah import NameMapper class Error(Exception): pass class GenUtils: """An abstract baseclass for the Compiler classes that provides methods that perform generic utility functions or generate pieces of output code from information passed in by the Parser baseclass. These methods don't do any parsing themselves.""" def genTimeInterval(self, timeString): ##@@ TR: need to add some error handling here if timeString[-1] == 's': interval = float(timeString[:-1]) elif timeString[-1] == 'm': interval = float(timeString[:-1])*60 elif timeString[-1] == 'h': interval = float(timeString[:-1])*60*60 elif timeString[-1] == 'd': interval = float(timeString[:-1])*60*60*24 elif timeString[-1] == 'w': interval = float(timeString[:-1])*60*60*24*7 else: # default to minutes interval = float(timeString)*60 return interval def genCacheInfo(self, cacheToken): """Decipher a placeholder cachetoken """ match = self._parser.cacheTokenRE.match(cacheToken) subGrpDict = match.groupdict() cacheInfo = {} if subGrpDict['REFRESH_CACHE']: cacheInfo['type'] = REFRESH_CACHE cacheInfo['interval'] = self.genTimeInterval(subGrpDict['interval']) elif subGrpDict['STATIC_CACHE']: cacheInfo['type'] = STATIC_CACHE return cacheInfo # is empty if no cache def genCacheInfoFromArgList(self, argList): cacheInfo = {'type':REFRESH_CACHE} for key, val in argList: if val[0] in '"\'': val = val[1:-1] if key == 'timer': key = 'interval' val = self.genTimeInterval(val) cacheInfo[key] = val return cacheInfo def genCheetahVar(self, nameChunks, plain=False): if nameChunks[0][0] in self.setting('gettextTokens'): self.addGetTextVar(nameChunks) if self.setting('useNameMapper') and not plain: return self.genNameMapperVar(nameChunks) else: return self.genPlainVar(nameChunks) def addGetTextVar(self, nameChunks): """Output something that gettext can recognize. This is a harmless side effect necessary to make gettext work when it is scanning compiled templates for strings marked for translation. """ # @@TR: this should be in the compiler not here self.addChunk("if False:") self.indent() self.addChunk(self.genPlainVar(nameChunks[:])) self.dedent() def genPlainVar(self, nameChunks): """Generate Python code for a Cheetah $var without using NameMapper (Unified Dotted Notation with the SearchList).""" nameChunks.reverse() chunk = nameChunks.pop() pythonCode = chunk[0] + chunk[2] while nameChunks: chunk = nameChunks.pop() pythonCode = (pythonCode + '.' + chunk[0] + chunk[2]) return pythonCode def genNameMapperVar(self, nameChunks): """Generate valid Python code for a Cheetah $var, using NameMapper (Unified Dotted Notation with the SearchList). nameChunks = list of var subcomponents represented as tuples [ (name,useAC,remainderOfExpr), ] where: name = the dotted name base useAC = where NameMapper should use autocalling on namemapperPart remainderOfExpr = any arglist, index, or slice If remainderOfExpr contains a call arglist (e.g. '(1234)') then useAC is False, otherwise it defaults to True. It is overridden by the global setting 'useAutocalling' if this setting is False. EXAMPLE ------------------------------------------------------------------------ if the raw Cheetah Var is $a.b.c[1].d().x.y.z nameChunks is the list [ ('a.b.c',True,'[1]'), # A ('d',False,'()'), # B ('x.y.z',True,''), # C ] When this method is fed the list above it returns VFN(VFN(VFFSL(SL, 'a.b.c',True)[1], 'd',False)(), 'x.y.z',True) which can be represented as VFN(B`, name=C[0], executeCallables=(useAC and C[1]))C[2] where: VFN = NameMapper.valueForName VFFSL = NameMapper.valueFromFrameOrSearchList VFSL = NameMapper.valueFromSearchList # optionally used instead of VFFSL SL = self.searchList() useAC = self.setting('useAutocalling') # True in this example A = ('a.b.c',True,'[1]') B = ('d',False,'()') C = ('x.y.z',True,'') C` = VFN( VFN( VFFSL(SL, 'a.b.c',True)[1], 'd',False)(), 'x.y.z',True) = VFN(B`, name='x.y.z', executeCallables=True) B` = VFN(A`, name=B[0], executeCallables=(useAC and B[1]))B[2] A` = VFFSL(SL, name=A[0], executeCallables=(useAC and A[1]))A[2] Note, if the compiler setting useStackFrames=False (default is true) then A` = VFSL([locals()]+SL+[globals(), __builtin__], name=A[0], executeCallables=(useAC and A[1]))A[2] This option allows Cheetah to be used with Psyco, which doesn't support stack frame introspection. """ defaultUseAC = self.setting('useAutocalling') useSearchList = self.setting('useSearchList') nameChunks.reverse() name, useAC, remainder = nameChunks.pop() if not useSearchList: firstDotIdx = name.find('.') if firstDotIdx != -1 and firstDotIdx < len(name): beforeFirstDot, afterDot = name[:firstDotIdx], name[firstDotIdx+1:] pythonCode = ('VFN(' + beforeFirstDot + ',"' + afterDot + '",' + repr(defaultUseAC and useAC) + ')' + remainder) #print 'DEBUG1: ', pythonCode, name, remainder else: pythonCode = name+remainder #print 'DEBUG2: ', pythonCode, name, remainder elif self.setting('useStackFrames'): pythonCode = ('VFFSL(SL,' '"'+ name + '",' + repr(defaultUseAC and useAC) + ')' + remainder) else: pythonCode = ('VFSL([locals()]+SL+[globals(), __builtin__],' '"'+ name + '",' + repr(defaultUseAC and useAC) + ')' + remainder) while nameChunks: name, useAC, remainder = nameChunks.pop() pythonCode = ('VFN(' + pythonCode + ',"' + name + '",' + repr(defaultUseAC and useAC) + ')' + remainder) return pythonCode ################################################## ## METHOD COMPILERS class MethodCompiler(GenUtils): def __init__(self, methodName, classCompiler, templateObj=None): self._settingsManager = classCompiler self._templateObj = templateObj self._methodName = methodName self._setupState() def setting(self, key): return self._settingsManager.setting(key) def _setupState(self): self._indent = self.setting('indentationStep') self._indentLev = self.setting('initialMethIndentLevel') self._pendingStrConstChunks = [] self._methodSignature = None self._methodDef = None self._docStringLines = [] self._methodBodyChunks = [] self._cacheRegionOpen = False def cleanupState(self): """Called by the containing class compiler instance""" pass def methodName(self): return self._methodName def setMethodName(self, name): self._methodName = name ## methods for managing indentation def indentation(self): return self._indent * self._indentLev def indent(self): self._indentLev +=1 def dedent(self): if self._indentLev: self._indentLev -=1 else: raise Error('Attempt to dedent when the indentLev is 0') ## methods for final code wrapping def methodDef(self): if self._methodDef: return self._methodDef else: return self.wrapCode() __str__ = methodDef def wrapCode(self): self.commitStrConst() methodDefChunks = ( self.methodSignature(), '\n', self.docString(), self.methodBody(), ) methodDef = ''.join(methodDefChunks) self._methodDef = methodDef return methodDef def methodSignature(self): return self._indent + self._methodSignature + ':' def setMethodSignature(self, signature): self._methodSignature = signature def methodBody(self): return ''.join( self._methodBodyChunks ) def docString(self): ind = self._indent*2 docStr = (ind + '"""\n' + ind + ('\n' + ind).join(self._docStringLines) + '\n' + ind + '"""\n') return docStr ## methods for adding code def addMethDocString(self, line): self._docStringLines.append(line.replace('%','%%')) def addChunk(self, chunk): self.commitStrConst() chunk = "\n" + self.indentation() + chunk self._methodBodyChunks.append(chunk) def appendToPrevChunk(self, appendage): self._methodBodyChunks[-1] = self._methodBodyChunks[-1] + appendage def addWriteChunk(self, chunk): self.addChunk('write(' + chunk + ')') def addFilteredChunk(self, chunk, filterArgs=None, rawExpr=None): """ """ if filterArgs is None: filterArgs = '' if self.setting('includeRawExprInFilterArgs') and rawExpr: filterArgs += ', rawExpr=%s'%repr(rawExpr) if self.setting('alwaysFilterNone'): self.addChunk("__v = %s"%chunk) if self.setting('useFilters'): self.addChunk("if __v is not None: write(filter(__v%s))"%filterArgs) else: self.addChunk("if __v is not None: write(str(__v))") else: if self.setting('useFilters'): self.addChunk("write(filter(%s%s))"%(chunk,filterArgs)) else: self.addChunk("write(str(%s))"%chunk) # @@TR: consider merging the next two methods into one def addStrConst(self, strConst): self._appendToPrevStrConst(strConst) def addRawText(self, text): self.addStrConst(text) def _appendToPrevStrConst(self, strConst): if self._pendingStrConstChunks: self._pendingStrConstChunks.append(strConst) else: self._pendingStrConstChunks = [strConst] 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 \$vars in the string.""" token = self.setting('directiveStartToken') return theString.replace('\\' + token, token) def commitStrConst(self): """Add the code for outputting the pending strConst without chopping off any whitespace from it. """ if self._pendingStrConstChunks: strConst = self._unescapeCheetahVars(''.join(self._pendingStrConstChunks)) strConst = self._unescapeDirectives(strConst) self._pendingStrConstChunks = [] if self.setting('reprShortStrConstants') and \ strConst.count('\n') < self.setting('reprNewlineThreshold'): self.addWriteChunk( repr(strConst).replace('\\012','\\n')) else: strConst = strConst.replace('\\','\\\\').replace("'''","'\'\'\'") if strConst[0] == "'": strConst = '\\' + strConst if strConst[-1] == "'": strConst = strConst[:-1] + '\\' + strConst[-1] self.addWriteChunk("'''" + strConst + "'''" ) def handleWSBeforeDirective(self): """Truncate the pending strCont to the beginning of the current line. """ if self._pendingStrConstChunks: src = self._pendingStrConstChunks[-1] BOL = max(src.rfind('\n')+1, src.rfind('\r')+1, 0) if BOL < len(src): self._pendingStrConstChunks[-1] = src[:BOL] def addMethComment(self, comm): offSet = self.setting('commentOffset') self.addChunk('#' + ' '*offSet + comm) def addSilent(self, expr): self.addChunk( expr ) def addSet(self, LVALUE, OP, RVALUE, isGlobal=True): ## we need to split the LVALUE to deal with globalSetVars splitPos1 = LVALUE.find('.') splitPos2 = LVALUE.find('[') if splitPos1 > 0 and splitPos2==-1: splitPos = splitPos1 elif splitPos1 > 0 and splitPos1 < max(splitPos2,0): splitPos = splitPos1 else: splitPos = splitPos2 if splitPos >0: primary = LVALUE[:splitPos] secondary = LVALUE[splitPos:] else: primary = LVALUE secondary = '' if isGlobal: LVALUE = 'globalSetVars["' + primary + '"]' + secondary else: pass self.addChunk( LVALUE + ' ' + OP + ' ' + RVALUE.strip() ) def addInclude(self, sourceExpr, includeFrom, isRaw): # @@TR: consider soft-coding this self.addChunk('self._includeCheetahSource(' + sourceExpr + ', trans=trans, ' + 'includeFrom="' + includeFrom + '", raw=' + repr(isRaw) + ')') def addWhile(self, expr): self.addIndentingDirective(expr) def addFor(self, expr): self.addIndentingDirective(expr) def addRepeat(self, expr): #the _repeatCount stuff here allows nesting of #repeat directives self._repeatCount = getattr(self, "_repeatCount", -1) + 1 self.addFor('for __i%s in range(%s)' % (self._repeatCount,expr)) def addIndentingDirective(self, expr): if expr and not expr[-1] == ':': expr = expr + ':' self.addChunk( expr ) self.indent() def addReIndentingDirective(self, expr): self.commitStrConst() self.dedent() if not expr[-1] == ':': expr = expr + ':' self.addChunk( expr ) self.indent() def addIf(self, expr): """For a full #if ... #end if directive """ self.addIndentingDirective(expr) def addOneLineIf(self, conditionExpr, trueExpr, falseExpr): """For a single-lie #if ... then .... else ... directive then else """ self.addIndentingDirective(conditionExpr) self.addFilteredChunk(trueExpr) self.dedent() self.addIndentingDirective('else') self.addFilteredChunk(falseExpr) self.dedent() def addElse(self, expr): expr = re.sub(r'else[ \f\t]+if','elif', expr) self.addReIndentingDirective(expr) def addUnless(self, expr): self.addIf('if not (' + expr + ')') def addTry(self, expr): self.addIndentingDirective(expr) def addExcept(self, expr): self.addReIndentingDirective(expr) def addFinally(self, expr): self.addReIndentingDirective(expr) def addReturn(self, expr): self.addChunk(expr) def addPSP(self, PSP): self.commitStrConst() autoIndent = False if PSP[0] == '=': PSP = PSP[1:] if PSP: self.addWriteChunk('filter(' + PSP + ')') return elif PSP.lower() == 'end': self.dedent() return elif PSP[-1] == '$': autoIndent = True PSP = PSP[:-1] elif PSP[-1] == ':': autoIndent = True for line in PSP.splitlines(): self.addChunk(line) if autoIndent: self.indent() def nextCacheID(self): return str(random.randrange(100, 999)) \ + str(random.randrange(10000, 99999)) def startCacheRegion(self, cacheInfo, lineCol): ID = self.nextCacheID() interval = cacheInfo.get('interval',None) test = cacheInfo.get('test',None) customID = cacheInfo.get('id',None) if customID: ID = repr(customID) varyBy = cacheInfo.get('varyBy',ID) self._cacheRegionOpen = True # attrib of current methodCompiler self.addChunk('## START CACHE REGION: at line, col ' + str(lineCol) + ' in the source.') self.addChunk('RECACHE = False') self.addChunk('region = self._cacheRegions.get(' + ID + ')') self.addChunk('if not region:') self.indent() self.addChunk("region = CacheRegion()") self.addChunk("self._cacheRegions[" + ID + "] = region") self.addChunk('RECACHE = True') self.dedent() self.addChunk('cache = region.getCache('+varyBy+')') if interval: self.addMethDocString('This cache will be refreshed every ' + str(interval) + ' seconds.') self.addChunk('if (not cache.getRefreshTime())' + ' or (currentTime() > cache.getRefreshTime()):') self.indent() self.addChunk("cache.setRefreshTime(currentTime() +" + str(interval) + ")") self.addChunk('RECACHE = True') self.dedent() if test: self.addChunk('if ' + test + ':') self.indent() self.addChunk('RECACHE = True') self.dedent() self.addChunk('if RECACHE or not cache.getData():') self.indent() self.addChunk('orig_trans = trans') self.addChunk('trans = cacheCollector = DummyTransaction()') self.addChunk('write = cacheCollector.response().write') def endCacheRegion(self): self._cacheRegionOpen = False self.addChunk('trans = orig_trans') self.addChunk('write = trans.response().write') self.addChunk('cache.setData(cacheCollector.response().getvalue())') self.addChunk('del cacheCollector') self.dedent() self.addWriteChunk('cache.getData()') self.addChunk('## END CACHE REGION') self.addChunk('') def setErrorCatcher(self, errorCatcherName): if self._templateObj: self._templateObj._errorCatcher = \ getattr(ErrorCatchers, errorCatcherName)(self._templateObj) self.addChunk('if self._errorCatchers.has_key("' + errorCatcherName + '"):') self.indent() self.addChunk('self._errorCatcher = self._errorCatchers["' + errorCatcherName + '"]') self.dedent() self.addChunk('else:') self.indent() self.addChunk('self._errorCatcher = self._errorCatchers["' + errorCatcherName + '"] = ErrorCatchers.' + errorCatcherName + '(self)' ) self.dedent() def setFilter(self, theFilter, isKlass): if isKlass: self.addChunk('filter = self._currentFilter = ' + theFilter.strip() + '(self).filter') else: if theFilter.lower() == 'none': self.addChunk('filter = self._initialFilter') else: # is string representing the name of a builtin filter self.addChunk('filterName = ' + repr(theFilter)) self.addChunk('if self._filters.has_key("' + theFilter + '"):') self.indent() self.addChunk('filter = self._currentFilter = self._filters[filterName]') self.dedent() self.addChunk('else:') self.indent() self.addChunk('filter = self._currentFilter = \\\n\t\t\tself._filters[filterName] = ' + 'getattr(self._filtersLib, filterName)(self).filter') self.dedent() class AutoMethodCompiler(MethodCompiler): def _setupState(self): MethodCompiler._setupState(self) self._argStringList = [ ("self",None) ] self._streamingEnabled = True def cleanupState(self): MethodCompiler.cleanupState(self) self.commitStrConst() if self._cacheRegionOpen: self.endCacheRegion() self._indentLev = self.setting('initialMethIndentLevel') mainBodyChunks = self._methodBodyChunks self._methodBodyChunks = [] self._addAutoSetupCode() self._methodBodyChunks.extend(mainBodyChunks) self._addAutoCleanupCode() if self._streamingEnabled: argList = [ ('trans', 'None'), #("dummyTrans","False"), ] if self.setting('useNameMapper'): argList.extend([("VFFSL","valueFromFrameOrSearchList"), ("VFN","valueForName")]) for argName, defVal in argList: self.addMethArg(argName, defVal) def _addAutoSetupCode(self): if self._streamingEnabled: self.addChunk('if not trans: trans = self.transaction' ' # is None unless self.awake() was called') self.addChunk('if not trans:') self.indent() self.addChunk('trans = DummyTransaction()') if self.setting('autoAssignDummyTransactionToSelf'): self.addChunk('self.transaction = trans') self.addChunk('dummyTrans = True') self.dedent() self.addChunk('else: dummyTrans = False') else: self.addChunk('trans = DummyTransaction()') self.addChunk('dummyTrans = True') self.addChunk('write = trans.response().write') if self.setting('useNameMapper'): self.addChunk('SL = self._searchList') self.addChunk('globalSetVars = self._globalSetVars') if self.setting('useFilters'): self.addChunk('filter = self._currentFilter') self.addChunk('') self.addChunk("#" *40) self.addChunk('## START - generated method body') self.addChunk('') def _addAutoCleanupCode(self): self.addChunk('') self.addChunk("#" *40) self.addChunk('## END - generated method body') self.addChunk('') self.addStop() self.addChunk('') def addStop(self, expr=None): self.addChunk('return dummyTrans and trans.response().getvalue() or ""') def addMethArg(self, name, defVal=None): asteriskPos = max(name.rfind('*')+1, 0) if asteriskPos: self._streamingEnabled = False self._argStringList.append( (name,defVal) ) def methodSignature(self): argStringChunks = [] for arg in self._argStringList: chunk = arg[0] if not arg[1] == None: chunk += '=' + arg[1] argStringChunks.append(chunk) return (self._indent + "def " + self.methodName() + "(" + (',\n' + self._indent*3).join(argStringChunks) + "):\n\n") ################################################## ## CLASS COMPILERS class ClassCompiler(GenUtils): methodCompilerClass = AutoMethodCompiler methodCompilerClassForInit = MethodCompiler def __init__(self, className, mainMethodName='respond', templateObj=None, fileName=None, settingsManager=None): self._settingsManager = settingsManager self._fileName = fileName self._className = className self._mainMethodName = mainMethodName self._templateObj = templateObj self._setupState() methodCompiler = self._spawnMethodCompiler(mainMethodName) methodCompiler.addMethDocString('This is the main method generated by Cheetah') self._setActiveMethodCompiler(methodCompiler) if fileName and self.setting('monitorSrcFile'): self._addSourceFileMonitoring(fileName) def setting(self, key): return self._settingsManager.setting(key) def __getattr__(self, name): """Provide access to the methods and attributes of the MethodCompiler at the top of the activeMethods stack: one-way namespace sharing WARNING: Use .setMethods to assign the attributes of the MethodCompiler from the methods of this class!!! or you will be assigning to attributes of this object instead.""" if self.__dict__.has_key(name): return self.__dict__[name] elif hasattr(self.__class__, name): return getattr(self.__class__, name) elif self._activeMethodsList and hasattr(self._activeMethodsList[-1], name): return getattr(self._activeMethodsList[-1], name) else: raise AttributeError, name def _setupState(self): self._classDef = None self._activeMethodsList = [] # stack while parsing/generating self._finishedMethodsList = [] # store by order self._methodsIndex = {} # store by name self._baseClass = 'Template' self._classDocStringLines = [] self._generatedAttribs = [] # printed after methods in the gen class def self._initMethChunks = [] self._alias__str__ = True # should we set the __str__ alias self._blockMetaData = {} self._errorCatcherCount = 0 self._placeholderToErrorCatcherMap = {} def cleanupState(self): while self._activeMethodsList: methCompiler = self._popActiveMethodCompiler() self._swallowMethodCompiler(methCompiler) self._setupInitMethod() if self._mainMethodName == 'respond': self._generatedAttribs.append('__str__ = respond') if self._templateObj: self._templateObj.__str__ = self._templateObj.respond self.addAttribute('_mainCheetahMethod_for_' + self._className + '= ' + repr(self._mainMethodName) ) def _setupInitMethod(self): __init__ = self._spawnMethodCompiler('__init__', klass=self.methodCompilerClassForInit) __init__.setMethodSignature("def __init__(self, *args, **KWs)") __init__.addChunk("%s.__init__(self, *args, **KWs)" % self._baseClass) for chunk in self._initMethChunks: __init__.addChunk(chunk) __init__.cleanupState() self._swallowMethodCompiler(__init__, pos=0) def _addSourceFileMonitoring(self, fileName): # the first bit is added to init self.addChunkToInit('self._filePath = ' + repr(fileName)) self.addChunkToInit('self._fileMtime = ' + str(getmtime(fileName)) ) if self._templateObj: setattr(self._templateObj, '_filePath', fileName) setattr(self._templateObj, '_fileMtime', getmtime(fileName)) # the rest is added to the main output method of the class ('mainMethod') self.addChunk('if exists(self._filePath) and ' + 'getmtime(self._filePath) > self._fileMtime:') self.indent() self.addChunk('self.compile(file=self._filePath, moduleName=' +className + ')') self.addChunk( 'write(getattr(self, self._mainCheetahMethod_for_' + self._className + ')(trans=trans))') self.addStop() self.dedent() def setClassName(self, name): self._className = name def className(self): return self._className def setBaseClass(self, baseClassName): self._baseClass = baseClassName def setMainMethodName(self, methodName): ## change the name in the methodCompiler and add new reference mainMethod = self._methodsIndex[self._mainMethodName] mainMethod.setMethodName(methodName) self._methodsIndex[methodName] = mainMethod ## make sure that fileUpdate code still works properly: chunkToChange = ('write(self.' + self._mainMethodName + '(trans=trans))') chunks = mainMethod._methodBodyChunks if chunkToChange in chunks: for i in range(len(chunks)): if chunks[i] == chunkToChange: chunks[i] = ('write(self.' + methodName + '(trans=trans))') ## get rid of the old reference and update self._mainMethodName del self._methodsIndex[self._mainMethodName] self._mainMethodName = methodName def _spawnMethodCompiler(self, methodName, klass=None): if klass is None: klass = self.methodCompilerClass methodCompiler = klass(methodName, classCompiler=self, templateObj=self._templateObj) self._methodsIndex[methodName] = methodCompiler return methodCompiler def _setActiveMethodCompiler(self, methodCompiler): self._activeMethodsList.append(methodCompiler) def _getActiveMethodCompiler(self): return self._activeMethodsList[-1] def _popActiveMethodCompiler(self): return self._activeMethodsList.pop() def _swallowMethodCompiler(self, methodCompiler, pos=None): methodCompiler.cleanupState() if pos==None: self._finishedMethodsList.append( methodCompiler ) else: self._finishedMethodsList.insert(pos, methodCompiler) if self._templateObj and methodCompiler.methodName() != '__init__': self._templateObj._bindCompiledMethod(methodCompiler) return methodCompiler def startMethodDef(self, methodName, argsList, parserComment): methodCompiler = self._spawnMethodCompiler(methodName) self._setActiveMethodCompiler(methodCompiler) ## deal with the method's argstring for argName, defVal in argsList: methodCompiler.addMethArg(argName, defVal) methodCompiler.addMethDocString(parserComment) def _finishedMethods(self): return self._finishedMethodsList def addClassDocString(self, line): self._classDocStringLines.append( line.replace('%','%%')) def addChunkToInit(self,chunk): self._initMethChunks.append(chunk) def addAttribute(self, attribExpr): ## first test to make sure that the user hasn't used any fancy Cheetah syntax # (placeholders, directives, etc.) inside the expression if attribExpr.find('VFN(') != -1 or attribExpr.find('VFFSL(') != -1: raise ParseError(self, 'Invalid #attr directive.' + ' It should only contain simple Python literals.') ## now add the attribute self._generatedAttribs.append(attribExpr) if self._templateObj: exec('self._templateObj.' + attribExpr.strip()) def addSettingsToInit(self, settingsStr, settingsType='ini'): #@@TR 2005-01-01: this may not be used anymore? if settingsType=='python': reader = 'updateSettingsFromPySrcStr' else: reader = 'updateSettingsFromConfigStr' settingsCode = ("self." + reader + "('''" + settingsStr.replace("'''","\'\'\'") + "''')") self.addChunkToInit(settingsCode) def addErrorCatcherCall(self, codeChunk, rawCode='', lineCol=''): if self._placeholderToErrorCatcherMap.has_key(rawCode): methodName = self._placeholderToErrorCatcherMap[rawCode] if not self.setting('outputRowColComments'): self._methodsIndex[methodName].addMethDocString( 'plus at line, col ' + str(lineCol)) return methodName self._errorCatcherCount += 1 methodName = '__errorCatcher' + str(self._errorCatcherCount) self._placeholderToErrorCatcherMap[rawCode] = methodName catcherMeth = self._spawnMethodCompiler(methodName, klass=MethodCompiler) catcherMeth.setMethodSignature('def ' + methodName + '(self, localsDict={})') # is this use of localsDict right? catcherMeth.addMethDocString('Generated from ' + rawCode + ' at line, col ' + str(lineCol) + '.') catcherMeth.addChunk('try:') catcherMeth.indent() catcherMeth.addChunk("return eval('''" + codeChunk + "''', globals(), localsDict)") catcherMeth.dedent() catcherMeth.addChunk('except self._errorCatcher.exceptions(), e:') catcherMeth.indent() catcherMeth.addChunk("return self._errorCatcher.warn(exc_val=e, code= " + repr(codeChunk) + " , rawCode= " + repr(rawCode) + " , lineCol=" + str(lineCol) +")") catcherMeth.cleanupState() self._swallowMethodCompiler(catcherMeth) return methodName def closeDef(self): self.commitStrConst() methCompiler = self._popActiveMethodCompiler() self._swallowMethodCompiler(methCompiler) def closeBlock(self): self.commitStrConst() methCompiler = self._popActiveMethodCompiler() methodName = methCompiler.methodName() if self.setting('includeBlockMarkers'): endMarker = self.setting('blockMarkerEnd') methCompiler.addStrConst(endMarker[0] + methodName + endMarker[1]) self._swallowMethodCompiler(methCompiler) #metaData = self._blockMetaData[methodName] #rawDirective = metaData['raw'] #lineCol = metaData['lineCol'] ## insert the code to call the block, caching if #cache directive is on codeChunk = 'self.' + methodName + '(trans=trans)' self.addChunk(codeChunk) #self.appendToPrevChunk(' # generated from ' + repr(rawDirective) ) #if self.setting('outputRowColComments'): # self.appendToPrevChunk(' at line %s, col %s' % lineCol + '.') ## code wrapping methods def classDef(self): if self._classDef: return self._classDef else: return self.wrapClassDef() __str__ = classDef def wrapClassDef(self): self.addClassDocString('') self.addClassDocString(self.setting('defDocStrMsg')) ind = self.setting('indentationStep') classDefChunks = ( self.classSignature(), self.classDocstring(), ind + '#'*50, ind + '## GENERATED METHODS', '\n', self.methodDefs(), ind + '#'*50, ind + '## GENERATED ATTRIBUTES', '\n', self.attributes(), ) classDef = '\n'.join(classDefChunks) self._classDef = classDef return classDef def classSignature(self): return "class %s(%s):" % (self.className(), self._baseClass) def classDocstring(self): ind = self.setting('indentationStep') docStr = ('%(ind)s"""\n%(ind)s' + '\n%(ind)s'.join(self._classDocStringLines) + '\n%(ind)s"""\n' ) % {'ind':ind} return docStr def methodDefs(self): methodDefs = [str(methGen) for methGen in self._finishedMethods() ] return '\n\n'.join(methodDefs) def attributes(self): attribs = [self.setting('indentationStep') + str(attrib) for attrib in self._generatedAttribs ] return '\n\n'.join(attribs) class AutoClassCompiler(ClassCompiler): pass ################################################## ## MODULE COMPILERS #class ModuleCompiler(Parser, GenUtils): class ModuleCompiler(SettingsManager, GenUtils): parserClass = Parser classCompilerClass = AutoClassCompiler def __init__(self, source=None, file=None, moduleName='GenTemplate', mainClassName=None, mainMethodName='respond', templateObj=None, settings=None): SettingsManager.__init__(self) if settings: self.updateSettings(settings) # disable useStackFrames if the C version of NameMapper isn't compiled # it's painfully slow in the Python version and bites Windows users all # the time: if not NameMapper.C_VERSION: warnings.warn( "\nYou don't have the C version of NameMapper installed! " "I'm disabling Cheetah's useStackFrames option as it is " "painfully slow with the Python version of NameMapper. " "You should get a copy of Cheetah with the compiled C version of NameMapper." ) self.setSetting('useStackFrames', False) self._templateObj = templateObj self._compiled = False self._moduleName = moduleName if not mainClassName: self._mainClassName = moduleName else: self._mainClassName = mainClassName self._mainMethodName = mainMethodName self._filePath = None self._fileMtime = None if source and file: raise TypeError("Cannot compile from a source string AND file.") elif isinstance(file, types.StringType) or isinstance(file, types.UnicodeType): # it's a filename. f = open(file) # Raises IOError. source = f.read() f.close() self._filePath = file self._fileMtime = os.path.getmtime(file) elif hasattr(file, 'read'): source = file.read() # Can't set filename or mtime--they're not accessible. elif file: raise TypeError("'file' argument must be a filename string or file-like object") if self._filePath: self._fileDirName, self._fileBaseName = os.path.split(self._filePath) self._fileBaseNameRoot, self._fileBaseNameExt = \ os.path.splitext(self._fileBaseName) if not (isinstance(source, str) or isinstance(source, unicode)): source = str( source ) # by converting to string here we allow objects such as other Templates # to be passed in # Handle the #indent directive by converting it to other directives. # (Over the long term we'll make it a real directive.) if source == "": warnings.warn("You supplied an empty string for the source!", ) if source.find('#indent') != -1: #@@TR: undocumented hack source = indentize(source) self._parser = self.parserClass(source, filename=self._filePath, compiler=self) self._setupCompilerState() def __getattr__(self, name): """Provide one-way access to the methods and attributes of the ClassCompiler, and thereby the MethodCompilers as well. WARNING: Use .setMethods to assign the attributes of the ClassCompiler from the methods of this class!!! or you will be assigning to attributes of this object instead.""" if self.__dict__.has_key(name): return self.__dict__[name] elif hasattr(self.__class__, name): return getattr(self.__class__, name) elif self._activeClassesList and hasattr(self._activeClassesList[-1], name): return getattr(self._activeClassesList[-1], name) else: raise AttributeError, name def _initializeSettings(self): defaults = { 'indentationStep': ' '*4, 'initialMethIndentLevel': 2, 'monitorSrcFile':False, ## controlling the handling of Cheetah $vars 'useNameMapper': True, # Unified dotted notation and the searchList 'useSearchList': True, # if false, assume the first # portion of the $variable (before the first dot) is a global, # builtin, or local var that doesn't need # looking up in the searchlist BUT use # namemapper on the rest of the lookup 'useAutocalling': True, # detect and call callable()'s, requires NameMapper 'useStackFrames': True, # use NameMapper.valueFromFrameOrSearchList # rather than NameMapper.valueFromSearchList 'useErrorCatcher':False, # the next four are new in 1.0rc2 'alwaysFilterNone':True, # filter out None, before the filter is called 'useFilters':True, # use str instead if =False 'includeRawExprInFilterArgs':True, 'autoAssignDummyTransactionToSelf':False, ## controlling the aesthetic appearance of the generated code 'commentOffset': 1, # should shorter str constant chunks be printed using repr rather than ''' quotes 'reprShortStrConstants': True, 'reprNewlineThreshold':3, 'outputRowColComments':True, ## should #block's be wrapped in a comment in the template's output 'includeBlockMarkers': False, 'blockMarkerStart':('\n\n'), 'blockMarkerEnd':('\n\n'), 'defDocStrMsg':'Autogenerated by CHEETAH: The Python-Powered Template Engine', 'gettextTokens': ["_", "N_", "ngettext"], ## @@TR: The following really belong in the parser, but I've put them ## here for the time being to facilitate separating the parser and ## compiler: 'cheetahVarStartToken':'$', 'commentStartToken':'##', 'multiLineCommentStartToken':'#*', 'multiLineCommentEndToken':'*#', 'directiveStartToken':'#', 'directiveEndToken':'#', 'PSPStartToken':'<%', 'PSPEndToken':'%>', } self.updateSettings( defaults ) def _setupCompilerState(self): self._activeClassesList = [] self._finishedClassesList = [] # listed by ordered self._finishedClassIndex = {} # listed by name self._moduleDef = None self._moduleShBang = '#!/usr/bin/env python' self._moduleEncoding = '' self._moduleHeaderLines = [] self._moduleDocStringLines = [] self._specialVars = {} self._importStatements = [ "import sys", "import os", "import os.path", "from os.path import getmtime, exists", "import time", "import types", "import __builtin__", "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", ] self._importedVarNames = ['sys', 'os', 'os.path', 'time', 'types', 'Template', 'DummyTransaction', 'NotFound', 'Filters', 'ErrorCatchers', 'CacheRegion', ] self._moduleConstants = [ "try:", " True, False", "except NameError:", " True, False = (1==1), (1==0)", "VFFSL=valueFromFrameOrSearchList", "VFSL=valueFromSearchList", "VFN=valueForName", "currentTime=time.time", ] self._errorCatcherOn = False def compile(self): classCompiler = self._spawnClassCompiler(self._mainClassName) self._addActiveClassCompiler(classCompiler) self._parser.parse() self._swallowClassCompiler(self._popActiveClassCompiler()) self._compiled = True def _spawnClassCompiler(self, className, klass=None, mainMethodName='respond'): if klass is None: klass = self.classCompilerClass classCompiler = klass(className, mainMethodName=self._mainMethodName, templateObj=self._templateObj, fileName=self._filePath, settingsManager=self, ) return classCompiler def _addActiveClassCompiler(self, classCompiler): self._activeClassesList.append(classCompiler) def _getActiveClassCompiler(self): return self._activeClassesList[-1] def _popActiveClassCompiler(self): return self._activeClassesList.pop() def _swallowClassCompiler(self, classCompiler): classCompiler.cleanupState() self._finishedClassesList.append( classCompiler ) self._finishedClassIndex[classCompiler.className()] = classCompiler return classCompiler def _finishedClasses(self): return self._finishedClassesList def importedVarNames(self): return self._importedVarNames def addImportedVarNames(self, varNames): self._importedVarNames.extend(varNames) def isErrorCatcherOn(self): return self._errorCatcherOn def turnErrorCatcherOn(self): self._errorCatcherOn = True def turnErrorCatcherOff(self): self._errorCatcherOn = False ## methods for adding stuff to the module and class definitions def setBaseClass(self, baseClassName): # change the default mainMethodName from the default 'respond' self.setMainMethodName('writeBody') # @@TR: needs some thought ################################################## ## If the #extends directive contains a classname or modulename that isn't # in self.importedVarNames() already, we assume that we need to add # an implied 'from ModName import ClassName' where ModName == ClassName. # - This is the case in WebKit servlet modules. # - We also assume that the final . separates the classname from the # module name. This might break if people do something really fancy # with their dots and namespaces. chunks = baseClassName.split('.') if len(chunks) > 1: modName, bareClassName = '.'.join(chunks[:-1]), chunks[-1] else: # baseClassName is either unimported modName # or a previously imported classname modName = bareClassName = baseClassName if modName not in self.importedVarNames(): if len(chunks) > 1 and bareClassName != chunks[:-1][-1]: modName = '.'.join(chunks) importStatement = "from %s import %s" % (modName, bareClassName) self.addImportStatement(importStatement) self.addImportedVarNames( [bareClassName,] ) self._getActiveClassCompiler().setBaseClass(bareClassName) ################################################## ## dynamically bind to and __init__ with this new baseclass # - this is required for dynamic use of templates compiled directly from file # - also necessary for the 'monitorSrc' fileMtime triggered recompiles if self._templateObj: mod = self._templateObj._importAsDummyModule('\n'.join(self._importStatements)) class newClass: pass newClass.__name__ = self._mainClassName __bases__ = (getattr(mod, self._baseClass), ) newClass.__bases__ = __bases__ self._templateObj.__class__ = newClass # must initialize it so instance attributes are accessible newClass.__init__(self._templateObj, _globalSetVars=self._templateObj._globalSetVars, _preBuiltSearchList=self._templateObj._searchList) def setCompilerSetting(self, key, valueExpr): self.setSetting(key, eval(valueExpr) ) self._parser.configureParser() def setCompilerSettings(self, keywords, settingsStr): KWs = keywords merge = True if 'nomerge' in KWs: merge = False if 'reset' in KWs: # @@TR: this is actually caught by the parser at the moment. # subject to change in the future self._initializeSettings() self._parser.configureParser() return elif 'python' in KWs: settingsReader = self.updateSettingsFromPySrcStr # this comes from SettingsManager else: # this comes from SettingsManager settingsReader = self.updateSettingsFromConfigStr settingsReader(settingsStr) self._parser.configureParser() def setShBang(self, shBang): self._moduleShBang = shBang def setModuleEncoding(self, encoding): self._moduleEncoding = '# -*- coding: %s -*-' %encoding def addModuleHeader(self, line): self._moduleHeaderLines.append(line) def addModuleDocString(self, line): self._moduleDocStringLines.append(line) def addSpecialVar(self, basename, contents): self._specialVars['__' + basename + '__'] = contents.strip() def addImportStatement(self, impStatement): self._importStatements.append(impStatement) #@@TR 2005-01-01: there's almost certainly a cleaner way to do this! importVarNames = impStatement[impStatement.find('import') + len('import'):].split(',') importVarNames = [var.split()[-1] for var in importVarNames] # handles aliases importVarNames = [var for var in importVarNames if var!='*'] self.addImportedVarNames(importVarNames) #used by #extend for auto-imports if self._templateObj: import Template as TemplateMod mod = self._templateObj._importAsDummyModule(impStatement) # @@TR 2005-01-15: testing this approach to support # 'from foo import *' self._templateObj._searchList.append(mod) # @@TR: old buggy approach is still needed for now for varName in importVarNames: if varName == '*': continue val = getattr(mod, varName.split('.')[0]) setattr(TemplateMod, varName, val) def addGlobalCodeChunk(self, codeChunk): self._globalCodeChunks.append(codeChunk) def addAttribute(self, attribName, expr): self._getActiveClassCompiler().addAttribute(attribName + ' =' + expr) if self._templateObj: # @@TR: this code should be delegated to the compiler val = eval(expr,{},{}) setattr(self._templateObj, attribName, val) def addComment(self, comm): if re.match(r'#+$',comm): # skip bar comments return specialVarMatch = specialVarRE.match(comm) if specialVarMatch: return self.addSpecialVar(specialVarMatch.group(1), comm[specialVarMatch.end():]) elif comm.startswith('doc:'): addLine = self.addMethDocString comm = comm[len('doc:'):].strip() elif comm.startswith('doc-method:'): addLine = self.addMethDocString comm = comm[len('doc-method:'):].strip() elif comm.startswith('doc-module:'): addLine = self.addModuleDocString comm = comm[len('doc-module:'):].strip() elif comm.startswith('doc-class:'): addLine = self.addClassDocString comm = comm[len('doc-class:'):].strip() elif comm.startswith('header:'): addLine = self.addModuleHeader comm = comm[len('header:'):].strip() else: addLine = self.addMethComment for line in comm.splitlines(): addLine(line) ## methods for module code wrapping def moduleDef(self): if not self._compiled: self.compile() if self._moduleDef: return self._moduleDef else: return self.wrapModuleDef() __str__ = moduleDef def wrapModuleDef(self): self.addModuleDocString('') self.addModuleDocString(self.setting('defDocStrMsg')) self.addModuleDocString(' CHEETAH VERSION: ' + Version) self.addSpecialVar('CHEETAH_version', Version) self.addModuleDocString(' Generation time: ' + self.timestamp()) self.addSpecialVar('CHEETAH_genTime', self.timestamp()) if self._filePath: self.addSpecialVar('CHEETAH_src', self._filePath) self.addModuleDocString(' Source file: ' + self._filePath) self.addModuleDocString(' Source file last modified: ' + self.timestamp(self._fileMtime)) moduleDef = """%(header)s %(docstring)s %(specialVars)s ################################################## ## DEPENDENCIES %(imports)s ################################################## ## MODULE CONSTANTS %(constants)s ################################################## ## CLASSES %(classes)s %(footer)s """ % {'header':self.moduleHeader(), 'docstring':self.moduleDocstring(), 'specialVars':self.specialVars(), 'imports':self.importStatements(), 'constants':self.moduleConstants(), 'classes':self.classDefs(), 'footer':self.moduleFooter(), } self._moduleDef = moduleDef return moduleDef def timestamp(self, theTime=None): if not theTime: theTime = time.time() return time.asctime(time.localtime(theTime)) def moduleHeader(self): header = self._moduleShBang + '\n' header += self._moduleEncoding + '\n' if self._moduleHeaderLines: offSet = self.setting('commentOffset') header += ( '#' + ' '*offSet + ('\n#'+ ' '*offSet).join(self._moduleHeaderLines) + '\n' ) return header def moduleDocstring(self): docStr = ('"""' + '\n'.join(self._moduleDocStringLines) + '\n"""\n' ) return docStr def specialVars(self): chunks = [] theVars = self._specialVars keys = theVars.keys() keys.sort() for key in keys: chunks.append(key + ' = ' + repr(theVars[key]) ) return '\n'.join(chunks) def importStatements(self): return '\n'.join(self._importStatements) def moduleConstants(self): return '\n'.join(self._moduleConstants) def classDefs(self): classDefs = [str(klass) for klass in self._finishedClasses() ] return '\n\n'.join(classDefs) def moduleFooter(self): return """ # CHEETAH was developed by Tavis Rudd, Mike Orr, Ian Bicking and Chuck Esterbrook; # 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__': %(className)s().runAsMainProgram() """ % {'className':self._mainClassName} ################################################## ## Make Compiler an alias for ModuleCompiler Compiler = ModuleCompiler PKt95wŸCheetah/Compiler.pyc; :Cc@s~dZdZddd!ZdkZdkZdkZdklZlZdkZdk Z dk Z dk Z dk Z dk lZdklZd klZlZlZlZlZd klZd klZd klZd efdYZdfdYZdefdYZdefdYZ defdYZ!de!fdYZ"deefdYZ#e#Z$dS(sCompiler classes for Cheetah: ModuleCompiler aka 'Compiler' ClassCompiler MethodCompiler If you are trying to grok this code start with ModuleCompiler.__init__, ModuleCompiler.compile, and ModuleCompiler.__getattr__. Meta-Data ================================================================================ Author: Tavis Rudd Version: $Revision: 1.77 $ Start Date: 2001/09/19 Last Revision Date: $Date: 2005/11/27 03:37:22 $ s!Tavis Rudd s$Revision: 1.77 $i iN(sgetmtimesexists(sVersion(sSettingsManager(sParsers ParseErrors specialVarREs STATIC_CACHEs REFRESH_CACHE(s indentize(s ErrorCatchers(s NameMappersErrorcBstZRS(N(s__name__s __module__(((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pysError&ssGenUtilscBsPtZdZdZdZdZedZdZdZ dZ RS(sAn abstract baseclass for the Compiler classes that provides methods that perform generic utility functions or generate pieces of output code from information passed in by the Parser baseclass. These methods don't do any parsing themselves.cCs|ddjot|d }n|ddjot|d d}n|ddjot|d dd}nw|ddjo t|d ddd}nF|ddjo$t|d dddd }nt|d}|SdS( Nisssmi<shsdiswi(s timeStringsfloatsinterval(sselfs timeStringsinterval((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pysgenTimeInterval1s $cCsx|iii|}|i}h}|do%t|d<|i |d|d then else selseN(sselfsaddIndentingDirectives conditionExprsaddFilteredChunkstrueExprsdedents falseExpr(sselfs conditionExprstrueExprs falseExpr((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pys addOneLineIfs     cCs&tidd|}|i|dS(Nselse[ \f\t]+ifselif(sressubsexprsselfsaddReIndentingDirective(sselfsexpr((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pysaddElsescCs|id|ddS(Nsif not (s)(sselfsaddIfsexpr(sselfsexpr((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pys addUnlessscCs|i|dS(N(sselfsaddIndentingDirectivesexpr(sselfsexpr((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pysaddTryscCs|i|dS(N(sselfsaddReIndentingDirectivesexpr(sselfsexpr((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pys addExceptscCs|i|dS(N(sselfsaddReIndentingDirectivesexpr(sselfsexpr((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pys addFinallyscCs|i|dS(N(sselfsaddChunksexpr(sselfsexpr((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pys addReturnscCs|it}|ddjo2|d}|o|id|dndSnf|idjo|idSnA|ddjot}|d }n|dd jo t}nx!|i D]}|i |qW|o|i ndS( Nis=isfilter(s)sendis$s:( sselfscommitStrConstsFalses autoIndentsPSPs addWriteChunkslowersdedentsTrues splitlinesslinesaddChunksindent(sselfsPSPs autoIndentsline((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pysaddPSPs(     cCs0ttiddttiddSdS(Nidii'i(sstrsrandoms randrange(sself((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pys nextCacheIDscCs |i}|idt}|idt}|idt}|ot |}n|id|}t |_ |i dt|d|i d|i d|d |i d |i|i d |i d |d |i d|i|i d|d |ol|idt|d|i dd|i|i dt|d |i d|in|o:|i d|d|i|i d|in|i d|i|i d|i d|i ddS(NsintervalstestsidsvaryBys$## START CACHE REGION: at line, col s in the source.sRECACHE = Falses region = self._cacheRegions.get(s)sif not region:sregion = CacheRegion()sself._cacheRegions[s ] = regionsRECACHE = Truescache = region.getCache(s#This cache will be refreshed every s seconds.sif (not cache.getRefreshTime())s- or (currentTime() > cache.getRefreshTime()):s$cache.setRefreshTime(currentTime() +sif s:s"if RECACHE or not cache.getData():sorig_trans = transs+trans = cacheCollector = DummyTransaction()s'write = cacheCollector.response().write(sselfs nextCacheIDsIDs cacheInfosgetsNonesintervalstestscustomIDsreprsvaryBysTrues_cacheRegionOpensaddChunksstrslineColsindentsdedentsaddMethDocString(sselfs cacheInfoslineColsintervalsvaryBystestscustomIDsID((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pysstartCacheRegionsF                cCsrt|_|id|id|id|id|i|id|id|iddS(Nstrans = orig_transswrite = trans.response().writes3cache.setData(cacheCollector.response().getvalue())sdel cacheCollectorscache.getData()s## END CACHE REGIONs(sFalsesselfs_cacheRegionOpensaddChunksdedents addWriteChunk(sself((s5build/bdist.darwin-8.7.1-i386/egg/Cheetah/Compiler.pysendCacheRegionEs        cCs|io"tt||i|i_n|id|d|i|id|d|i|id|i|id|d|d|idS(Ns if self._errorCatchers.has_key("s"):s*self._errorCatcher = self._errorCatchers["s"]selse:s"] = ErrorCatchers.s(self)( sselfs _templateObjsgetattrs ErrorCatchersserrorCatcherNames _errorCatchersaddChunksindentsdedent(sselfserrorCatcherName((s5bu