diff options
author | Michael DeHaan <mdehaan@redhat.com> | 2007-02-19 15:40:20 -0500 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2007-02-19 15:40:20 -0500 |
commit | 2bb24f6178d3d930f10906a0e80c7d5f272668f0 (patch) | |
tree | e3049895ae7d104d3c7870787bb77056f8bdc1c8 | |
parent | 4a2197efaa111af43ebfcc4455112a2ce2a89ea7 (diff) | |
download | third_party-cobbler-2bb24f6178d3d930f10906a0e80c7d5f272668f0.tar.gz third_party-cobbler-2bb24f6178d3d930f10906a0e80c7d5f272668f0.tar.xz third_party-cobbler-2bb24f6178d3d930f10906a0e80c7d5f272668f0.zip |
Removing Cheetah, RHEL4/Centos users can find an RPM, so that's fair.
53 files changed, 0 insertions, 18000 deletions
diff --git a/cobbler/Cheetah/CacheRegion.py b/cobbler/Cheetah/CacheRegion.py deleted file mode 100644 index 16de188..0000000 --- a/cobbler/Cheetah/CacheRegion.py +++ /dev/null @@ -1,138 +0,0 @@ -# $Id: CacheRegion.py,v 1.3 2006/01/28 04:19:30 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 dictionary (keyed by cacheRegionID) -handling at least one cache item (the default one). It's possible to add -cacheItems in a region by using the `varyBy` #cache directive parameter as -in the following example:: - #def getArticle - this is the article content. - #end def - - #cache varyBy=$getArticleID() - $getArticle($getArticleID()) - #end cache - -The code above will generate a CacheRegion and add new cacheItem for each value -of $getArticleID(). - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> and Philippe Normand <phil@base-art.net> -Version: $Revision: 1.3 $ -Start Date: 2005/06/20 -Last Revision Date: $Date: 2006/01/28 04:19:30 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com> and Philippe Normand <phil@base-art.net>" -__revision__ = "$Revision: 1.3 $"[11:-2] - -import md5 -from time import time as currentTime -from Cheetah.CacheStore import MemoryCacheStore - -class CacheItem: - """A CacheItem 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, cacheItemID, cacheStore): - self._cacheItemID = cacheItemID - self._cacheStore = cacheStore - self._refreshTime = None - self._expiryTime = 0 - - def hasExpired(self): - return (self._expiryTime and currentTime() > self._expiryTime) - - def setExpiryTime(self, time): - self._expiryTime = time - - def getExpiryTime(self): - return self._expiryTime - - def setData(self, data): - self._refreshTime = currentTime() - self._cacheStore.set(self._cacheItemID, data, self._expiryTime) - - def getRefreshTime(self): - return self._refreshTime - - def getData(self): - assert self._refreshTime - return self._cacheStore.get(self._cacheItemID) - - def renderOutput(self): - """Can be overridden to implement edge-caching""" - return self.getData() or "" - - def clear(self): - self._cacheStore.delete(self._cacheItemID) - self._refreshTime = None - -class _CacheDataStoreWrapper: - def __init__(self, dataStore, keyPrefix): - self._dataStore = dataStore - self._keyPrefix = keyPrefix - - def get(self, key): - return self._dataStore.get(self._keyPrefix+key) - - def delete(self, key): - self._dataStore.delete(self._keyPrefix+key) - - def set(self, key, val, time=0): - self._dataStore.set(self._keyPrefix+key, val, time=time) - -class CacheRegion: - """ A `CacheRegion` stores some `CacheItem` instances. - - This implementation stores the data in the memory of the current process. - If you need a more advanced data store, create a cacheStore class that works - with Cheetah's CacheStore protocol and provide it as the cacheStore argument - to __init__. For example you could use - Cheetah.CacheStore.MemcachedCacheStore, a wrapper around the Python - memcached API (http://www.danga.com/memcached). - """ - _cacheItemClass = CacheItem - - def __init__(self, regionID, templateCacheIdPrefix='', cacheStore=None): - self._isNew = True - self._regionID = regionID - self._templateCacheIdPrefix = templateCacheIdPrefix - if not cacheStore: - cacheStore = MemoryCacheStore() - self._cacheStore = cacheStore - self._wrappedCacheDataStore = _CacheDataStoreWrapper( - cacheStore, keyPrefix=templateCacheIdPrefix+':'+regionID+':') - self._cacheItems = {} - - def isNew(self): - return self._isNew - - def clear(self): - " drop all the caches stored in this cache region " - for cacheItemId in self._cacheItems.keys(): - cacheItem = self._cacheItems[cacheItemId] - cacheItem.clear() - del self._cacheItems[cacheItemId] - - def getCacheItem(self, cacheItemID): - """ Lazy access to a cacheItem - - Try to find a cache in the stored caches. If it doesn't - exist, it's created. - - Returns a `CacheItem` instance. - """ - cacheItemID = md5.new(str(cacheItemID)).hexdigest() - - if not self._cacheItems.has_key(cacheItemID): - cacheItem = self._cacheItemClass( - cacheItemID=cacheItemID, cacheStore=self._wrappedCacheDataStore) - self._cacheItems[cacheItemID] = cacheItem - self._isNew = False - return self._cacheItems[cacheItemID] diff --git a/cobbler/Cheetah/CacheStore.py b/cobbler/Cheetah/CacheStore.py deleted file mode 100644 index f1a1840..0000000 --- a/cobbler/Cheetah/CacheStore.py +++ /dev/null @@ -1,108 +0,0 @@ -"""Provides several CacheStore backends for Cheetah's caching framework. The -methods provided by these classes have the same semantics as those in the -python-memcached API, except for their return values: - -set(key, val, time=0) - set the value unconditionally -add(key, val, time=0) - set only if the server doesn't already have this key -replace(key, val, time=0) - set only if the server already have this key -get(key, val) - returns val or raises a KeyError -delete(key) - deletes or raises a KeyError - -""" -from time import time as currentTime - -from Cheetah.Utils.memcache import Client as MemcachedClient - -class Error(Exception): - pass - -class AbstractCacheStore(object): - - def set(self, key, val, time=None): - raise NotImplementedError - - def add(self, key, val, time=None): - raise NotImplementedError - - def replace(self, key, val, time=None): - raise NotImplementedError - - def delete(self, key): - raise NotImplementedError - - def get(self, key): - raise NotImplementedError - -class MemoryCacheStore(AbstractCacheStore): - def __init__(self): - self._data = {} - - def set(self, key, val, time=0): - self._data[key] = (val, time) - - def add(self, key, val, time=0): - if self._data.has_key(key): - raise Error('a value for key %r is already in the cache'%key) - self._data[key] = (val, time) - - def replace(self, key, val, time=0): - if self._data.has_key(key): - raise Error('a value for key %r is already in the cache'%key) - self._data[key] = (val, time) - - def delete(self, key): - del self._data[key] - - def get(self, key): - (val, exptime) = self._data[key] - if exptime and currentTime() > exptime: - del self._data[key] - raise KeyError(key) - else: - return val - - def clear(self): - self._data.clear() - -class MemcachedCacheStore(AbstractCacheStore): - servers = ('127.0.0.1:11211') - def __init__(self, servers=None, debug=False): - if servers is None: - servers = self.servers - - self._client = MemcachedClient(servers, debug) - - def set(self, key, val, time=0): - self._client.set(key, val, time) - - def add(self, key, val, time=0): - res = self._client.add(key, val, time) - if not res: - raise Error('a value for key %r is already in the cache'%key) - self._data[key] = (val, time) - - def replace(self, key, val, time=0): - res = self._client.replace(key, val, time) - if not res: - raise Error('a value for key %r is already in the cache'%key) - self._data[key] = (val, time) - - def delete(self, key): - res = self._client.delete(key, time=0) - if not res: - raise KeyError(key) - - def get(self, key): - val = self._client.get(key) - if val is None: - raise KeyError(key) - else: - return val - - def clear(self): - self._client.flush_all() diff --git a/cobbler/Cheetah/CheetahWrapper.py b/cobbler/Cheetah/CheetahWrapper.py deleted file mode 100644 index 68a8598..0000000 --- a/cobbler/Cheetah/CheetahWrapper.py +++ /dev/null @@ -1,589 +0,0 @@ -#!/usr/bin/env python -# $Id: CheetahWrapper.py,v 1.25 2006/02/04 00:59:46 tavis_rudd Exp $ -"""Cheetah 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 <tavis@damnsimple.com> and Mike Orr <iron@mso.oz.net> -Version: $Revision: 1.25 $ -Start Date: 2001/03/30 -Last Revision Date: $Date: 2006/02/04 00:59:46 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com> and Mike Orr <iron@mso.oz.net>" -__revision__ = "$Revision: 1.25 $"[11:-2] - -import getopt, glob, os, pprint, re, shutil, sys -import cPickle as pickle - -from Cheetah.Version import Version -from Cheetah.Template import Template, DEFAULT_COMPILER_SETTINGS -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 "<Bundle %r>" % 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 <tavis@damnsimple.com> - \__________/ and Mike Orr <iron@mso.oz.net> - -""" % 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) - --settings : a string representing the compiler settings to use - e.g. --settings='useNameMapper=False,useFilters=False' - This string is eval'd in Python so it should contain - valid Python syntax. - --templateAPIClass : a string representing a subclass of - Cheetah.Template:Template to use for compilation - -Run "cheetah help" for the main help screen. -""" - -################################################## -## CheetahWrapper CLASS - -class CheetahWrapper: - MAKE_BACKUPS = True - BACKUP_SUFFIX = ".bak" - _templateClass = None - _compilerSettings = None - - def __init__(self): - self.progName = None - self.command = None - self.opts = None - self.pathArgs = None - self.sourceFiles = [] - self.searchList = [] - - ################################################## - ## 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) - - 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) - pao("--settings", action="store", dest="compilerSettingsString", default=None) - pao("--templateAPIClass", action="store", dest="templateClassName", default=None) - - self.opts, self.pathArgs = opts, files = parser.parse_args(args) - D("""\ -cheetah compile %s -Options are -%s -Files are %s""", args, pprint.pformat(vars(opts)), files) - - - #cleanup trailing path separators - seps = [sep for sep in [os.sep, os.altsep] if sep] - for attr in ['idir', 'odir']: - for sep in seps: - path = getattr(opts, attr, None) - if path and path.endswith(sep): - path = path[:-len(sep)] - setattr(opts, attr, path) - break - - self._fixExts() - if opts.env: - self.searchList.insert(0, os.environ) - if opts.pickle: - f = open(opts.pickle, 'rb') - unpickled = pickle.load(f) - f.close() - self.searchList.insert(0, unpickled) - opts.verbose = not opts.stdout - - ################################################## - ## COMMAND METHODS - - def compile(self): - self._compileOrFill() - - def fill(self): - from Cheetah.ImportHooks import install - install() - 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(). - - ################################################## - ## LOGGING 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) - - def error(self, format, *args): - """Always print a warning message to stderr and exit with an error code. - """ - fprintfMessage(sys.stderr, format, *args) - sys.exit(1) - - ################################################## - ## 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 _compileOrFill(self): - C, D, W = self.chatter, self.debug, self.warn - opts, files = self.opts, self.pathArgs - 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) - - 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 _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 f in files: - path = os.path.join(dir, f) - 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 - files = [] - for f in self.pathArgs: - oldFilesLen = len(files) - D("Expanding %s", f) - path = os.path.join(idir, f) - pathWithExt = path + iext # May or may not be valid. - if os.path.isdir(path): - if recurse: - os.path.walk(path, self._expandSourceFilesWalk, files) - else: - raise Error("source file '%s' is a directory" % path) - elif os.path.isfile(path): - files.append(path) - elif (addIextIfMissing and not path.endswith(iext) and - os.path.isfile(pathWithExt)): - files.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(files) > oldFilesLen: - D(" ... found %s", files[oldFilesLen:]) - return files - - - 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 != '': - idx = base.find(odd) - if idx == 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 _getTemplateClass(self): - C, D, W = self.chatter, self.debug, self.warn - modname = None - if self._templateClass: - return self._templateClass - - modname = self.opts.templateClassName - - if not modname: - return Template - p = modname.rfind('.') - if ':' not in modname: - self.error('The value of option --templateAPIClass is invalid\n' - 'It must be in the form "module:class", ' - 'e.g. "Cheetah.Template:Template"') - - modname, classname = modname.split(':') - - C('using --templateAPIClass=%s:%s'%(modname, classname)) - - if p >= 0: - mod = getattr(__import__(modname[:p], {}, {}, [modname[p+1:]]), modname[p+1:]) - else: - mod = __import__(modname, {}, {}, []) - - klass = getattr(mod, classname, None) - if klass: - self._templateClass = klass - return klass - else: - self.error('**Template class specified in option --templateAPIClass not found\n' - '**Falling back on Cheetah.Template:Template') - - - def _getCompilerSettings(self): - if self._compilerSettings: - return self._compilerSettings - - def getkws(**kws): - return kws - if self.opts.compilerSettingsString: - try: - exec 'settings = getkws(%s)'%self.opts.compilerSettingsString - except: - self.error("There's an error in your --settings option." - "It must be valid Python syntax.\n" - +" --settings='%s'\n"%self.opts.compilerSettingsString - +" %s: %s"%sys.exc_info()[:2] - ) - - validKeys = DEFAULT_COMPILER_SETTINGS.keys() - if [k for k in settings.keys() if k not in validKeys]: - self.error( - 'The --setting "%s" is not a valid compiler setting name.'%k) - - self._compilerSettings = settings - return settings - else: - return {} - - def _compileOrFillStdin(self): - TemplateClass = self._getTemplateClass() - compilerSettings = self._getCompilerSettings() - if self.isCompile: - pysrc = TemplateClass.compile(file=sys.stdin, - compilerSettings=compilerSettings, - returnAClass=False) - output = pysrc - else: - output = str(TemplateClass(file=sys.stdin, compilerSettings=compilerSettings)) - sys.stdout.write(output) - - def _compileOrFillBundle(self, b): - C, D, W = self.chatter, self.debug, self.warn - TemplateClass = self._getTemplateClass() - compilerSettings = self._getCompilerSettings() - 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) - pysrc = TemplateClass.compile(file=src, returnAClass=False, - moduleName=basename, - className=basename, - compilerSettings=compilerSettings) - output = pysrc - else: - #output = str(TemplateClass(file=src, searchList=self.searchList)) - tclass = TemplateClass.compile(file=src, compilerSettings=compilerSettings) - output = str(tclass(searchList=self.searchList)) - - 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() - - -################################################## -## if run from the command line -if __name__ == '__main__': CheetahWrapper().main() - -# vim: shiftwidth=4 tabstop=4 expandtab diff --git a/cobbler/Cheetah/DummyTransaction.py b/cobbler/Cheetah/DummyTransaction.py deleted file mode 100644 index 8ebe33d..0000000 --- a/cobbler/Cheetah/DummyTransaction.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# $Id: DummyTransaction.py,v 1.13 2005/11/13 01:12:13 tavis_rudd Exp $ - -"""Provides dummy Transaction and Response classes is used by Cheetah in place -of real Webware transactions when the Template obj is not used directly as a -Webware servlet. - -Meta-Data -========== -Author: Tavis Rudd <tavis@damnsimple.com> -Version: $Revision: 1.13 $ -Start Date: 2001/08/30 -Last Revision Date: $Date: 2005/11/13 01:12:13 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.13 $"[11:-2] - -def flush(): - pass - -class DummyResponse: - - """A dummy Response class is used by Cheetah in place of real Webware - Response objects when the Template obj is not used directly as a Webware - servlet. """ - - - def __init__(self): - self._outputChunks = outputChunks = [] - self.write = write = outputChunks.append - def getvalue(outputChunks=outputChunks): - return ''.join(outputChunks) - self.getvalue = getvalue - - def writeln(txt): - write(txt) - write('\n') - self.writeln = writeln - self.flush = flush - - def writelines(self, *lines): - ## not used - [self.writeln(ln) for ln in lines] - -class DummyTransaction: - - """A dummy Transaction class is used by Cheetah in place of real Webware - transactions when the Template obj is not used directly as a Webware - servlet. - - It only provides a response object and method. All other methods and - attributes make no sense in this context. - """ - - def __init__(self, DummyResponse=DummyResponse): - def response(resp=DummyResponse()): - return resp - self.response = response diff --git a/cobbler/Cheetah/ErrorCatchers.py b/cobbler/Cheetah/ErrorCatchers.py deleted file mode 100644 index d33b979..0000000 --- a/cobbler/Cheetah/ErrorCatchers.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -# $Id: ErrorCatchers.py,v 1.7 2005/01/03 19:59:07 tavis_rudd Exp $ -"""ErrorCatcher class for Cheetah Templates - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -Version: $Revision: 1.7 $ -Start Date: 2001/08/01 -Last Revision Date: $Date: 2005/01/03 19:59:07 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.7 $"[11:-2] - -import time -from Cheetah.NameMapper import NotFound - -class Error(Exception): - pass - -class ErrorCatcher: - _exceptionsToCatch = (NotFound,) - - def __init__(self, templateObj): - pass - - def exceptions(self): - return self._exceptionsToCatch - - def warn(self, exc_val, code, rawCode, lineCol): - return rawCode -## make an alias -Echo = ErrorCatcher - -class BigEcho(ErrorCatcher): - def warn(self, exc_val, code, rawCode, lineCol): - return "="*15 + "<" + rawCode + " could not be found>" + "="*15 - -class KeyError(ErrorCatcher): - def warn(self, exc_val, code, rawCode, lineCol): - raise KeyError("no '%s' in this Template Object's Search List" % rawCode) - -class ListErrors(ErrorCatcher): - """Accumulate a list of errors.""" - _timeFormat = "%c" - - def __init__(self, templateObj): - ErrorCatcher.__init__(self, templateObj) - self._errors = [] - - def warn(self, exc_val, code, rawCode, lineCol): - dict = locals().copy() - del dict['self'] - dict['time'] = time.strftime(self._timeFormat, - time.localtime(time.time())) - self._errors.append(dict) - return rawCode - - def listErrors(self): - """Return the list of errors.""" - return self._errors - - diff --git a/cobbler/Cheetah/FileUtils.py b/cobbler/Cheetah/FileUtils.py deleted file mode 100644 index c3749f5..0000000 --- a/cobbler/Cheetah/FileUtils.py +++ /dev/null @@ -1,374 +0,0 @@ -#!/usr/bin/env python -# $Id: FileUtils.py,v 1.12 2005/11/02 22:26:07 tavis_rudd Exp $ -"""File utitilies for Python: - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -License: This software is released for unlimited distribution under the - terms of the MIT license. See the LICENSE file. -Version: $Revision: 1.12 $ -Start Date: 2001/09/26 -Last Revision Date: $Date: 2005/11/02 22:26:07 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.12 $"[11:-2] - - -from glob import glob -import os -from os import listdir -import os.path -import re -from types import StringType -from tempfile import mktemp - -def _escapeRegexChars(txt, - escapeRE=re.compile(r'([\$\^\*\+\.\?\{\}\[\]\(\)\|\\])')): - return escapeRE.sub(r'\\\1' , txt) - -def findFiles(*args, **kw): - """Recursively find all the files matching a glob pattern. - - This function is a wrapper around the FileFinder class. See its docstring - for details about the accepted arguments, etc.""" - - return FileFinder(*args, **kw).files() - -def replaceStrInFiles(files, theStr, repl): - - """Replace all instances of 'theStr' with 'repl' for each file in the 'files' - list. Returns a dictionary with data about the matches found. - - This is like string.replace() on a multi-file basis. - - This function is a wrapper around the FindAndReplace class. See its - docstring for more details.""" - - pattern = _escapeRegexChars(theStr) - return FindAndReplace(files, pattern, repl).results() - -def replaceRegexInFiles(files, pattern, repl): - - """Replace all instances of regex 'pattern' with 'repl' for each file in the - 'files' list. Returns a dictionary with data about the matches found. - - This is like re.sub on a multi-file basis. - - This function is a wrapper around the FindAndReplace class. See its - docstring for more details.""" - - return FindAndReplace(files, pattern, repl).results() - - -################################################## -## CLASSES - -class FileFinder: - - """Traverses a directory tree and finds all files in it that match one of - the specified glob patterns.""" - - def __init__(self, rootPath, - globPatterns=('*',), - ignoreBasenames=('CVS','.svn'), - ignoreDirs=(), - ): - - self._rootPath = rootPath - self._globPatterns = globPatterns - self._ignoreBasenames = ignoreBasenames - self._ignoreDirs = ignoreDirs - self._files = [] - - self.walkDirTree(rootPath) - - def walkDirTree(self, dir='.', - - listdir=os.listdir, - isdir=os.path.isdir, - join=os.path.join, - ): - - """Recursively walk through a directory tree and find matching files.""" - processDir = self.processDir - filterDir = self.filterDir - - pendingDirs = [dir] - addDir = pendingDirs.append - getDir = pendingDirs.pop - - while pendingDirs: - dir = getDir() - ## process this dir - processDir(dir) - - ## and add sub-dirs - for baseName in listdir(dir): - fullPath = join(dir, baseName) - if isdir(fullPath): - if filterDir(baseName, fullPath): - addDir( fullPath ) - - def filterDir(self, baseName, fullPath): - - """A hook for filtering out certain dirs. """ - - return not (baseName in self._ignoreBasenames or - fullPath in self._ignoreDirs) - - def processDir(self, dir, glob=glob): - extend = self._files.extend - for pattern in self._globPatterns: - extend( glob(os.path.join(dir, pattern)) ) - - def files(self): - return self._files - -class _GenSubberFunc: - - """Converts a 'sub' string in the form that one feeds to re.sub (backrefs, - groups, etc.) into a function that can be used to do the substitutions in - the FindAndReplace class.""" - - backrefRE = re.compile(r'\\([1-9][0-9]*)') - groupRE = re.compile(r'\\g<([a-zA-Z_][a-zA-Z_]*)>') - - def __init__(self, replaceStr): - self._src = replaceStr - self._pos = 0 - self._codeChunks = [] - self.parse() - - def src(self): - return self._src - - def pos(self): - return self._pos - - def setPos(self, pos): - self._pos = pos - - def atEnd(self): - return self._pos >= len(self._src) - - def advance(self, offset=1): - self._pos += offset - - def readTo(self, to, start=None): - if start == None: - start = self._pos - self._pos = to - if self.atEnd(): - return self._src[start:] - else: - return self._src[start:to] - - ## match and get methods - - def matchBackref(self): - return self.backrefRE.match(self.src(), self.pos()) - - def getBackref(self): - m = self.matchBackref() - self.setPos(m.end()) - return m.group(1) - - def matchGroup(self): - return self.groupRE.match(self.src(), self.pos()) - - def getGroup(self): - m = self.matchGroup() - self.setPos(m.end()) - return m.group(1) - - ## main parse loop and the eat methods - - def parse(self): - while not self.atEnd(): - if self.matchBackref(): - self.eatBackref() - elif self.matchGroup(): - self.eatGroup() - else: - self.eatStrConst() - - def eatStrConst(self): - startPos = self.pos() - while not self.atEnd(): - if self.matchBackref() or self.matchGroup(): - break - else: - self.advance() - strConst = self.readTo(self.pos(), start=startPos) - self.addChunk(repr(strConst)) - - def eatBackref(self): - self.addChunk( 'm.group(' + self.getBackref() + ')' ) - - def eatGroup(self): - self.addChunk( 'm.group("' + self.getGroup() + '")' ) - - def addChunk(self, chunk): - self._codeChunks.append(chunk) - - ## code wrapping methods - - def codeBody(self): - return ', '.join(self._codeChunks) - - def code(self): - return "def subber(m):\n\treturn ''.join([%s])\n" % (self.codeBody()) - - def subberFunc(self): - exec self.code() - return subber - - -class FindAndReplace: - - """Find and replace all instances of 'patternOrRE' with 'replacement' for - each file in the 'files' list. This is a multi-file version of re.sub(). - - 'patternOrRE' can be a raw regex pattern or - a regex object as generated by the re module. 'replacement' can be any - string that would work with patternOrRE.sub(replacement, fileContents). - """ - - def __init__(self, files, patternOrRE, replacement, - recordResults=True): - - - if type(patternOrRE) == StringType: - self._regex = re.compile(patternOrRE) - else: - self._regex = patternOrRE - if type(replacement) == StringType: - self._subber = _GenSubberFunc(replacement).subberFunc() - else: - self._subber = replacement - - self._pattern = pattern = self._regex.pattern - self._files = files - self._results = {} - self._recordResults = recordResults - - ## see if we should use pgrep to do the file matching - self._usePgrep = False - if (os.popen3('pgrep')[2].read()).startswith('Usage:'): - ## now check to make sure pgrep understands the pattern - tmpFile = mktemp() - open(tmpFile, 'w').write('#') - if not (os.popen3('pgrep "' + pattern + '" ' + tmpFile)[2].read()): - # it didn't print an error msg so we're ok - self._usePgrep = True - os.remove(tmpFile) - - self._run() - - def results(self): - return self._results - - def _run(self): - regex = self._regex - subber = self._subDispatcher - usePgrep = self._usePgrep - pattern = self._pattern - for file in self._files: - if not os.path.isfile(file): - continue # skip dirs etc. - - self._currFile = file - found = False - if locals().has_key('orig'): - del orig - if self._usePgrep: - if os.popen('pgrep "' + pattern + '" ' + file ).read(): - found = True - else: - orig = open(file).read() - if regex.search(orig): - found = True - if found: - if not locals().has_key('orig'): - orig = open(file).read() - new = regex.sub(subber, orig) - open(file, 'w').write(new) - - def _subDispatcher(self, match): - if self._recordResults: - if not self._results.has_key(self._currFile): - res = self._results[self._currFile] = {} - res['count'] = 0 - res['matches'] = [] - else: - res = self._results[self._currFile] - res['count'] += 1 - res['matches'].append({'contents':match.group(), - 'start':match.start(), - 'end':match.end(), - } - ) - return self._subber(match) - - -class SourceFileStats: - - """ - """ - - _fileStats = None - - def __init__(self, files): - self._fileStats = stats = {} - for file in files: - stats[file] = self.getFileStats(file) - - def rawStats(self): - return self._fileStats - - def summary(self): - codeLines = 0 - blankLines = 0 - commentLines = 0 - totalLines = 0 - for fileStats in self.rawStats().values(): - codeLines += fileStats['codeLines'] - blankLines += fileStats['blankLines'] - commentLines += fileStats['commentLines'] - totalLines += fileStats['totalLines'] - - stats = {'codeLines':codeLines, - 'blankLines':blankLines, - 'commentLines':commentLines, - 'totalLines':totalLines, - } - return stats - - def printStats(self): - pass - - def getFileStats(self, fileName): - codeLines = 0 - blankLines = 0 - commentLines = 0 - commentLineRe = re.compile(r'\s#.*$') - blankLineRe = re.compile('\s$') - lines = open(fileName).read().splitlines() - totalLines = len(lines) - - for line in lines: - if commentLineRe.match(line): - commentLines += 1 - elif blankLineRe.match(line): - blankLines += 1 - else: - codeLines += 1 - - stats = {'codeLines':codeLines, - 'blankLines':blankLines, - 'commentLines':commentLines, - 'totalLines':totalLines, - } - - return stats diff --git a/cobbler/Cheetah/Filters.py b/cobbler/Cheetah/Filters.py deleted file mode 100644 index 2bf4784..0000000 --- a/cobbler/Cheetah/Filters.py +++ /dev/null @@ -1,290 +0,0 @@ -#!/usr/bin/env python -# $Id: Filters.py,v 1.28 2006/06/16 20:15:24 hierro Exp $ -"""Filters for the #filter directive; output filters Cheetah's $placeholders . - -Filters may now be used standalone, for debugging or for use outside Cheetah. -Class DummyTemplate, instance _dummyTemplateObj and class NoDefault exist only -for this, to provide a default argument for the filter constructors (which -would otherwise require a real template object). - -The default filter is now RawOrEncodedUnicode. Please use this as a base class instead of Filter because it handles non-ASCII characters better. - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -Version: $Revision: 1.28 $ -Start Date: 2001/08/01 -Last Revision Date: $Date: 2006/06/16 20:15:24 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.28 $"[11:-2] - -from StringIO import StringIO # not cStringIO because of unicode support - -# Additional entities WebSafe knows how to transform. No need to include -# '<', '>' or '&' since those will have been done already. -webSafeEntities = {' ': ' ', '"': '"'} - -class Error(Exception): - pass - -class NoDefault: - pass - - -class DummyTemplate: - """Fake template class to allow filters to be used standalone. - - This is provides only the level of Template compatibility required by the - standard filters. Namely, the get-settings interface works but there are - no settings. Other aspects of Template are not implemented. - """ - def setting(self, name, default=NoDefault): - if default is NoDefault: - raise KeyError(name) - else: - return default - - def settings(self): - return {} - -_dummyTemplateObj = DummyTemplate() - - -################################################## -## BASE CLASS - -class Filter(object): - """A baseclass for the Cheetah Filters.""" - - def __init__(self, templateObj=_dummyTemplateObj): - """Setup a ref to the templateObj. Subclasses should call this method. - """ - if hasattr(templateObj, 'setting'): - self.setting = templateObj.setting - else: - self.setting = lambda k: None - - if hasattr(templateObj, 'settings'): - self.settings = templateObj.settings - else: - self.settings = lambda: {} - - def generateAutoArgs(self): - - """This hook allows the filters to generate an arg-list that will be - appended to the arg-list of a $placeholder tag when it is being - translated into Python code during the template compilation process. See - the 'Pager' filter class for an example.""" - - return '' - - def filter(self, val, **kw): - - """Reimplement this method if you want more advanced filterting.""" - - return str(val) - - -################################################## -## ENHANCED FILTERS - -##### -class ReplaceNone(Filter): - def filter(self, val, **kw): - - """Replace None with an empty string. Reimplement this method if you - want more advanced filterting.""" - - if val is None: - return '' - return str(val) -##### -class EncodeUnicode(Filter): - def filter(self, val, - encoding='utf8', - str=str, type=type, unicodeType=type(u''), - **kw): - """Encode Unicode strings, by default in UTF-8. - - >>> import Cheetah.Template - >>> t = Cheetah.Template.Template(''' - ... $myvar - ... ${myvar, encoding='utf16'} - ... ''', searchList=[{'myvar': u'Asni\xe8res'}], - ... filter='EncodeUnicode') - >>> print t - """ - if type(val)==unicodeType: - filtered = val.encode(encoding) - elif val is None: - filtered = '' - else: - filtered = str(val) - return filtered - -class RawOrEncodedUnicode(Filter): - def filter(self, val, - #encoding='utf8', - encoding=None, - str=str, type=type, unicodeType=type(u''), - **kw): - """Pass Unicode strings through unmolested, unless an encoding is specified. - """ - if type(val)==unicodeType: - if encoding: - filtered = val.encode(encoding) - else: - filtered = val - elif val is None: - filtered = '' - else: - filtered = str(val) - return filtered - -##### -class MaxLen(RawOrEncodedUnicode): - def filter(self, val, **kw): - """Replace None with '' and cut off at maxlen.""" - - output = super(MaxLen, self).filter(val, **kw) - if kw.has_key('maxlen') and len(output) > kw['maxlen']: - return output[:kw['maxlen']] - return output - - -##### -class Pager(RawOrEncodedUnicode): - def __init__(self, templateObj=_dummyTemplateObj): - Filter.__init__(self, templateObj) - self._IDcounter = 0 - - def buildQString(self,varsDict, updateDict): - finalDict = varsDict.copy() - finalDict.update(updateDict) - qString = '?' - for key, val in finalDict.items(): - qString += str(key) + '=' + str(val) + '&' - return qString - - def generateAutoArgs(self): - ID = str(self._IDcounter) - self._IDcounter += 1 - return ', trans=trans, ID=' + ID - - def filter(self, val, **kw): - """Replace None with '' and cut off at maxlen.""" - output = super(Pager, self).filter(val, **kw) - if kw.has_key('trans') and kw['trans']: - ID = kw['ID'] - marker = kw.get('marker', '<split>') - req = kw['trans'].request() - URI = req.environ()['SCRIPT_NAME'] + req.environ()['PATH_INFO'] - queryVar = 'pager' + str(ID) + '_page' - fields = req.fields() - page = int(fields.get( queryVar, 1)) - pages = output.split(marker) - output = pages[page-1] - output += '<BR>' - if page > 1: - output +='<A HREF="' + URI + self.buildQString(fields, {queryVar:max(page-1,1)}) + \ - '">Previous Page</A> ' - if page < len(pages): - output += '<A HREF="' + URI + self.buildQString( - fields, - {queryVar: - min(page+1,len(pages))}) + \ - '">Next Page</A>' - - return output - return output - - -##### -class WebSafe(RawOrEncodedUnicode): - """Escape HTML entities in $placeholders. - """ - def filter(self, val, **kw): - s = super(WebSafe, self).filter(val, **kw) - # These substitutions are copied from cgi.escape(). - s = s.replace("&", "&") # Must be done first! - s = s.replace("<", "<") - s = s.replace(">", ">") - # Process the additional transformations if any. - if kw.has_key('also'): - also = kw['also'] - entities = webSafeEntities # Global variable. - for k in also: - if entities.has_key(k): - v = entities[k] - else: - v = "&#%s;" % ord(k) - s = s.replace(k, v) - # Return the puppy. - return s - - -##### -class Strip(RawOrEncodedUnicode): - """Strip leading/trailing whitespace but preserve newlines. - - This filter goes through the value line by line, removing leading and - trailing whitespace on each line. It does not strip newlines, so every - input line corresponds to one output line, with its trailing newline intact. - - We do not use val.split('\n') because that would squeeze out consecutive - blank lines. Instead, we search for each newline individually. This - makes us unable to use the fast C .split method, but it makes the filter - much more widely useful. - - This filter is intended to be usable both with the #filter directive and - with the proposed #sed directive (which has not been ratified yet.) - """ - def filter(self, val, **kw): - s = super(Strip, self).filter(val, **kw) - result = [] - start = 0 # The current line will be s[start:end]. - while 1: # Loop through each line. - end = s.find('\n', start) # Find next newline. - if end == -1: # If no more newlines. - break - chunk = s[start:end].strip() - result.append(chunk) - result.append('\n') - start = end + 1 - # Write the unfinished portion after the last newline, if any. - chunk = s[start:].strip() - result.append(chunk) - return "".join(result) - -##### -class StripSqueeze(RawOrEncodedUnicode): - """Canonicalizes every chunk of whitespace to a single space. - - Strips leading/trailing whitespace. Removes all newlines, so multi-line - input is joined into one ling line with NO trailing newline. - """ - def filter(self, val, **kw): - s = super(StripSqueeze, self).filter(val, **kw) - s = s.split() - return " ".join(s) - -################################################## -## MAIN ROUTINE -- testing - -def test(): - s1 = "abc <=> &" - s2 = " asdf \n\t 1 2 3\n" - print "WebSafe INPUT:", `s1` - print " WebSafe:", `WebSafe().filter(s1)` - - print - print " Strip INPUT:", `s2` - print " Strip:", `Strip().filter(s2)` - print "StripSqueeze:", `StripSqueeze().filter(s2)` - - print "Unicode:", `EncodeUnicode().filter(u'aoeu12345\u1234')` - -if __name__ == "__main__": test() - -# vim: shiftwidth=4 tabstop=4 expandtab diff --git a/cobbler/Cheetah/ImportHooks.py b/cobbler/Cheetah/ImportHooks.py deleted file mode 100644 index 9d50119..0000000 --- a/cobbler/Cheetah/ImportHooks.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python -# $Id: ImportHooks.py,v 1.25 2006/06/20 19:23:27 tavis_rudd Exp $ - -"""Provides some import hooks to allow Cheetah's .tmpl files to be imported -directly like Python .py modules. - -To use these: - import Cheetah.ImportHooks - Cheetah.ImportHooks.install() - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -License: This software is released for unlimited distribution under the - terms of the MIT license. See the LICENSE file. -Version: $Revision: 1.25 $ -Start Date: 2001/03/30 -Last Revision Date: $Date: 2006/06/20 19:23:27 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.25 $"[11:-2] - -import sys -import os.path -import types -import __builtin__ -import new -import imp -from threading import Lock -import string -import traceback -from Cheetah import ImportManager -from Cheetah.ImportManager import DirOwner -from Cheetah.Compiler import Compiler -from Cheetah.convertTmplPathToModuleName import convertTmplPathToModuleName - -_installed = False - -################################################## -## HELPER FUNCS - -_cacheDir = [] -def setCacheDir(cacheDir): - global _cacheDir - _cacheDir.append(cacheDir) - -################################################## -## CLASSES - -class CheetahDirOwner(DirOwner): - _lock = Lock() - _acquireLock = _lock.acquire - _releaseLock = _lock.release - - templateFileExtensions = ('.tmpl',) - - def getmod(self, name): - try: - self._acquireLock() - mod = DirOwner.getmod(self, name) - if mod: - return mod - - for ext in self.templateFileExtensions: - tmplPath = os.path.join(self.path, name + ext) - if os.path.exists(tmplPath): - try: - return self._compile(name, tmplPath) - except: - # @@TR: log the error - exc_txt = traceback.format_exc() - exc_txt =' '+(' \n'.join(exc_txt.splitlines())) - raise ImportError( - 'Error while compiling Cheetah module' - ' %(name)s, original traceback follows:\n%(exc_txt)s'%locals()) - ## - return None - - finally: - self._releaseLock() - - def _compile(self, name, tmplPath): - ## @@ consider adding an ImportError raiser here - code = str(Compiler(file=tmplPath, moduleName=name, - mainClassName=name)) - if _cacheDir: - __file__ = os.path.join(_cacheDir[0], - convertTmplPathToModuleName(tmplPath)) + '.py' - try: - open(__file__, 'w').write(code) - except OSError: - ## @@ TR: need to add some error code here - traceback.print_exc(file=sys.stderr) - __file__ = tmplPath - else: - __file__ = tmplPath - co = compile(code+'\n', __file__, 'exec') - - mod = imp.new_module(name) - mod.__file__ = co.co_filename - if _cacheDir: - mod.__orig_file__ = tmplPath # @@TR: this is used in the WebKit - # filemonitoring code - mod.__co__ = co - return mod - - -################################################## -## FUNCTIONS - -def install(templateFileExtensions=('.tmpl',)): - """Install the Cheetah Import Hooks""" - - global _installed - if not _installed: - CheetahDirOwner.templateFileExtensions = templateFileExtensions - import __builtin__ - if type(__builtin__.__import__) == types.BuiltinFunctionType: - global __oldimport__ - __oldimport__ = __builtin__.__import__ - ImportManager._globalOwnerTypes.insert(0, CheetahDirOwner) - #ImportManager._globalOwnerTypes.append(CheetahDirOwner) - global _manager - _manager=ImportManager.ImportManager() - _manager.setThreaded() - _manager.install() - -def uninstall(): - """Uninstall the Cheetah Import Hooks""" - global _installed - if not _installed: - import __builtin__ - if type(__builtin__.__import__) == types.MethodType: - __builtin__.__import__ = __oldimport__ - global _manager - del _manager - -if __name__ == '__main__': - install() diff --git a/cobbler/Cheetah/ImportManager.py b/cobbler/Cheetah/ImportManager.py deleted file mode 100644 index 3ff1dbe..0000000 --- a/cobbler/Cheetah/ImportManager.py +++ /dev/null @@ -1,562 +0,0 @@ -#!/usr/bin/env python -# $Id: ImportManager.py,v 1.5 2006/01/27 19:00:20 tavis_rudd Exp $ - -"""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 - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> based on Gordon McMillan's iu.py -License: This software is released for unlimited distribution under the - terms of the MIT license. See the LICENSE file. -Version: $Revision: 1.5 $ -Start Date: 2001/03/30 -Last Revision Date: $Date: 2006/01/27 19:00:20 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.5 $"[11:-2] - -################################################## -## DEPENDENCIES - -import sys -import imp -import marshal - -################################################## -## CONSTANTS & GLOBALS - -try: - True,False -except NameError: - True, False = (1==1),(1==0) - -_installed = False - -STRINGTYPE = type('') - -# _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 - path = s - 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 1: - 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 type(thing) is STRINGTYPE: - 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): - # 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 in 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, -] diff --git a/cobbler/Cheetah/Macros/I18n.py b/cobbler/Cheetah/Macros/I18n.py deleted file mode 100644 index 7c2b1ef..0000000 --- a/cobbler/Cheetah/Macros/I18n.py +++ /dev/null @@ -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 - diff --git a/cobbler/Cheetah/Macros/__init__.py b/cobbler/Cheetah/Macros/__init__.py deleted file mode 100644 index 792d600..0000000 --- a/cobbler/Cheetah/Macros/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# diff --git a/cobbler/Cheetah/NameMapper.py b/cobbler/Cheetah/NameMapper.py deleted file mode 100644 index 2d6d953..0000000 --- a/cobbler/Cheetah/NameMapper.py +++ /dev/null @@ -1,355 +0,0 @@ -#!/usr/bin/env python -# $Id: NameMapper.py,v 1.29 2006/01/15 20:27:42 tavis_rudd Exp $ - -"""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. - -Meta-Data -================================================================================ -Authors: Tavis Rudd <tavis@damnsimple.com>, - Chuck Esterbrook <echuck@mindspring.com> -Version: $Revision: 1.29 $ -Start Date: 2001/04/03 -Last Revision Date: $Date: 2006/01/15 20:27:42 $ -""" -from __future__ import generators -__author__ = "Tavis Rudd <tavis@damnsimple.com>," +\ - "\nChuck Esterbrook <echuck@mindspring.com>" -__revision__ = "$Revision: 1.29 $"[11:-2] -import types -from types import StringType, InstanceType, ClassType, TypeType -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', - ] - - -## 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: - excString += ' in the namespace %s'%pformat(namespace) - exc.args = (excStr,) - raise - -def hasKey(obj, key): - """Determine if 'obj' has 'key' """ - if hasattr(obj,'has_key') and obj.has_key(key): - return True - elif hasattr(obj, key): - return True - else: - return False - -def valueForKey(obj, key): - if hasattr(obj, 'has_key') and obj.has_key(key): - 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 obj.has_key(key): - nextObj = obj[key] - elif hasattr(obj, key): - nextObj = getattr(obj, key) - else: - _raiseNotFoundException(key, obj) - - if (executeCallables and callable(nextObj) - and (type(nextObj) not in (InstanceType, ClassType))): - 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 _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() - - - diff --git a/cobbler/Cheetah/Parser.py b/cobbler/Cheetah/Parser.py deleted file mode 100644 index a72e702..0000000 --- a/cobbler/Cheetah/Parser.py +++ /dev/null @@ -1,2558 +0,0 @@ -#!/usr/bin/env python -# $Id: Parser.py,v 1.130 2006/06/21 23:49:14 tavis_rudd Exp $ -"""Parser classes for Cheetah's Compiler - -Classes: - ParseError( Exception ) - _LowLevelParser( Cheetah.SourceReader.SourceReader ), basically a lexer - _HighLevelParser( _LowLevelParser ) - Parser === _HighLevelParser (an alias) - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -Version: $Revision: 1.130 $ -Start Date: 2001/08/01 -Last Revision Date: $Date: 2006/06/21 23:49:14 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.130 $"[11:-2] - -import os -import sys -import re -from re import DOTALL, MULTILINE -from types import StringType, ListType, TupleType, ClassType, TypeType -import time -from tokenize import pseudoprog -import inspect -import new -import traceback - -from Cheetah.SourceReader import SourceReader -from Cheetah import Filters -from Cheetah import ErrorCatchers -from Cheetah.Unspecified import Unspecified - -# re tools -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 apply(group, choices) + '*' -def maybe(*choices): return apply(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 - -directiveNamesAndParsers = { - # importing and inheritance - 'import':None, - 'from':None, - 'extends': 'eatExtends', - 'implements': 'eatImplements', - - # output, filtering, and caching - 'slurp': 'eatSlurp', - 'raw': 'eatRaw', - 'include': 'eatInclude', - 'cache': 'eatCache', - 'filter': 'eatFilter', - 'echo': None, - 'silent': None, - - '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: - 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: - """Used by _LowLevelParser.getArgList()""" - - def __init__(self): - self.argNames = [] - self.defVals = [] - self.i = 0 - - def addArgName(self, name): - self.argNames.append( name ) - self.defVals.append( None ) - - def next(self): - self.i += 1 - - def addToDefVal(self, token): - i = self.i - if self.defVals[i] == None: - self.defVals[i] = '' - self.defVals[i] += token - - def merge(self): - defVals = self.defVals - for i in range(len(defVals)): - if type(defVals[i]) == StringType: - defVals[i] = defVals[i].strip() - - return map(None, [i.strip() for i in self.argNames], defVals) - - 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 = re.compile(cacheToken) - - silentPlaceholderToken = (r'(?:' + - r'(?P<SILENT>' +escapeRegexChars('!')+')'+ - '|' + - r'(?P<NOT_SILENT>)' + - ')') - self.silentPlaceholderTokenRE = re.compile(silentPlaceholderToken) - - self.cheetahVarStartRE = re.compile( - 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 = re.compile( - escCharLookBehind + - escapeRegexChars(self.setting('cheetahVarStartToken')) - +validCharsLookAhead - ) - - self.cheetahVarInExpressionStartTokenRE = re.compile( - escapeRegexChars(self.setting('cheetahVarStartToken')) - +r'(?=[A-Za-z_])' - ) - - self.expressionPlaceholderStartRE = re.compile( - 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 = re.compile( - 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 = re.compile(escCharLookBehind + startTokenEsc) - del startTokenEsc - - startTokenEsc = escapeRegexChars( - self.setting('multiLineCommentStartToken')) - endTokenEsc = escapeRegexChars( - self.setting('multiLineCommentEndToken')) - self.multiLineCommentTokenStartRE = re.compile(escCharLookBehind + - startTokenEsc) - self.multiLineCommentEndTokenRE = re.compile(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 = re.compile(''.join(reParts)) - self.directiveEndTokenRE = re.compile(escCharLookBehind + endTokenEsc) - - def _makePspREs(self): - """Setup the regexs for PSP parsing.""" - startToken = self.setting('PSPStartToken') - startTokenEsc = escapeRegexChars(startToken) - self.PSPStartTokenRE = re.compile(escCharLookBehind + startTokenEsc) - endToken = self.setting('PSPEndToken') - endTokenEsc = escapeRegexChars(endToken) - self.PSPEndTokenRE = re.compile(escCharLookBehind + endTokenEsc) - - - 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 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() - directives = self._directiveNamesAndParsers.keys() - possibleMatches = [] - name = '' - while not self.atEnd(): - c = self.getc() - if not c in directiveNameChars: - break - name += c - if name in directives: - possibleMatches.append(name) - - possibleMatches.sort() - possibleMatches.reverse() # longest match first - - directiveName = False - if possibleMatches: - directiveName = possibleMatches[0] - - self.setPos(startPos) - return directiveName - - 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 1: - 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 1: - if self.atEnd(): - self.setPos(enclosures[-1][1]) - 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.addToDefVal(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.addArgName( 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.addToDefVal(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.addArgName(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 1: - 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 - #print 'CHEETAH STRING', nextToken, theStr, startPosIdx - 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)) - #if not self.atEnd() and self.matches('.join('): - # print 'DEBUG***' - 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): - _LowLevelParser.__init__(self, 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): - _LowLevelParser.configureParser(self) - self._initDirectives() - - def _initDirectives(self): - def normalizeParserVal(val): - if isinstance(val, (str,unicode)): - handler = getattr(self, val) - elif type(val) in (ClassType, TypeType): - handler = val(self) - elif callable(val): - 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',{}) - from Cheetah.Macros.I18n import I18n - macroDirectives['i18n'] = I18n - - - for macroName, callback in macroDirectives.items(): - if type(callback) in (ClassType, TypeType): - 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) - 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 1: - 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 ParserError(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: - out = sys.stderr - print >> out, 'An error occurred while processing the following #compiler directive.' - print >> out, '-'*80 - print >> out, self[startPos:endPos] - print >> out, '-'*80 - print >> out, 'Please check the syntax of these settings.' - print >> out, 'A full Python exception traceback follows.' - 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: - out = sys.stderr - print >> out, 'An error occurred while processing the following compiler settings.' - print >> out, '-'*80 - print >> out, settingsStr.strip() - print >> out, '-'*80 - print >> out, 'Please check the syntax of these settings.' - print >> out, 'A full Python exception traceback follows.' - 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 or #closure') - 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) - 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.getDottedName() - - 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 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 not self._directiveNamesAndParsers.has_key(macroName) - 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 not kwArgs.has_key('src') - kwArgs['src'] = srcBlock - - if type(macro)==new.instancemethod: - 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 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 diff --git a/cobbler/Cheetah/Servlet.py b/cobbler/Cheetah/Servlet.py deleted file mode 100644 index 5295d30..0000000 --- a/cobbler/Cheetah/Servlet.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python -# $Id: Servlet.py,v 1.40 2006/02/04 23:06:15 tavis_rudd Exp $ -"""Provides an abstract Servlet baseclass for Cheetah's Template class - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -License: This software is released for unlimited distribution under the - terms of the MIT license. See the LICENSE file. -Version: $Revision: 1.40 $ -Start Date: 2001/10/03 -Last Revision Date: $Date: 2006/02/04 23:06:15 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.40 $"[11:-2] - -import sys -import os.path - -isWebwareInstalled = False -try: - if 'ds.appserver' in sys.modules.keys(): - from ds.appserver.Servlet import Servlet as BaseServlet - else: - from WebKit.Servlet import Servlet as BaseServlet - isWebwareInstalled = True - - if not issubclass(BaseServlet, object): - class NewStyleBaseServlet(BaseServlet, object): pass - BaseServlet = NewStyleBaseServlet -except: - class BaseServlet(object): - _reusable = 1 - _threadSafe = 0 - - def __init__(self): - pass - - def awake(self, transaction): - pass - - def sleep(self, transaction): - pass - - def shutdown(self): - pass - -################################################## -## CLASSES - -class Servlet(BaseServlet): - - """This class is an abstract baseclass for Cheetah.Template.Template. - - It wraps WebKit.Servlet and provides a few extra convenience methods that - are also found in WebKit.Page. It doesn't do any of the HTTP method - resolution that is done in WebKit.HTTPServlet - """ - - transaction = None - application = None - request = None - session = None - - def __init__(self): - BaseServlet.__init__(self) - - # this default will be changed by the .awake() method - self._CHEETAH__isControlledByWebKit = False - - ## methods called by Webware during the request-response - - def awake(self, transaction): - BaseServlet.awake(self, transaction) - - # a hack to signify that the servlet is being run directly from WebKit - self._CHEETAH__isControlledByWebKit = True - - self.transaction = transaction - #self.application = transaction.application - self.response = response = transaction.response - self.request = transaction.request - - # Temporary hack to accomodate bug in - # WebKit.Servlet.Servlet.serverSidePath: it uses - # self._request even though this attribute does not exist. - # This attribute WILL disappear in the future. - self._request = transaction.request() - - - self.session = transaction.session - self.write = response().write - #self.writeln = response.writeln - - 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): - BaseServlet.sleep(self, 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 self._CHEETAH__isControlledByWebKit: - return BaseServlet.serverSidePath(self, path) - elif 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 diff --git a/cobbler/Cheetah/SettingsManager.py b/cobbler/Cheetah/SettingsManager.py deleted file mode 100644 index 0967155..0000000 --- a/cobbler/Cheetah/SettingsManager.py +++ /dev/null @@ -1,623 +0,0 @@ -#!/usr/bin/env python - -"""Provides a mixin/base class for collecting and managing application settings - -Meta-Data -========== -Author: Tavis Rudd <tavis@damnsimple.com> -Version: $Revision: 1.28 $ -Start Date: 2001/05/30 -Last Revision Date: $Date: 2006/01/29 07:19:12 $ -""" - -# $Id: SettingsManager.py,v 1.28 2006/01/29 07:19:12 tavis_rudd Exp $ -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.28 $"[11:-2] - - -################################################## -## DEPENDENCIES ## - -import sys -import os.path -import copy as copyModule -from ConfigParser import ConfigParser -import re -from tokenize import Intnumber, Floatnumber, Number -from types import * -import types -import new -import tempfile -import imp -import time - -from StringIO import StringIO # not cStringIO because of unicode support - -import imp # used by SettingsManager.updateSettingsFromPySrcFile() - -try: - import threading - from threading import Lock # used for thread lock on sys.path manipulations -except: - ## provide a dummy for non-threading Python systems - class Lock: - def acquire(self): - pass - def release(self): - pass - -class BaseErrorClass: pass - -################################################## -## CONSTANTS & GLOBALS ## - -try: - True,False -except NameError: - True, False = (1==1),(1==0) - -numberRE = re.compile(Number) -complexNumberRE = re.compile('[\(]*' +Number + r'[ \t]*\+[ \t]*' + Number + '[\)]*') - -convertableToStrTypes = (StringType, IntType, FloatType, - LongType, ComplexType, NoneType, - UnicodeType) - -################################################## -## 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.items(): - if dict1.has_key(key) and type(val) == types.DictType and \ - type(dict1[key]) == types.DictType: - - 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, {}, {}) - - - -###### - -ident = r'[_a-zA-Z][_a-zA-Z0-9]*' -firstChunk = r'^(?P<indent>\s*)(?P<class>[_a-zA-Z][_a-zA-Z0-9]*)' -customClassRe = re.compile(firstChunk + r'\s*:') -baseClasses = r'(?P<bases>\(\s*([_a-zA-Z][_a-zA-Z0-9]*\s*(,\s*[_a-zA-Z][_a-zA-Z0-9]*\s*)*)\))' -customClassWithBasesRe = re.compile(firstChunk + baseClasses + '\s*:') - -def translateClassBasedConfigSyntax(src): - - """Compiles a config file in the custom class-based SettingsContainer syntax - to Vanilla Python - - # WebKit.config - Applications: - MyApp: - Dirs: - ROOT = '/home/www/Home' - Products = '/home/www/Products' - becomes: - # WebKit.config - from Cheetah.SettingsManager import SettingsContainer - class Applications(SettingsContainer): - class MyApp(SettingsContainer): - class Dirs(SettingsContainer): - ROOT = '/home/www/Home' - Products = '/home/www/Products' - """ - - outputLines = [] - for line in src.splitlines(): - if customClassRe.match(line) and \ - line.strip().split(':')[0] not in ('else','try', 'except', 'finally'): - - line = customClassRe.sub( - r'\g<indent>class \g<class>(SettingsContainer):', line) - - elif customClassWithBasesRe.match(line) and not line.strip().startswith('except'): - line = customClassWithBasesRe.sub( - r'\g<indent>class \g<class>\g<bases>:', line) - - outputLines.append(line) - - ## prepend this to the first line to make sure that tracebacks report the right line nums - if outputLines[0].find('class ') == -1: - initLine = 'from Cheetah.SettingsManager import SettingsContainer; True, False = 1, 0; ' - else: - initLine = 'from Cheetah.SettingsManager import SettingsContainer; True, False = 1, 0\n' - return initLine + '\n'.join(outputLines) + '\n' - - -################################################## -## CLASSES ## - -class Error(BaseErrorClass): - pass - -class NoDefault: - 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 SettingsContainer: - """An abstract base class for 'classes' that are used to house settings.""" - pass - - -class _SettingsCollector: - - """An abstract base class that provides the methods SettingsManager uses to - collect settings from config files and SettingsContainers. - - This class only collects settings it doesn't modify the _settings dictionary - of SettingsManager instances in any way. - - SettingsCollector is designed to: - - be able to read settings from Python src files (or strings) so that - complex Python objects can be stored in the application's settings - dictionary. For example, you might want to store references to various - classes that are used by the application and plugins to the application - might want to substitute one class for another. - - be able to read/write .ini style config files (or strings) - - allow sections in .ini config files to be extended by settings in Python - src files - - allow python literals to be used values in .ini config files - - maintain the case of setting names, unlike the ConfigParser module - - """ - - _sysPathLock = Lock() # used by the updateSettingsFromPySrcFile() method - _ConfigParserClass = ConfigParserCaseSensitive - - - def __init__(self): - pass - - def normalizePath(self, path): - - """A hook for any neccessary path manipulations. - - For example, when this is used with WebKit servlets all relative paths - must be converted so they are relative to the servlet's directory rather - than relative to the program's current working dir. - - The default implementation just normalizes the path for the current - operating system.""" - - return os.path.normpath(path.replace("\\",'/')) - - - def readSettingsFromContainer(self, container, ignoreUnderscored=True): - - """Returns all settings from a SettingsContainer or Python - module. - - This method is recursive. - """ - - S = {} - if type(container) == ModuleType: - attrs = vars(container) - else: - attrs = self._getAllAttrsFromContainer(container) - - for k, v in attrs.items(): - if (ignoreUnderscored and k.startswith('_')) or v is SettingsContainer: - continue - if self._isContainer(v): - S[k] = self.readSettingsFromContainer(v) - else: - S[k] = v - return S - - # provide an alias - readSettingsFromModule = readSettingsFromContainer - - def _isContainer(self, thing): - - """Check if 'thing' is a Python module or a subclass of - SettingsContainer.""" - - return type(thing) == ModuleType or ( - type(thing) == ClassType and issubclass(thing, SettingsContainer) - ) - - def _getAllAttrsFromContainer(self, container): - """Extract all the attributes of a SettingsContainer subclass. - - The 'container' is a class, so extracting all attributes from it, an - instance of it, and all its base classes. - - This method is not recursive. - """ - - attrs = container.__dict__.copy() - # init an instance of the container and get all attributes - attrs.update( container().__dict__ ) - - for base in container.__bases__: - for k, v in base.__dict__.items(): - if not attrs.has_key(k): - attrs[k] = v - return attrs - - def readSettingsFromPySrcFile(self, path): - - """Return new settings dict from variables in a Python source file. - - This method will temporarily add the directory of src file to sys.path so - that import statements relative to that dir will work properly.""" - - path = self.normalizePath(path) - dirName = os.path.dirname(path) - tmpPath = tempfile.mkstemp('webware_temp') - - pySrc = translateClassBasedConfigSyntax(open(path).read()) - modName = path.replace('.','_').replace('/','_').replace('\\','_') - open(tmpPath, 'w').write(pySrc) - try: - fp = open(tmpPath) - self._sysPathLock.acquire() - sys.path.insert(0, dirName) - module = imp.load_source(modName, path, fp) - newSettings = self.readSettingsFromModule(module) - del sys.path[0] - self._sysPathLock.release() - return newSettings - finally: - fp.close() - try: - os.remove(tmpPath) - except: - pass - if os.path.exists(tmpPath + 'c'): - try: - os.remove(tmpPath + 'c') - except: - pass - if os.path.exists(path + 'c'): - try: - os.remove(path + 'c') - except: - pass - - - def readSettingsFromPySrcStr(self, theString): - - """Return a dictionary of the settings in a Python src string.""" - - globalsDict = {'True':1, - 'False':0, - 'SettingsContainer':SettingsContainer, - } - newSettings = {'self':self} - exec theString in globalsDict, newSettings - del newSettings['self'], newSettings['True'], newSettings['False'] - module = new.module('temp_settings_module') - module.__dict__.update(newSettings) - return self.readSettingsFromModule(module) - - def readSettingsFromConfigFile(self, path, convert=True): - path = self.normalizePath(path) - fp = open(path) - settings = self.readSettingsFromConfigFileObj(fp, convert=convert) - fp.close() - return settings - - 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. - """ - - ## init methods - - def __init__(self): - """MUST BE CALLED BY SUBCLASSES""" - _SettingsCollector.__init__(self) - 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 self._settings.has_key(key) - - 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 copy(self._settings) - - def deepcopySettings(self): - """Returns a deep copy of the settings dictionary""" - return 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 updateSettingsFromPySrcFile(self, path, merge=True): - - """Update the settings from variables in a Python source file. - - This method will temporarily add the directory of src file to sys.path so - that import statements relative to that dir will work properly.""" - - newSettings = self.readSettingsFromPySrcFile(path) - self.updateSettings(newSettings, - merge=newSettings.get('mergeSettings',merge) ) - - - def updateSettingsFromConfigFile(self, path, **kw): - - """Update the settings from a text file using the syntax accepted by - Python's standard ConfigParser module (like Windows .ini files). - """ - - path = self.normalizePath(path) - fp = open(path) - self.updateSettingsFromConfigFileObj(fp, **kw) - fp.close() - - - 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)) - - - ## methods for output representations of the settings - - def _createConfigFile(self, outFile=None): - - """ - Write all the settings that can be represented as strings to an .ini - style config string. - - This method can only handle one level of nesting and will only work with - numbers, strings, and None. - """ - - if outFile is None: - outFile = StringIO() - iniSettings = {'Globals':{}} - globals = iniSettings['Globals'] - - for key, theSetting in self.settings().items(): - if type(theSetting) in convertableToStrTypes: - globals[key] = theSetting - if type(theSetting) is DictType: - iniSettings[key] = {} - for subKey, subSetting in theSetting.items(): - if type(subSetting) in convertableToStrTypes: - iniSettings[key][subKey] = subSetting - - sections = iniSettings.keys() - sections.sort() - outFileWrite = outFile.write # short-cut namebinding for efficiency - for section in sections: - outFileWrite("[" + section + "]\n") - sectDict = iniSettings[section] - - keys = sectDict.keys() - keys.sort() - for key in keys: - if key == "__name__": - continue - outFileWrite("%s = %s\n" % (key, sectDict[key])) - outFileWrite("\n") - - return outFile - - def writeConfigFile(self, path): - - """Write all the settings that can be represented as strings to an .ini - style config file.""" - - path = self.normalizePath(path) - fp = open(path,'w') - self._createConfigFile(fp) - fp.close() - - def getConfigString(self): - """Return a string with the settings in .ini file format.""" - - return self._createConfigFile().getvalue() - -# vim: shiftwidth=4 tabstop=4 expandtab diff --git a/cobbler/Cheetah/SourceReader.py b/cobbler/Cheetah/SourceReader.py deleted file mode 100644 index e91c200..0000000 --- a/cobbler/Cheetah/SourceReader.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env python -# $Id: SourceReader.py,v 1.14 2006/01/18 03:16:59 tavis_rudd Exp $ -"""SourceReader class for Cheetah's Parser and CodeGenerator - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -License: This software is released for unlimited distribution under the - terms of the MIT license. See the LICENSE file. -Version: $Revision: 1.14 $ -Start Date: 2001/09/19 -Last Revision Date: $Date: 2006/01/18 03:16:59 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.14 $"[11:-2] - -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: - def __init__(self, src, filename=None, breakPoint=None, encoding=None): - - ## @@TR 2005-01-17: the following comes from a patch Terrel Shumway - ## contributed to add unicode support to the reading of Cheetah source - ## files with dynamically compiled templates. All the existing unit - ## tests pass but, it needs more testing and some test cases of its - ## own. My instinct is to move this up into the code that passes in the - ## src string rather than leaving it here. As implemented here it - ## forces all src strings to unicode, which IMO is not what we want. - # if encoding is None: - # # peek at the encoding in the first two lines - # m = EOLZre.search(src) - # pos = m.end() - # if pos<len(src): - # m = EOLZre.search(src,pos) - # pos = m.end() - # m = ENCODINGsearch(src,0,pos) - # if m: - # encoding = m.group(1) - # else: - # encoding = sys.getfilesystemencoding() - # self._encoding = encoding - # if type(src) is not unicode: - # src = src.decode(encoding) - ## end of Terrel's patch - - 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): - 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 self._bookmarks.has_key(name) - - def gotoBookmark(self, name): - if not self.hasBookmark(name): - raise Error("Invalid bookmark (" + name + ', '+ - str(pos) + ") 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()] diff --git a/cobbler/Cheetah/Template.py b/cobbler/Cheetah/Template.py deleted file mode 100644 index 0185b50..0000000 --- a/cobbler/Cheetah/Template.py +++ /dev/null @@ -1,1858 +0,0 @@ -#!/usr/bin/env python -# $Id: Template.py,v 1.181 2006/06/22 20:25:16 hierro Exp $ -"""Provides the core API for Cheetah. - -See the docstring in the Template class and the Users' Guide for more information - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -License: This software is released for unlimited distribution under the - terms of the MIT license. See the LICENSE file. -Version: $Revision: 1.181 $ -Start Date: 2001/03/30 -Last Revision Date: $Date: 2006/06/22 20:25:16 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.181 $"[11:-2] - -################################################################################ -## DEPENDENCIES -import sys # used in the error handling code -import re # used to define the internal delims regex -import new # used to bind methods and create dummy modules -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 -from types import StringType, ClassType -try: - from types import StringTypes -except ImportError: - StringTypes = (types.StringType,types.UnicodeType) -try: - from types import BooleanType - boolTypeAvailable = True -except ImportError: - boolTypeAvailable = False - -try: - from threading import Lock -except ImportError: - class Lock: - def acquire(self): pass - def release(self): pass - -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 import VerifyType # Used in Template.__init__ -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 - -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 = d.items() - items.sort() - 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_'+baseModuleName - +'_' - +''.join(map(lambda x: '%02d' % x, time.localtime(time.time())[:6])) - + 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 - -# used in Template.compile() -def valOrDefault(val, default): - if val is not Unspecified: return val - else: return default - - -class CompileCacheItem: - pass - -class TemplatePreprocessor: - """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_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 - - def _getCompilerClass(klass, source=None, file=None): - return klass._CHEETAH_compilerClass - _getCompilerClass = classmethod(_getCompilerClass) - - def _getCompilerSettings(klass, source=None, file=None): - return klass._CHEETAH_compilerSettings - _getCompilerSettings = classmethod(_getCompilerSettings) - - 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, - - 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=[...]) ] ) - - """ - ################################################## - ## normalize and validate args - try: - vt = VerifyType.VerifyType - vtc = VerifyType.VerifyTypeClass - N = types.NoneType; S = types.StringType; U = types.UnicodeType - D = types.DictType; F = types.FileType - C = types.ClassType; M = types.ModuleType - I = types.IntType - - if boolTypeAvailable: - B = types.BooleanType - - vt(source, 'source', [N,S,U], 'string or None') - vt(file, 'file',[N,S,U,F], 'string, file-like object, or None') - - baseclass = valOrDefault(baseclass, klass._CHEETAH_defaultBaseclassForTemplates) - if isinstance(baseclass, Template): - baseclass = baseclass.__class__ - vt(baseclass, 'baseclass', [N,S,C,type], 'string, class or None') - - cacheCompilationResults = valOrDefault( - cacheCompilationResults, klass._CHEETAH_cacheCompilationResults) - if boolTypeAvailable: - vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean') - - useCache = valOrDefault(useCache, klass._CHEETAH_useCompilationCache) - if boolTypeAvailable: - vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean') - - compilerSettings = valOrDefault( - compilerSettings, klass._getCompilerSettings(source, file) or {}) - vt(compilerSettings, 'compilerSettings', [D], 'dictionary') - - compilerClass = valOrDefault(compilerClass, klass._getCompilerClass(source, file)) - - preprocessors = valOrDefault(preprocessors, klass._CHEETAH_preprocessors) - - keepRefToGeneratedCode = valOrDefault( - keepRefToGeneratedCode, klass._CHEETAH_keepRefToGeneratedCode) - if boolTypeAvailable: - vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean') - - vt(moduleName, 'moduleName', [N,S], 'string or None') - __orig_file__ = None - if not moduleName: - if file and type(file) in StringTypes: - moduleName = convertTmplPathToModuleName(file) - __orig_file__ = file - else: - moduleName = klass._CHEETAH_defaultModuleNameForTemplates - - className = valOrDefault( - className, klass._CHEETAH_defaultClassNameForTemplates) - vt(className, 'className', [N,S], 'string or None') - className = className or moduleName - - mainMethodName = valOrDefault( - mainMethodName, klass._CHEETAH_defaultMainMethodNameForTemplates) - vt(mainMethodName, 'mainMethodName', [N,S], 'string or None') - - moduleGlobals = valOrDefault( - moduleGlobals, klass._CHEETAH_defaultModuleGlobalsForTemplates) - - cacheModuleFilesForTracebacks = valOrDefault( - cacheModuleFilesForTracebacks, klass._CHEETAH_cacheModuleFilesForTracebacks) - if boolTypeAvailable: - vt(cacheModuleFilesForTracebacks, 'cacheModuleFilesForTracebacks', [I,B], 'boolean') - - cacheDirForModuleFiles = valOrDefault( - cacheDirForModuleFiles, klass._CHEETAH_cacheDirForModuleFiles) - vt(cacheDirForModuleFiles, 'cacheDirForModuleFiles', [N,S], 'string or None') - - except TypeError, reason: - raise TypeError(reason) - - ################################################## - ## 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 type(baseclass) in StringTypes: - baseclassName = baseclass - elif type(baseclass) in (ClassType, type): - # @@TR: should soft-code this - baseclassName = 'CHEETAH_dynamicallyAssignedBaseClass_'+baseclass.__name__ - baseclassValue = baseclass - - - cacheHash = None - cacheItem = None - if source or isinstance(file, (str, unicode)): - compilerSettingsHash = None - if compilerSettings: - compilerSettingsHash = hashDict(compilerSettings) - - moduleGlobalsHash = None - if moduleGlobals: - moduleGlobalsHash = hashDict(moduleGlobals) - - fileHash = None - if file: - fileHash = str(hash(file))+str(os.path.getmtime(file)) - - try: - 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 - if useCache and cacheHash and klass._CHEETAH_compileCache.has_key(cacheHash): - cacheItem = klass._CHEETAH_compileCache[cacheHash] - generatedModuleCode = cacheItem.code - #print 'DEBUG: found cached copy' - else: - compiler = compilerClass(source, file, - moduleName=moduleName, - mainClassName=className, - baseclassName=baseclassName, - mainMethodName=mainMethodName, - settings=(compilerSettings or {})) - compiler.compile() - generatedModuleCode = compiler.getModuleCode() - - if not returnAClass: - return generatedModuleCode - else: - if cacheItem: - cacheItem.lastCheckoutTime = time.time() - return cacheItem.klass - - def updateLinecache(filename, src): - import linecache - size = len(src) - mtime = time.time() - lines = src.splitlines() - fullname = filename - linecache.cache[filename] = size, mtime, lines, fullname - - - try: - klass._CHEETAH_compileLock.acquire() - uniqueModuleName = _genUniqueModuleName(moduleName) - __file__ = uniqueModuleName+'.py' # relative file path with no dir part - mod = new.module(uniqueModuleName) - sys.modules[uniqueModuleName] = mod - finally: - klass._CHEETAH_compileLock.release() - - try: - if cacheModuleFilesForTracebacks: - if not os.path.exists(cacheDirForModuleFiles): - raise Exception('%s does not exist'% - cacheDirForModuleFiles) - - __file__ = os.path.join(cacheDirForModuleFiles, __file__) - try: - klass._CHEETAH_compileLock.acquire() - # @@TR: might want to assert that it doesn't already exist - try: - open(__file__, 'w').write(generatedModuleCode) - # @@TR: should probably restrict the perms, etc. - except OSError: - # @@ TR: should this optionally raise? - traceback.print_exc(file=sys.stderr) - finally: - klass._CHEETAH_compileLock.release() - - 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 in mod.__dict__ - except SyntaxError, e: - try: - parseError = genParserErrorFromPythonException( - source, file, generatedModuleCode, exception=e) - except: - traceback.print_exc() - updateLinecache(__file__, generatedModuleCode) - e.generatedModuleCode = generatedModuleCode - raise e - else: - raise parseError - except Exception, e: - updateLinecache(__file__, generatedModuleCode) - e.generatedModuleCode = generatedModuleCode - raise - - except: - del sys.modules[uniqueModuleName] - raise - - templateClass = getattr(mod, className) - - if (cacheCompilationResults - and cacheHash - and not klass._CHEETAH_compileCache.has_key(cacheHash)): - - 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 - - return templateClass - compile = classmethod(compile) - - 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) - subclass = classmethod(subclass) - - 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 - _preprocessSource = classmethod(_preprocessSource) - - 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 callable(arg): - 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) - - _normalizePreprocessorArg = classmethod(_normalizePreprocessorArg) - - 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 - _normalizePreprocessorSettings = classmethod(_normalizePreprocessorSettings) - - 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 - _updateSettingsWithPreprocessTokens = classmethod(_updateSettingsWithPreprocessTokens) - - 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 = new.instancemethod(method.im_func, None, concreteTemplateClass) - #print methodname, method - 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): return getattr(self, mainMethName)() - elif (hasattr(concreteTemplateClass, 'respond') - and concreteTemplateClass.respond!=Servlet.respond): - def __str__(self): return self.respond() - else: - def __str__(self): - if hasattr(self, mainMethNameAttr): - return getattr(self,mainMethNameAttr)() - elif hasattr(self, 'respond'): - return self.respond() - else: - return super(self.__class__, self).__str__() - - __str__ = new.instancemethod(__str__, None, concreteTemplateClass) - setattr(concreteTemplateClass, '__str__', __str__) - - _addCheetahPlumbingCodeToClass = classmethod(_addCheetahPlumbingCodeToClass) - - ## end classmethods ## - - 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! - - """ - - ################################################## - ## Verify argument keywords and types - - S = types.StringType; U = types.UnicodeType - L = types.ListType; T = types.TupleType - D = types.DictType; F = types.FileType - C = types.ClassType; M = types.ModuleType - N = types.NoneType - vt = VerifyType.VerifyType - vtc = VerifyType.VerifyTypeClass - try: - vt(source, 'source', [N,S,U], 'string or None') - vt(file, 'file', [N,S,U,F], 'string, file open for reading, or None') - vtc(filter, 'filter', [S,C,type], 'string or class', - Filters.Filter, - '(if class, must be subclass of Cheetah.Filters.Filter)') - vt(filtersLib, 'filtersLib', [S,M], 'string or module', - '(if module, must contain subclasses of Cheetah.Filters.Filter)') - vtc(errorCatcher, 'errorCatcher', [N,S,C,type], 'string, class or None', - ErrorCatchers.ErrorCatcher, - '(if class, must be subclass of Cheetah.ErrorCatchers.ErrorCatcher)') - if compilerSettings is not Unspecified: - vt(compilerSettings, 'compilerSettings', [D], 'dictionary') - - except TypeError, reason: - # Re-raise the exception here so that the traceback will end in - # this function rather than in some utility function. - raise TypeError(reason) - - 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. - Servlet.__init__(self) - - ################################################## - ## 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 - - self._initCheetahInstance( - searchList=searchList, namespaces=namespaces, - filter=filter, filtersLib=filtersLib, - errorCatcher=errorCatcher, - _globalSetVars=_globalSetVars, - _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 key, cregion in self.getCacheRegions(): - cregion.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, - _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] - if searchList is not None: - self._CHEETAH__searchList.extend(list(searchList)) - self._CHEETAH__searchList.append( self ) - self._CHEETAH__cheetahIncludes = {} - self._CHEETAH__cacheRegions = {} - self._CHEETAH__indenter = Indenter() - self._CHEETAH__filtersLib = filtersLib - self._CHEETAH__filters = {} - if type(filter) in StringTypes: - 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 type(errorCatcher) in StringTypes: - errorCatcherClass = getattr(ErrorCatchers, errorCatcher) - elif type(errorCatcher) == ClassType: - 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 type(file) in StringTypes: - 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) - 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 not self._CHEETAH__cheetahIncludes.has_key(_includeID): - if not raw: - if includeFrom == 'file': - source = None - if type(srcArg) in StringTypes: - 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) - 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.181 $ - Start Date: 2002/03/17 - Last Revision Date: $Date: 2006/06/22 20:25:16 $ - """ - 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. - - -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) + '^\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 diff --git a/cobbler/Cheetah/TemplateCmdLineIface.py b/cobbler/Cheetah/TemplateCmdLineIface.py deleted file mode 100644 index abd8ae2..0000000 --- a/cobbler/Cheetah/TemplateCmdLineIface.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -# $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 diff --git a/cobbler/Cheetah/Templates/SkeletonPage.py b/cobbler/Cheetah/Templates/SkeletonPage.py deleted file mode 100644 index 0049d17..0000000 --- a/cobbler/Cheetah/Templates/SkeletonPage.py +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/env python - - -"""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 callable(self.transaction)): - 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 callable(self.transaction)): - 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 callable(self.transaction)): - 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() - - diff --git a/cobbler/Cheetah/Templates/SkeletonPage.tmpl b/cobbler/Cheetah/Templates/SkeletonPage.tmpl deleted file mode 100644 index 43c5ecd..0000000 --- a/cobbler/Cheetah/Templates/SkeletonPage.tmpl +++ /dev/null @@ -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> - - - diff --git a/cobbler/Cheetah/Templates/_SkeletonPage.py b/cobbler/Cheetah/Templates/_SkeletonPage.py deleted file mode 100644 index bf10e30..0000000 --- a/cobbler/Cheetah/Templates/_SkeletonPage.py +++ /dev/null @@ -1,216 +0,0 @@ -#!/usr/bin/env python -# $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 not self._stylesheets.has_key(identifier): - 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.items(): - if type(details) not in (types.ListType, types.TupleType): - 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.items(): - if type(details) not in (types.ListType, types.TupleType): - 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 metaTags.has_key('HTTP-EQUIV'): - for http_equiv, contents in metaTags['HTTP-EQUIV'].items(): - metaTagsTxt += ['<meta http-equiv="', str(http_equiv), '" content="', - str(contents), '" />\n'] - - if metaTags.has_key('NAME'): - for name, contents in metaTags['NAME'].items(): - metaTagsTxt += ['<meta name="', str(name), '" content="', str(contents), - '" />\n'] - return ''.join(metaTagsTxt) - diff --git a/cobbler/Cheetah/Templates/__init__.py b/cobbler/Cheetah/Templates/__init__.py deleted file mode 100644 index 4265cc3..0000000 --- a/cobbler/Cheetah/Templates/__init__.py +++ /dev/null @@ -1 +0,0 @@ -#!/usr/bin/env python diff --git a/cobbler/Cheetah/Tests/CheetahWrapper.py b/cobbler/Cheetah/Tests/CheetahWrapper.py deleted file mode 100644 index 316c43b..0000000 --- a/cobbler/Cheetah/Tests/CheetahWrapper.py +++ /dev/null @@ -1,596 +0,0 @@ -#!/usr/bin/env python -# $Id: CheetahWrapper.py,v 1.5 2006/01/07 07:18:44 tavis_rudd Exp $ -"""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.) - -Meta-Data -================================================================================ -Author: Mike Orr <iron@mso.oz.net>, -Version: $Revision: 1.5 $ -Start Date: 2001/10/01 -Last Revision Date: $Date: 2006/01/07 07:18:44 $ -""" -__author__ = "Mike Orr <iron@mso.oz.net>" -__revision__ = "$Revision: 1.5 $"[11:-2] - - -################################################## -## DEPENDENCIES ## - -import commands, os, shutil, sys, tempfile -import unittest_local_copy as unittest - -import re # Used by listTests. -from Cheetah.CheetahWrapper import CheetahWrapper # Used by NoBackup. -from Cheetah.Utils.optik import OptionParser # Used by main. - -################################################## -## CONSTANTS & GLOBALS ## - -try: - True,False -except NameError: - True, False = (1==1),(1==0) - -DELETE = True # True to clean up after ourselves, False for debugging. -OUTPUT = False # Normally False, True for debugging. - -#DELETE = False # True to clean up after ourselves, False for debugging. -#OUTPUT = True # Normally False, True for debugging. - -BACKUP_SUFFIX = CheetahWrapper.BACKUP_SUFFIX - -def warn(msg): - sys.stderr.write(msg + '\n') - -################################################## -## TEST BASE CLASSES - -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. - """ - 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 = R"'Hello, world!\n')" # 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 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. - """ - # Use commands.getstatusoutput instead of os.system so - # that we can mimic ">/dev/null 2>/dev/null" even on - # non-Unix platforms. - exit, output = commands.getstatusoutput(cmd) - status, signal = divmod(exit, 256) - if OUTPUT: - if output.endswith("\n"): - output = output[:-1] - print - print "SUBCOMMAND:", cmd - print output - print - msg = "subcommand killed by signal %d: %s" % (signal, cmd) - self.failUnlessEqual(signal, 0, msg) - msg = "subcommand exit status %d: %s" % (status, cmd) - if status!=expectedStatus: - print output - self.failUnlessEqual(status, expectedStatus, msg) - 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) - - - def goExpectError(self, cmd): - """Run a subcommand and expect it to fail. - - in : cmd, string, the command to run. - out: None. - """ - # Use commands.getstatusoutput instead of os.system so - # that we can mimic ">/dev/null 2>/dev/null" even on - # non-Unix platforms. - exit, output = commands.getstatusoutput(cmd) - status, signal = divmod(exit, 256) - msg = "subcommand killed by signal %s: %s" % (signal, cmd) - self.failUnlessEqual(signal, 0, msg) # Signal must be 0. - msg = "subcommand exit status %s: %s" % (status, cmd) - self.failIfEqual(status, 0, msg) # Status must *not* be 0. - if OUTPUT: - if output.endswith("\n"): - output = output[:-1] - print - print "SUBCOMMAND:", cmd - print output - print - - -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.goExpectError("cheetah compile -R --flat") - - def testFill(self): - self.goExpectError("cheetah fill -R --flat") - - def testText(self): - self.goExpectError("cheetah fill -R --flat") - - -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.goExpectError("cheetah compile -R --flat --idir SRC") - - def testFill(self): - self.goExpectError("cheetah fill -R --flat --idir SRC") - - def testText(self): - self.goExpectError("cheetah fill -R --flat --idir SRC --oext txt") - - -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) - - - - - -################################################## -## LIST TESTS ## - -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 1: - lin = f.readline() - if not lin: - break - m = rx.search(lin) - if m: - print m.group(1) - f.close() - -################################################## -## MAIN ROUTINE ## - -class MyOptionParser(OptionParser): - """Disable the standard --help and --verbose options since - --help is used for another purpose. - """ - standard_option_list = [] - -def main(): - global DELETE, OUTPUT - parser = MyOptionParser() - 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("-h", "--help", 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", "help", "verbose", "quiet"): - if getattr(opts, opt): - sys.argv.append("--" + opt) - sys.argv.extend(files) - unittest.main() - -################################################## -## if run from the command line ## - -if __name__ == '__main__': main() - -# vim: sw=4 ts=4 expandtab diff --git a/cobbler/Cheetah/Tests/FileRefresh.py b/cobbler/Cheetah/Tests/FileRefresh.py deleted file mode 100644 index 4beb3e7..0000000 --- a/cobbler/Cheetah/Tests/FileRefresh.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -# $Id: FileRefresh.py,v 1.6 2002/10/01 17:52:03 tavis_rudd Exp $ -"""Tests to make sure that the file-update-monitoring code is working properly - -THIS TEST MODULE IS JUST A SHELL AT THE MOMENT. Feel like filling it in?? - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com>, -Version: $Revision: 1.6 $ -Start Date: 2001/10/01 -Last Revision Date: $Date: 2002/10/01 17:52:03 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.6 $"[11:-2] - - -################################################## -## DEPENDENCIES ## - -import sys -import types -import os -import os.path - - -import unittest_local_copy as unittest -from Cheetah.Template import Template - -################################################## -## CONSTANTS & GLOBALS ## - -try: - True,False -except NameError: - True, False = (1==1),(1==0) - -################################################## -## TEST DATA FOR USE IN THE TEMPLATES ## - -################################################## -## TEST BASE CLASSES - -class TemplateTest(unittest.TestCase): - pass - -################################################## -## TEST CASE CLASSES - - -################################################## -## if run from the command line ## - -if __name__ == '__main__': - unittest.main() diff --git a/cobbler/Cheetah/Tests/NameMapper.py b/cobbler/Cheetah/Tests/NameMapper.py deleted file mode 100644 index 2782463..0000000 --- a/cobbler/Cheetah/Tests/NameMapper.py +++ /dev/null @@ -1,539 +0,0 @@ -#!/usr/bin/env python -# $Id: NameMapper.py,v 1.11 2006/01/15 20:45:22 tavis_rudd Exp $ -"""NameMapper Tests - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com>, -Version: $Revision: 1.11 $ -Start Date: 2001/10/01 -Last Revision Date: $Date: 2006/01/15 20:45:22 $ -""" -from __future__ import generators -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.11 $"[11:-2] -import sys -import types -import os -import os.path - -import unittest_local_copy as unittest -from Cheetah.NameMapper import NotFound, valueForKey, \ - valueForName, valueFromSearchList, valueFromFrame, valueFromFrameOrSearchList - - -################################################## -## TEST DATA FOR USE IN THE TEMPLATES ## - -class DummyClass: - 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 - - -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(), - '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,AssertionError) - _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 autoCallResults.has_key(name): - 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) - -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 - - -################################################## -## if run from the command line ## - -if __name__ == '__main__': - unittest.main() diff --git a/cobbler/Cheetah/Tests/SyntaxAndOutput.py b/cobbler/Cheetah/Tests/SyntaxAndOutput.py deleted file mode 100644 index 09abc4d..0000000 --- a/cobbler/Cheetah/Tests/SyntaxAndOutput.py +++ /dev/null @@ -1,3170 +0,0 @@ -#!/usr/bin/env python -# $Id: SyntaxAndOutput.py,v 1.105 2006/06/21 23:48:19 tavis_rudd Exp $ -"""Syntax and Output tests. - -TODO -- #finally -- #filter -- #errorCatcher -- #echo -- #silent - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -Version: $Revision: 1.105 $ -Start Date: 2001/03/30 -Last Revision Date: $Date: 2006/06/21 23:48:19 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.105 $"[11:-2] - - -################################################## -## DEPENDENCIES ## - -import sys -import types -import re -from copy import deepcopy -import os -import os.path -import new -import warnings - -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 -import unittest_local_copy as unittest - -class Unspecified: pass -################################################## -## CONSTANTS & GLOBALS ## - -majorVer, minorVer = sys.version_info[0], sys.version_info[1] -versionTuple = (majorVer, minorVer) - -try: - True,False -except NameError: - True, False = (1==1),(1==0) - -################################################## -## TEST DATA FOR USE IN THE TEMPLATES ## - -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 - self.template = templateObj = templateClass(searchList=self.searchList()) - else: - self.template = templateObj = Template( - input, - searchList=self.searchList(), - compilerSettings=self._getCompilerSettings(), - ) - moduleCode = templateObj._CHEETAH_generatedModuleCode - if self.DEBUGLEV >= 1: - print moduleCode - try: - try: - output = templateObj.respond() # rather than __str__, because of unicode - if outputEncoding: - output = output.decode(outputEncoding) - assert output==expectedOutput, self._outputMismatchReport(output, expectedOutput) - except: - #print >>sys.stderr, moduleCode - raise - 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 ascii\n\xe1\x88\xb4", - "\xe1\x88\xb4") - - def test5(self): - """basic #encoding """ - self.verify("#encoding latin-1\nAndr\202", - u'Andr\202', outputEncoding='latin-1') - -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") - - def test11(self): - r"""func placeholder - with ('''\nstring'\n''')""" - self.verify("$aFunc('''\naoeu'\n''')", - "\naoeu'\n") - - def test12(self): - r'''func placeholder - with ("""\nstring\n""")''' - self.verify('$aFunc("""\naoeu\n""")', - "\naoeu\n") - - 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) - - -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") - -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") - - -class DecoratorDirective(OutputTest): - def test1(self): - """single line #def with decorator""" - 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') - -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 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-") - - -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 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 ReplaceNone - """ - self.verify("#filter ReplaceNone\n$none#end filter", - "") - - self.verify("#filter ReplaceNone: $none", - "") - - def test2(self): - """#filter ReplaceNone with WS - """ - self.verify("#filter ReplaceNone \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 <=> &") - - def test6(self): - """#filter WebSafe -- also space - """ - self.verify("#filter WebSafe \n${webSafeTest, $also=' '}#end filter", - "abc <=> &") - - def test7(self): - """#filter WebSafe -- also space, without $ on the args - """ - self.verify("#filter WebSafe \n${webSafeTest, also=' '}#end filter", - "abc <=> &") - - 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} - - -for klass in [var for var in globals().values() - if type(var) == types.ClassType and issubclass(var, unittest.TestCase)]: - 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() - #print win32Src - #print macSrc - exec win32Src+'\n' - exec macSrc+'\n' - - if versionTuple >= (2,3): - src = r"class %(name)s_DiffBaseClass(%(name)s): "%locals() - src += " _extraCompileKwArgs = extraCompileKwArgsForDiffBaseclass" - exec src+'\n' - - del name - del klass - -################################################## -## if run from the command line ## - -if __name__ == '__main__': - unittest.main() - -# vim: shiftwidth=4 tabstop=4 expandtab diff --git a/cobbler/Cheetah/Tests/Template.py b/cobbler/Cheetah/Tests/Template.py deleted file mode 100644 index b97cf5d..0000000 --- a/cobbler/Cheetah/Tests/Template.py +++ /dev/null @@ -1,312 +0,0 @@ -#!/usr/bin/env python -# $Id: Template.py,v 1.16 2006/02/03 21:05:50 tavis_rudd Exp $ -"""Tests of the Template class API - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com>, -Version: $Revision: 1.16 $ -Start Date: 2001/10/01 -Last Revision Date: $Date: 2006/02/03 21:05:50 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.16 $"[11:-2] - - -################################################## -## DEPENDENCIES ## - -import sys -import types -import os -import os.path -import tempfile -import shutil -import unittest_local_copy as unittest -from Cheetah.Template import Template - -################################################## -## CONSTANTS & GLOBALS ## - -majorVer, minorVer = sys.version_info[0], sys.version_info[1] -versionTuple = (majorVer, minorVer) - -try: - True,False -except NameError: - True, False = (1==1),(1==0) - -################################################## -## TEST DATA FOR USE IN THE TEMPLATES ## - -################################################## -## TEST BASE CLASSES - -class TemplateTest(unittest.TestCase): - pass - -################################################## -## TEST CASE CLASSES - -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] - - -################################################## -## if run from the command line ## - -if __name__ == '__main__': - unittest.main() diff --git a/cobbler/Cheetah/Tests/Test.py b/cobbler/Cheetah/Tests/Test.py deleted file mode 100644 index 9e46a5d..0000000 --- a/cobbler/Cheetah/Tests/Test.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# $Id: Test.py,v 1.44 2006/01/15 20:45:10 tavis_rudd Exp $ -"""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 - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com>, -License: This software is released for unlimited distribution under the - terms of the MIT license. See the LICENSE file. -Version: $Revision: 1.44 $ -Start Date: 2001/03/30 -Last Revision Date: $Date: 2006/01/15 20:45:10 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.44 $"[11:-2] - - -################################################## -## DEPENDENCIES ## - -import sys -import unittest_local_copy as unittest - -################################################## -## CONSTANTS & GLOBALS - -try: - True, False -except NameError: - True, False = (1==1),(1==0) - -################################################## -## TESTS - -import SyntaxAndOutput -import NameMapper -import Template -import FileRefresh -import CheetahWrapper - -SyntaxSuite = unittest.findTestCases(SyntaxAndOutput) -NameMapperSuite = unittest.findTestCases(NameMapper) -TemplateSuite = unittest.findTestCases(Template) -FileRefreshSuite = unittest.findTestCases(FileRefresh) -if not sys.platform.startswith('java'): - CheetahWrapperSuite = unittest.findTestCases(CheetahWrapper) - -from SyntaxAndOutput import * -from NameMapper import * -from Template import * -from FileRefresh import * - -if not sys.platform.startswith('java'): - from CheetahWrapper import * - -################################################## -## if run from the command line - -if __name__ == '__main__': - unittest.main() - - - diff --git a/cobbler/Cheetah/Tests/__init__.py b/cobbler/Cheetah/Tests/__init__.py deleted file mode 100644 index 792d600..0000000 --- a/cobbler/Cheetah/Tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# diff --git a/cobbler/Cheetah/Tests/unittest_local_copy.py b/cobbler/Cheetah/Tests/unittest_local_copy.py deleted file mode 100644 index 54061ae..0000000 --- a/cobbler/Cheetah/Tests/unittest_local_copy.py +++ /dev/null @@ -1,977 +0,0 @@ -#!/usr/bin/env python -""" This is a hacked version of PyUnit that extends its reporting capabilities -with optional meta data on the test cases. It also makes it possible to -separate the standard and error output streams in TextTestRunner. - -It's a hack rather than a set of subclasses because a) Steve had used double -underscore private attributes for some things I needed access to, and b) the -changes affected so many classes that it was easier just to hack it. - -The changes are in the following places: -TestCase: - - minor refactoring of __init__ and __call__ internals - - added some attributes and methods for storing and retrieving meta data - -_TextTestResult - - refactored the stream handling - - incorporated all the output code from TextTestRunner - - made the output of FAIL and ERROR information more flexible and - incorporated the new meta data from TestCase - - added a flag called 'explain' to __init__ that controls whether the new ' - explanation' meta data from TestCase is printed along with tracebacks - -TextTestRunner - - delegated all output to _TextTestResult - - added 'err' and 'explain' to the __init__ signature to match the changes - in _TextTestResult - -TestProgram - - added -e and --explain as flags on the command line - --- Tavis Rudd <tavis@redonions.net> (Sept 28th, 2001) - -- _TestTextResult.printErrorList(): print blank line after each traceback - --- Mike Orr <mso@oz.net> (Nov 11, 2002) - -TestCase methods copied from unittest in Python 2.3: - - .assertAlmostEqual(first, second, places=7, msg=None): to N decimal places. - - .failIfAlmostEqual(first, second, places=7, msg=None) - --- Mike Orr (Jan 5, 2004) - - -Below is the original docstring for unittest. ---------------------------------------------------------------------------- -Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's -Smalltalk testing framework. - -This module contains the core framework classes that form the basis of -specific test cases and suites (TestCase, TestSuite etc.), and also a -text-based utility class for running the tests and reporting the results -(TextTestRunner). - -Simple usage: - - import unittest - - class IntegerArithmenticTestCase(unittest.TestCase): - def testAdd(self): ## test method names begin 'test*' - self.assertEquals((1 + 2), 3) - self.assertEquals(0 + 1, 1) - def testMultiply(self); - self.assertEquals((0 * 10), 0) - self.assertEquals((5 * 8), 40) - - if __name__ == '__main__': - unittest.main() - -Further information is available in the bundled documentation, and from - - http://pyunit.sourceforge.net/ - -Copyright (c) 1999, 2000, 2001 Steve Purcell -This module is free software, and you may redistribute it and/or modify -it under the same terms as Python itself, so long as this copyright message -and disclaimer are retained in their original form. - -IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, -SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF -THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - -THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, -AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, -SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -""" - -__author__ = "Steve Purcell" -__email__ = "stephen_purcell at yahoo dot com" -__revision__ = "$Revision: 1.11 $"[11:-2] - - -################################################## -## DEPENDENCIES ## - -import os -import re -import string -import sys -import time -import traceback -import types -import pprint - -################################################## -## CONSTANTS & GLOBALS - -try: - True,False -except NameError: - True, False = (1==1),(1==0) - -############################################################################## -# Test framework core -############################################################################## - - -class TestResult: - """Holder for test result information. - - Test results are automatically managed by the TestCase and TestSuite - classes, and do not need to be explicitly manipulated by writers of tests. - - Each instance holds the total number of tests run, and collections of - failures and errors that occurred among those test runs. The collections - contain tuples of (testcase, exceptioninfo), where exceptioninfo is a - tuple of values as returned by sys.exc_info(). - """ - def __init__(self): - self.failures = [] - self.errors = [] - self.testsRun = 0 - self.shouldStop = 0 - - def startTest(self, test): - "Called when the given test is about to be run" - self.testsRun = self.testsRun + 1 - - def stopTest(self, test): - "Called when the given test has been run" - pass - - def addError(self, test, err): - "Called when an error has occurred" - self.errors.append((test, err)) - - def addFailure(self, test, err): - "Called when a failure has occurred" - self.failures.append((test, err)) - - def addSuccess(self, test): - "Called when a test has completed successfully" - pass - - def wasSuccessful(self): - "Tells whether or not this result was a success" - return len(self.failures) == len(self.errors) == 0 - - def stop(self): - "Indicates that the tests should be aborted" - self.shouldStop = 1 - - def __repr__(self): - return "<%s run=%i errors=%i failures=%i>" % \ - (self.__class__, self.testsRun, len(self.errors), - len(self.failures)) - -class TestCase: - """A class whose instances are single test cases. - - By default, the test code itself should be placed in a method named - 'runTest'. - - If the fixture may be used for many test cases, create as - many test methods as are needed. When instantiating such a TestCase - subclass, specify in the constructor arguments the name of the test method - that the instance is to execute. - - Test authors should subclass TestCase for their own tests. Construction - and deconstruction of the test's environment ('fixture') can be - implemented by overriding the 'setUp' and 'tearDown' methods respectively. - - If it is necessary to override the __init__ method, the base class - __init__ method must always be called. It is important that subclasses - should not change the signature of their __init__ method, since instances - of the classes are instantiated automatically by parts of the framework - in order to be run. - """ - - # This attribute determines which exception will be raised when - # the instance's assertion methods fail; test methods raising this - # exception will be deemed to have 'failed' rather than 'errored' - - failureException = AssertionError - - # the name of the fixture. Used for displaying meta data about the test - name = None - - def __init__(self, methodName='runTest'): - """Create an instance of the class that will use the named test - method when executed. Raises a ValueError if the instance does - not have a method with the specified name. - """ - self._testMethodName = methodName - self._setupTestMethod() - self._setupMetaData() - - def _setupTestMethod(self): - try: - self._testMethod = getattr(self, self._testMethodName) - except AttributeError: - raise ValueError, "no such test method in %s: %s" % \ - (self.__class__, self._testMethodName) - - ## meta data methods - - def _setupMetaData(self): - """Setup the default meta data for the test case: - - - id: self.__class__.__name__ + testMethodName OR self.name + testMethodName - - description: 1st line of Class docstring + 1st line of method docstring - - explanation: rest of Class docstring + rest of method docstring - - """ - - - testDoc = self._testMethod.__doc__ or '\n' - testDocLines = testDoc.splitlines() - - testDescription = testDocLines[0].strip() - if len(testDocLines) > 1: - testExplanation = '\n'.join( - [ln.strip() for ln in testDocLines[1:]] - ).strip() - else: - testExplanation = '' - - fixtureDoc = self.__doc__ or '\n' - fixtureDocLines = fixtureDoc.splitlines() - fixtureDescription = fixtureDocLines[0].strip() - if len(fixtureDocLines) > 1: - fixtureExplanation = '\n'.join( - [ln.strip() for ln in fixtureDocLines[1:]] - ).strip() - else: - fixtureExplanation = '' - - if not self.name: - self.name = self.__class__ - self._id = "%s.%s" % (self.name, self._testMethodName) - - if not fixtureDescription: - self._description = testDescription - else: - self._description = fixtureDescription + ', ' + testDescription - - if not fixtureExplanation: - self._explanation = testExplanation - else: - self._explanation = ['Fixture Explanation:', - '--------------------', - fixtureExplanation, - '', - 'Test Explanation:', - '-----------------', - testExplanation - ] - self._explanation = '\n'.join(self._explanation) - - def id(self): - return self._id - - def setId(self, id): - self._id = id - - def describe(self): - """Returns a one-line description of the test, or None if no - description has been provided. - - The default implementation of this method returns the first line of - the specified test method's docstring. - """ - return self._description - - shortDescription = describe - - def setDescription(self, descr): - self._description = descr - - def explain(self): - return self._explanation - - def setExplanation(self, expln): - self._explanation = expln - - ## core methods - - def setUp(self): - "Hook method for setting up the test fixture before exercising it." - pass - - def run(self, result=None): - return self(result) - - def tearDown(self): - "Hook method for deconstructing the test fixture after testing it." - pass - - def debug(self): - """Run the test without collecting errors in a TestResult""" - self.setUp() - self._testMethod() - self.tearDown() - - ## internal methods - - def defaultTestResult(self): - return TestResult() - - def __call__(self, result=None): - if result is None: - result = self.defaultTestResult() - - result.startTest(self) - try: - try: - self.setUp() - except: - result.addError(self, self.__exc_info()) - return - - ok = 0 - try: - self._testMethod() - ok = 1 - except self.failureException, e: - result.addFailure(self, self.__exc_info()) - except: - result.addError(self, self.__exc_info()) - try: - self.tearDown() - except: - result.addError(self, self.__exc_info()) - ok = 0 - if ok: - result.addSuccess(self) - finally: - result.stopTest(self) - - return result - - def countTestCases(self): - return 1 - - def __str__(self): - return "%s (%s)" % (self._testMethodName, self.__class__) - - def __repr__(self): - return "<%s testMethod=%s>" % \ - (self.__class__, self._testMethodName) - - def __exc_info(self): - """Return a version of sys.exc_info() with the traceback frame - minimised; usually the top level of the traceback frame is not - needed. - """ - exctype, excvalue, tb = sys.exc_info() - if sys.platform[:4] == 'java': ## tracebacks look different in Jython - return (exctype, excvalue, tb) - newtb = tb.tb_next - if newtb is None: - return (exctype, excvalue, tb) - return (exctype, excvalue, newtb) - - ## methods for use by the test cases - - def fail(self, msg=None): - """Fail immediately, with the given message.""" - raise self.failureException, msg - - def failIf(self, expr, msg=None): - "Fail the test if the expression is true." - if expr: raise self.failureException, msg - - def failUnless(self, expr, msg=None): - """Fail the test unless the expression is true.""" - if not expr: raise self.failureException, msg - - def failUnlessRaises(self, excClass, callableObj, *args, **kwargs): - """Fail unless an exception of class excClass is thrown - by callableObj when invoked with arguments args and keyword - arguments kwargs. If a different type of exception is - thrown, it will not be caught, and the test case will be - deemed to have suffered an error, exactly as for an - unexpected exception. - """ - try: - apply(callableObj, args, kwargs) - except excClass: - return - else: - if hasattr(excClass,'__name__'): excName = excClass.__name__ - else: excName = str(excClass) - raise self.failureException, excName - - def failUnlessEqual(self, first, second, msg=None): - """Fail if the two objects are unequal as determined by the '!=' - operator. - """ - if first != second: - raise self.failureException, (msg or '%s != %s' % (first, second)) - - def failIfEqual(self, first, second, msg=None): - """Fail if the two objects are equal as determined by the '==' - operator. - """ - if first == second: - raise self.failureException, (msg or '%s == %s' % (first, second)) - - def failUnlessAlmostEqual(self, first, second, places=7, msg=None): - """Fail if the two objects are unequal as determined by their - difference rounded to the given number of decimal places - (default 7) and comparing to zero. - - Note that decimal places (from zero) is usually not the same - as significant digits (measured from the most signficant digit). - """ - if round(second-first, places) != 0: - raise self.failureException, \ - (msg or '%s != %s within %s places' % (`first`, `second`, `places` )) - - def failIfAlmostEqual(self, first, second, places=7, msg=None): - """Fail if the two objects are equal as determined by their - difference rounded to the given number of decimal places - (default 7) and comparing to zero. - - Note that decimal places (from zero) is usually not the same - as significant digits (measured from the most signficant digit). - """ - if round(second-first, places) == 0: - raise self.failureException, \ - (msg or '%s == %s within %s places' % (`first`, `second`, `places`)) - - ## aliases - - assertEqual = assertEquals = failUnlessEqual - - assertNotEqual = assertNotEquals = failIfEqual - - assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual - - assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual - - assertRaises = failUnlessRaises - - assert_ = failUnless - - -class FunctionTestCase(TestCase): - """A test case that wraps a test function. - - This is useful for slipping pre-existing test functions into the - PyUnit framework. Optionally, set-up and tidy-up functions can be - supplied. As with TestCase, the tidy-up ('tearDown') function will - always be called if the set-up ('setUp') function ran successfully. - """ - - def __init__(self, testFunc, setUp=None, tearDown=None, - description=None): - TestCase.__init__(self) - self.__setUpFunc = setUp - self.__tearDownFunc = tearDown - self.__testFunc = testFunc - self.__description = description - - def setUp(self): - if self.__setUpFunc is not None: - self.__setUpFunc() - - def tearDown(self): - if self.__tearDownFunc is not None: - self.__tearDownFunc() - - def runTest(self): - self.__testFunc() - - def id(self): - return self.__testFunc.__name__ - - def __str__(self): - return "%s (%s)" % (self.__class__, self.__testFunc.__name__) - - def __repr__(self): - return "<%s testFunc=%s>" % (self.__class__, self.__testFunc) - - - def describe(self): - if self.__description is not None: return self.__description - doc = self.__testFunc.__doc__ - return doc and string.strip(string.split(doc, "\n")[0]) or None - - ## aliases - shortDescription = describe - -class TestSuite: - """A test suite is a composite test consisting of a number of TestCases. - - For use, create an instance of TestSuite, then add test case instances. - When all tests have been added, the suite can be passed to a test - runner, such as TextTestRunner. It will run the individual test cases - in the order in which they were added, aggregating the results. When - subclassing, do not forget to call the base class constructor. - """ - def __init__(self, tests=(), suiteName=None): - self._tests = [] - self._testMap = {} - self.suiteName = suiteName - self.addTests(tests) - - def __repr__(self): - return "<%s tests=%s>" % (self.__class__, pprint.pformat(self._tests)) - - __str__ = __repr__ - - def countTestCases(self): - cases = 0 - for test in self._tests: - cases = cases + test.countTestCases() - return cases - - def addTest(self, test): - self._tests.append(test) - if isinstance(test, TestSuite) and test.suiteName: - name = test.suiteName - elif isinstance(test, TestCase): - #print test, test._testMethodName - name = test._testMethodName - else: - name = test.__class__.__name__ - self._testMap[name] = test - - def addTests(self, tests): - for test in tests: - self.addTest(test) - - def getTestForName(self, name): - return self._testMap[name] - - def run(self, result): - return self(result) - - def __call__(self, result): - for test in self._tests: - if result.shouldStop: - break - test(result) - return result - - def debug(self): - """Run the tests without collecting errors in a TestResult""" - for test in self._tests: test.debug() - - -############################################################################## -# Text UI -############################################################################## - -class StreamWrapper: - def __init__(self, out=sys.stdout, err=sys.stderr): - self._streamOut = out - self._streamErr = err - - def write(self, txt): - self._streamOut.write(txt) - self._streamOut.flush() - - def writeln(self, *lines): - for line in lines: - self.write(line + '\n') - if not lines: - self.write('\n') - - def writeErr(self, txt): - self._streamErr.write(txt) - - def writelnErr(self, *lines): - for line in lines: - self.writeErr(line + '\n') - if not lines: - self.writeErr('\n') - - -class _TextTestResult(TestResult, StreamWrapper): - _separatorWidth = 70 - _sep1 = '=' - _sep2 = '-' - _errorSep1 = '*' - _errorSep2 = '-' - _errorSep3 = '' - - def __init__(self, - stream=sys.stdout, - errStream=sys.stderr, - verbosity=1, - explain=False): - - TestResult.__init__(self) - StreamWrapper.__init__(self, out=stream, err=errStream) - - self._verbosity = verbosity - self._showAll = verbosity > 1 - self._dots = (verbosity == 1) - self._explain = explain - - ## startup and shutdown methods - - def beginTests(self): - self._startTime = time.time() - - def endTests(self): - self._stopTime = time.time() - self._timeTaken = float(self._stopTime - self._startTime) - - def stop(self): - self.shouldStop = 1 - - ## methods called for each test - - def startTest(self, test): - TestResult.startTest(self, test) - if self._showAll: - self.write("%s (%s)" %( test.id(), test.describe() ) ) - self.write(" ... ") - - def addSuccess(self, test): - TestResult.addSuccess(self, test) - if self._showAll: - self.writeln("ok") - elif self._dots: - self.write('.') - - def addError(self, test, err): - TestResult.addError(self, test, err) - if self._showAll: - self.writeln("ERROR") - elif self._dots: - self.write('E') - if err[0] is KeyboardInterrupt: - self.stop() - - def addFailure(self, test, err): - TestResult.addFailure(self, test, err) - if self._showAll: - self.writeln("FAIL") - elif self._dots: - self.write('F') - - ## display methods - - def summarize(self): - self.printErrors() - self.writeSep2() - run = self.testsRun - self.writeln("Ran %d test%s in %.3fs" % - (run, run == 1 and "" or "s", self._timeTaken)) - self.writeln() - if not self.wasSuccessful(): - self.writeErr("FAILED (") - failed, errored = map(len, (self.failures, self.errors)) - if failed: - self.writeErr("failures=%d" % failed) - if errored: - if failed: self.writeErr(", ") - self.writeErr("errors=%d" % errored) - self.writelnErr(")") - else: - self.writelnErr("OK") - - def writeSep1(self): - self.writeln(self._sep1 * self._separatorWidth) - - def writeSep2(self): - self.writeln(self._sep2 * self._separatorWidth) - - def writeErrSep1(self): - self.writeln(self._errorSep1 * self._separatorWidth) - - def writeErrSep2(self): - self.writeln(self._errorSep2 * self._separatorWidth) - - def printErrors(self): - if self._dots or self._showAll: - self.writeln() - self.printErrorList('ERROR', self.errors) - self.printErrorList('FAIL', self.failures) - - def printErrorList(self, flavour, errors): - for test, err in errors: - self.writeErrSep1() - self.writelnErr("%s %s (%s)" % (flavour, test.id(), test.describe() )) - if self._explain: - expln = test.explain() - if expln: - self.writeErrSep2() - self.writeErr( expln ) - self.writelnErr() - - self.writeErrSep2() - for line in apply(traceback.format_exception, err): - for l in line.split("\n")[:-1]: - self.writelnErr(l) - self.writelnErr("") - -class TextTestRunner: - def __init__(self, - stream=sys.stdout, - errStream=sys.stderr, - verbosity=1, - explain=False): - - self._out = stream - self._err = errStream - self._verbosity = verbosity - self._explain = explain - - ## main methods - - def run(self, test): - result = self._makeResult() - result.beginTests() - test( result ) - result.endTests() - result.summarize() - - return result - - ## internal methods - - def _makeResult(self): - return _TextTestResult(stream=self._out, - errStream=self._err, - verbosity=self._verbosity, - explain=self._explain, - ) - -############################################################################## -# Locating and loading tests -############################################################################## - -class TestLoader: - """This class is responsible for loading tests according to various - criteria and returning them wrapped in a Test - """ - testMethodPrefix = 'test' - sortTestMethodsUsing = cmp - suiteClass = TestSuite - - def loadTestsFromTestCase(self, testCaseClass): - """Return a suite of all tests cases contained in testCaseClass""" - return self.suiteClass(tests=map(testCaseClass, - self.getTestCaseNames(testCaseClass)), - suiteName=testCaseClass.__name__) - - def loadTestsFromModule(self, module): - """Return a suite of all tests cases contained in the given module""" - tests = [] - for name in dir(module): - obj = getattr(module, name) - if type(obj) == types.ClassType and issubclass(obj, TestCase): - tests.append(self.loadTestsFromTestCase(obj)) - return self.suiteClass(tests) - - def loadTestsFromName(self, name, module=None): - """Return a suite of all tests cases given a string specifier. - - The name may resolve either to a module, a test case class, a - test method within a test case class, or a callable object which - returns a TestCase or TestSuite instance. - - The method optionally resolves the names relative to a given module. - """ - parts = string.split(name, '.') - if module is None: - if not parts: - raise ValueError, "incomplete test name: %s" % name - else: - parts_copy = parts[:] - while parts_copy: - try: - module = __import__(string.join(parts_copy,'.')) - break - except ImportError: - del parts_copy[-1] - if not parts_copy: raise - parts = parts[1:] - obj = module - for part in parts: - if isinstance(obj, TestSuite): - obj = obj.getTestForName(part) - else: - obj = getattr(obj, part) - - if type(obj) == types.ModuleType: - return self.loadTestsFromModule(obj) - elif type(obj) == types.ClassType and issubclass(obj, TestCase): - return self.loadTestsFromTestCase(obj) - elif type(obj) == types.UnboundMethodType: - return obj.im_class(obj.__name__) - elif isinstance(obj, TestSuite): - return obj - elif isinstance(obj, TestCase): - return obj - elif callable(obj): - test = obj() - if not isinstance(test, TestCase) and \ - not isinstance(test, TestSuite): - raise ValueError, \ - "calling %s returned %s, not a test" %(obj,test) - return test - else: - raise ValueError, "don't know how to make test from: %s" % obj - - def loadTestsFromNames(self, names, module=None): - """Return a suite of all tests cases found using the given sequence - of string specifiers. See 'loadTestsFromName()'. - """ - suites = [] - for name in names: - suites.append(self.loadTestsFromName(name, module)) - return self.suiteClass(suites) - - def getTestCaseNames(self, testCaseClass): - """Return a sorted sequence of method names found within testCaseClass. - """ - testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p, - dir(testCaseClass)) - for baseclass in testCaseClass.__bases__: - for testFnName in self.getTestCaseNames(baseclass): - if testFnName not in testFnNames: # handle overridden methods - testFnNames.append(testFnName) - if self.sortTestMethodsUsing: - testFnNames.sort(self.sortTestMethodsUsing) - return testFnNames - - - -defaultTestLoader = TestLoader() - - -############################################################################## -# Patches for old functions: these functions should be considered obsolete -############################################################################## - -def _makeLoader(prefix, sortUsing, suiteClass=None): - loader = TestLoader() - loader.sortTestMethodsUsing = sortUsing - loader.testMethodPrefix = prefix - if suiteClass: loader.suiteClass = suiteClass - return loader - -def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): - return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) - -def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite): - return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) - -def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite): - return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) - -############################################################################## -# Facilities for running tests from the command line -############################################################################## - -class TestProgram: - """A command-line program that runs a set of tests; this is primarily - for making test modules conveniently executable. - """ - USAGE = """\ -Usage: %(progName)s [options] [test] [...] - -Options: - -h, --help Show this message - -v, --verbose Verbose output - -q, --quiet Minimal output - -e, --expain Output extra test details if there is a failure or error - -Examples: - %(progName)s - run default set of tests - %(progName)s MyTestSuite - run suite 'MyTestSuite' - %(progName)s MyTestSuite.MyTestCase - run suite 'MyTestSuite' - %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething - %(progName)s MyTestCase - run all 'test*' test methods - in MyTestCase -""" - def __init__(self, module='__main__', defaultTest=None, - argv=None, testRunner=None, testLoader=defaultTestLoader, - testSuite=None): - if type(module) == type(''): - self.module = __import__(module) - for part in string.split(module,'.')[1:]: - self.module = getattr(self.module, part) - else: - self.module = module - if argv is None: - argv = sys.argv - self.test = testSuite - self.verbosity = 1 - self.explain = 0 - self.defaultTest = defaultTest - self.testRunner = testRunner - self.testLoader = testLoader - self.progName = os.path.basename(argv[0]) - self.parseArgs(argv) - self.runTests() - - def usageExit(self, msg=None): - if msg: print msg - print self.USAGE % self.__dict__ - sys.exit(2) - - def parseArgs(self, argv): - import getopt - try: - options, args = getopt.getopt(argv[1:], 'hHvqer', - ['help','verbose','quiet','explain', 'raise']) - for opt, value in options: - if opt in ('-h','-H','--help'): - self.usageExit() - if opt in ('-q','--quiet'): - self.verbosity = 0 - if opt in ('-v','--verbose'): - self.verbosity = 2 - if opt in ('-e','--explain'): - self.explain = True - if len(args) == 0 and self.defaultTest is None and self.test is None: - self.test = self.testLoader.loadTestsFromModule(self.module) - return - if len(args) > 0: - self.testNames = args - else: - self.testNames = (self.defaultTest,) - self.createTests() - except getopt.error, msg: - self.usageExit(msg) - - def createTests(self): - if self.test == None: - self.test = self.testLoader.loadTestsFromNames(self.testNames, - self.module) - - def runTests(self): - if self.testRunner is None: - self.testRunner = TextTestRunner(verbosity=self.verbosity, - explain=self.explain) - result = self.testRunner.run(self.test) - self._cleanupAfterRunningTests() - sys.exit(not result.wasSuccessful()) - - def _cleanupAfterRunningTests(self): - """A hook method that is called immediately prior to calling - sys.exit(not result.wasSuccessful()) in self.runTests(). - """ - pass - -main = TestProgram - - -############################################################################## -# Executing this module from the command line -############################################################################## - -if __name__ == "__main__": - main(module=None) - -# vim: shiftwidth=4 tabstop=4 expandtab diff --git a/cobbler/Cheetah/Tools/CGITemplate.py b/cobbler/Cheetah/Tools/CGITemplate.py deleted file mode 100644 index b72e62b..0000000 --- a/cobbler/Cheetah/Tools/CGITemplate.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# $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 = os.environ.has_key('REQUEST_METHOD') - wk = self._CHEETAH__isControlledByWebKit - return env and not wk - - - -# vim: shiftwidth=4 tabstop=4 expandtab diff --git a/cobbler/Cheetah/Tools/MondoReport.py b/cobbler/Cheetah/Tools/MondoReport.py deleted file mode 100644 index f73e7fc..0000000 --- a/cobbler/Cheetah/Tools/MondoReport.py +++ /dev/null @@ -1,464 +0,0 @@ -#!/usr/bin/env python -""" -@@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, types -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. - -########## CONSTANTS ############################## - -True, False = (1==1), (1==0) -numericTypes = types.IntType, types.LongType, types.FloatType - -########## PUBLIC GENERIC FUNCTIONS ############################## - -class NegativeError(ValueError): - pass - -def isNumeric(v): - return type(v) in numericTypes - -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 = lis[:] - lis.sort() - 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 = 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): - raiseNotImplementedError() - - def variance_n(self, field=None): - raiseNotImplementedError() - - def standardDeviation(self, field=None): - raiseNotImplementedError() - - def standardDeviation_n(self, field=None): - raiseNotImplementedError() - - -class PrevNextPage: - def __init__(self, origList, size, start): - end = start + size - self.start = IndexFormats(start, origList[start]) - self.end = IndexFormats(end, origList[end]) - self.length = size - - -########## MAIN PUBLIC CLASS ############################## -class MondoReport: - _RecordStatsClass = RecordStats - _SummaryClass = Summary - - def __init__(self, origlist): - self._origList = origlist - - def page(self, size, start, overlap=0, orphan=0): - """Returns list of ($r, $a, $b) - """ - if overlap != 0: - raise NotImplementedError("non-zero overlap") - if orphan != 0: - raise NotImplementedError("non-zero orphan") - origList = self._origList - origList_len = len(origList) - start = max(0, start) - end = min( start + size, len(self._origList) ) - mySlice = origList[start:end] - ret = [] - for rel in range(size): - abs_ = start + rel - r = mySlice[rel] - a = self._RecordStatsClass(origList, abs_) - b = self._RecordStatsClass(mySlice, rel) - tup = r, a, b - ret.append(tup) - return ret - - - batch = page - - def all(self): - origList_len = len(self._origList) - return self.page(origList_len, 0, 0, 0) - - - def summary(self): - return self._SummaryClass(self._origList) - -""" -********************************** - Return a pageful of records from a sequence, with statistics. - - in : origlist, list or tuple. The entire set of records. This is - usually a list of objects or a list of dictionaries. - page, int >= 0. Which page to display. - size, int >= 1. How many records per page. - widow, int >=0. Not implemented. - orphan, int >=0. Not implemented. - base, int >=0. Number of first page (usually 0 or 1). - - out: list of (o, b) pairs. The records for the current page. 'o' is - the original element from 'origlist' unchanged. 'b' is a Batch - object containing meta-info about 'o'. - exc: IndexError if 'page' or 'size' is < 1. If 'origlist' is empty or - 'page' is too high, it returns an empty list rather than raising - an error. - - origlist_len = len(origlist) - start = (page + base) * size - end = min(start + size, origlist_len) - ret = [] - # widow, orphan calculation: adjust 'start' and 'end' up and down, - # Set 'widow', 'orphan', 'first_nonwidow', 'first_nonorphan' attributes. - for i in range(start, end): - o = origlist[i] - b = Batch(origlist, size, i) - tup = o, b - ret.append(tup) - return ret - - def prev(self): - # return a PrevNextPage or None - - def next(self): - # return a PrevNextPage or None - - def prev_batches(self): - # return a list of SimpleBatch for the previous batches - - def next_batches(self): - # return a list of SimpleBatch for the next batches - -########## PUBLIC MIXIN CLASS FOR CHEETAH TEMPLATES ############## -class MondoReportMixin: - def batch(self, origList, size=None, start=0, overlap=0, orphan=0): - bat = MondoReport(origList) - return bat.batch(size, start, overlap, orphan) - def batchstats(self, origList): - bat = MondoReport(origList) - return bat.stats() -""" - -# vim: shiftwidth=4 tabstop=4 expandtab textwidth=79 diff --git a/cobbler/Cheetah/Tools/MondoReportDoc.txt b/cobbler/Cheetah/Tools/MondoReportDoc.txt deleted file mode 100644 index 29a026d..0000000 --- a/cobbler/Cheetah/Tools/MondoReportDoc.txt +++ /dev/null @@ -1,391 +0,0 @@ -MondoReport Documentation -Version 0.01 alpha 24-Nov-2001. iron@mso.oz.net or mso@oz.net. -Copyright (c) 2001 Mike Orr. License: same as Python or Cheetah. - -* * * * * -STATUS: previous/next batches and query string are not implemented yet. -Sorting not designed yet. Considering "click on this column header to sort by -this field" and multiple ascending/descending sort fields for a future version. - -Tested with Python 2.2b1. May work with Python 2.1 or 2.0. - -* * * * * -OVERVIEW - -MondoReport -- provide information about a list that is useful in generating -any kind of report. The module consists of one main public class, and some -generic functions you may find useful in other programs. This file contains an -overview, syntax reference and examples. The module is designed both for -standalone use and for integration with the Cheetah template system -(http://www.cheetahtemplate.org/), so the examples are in both Python and -Cheetah. The main uses of MondoReport are: - -(A) to iterate through a list. In this sense MR is a for-loop enhancer, -providing information that would be verbose to calculate otherwise. - -(B) to separate a list into equal-size "pages" (or "batches"--the two terms are -interchangeable) and only display the current page, plus limited information -about the previous and next pages. - -(C) to extract summary statistics about a certain column ("field") in the list. - -* * * * * -MAIN PUBLIC CLASS - -To create a MondoReport instance, supply a list to operate on. - - mr = MondoReport(origList) - -The list may be a list of anything, but if you use the 'field' argument in any -of the methods below, the elements must be instances or dictionaries. - -MondoReport assumes it's operating on an unchanging list. Do not modify the -list or any of its elements until you are completely finished with the -ModoReport object and its sub-objects. Otherwise, you may get an exception or -incorrect results. - -MondoReport instances have three methods: - - .page(size, start, overlap=0, orphan=0 - sort=None, reverse=False) => list of (r, a, b). - -'size' is an integer >= 1. 'start', 'overlap' and 'orphan' are integers >= 0. -The list returned contains one triple for each record in the current page. 'r' -is the original record. 'a' is a BatchRecord instance for the current record -in relation to all records in the origList. 'b' is a BatchRecord instance for -the current record in relation to all the records in that batch/page. (There -is a .batch method that's identical to .page.) - -The other options aren't implemented yet, but 'overlap' duplicates this many -records on adjacent batches. 'orphan' moves this many records or fewer, if -they are on a page alone, onto the neighboring page. 'sort' (string) specifies -a field to sort the records by. It may be suffixed by ":desc" to sort in -descending order. 'reverse' (boolean) reverses the sort order. If both -":desc" and 'reverse' are specified, they will cancel each other out. This -sorting/reversal happens on a copy of the origList, and all objects returned -by this method use the sorted list, except when resorting the next time. -To do more complicated sorting, such as a hierarchy of columns, do it to the -original list before creating the ModoReport object. - - .all(sort=None, reverse=False) => list of (r, a). - -Same, but the current page spans the entire origList. - - .summary() => Summary instance. - -Summary statistics for the entire origList. - -In Python, use .page or .all in a for loop: - - from Cheetah.Tools.MondoReport import MondoReport - mr = MondoReport(myList) - for r, a, b in mr.page(20, 40): - # Do something with r, a and b. The current page is the third page, - # with twenty records corresponding to origList[40:60]. - if not myList: - # Warn the user there are no records in the list. - -It works the same way in Cheetah, just convert to Cheetah syntax. This example -assumes the template doubles as a Webware servlet, so we use the servlet's -'$request' method to look up the CGI parameter 'start'. The default value is 0 -for the first page. - - #from Cheetah.Tools.MondoReport import MondoReport - #set $mr = $MondoReport($bigList) - #set $start = $request.field("start", 0) - #for $o, $a, $b in $mr.page(20, $start) - ... do something with $o, $a and $b ... - #end for - #unless $bigList - This is displayed if the original list has no elements. - It's equivalent to the "else" part Zope DTML's <dtml-in>. - #end unless - -* * * * * -USING 'r' RECORDS - -Use 'r' just as you would the original element. For instance: - - print r.attribute # If r is an instance. - print r['key'] # If r is a dictionary. - print r # If r is numeric or a string. - -In Cheetah, you can take advantage of Universal Dotted Notation and autocalling: - - $r.name ## 'name' may be an attribute or key of 'r'. If 'r' and/or - ## 'name' is a function or method, it will be called without - ## arguments. - $r.attribute - $r['key'] - $r - $r().attribute()['key']() - -If origList is a list of name/value pairs (2-tuples or 2-lists), you may -prefer to do this: - - for (key, value), a, b in mr.page(20, 40): - print key, "=>", value - - #for ($key, $value), $a, $b in $mr.page(20, $start) - $key => $value - #end for - -* * * * * -STATISTICS METHODS AND FIELD VALUES - -Certain methods below have an optional argument 'field'. If specified, -MondoReport will look up that field in each affected record and use its value -in the calculation. MondoReport uses Cheetah's NameMapper if available, -otherwise it uses a minimal NameMapper substitute that looks for an attribute -or dictionary key called "field". You'll get an exception if any record is a -type without attributes or keys, or if one or more records is missing that -attribute/key. - -If 'field' is None, MondoReport will use the entire record in its -calculation. This makes sense mainly if the records are a numeric type. - -All statistics methods filter out None values from their calculations, and -reduce the number of records accordingly. Most filter out non-numeric fields -(or records). Some raise NegativeError if a numeric field (or record) is -negative. - - -* * * * * -BatchRecord METHODS - -The 'a' and 'b' objects of MondoReport.page() and MondoReport.all() provide -these methods. - - .index() - -The current subscript. For 'a', this is the true subscript into origList. -For 'b', this is relative to the current page, so the first record will be 0. -Hint: In Cheetah, use autocalling to skip the parentheses: '$b.index'. - - .number() - -The record's position starting from 1. This is always '.index() + 1'. - - .Letter() - -The letter ("A", "B", "C") corresponding to .number(). Undefined if .number() -> 26. The current implementation just adds the offset to 'a' and returns -whatever character it happens to be. - -To make a less dumb implementation (e.g., "Z, AA, BB" or "Z, A1, B1"): -1) Subclass BatchRecord and override the .Letter method. -2) Subclass MondoReport and set the class variable .BatchRecordClass to your -new improved class. - - .letter() - -Same but lower case. - - .Roman() - -The Roman numeral corresponding to .number(). - - .roman() - -Same but lower case. - - .even() - -True if .number() is even. - - .odd() - -True if .number() is odd. - - .even_i() - -True if .index() is even. - - .odd_i() - -True if .index() is odd. - - .length() - -For 'a', number of records in origList. For 'b', number of records on this -page. - - .item() - -The record itself. You don't need this in the normal case since it's the same -as 'r', but it's useful for previous/next batches. - - .size() - -The 'size' argument used when this BatchRecord was created. -'a.size() == b.size()'. - - .first() - -True if this is the first record. - - .last() - -True if this is the last record. - - .firstValue(field=None) - -True if there is no previous record, or if the previous field/record has a -different value. Used for to print section headers. For instance, if you -are printing addresses by country, this will be true at the first occurrance -of each country. Or for indexes, you can have a non-printing field showing -which letter of the alphablet this entry starts with, and then print a "B" -header before printing the first record starting with "B". - - .lastValue(field=None) - -True if this is the last record containing the current value in the -field/record. - - .percentOfTotal(field=None, suffix="%", default="N/A", decimals=2) - -Returns the percent that the current field/record is of all fields/records. -If 'suffix' is None, returns a number; otherwise it returns a string with -'suffix' suffixed. If the current value is non-numeric, returns 'default' -instead (without 'suffix'). 'decimals' tells the number of decimal places to -return; if 0, there will be no decimal point. - - .prev() - -Returns a PrevNextBatch instance for the previous page. If there is no -previous page, returns None. [Not implemented yet.] - - .next() - -Returns a PrevNextBatch instance for the next page. If there is no next page, -returns None. [Not implemented yet.] - - .prevPages() - -Returns a list of PrevNextPage instances for every previous page, or [] if no -previous pages. [Not implemented yet.] - - .nextPages() - -Returns a list of PrevNextPage instances for every next page, or [] if no next -pages. [Not implemented yet.] - - .query(start=None, label=None, attribName="start", attribs=[]) - -[Not implemented yet.] - -With no arguments, returns the HTML query string with start value removed (so -you can append a new start value in your hyperlink). The query string is taken -from the 'QUERY_STRING' environmental variable, or "" if missing. (This is -Webware compatible.) - -With 'start' (an integer >= 0), returns the query string with an updated start -value, normally for the next or previous batch. - -With 'label' (a string), returns a complete HTML hyperlink: -'<A HREF="?new_query_string">label</A>'. You'll get a TypeError if you specify -'label' but not 'start'. - -With 'attribName' (a string), uses this attribute name rather than "start". -Useful if you have another CGI parameter "start" that's used for something -else. - -With 'attribs' (a dictionary), adds these attributes to the hyperlink. -For instance, 'attribs={"target": "_blank"}'. Ignored unless 'label' is -specified too. - -This method assumes the start parameter is a GET variable, not a POST variable. - - .summary() - -Returns a Summary instance. 'a.summary()' refers to all records in the -origList, so it's the same as MondoReport.summary(). 'b.summary()' refers only -to the records on the current page. [Not implemented yet.] - -* * * * * -PrevNextPage INSTANCES - -[Not implemented yet.] - -PrevNextPage instances have the following methods: - - .start() - -The index (true index of origList) that that page starts at. You may also use -'.start().index()', '.start().number()', etc. Also -'.start().item(field=None)'. (Oh, so *that*'s what .item is for!) - - .end() - -The index (true index of origList) that that page ends at. You may also use -'.end().index()', '.end().number()', etc. Also -'.end().item(field=None)'. - - .length() - -Number of records on that page. - - .query(label=None, attribName="start", attribs={}, before="", after="") - -[Not implemented yet.] - -Similar to 'a.query()' and 'b.query()', but automatically calculates the start -value for the appropriate page. - -For fancy HTML formatting, 'before' is prepended to the returned text and -'after' is appended. (There was an argument 'else_' for if there is no such -batch, but it was removed because you can't even get to this method at all in -that case.) - -* * * * * * -SUMMARY STATISTICS - -These methods are supported by the Summary instances returned by -MondoReport.Summary(): - - .sum(field=None) - -Sum of all numeric values in a field, or sum of all records. - - .total(field=None) - -Same. - - .count(field=None) - -Number of fields/records with non-None values. - - .min(field=None) - -Minimum value in that field/record. Ignores None values. - - .max(field=None) - -Maximum value in that field/record. Ignores None values. - - .mean(field=None) - -The mean (=average) of all numeric values in that field/record. - - .average(field=None) - -Same. - - .median(field=None) - -The median of all numeric values in that field/record. This is done by sorting -the values and taking the middle value. - - .variance(field=None), .variance_n(field=None) - .standardDeviation(field=None), .standardDeviation_n(field=None) - -[Not implemented yet.] - - -* * * * * -To run the regression tests (requires unittest.py, which is standard with -Python 2.2), run MondoReportTest.py from the command line. The regression test -double as usage examples. - - -# vim: shiftwidth=4 tabstop=4 expandtab textwidth=79 diff --git a/cobbler/Cheetah/Tools/RecursiveNull.py b/cobbler/Cheetah/Tools/RecursiveNull.py deleted file mode 100644 index 4897d80..0000000 --- a/cobbler/Cheetah/Tools/RecursiveNull.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -"""Nothing, but in a friendly way. Good for filling in for objects you want to -hide. If $form.f1 is a RecursiveNull object, then -$form.f1.anything["you"].might("use") will resolve to the empty string. - -This module was contributed by Ian Bicking. -""" - -class RecursiveNull: - __doc__ = __doc__ # Use the module's docstring for the class's docstring. - def __getattr__(self, attr): - return self - def __getitem__(self, item): - return self - def __call__(self, *vars, **kw): - return self - def __str__(self): - return '' - def __repr__(self): - return '' - def __nonzero__(self): - return 0 - diff --git a/cobbler/Cheetah/Tools/SiteHierarchy.py b/cobbler/Cheetah/Tools/SiteHierarchy.py deleted file mode 100644 index d4a92e1..0000000 --- a/cobbler/Cheetah/Tools/SiteHierarchy.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python -# $Id: SiteHierarchy.py,v 1.1 2001/10/11 03:25:54 tavis_rudd Exp $ -"""Create menus and crumbs from a site hierarchy. - -You define the site hierarchy as lists/tuples. Each location in the hierarchy -is a (url, description) tuple. Each list has the base URL/text in the 0 -position, and all the children coming after it. Any child can be a list, -representing further depth to the hierarchy. See the end of the file for an -example hierarchy. - -Use Hierarchy(contents, currentURL), where contents is this hierarchy, and -currentURL is the position you are currently in. The menubar and crumbs methods -give you the HTML output. - -There are methods you can override to customize the HTML output. - -Meta-Data -================================================================================ -Author: Ian Bicking <ianb@colorstudy.com> -Version: $Revision: 1.1 $ -Start Date: 2001/07/23 -Last Revision Date: $Date: 2001/10/11 03:25:54 $ -""" -__author__ = "Ian Bicking <ianb@colorstudy.com>" -__version__ = "$Revision: 1.1 $"[11:-2] - -################################################## -## DEPENDENCIES -import string -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - - -################################################## -## GLOBALS & CONSTANTS - -True, False = (1==1), (0==1) - -################################################## -## CLASSES - -class Hierarchy: - def __init__(self, hierarchy, currentURL, prefix='', menuCSSClass=None, - crumbCSSClass=None): - """ - hierarchy is described above, currentURL should be somewhere in - the hierarchy. prefix will be added before all of the URLs (to - help mitigate the problems with absolute URLs), and if given, - cssClass will be used for both links *and* nonlinks. - """ - - self._contents = hierarchy - self._currentURL = currentURL - if menuCSSClass: - self._menuCSSClass = ' class="%s"' % menuCSSClass - else: - self._menuCSSClass = '' - if crumbCSSClass: - self._crumbCSSClass = ' class="%s"' % crumbCSSClass - else: - self._crumbCSSClass = '' - self._prefix=prefix - - - ## Main output methods - - def menuList(self, menuCSSClass=None): - """An indented menu list""" - if menuCSSClass: - self._menuCSSClass = ' class="%s"' % menuCSSClass - - stream = StringIO() - for item in self._contents[1:]: - self._menubarRecurse(item, 0, stream) - return stream.getvalue() - - def crumbs(self, crumbCSSClass=None): - """The home>where>you>are crumbs""" - if crumbCSSClass: - self._crumbCSSClass = ' class="%s"' % crumbCSSClass - - path = [] - pos = self._contents - while 1: - ## This is not the fastest algorithm, I'm afraid. - ## But it probably won't be for a huge hierarchy anyway. - foundAny = False - path.append(pos[0]) - for item in pos[1:]: - if self._inContents(item): - if type(item) is type(()): - path.append(item) - break - else: - pos = item - foundAny = True - break - if not foundAny: - break - if len(path) == 1: - return self.emptyCrumb() - return string.join(map(lambda x, self=self: self.crumbLink(x[0], x[1]), - path), self.crumbSeperator()) + \ - self.crumbTerminator() - - ## Methods to control the Aesthetics - # - override these methods for your own look - - def menuLink(self, url, text, indent): - if url == self._currentURL or self._prefix + url == self._currentURL: - return '%s<B%s>%s</B> <BR>\n' % (' '*2*indent, - self._menuCSSClass, text) - else: - return '%s<A HREF="%s%s"%s>%s</A> <BR>\n' % \ - (' '*2*indent, self._prefix, url, - self._menuCSSClass, text) - - def crumbLink(self, url, text): - if url == self._currentURL or self._prefix + url == self._currentURL: - return '<B%s>%s</B>' % (text, self._crumbCSSClass) - else: - return '<A HREF="%s%s"%s>%s</A>' % \ - (self._prefix, url, self._crumbCSSClass, text) - - def crumbSeperator(self): - return ' > ' - - def crumbTerminator(self): - return '' - - def emptyCrumb(self): - """When you are at the homepage""" - return '' - - ## internal methods - - def _menubarRecurse(self, contents, indent, stream): - if type(contents) is type(()): - url, text = contents - rest = [] - else: - url, text = contents[0] - rest = contents[1:] - stream.write(self.menuLink(url, text, indent)) - if self._inContents(contents): - for item in rest: - self._menubarRecurse(item, indent+1, stream) - - def _inContents(self, contents): - if type(contents) is type(()): - return self._currentURL == contents[0] - for item in contents: - if self._inContents(item): - return True - return False - -################################################## -## from the command line - -if __name__ == '__main__': - hierarchy = [('/', 'home'), - ('/about', 'About Us'), - [('/services', 'Services'), - [('/services/products', 'Products'), - ('/services/products/widget', 'The Widget'), - ('/services/products/wedge', 'The Wedge'), - ('/services/products/thimble', 'The Thimble'), - ], - ('/services/prices', 'Prices'), - ], - ('/contact', 'Contact Us'), - ] - - for url in ['/', '/services', '/services/products/widget', '/contact']: - print '<p>', '='*50 - print '<br> %s: <br>\n' % url - n = Hierarchy(hierarchy, url, menuCSSClass='menu', crumbCSSClass='crumb', - prefix='/here') - print n.menuList() - print '<p>', '-'*50 - print n.crumbs() diff --git a/cobbler/Cheetah/Tools/__init__.py b/cobbler/Cheetah/Tools/__init__.py deleted file mode 100644 index 506503b..0000000 --- a/cobbler/Cheetah/Tools/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""This package contains classes, functions, objects and packages contributed - by Cheetah users. They are not used by Cheetah itself. There is no - guarantee that this directory will be included in Cheetah releases, that - these objects will remain here forever, or that they will remain - backward-compatible. -""" - -# vim: shiftwidth=5 tabstop=5 expandtab diff --git a/cobbler/Cheetah/Unspecified.py b/cobbler/Cheetah/Unspecified.py deleted file mode 100644 index 89c5176..0000000 --- a/cobbler/Cheetah/Unspecified.py +++ /dev/null @@ -1,9 +0,0 @@ -try: - from ds.sys.Unspecified import Unspecified -except ImportError: - class _Unspecified: - def __repr__(self): - return 'Unspecified' - def __str__(self): - return 'Unspecified' - Unspecified = _Unspecified() diff --git a/cobbler/Cheetah/Utils/Indenter.py b/cobbler/Cheetah/Utils/Indenter.py deleted file mode 100644 index abdb0dd..0000000 --- a/cobbler/Cheetah/Utils/Indenter.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python -# $Id: Indenter.py,v 1.7 2006/01/08 01:09:30 tavis_rudd Exp $ -"""Indentation maker. -@@TR: this code is unsupported and largely undocumented ... - -This version is based directly on code by Robert Kuzelj -<robert_kuzelj@yahoo.com> and uses his directive syntax. Some classes and -attributes have been renamed. Indentation is output via -$self._CHEETAH__indenter.indent() to prevent '_indenter' being looked up on the -searchList and another one being found. The directive syntax will -soon be changed somewhat. - -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.7 $ -Start Date: 2001/11/07 -Last Revision Date: $Date: 2006/01/08 01:09:30 $ -""" -__author__ = "Mike Orr <iron@mso.oz.net>" -__revision__ = "$Revision: 1.7 $"[11:-2] - -import re -import sys - -def indentize(source): - return IndentProcessor().process(source) - -class IndentProcessor: - """Preprocess #indent tags.""" - LINE_SEP = '\n' - ARGS = "args" - INDENT_DIR = re.compile(r'[ \t]*#indent[ \t]*(?P<args>.*)') - DIRECTIVE = re.compile(r"[ \t]*#") - WS = "ws" - WHITESPACES = re.compile(r"(?P<ws>[ \t]*)") - - INC = "++" - DEC = "--" - - SET = "=" - CHAR = "char" - - ON = "on" - OFF = "off" - - PUSH = "push" - POP = "pop" - - def process(self, _txt): - result = [] - - for line in _txt.splitlines(): - match = self.INDENT_DIR.match(line) - if match: - #is indention directive - args = match.group(self.ARGS).strip() - if args == self.ON: - line = "#silent $self._CHEETAH__indenter.on()" - elif args == self.OFF: - line = "#silent $self._CHEETAH__indenter.off()" - elif args == self.INC: - line = "#silent $self._CHEETAH__indenter.inc()" - elif args == self.DEC: - line = "#silent $self._CHEETAH__indenter.dec()" - elif args.startswith(self.SET): - level = int(args[1:]) - line = "#silent $self._CHEETAH__indenter.setLevel(%(level)d)" % {"level":level} - elif args.startswith('chars'): - self.indentChars = eval(args.split('=')[1]) - line = "#silent $self._CHEETAH__indenter.setChars(%(level)d)" % {"level":level} - elif args.startswith(self.PUSH): - line = "#silent $self._CHEETAH__indenter.push()" - elif args.startswith(self.POP): - line = "#silent $self._CHEETAH__indenter.pop()" - else: - match = self.DIRECTIVE.match(line) - if not match: - #is not another directive - match = self.WHITESPACES.match(line) - if match: - size = len(match.group("ws").expandtabs(4)) - line = ("${self._CHEETAH__indenter.indent(%(size)d)}" % {"size":size}) + line.lstrip() - else: - line = "${self._CHEETAH__indenter.indent(0)}" + line - result.append(line) - - return self.LINE_SEP.join(result) - -class Indenter: - """A class that keeps track of the current indentation level. - .indent() returns the appropriate amount of indentation. - """ - def __init__(self): - self.On = 1 - self.Level = 0 - self.Chars = " "*4 - self.LevelStack = [] - def on(self): - self.On = 1 - def off(self): - self.On = 0 - def inc(self): - self.Level += 1 - def dec(self): - """decrement can only be applied to values greater zero - values below zero don't make any sense at all!""" - if self.Level > 0: - self.Level -= 1 - def push(self): - self.LevelStack.append(self.Level) - def pop(self): - """the levestack can not become -1. any attempt to do so - sets the level to 0!""" - if len(self.LevelStack) > 0: - self.Level = self.LevelStack.pop() - else: - self.Level = 0 - def setLevel(self, _level): - """the leve can't be less than zero. any attempt to do so - sets the level automatically to zero!""" - if _level < 0: - self.Level = 0 - else: - self.Level = _level - def setChar(self, _chars): - self.Chars = _chars - def indent(self, _default=0): - if self.On: - return self.Chars * self.Level - else: - return " " * _default - diff --git a/cobbler/Cheetah/Utils/Misc.py b/cobbler/Cheetah/Utils/Misc.py deleted file mode 100644 index aa5cc6d..0000000 --- a/cobbler/Cheetah/Utils/Misc.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python -# $Id: Misc.py,v 1.8 2005/11/02 22:26:08 tavis_rudd Exp $ -"""Miscellaneous functions/objects used by Cheetah but also useful standalone. - -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.8 $ -Start Date: 2001/11/07 -Last Revision Date: $Date: 2005/11/02 22:26:08 $ -""" -__author__ = "Mike Orr <iron@mso.oz.net>" -__revision__ = "$Revision: 1.8 $"[11:-2] - -import os # Used in mkdirsWithPyInitFile. -import types # Used in useOrRaise. -import sys # Used in die. - -################################################## -## MISCELLANEOUS FUNCTIONS - -def die(reason): - sys.stderr.write(reason + '\n') - sys.exit(1) - -def useOrRaise(thing, errmsg=''): - """Raise 'thing' if it's a subclass of Exception. Otherwise return it. - - Called by: Cheetah.Servlet.cgiImport() - """ - if type(thing) == types.ClassType and issubclass(thing, Exception): - raise thing(errmsg) - return thing - - -def checkKeywords(dic, legalKeywords, what='argument'): - """Verify no illegal keyword arguments were passed to a function. - - in : dic, dictionary (**kw in the calling routine). - legalKeywords, list of strings, the keywords that are allowed. - what, string, suffix for error message (see function source). - out: None. - exc: TypeError if 'dic' contains a key not in 'legalKeywords'. - called by: Cheetah.Template.__init__() - """ - # XXX legalKeywords could be a set when sets get added to Python. - for k in dic.keys(): # Can be dic.iterkeys() if Python >= 2.2. - if k not in legalKeywords: - raise TypeError("'%s' is not a valid %s" % (k, what)) - - -def removeFromList(list_, *elements): - """Save as list_.remove(each element) but don't raise an error if - element is missing. Modifies 'list_' in place! Returns None. - """ - for elm in elements: - try: - list_.remove(elm) - except ValueError: - pass - - -def mkdirsWithPyInitFiles(path): - """Same as os.makedirs (mkdir 'path' and all missing parent directories) - but also puts a Python '__init__.py' file in every directory it - creates. Does nothing (without creating an '__init__.py' file) if the - directory already exists. - """ - dir, fil = os.path.split(path) - if dir and not os.path.exists(dir): - mkdirsWithPyInitFiles(dir) - if not os.path.exists(path): - os.mkdir(path) - init = os.path.join(path, "__init__.py") - f = open(init, 'w') # Open and close to produce empty file. - f.close() - - - -# vim: shiftwidth=4 tabstop=4 expandtab diff --git a/cobbler/Cheetah/Utils/VerifyType.py b/cobbler/Cheetah/Utils/VerifyType.py deleted file mode 100644 index 6c52e09..0000000 --- a/cobbler/Cheetah/Utils/VerifyType.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python -# $Id: VerifyType.py,v 1.4 2005/11/02 22:26:08 tavis_rudd Exp $ -"""Functions to verify an argument's type - -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.4 $ -Start Date: 2001/11/07 -Last Revision Date: $Date: 2005/11/02 22:26:08 $ -""" -__author__ = "Mike Orr <iron@mso.oz.net>" -__revision__ = "$Revision: 1.4 $"[11:-2] - -################################################## -## DEPENDENCIES - -import types # Used in VerifyTypeClass. - -################################################## -## PRIVATE FUNCTIONS - -def _errmsg(argname, ltd, errmsgExtra=''): - """Construct an error message. - - argname, string, the argument name. - ltd, string, description of the legal types. - errmsgExtra, string, text to append to error mssage. - Returns: string, the error message. - """ - if errmsgExtra: - errmsgExtra = '\n' + errmsgExtra - return "arg '%s' must be %s%s" % (argname, ltd, errmsgExtra) - - -################################################## -## TYPE VERIFICATION FUNCTIONS - -def VerifyType(arg, argname, legalTypes, ltd, errmsgExtra=''): - """Verify the type of an argument. - - arg, any, the argument. - argname, string, name of the argument. - legalTypes, list of type objects, the allowed types. - ltd, string, description of legal types (for error message). - errmsgExtra, string, text to append to error message. - Returns: None. - Exceptions: TypeError if 'arg' is the wrong type. - """ - if type(arg) not in legalTypes: - m = _errmsg(argname, ltd, errmsgExtra) - raise TypeError(m) - - -def VerifyTypeClass(arg, argname, legalTypes, ltd, klass, errmsgExtra=''): - """Same, but if it's a class, verify it's a subclass of the right class. - - arg, any, the argument. - argname, string, name of the argument. - legalTypes, list of type objects, the allowed types. - ltd, string, description of legal types (for error message). - klass, class, the parent class. - errmsgExtra, string, text to append to the error message. - Returns: None. - Exceptions: TypeError if 'arg' is the wrong type. - """ - VerifyType(arg, argname, legalTypes, ltd, errmsgExtra) - # If no exception, the arg is a legal type. - if type(arg) == types.ClassType and not issubclass(arg, klass): - # Must test for "is class type" to avoid TypeError from issubclass(). - m = _errmsg(argname, ltd, errmsgExtra) - raise TypeError(m) - -# @@MO: Commented until we determine whether it's useful. -#def VerifyClass(arg, argname, klass, ltd): -# """Same, but allow *only* a subclass of the right class. -# """ -# VerifyTypeClass(arg, argname, [types.ClassType], ltd, klass) - -# vim: shiftwidth=4 tabstop=4 expandtab diff --git a/cobbler/Cheetah/Utils/WebInputMixin.py b/cobbler/Cheetah/Utils/WebInputMixin.py deleted file mode 100644 index 930c13e..0000000 --- a/cobbler/Cheetah/Utils/WebInputMixin.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -# $Id: WebInputMixin.py,v 1.10 2006/01/06 21:56:54 tavis_rudd Exp $ -"""Provides helpers for Template.webInput(), a method for importing web -transaction variables in bulk. See the docstring of webInput for full details. - -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.10 $ -Start Date: 2002/03/17 -Last Revision Date: $Date: 2006/01/06 21:56:54 $ -""" -__author__ = "Mike Orr <iron@mso.oz.net>" -__revision__ = "$Revision: 1.10 $"[11:-2] - -from Cheetah.Utils.Misc import useOrRaise - -class NonNumericInputError(ValueError): pass - -################################################## -## PRIVATE FUNCTIONS AND CLASSES - -class _Converter: - """A container object for info about type converters. - .name, string, name of this converter (for error messages). - .func, function, factory function. - .default, value to use or raise if the real value is missing. - .error, value to use or raise if .func() raises an exception. - """ - def __init__(self, name, func, default, error): - self.name = name - self.func = func - self.default = default - self.error = error - - -def _lookup(name, func, multi, converters): - """Look up a Webware field/cookie/value/session value. Return - '(realName, value)' where 'realName' is like 'name' but with any - conversion suffix strips off. Applies numeric conversion and - single vs multi values according to the comments in the source. - """ - # Step 1 -- split off the conversion suffix from 'name'; e.g. "height:int". - # If there's no colon, the suffix is "". 'longName' is the name with the - # suffix, 'shortName' is without. - # XXX This implementation assumes "height:" means "height". - colon = name.find(':') - if colon != -1: - longName = name - shortName, ext = name[:colon], name[colon+1:] - else: - longName = shortName = name - ext = '' - - # Step 2 -- look up the values by calling 'func'. - if longName != shortName: - values = func(longName, None) or func(shortName, None) - else: - values = func(shortName, None) - # 'values' is a list of strings, a string or None. - - # Step 3 -- Coerce 'values' to a list of zero, one or more strings. - if values is None: - values = [] - elif isinstance(values, str): - values = [values] - - # Step 4 -- Find a _Converter object or raise TypeError. - try: - converter = converters[ext] - except KeyError: - fmt = "'%s' is not a valid converter name in '%s'" - tup = (ext, longName) - raise TypeError(fmt % tup) - - # Step 5 -- if there's a converter func, run it on each element. - # If the converter raises an exception, use or raise 'converter.error'. - if converter.func is not None: - tmp = values[:] - values = [] - for elm in tmp: - try: - elm = converter.func(elm) - except (TypeError, ValueError): - tup = converter.name, elm - errmsg = "%s '%s' contains invalid characters" % tup - elm = useOrRaise(converter.error, errmsg) - values.append(elm) - # 'values' is now a list of strings, ints or floats. - - # Step 6 -- If we're supposed to return a multi value, return the list - # as is. If we're supposed to return a single value and the list is - # empty, return or raise 'converter.default'. Otherwise, return the - # first element in the list and ignore any additional values. - if multi: - return shortName, values - if len(values) == 0: - return shortName, useOrRaise(converter.default) - return shortName, values[0] - -# vim: sw=4 ts=4 expandtab diff --git a/cobbler/Cheetah/Utils/__init__.py b/cobbler/Cheetah/Utils/__init__.py deleted file mode 100644 index 792d600..0000000 --- a/cobbler/Cheetah/Utils/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# diff --git a/cobbler/Cheetah/Utils/htmlDecode.py b/cobbler/Cheetah/Utils/htmlDecode.py deleted file mode 100644 index 2832a74..0000000 --- a/cobbler/Cheetah/Utils/htmlDecode.py +++ /dev/null @@ -1,14 +0,0 @@ -"""This is a copy of the htmlDecode function in Webware. - -@@TR: It implemented more efficiently. - -""" - -from Cheetah.Utils.htmlEncode import htmlCodesReversed - -def htmlDecode(s, codes=htmlCodesReversed): - """ Returns the ASCII decoded version of the given HTML string. This does - NOT remove normal HTML tags like <p>. It is the inverse of htmlEncode().""" - for code in codes: - s = s.replace(code[1], code[0]) - return s diff --git a/cobbler/Cheetah/Utils/htmlEncode.py b/cobbler/Cheetah/Utils/htmlEncode.py deleted file mode 100644 index f76c77e..0000000 --- a/cobbler/Cheetah/Utils/htmlEncode.py +++ /dev/null @@ -1,21 +0,0 @@ -"""This is a copy of the htmlEncode function in Webware. - - -@@TR: It implemented more efficiently. - -""" -htmlCodes = [ - ['&', '&'], - ['<', '<'], - ['>', '>'], - ['"', '"'], -] -htmlCodesReversed = htmlCodes[:] -htmlCodesReversed.reverse() - -def htmlEncode(s, codes=htmlCodes): - """ Returns the HTML encoded version of the given string. This is useful to - display a plain ASCII text string on a web page.""" - for code in codes: - s = s.replace(code[0], code[1]) - return s diff --git a/cobbler/Cheetah/Utils/memcache.py b/cobbler/Cheetah/Utils/memcache.py deleted file mode 100644 index 03ba032..0000000 --- a/cobbler/Cheetah/Utils/memcache.py +++ /dev/null @@ -1,625 +0,0 @@ -#!/usr/bin/env python - -""" -client module for memcached (memory cache daemon) - -Overview -======== - -See U{the MemCached homepage<http://www.danga.com/memcached>} for more about memcached. - -Usage summary -============= - -This should give you a feel for how this module operates:: - - import memcache - mc = memcache.Client(['127.0.0.1:11211'], debug=0) - - mc.set("some_key", "Some value") - value = mc.get("some_key") - - mc.set("another_key", 3) - mc.delete("another_key") - - mc.set("key", "1") # note that the key used for incr/decr must be a string. - mc.incr("key") - mc.decr("key") - -The standard way to use memcache with a database is like this:: - - key = derive_key(obj) - obj = mc.get(key) - if not obj: - obj = backend_api.get(...) - mc.set(key, obj) - - # we now have obj, and future passes through this code - # will use the object from the cache. - -Detailed Documentation -====================== - -More detailed documentation is available in the L{Client} class. -""" - -import sys -import socket -import time -import types -try: - import cPickle as pickle -except ImportError: - import pickle - -__author__ = "Evan Martin <martine@danga.com>" -__version__ = "1.2_tummy5" -__copyright__ = "Copyright (C) 2003 Danga Interactive" -__license__ = "Python" - -class _Error(Exception): - pass - -class Client: - """ - Object representing a pool of memcache servers. - - See L{memcache} for an overview. - - In all cases where a key is used, the key can be either: - 1. A simple hashable type (string, integer, etc.). - 2. A tuple of C{(hashvalue, key)}. This is useful if you want to avoid - making this module calculate a hash value. You may prefer, for - example, to keep all of a given user's objects on the same memcache - server, so you could use the user's unique id as the hash value. - - @group Setup: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog - @group Insertion: set, add, replace - @group Retrieval: get, get_multi - @group Integers: incr, decr - @group Removal: delete - @sort: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog,\ - set, add, replace, get, get_multi, incr, decr, delete - """ - - _usePickle = False - _FLAG_PICKLE = 1<<0 - _FLAG_INTEGER = 1<<1 - _FLAG_LONG = 1<<2 - - _SERVER_RETRIES = 10 # how many times to try finding a free server. - - def __init__(self, servers, debug=0): - """ - Create a new Client object with the given list of servers. - - @param servers: C{servers} is passed to L{set_servers}. - @param debug: whether to display error messages when a server can't be - contacted. - """ - self.set_servers(servers) - self.debug = debug - self.stats = {} - - def set_servers(self, servers): - """ - Set the pool of servers used by this client. - - @param servers: an array of servers. - Servers can be passed in two forms: - 1. Strings of the form C{"host:port"}, which implies a default weight of 1. - 2. Tuples of the form C{("host:port", weight)}, where C{weight} is - an integer weight value. - """ - self.servers = [_Host(s, self.debuglog) for s in servers] - self._init_buckets() - - def get_stats(self): - '''Get statistics from each of the servers. - - @return: A list of tuples ( server_identifier, stats_dictionary ). - The dictionary contains a number of name/value pairs specifying - the name of the status field and the string value associated with - it. The values are not converted from strings. - ''' - data = [] - for s in self.servers: - if not s.connect(): continue - name = '%s:%s (%s)' % ( s.ip, s.port, s.weight ) - s.send_cmd('stats') - serverData = {} - data.append(( name, serverData )) - readline = s.readline - while 1: - line = readline() - if not line or line.strip() == 'END': break - stats = line.split(' ', 2) - serverData[stats[1]] = stats[2] - - return(data) - - def flush_all(self): - 'Expire all data currently in the memcache servers.' - for s in self.servers: - if not s.connect(): continue - s.send_cmd('flush_all') - s.expect("OK") - - def debuglog(self, str): - if self.debug: - sys.stderr.write("MemCached: %s\n" % str) - - def _statlog(self, func): - if not self.stats.has_key(func): - self.stats[func] = 1 - else: - self.stats[func] += 1 - - def forget_dead_hosts(self): - """ - Reset every host in the pool to an "alive" state. - """ - for s in self.servers: - s.dead_until = 0 - - def _init_buckets(self): - self.buckets = [] - for server in self.servers: - for i in range(server.weight): - self.buckets.append(server) - - def _get_server(self, key): - if type(key) == types.TupleType: - serverhash = key[0] - key = key[1] - else: - serverhash = hash(key) - - for i in range(Client._SERVER_RETRIES): - server = self.buckets[serverhash % len(self.buckets)] - if server.connect(): - #print "(using server %s)" % server, - return server, key - serverhash = hash(str(serverhash) + str(i)) - return None, None - - def disconnect_all(self): - for s in self.servers: - s.close_socket() - - def delete(self, key, time=0): - '''Deletes a key from the memcache. - - @return: Nonzero on success. - @rtype: int - ''' - server, key = self._get_server(key) - if not server: - return 0 - self._statlog('delete') - if time != None: - cmd = "delete %s %d" % (key, time) - else: - cmd = "delete %s" % key - - try: - server.send_cmd(cmd) - server.expect("DELETED") - except socket.error, msg: - server.mark_dead(msg[1]) - return 0 - return 1 - - def incr(self, key, delta=1): - """ - Sends a command to the server to atomically increment the value for C{key} by - C{delta}, or by 1 if C{delta} is unspecified. Returns None if C{key} doesn't - exist on server, otherwise it returns the new value after incrementing. - - Note that the value for C{key} must already exist in the memcache, and it - must be the string representation of an integer. - - >>> mc.set("counter", "20") # returns 1, indicating success - 1 - >>> mc.incr("counter") - 21 - >>> mc.incr("counter") - 22 - - Overflow on server is not checked. Be aware of values approaching - 2**32. See L{decr}. - - @param delta: Integer amount to increment by (should be zero or greater). - @return: New value after incrementing. - @rtype: int - """ - return self._incrdecr("incr", key, delta) - - def decr(self, key, delta=1): - """ - Like L{incr}, but decrements. Unlike L{incr}, underflow is checked and - new values are capped at 0. If server value is 1, a decrement of 2 - returns 0, not -1. - - @param delta: Integer amount to decrement by (should be zero or greater). - @return: New value after decrementing. - @rtype: int - """ - return self._incrdecr("decr", key, delta) - - def _incrdecr(self, cmd, key, delta): - server, key = self._get_server(key) - if not server: - return 0 - self._statlog(cmd) - cmd = "%s %s %d" % (cmd, key, delta) - try: - server.send_cmd(cmd) - line = server.readline() - return int(line) - except socket.error, msg: - server.mark_dead(msg[1]) - return None - - def add(self, key, val, time=0): - ''' - Add new key with value. - - Like L{set}, but only stores in memcache if the key doesn\'t already exist. - - @return: Nonzero on success. - @rtype: int - ''' - return self._set("add", key, val, time) - def replace(self, key, val, time=0): - '''Replace existing key with value. - - Like L{set}, but only stores in memcache if the key already exists. - The opposite of L{add}. - - @return: Nonzero on success. - @rtype: int - ''' - return self._set("replace", key, val, time) - def set(self, key, val, time=0): - '''Unconditionally sets a key to a given value in the memcache. - - The C{key} can optionally be an tuple, with the first element being the - hash value, if you want to avoid making this module calculate a hash value. - You may prefer, for example, to keep all of a given user's objects on the - same memcache server, so you could use the user's unique id as the hash - value. - - @return: Nonzero on success. - @rtype: int - ''' - return self._set("set", key, val, time) - - def _set(self, cmd, key, val, time): - server, key = self._get_server(key) - if not server: - return 0 - - self._statlog(cmd) - - flags = 0 - if isinstance(val, types.StringTypes): - pass - elif isinstance(val, int): - flags |= Client._FLAG_INTEGER - val = "%d" % val - elif isinstance(val, long): - flags |= Client._FLAG_LONG - val = "%d" % val - elif self._usePickle: - flags |= Client._FLAG_PICKLE - val = pickle.dumps(val, 2) - else: - pass - - fullcmd = "%s %s %d %d %d\r\n%s" % (cmd, key, flags, time, len(val), val) - try: - server.send_cmd(fullcmd) - server.expect("STORED") - except socket.error, msg: - server.mark_dead(msg[1]) - return 0 - return 1 - - def get(self, key): - '''Retrieves a key from the memcache. - - @return: The value or None. - ''' - server, key = self._get_server(key) - if not server: - return None - - self._statlog('get') - - try: - server.send_cmd("get %s" % key) - rkey, flags, rlen, = self._expectvalue(server) - if not rkey: - return None - value = self._recv_value(server, flags, rlen) - server.expect("END") - except (_Error, socket.error), msg: - if type(msg) is types.TupleType: - msg = msg[1] - server.mark_dead(msg) - return None - return value - - def get_multi(self, keys): - ''' - Retrieves multiple keys from the memcache doing just one query. - - >>> success = mc.set("foo", "bar") - >>> success = mc.set("baz", 42) - >>> mc.get_multi(["foo", "baz", "foobar"]) == {"foo": "bar", "baz": 42} - 1 - - This method is recommended over regular L{get} as it lowers the number of - total packets flying around your network, reducing total latency, since - your app doesn\'t have to wait for each round-trip of L{get} before sending - the next one. - - @param keys: An array of keys. - @return: A dictionary of key/value pairs that were available. - - ''' - - self._statlog('get_multi') - - server_keys = {} - - # build up a list for each server of all the keys we want. - for key in keys: - server, key = self._get_server(key) - if not server: - continue - if not server_keys.has_key(server): - server_keys[server] = [] - server_keys[server].append(key) - - # send out all requests on each server before reading anything - dead_servers = [] - for server in server_keys.keys(): - try: - server.send_cmd("get %s" % " ".join(server_keys[server])) - except socket.error, msg: - server.mark_dead(msg[1]) - dead_servers.append(server) - - # if any servers died on the way, don't expect them to respond. - for server in dead_servers: - del server_keys[server] - - retvals = {} - for server in server_keys.keys(): - try: - line = server.readline() - while line and line != 'END': - rkey, flags, rlen = self._expectvalue(server, line) - # Bo Yang reports that this can sometimes be None - if rkey is not None: - val = self._recv_value(server, flags, rlen) - retvals[rkey] = val - line = server.readline() - except (_Error, socket.error), msg: - server.mark_dead(msg) - return retvals - - def _expectvalue(self, server, line=None): - if not line: - line = server.readline() - - if line[:5] == 'VALUE': - resp, rkey, flags, len = line.split() - flags = int(flags) - rlen = int(len) - return (rkey, flags, rlen) - else: - return (None, None, None) - - def _recv_value(self, server, flags, rlen): - rlen += 2 # include \r\n - buf = server.recv(rlen) - if len(buf) != rlen: - raise _Error("received %d bytes when expecting %d" % (len(buf), rlen)) - - if len(buf) == rlen: - buf = buf[:-2] # strip \r\n - - if flags == 0: - val = buf - elif flags & Client._FLAG_INTEGER: - val = int(buf) - elif flags & Client._FLAG_LONG: - val = long(buf) - elif self._usePickle and flags & Client._FLAG_PICKLE: - try: - val = pickle.loads(buf) - except: - self.debuglog('Pickle error...\n') - val = None - else: - self.debuglog("unknown flags on get: %x\n" % flags) - - return val - -class _Host: - _DEAD_RETRY = 30 # number of seconds before retrying a dead server. - - def __init__(self, host, debugfunc=None): - if isinstance(host, types.TupleType): - host = host[0] - self.weight = host[1] - else: - self.weight = 1 - - if host.find(":") > 0: - self.ip, self.port = host.split(":") - self.port = int(self.port) - else: - self.ip, self.port = host, 11211 - - if not debugfunc: - debugfunc = lambda x: x - self.debuglog = debugfunc - - self.deaduntil = 0 - self.socket = None - - def _check_dead(self): - if self.deaduntil and self.deaduntil > time.time(): - return 1 - self.deaduntil = 0 - return 0 - - def connect(self): - if self._get_socket(): - return 1 - return 0 - - def mark_dead(self, reason): - self.debuglog("MemCache: %s: %s. Marking dead." % (self, reason)) - self.deaduntil = time.time() + _Host._DEAD_RETRY - self.close_socket() - - def _get_socket(self): - if self._check_dead(): - return None - if self.socket: - return self.socket - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - # Python 2.3-ism: s.settimeout(1) - try: - s.connect((self.ip, self.port)) - except socket.error, msg: - self.mark_dead("connect: %s" % msg[1]) - return None - self.socket = s - return s - - def close_socket(self): - if self.socket: - self.socket.close() - self.socket = None - - def send_cmd(self, cmd): - if len(cmd) > 100: - self.socket.sendall(cmd) - self.socket.sendall('\r\n') - else: - self.socket.sendall(cmd + '\r\n') - - def readline(self): - buffers = '' - recv = self.socket.recv - while 1: - data = recv(1) - if not data: - self.mark_dead('Connection closed while reading from %s' - % repr(self)) - break - if data == '\n' and buffers and buffers[-1] == '\r': - return(buffers[:-1]) - buffers = buffers + data - return(buffers) - - def expect(self, text): - line = self.readline() - if line != text: - self.debuglog("while expecting '%s', got unexpected response '%s'" % (text, line)) - return line - - def recv(self, rlen): - buf = '' - recv = self.socket.recv - while len(buf) < rlen: - buf = buf + recv(rlen - len(buf)) - return buf - - def __str__(self): - d = '' - if self.deaduntil: - d = " (dead until %d)" % self.deaduntil - return "%s:%d%s" % (self.ip, self.port, d) - -def _doctest(): - import doctest, memcache - servers = ["127.0.0.1:11211"] - mc = Client(servers, debug=1) - globs = {"mc": mc} - return doctest.testmod(memcache, globs=globs) - -if __name__ == "__main__": - print "Testing docstrings..." - _doctest() - print "Running tests:" - print - #servers = ["127.0.0.1:11211", "127.0.0.1:11212"] - servers = ["127.0.0.1:11211"] - mc = Client(servers, debug=1) - - def to_s(val): - if not isinstance(val, types.StringTypes): - return "%s (%s)" % (val, type(val)) - return "%s" % val - def test_setget(key, val): - print "Testing set/get {'%s': %s} ..." % (to_s(key), to_s(val)), - mc.set(key, val) - newval = mc.get(key) - if newval == val: - print "OK" - return 1 - else: - print "FAIL" - return 0 - - class FooStruct: - def __init__(self): - self.bar = "baz" - def __str__(self): - return "A FooStruct" - def __eq__(self, other): - if isinstance(other, FooStruct): - return self.bar == other.bar - return 0 - - test_setget("a_string", "some random string") - test_setget("an_integer", 42) - if test_setget("long", long(1<<30)): - print "Testing delete ...", - if mc.delete("long"): - print "OK" - else: - print "FAIL" - print "Testing get_multi ...", - print mc.get_multi(["a_string", "an_integer"]) - - print "Testing get(unknown value) ...", - print to_s(mc.get("unknown_value")) - - f = FooStruct() - test_setget("foostruct", f) - - print "Testing incr ...", - x = mc.incr("an_integer", 1) - if x == 43: - print "OK" - else: - print "FAIL" - - print "Testing decr ...", - x = mc.decr("an_integer", 1) - if x == 42: - print "OK" - else: - print "FAIL" - - - -# vim: ts=4 sw=4 et : diff --git a/cobbler/Cheetah/Utils/optik/__init__.py b/cobbler/Cheetah/Utils/optik/__init__.py deleted file mode 100644 index 75a30ba..0000000 --- a/cobbler/Cheetah/Utils/optik/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -"""optik - -A powerful, extensible, and easy-to-use command-line parser for Python. - -By Greg Ward <gward@python.net> - -See http://optik.sourceforge.net/ - -Cheetah modifications: added "Cheetah.Utils.optik." prefix to - all intra-Optik imports. -""" - -# Copyright (c) 2001 Gregory P. Ward. All rights reserved. -# See the README.txt distributed with Optik for licensing terms. - -__revision__ = "$Id: __init__.py,v 1.2 2002/09/12 06:56:51 hierro Exp $" - -__version__ = "1.3" - - -# Re-import these for convenience -from Cheetah.Utils.optik.option import Option -from Cheetah.Utils.optik.option_parser import \ - OptionParser, SUPPRESS_HELP, SUPPRESS_USAGE, STD_HELP_OPTION -from Cheetah.Utils.optik.errors import OptionValueError - - -# Some day, there might be many Option classes. As of Optik 1.3, the -# preferred way to instantiate Options is indirectly, via make_option(), -# which will become a factory function when there are many Option -# classes. -make_option = Option diff --git a/cobbler/Cheetah/Utils/optik/errors.py b/cobbler/Cheetah/Utils/optik/errors.py deleted file mode 100644 index 2ed75e6..0000000 --- a/cobbler/Cheetah/Utils/optik/errors.py +++ /dev/null @@ -1,52 +0,0 @@ -"""optik.errors - -Exception classes used by Optik. -""" - -__revision__ = "$Id: errors.py,v 1.1 2002/08/24 17:10:06 hierro Exp $" - -# Copyright (c) 2001 Gregory P. Ward. All rights reserved. -# See the README.txt distributed with Optik for licensing terms. - -# created 2001/10/17 GPW (from optik.py) - - -class OptikError (Exception): - def __init__ (self, msg): - self.msg = msg - - def __str__ (self): - return self.msg - - -class OptionError (OptikError): - """ - Raised if an Option instance is created with invalid or - inconsistent arguments. - """ - - def __init__ (self, msg, option): - self.msg = msg - self.option_id = str(option) - - def __str__ (self): - if self.option_id: - return "option %s: %s" % (self.option_id, self.msg) - else: - return self.msg - -class OptionConflictError (OptionError): - """ - Raised if conflicting options are added to an OptionParser. - """ - -class OptionValueError (OptikError): - """ - Raised if an invalid option value is encountered on the command - line. - """ - -class BadOptionError (OptikError): - """ - Raised if an invalid or ambiguous option is seen on the command-line. - """ diff --git a/cobbler/Cheetah/Utils/optik/option.py b/cobbler/Cheetah/Utils/optik/option.py deleted file mode 100644 index ac85c3d..0000000 --- a/cobbler/Cheetah/Utils/optik/option.py +++ /dev/null @@ -1,354 +0,0 @@ -"""optik.option - -Defines the Option class and some standard value-checking functions. - -Cheetah modifications: added "Cheetah.Utils.optik." prefix to - all intra-Optik imports. -""" - -__revision__ = "$Id: option.py,v 1.2 2002/09/12 06:56:51 hierro Exp $" - -# Copyright (c) 2001 Gregory P. Ward. All rights reserved. -# See the README.txt distributed with Optik for licensing terms. - -# created 2001/10/17, GPW (from optik.py) - -import sys -from types import TupleType, DictType -from Cheetah.Utils.optik.errors import OptionError, OptionValueError - -_builtin_cvt = { "int" : (int, "integer"), - "long" : (long, "long integer"), - "float" : (float, "floating-point"), - "complex" : (complex, "complex") } - -def check_builtin (option, opt, value): - (cvt, what) = _builtin_cvt[option.type] - try: - return cvt(value) - except ValueError: - raise OptionValueError( - #"%s: invalid %s argument %r" % (opt, what, value)) - "option %s: invalid %s value: %r" % (opt, what, value)) - -# Not supplying a default is different from a default of None, -# so we need an explicit "not supplied" value. -NO_DEFAULT = "NO"+"DEFAULT" - - -class Option: - """ - Instance attributes: - _short_opts : [string] - _long_opts : [string] - - action : string - type : string - dest : string - default : any - nargs : int - const : any - callback : function - callback_args : (any*) - callback_kwargs : { string : any } - help : string - metavar : string - """ - - # The list of instance attributes that may be set through - # keyword args to the constructor. - ATTRS = ['action', - 'type', - 'dest', - 'default', - 'nargs', - 'const', - 'callback', - 'callback_args', - 'callback_kwargs', - 'help', - 'metavar'] - - # The set of actions allowed by option parsers. Explicitly listed - # here so the constructor can validate its arguments. - ACTIONS = ("store", - "store_const", - "store_true", - "store_false", - "append", - "count", - "callback", - "help", - "version") - - # The set of actions that involve storing a value somewhere; - # also listed just for constructor argument validation. (If - # the action is one of these, there must be a destination.) - STORE_ACTIONS = ("store", - "store_const", - "store_true", - "store_false", - "append", - "count") - - # The set of actions for which it makes sense to supply a value - # type, ie. where we expect an argument to this option. - TYPED_ACTIONS = ("store", - "append", - "callback") - - # The set of known types for option parsers. Again, listed here for - # constructor argument validation. - TYPES = ("string", "int", "long", "float", "complex") - - # Dictionary of argument checking functions, which convert and - # validate option arguments according to the option type. - # - # Signature of checking functions is: - # check(option : Option, opt : string, value : string) -> any - # where - # option is the Option instance calling the checker - # opt is the actual option seen on the command-line - # (eg. "-a", "--file") - # value is the option argument seen on the command-line - # - # The return value should be in the appropriate Python type - # for option.type -- eg. an integer if option.type == "int". - # - # If no checker is defined for a type, arguments will be - # unchecked and remain strings. - TYPE_CHECKER = { "int" : check_builtin, - "long" : check_builtin, - "float" : check_builtin, - "complex" : check_builtin, - } - - - # CHECK_METHODS is a list of unbound method objects; they are called - # by the constructor, in order, after all attributes are - # initialized. The list is created and filled in later, after all - # the methods are actually defined. (I just put it here because I - # like to define and document all class attributes in the same - # place.) Subclasses that add another _check_*() method should - # define their own CHECK_METHODS list that adds their check method - # to those from this class. - CHECK_METHODS = None - - - # -- Constructor/initialization methods ---------------------------- - - def __init__ (self, *opts, **attrs): - # Set _short_opts, _long_opts attrs from 'opts' tuple - opts = self._check_opt_strings(opts) - self._set_opt_strings(opts) - - # Set all other attrs (action, type, etc.) from 'attrs' dict - self._set_attrs(attrs) - - # Check all the attributes we just set. There are lots of - # complicated interdependencies, but luckily they can be farmed - # out to the _check_*() methods listed in CHECK_METHODS -- which - # could be handy for subclasses! The one thing these all share - # is that they raise OptionError if they discover a problem. - for checker in self.CHECK_METHODS: - checker(self) - - def _check_opt_strings (self, opts): - # Filter out None because early versions of Optik had exactly - # one short option and one long option, either of which - # could be None. - opts = filter(None, opts) - if not opts: - raise OptionError("at least one option string must be supplied", - self) - return opts - - def _set_opt_strings (self, opts): - self._short_opts = [] - self._long_opts = [] - for opt in opts: - if len(opt) < 2: - raise OptionError( - "invalid option string %r: " - "must be at least two characters long" % opt, self) - elif len(opt) == 2: - if not (opt[0] == "-" and opt[1] != "-"): - raise OptionError( - "invalid short option string %r: " - "must be of the form -x, (x any non-dash char)" % opt, - self) - self._short_opts.append(opt) - else: - if not (opt[0:2] == "--" and opt[2] != "-"): - raise OptionError( - "invalid long option string %r: " - "must start with --, followed by non-dash" % opt, - self) - self._long_opts.append(opt) - - def _set_attrs (self, attrs): - for attr in self.ATTRS: - if attrs.has_key(attr): - setattr(self, attr, attrs[attr]) - del attrs[attr] - else: - if attr == 'default': - setattr(self, attr, NO_DEFAULT) - else: - setattr(self, attr, None) - if attrs: - raise OptionError( - "invalid keyword arguments: %s" % ", ".join(attrs.keys()), - self) - - - # -- Constructor validation methods -------------------------------- - - def _check_action (self): - if self.action is None: - self.action = "store" - elif self.action not in self.ACTIONS: - raise OptionError("invalid action: %r" % self.action, self) - - def _check_type (self): - if self.type is None: - # XXX should factor out another class attr here: list of - # actions that *require* a type - if self.action in ("store", "append"): - # No type given? "string" is the most sensible default. - self.type = "string" - else: - if self.type not in self.TYPES: - raise OptionError("invalid option type: %r" % self.type, self) - if self.action not in self.TYPED_ACTIONS: - raise OptionError( - "must not supply a type for action %r" % self.action, self) - - def _check_dest (self): - if self.action in self.STORE_ACTIONS and self.dest is None: - # No destination given, and we need one for this action. - # Glean a destination from the first long option string, - # or from the first short option string if no long options. - if self._long_opts: - # eg. "--foo-bar" -> "foo_bar" - self.dest = self._long_opts[0][2:].replace('-', '_') - else: - self.dest = self._short_opts[0][1] - - def _check_const (self): - if self.action != "store_const" and self.const is not None: - raise OptionError( - "'const' must not be supplied for action %r" % self.action, - self) - - def _check_nargs (self): - if self.action in self.TYPED_ACTIONS: - if self.nargs is None: - self.nargs = 1 - elif self.nargs is not None: - raise OptionError( - "'nargs' must not be supplied for action %r" % self.action, - self) - - def _check_callback (self): - if self.action == "callback": - if not callable(self.callback): - raise OptionError( - "callback not callable: %r" % self.callback, self) - if (self.callback_args is not None and - type(self.callback_args) is not TupleType): - raise OptionError( - "callback_args, if supplied, must be a tuple: not %r" - % self.callback_args, self) - if (self.callback_kwargs is not None and - type(self.callback_kwargs) is not DictType): - raise OptionError( - "callback_kwargs, if supplied, must be a dict: not %r" - % self.callback_kwargs, self) - else: - if self.callback is not None: - raise OptionError( - "callback supplied (%r) for non-callback option" - % self.callback, self) - if self.callback_args is not None: - raise OptionError( - "callback_args supplied for non-callback option", self) - if self.callback_kwargs is not None: - raise OptionError( - "callback_kwargs supplied for non-callback option", self) - - - CHECK_METHODS = [_check_action, - _check_type, - _check_dest, - _check_const, - _check_nargs, - _check_callback] - - - # -- Miscellaneous methods ----------------------------------------- - - def __str__ (self): - if self._short_opts or self._long_opts: - return "/".join(self._short_opts + self._long_opts) - else: - raise RuntimeError, "short_opts and long_opts both empty!" - - def takes_value (self): - return self.type is not None - - - # -- Processing methods -------------------------------------------- - - def check_value (self, opt, value): - checker = self.TYPE_CHECKER.get(self.type) - if checker is None: - return value - else: - return checker(self, opt, value) - - def process (self, opt, value, values, parser): - - # First, convert the value(s) to the right type. Howl if any - # value(s) are bogus. - if value is not None: - if self.nargs == 1: - value = self.check_value(opt, value) - else: - value = tuple([self.check_value(opt, v) for v in value]) - - # And then take whatever action is expected of us. - # This is a separate method to make life easier for - # subclasses to add new actions. - return self.take_action( - self.action, self.dest, opt, value, values, parser) - - def take_action (self, action, dest, opt, value, values, parser): - if action == "store": - setattr(values, dest, value) - elif action == "store_const": - setattr(values, dest, self.const) - elif action == "store_true": - setattr(values, dest, 1) - elif action == "store_false": - setattr(values, dest, 0) - elif action == "append": - values.ensure_value(dest, []).append(value) - elif action == "count": - setattr(values, dest, values.ensure_value(dest, 0) + 1) - elif action == "callback": - args = self.callback_args or () - kwargs = self.callback_kwargs or {} - self.callback(self, opt, value, parser, *args, **kwargs) - elif action == "help": - parser.print_help() - sys.exit(0) - elif action == "version": - parser.print_version() - sys.exit(0) - else: - raise RuntimeError, "unknown action %r" % self.action - - return 1 - -# class Option diff --git a/cobbler/Cheetah/Utils/optik/option_parser.py b/cobbler/Cheetah/Utils/optik/option_parser.py deleted file mode 100644 index 1b4e632..0000000 --- a/cobbler/Cheetah/Utils/optik/option_parser.py +++ /dev/null @@ -1,667 +0,0 @@ -"""optik.option_parser - -Provides the OptionParser and Values classes. - -Cheetah modifications: added "Cheetah.Utils.optik." prefix to - all intra-Optik imports. -""" - -__revision__ = "$Id: option_parser.py,v 1.2 2002/09/12 06:56:51 hierro Exp $" - -# Copyright (c) 2001 Gregory P. Ward. All rights reserved. -# See the README.txt distributed with Optik for licensing terms. - -# created 2001/10/17, GPW (from optik.py) - -import sys, os -import types -from Cheetah.Utils.optik.option import Option, NO_DEFAULT -from Cheetah.Utils.optik.errors import OptionConflictError, OptionValueError, BadOptionError - -def get_prog_name (): - return os.path.basename(sys.argv[0]) - - -SUPPRESS_HELP = "SUPPRESS"+"HELP" -SUPPRESS_USAGE = "SUPPRESS"+"USAGE" - -STD_HELP_OPTION = Option("-h", "--help", - action="help", - help="show this help message and exit") -STD_VERSION_OPTION = Option("--version", - action="version", - help="show program's version number and exit") - - -class Values: - - def __init__ (self, defaults=None): - if defaults: - for (attr, val) in defaults.items(): - setattr(self, attr, val) - - - def _update_careful (self, dict): - """ - Update the option values from an arbitrary dictionary, but only - use keys from dict that already have a corresponding attribute - in self. Any keys in dict without a corresponding attribute - are silently ignored. - """ - for attr in dir(self): - if dict.has_key(attr): - dval = dict[attr] - if dval is not None: - setattr(self, attr, dval) - - def _update_loose (self, dict): - """ - Update the option values from an arbitrary dictionary, - using all keys from the dictionary regardless of whether - they have a corresponding attribute in self or not. - """ - self.__dict__.update(dict) - - def _update (self, dict, mode): - if mode == "careful": - self._update_careful(dict) - elif mode == "loose": - self._update_loose(dict) - else: - raise ValueError, "invalid update mode: %r" % mode - - def read_module (self, modname, mode="careful"): - __import__(modname) - mod = sys.modules[modname] - self._update(vars(mod), mode) - - def read_file (self, filename, mode="careful"): - vars = {} - execfile(filename, vars) - self._update(vars, mode) - - def ensure_value (self, attr, value): - if not hasattr(self, attr) or getattr(self, attr) is None: - setattr(self, attr, value) - return getattr(self, attr) - - -class OptionParser: - """ - Class attributes: - standard_option_list : [Option] - list of standard options that will be accepted by all instances - of this parser class (intended to be overridden by subclasses). - - Instance attributes: - usage : string - a usage string for your program. Before it is displayed - to the user, "%prog" will be expanded to the name of - your program (os.path.basename(sys.argv[0])). - option_list : [Option] - the list of all options accepted on the command-line of - this program - _short_opt : { string : Option } - dictionary mapping short option strings, eg. "-f" or "-X", - to the Option instances that implement them. If an Option - has multiple short option strings, it will appears in this - dictionary multiple times. - _long_opt : { string : Option } - dictionary mapping long option strings, eg. "--file" or - "--exclude", to the Option instances that implement them. - Again, a given Option can occur multiple times in this - dictionary. - _long_opts : [string] - list of long option strings recognized by this option - parser. Should be equal to _long_opt.values(). - defaults : { string : any } - dictionary mapping option destination names to default - values for each destination. - - allow_interspersed_args : boolean = true - if true, positional arguments may be interspersed with options. - Assuming -a and -b each take a single argument, the command-line - -ablah foo bar -bboo baz - will be interpreted the same as - -ablah -bboo -- foo bar baz - If this flag were false, that command line would be interpreted as - -ablah -- foo bar -bboo baz - -- ie. we stop processing options as soon as we see the first - non-option argument. (This is the tradition followed by - Python's getopt module, Perl's Getopt::Std, and other argument- - parsing libraries, but it is generally annoying to users.) - - rargs : [string] - the argument list currently being parsed. Only set when - parse_args() is active, and continually trimmed down as - we consume arguments. Mainly there for the benefit of - callback options. - largs : [string] - the list of leftover arguments that we have skipped while - parsing options. If allow_interspersed_args is false, this - list is always empty. - values : Values - the set of option values currently being accumulated. Only - set when parse_args() is active. Also mainly for callbacks. - - Because of the 'rargs', 'largs', and 'values' attributes, - OptionParser is not thread-safe. If, for some perverse reason, you - need to parse command-line arguments simultaneously in different - threads, use different OptionParser instances. - - """ - - standard_option_list = [STD_HELP_OPTION] - - - def __init__ (self, - usage=None, - option_list=None, - option_class=Option, - version=None, - conflict_handler="error"): - self.set_usage(usage) - self.option_class = option_class - self.version = version - self.set_conflict_handler(conflict_handler) - self.allow_interspersed_args = 1 - - # Create the various lists and dicts that constitute the - # "option list". See class docstring for details about - # each attribute. - self._create_option_list() - - # Populate the option list; initial sources are the - # standard_option_list class attribute, the 'option_list' - # argument, and the STD_VERSION_OPTION global (if 'version' - # supplied). - self._populate_option_list(option_list) - - self._init_parsing_state() - - # -- Private methods ----------------------------------------------- - # (used by the constructor) - - def _create_option_list (self): - self.option_list = [] - self._short_opt = {} # single letter -> Option instance - self._long_opt = {} # long option -> Option instance - self._long_opts = [] # list of long options - self.defaults = {} # maps option dest -> default value - - def _populate_option_list (self, option_list): - if self.standard_option_list: - self.add_options(self.standard_option_list) - if self.version: - self.add_option(STD_VERSION_OPTION) - if option_list: - self.add_options(option_list) - - def _init_parsing_state (self): - # These are set in parse_args() for the convenience of callbacks. - self.rargs = None - self.largs = None - self.values = None - - - # -- Simple modifier methods --------------------------------------- - - def set_usage (self, usage): - if usage is None: - self.usage = "usage: %prog [options]" - elif usage is SUPPRESS_USAGE: - self.usage = None - else: - self.usage = usage - - def enable_interspersed_args (self): - self.allow_interspersed_args = 1 - - def disable_interspersed_args (self): - self.allow_interspersed_args = 0 - - def set_conflict_handler (self, handler): - if handler not in ("ignore", "error", "resolve"): - raise ValueError, "invalid conflict_resolution value %r" % handler - self.conflict_handler = handler - - def set_default (self, dest, value): - self.defaults[dest] = value - - def set_defaults (self, **kwargs): - self.defaults.update(kwargs) - - - # -- Option-adding methods ----------------------------------------- - - def _check_conflict (self, option): - conflict_opts = [] - for opt in option._short_opts: - if self._short_opt.has_key(opt): - conflict_opts.append((opt, self._short_opt[opt])) - for opt in option._long_opts: - if self._long_opt.has_key(opt): - conflict_opts.append((opt, self._long_opt[opt])) - - if conflict_opts: - handler = self.conflict_handler - if handler == "ignore": # behaviour for Optik 1.0, 1.1 - pass - elif handler == "error": # new in 1.2 - raise OptionConflictError( - "conflicting option string(s): %s" - % ", ".join([co[0] for co in conflict_opts]), - option) - elif handler == "resolve": # new in 1.2 - for (opt, c_option) in conflict_opts: - if opt.startswith("--"): - c_option._long_opts.remove(opt) - del self._long_opt[opt] - else: - c_option._short_opts.remove(opt) - del self._short_opt[opt] - if not (c_option._short_opts or c_option._long_opts): - self.option_list.remove(c_option) - - - def add_option (self, *args, **kwargs): - """add_option(Option) - add_option(opt_str, ..., kwarg=val, ...) - """ - if type(args[0]) is types.StringType: - option = self.option_class(*args, **kwargs) - elif len(args) == 1 and not kwargs: - option = args[0] - if not isinstance(option, Option): - raise TypeError, "not an Option instance: %r" % option - else: - raise TypeError, "invalid arguments" - - self._check_conflict(option) - - self.option_list.append(option) - for opt in option._short_opts: - self._short_opt[opt] = option - for opt in option._long_opts: - self._long_opt[opt] = option - self._long_opts.append(opt) - - if option.dest is not None: # option has a dest, we need a default - if option.default is not NO_DEFAULT: - self.defaults[option.dest] = option.default - elif not self.defaults.has_key(option.dest): - self.defaults[option.dest] = None - - def add_options (self, option_list): - for option in option_list: - self.add_option(option) - - - # -- Option query/removal methods ---------------------------------- - - def get_option (self, opt_str): - return (self._short_opt.get(opt_str) or - self._long_opt.get(opt_str)) - - def has_option (self, opt_str): - return (self._short_opt.has_key(opt_str) or - self._long_opt.has_key(opt_str)) - - - def remove_option (self, opt_str): - option = self._short_opt.get(opt_str) - if option is None: - option = self._long_opt.get(opt_str) - if option is None: - raise ValueError("no such option %r" % opt_str) - - for opt in option._short_opts: - del self._short_opt[opt] - for opt in option._long_opts: - del self._long_opt[opt] - self._long_opts.remove(opt) - self.option_list.remove(option) - - - # -- Option-parsing methods ---------------------------------------- - - def _get_args (self, args): - if args is None: - return sys.argv[1:] - else: - return args[:] # don't modify caller's list - - def parse_args (self, args=None, values=None): - """ - parse_args(args : [string] = sys.argv[1:], - values : Values = None) - -> (values : Values, args : [string]) - - Parse the command-line options found in 'args' (default: - sys.argv[1:]). Any errors result in a call to 'error()', which - by default prints the usage message to stderr and calls - sys.exit() with an error message. On success returns a pair - (values, args) where 'values' is an Values instance (with all - your option values) and 'args' is the list of arguments left - over after parsing options. - """ - rargs = self._get_args(args) - if values is None: - values = Values(self.defaults) - - # Store the halves of the argument list as attributes for the - # convenience of callbacks: - # rargs - # the rest of the command-line (the "r" stands for - # "remaining" or "right-hand") - # largs - # the leftover arguments -- ie. what's left after removing - # options and their arguments (the "l" stands for "leftover" - # or "left-hand") - - # Say this is the original argument list: - # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] - # ^ - # (we are about to process arg(i)). - # - # Then rargs is [arg(i), ..., arg(N-1)] - # and largs is a *subset* of [arg0, ..., arg(i-1)] - # (any options and their arguments will have been removed - # from largs). - # - # _process_arg() will always consume 1 or more arguments. - # If it consumes 1 (eg. arg is an option that takes no arguments), - # then after _process_arg() is done the situation is: - # largs = subset of [arg0, ..., arg(i)] - # rargs = [arg(i+1), ..., arg(N-1)] - # - # If allow_interspersed_args is false, largs will always be - # *empty* -- still a subset of [arg0, ..., arg(i-1)], but - # not a very interesting subset! - - self.rargs = rargs - self.largs = largs = [] - self.values = values - - stop = 0 - while rargs and not stop: - try: - stop = self._process_arg(largs, rargs, values) - except (BadOptionError, OptionValueError), err: - self.error(err.msg) - - args = largs + rargs - return self.check_values(values, args) - - def check_values (self, values, args): - """ - check_values(values : Values, args : [string]) - -> (values : Values, args : [string]) - - Check that the supplied option values and leftover arguments are - valid. Returns the option values and leftover arguments - (possibly adjusted, possibly completely new -- whatever you - like). Default implementation just returns the passed-in - values; subclasses may override as desired. - """ - return (values, args) - - def _process_arg (self, largs, rargs, values): - """_process_args(largs : [string], - rargs : [string], - values : Values) - -> stop : boolean - - Process a single command-line argument, consuming zero or more - arguments. The next argument to process is rargs[0], which will - almost certainly be consumed from rargs. (It might wind up in - largs, or it might affect a value in values, or -- if a callback - is involved -- almost anything might happen. It will not be - consumed if it is a non-option argument and - allow_interspersed_args is false.) More arguments from rargs - may also be consumed, depending on circumstances. - - Returns true if option processing should stop after this - argument is processed. - """ - - # We handle bare "--" explicitly, and bare "-" is handled by the - # standard arg handler since the short arg case ensures that the len - # of the opt string is greater than 1. - - arg = rargs[0] - if arg == "--": - del rargs[0] - return 1 - elif arg[0:2] == "--": - # process a single long option (possibly with value(s)) - self._process_long_opt(rargs, values) - elif arg[:1] == "-" and len(arg) > 1: - # process a cluster of short options (possibly with - # value(s) for the last one only) - self._process_short_opts(rargs, values) - else: - if self.allow_interspersed_args: - largs.append(arg) - del rargs[0] - else: - return 1 # stop now, leave this arg in rargs - - return 0 # keep processing args - - def _match_long_opt (self, opt): - """_match_long_opt(opt : string) -> string - - Determine which long option string 'opt' matches, ie. which one - it is an unambiguous abbrevation for. Raises BadOptionError if - 'opt' doesn't unambiguously match any long option string. - """ - return _match_abbrev(opt, self._long_opts) - - def _process_long_opt (self, rargs, values): - arg = rargs.pop(0) - - # Value explicitly attached to arg? Pretend it's the next - # argument. - if "=" in arg: - (opt, next_arg) = arg.split("=", 1) - rargs.insert(0, next_arg) - had_explicit_value = 1 - else: - opt = arg - had_explicit_value = 0 - - opt = self._match_long_opt(opt) - option = self._long_opt[opt] - if option.takes_value(): - nargs = option.nargs - if len(rargs) < nargs: - if nargs == 1: - self.error("%s option requires a value" % opt) - else: - self.error("%s option requires %d values" - % (opt, nargs)) - elif nargs == 1: - value = rargs.pop(0) - else: - value = tuple(rargs[0:nargs]) - del rargs[0:nargs] - - elif had_explicit_value: - self.error("%s option does not take a value" % opt) - - else: - value = None - - option.process(opt, value, values, self) - - def _process_short_opts (self, rargs, values): - arg = rargs.pop(0) - stop = 0 - i = 1 - for ch in arg[1:]: - opt = "-" + ch - option = self._short_opt.get(opt) - i += 1 # we have consumed a character - - if not option: - self.error("no such option: %s" % opt) - if option.takes_value(): - # Any characters left in arg? Pretend they're the - # next arg, and stop consuming characters of arg. - if i < len(arg): - rargs.insert(0, arg[i:]) - stop = 1 - - nargs = option.nargs - if len(rargs) < nargs: - if nargs == 1: - self.error("%s option requires a value" % opt) - else: - self.error("%s option requires %s values" - % (opt, nargs)) - elif nargs == 1: - value = rargs.pop(0) - else: - value = tuple(rargs[0:nargs]) - del rargs[0:nargs] - - else: # option doesn't take a value - value = None - - option.process(opt, value, values, self) - - if stop: - break - - - # -- Output/error methods ------------------------------------------ - - def error (self, msg): - self.print_usage(sys.stderr) - sys.exit("%s: error: %s" % (get_prog_name(), msg)) - - def print_usage (self, file=None): - if self.usage: - usage = self.usage.replace("%prog", get_prog_name()) - print >>file, usage - print >>file - - def print_version (self, file=None): - if self.version: - version = self.version.replace("%prog", get_prog_name()) - print >>file, version - - def print_help (self, file=None): - from distutils.fancy_getopt import wrap_text - - if file is None: - file = sys.stdout - - self.print_usage(file) - - # The help for each option consists of two parts: - # * the opt strings and metavars - # eg. ("-x", or "-fFILENAME, --file=FILENAME") - # * the user-supplied help string - # eg. ("turn on expert mode", "read data from FILENAME") - # - # If possible, we write both of these on the same line: - # -x turn on expert mode - # - # But if the opt string list is too long, we put the help - # string on a second line, indented to the same column it would - # start in if it fit on the first line. - # -fFILENAME, --file=FILENAME - # read data from FILENAME - - print >>file, "options:" - width = 78 # assume 80 cols for now - - option_help = [] # list of (string, string) tuples - lengths = [] - - for option in self.option_list: - takes_value = option.takes_value() - if takes_value: - metavar = option.metavar or option.dest.upper() - - opts = [] # list of "-a" or "--foo=FILE" strings - if option.help is SUPPRESS_HELP: - continue - - if takes_value: - for sopt in option._short_opts: - opts.append(sopt + metavar) - for lopt in option._long_opts: - opts.append(lopt + "=" + metavar) - else: - for opt in option._short_opts + option._long_opts: - opts.append(opt) - - opts = ", ".join(opts) - option_help.append((opts, option.help)) - lengths.append(len(opts)) - - max_opts = min(max(lengths), 20) - - for (opts, help) in option_help: - # how much to indent lines 2 .. N of help text - indent_rest = 2 + max_opts + 2 - help_width = width - indent_rest - - if len(opts) > max_opts: - opts = " " + opts + "\n" - indent_first = indent_rest - - else: # start help on same line as opts - opts = " %-*s " % (max_opts, opts) - indent_first = 0 - - file.write(opts) - - if help: - help_lines = wrap_text(help, help_width) - print >>file, "%*s%s" % (indent_first, "", help_lines[0]) - for line in help_lines[1:]: - print >>file, "%*s%s" % (indent_rest, "", line) - elif opts[-1] != "\n": - file.write("\n") - -# class OptionParser - - -def _match_abbrev (s, words): - """_match_abbrev(s : string, words : [string]) -> string - - Returns the string in 'words' for which 's' is an unambiguous - abbreviation. If 's' is found to be ambiguous or doesn't match any - of 'words', raises BadOptionError. - """ - match = None - for word in words: - # If s isn't even a prefix for this word, don't waste any - # more time on it: skip to the next word and try again. - if not word.startswith(s): - continue - - # Exact match? Great, return now. - if s == word: - return word - - # Now comes the tricky business of disambiguation. At this - # point, we know s is a proper prefix of word, eg. s='--foo' and - # word=='--foobar'. If we have already seen another word where - # this was the case, eg. '--foobaz', fail: s is ambiguous. - # Otherwise record this match and keep looping; we will return - # if we see an exact match, or when we fall out of the loop and - # it turns out that the current word is the match. - if match: - raise BadOptionError("ambiguous option: %s (%s, %s, ...?)" - % (s, match, word)) - match = word - - if match: - return match - else: - raise BadOptionError("no such option: %s" % s) diff --git a/cobbler/Cheetah/Version.py b/cobbler/Cheetah/Version.py deleted file mode 100644 index 32af08a..0000000 --- a/cobbler/Cheetah/Version.py +++ /dev/null @@ -1,58 +0,0 @@ -Version = '2.0rc7' -VersionTuple = (2,0,0,'candidate',7) - -MinCompatibleVersion = '2.0rc6' -MinCompatibleVersionTuple = (2,0,0,'candidate',6) - -#### -def convertVersionStringToTuple(s): - versionNum = [0,0,0] - releaseType = 'final' - releaseTypeSubNum = 0 - if s.find('a')!=-1: - num, releaseTypeSubNum = s.split('a') - releaseType = 'alpha' - elif s.find('b')!=-1: - num, releaseTypeSubNum = s.split('b') - releaseType = 'beta' - elif s.find('rc')!=-1: - num, releaseTypeSubNum = s.split('rc') - releaseType = 'candidate' - else: - num = s - num = num.split('.') - for i in range(len(num)): - versionNum[i] = int(num[i]) - if len(versionNum)<3: - versionNum += [0] - releaseTypeSubNum = int(releaseTypeSubNum) - - return tuple(versionNum+[releaseType,releaseTypeSubNum]) - - -if __name__ == '__main__': - c = convertVersionStringToTuple - print c('2.0a1') - print c('2.0b1') - print c('2.0rc1') - print c('2.0') - print c('2.0.2') - - - assert c('0.9.19b1') < c('0.9.19') - assert c('0.9b1') < c('0.9.19') - - assert c('2.0a2') > c('2.0a1') - assert c('2.0b1') > c('2.0a2') - assert c('2.0b2') > c('2.0b1') - assert c('2.0b2') == c('2.0b2') - - assert c('2.0rc1') > c('2.0b1') - assert c('2.0rc2') > c('2.0rc1') - assert c('2.0rc2') > c('2.0b1') - - assert c('2.0') > c('2.0a1') - assert c('2.0') > c('2.0b1') - assert c('2.0') > c('2.0rc1') - assert c('2.0.1') > c('2.0') - assert c('2.0rc1') > c('2.0b1') diff --git a/cobbler/Cheetah/__init__.py b/cobbler/Cheetah/__init__.py deleted file mode 100644 index 08c240e..0000000 --- a/cobbler/Cheetah/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# $Id: __init__.py,v 1.10 2006/01/14 04:44:07 tavis_rudd Exp $ - -"""Cheetah is an open source template engine and code generation tool. - -It can be used standalone or combined with other tools and frameworks. Web -development is its principle use, but Cheetah is very flexible and is also being -used to generate C++ game code, Java, sql, form emails and even Python code. - -Homepage -================================================================================ -http://www.CheetahTemplate.org/ - -Documentation -================================================================================ -For a high-level introduction to Cheetah please refer to the User's Guide -at http://cheetahtemplate.org/learn.html - -Mailing list -================================================================================ -cheetahtemplate-discuss@lists.sourceforge.net -Subscribe at http://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.10 $"[11:-2] - -from Version import Version diff --git a/cobbler/Cheetah/_namemapper.so b/cobbler/Cheetah/_namemapper.so Binary files differdeleted file mode 100755 index 8f56724..0000000 --- a/cobbler/Cheetah/_namemapper.so +++ /dev/null diff --git a/cobbler/Cheetah/convertTmplPathToModuleName.py b/cobbler/Cheetah/convertTmplPathToModuleName.py deleted file mode 100644 index 4f9d8ea..0000000 --- a/cobbler/Cheetah/convertTmplPathToModuleName.py +++ /dev/null @@ -1,15 +0,0 @@ -import os.path -import string - -l = ['_'] * 256 -for c in string.digits + string.letters: - l[ord(c)] = c -_pathNameTransChars = string.join(l, '') -del l, c - -def convertTmplPathToModuleName(tmplPath, - _pathNameTransChars=_pathNameTransChars, - splitdrive=os.path.splitdrive, - translate=string.translate, - ): - return translate(splitdrive(tmplPath)[1], _pathNameTransChars) |