Cheetah-2.4.4/0000755000175000001440000000000011501314001012122 5ustar tylerusersCheetah-2.4.4/Cheetah.egg-info/0000755000175000001440000000000011501314001015155 5ustar tylerusersCheetah-2.4.4/Cheetah.egg-info/dependency_links.txt0000644000175000001440000000000111501314001021223 0ustar tylerusers Cheetah-2.4.4/Cheetah.egg-info/SOURCES.txt0000644000175000001440000000375111501314001017047 0ustar tylerusersCHANGES LICENSE MANIFEST.in README.markdown SetupConfig.py SetupTools.py TODO setup.py Cheetah.egg-info/PKG-INFO Cheetah.egg-info/SOURCES.txt Cheetah.egg-info/dependency_links.txt Cheetah.egg-info/requires.txt Cheetah.egg-info/top_level.txt bin/cheetah bin/cheetah-analyze bin/cheetah-compile cheetah/CacheRegion.py cheetah/CacheStore.py cheetah/CheetahWrapper.py cheetah/Compiler.py cheetah/DirectiveAnalyzer.py cheetah/Django.py cheetah/DummyTransaction.py cheetah/ErrorCatchers.py cheetah/FileUtils.py cheetah/Filters.py cheetah/ImportHooks.py cheetah/ImportManager.py cheetah/NameMapper.py cheetah/Parser.py cheetah/Servlet.py cheetah/SettingsManager.py cheetah/SourceReader.py cheetah/Template.py cheetah/TemplateCmdLineIface.py cheetah/Unspecified.py cheetah/Version.py cheetah/__init__.py cheetah/convertTmplPathToModuleName.py cheetah/Macros/I18n.py cheetah/Macros/__init__.py cheetah/Templates/SkeletonPage.py cheetah/Templates/SkeletonPage.tmpl cheetah/Templates/_SkeletonPage.py cheetah/Templates/__init__.py cheetah/Tests/Analyzer.py cheetah/Tests/CheetahWrapper.py cheetah/Tests/Cheps.py cheetah/Tests/Filters.py cheetah/Tests/Misc.py cheetah/Tests/NameMapper.py cheetah/Tests/Parser.py cheetah/Tests/Performance.py cheetah/Tests/Regressions.py cheetah/Tests/SyntaxAndOutput.py cheetah/Tests/Template.py cheetah/Tests/Test.py cheetah/Tests/Unicode.py cheetah/Tests/__init__.py cheetah/Tests/xmlrunner.py cheetah/Tools/CGITemplate.py cheetah/Tools/MondoReport.py cheetah/Tools/MondoReportDoc.txt cheetah/Tools/RecursiveNull.py cheetah/Tools/SiteHierarchy.py cheetah/Tools/__init__.py cheetah/Tools/turbocheetah/__init__.py cheetah/Tools/turbocheetah/cheetahsupport.py cheetah/Tools/turbocheetah/tests/__init__.py cheetah/Tools/turbocheetah/tests/test_template.py cheetah/Utils/Indenter.py cheetah/Utils/Misc.py cheetah/Utils/WebInputMixin.py cheetah/Utils/__init__.py cheetah/Utils/htmlDecode.py cheetah/Utils/htmlEncode.py cheetah/Utils/statprof.py cheetah/c/Cheetah.h cheetah/c/_namemapper.c cheetah/c/cheetah.hCheetah-2.4.4/Cheetah.egg-info/requires.txt0000644000175000001440000000002111501314001017546 0ustar tylerusersMarkdown >= 2.0.1Cheetah-2.4.4/Cheetah.egg-info/top_level.txt0000644000175000001440000000001011501314001017676 0ustar tylerusersCheetah Cheetah-2.4.4/Cheetah.egg-info/PKG-INFO0000644000175000001440000000423311501314001016254 0ustar tylerusersMetadata-Version: 1.0 Name: Cheetah Version: 2.4.4 Summary: Cheetah is a template engine and code generation tool. Home-page: http://www.cheetahtemplate.org/ Author: R. Tyler Ballance Author-email: cheetahtemplate-discuss@lists.sf.net License: UNKNOWN Description: 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. Documentation ================================================================================ For a high-level introduction to Cheetah please refer to the User's Guide at http://www.cheetahtemplate.org/learn.html Mailing list ================================================================================ cheetahtemplate-discuss@lists.sourceforge.net Subscribe at http://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss Credits ================================================================================ http://www.cheetahtemplate.org/credits.html Recent Changes ================================================================================ See http://www.cheetahtemplate.org/CHANGES.txt for full details Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Internet :: WWW/HTTP :: Site Management Classifier: Topic :: Software Development :: Code Generators Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: User Interfaces Classifier: Topic :: Text Processing Cheetah-2.4.4/setup.py0000755000175000001440000000050011444460041013646 0ustar tylerusers#!/usr/bin/env python # $Id: setup.py,v 1.15 2005/01/03 17:58:41 tavis_rudd Exp $ import os try: os.remove('MANIFEST') # to avoid those bloody out-of-date manifests!! except: pass import SetupTools import SetupConfig configurations = (SetupConfig,) SetupTools.run_setup( configurations ) Cheetah-2.4.4/TODO0000644000175000001440000003035011413255114012626 0ustar tylerusersNOTE: Please see http://bugs.cheetahtemplate.org for future feature requests/bugs/TODO =============================================================================== =============================================================================== Desired for Cheetah 2.0 ======================= - Smart HTML filter that escapes all values except those individually marked as preformatted, a la Kid/PTL/QPY. (MO) TODO Items (many are just ideas. This is not an official roadmap!) ================================================================================ - "cheetah test" problem: subcommands fail mysteriously on Windows. Rewrite to avoid using subcommands. Instead, set sys.argv and call the appropriate main() for each test. - Documentation: document #encoding. Explain problems "cheetah test" if they haven't been fixed yet. - There's a kludge in CheetahWrapper.py to abort with a helpful error message if the user runs 'cheetah test' but doesn't have write permission in the current directory. The tests should instead put their temporary files under the system tmp directory. - Reset the current filter to the default (or to the constructor's filter if specified) at the beginning of each fill. Currently, filter changes leak from one fill to the next. - CheetahWrapper stuff: (MO) * "cheetah preview [options] [FILES]" print template-specific portion of main method(s) to stdout, with line numbers based on the .py template module. Make a Template method to do the same thing, a la .generatedModuleCode(). * Refactor, make compile/fill/code routines callbacks using a bundle arg. * If an input file ends in a dot, intelligently add the input extension if not found. - Debugging tools. See section below. - Provide a utility to list the names of all placeholders in the template. Requested by Tracy Ruggles on Feb 21, 2003. - 'errorCatcher None' to stop catching errors in the middle of a template. - Utils.WebInputMixin: factor out Cheetah-specific code so it can be used in non-Cheetah applications. Don't modify the searchList: have a Template wrapper method do that. Consider turning it into a function that does not require 'self'. Consider making Webware-specific code into plugins so that, e.g., other cookie-handling methods can be grafted in. Maybe use callback classes like the planned rewrite for CheetahWrapper. Low priority. (MO) - Look through Zope Page Templates (TAL) for ideas to borrow. http://www.zope.org/Documentation/Books/ZopeBook/current/AppendixC.stx http://www.owlfish.com/software/simpleTAL/index.html Debugging Tools (Dump Tools) ============================ It would be nice to provide debugging tools for users who can't figure out why a certain placeholder value isn't found or is being overridden. My idea is to define $dumpSearchList() and $dumpSearchListFlat() in Template, which would print a stanza in the output showing all searchList variables and their values. $dumpSearchList would group by searchList element; $dumpSearchListFlat would combine all into a single alphabetical listing. I made an experimental version but it printed only instance variables, not methods and not inherited attributes. Also, it wouldn't print right using the usual pattern of write-to-custom-StringIO-object-and-return- the-.getvalue() and I couldn't figure out why. The stanza should be set apart by a row of stars with the words "BEGIN/END SEARCH LIST DUMP". Then for $dumpSearchList, precede each group with "*** searchList[i], type , 142 variables ***". Because some elements like 'self' may have hundreds of inherited methods that would create a forest-through-trees situation for the user, we may need an option to supress the variable listing for elements with > 20 variables (just print the summary line instead). ? The final version should be in Template so it has implicit access to the searchList and perhaps later to other variables (locals, globals, "#set global"s, builtins) too. This is such a central debugging tool that you should not have to monopolize an #extends (the template's only #extends) to use it. You could import it, however, if you pass in the searchList explicitly as an argument. In that case, perhaps we can base it on a generic module for dumping variables/values. Note that we cannot simply depend on str() and pprint, because we need to show instances as dictionaries. Likewise, dir() and vars() may get us part of the distance, but only if they show methods and inherited attributes too. These functions should print only top-level variables, not the subelements of collections. I.e, if the first searchList element is a dictionary, show its keys/values, but do not expand any subvalues if they are dictionaries too, unless the display tool happens to default to that. #entry $func($arg1, $arg2="default", $**kw) =============================================================================== Make a wrapper function in the .py template module that builds a searchList from its positional arguments, then instantiates and fills a template and returns the result. The preceding example would create a function thus: def func(arg1, arg2="default", searchList=None, **kw): """Function docstring.""" sl = {'arg1': arg1, 'arg2': arg2} if searchList is None: searchList = [sl] elif type(searchList) == types.ListType: searchList.insert(0, sl) else: raise TypeError("arg 'searchList'") t = TheTemplate(searchList=searchList, **kw) return str(t) ##doc-entry: and #*doc-entry: comments are appended to the function docstring. Finally, make this function accessible directly from the shell. If there are any non-option arguments on the command line, call the function instead of filling the template the normal way. This would perhaps make more sense as arguments to .respond(). But .respond() has that pesky 'trans' argument that mustn't be interfered with, and other programs may assume .respond() takes only one argument. Also, when called via str(), str() cannot take arguments. #indent ======================================================================== The current indenter (which exists but is undocumented) is a kludge that has an indentation object, with implicit placeholder calls added at each line to generate the indentation, and #silent calls to adjust the object. It should be reimplemented to generate code to call the indentation object directly. Also, the user interface should be cleaned up, the implementation and Users' Guide synchronized, and test cases built. The desired implementation revolves around self._indenter, which knows the current indentation level (a non-negative integer), chars (the string output per level, default four spaces), and stack (the previous indentation levels). The .indent() method returns the indentation string currently appropriate. The desired interface for phase 1 (subject to change): #indent strip ; strip leading whitespace from input lines #indent add ; add indentation to output lines as appropriate #indent on ; do both #indent off ; do neither #indent reset ; set level to 0 and clear stack #indent ++ ; increment level #indent -- ; decrement level #indent pop [EXPR] ; revert to Nth previous level (default 1) ; if pop past end of stack, set level to 0 and ; clear stack. All +/-/= operations push the old level ; onto the stack. #indent debug ; dump level, chars and stack to template output Possible extensions: #indent =EXPR ; set level to N (likely to be added to phase 1) #indent +EXPR ; add N to level (not very necessary) #indent -EXPR ; subtract N from level (not very necessary) #indent balance BOOL ; require all indent changes in a #def/#block to be ; popped before exiting the method. (difficult to ; implement) #indent implicitPop BOOL ; automatically pop indent changes within a ; #def/block when that method exits. (difficult to ; implement) #indent ?? ; a 3-way switch that combines unbalanced, balanced and ; implicit pop. (difficult to implement) #indent ?? ; smart stripping: strip input indentation according to ; nested directive level; e.g., ; 01: #if foo=1 ; 02: public int foo() ; 03: { ; 04: return FOO; ; 05: } ; 06: #end if ; With smart stripping, line 4 would be indented and the ; others not. With "on" or "strip" stripping, all lines ; 2-5 would be unindented. With "off" stripping, ; lines 2-5 would not be stripped. There should be one indentation object per Template instance, shared by methods and include files. Upload File ======================================================================== @@TR: This is way outside Cheetah's scope! A mixin method in Cheetah.Utils (for Template) that handles file uploads -- these are too complicated for .webInput(). The method should do a "safe" file upload; e.g., http://us3.php.net/manual/en/features.file-upload.php , within the limitations of Python's cgi module. The user has the choice of three destinations for the file contents: (A) copied to a local path you specify, (B) placed in a namespace variable like .cgiImport() does, or (C) returned. (B) parallels .webInput, but (A) will certainly be desirable situations where we just want to save the file, not read it into memory. Reject files larger than a user-specified size or not in a list of user-approved MIME types. Define appropriate exceptions for typical file-upload errors. Method name .webUploadFileAsString? One situation to support is when form has a text(area) field related to a file-upload control on the same form, and the user has the choice of typing into the field or uploading a text file. We need a method that updates the text field's value if there is an uploaded file, but not if there isn't. This may be handled by the regular method(s) or may require a separate method. RPM Building ============ From: John Landahl To: cheetahtemplate-discuss@lists.sourceforge.net Subject: [Cheetahtemplate-discuss] Building Cheetah RPMs Date: Wed, 05 Nov 2003 01:27:24 -0800 If anyone is interested in building Cheetah RPMs, simply add the following lines to a file called MANIFEST.in in the Cheetah directory and you'll be able to use the "bdist_rpm" option to setup.py (i.e. "python setup.py bdist_rpm"): include SetupTools.py include SetupConfig.py include bin/* Also, I've found that using /usr/lib/site-python for add-on Python packages is much more convenient than the default of /usr/lib/pythonX/site-packages, especially when jumping back and forth between 2.2 and 2.3. If you'd like Cheetah in /usr/lib/site-python, createa a setup.cfg with the following contents: [install] install-lib = /usr/lib/site-python Of course if you do have version specific libraries they should stay in /usr/lib/pythonX/site-packages, but Cheetah seems happy in both 2.2 and 2.3 and so is a good candidate for /usr/lib/site-python. User-defined directives ======================================================================= IF we decide to support user-defined directives someday, consider Spyce's interface. Spyce uses a base class which provides generic services to custom "active tags". http://spyce.sourceforge.net/doc-tag.html http://spyce.sourceforge.net/doc-tag_new.html Test Suite ================================================================================ - add cases that test the cheetah-compile script - add cases that test the integration with various webdev frameworks Examples ================================================================================ - create some non-html code generation examples - SQL - LaTeX - form email - Template definitions in a database. .py template modules in a database? Caching template classes and/or instances extracted from a database. - Pickled templates? Cheetah-2.4.4/cheetah/0000755000175000001440000000000011501314001013523 5ustar tylerusersCheetah-2.4.4/cheetah/TemplateCmdLineIface.py0000644000175000001440000000635711413255133020063 0ustar tylerusers# $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 Version: $Revision: 1.13 $ Start Date: 2001/12/06 Last Revision Date: $Date: 2006/01/10 20:34:35 $ """ __author__ = "Tavis Rudd " __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 Use a variables from a dictionary stored in Python pickle file to fill $placeholders in the template. If 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 Cheetah-2.4.4/cheetah/Macros/0000755000175000001440000000000011501314001014747 5ustar tylerusersCheetah-2.4.4/cheetah/Macros/__init__.py0000644000175000001440000000000211413255133017064 0ustar tylerusers# Cheetah-2.4.4/cheetah/Macros/I18n.py0000644000175000001440000000426611413255133016064 0ustar tylerusersimport 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 %s ''' % ', '.join(list(intersection))) logging.info(''' Please change the key's name or use the compiler setting "prioritizeSearchListOverSelf=True" to prevent the NameMapper from using ''') logging.info(''' the Template member in place of your searchList variable ''') self._initCheetahInstance( searchList=searchList, namespaces=namespaces, filter=filter, filtersLib=filtersLib, errorCatcher=errorCatcher, _globalSetVars=_globalSetVars, compilerSettings=compilerSettings, _preBuiltSearchList=_preBuiltSearchList) ################################################## ## Now, compile if we're meant to if (source is not None) or (file is not None): self._compile(source, file, compilerSettings=compilerSettings) def generatedModuleCode(self): """Return the module code the compiler generated, or None if no compilation took place. """ return self._CHEETAH_generatedModuleCode def generatedClassCode(self): """Return the class code the compiler generated, or None if no compilation took place. """ return self._CHEETAH_generatedModuleCode[ self._CHEETAH_generatedModuleCode.find('\nclass '): self._CHEETAH_generatedModuleCode.find('\n## END CLASS DEFINITION')] def searchList(self): """Return a reference to the searchlist """ return self._CHEETAH__searchList def errorCatcher(self): """Return a reference to the current errorCatcher """ return self._CHEETAH__errorCatcher ## cache methods ## def _getCacheStore(self): if not self._CHEETAH__cacheStore: if self._CHEETAH_cacheStore is not None: self._CHEETAH__cacheStore = self._CHEETAH_cacheStore else: # @@TR: might want to provide a way to provide init args self._CHEETAH__cacheStore = self._CHEETAH_cacheStoreClass() return self._CHEETAH__cacheStore def _getCacheStoreIdPrefix(self): if self._CHEETAH_cacheStoreIdPrefix is not None: return self._CHEETAH_cacheStoreIdPrefix else: return str(id(self)) def _createCacheRegion(self, regionID): return self._CHEETAH_cacheRegionClass( regionID=regionID, templateCacheIdPrefix=self._getCacheStoreIdPrefix(), cacheStore=self._getCacheStore()) def getCacheRegion(self, regionID, cacheInfo=None, create=True): cacheRegion = self._CHEETAH__cacheRegions.get(regionID) if not cacheRegion and create: cacheRegion = self._createCacheRegion(regionID) self._CHEETAH__cacheRegions[regionID] = cacheRegion return cacheRegion def getCacheRegions(self): """Returns a dictionary of the 'cache regions' initialized in a template. Each #cache directive block or $*cachedPlaceholder is a separate 'cache region'. """ # returns a copy to prevent users mucking it up return self._CHEETAH__cacheRegions.copy() def refreshCache(self, cacheRegionId=None, cacheItemId=None): """Refresh a cache region or a specific cache item within a region. """ if not cacheRegionId: for cacheRegion in self.getCacheRegions().itervalues(): cacheRegion.clear() else: cregion = self._CHEETAH__cacheRegions.get(cacheRegionId) if not cregion: return if not cacheItemId: # clear the desired region and all its cacheItems cregion.clear() else: # clear one specific cache of a specific region cache = cregion.getCacheItem(cacheItemId) if cache: cache.clear() ## end cache methods ## def shutdown(self): """Break reference cycles before discarding a servlet. """ try: Servlet.shutdown(self) except: pass self._CHEETAH__searchList = None self.__dict__ = {} ## utility functions ## def getVar(self, varName, default=Unspecified, autoCall=True): """Get a variable from the searchList. If the variable can't be found in the searchList, it returns the default value if one was given, or raises NameMapper.NotFound. """ try: return valueFromSearchList(self.searchList(), varName.replace('$', ''), autoCall) except NotFound: if default is not Unspecified: return default else: raise def varExists(self, varName, autoCall=True): """Test if a variable name exists in the searchList. """ try: valueFromSearchList(self.searchList(), varName.replace('$', ''), autoCall) return True except NotFound: return False hasVar = varExists def i18n(self, message, plural=None, n=None, id=None, domain=None, source=None, target=None, comment=None ): """This is just a stub at this time. plural = the plural form of the message n = a sized argument to distinguish between single and plural forms id = msgid in the translation catalog domain = translation domain source = source lang target = a specific target lang comment = a comment to the translation team See the following for some ideas http://www.zope.org/DevHome/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport Other notes: - There is no need to replicate the i18n:name attribute from plone / PTL, as cheetah placeholders serve the same purpose """ return message def getFileContents(self, path): """A hook for getting the contents of a file. The default implementation just uses the Python open() function to load local files. This method could be reimplemented to allow reading of remote files via various protocols, as PHP allows with its 'URL fopen wrapper' """ fp = open(path, 'r') output = fp.read() fp.close() return output def runAsMainProgram(self): """Allows the Template to function as a standalone command-line program for static page generation. Type 'python yourtemplate.py --help to see what it's capabable of. """ from TemplateCmdLineIface import CmdLineIface CmdLineIface(templateObj=self).run() ################################################## ## internal methods -- not to be called by end-users def _initCheetahInstance(self, searchList=None, namespaces=None, filter='RawOrEncodedUnicode', # which filter from Cheetah.Filters filtersLib=Filters, errorCatcher=None, _globalSetVars=None, compilerSettings=None, _preBuiltSearchList=None): """Sets up the instance attributes that cheetah templates use at run-time. This is automatically called by the __init__ method of compiled templates. Note that the names of instance attributes used by Cheetah are prefixed with '_CHEETAH__' (2 underscores), where class attributes are prefixed with '_CHEETAH_' (1 underscore). """ if getattr(self, '_CHEETAH__instanceInitialized', False): return if namespaces is not None: assert searchList is None, ( 'Provide "namespaces" or "searchList", not both!') searchList = namespaces if searchList is not None and not isinstance(searchList, (list, tuple)): searchList = [searchList] self._CHEETAH__globalSetVars = {} if _globalSetVars is not None: # this is intended to be used internally by Nested Templates in #include's self._CHEETAH__globalSetVars = _globalSetVars if _preBuiltSearchList is not None: # happens with nested Template obj creation from #include's self._CHEETAH__searchList = list(_preBuiltSearchList) self._CHEETAH__searchList.append(self) else: # create our own searchList self._CHEETAH__searchList = [self._CHEETAH__globalSetVars, self] if searchList is not None: if isinstance(compilerSettings, dict) and compilerSettings.get('prioritizeSearchListOverSelf'): self._CHEETAH__searchList = searchList + self._CHEETAH__searchList else: self._CHEETAH__searchList.extend(list(searchList)) self._CHEETAH__cheetahIncludes = {} self._CHEETAH__cacheRegions = {} self._CHEETAH__indenter = Indenter() # @@TR: consider allowing simple callables as the filter argument self._CHEETAH__filtersLib = filtersLib self._CHEETAH__filters = {} if isinstance(filter, basestring): filterName = filter klass = getattr(self._CHEETAH__filtersLib, filterName) else: klass = filter filterName = klass.__name__ self._CHEETAH__currentFilter = self._CHEETAH__filters[filterName] = klass(self).filter self._CHEETAH__initialFilter = self._CHEETAH__currentFilter self._CHEETAH__errorCatchers = {} if errorCatcher: if isinstance(errorCatcher, basestring): errorCatcherClass = getattr(ErrorCatchers, errorCatcher) elif isinstance(errorCatcher, type): errorCatcherClass = errorCatcher self._CHEETAH__errorCatcher = ec = errorCatcherClass(self) self._CHEETAH__errorCatchers[errorCatcher.__class__.__name__] = ec else: self._CHEETAH__errorCatcher = None self._CHEETAH__initErrorCatcher = self._CHEETAH__errorCatcher if not hasattr(self, 'transaction'): self.transaction = None self._CHEETAH__instanceInitialized = True self._CHEETAH__isBuffering = False self._CHEETAH__isControlledByWebKit = False self._CHEETAH__cacheStore = None if self._CHEETAH_cacheStore is not None: self._CHEETAH__cacheStore = self._CHEETAH_cacheStore def _compile(self, source=None, file=None, compilerSettings=Unspecified, moduleName=None, mainMethodName=None): """Compile the template. This method is automatically called by Template.__init__ it is provided with 'file' or 'source' args. USERS SHOULD *NEVER* CALL THIS METHOD THEMSELVES. Use Template.compile instead. """ if compilerSettings is Unspecified: compilerSettings = self._getCompilerSettings(source, file) or {} mainMethodName = mainMethodName or self._CHEETAH_defaultMainMethodName self._fileMtime = None self._fileDirName = None self._fileBaseName = None if file and isinstance(file, basestring): file = self.serverSidePath(file) self._fileMtime = os.path.getmtime(file) self._fileDirName, self._fileBaseName = os.path.split(file) self._filePath = file templateClass = self.compile(source, file, moduleName=moduleName, mainMethodName=mainMethodName, compilerSettings=compilerSettings, keepRefToGeneratedCode=True) if not self.__class__ == Template: # Only propogate attributes if we're in a subclass of # Template for k, v in self.__class__.__dict__.iteritems(): if not v or k.startswith('__'): continue ## Propogate the class attributes to the instance ## since we're about to obliterate self.__class__ ## (see: cheetah.Tests.Tepmlate.SubclassSearchListTest) setattr(self, k, v) self.__class__ = templateClass # must initialize it so instance attributes are accessible templateClass.__init__(self, #_globalSetVars=self._CHEETAH__globalSetVars, #_preBuiltSearchList=self._CHEETAH__searchList ) if not hasattr(self, 'transaction'): self.transaction = None def _handleCheetahInclude(self, srcArg, trans=None, includeFrom='file', raw=False): """Called at runtime to handle #include directives. """ _includeID = srcArg if _includeID not in self._CHEETAH__cheetahIncludes: if not raw: if includeFrom == 'file': source = None if isinstance(srcArg, basestring): if hasattr(self, 'serverSidePath'): file = path = self.serverSidePath(srcArg) else: file = path = os.path.normpath(srcArg) else: file = srcArg ## a file-like object else: source = srcArg file = None # @@TR: might want to provide some syntax for specifying the # Template class to be used for compilation so compilerSettings # can be changed. compiler = self._getTemplateAPIClassForIncludeDirectiveCompilation(source, file) nestedTemplateClass = compiler.compile(source=source, file=file) nestedTemplate = nestedTemplateClass(_preBuiltSearchList=self.searchList(), _globalSetVars=self._CHEETAH__globalSetVars) # Set the inner template filters to the initial filter of the # outer template: # this is the only really safe way to use # filter='WebSafe'. nestedTemplate._CHEETAH__initialFilter = self._CHEETAH__initialFilter nestedTemplate._CHEETAH__currentFilter = self._CHEETAH__initialFilter self._CHEETAH__cheetahIncludes[_includeID] = nestedTemplate else: if includeFrom == 'file': path = self.serverSidePath(srcArg) self._CHEETAH__cheetahIncludes[_includeID] = self.getFileContents(path) else: self._CHEETAH__cheetahIncludes[_includeID] = srcArg ## if not raw: self._CHEETAH__cheetahIncludes[_includeID].respond(trans) else: trans.response().write(self._CHEETAH__cheetahIncludes[_includeID]) def _getTemplateAPIClassForIncludeDirectiveCompilation(self, source, file): """Returns the subclass of Template which should be used to compile #include directives. This abstraction allows different compiler settings to be used in the included template than were used in the parent. """ if issubclass(self.__class__, Template): return self.__class__ else: return Template ## functions for using templates as CGI scripts def webInput(self, names, namesMulti=(), default='', src='f', defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False): """Method for importing web transaction variables in bulk. This works for GET/POST fields both in Webware servlets and in CGI scripts, and for cookies and session variables in Webware servlets. If you try to read a cookie or session variable in a CGI script, you'll get a RuntimeError. 'In a CGI script' here means 'not running as a Webware servlet'. If the CGI environment is not properly set up, Cheetah will act like there's no input. The public method provided is: def webInput(self, names, namesMulti=(), default='', src='f', defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False): This method places the specified GET/POST fields, cookies or session variables into a dictionary, which is both returned and put at the beginning of the searchList. It handles: * single vs multiple values * conversion to integer or float for specified names * default values/exceptions for missing or bad values * printing a snapshot of all values retrieved for debugging All the 'default*' and 'bad*' arguments have 'use or raise' behavior, meaning that if they're a subclass of Exception, they're raised. If they're anything else, that value is substituted for the missing/bad value. The simplest usage is: #silent $webInput(['choice']) $choice dic = self.webInput(['choice']) write(dic['choice']) Both these examples retrieves the GET/POST field 'choice' and print it. If you leave off the'#silent', all the values would be printed too. But a better way to preview the values is #silent $webInput(['name'], $debug=1) because this pretty-prints all the values inside HTML
 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 
        License: This software is released for unlimited distribution under the
                 terms of the MIT license.  See the LICENSE file.
        Version: $Revision: 1.186 $
        Start Date: 2002/03/17
        Last Revision Date: $Date: 2008/03/10 04:48:11 $
        """ 
        src = src.lower()
        isCgi = not self._CHEETAH__isControlledByWebKit
        if   isCgi and src in ('f', 'v'):
            global _formUsedByWebInput
            if _formUsedByWebInput is None:
                _formUsedByWebInput = cgi.FieldStorage()
            source, func = 'field',   _formUsedByWebInput.getvalue
        elif isCgi and src == 'c':
            raise RuntimeError("can't get cookies from a CGI script")
        elif isCgi and src == 's':
            raise RuntimeError("can't get session variables from a CGI script")
        elif isCgi and src == 'v':
            source, func = 'value',   self.request().value
        elif isCgi and src == 's':
            source, func = 'session', self.request().session().value
        elif src == 'f':
            source, func = 'field',   self.request().field
        elif src == 'c':
            source, func = 'cookie',  self.request().cookie
        elif src == 'v':
            source, func = 'value',   self.request().value
        elif src == 's':
            source, func = 'session', self.request().session().value
        else:
            raise TypeError("arg 'src' invalid")
        sources = source + 's'
        converters = {
            '': _Converter('string', None, default,      default ),
            'int': _Converter('int',     int, defaultInt,   badInt  ),
            'float': _Converter('float', float, defaultFloat, badFloat),  }
        #pprint.pprint(locals());  return {}
        dic = {} # Destination.
        for name in names:
            k, v = _lookup(name, func, False, converters)
            dic[k] = v
        for name in namesMulti:
            k, v = _lookup(name, func, True, converters)
            dic[k] = v
        # At this point, 'dic' contains all the keys/values we want to keep.
        # We could split the method into a superclass
        # method for Webware/WebwareExperimental and a subclass for Cheetah.
        # The superclass would merely 'return dic'.  The subclass would
        # 'dic = super(ThisClass, self).webInput(names, namesMulti, ...)'
        # and then the code below.
        if debug:
           print("
\n" + pprint.pformat(dic) + "\n
\n\n") self.searchList().insert(0, dic) return dic T = Template # Short and sweet for debugging at the >>> prompt. Template.Reserved_SearchList = set(dir(Template)) def genParserErrorFromPythonException(source, file, generatedPyCode, exception): #print dir(exception) filename = isinstance(file, (str, unicode)) and file or None sio = StringIO.StringIO() traceback.print_exc(1, sio) formatedExc = sio.getvalue() if hasattr(exception, 'lineno'): pyLineno = exception.lineno else: pyLineno = int(re.search('[ \t]*File.*line (\d+)', formatedExc).group(1)) lines = generatedPyCode.splitlines() prevLines = [] # (i, content) for i in range(1, 4): if pyLineno-i <=0: break prevLines.append( (pyLineno+1-i, lines[pyLineno-i]) ) nextLines = [] # (i, content) for i in range(1, 4): if not pyLineno+i < len(lines): break nextLines.append( (pyLineno+i, lines[pyLineno+i]) ) nextLines.reverse() report = 'Line|Python Code\n' report += '----|-------------------------------------------------------------\n' while prevLines: lineInfo = prevLines.pop() report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]} if hasattr(exception, 'offset'): report += ' '*(3+(exception.offset or 0)) + '^\n' while nextLines: lineInfo = nextLines.pop() report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]} message = [ "Error in the Python code which Cheetah generated for this template:", '='*80, '', str(exception), '', report, '='*80, ] cheetahPosMatch = re.search('line (\d+), col (\d+)', formatedExc) if cheetahPosMatch: lineno = int(cheetahPosMatch.group(1)) col = int(cheetahPosMatch.group(2)) #if hasattr(exception, 'offset'): # col = exception.offset message.append('\nHere is the corresponding Cheetah code:\n') else: lineno = None col = None cheetahPosMatch = re.search('line (\d+), col (\d+)', '\n'.join(lines[max(pyLineno-2, 0):])) if cheetahPosMatch: lineno = int(cheetahPosMatch.group(1)) col = int(cheetahPosMatch.group(2)) message.append('\nHere is the corresponding Cheetah code.') message.append('** I had to guess the line & column numbers,' ' so they are probably incorrect:\n') message = '\n'.join(message) reader = SourceReader(source, filename=filename) return ParseError(reader, message, lineno=lineno, col=col) # vim: shiftwidth=4 tabstop=4 expandtab Cheetah-2.4.4/cheetah/Tests/0000755000175000001440000000000011501314001014625 5ustar tylerusersCheetah-2.4.4/cheetah/Tests/Template.py0000644000175000001440000003025711413255133016775 0ustar tylerusers#!/usr/bin/env python import pdb import sys import types import os import os.path import tempfile import shutil import unittest from Cheetah.Template import Template majorVer, minorVer = sys.version_info[0], sys.version_info[1] versionTuple = (majorVer, minorVer) class TemplateTest(unittest.TestCase): pass class ClassMethods_compile(TemplateTest): """I am using the same Cheetah source for each test to root out clashes caused by the compile caching in Template.compile(). """ def test_basicUsage(self): klass = Template.compile(source='$foo') t = klass(namespaces={'foo':1234}) assert str(t)=='1234' def test_baseclassArg(self): klass = Template.compile(source='$foo', baseclass=dict) t = klass({'foo':1234}) assert str(t)=='1234' klass2 = Template.compile(source='$foo', baseclass=klass) t = klass2({'foo':1234}) assert str(t)=='1234' klass3 = Template.compile(source='#implements dummy\n$bar', baseclass=klass2) t = klass3({'foo':1234}) assert str(t)=='1234' klass4 = Template.compile(source='$foo', baseclass='dict') t = klass4({'foo':1234}) assert str(t)=='1234' def test_moduleFileCaching(self): if versionTuple < (2, 3): return tmpDir = tempfile.mkdtemp() try: #print tmpDir assert os.path.exists(tmpDir) klass = Template.compile(source='$foo', cacheModuleFilesForTracebacks=True, cacheDirForModuleFiles=tmpDir) mod = sys.modules[klass.__module__] #print mod.__file__ assert os.path.exists(mod.__file__) assert os.path.dirname(mod.__file__)==tmpDir finally: shutil.rmtree(tmpDir, True) def test_classNameArg(self): klass = Template.compile(source='$foo', className='foo123') assert klass.__name__=='foo123' t = klass(namespaces={'foo':1234}) assert str(t)=='1234' def test_moduleNameArg(self): klass = Template.compile(source='$foo', moduleName='foo99') mod = sys.modules['foo99'] assert klass.__name__=='foo99' t = klass(namespaces={'foo':1234}) assert str(t)=='1234' klass = Template.compile(source='$foo', moduleName='foo1', className='foo2') mod = sys.modules['foo1'] assert klass.__name__=='foo2' t = klass(namespaces={'foo':1234}) assert str(t)=='1234' def test_mainMethodNameArg(self): klass = Template.compile(source='$foo', className='foo123', mainMethodName='testMeth') assert klass.__name__=='foo123' t = klass(namespaces={'foo':1234}) #print t.generatedClassCode() assert str(t)=='1234' assert t.testMeth()=='1234' klass = Template.compile(source='$foo', moduleName='fooXXX', className='foo123', mainMethodName='testMeth', baseclass=dict) assert klass.__name__=='foo123' t = klass({'foo':1234}) #print t.generatedClassCode() assert str(t)=='1234' assert t.testMeth()=='1234' def test_moduleGlobalsArg(self): klass = Template.compile(source='$foo', moduleGlobals={'foo':1234}) t = klass() assert str(t)=='1234' klass2 = Template.compile(source='$foo', baseclass='Test1', moduleGlobals={'Test1':dict}) t = klass2({'foo':1234}) assert str(t)=='1234' klass3 = Template.compile(source='$foo', baseclass='Test1', moduleGlobals={'Test1':dict, 'foo':1234}) t = klass3() assert str(t)=='1234' def test_keepRefToGeneratedCodeArg(self): klass = Template.compile(source='$foo', className='unique58', cacheCompilationResults=False, keepRefToGeneratedCode=False) t = klass(namespaces={'foo':1234}) assert str(t)=='1234' assert not t.generatedModuleCode() klass2 = Template.compile(source='$foo', className='unique58', keepRefToGeneratedCode=True) t = klass2(namespaces={'foo':1234}) assert str(t)=='1234' assert t.generatedModuleCode() klass3 = Template.compile(source='$foo', className='unique58', keepRefToGeneratedCode=False) t = klass3(namespaces={'foo':1234}) assert str(t)=='1234' # still there as this class came from the cache assert t.generatedModuleCode() def test_compilationCache(self): klass = Template.compile(source='$foo', className='unique111', cacheCompilationResults=False) t = klass(namespaces={'foo':1234}) assert str(t)=='1234' assert not klass._CHEETAH_isInCompilationCache # this time it will place it in the cache klass = Template.compile(source='$foo', className='unique111', cacheCompilationResults=True) t = klass(namespaces={'foo':1234}) assert str(t)=='1234' assert klass._CHEETAH_isInCompilationCache # by default it will be in the cache klass = Template.compile(source='$foo', className='unique999099') t = klass(namespaces={'foo':1234}) assert str(t)=='1234' assert klass._CHEETAH_isInCompilationCache class ClassMethods_subclass(TemplateTest): def test_basicUsage(self): klass = Template.compile(source='$foo', baseclass=dict) t = klass({'foo':1234}) assert str(t)=='1234' klass2 = klass.subclass(source='$foo') t = klass2({'foo':1234}) assert str(t)=='1234' klass3 = klass2.subclass(source='#implements dummy\n$bar') t = klass3({'foo':1234}) assert str(t)=='1234' class Preprocessors(TemplateTest): def test_basicUsage1(self): src='''\ %set foo = @a $(@foo*10) @a''' src = '\n'.join([ln.strip() for ln in src.splitlines()]) preprocessors = {'tokens':'@ %', 'namespaces':{'a':99} } klass = Template.compile(src, preprocessors=preprocessors) assert str(klass())=='990\n99' def test_normalizePreprocessorArgVariants(self): src='%set foo = 12\n%%comment\n$(@foo*10)' class Settings1: tokens = '@ %' Settings1 = Settings1() from Cheetah.Template import TemplatePreprocessor settings = Template._normalizePreprocessorSettings(Settings1) preprocObj = TemplatePreprocessor(settings) def preprocFunc(source, file): return '$(12*10)', None class TemplateSubclass(Template): pass compilerSettings = {'cheetahVarStartToken': '@', 'directiveStartToken': '%', 'commentStartToken': '%%', } for arg in ['@ %', {'tokens':'@ %'}, {'compilerSettings':compilerSettings}, {'compilerSettings':compilerSettings, 'templateInitArgs':{}}, {'tokens':'@ %', 'templateAPIClass':TemplateSubclass}, Settings1, preprocObj, preprocFunc, ]: klass = Template.compile(src, preprocessors=arg) assert str(klass())=='120' def test_complexUsage(self): src='''\ %set foo = @a %def func1: #def func(arg): $arg("***") %% comment $(@foo*10) @func1 $func(lambda x:c"--$x--@a")''' src = '\n'.join([ln.strip() for ln in src.splitlines()]) for arg in [{'tokens':'@ %', 'namespaces':{'a':99} }, {'tokens':'@ %', 'namespaces':{'a':99} }, ]: klass = Template.compile(src, preprocessors=arg) t = klass() assert str(t)=='990\n--***--99' def test_i18n(self): src='''\ %i18n: This is a $string that needs translation %i18n id="foo", domain="root": This is a $string that needs translation ''' src = '\n'.join([ln.strip() for ln in src.splitlines()]) klass = Template.compile(src, preprocessors='@ %', baseclass=dict) t = klass({'string':'bit of text'}) #print str(t), repr(str(t)) assert str(t)==('This is a bit of text that needs translation\n'*2)[:-1] class TryExceptImportTest(TemplateTest): def test_FailCase(self): ''' Test situation where an inline #import statement will get relocated ''' source = ''' #def myFunction() Ahoy! #try #import sys #except ImportError $print "This will never happen!" #end try #end def ''' # This should raise an IndentationError (if the bug exists) klass = Template.compile(source=source, compilerSettings={'useLegacyImportMode' : False}) t = klass(namespaces={'foo' : 1234}) class ClassMethodSupport(TemplateTest): def test_BasicDecorator(self): if sys.version_info[0] == 2 and sys.version_info[1] == 3: print('This version of Python doesn\'t support decorators, skipping tests') return template = ''' #@classmethod #def myClassMethod() #return '$foo = %s' % $foo #end def ''' template = Template.compile(source=template) try: rc = template.myClassMethod(foo='bar') assert rc == '$foo = bar', (rc, 'Template class method didn\'t return what I expected') except AttributeError, ex: self.fail(ex) class StaticMethodSupport(TemplateTest): def test_BasicDecorator(self): if sys.version_info[0] == 2 and sys.version_info[1] == 3: print('This version of Python doesn\'t support decorators, skipping tests') return template = ''' #@staticmethod #def myStaticMethod() #return '$foo = %s' % $foo #end def ''' template = Template.compile(source=template) try: rc = template.myStaticMethod(foo='bar') assert rc == '$foo = bar', (rc, 'Template class method didn\'t return what I expected') except AttributeError, ex: self.fail(ex) class Useless(object): def boink(self): return [1, 2, 3] class MultipleInheritanceSupport(TemplateTest): def runTest(self): template = ''' #extends Template, Useless #def foo() #return [4,5] + $boink() #end def ''' template = Template.compile(template, moduleGlobals={'Useless' : Useless}, compilerSettings={'autoImportForExtendsDirective' : False}) template = template() result = template.foo() assert result == [4, 5, 1, 2, 3], (result, 'Unexpected result') class SubclassSearchListTest(TemplateTest): ''' Verify that if we subclass Template, we can still use attributes on that subclass in the searchList ''' def runTest(self): class Sub(Template): greeting = 'Hola' tmpl = Sub('''When we meet, I say "${greeting}"''') self.assertEquals(unicode(tmpl), 'When we meet, I say "Hola"') ################################################## ## if run from the command line ## if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/SyntaxAndOutput.py0000644000175000001440000026646711501313273020370 0ustar tylerusers#!/usr/bin/env python # -*- coding: latin-1 -*- ''' Syntax and Output tests. TODO - #finally - #filter - #errorCatcher - #echo - #silent ''' ################################################## ## DEPENDENCIES ## import sys import types import re from copy import deepcopy import os import os.path import warnings import unittest from Cheetah.NameMapper import NotFound from Cheetah.NameMapper import C_VERSION as NameMapper_C_VERSION from Cheetah.Template import Template from Cheetah.Parser import ParseError from Cheetah.Compiler import Compiler, DEFAULT_COMPILER_SETTINGS class Unspecified(object): pass majorVer, minorVer = sys.version_info[0], sys.version_info[1] versionTuple = (majorVer, minorVer) def testdecorator(func): return func class DummyClass: _called = False def __str__(self): return 'object' def meth(self, arg="arff"): return str(arg) def meth1(self, arg="doo"): return arg def meth2(self, arg1="a1", arg2="a2"): return str(arg1) + str(arg2) def methWithPercentSignDefaultArg(self, arg1="110%"): return str(arg1) def callIt(self, arg=1234): self._called = True self._callArg = arg def dummyFunc(arg="Scooby"): return arg defaultTestNameSpace = { 'aStr': 'blarg', 'anInt': 1, 'aFloat': 1.5, 'aList': ['item0', 'item1', 'item2'], 'aDict': {'one': 'item1', 'two': 'item2', 'nestedDict': {1:'nestedItem1', 'two':'nestedItem2' }, 'nestedFunc': dummyFunc, }, 'aFunc': dummyFunc, 'anObj': DummyClass(), 'aMeth': DummyClass().meth1, 'aStrToBeIncluded': "$aStr $anInt", 'none': None, 'emptyString': '', 'numOne': 1, 'numTwo': 2, 'zero': 0, 'tenDigits': 1234567890, 'webSafeTest': 'abc <=> &', 'strip1': ' \t strippable whitespace \t\t \n', 'strip2': ' \t strippable whitespace \t\t ', 'strip3': ' \t strippable whitespace \t\t\n1 2 3\n', 'blockToBeParsed': """$numOne $numTwo""", 'includeBlock2': """$numOne $numTwo $aSetVar""", 'includeFileName': 'parseTest.txt', 'listOfLambdas': [lambda x: x, lambda x: x, lambda x: x,], 'list': [ {'index': 0, 'numOne': 1, 'numTwo': 2}, {'index': 1, 'numOne': 1, 'numTwo': 2}, ], 'nameList': [('john', 'doe'), ('jane', 'smith')], 'letterList': ['a', 'b', 'c'], '_': lambda x: 'Translated: ' + x, 'unicodeData': u'aoeu12345\u1234', } ################################################## ## TEST BASE CLASSES class OutputTest(unittest.TestCase): report = ''' Template output mismatch: Input Template = %(template)s%(end)s Expected Output = %(expected)s%(end)s Actual Output = %(actual)s%(end)s''' convertEOLs = True _EOLreplacement = None _debugEOLReplacement = False DEBUGLEV = 0 _searchList = [defaultTestNameSpace] _useNewStyleCompilation = True #_useNewStyleCompilation = False _extraCompileKwArgs = None def searchList(self): return self._searchList def verify(self, input, expectedOutput, inputEncoding=None, outputEncoding=None, convertEOLs=Unspecified): if self._EOLreplacement: if convertEOLs is Unspecified: convertEOLs = self.convertEOLs if convertEOLs: input = input.replace('\n', self._EOLreplacement) expectedOutput = expectedOutput.replace('\n', self._EOLreplacement) self._input = input if self._useNewStyleCompilation: extraKwArgs = self._extraCompileKwArgs or {} templateClass = Template.compile( source=input, compilerSettings=self._getCompilerSettings(), keepRefToGeneratedCode=True, **extraKwArgs ) moduleCode = templateClass._CHEETAH_generatedModuleCode searchList = self.searchList() or self._searchList self.template = templateObj = templateClass(searchList=searchList) else: self.template = templateObj = Template( input, searchList=self.searchList(), compilerSettings=self._getCompilerSettings(), ) moduleCode = templateObj._CHEETAH_generatedModuleCode if self.DEBUGLEV >= 1: print(moduleCode) try: output = templateObj.respond() # rather than __str__, because of unicode assert output==expectedOutput, self._outputMismatchReport(output, expectedOutput) finally: templateObj.shutdown() def _getCompilerSettings(self): return {} def _outputMismatchReport(self, output, expectedOutput): if self._debugEOLReplacement and self._EOLreplacement: EOLrepl = self._EOLreplacement marker = '*EOL*' return self.report % {'template': self._input.replace(EOLrepl, marker), 'expected': expectedOutput.replace(EOLrepl, marker), 'actual': output.replace(EOLrepl, marker), 'end': '(end)'} else: return self.report % {'template': self._input, 'expected': expectedOutput, 'actual': output, 'end': '(end)'} def genClassCode(self): if hasattr(self, 'template'): return self.template.generatedClassCode() def genModuleCode(self): if hasattr(self, 'template'): return self.template.generatedModuleCode() ################################################## ## TEST CASE CLASSES class EmptyTemplate(OutputTest): convertEOLs = False def test1(self): """an empty string for the template""" warnings.filterwarnings('error', 'You supplied an empty string for the source!', UserWarning) try: self.verify("", "") except UserWarning: pass else: self.fail("Should warn about empty source strings.") try: self.verify("#implements foo", "") except NotImplementedError: pass else: self.fail("This should barf about respond() not being implemented.") self.verify("#implements respond", "") self.verify("#implements respond(foo=1234)", "") class Backslashes(OutputTest): convertEOLs = False def setUp(self): fp = open('backslashes.txt', 'w') fp.write(r'\ #LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n') fp.flush() fp.close def tearDown(self): if os.path.exists('backslashes.txt'): os.remove('backslashes.txt') def test1(self): """ a single \\ using rawstrings""" self.verify(r"\ ", r"\ ") def test2(self): """ a single \\ using rawstrings and lots of lines""" self.verify(r"\ " + "\n\n\n\n\n\n\n\n\n", r"\ " + "\n\n\n\n\n\n\n\n\n") def test3(self): """ a single \\ without using rawstrings""" self.verify("\ \ ", "\ \ ") def test4(self): """ single line from an apache conf file""" self.verify(r'#LogFormat "%h %l %u %t \"%r\" %>s %b"', r'#LogFormat "%h %l %u %t \"%r\" %>s %b"') def test5(self): """ single line from an apache conf file with many NEWLINES The NEWLINES are used to make sure that MethodCompiler.commitStrConst() is handling long and short strings in the same fashion. It uses triple-quotes for strings with lots of \\n in them and repr(theStr) for shorter strings with only a few newlines.""" self.verify(r'#LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n', r'#LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n') def test6(self): """ test backslash handling in an included file""" self.verify(r'#include "backslashes.txt"', r'\ #LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n') def test7(self): """ a single \\ without using rawstrings plus many NEWLINES""" self.verify("\ \ " + "\n\n\n\n\n\n\n\n\n", "\ \ " + "\n\n\n\n\n\n\n\n\n") def test8(self): """ single line from an apache conf file with single quotes and many NEWLINES """ self.verify(r"""#LogFormat '%h %l %u %t \"%r\" %>s %b'""" + '\n\n\n\n\n\n\n', r"""#LogFormat '%h %l %u %t \"%r\" %>s %b'""" + '\n\n\n\n\n\n\n') class NonTokens(OutputTest): def test1(self): """dollar signs not in Cheetah $vars""" self.verify("$ $$ $5 $. $ test", "$ $$ $5 $. $ test") def test2(self): """hash not in #directives""" self.verify("# \# #5 ", "# # #5 ") def test3(self): """escapted comments""" self.verify(" \##escaped comment ", " ##escaped comment ") def test4(self): """escapted multi-line comments""" self.verify(" \#*escaped comment \n*# ", " #*escaped comment \n*# ") def test5(self): """1 dollar sign""" self.verify("$", "$") def _X_test6(self): """1 dollar sign followed by hash""" self.verify("\n$#\n", "\n$#\n") def test6(self): """1 dollar sign followed by EOL Slurp Token""" if DEFAULT_COMPILER_SETTINGS['EOLSlurpToken']: self.verify("\n$%s\n"%DEFAULT_COMPILER_SETTINGS['EOLSlurpToken'], "\n$") else: self.verify("\n$#\n", "\n$#\n") class Comments_SingleLine(OutputTest): def test1(self): """## followed by WS""" self.verify("## ", "") def test2(self): """## followed by NEWLINE""" self.verify("##\n", "") def test3(self): """## followed by text then NEWLINE""" self.verify("## oeuao aoe uaoe \n", "") def test4(self): """## gobbles leading WS""" self.verify(" ## oeuao aoe uaoe \n", "") def test5(self): """## followed by text then NEWLINE, + leading WS""" self.verify(" ## oeuao aoe uaoe \n", "") def test6(self): """## followed by EOF""" self.verify("##", "") def test7(self): """## followed by EOF with leading WS""" self.verify(" ##", "") def test8(self): """## gobble line with text on previous and following lines""" self.verify("line1\n ## aoeu 1234 \nline2", "line1\nline2") def test9(self): """## don't gobble line with text on previous and following lines""" self.verify("line1\n 12 ## aoeu 1234 \nline2", "line1\n 12 \nline2") def test10(self): """## containing $placeholders """ self.verify("##$a$b $c($d)", "") def test11(self): """## containing #for directive """ self.verify("##for $i in range(15)", "") class Comments_MultiLine_NoGobble(OutputTest): """ Multiline comments used to not gobble whitespace. They do now, but this can be turned off with a compilerSetting """ def _getCompilerSettings(self): return {'gobbleWhitespaceAroundMultiLineComments':False} def test1(self): """#* *# followed by WS Shouldn't gobble WS """ self.verify("#* blarg *# ", " ") def test2(self): """#* *# preceded and followed by WS Shouldn't gobble WS """ self.verify(" #* blarg *# ", " ") def test3(self): """#* *# followed by WS, with NEWLINE Shouldn't gobble WS """ self.verify("#* \nblarg\n *# ", " ") def test4(self): """#* *# preceded and followed by WS, with NEWLINE Shouldn't gobble WS """ self.verify(" #* \nblarg\n *# ", " ") class Comments_MultiLine(OutputTest): """ Note: Multiline comments don't gobble whitespace! """ def test1(self): """#* *# followed by WS Should gobble WS """ self.verify("#* blarg *# ", "") def test2(self): """#* *# preceded and followed by WS Should gobble WS """ self.verify(" #* blarg *# ", "") def test3(self): """#* *# followed by WS, with NEWLINE Shouldn't gobble WS """ self.verify("#* \nblarg\n *# ", "") def test4(self): """#* *# preceded and followed by WS, with NEWLINE Shouldn't gobble WS """ self.verify(" #* \nblarg\n *# ", "") def test5(self): """#* *# containing nothing """ self.verify("#**#", "") def test6(self): """#* *# containing only NEWLINES """ self.verify(" #*\n\n\n\n\n\n\n\n*# ", "") def test7(self): """#* *# containing $placeholders """ self.verify("#* $var $var(1234*$c) *#", "") def test8(self): """#* *# containing #for directive """ self.verify("#* #for $i in range(15) *#", "") def test9(self): """ text around #* *# containing #for directive """ self.verify("foo\nfoo bar #* #for $i in range(15) *# foo\n", "foo\nfoo bar foo\n") def test9(self): """ text around #* *# containing #for directive and trailing whitespace which should be gobbled """ self.verify("foo\nfoo bar #* #for $i in range(15) *# \ntest", "foo\nfoo bar \ntest") def test10(self): """ text around #* *# containing #for directive and newlines: trailing whitespace which should be gobbled. """ self.verify("foo\nfoo bar #* \n\n#for $i in range(15) \n\n*# \ntest", "foo\nfoo bar \ntest") class Placeholders(OutputTest): def test1(self): """1 placeholder""" self.verify("$aStr", "blarg") def test2(self): """2 placeholders""" self.verify("$aStr $anInt", "blarg 1") def test3(self): """2 placeholders, back-to-back""" self.verify("$aStr$anInt", "blarg1") def test4(self): """1 placeholder enclosed in ()""" self.verify("$(aStr)", "blarg") def test5(self): """1 placeholder enclosed in {}""" self.verify("${aStr}", "blarg") def test6(self): """1 placeholder enclosed in []""" self.verify("$[aStr]", "blarg") def test7(self): """1 placeholder enclosed in () + WS Test to make sure that $(.. 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 $*(.. 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 + **cache""" self.verify("$*5*{ aStr }", "blarg") def test14(self): """1 placeholder enclosed in [] + WS + **cache""" self.verify("$*5*[ aStr ]", "blarg") def test15(self): """1 placeholder enclosed in {} + WS + **cache""" self.verify("$*0.5d*{ aStr }", "blarg") def test16(self): """1 placeholder enclosed in [] + WS + **cache""" self.verify("$*.5*[ aStr ]", "blarg") def test17(self): """1 placeholder + **cache""" self.verify("$*5*aStr", "blarg") def test18(self): """1 placeholder **cache""" self.verify("$*0.5h*aStr", "blarg") def test19(self): """1 placeholder surrounded by single quotes and multiple newlines""" self.verify("""'\n\n\n\n'$aStr'\n\n\n\n'""", """'\n\n\n\n'blarg'\n\n\n\n'""") def test20(self): """silent mode $!placeholders """ self.verify("$!aStr$!nonExistant$!*nonExistant$!{nonExistant}", "blarg") try: self.verify("$!aStr$nonExistant", "blarg") except NotFound: pass else: self.fail('should raise NotFound exception') def test21(self): """Make sure that $*caching is actually working""" namesStr = 'You Me Them Everyone' names = namesStr.split() tmpl = Template.compile('#for name in $names: $name ', baseclass=dict) assert str(tmpl({'names':names})).strip()==namesStr tmpl = tmpl.subclass('#for name in $names: $*name ') assert str(tmpl({'names':names}))=='You '*len(names) tmpl = tmpl.subclass('#for name in $names: $*1*name ') assert str(tmpl({'names':names}))=='You '*len(names) tmpl = tmpl.subclass('#for name in $names: $*1*(name) ') assert str(tmpl({'names':names}))=='You '*len(names) if versionTuple > (2, 2): tmpl = tmpl.subclass('#for name in $names: $*1*(name) ') assert str(tmpl(names=names))=='You '*len(names) class Placeholders_Vals(OutputTest): convertEOLs = False def test1(self): """string""" self.verify("$aStr", "blarg") def test2(self): """string - with whitespace""" self.verify(" $aStr ", " blarg ") def test3(self): """empty string - with whitespace""" self.verify("$emptyString", "") def test4(self): """int""" self.verify("$anInt", "1") def test5(self): """float""" self.verify("$aFloat", "1.5") def test6(self): """list""" self.verify("$aList", "['item0', 'item1', 'item2']") def test7(self): """None The default output filter is ReplaceNone. """ self.verify("$none", "") def test8(self): """True, False """ self.verify("$True $False", "%s %s"%(repr(True), repr(False))) def test9(self): """$_ """ self.verify("$_('foo')", "Translated: foo") class PlaceholderStrings(OutputTest): def test1(self): """some c'text $placeholder text' strings""" self.verify("$str(c'$aStr')", "blarg") def test2(self): """some c'text $placeholder text' strings""" self.verify("$str(c'$aStr.upper')", "BLARG") def test3(self): """some c'text $placeholder text' strings""" self.verify("$str(c'$(aStr.upper.replace(c\"A$str()\",\"\"))')", "BLRG") def test4(self): """some c'text $placeholder text' strings""" self.verify("#echo $str(c'$(aStr.upper)')", "BLARG") def test5(self): """some c'text $placeholder text' strings""" self.verify("#if 1 then $str(c'$(aStr.upper)') else 0", "BLARG") def test6(self): """some c'text $placeholder text' strings""" self.verify("#if 1\n$str(c'$(aStr.upper)')#slurp\n#else\n0#end if", "BLARG") def test7(self): """some c'text $placeholder text' strings""" self.verify("#def foo(arg=c'$(\"BLARG\")')\n" "$arg#slurp\n" "#end def\n" "$foo()$foo(c'$anInt')#slurp", "BLARG1") class UnicodeStrings(OutputTest): def test1(self): """unicode data in placeholder """ #self.verify(u"$unicodeData", defaultTestNameSpace['unicodeData'], outputEncoding='utf8') self.verify(u"$unicodeData", defaultTestNameSpace['unicodeData']) def test2(self): """unicode data in body """ self.verify(u"aoeu12345\u1234", u"aoeu12345\u1234") #self.verify(u"#encoding utf8#aoeu12345\u1234", u"aoeu12345\u1234") class EncodingDirective(OutputTest): def test1(self): """basic #encoding """ self.verify("#encoding utf-8\n1234", "1234") def test2(self): """basic #encoding """ self.verify("#encoding ascii\n1234", "1234") def test3(self): """basic #encoding """ self.verify("#encoding utf-8\n\xe1\x88\xb4", u'\u1234', outputEncoding='utf8') def test4(self): """basic #encoding """ self.verify("#encoding latin-1\n\xe1\x88\xb4", u"\xe1\x88\xb4") def test5(self): """basic #encoding """ self.verify("#encoding latin-1\nAndr\202", u'Andr\202') def test6(self): '''Using #encoding on the second line''' self.verify("""### Comments on the first line #encoding utf-8\n\xe1\x88\xb4""", u'\u1234', outputEncoding='utf8') class UnicodeDirective(OutputTest): def test1(self): """basic #unicode """ self.verify("#unicode utf-8\n1234", u"1234") self.verify("#unicode ascii\n1234", u"1234") self.verify("#unicode latin-1\n1234", u"1234") self.verify("#unicode latin-1\n1234ü", u"1234ü") self.verify("#unicode: latin-1\n1234ü", u"1234ü") self.verify("# unicode : latin-1\n1234ü", u"1234ü") self.verify(u"#unicode latin-1\n1234ü", u"1234ü") self.verify("#encoding latin-1\n1234ü", u"1234ü") class Placeholders_Esc(OutputTest): convertEOLs = False def test1(self): """1 escaped placeholder""" self.verify("\$var", "$var") def test2(self): """2 escaped placeholders""" self.verify("\$var \$_", "$var $_") def test3(self): """2 escaped placeholders - back to back""" self.verify("\$var\$_", "$var$_") def test4(self): """2 escaped placeholders - nested""" self.verify("\$var(\$_)", "$var($_)") def test5(self): """2 escaped placeholders - nested and enclosed""" self.verify("\$(var(\$_)", "$(var($_)") class Placeholders_Calls(OutputTest): def test1(self): """func placeholder - no ()""" self.verify("$aFunc", "Scooby") def test2(self): """func placeholder - with ()""" self.verify("$aFunc()", "Scooby") def test3(self): r"""func placeholder - with (\n\n)""" self.verify("$aFunc(\n\n)", "Scooby", convertEOLs=False) def test4(self): r"""func placeholder - with (\n\n) and $() enclosure""" self.verify("$(aFunc(\n\n))", "Scooby", convertEOLs=False) def test5(self): r"""func placeholder - with (\n\n) and ${} enclosure""" self.verify("${aFunc(\n\n)}", "Scooby", convertEOLs=False) def test6(self): """func placeholder - with (int)""" self.verify("$aFunc(1234)", "1234") def test7(self): r"""func placeholder - with (\nint\n)""" self.verify("$aFunc(\n1234\n)", "1234", convertEOLs=False) def test8(self): """func placeholder - with (string)""" self.verify("$aFunc('aoeu')", "aoeu") def test9(self): """func placeholder - with ('''string''')""" self.verify("$aFunc('''aoeu''')", "aoeu") def test10(self): r"""func placeholder - with ('''\nstring\n''')""" self.verify("$aFunc('''\naoeu\n''')", "\naoeu\n", convertEOLs=False) def test11(self): r"""func placeholder - with ('''\nstring'\n''')""" self.verify("$aFunc('''\naoeu'\n''')", "\naoeu'\n", convertEOLs=False) def test12(self): r'''func placeholder - with ("""\nstring\n""")''' self.verify('$aFunc("""\naoeu\n""")', "\naoeu\n", convertEOLs=False) def test13(self): """func placeholder - with (string*int)""" self.verify("$aFunc('aoeu'*2)", "aoeuaoeu") def test14(self): """func placeholder - with (int*int)""" self.verify("$aFunc(2*2)", "4") def test15(self): """func placeholder - with (int*float)""" self.verify("$aFunc(2*2.0)", "4.0") def test16(self): r"""func placeholder - with (int\n*\nfloat)""" self.verify("$aFunc(2\n*\n2.0)", "4.0", convertEOLs=False) def test17(self): """func placeholder - with ($arg=float)""" self.verify("$aFunc($arg=4.0)", "4.0") def test18(self): """func placeholder - with (arg=float)""" self.verify("$aFunc(arg=4.0)", "4.0") def test19(self): """deeply nested argstring, no enclosure""" self.verify("$aFunc($arg=$aMeth($arg=$aFunc(1)))", "1") def test20(self): """deeply nested argstring, no enclosure + with WS""" self.verify("$aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) )", "1") def test21(self): """deeply nested argstring, () enclosure + with WS""" self.verify("$(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )", "1") def test22(self): """deeply nested argstring, {} enclosure + with WS""" self.verify("${aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) }", "1") def test23(self): """deeply nested argstring, [] enclosure + with WS""" self.verify("$[aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) ]", "1") def test24(self): """deeply nested argstring, () enclosure + *cache""" self.verify("$*(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )", "1") def test25(self): """deeply nested argstring, () enclosure + *15*cache""" self.verify("$*15*(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )", "1") def test26(self): """a function call with the Python None kw.""" self.verify("$aFunc(None)", "") class NameMapper(OutputTest): def test1(self): """autocalling""" self.verify("$aFunc! $aFunc().", "Scooby! Scooby.") def test2(self): """nested autocalling""" self.verify("$aFunc($aFunc).", "Scooby.") def test3(self): """list subscription""" self.verify("$aList[0]", "item0") def test4(self): """list slicing""" self.verify("$aList[:2]", "['item0', 'item1']") def test5(self): """list slicing and subcription combined""" self.verify("$aList[:2][0]", "item0") def test6(self): """dictionary access - NameMapper style""" self.verify("$aDict.one", "item1") def test7(self): """dictionary access - Python style""" self.verify("$aDict['one']", "item1") def test8(self): """dictionary access combined with autocalled string method""" self.verify("$aDict.one.upper", "ITEM1") def test9(self): """dictionary access combined with string method""" self.verify("$aDict.one.upper()", "ITEM1") def test10(self): """nested dictionary access - NameMapper style""" self.verify("$aDict.nestedDict.two", "nestedItem2") def test11(self): """nested dictionary access - Python style""" self.verify("$aDict['nestedDict']['two']", "nestedItem2") def test12(self): """nested dictionary access - alternating style""" self.verify("$aDict['nestedDict'].two", "nestedItem2") def test13(self): """nested dictionary access using method - alternating style""" self.verify("$aDict.get('nestedDict').two", "nestedItem2") def test14(self): """nested dictionary access - NameMapper style - followed by method""" self.verify("$aDict.nestedDict.two.upper", "NESTEDITEM2") def test15(self): """nested dictionary access - alternating style - followed by method""" self.verify("$aDict['nestedDict'].two.upper", "NESTEDITEM2") def test16(self): """nested dictionary access - NameMapper style - followed by method, then slice""" self.verify("$aDict.nestedDict.two.upper[:4]", "NEST") def test17(self): """nested dictionary access - Python style using a soft-coded key""" self.verify("$aDict[$anObj.meth('nestedDict')].two", "nestedItem2") def test18(self): """object method access""" self.verify("$anObj.meth1", "doo") def test19(self): """object method access, followed by complex slice""" self.verify("$anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ]", "do") def test20(self): """object method access, followed by a very complex slice If it can pass this one, it's safe to say it works!!""" self.verify("$( anObj.meth1[0:\n (\n(4/4*2)*2)/$anObj.meth1(2)\n ] )", "do") def test21(self): """object method access with % in the default arg for the meth. This tests a bug that Jeff Johnson found and submitted a patch to SF for.""" self.verify("$anObj.methWithPercentSignDefaultArg", "110%") #class NameMapperDict(OutputTest): # # _searchList = [{"update": "Yabba dabba doo!"}] # # def test1(self): # if NameMapper_C_VERSION: # return # This feature is not in the C version yet. # self.verify("$update", "Yabba dabba doo!") # class CacheDirective(OutputTest): def test1(self): r"""simple #cache """ self.verify("#cache:$anInt", "1") def test2(self): r"""simple #cache + WS""" self.verify(" #cache \n$anInt#end cache", "1") def test3(self): r"""simple #cache ... #end cache""" self.verify("""#cache id='cache1', timer=150m $anInt #end cache $aStr""", "1\nblarg") def test4(self): r"""2 #cache ... #end cache blocks""" self.verify("""#slurp #def foo #cache ID='cache1', timer=150m $anInt #end cache #cache id='cache2', timer=15s #for $i in range(5) $i#slurp #end for #end cache $aStr#slurp #end def $foo$foo$foo$foo$foo""", "1\n01234blarg"*5) def test5(self): r"""nested #cache blocks""" self.verify("""#slurp #def foo #cache ID='cache1', timer=150m $anInt #cache id='cache2', timer=15s #for $i in range(5) $i#slurp #end for $*(6)#slurp #end cache #end cache $aStr#slurp #end def $foo$foo$foo$foo$foo""", "1\n012346blarg"*5) def test6(self): r"""Make sure that partial directives don't match""" self.verify("#cache_foo", "#cache_foo") self.verify("#cached", "#cached") class CallDirective(OutputTest): def test1(self): r"""simple #call """ self.verify("#call int\n$anInt#end call", "1") # single line version self.verify("#call int: $anInt", "1") self.verify("#call int: 10\n$aStr", "10\nblarg") def test2(self): r"""simple #call + WS""" self.verify("#call int\n$anInt #end call", "1") def test3(self): r"""a longer #call""" self.verify('''\ #def meth(arg) $arg.upper()#slurp #end def #call $meth $(1234+1) foo#slurp #end call''', "1235 FOO") def test4(self): r"""#call with keyword #args""" self.verify('''\ #def meth(arg1, arg2) $arg1.upper() - $arg2.lower()#slurp #end def #call self.meth #arg arg1 $(1234+1) foo#slurp #arg arg2 UPPER#slurp #end call''', "1235 FOO - upper") def test5(self): r"""#call with single-line keyword #args """ self.verify('''\ #def meth(arg1, arg2) $arg1.upper() - $arg2.lower()#slurp #end def #call self.meth #arg arg1:$(1234+1) foo#slurp #arg arg2:UPPER#slurp #end call''', "1235 FOO - upper") def test6(self): """#call with python kwargs and cheetah output for the 1s positional arg""" self.verify('''\ #def meth(arg1, arg2) $arg1.upper() - $arg2.lower()#slurp #end def #call self.meth arg2="UPPER" $(1234+1) foo#slurp #end call''', "1235 FOO - upper") def test7(self): """#call with python kwargs and #args""" self.verify('''\ #def meth(arg1, arg2, arg3) $arg1.upper() - $arg2.lower() - $arg3#slurp #end def #call self.meth arg2="UPPER", arg3=999 #arg arg1:$(1234+1) foo#slurp #end call''', "1235 FOO - upper - 999") def test8(self): """#call with python kwargs and #args, and using a function to get the function that will be called""" self.verify('''\ #def meth(arg1, arg2, arg3) $arg1.upper() - $arg2.lower() - $arg3#slurp #end def #call getattr(self, "meth") arg2="UPPER", arg3=999 #arg arg1:$(1234+1) foo#slurp #end call''', "1235 FOO - upper - 999") def test9(self): """nested #call directives""" self.verify('''\ #def meth(arg1) $arg1#slurp #end def #def meth2(x,y) $x$y#slurp #end def ## #call self.meth 1#slurp #call self.meth 2#slurp #call self.meth 3#slurp #end call 3 #set two = 2 #call self.meth2 y=c"$(10/$two)" #arg x 4#slurp #end call 4 #end call 2 #end call 1''', "12345") class I18nDirective(OutputTest): def test1(self): r"""simple #call """ self.verify("#i18n \n$anInt#end i18n", "1") # single line version self.verify("#i18n: $anInt", "1") self.verify("#i18n: 10\n$aStr", "10\nblarg") class CaptureDirective(OutputTest): def test1(self): r"""simple #capture""" self.verify('''\ #capture cap1 $(1234+1) foo#slurp #end capture $cap1#slurp ''', "1235 foo") def test2(self): r"""slightly more complex #capture""" self.verify('''\ #def meth(arg) $arg.upper()#slurp #end def #capture cap1 $(1234+1) $anInt $meth("foo")#slurp #end capture $cap1#slurp ''', "1235 1 FOO") class SlurpDirective(OutputTest): def test1(self): r"""#slurp with 1 \n """ self.verify("#slurp\n", "") def test2(self): r"""#slurp with 1 \n, leading whitespace Should gobble""" self.verify(" #slurp\n", "") def test3(self): r"""#slurp with 1 \n, leading content Shouldn't gobble""" self.verify(" 1234 #slurp\n", " 1234 ") def test4(self): r"""#slurp with WS then \n, leading content Shouldn't gobble""" self.verify(" 1234 #slurp \n", " 1234 ") def test5(self): r"""#slurp with garbage chars then \n, leading content Should eat the garbage""" self.verify(" 1234 #slurp garbage \n", " 1234 ") class EOLSlurpToken(OutputTest): _EOLSlurpToken = DEFAULT_COMPILER_SETTINGS['EOLSlurpToken'] def test1(self): r"""#slurp with 1 \n """ self.verify("%s\n"%self._EOLSlurpToken, "") def test2(self): r"""#slurp with 1 \n, leading whitespace Should gobble""" self.verify(" %s\n"%self._EOLSlurpToken, "") def test3(self): r"""#slurp with 1 \n, leading content Shouldn't gobble""" self.verify(" 1234 %s\n"%self._EOLSlurpToken, " 1234 ") def test4(self): r"""#slurp with WS then \n, leading content Shouldn't gobble""" self.verify(" 1234 %s \n"%self._EOLSlurpToken, " 1234 ") def test5(self): r"""#slurp with garbage chars then \n, leading content Should NOT eat the garbage""" self.verify(" 1234 %s garbage \n"%self._EOLSlurpToken, " 1234 %s garbage \n"%self._EOLSlurpToken) if not DEFAULT_COMPILER_SETTINGS['EOLSlurpToken']: del EOLSlurpToken class RawDirective(OutputTest): def test1(self): """#raw till EOF""" self.verify("#raw\n$aFunc().\n\n", "$aFunc().\n\n") def test2(self): """#raw till #end raw""" self.verify("#raw\n$aFunc().\n#end raw\n$anInt", "$aFunc().\n1") def test3(self): """#raw till #end raw gobble WS""" self.verify(" #raw \n$aFunc().\n #end raw \n$anInt", "$aFunc().\n1") def test4(self): """#raw till #end raw using explicit directive closure Shouldn't gobble""" self.verify(" #raw #\n$aFunc().\n #end raw #\n$anInt", " \n$aFunc().\n\n1") def test5(self): """single-line short form #raw: """ self.verify("#raw: $aFunc().\n\n", "$aFunc().\n\n") self.verify("#raw: $aFunc().\n$anInt", "$aFunc().\n1") def test6(self): """ Escape characters in a #raw block """ self.verify( """#raw: This escape should be preserved: \\$unexpanded So should this one: \\#blah The string "\\012" should not disappear.""", r"""This escape should be preserved: \$unexpanded So should this one: \#blah The string "\012" should not disappear.""") class BreakpointDirective(OutputTest): def test1(self): """#breakpoint part way through source code""" self.verify("$aFunc(2).\n#breakpoint\n$anInt", "2.\n") def test2(self): """#breakpoint at BOF""" self.verify("#breakpoint\n$anInt", "") def test3(self): """#breakpoint at EOF""" self.verify("$anInt\n#breakpoint", "1\n") class StopDirective(OutputTest): def test1(self): """#stop part way through source code""" self.verify("$aFunc(2).\n#stop\n$anInt", "2.\n") def test2(self): """#stop at BOF""" self.verify("#stop\n$anInt", "") def test3(self): """#stop at EOF""" self.verify("$anInt\n#stop", "1\n") def test4(self): """#stop in pos test block""" self.verify("""$anInt #if 1 inside the if block #stop #end if blarg""", "1\ninside the if block\n") def test5(self): """#stop in neg test block""" self.verify("""$anInt #if 0 inside the if block #stop #end if blarg""", "1\nblarg") class ReturnDirective(OutputTest): def test1(self): """#return'ing an int """ self.verify("""1 $str($test-6) 3 #def test #if 1 #return (3 *2) \ + 2 #else aoeuoaeu #end if #end def """, "1\n2\n3\n") def test2(self): """#return'ing an string """ self.verify("""1 $str($test[1]) 3 #def test #if 1 #return '123' #else aoeuoaeu #end if #end def """, "1\n2\n3\n") def test3(self): """#return'ing an string AND streaming other output via the transaction""" self.verify("""1 $str($test(trans=trans)[1]) 3 #def test 1.5 #if 1 #return '123' #else aoeuoaeu #end if #end def """, "1\n1.5\n2\n3\n") class YieldDirective(OutputTest): convertEOLs = False def test1(self): """simple #yield """ src1 = """#for i in range(10)\n#yield i\n#end for""" src2 = """#for i in range(10)\n$i#slurp\n#yield\n#end for""" src3 = ("#def iterator\n" "#for i in range(10)\n#yield i\n#end for\n" "#end def\n" "#for i in $iterator\n$i#end for" ) for src in (src1, src2, src3): klass = Template.compile(src, keepRefToGeneratedCode=True) #print klass._CHEETAH_generatedModuleCode iter = klass().respond() output = [str(i) for i in iter] assert ''.join(output)=='0123456789' #print ''.join(output) # @@TR: need to expand this to cover error conditions etc. if versionTuple < (2, 3): del YieldDirective class ForDirective(OutputTest): def test1(self): """#for loop with one local var""" self.verify("#for $i in range(5)\n$i\n#end for", "0\n1\n2\n3\n4\n") self.verify("#for $i in range(5):\n$i\n#end for", "0\n1\n2\n3\n4\n") self.verify("#for $i in range(5): ##comment\n$i\n#end for", "0\n1\n2\n3\n4\n") self.verify("#for $i in range(5) ##comment\n$i\n#end for", "0\n1\n2\n3\n4\n") def test2(self): """#for loop with WS in loop""" self.verify("#for $i in range(5)\n$i \n#end for", "0 \n1 \n2 \n3 \n4 \n") def test3(self): """#for loop gobble WS""" self.verify(" #for $i in range(5) \n$i \n #end for ", "0 \n1 \n2 \n3 \n4 \n") def test4(self): """#for loop over list""" self.verify("#for $i, $j in [(0,1),(2,3)]\n$i,$j\n#end for", "0,1\n2,3\n") def test5(self): """#for loop over list, with #slurp""" self.verify("#for $i, $j in [(0,1),(2,3)]\n$i,$j#slurp\n#end for", "0,12,3") def test6(self): """#for loop with explicit closures""" self.verify("#for $i in range(5)#$i#end for#", "01234") def test7(self): """#for loop with explicit closures and WS""" self.verify(" #for $i in range(5)#$i#end for# ", " 01234 ") def test8(self): """#for loop using another $var""" self.verify(" #for $i in range($aFunc(5))#$i#end for# ", " 01234 ") def test9(self): """test methods in for loops""" self.verify("#for $func in $listOfLambdas\n$func($anInt)\n#end for", "1\n1\n1\n") def test10(self): """#for loop over list, using methods of the items""" self.verify("#for i, j in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for", "AA,BB\nCC,DD\n") self.verify("#for $i, $j in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for", "AA,BB\nCC,DD\n") def test11(self): """#for loop over list, using ($i,$j) style target list""" self.verify("#for (i, j) in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for", "AA,BB\nCC,DD\n") self.verify("#for ($i, $j) in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for", "AA,BB\nCC,DD\n") def test12(self): """#for loop over list, using i, (j,k) style target list""" self.verify("#for i, (j, k) in enumerate([('aa','bb'),('cc','dd')])\n$j.upper,$k.upper\n#end for", "AA,BB\nCC,DD\n") self.verify("#for $i, ($j, $k) in enumerate([('aa','bb'),('cc','dd')])\n$j.upper,$k.upper\n#end for", "AA,BB\nCC,DD\n") def test13(self): """single line #for""" self.verify("#for $i in range($aFunc(5)): $i", "01234") def test14(self): """single line #for with 1 extra leading space""" self.verify("#for $i in range($aFunc(5)): $i", " 0 1 2 3 4") def test15(self): """2 times single line #for""" self.verify("#for $i in range($aFunc(5)): $i#slurp\n"*2, "01234"*2) def test16(self): """false single line #for """ self.verify("#for $i in range(5): \n$i\n#end for", "0\n1\n2\n3\n4\n") if versionTuple < (2, 3): del ForDirective.test12 class RepeatDirective(OutputTest): def test1(self): """basic #repeat""" self.verify("#repeat 3\n1\n#end repeat", "1\n1\n1\n") self.verify("#repeat 3: \n1\n#end repeat", "1\n1\n1\n") self.verify("#repeat 3 ##comment\n1\n#end repeat", "1\n1\n1\n") self.verify("#repeat 3: ##comment\n1\n#end repeat", "1\n1\n1\n") def test2(self): """#repeat with numeric expression""" self.verify("#repeat 3*3/3\n1\n#end repeat", "1\n1\n1\n") def test3(self): """#repeat with placeholder""" self.verify("#repeat $numTwo\n1\n#end repeat", "1\n1\n") def test4(self): """#repeat with placeholder * num""" self.verify("#repeat $numTwo*1\n1\n#end repeat", "1\n1\n") def test5(self): """#repeat with placeholder and WS""" self.verify(" #repeat $numTwo \n1\n #end repeat ", "1\n1\n") def test6(self): """single-line #repeat""" self.verify("#repeat $numTwo: 1", "11") self.verify("#repeat $numTwo: 1\n"*2, "1\n1\n"*2) #false single-line self.verify("#repeat 3: \n1\n#end repeat", "1\n1\n1\n") class AttrDirective(OutputTest): def test1(self): """#attr with int""" self.verify("#attr $test = 1234\n$test", "1234") def test2(self): """#attr with string""" self.verify("#attr $test = 'blarg'\n$test", "blarg") def test3(self): """#attr with expression""" self.verify("#attr $test = 'blarg'.upper()*2\n$test", "BLARGBLARG") def test4(self): """#attr with string + WS Should gobble""" self.verify(" #attr $test = 'blarg' \n$test", "blarg") def test5(self): """#attr with string + WS + leading text Shouldn't gobble""" self.verify(" -- #attr $test = 'blarg' \n$test", " -- \nblarg") class DefDirective(OutputTest): def test1(self): """#def without argstring""" self.verify("#def testMeth\n1234\n#end def\n$testMeth", "1234\n") self.verify("#def testMeth ## comment\n1234\n#end def\n$testMeth", "1234\n") self.verify("#def testMeth: ## comment\n1234\n#end def\n$testMeth", "1234\n") def test2(self): """#def without argstring, gobble WS""" self.verify(" #def testMeth \n1234\n #end def \n$testMeth", "1234\n") def test3(self): """#def with argstring, gobble WS""" self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth", "1234-999\n") def test4(self): """#def with argstring, gobble WS, string used in call""" self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth('ABC')", "1234-ABC\n") def test5(self): """#def with argstring, gobble WS, list used in call""" self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth([1,2,3])", "1234-[1, 2, 3]\n") def test6(self): """#def with 2 args, gobble WS, list used in call""" self.verify(" #def testMeth($a, $b='default') \n1234-$a$b\n #end def\n$testMeth([1,2,3])", "1234-[1, 2, 3]default\n") def test7(self): """#def with *args, gobble WS""" self.verify(" #def testMeth($*args) \n1234-$args\n #end def\n$testMeth", "1234-()\n") def test8(self): """#def with **KWs, gobble WS""" self.verify(" #def testMeth($**KWs) \n1234-$KWs\n #end def\n$testMeth", "1234-{}\n") def test9(self): """#def with *args + **KWs, gobble WS""" self.verify(" #def testMeth($*args, $**KWs) \n1234-$args-$KWs\n #end def\n$testMeth", "1234-()-{}\n") def test10(self): """#def with *args + **KWs, gobble WS""" self.verify( " #def testMeth($*args, $**KWs) \n1234-$args-$KWs.a\n #end def\n$testMeth(1,2, a=1)", "1234-(1, 2)-1\n") def test11(self): """single line #def with extra WS""" self.verify( "#def testMeth: aoeuaoeu\n- $testMeth -", "- aoeuaoeu -") def test12(self): """single line #def with extra WS and nested $placeholders""" self.verify( "#def testMeth: $anInt $aFunc(1234)\n- $testMeth -", "- 1 1234 -") def test13(self): """single line #def escaped $placeholders""" self.verify( "#def testMeth: \$aFunc(\$anInt)\n- $testMeth -", "- $aFunc($anInt) -") def test14(self): """single line #def 1 escaped $placeholders""" self.verify( "#def testMeth: \$aFunc($anInt)\n- $testMeth -", "- $aFunc(1) -") def test15(self): """single line #def 1 escaped $placeholders + more WS""" self.verify( "#def testMeth : \$aFunc($anInt)\n- $testMeth -", "- $aFunc(1) -") def test16(self): """multiline #def with $ on methodName""" self.verify("#def $testMeth\n1234\n#end def\n$testMeth", "1234\n") def test17(self): """single line #def with $ on methodName""" self.verify("#def $testMeth:1234\n$testMeth", "1234") def test18(self): """single line #def with an argument""" self.verify("#def $testMeth($arg=1234):$arg\n$testMeth", "1234") def test19(self): """#def that extends over two lines with arguments""" self.verify("#def $testMeth($arg=1234,\n" +" $arg2=5678)\n" +"$arg $arg2\n" +"#end def\n" +"$testMeth", "1234 5678\n") class DecoratorDirective(OutputTest): def test1(self): """single line #def with decorator""" self.verify("#@ blah", "#@ blah") self.verify("#@23 blah", "#@23 blah") self.verify("#@@TR: comment", "#@@TR: comment") self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n" +"#@testdecorator" +"\n#def $testMeth():1234\n$testMeth", "1234") self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n" +"#@testdecorator" +"\n#block $testMeth():1234", "1234") try: self.verify( "#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n" +"#@testdecorator\n sdf" +"\n#def $testMeth():1234\n$testMeth", "1234") except ParseError: pass else: self.fail('should raise a ParseError') def test2(self): """#def with multiple decorators""" self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n" +"#@testdecorator\n" +"#@testdecorator\n" +"#def testMeth\n" +"1234\n" "#end def\n" "$testMeth", "1234\n") if versionTuple < (2, 4): del DecoratorDirective class BlockDirective(OutputTest): def test1(self): """#block without argstring""" self.verify("#block testBlock\n1234\n#end block", "1234\n") self.verify("#block testBlock ##comment\n1234\n#end block", "1234\n") def test2(self): """#block without argstring, gobble WS""" self.verify(" #block testBlock \n1234\n #end block ", "1234\n") def test3(self): """#block with argstring, gobble WS Because blocks can be reused in multiple parts of the template arguments (!!with defaults!!) can be given.""" self.verify(" #block testBlock($a=999) \n1234-$a\n #end block ", "1234-999\n") def test4(self): """#block with 2 args, gobble WS""" self.verify(" #block testBlock($a=999, $b=444) \n1234-$a$b\n #end block ", "1234-999444\n") def test5(self): """#block with 2 nested blocks Blocks can be nested to any depth and the name of the block is optional for the #end block part: #end block OR #end block [name] """ self.verify("""#block testBlock this is a test block #block outerNest outer #block innerNest inner #end block innerNest #end block outerNest --- #end block testBlock """, "this is a test block\nouter\ninner\n---\n") def test6(self): """single line #block """ self.verify( "#block testMeth: This is my block", "This is my block") def test7(self): """single line #block with WS""" self.verify( "#block testMeth: This is my block", "This is my block") def test8(self): """single line #block 1 escaped $placeholders""" self.verify( "#block testMeth: \$aFunc($anInt)", "$aFunc(1)") def test9(self): """single line #block 1 escaped $placeholders + WS""" self.verify( "#block testMeth: \$aFunc( $anInt )", "$aFunc( 1 )") def test10(self): """single line #block 1 escaped $placeholders + more WS""" self.verify( "#block testMeth : \$aFunc( $anInt )", "$aFunc( 1 )") def test11(self): """multiline #block $ on argstring""" self.verify("#block $testBlock\n1234\n#end block", "1234\n") def test12(self): """single line #block with $ on methodName """ self.verify( "#block $testMeth: This is my block", "This is my block") def test13(self): """single line #block with an arg """ self.verify( "#block $testMeth($arg='This is my block'): $arg", "This is my block") def test14(self): """single line #block with None for content""" self.verify( """#block $testMeth: $None\ntest $testMeth-""", "test -") def test15(self): """single line #block with nothing for content""" self.verify( """#block $testMeth: \nfoo\n#end block\ntest $testMeth-""", "foo\ntest foo\n-") class IncludeDirective(OutputTest): def setUp(self): fp = open('parseTest.txt', 'w') fp.write("$numOne $numTwo") fp.flush() fp.close def tearDown(self): if os.path.exists('parseTest.txt'): os.remove('parseTest.txt') def test1(self): """#include raw of source $emptyString""" self.verify("#include raw source=$emptyString", "") def test2(self): """#include raw of source $blockToBeParsed""" self.verify("#include raw source=$blockToBeParsed", "$numOne $numTwo") def test3(self): """#include raw of 'parseTest.txt'""" self.verify("#include raw 'parseTest.txt'", "$numOne $numTwo") def test4(self): """#include raw of $includeFileName""" self.verify("#include raw $includeFileName", "$numOne $numTwo") def test5(self): """#include raw of $includeFileName, with WS""" self.verify(" #include raw $includeFileName ", "$numOne $numTwo") def test6(self): """#include raw of source= , with WS""" self.verify(" #include raw source='This is my $Source '*2 ", "This is my $Source This is my $Source ") def test7(self): """#include of $blockToBeParsed""" self.verify("#include source=$blockToBeParsed", "1 2") def test8(self): """#include of $blockToBeParsed, with WS""" self.verify(" #include source=$blockToBeParsed ", "1 2") def test9(self): """#include of 'parseTest.txt', with WS""" self.verify(" #include source=$blockToBeParsed ", "1 2") def test10(self): """#include of "parseTest.txt", with WS""" self.verify(" #include source=$blockToBeParsed ", "1 2") def test11(self): """#include of 'parseTest.txt', with WS and surrounding text""" self.verify("aoeu\n #include source=$blockToBeParsed \naoeu", "aoeu\n1 2aoeu") def test12(self): """#include of 'parseTest.txt', with WS and explicit closure""" self.verify(" #include source=$blockToBeParsed# ", " 1 2 ") class SilentDirective(OutputTest): def test1(self): """simple #silent""" self.verify("#silent $aFunc", "") def test2(self): """simple #silent""" self.verify("#silent $anObj.callIt\n$anObj.callArg", "1234") self.verify("#silent $anObj.callIt ##comment\n$anObj.callArg", "1234") def test3(self): """simple #silent""" self.verify("#silent $anObj.callIt(99)\n$anObj.callArg", "99") class SetDirective(OutputTest): def test1(self): """simple #set""" self.verify("#set $testVar = 'blarg'\n$testVar", "blarg") self.verify("#set testVar = 'blarg'\n$testVar", "blarg") self.verify("#set testVar = 'blarg'##comment\n$testVar", "blarg") def test2(self): """simple #set with no WS between operands""" self.verify("#set $testVar='blarg'", "") def test3(self): """#set + use of var""" self.verify("#set $testVar = 'blarg'\n$testVar", "blarg") def test4(self): """#set + use in an #include""" self.verify("#set global $aSetVar = 1234\n#include source=$includeBlock2", "1 2 1234") def test5(self): """#set with a dictionary""" self.verify( """#set $testDict = {'one':'one1','two':'two2','three':'three3'} $testDict.one $testDict.two""", "one1\ntwo2") def test6(self): """#set with string, then used in #if block""" self.verify("""#set $test='a string'\n#if $test#blarg#end if""", "blarg") def test7(self): """simple #set, gobble WS""" self.verify(" #set $testVar = 'blarg' ", "") def test8(self): """simple #set, don't gobble WS""" self.verify(" #set $testVar = 'blarg'#---", " ---") def test9(self): """simple #set with a list""" self.verify(" #set $testVar = [1, 2, 3] \n$testVar", "[1, 2, 3]") def test10(self): """simple #set global with a list""" self.verify(" #set global $testVar = [1, 2, 3] \n$testVar", "[1, 2, 3]") def test11(self): """simple #set global with a list and *cache Caching only works with global #set vars. Local vars are not accesible to the cache namespace. """ self.verify(" #set global $testVar = [1, 2, 3] \n$*testVar", "[1, 2, 3]") def test12(self): """simple #set global with a list and **cache""" self.verify(" #set global $testVar = [1, 2, 3] \n$*5*testVar", "[1, 2, 3]") def test13(self): """simple #set with a list and **cache""" self.verify(" #set global $testVar = [1, 2, 3] \n$*.5*testVar", "[1, 2, 3]") def test14(self): """simple #set without NameMapper on""" self.verify("""#compiler useNameMapper = 0\n#set $testVar = 1 \n$testVar""", "1") def test15(self): """simple #set without $""" self.verify("""#set testVar = 1 \n$testVar""", "1") def test16(self): """simple #set global without $""" self.verify("""#set global testVar = 1 \n$testVar""", "1") def test17(self): """simple #set module without $""" self.verify("""#set module __foo__ = 'bar'\n$__foo__""", "bar") def test18(self): """#set with i,j=list style assignment""" self.verify("""#set i,j = [1,2]\n$i$j""", "12") self.verify("""#set $i,$j = [1,2]\n$i$j""", "12") def test19(self): """#set with (i,j)=list style assignment""" self.verify("""#set (i,j) = [1,2]\n$i$j""", "12") self.verify("""#set ($i,$j) = [1,2]\n$i$j""", "12") def test20(self): """#set with i, (j,k)=list style assignment""" self.verify("""#set i, (j,k) = [1,(2,3)]\n$i$j$k""", "123") self.verify("""#set $i, ($j,$k) = [1,(2,3)]\n$i$j$k""", "123") class IfDirective(OutputTest): def test1(self): """simple #if block""" self.verify("#if 1\n$aStr\n#end if\n", "blarg\n") self.verify("#if 1:\n$aStr\n#end if\n", "blarg\n") self.verify("#if 1: \n$aStr\n#end if\n", "blarg\n") self.verify("#if 1: ##comment \n$aStr\n#end if\n", "blarg\n") self.verify("#if 1 ##comment \n$aStr\n#end if\n", "blarg\n") self.verify("#if 1##for i in range(10)#$i#end for##end if", '0123456789') self.verify("#if 1: #for i in range(10)#$i#end for", '0123456789') self.verify("#if 1: #for i in range(10):$i", '0123456789') def test2(self): """simple #if block, with WS""" self.verify(" #if 1\n$aStr\n #end if \n", "blarg\n") def test3(self): """simple #if block, with WS and explicit closures""" self.verify(" #if 1#\n$aStr\n #end if #--\n", " \nblarg\n --\n") def test4(self): """#if block using $numOne""" self.verify("#if $numOne\n$aStr\n#end if\n", "blarg\n") def test5(self): """#if block using $zero""" self.verify("#if $zero\n$aStr\n#end if\n", "") def test6(self): """#if block using $emptyString""" self.verify("#if $emptyString\n$aStr\n#end if\n", "") def test7(self): """#if ... #else ... block using a $emptyString""" self.verify("#if $emptyString\n$anInt\n#else\n$anInt - $anInt\n#end if", "1 - 1\n") def test8(self): """#if ... #elif ... #else ... block using a $emptyString""" self.verify("#if $emptyString\n$c\n#elif $numOne\n$numOne\n#else\n$c - $c\n#end if", "1\n") def test9(self): """#if 'not' test, with #slurp""" self.verify("#if not $emptyString\n$aStr#slurp\n#end if\n", "blarg") def test10(self): """#if block using $*emptyString This should barf """ try: self.verify("#if $*emptyString\n$aStr\n#end if\n", "") except ParseError: pass else: self.fail('This should barf') def test11(self): """#if block using invalid top-level $(placeholder) syntax - should barf""" for badSyntax in ("#if $*5*emptyString\n$aStr\n#end if\n", "#if ${emptyString}\n$aStr\n#end if\n", "#if $(emptyString)\n$aStr\n#end if\n", "#if $[emptyString]\n$aStr\n#end if\n", "#if $!emptyString\n$aStr\n#end if\n", ): try: self.verify(badSyntax, "") except ParseError: pass else: self.fail('This should barf') def test12(self): """#if ... #else if ... #else ... block using a $emptyString Same as test 8 but using else if instead of elif""" self.verify("#if $emptyString\n$c\n#else if $numOne\n$numOne\n#else\n$c - $c\n#end if", "1\n") def test13(self): """#if# ... #else # ... block using a $emptyString with """ self.verify("#if $emptyString# $anInt#else#$anInt - $anInt#end if", "1 - 1") def test14(self): """single-line #if: simple""" self.verify("#if $emptyString then 'true' else 'false'", "false") def test15(self): """single-line #if: more complex""" self.verify("#if $anInt then 'true' else 'false'", "true") def test16(self): """single-line #if: with the words 'else' and 'then' in the output """ self.verify("#if ($anInt and not $emptyString==''' else ''') then $str('then') else 'else'", "then") def test17(self): """single-line #if: """ self.verify("#if 1: foo\n#if 0: bar\n#if 1: foo", "foo\nfoo") self.verify("#if 1: foo\n#if 0: bar\n#if 1: foo", "foo\nfoo") def test18(self): """single-line #if: \n#else: """ self.verify("#if 1: foo\n#elif 0: bar", "foo\n") self.verify("#if 1: foo\n#elif 0: bar\n#else: blarg\n", "foo\n") self.verify("#if 0: foo\n#elif 0: bar\n#else: blarg\n", "blarg\n") class UnlessDirective(OutputTest): def test1(self): """#unless 1""" self.verify("#unless 1\n 1234 \n#end unless", "") self.verify("#unless 1:\n 1234 \n#end unless", "") self.verify("#unless 1: ##comment\n 1234 \n#end unless", "") self.verify("#unless 1 ##comment\n 1234 \n#end unless", "") def test2(self): """#unless 0""" self.verify("#unless 0\n 1234 \n#end unless", " 1234 \n") def test3(self): """#unless $none""" self.verify("#unless $none\n 1234 \n#end unless", " 1234 \n") def test4(self): """#unless $numTwo""" self.verify("#unless $numTwo\n 1234 \n#end unless", "") def test5(self): """#unless $numTwo with WS""" self.verify(" #unless $numTwo \n 1234 \n #end unless ", "") def test6(self): """single-line #unless""" self.verify("#unless 1: 1234", "") self.verify("#unless 0: 1234", "1234") self.verify("#unless 0: 1234\n"*2, "1234\n"*2) class PSP(OutputTest): def searchList(self): return None def test1(self): """simple <%= [int] %>""" self.verify("<%= 1234 %>", "1234") def test2(self): """simple <%= [string] %>""" self.verify("<%= 'blarg' %>", "blarg") def test3(self): """simple <%= None %>""" self.verify("<%= None %>", "") def test4(self): """simple <%= [string] %> + $anInt""" self.verify("<%= 'blarg' %>$anInt", "blarg1") def test5(self): """simple <%= [EXPR] %> + $anInt""" self.verify("<%= ('blarg'*2).upper() %>$anInt", "BLARGBLARG1") def test6(self): """for loop in <%%>""" self.verify("<% for i in range(5):%>1<%end%>", "11111") def test7(self): """for loop in <%%> and using <%=i%>""" self.verify("<% for i in range(5):%><%=i%><%end%>", "01234") def test8(self): """for loop in <% $%> and using <%=i%>""" self.verify("""<% for i in range(5): i=i*2$%><%=i%><%end%>""", "02468") def test9(self): """for loop in <% $%> and using <%=i%> plus extra text""" self.verify("""<% for i in range(5): i=i*2$%><%=i%>-<%end%>""", "0-2-4-6-8-") def test10(self): """ Using getVar and write within a PSP """ self._searchList = [{'me' : 1}] template = '''This is my template <% me = self.getVar('me') if isinstance(me, int): write('Bork') else: write('Nork') %>''' self.verify(template, 'This is my template\nBork') class WhileDirective(OutputTest): def test1(self): """simple #while with a counter""" self.verify("#set $i = 0\n#while $i < 5\n$i#slurp\n#set $i += 1\n#end while", "01234") class ContinueDirective(OutputTest): def test1(self): """#continue with a #while""" self.verify("""#set $i = 0 #while $i < 5 #if $i == 3 #set $i += 1 #continue #end if $i#slurp #set $i += 1 #end while""", "0124") def test2(self): """#continue with a #for""" self.verify("""#for $i in range(5) #if $i == 3 #continue #end if $i#slurp #end for""", "0124") class BreakDirective(OutputTest): def test1(self): """#break with a #while""" self.verify("""#set $i = 0 #while $i < 5 #if $i == 3 #break #end if $i#slurp #set $i += 1 #end while""", "012") def test2(self): """#break with a #for""" self.verify("""#for $i in range(5) #if $i == 3 #break #end if $i#slurp #end for""", "012") class TryDirective(OutputTest): def test1(self): """simple #try """ self.verify("#try\n1234\n#except\nblarg\n#end try", "1234\n") def test2(self): """#try / #except with #raise """ self.verify("#try\n#raise ValueError\n#except\nblarg\n#end try", "blarg\n") def test3(self): """#try / #except with #raise + WS Should gobble """ self.verify(" #try \n #raise ValueError \n #except \nblarg\n #end try", "blarg\n") def test4(self): """#try / #except with #raise + WS and leading text Shouldn't gobble """ self.verify("--#try \n #raise ValueError \n #except \nblarg\n #end try#--", "--\nblarg\n --") def test5(self): """nested #try / #except with #raise """ self.verify( """#try #raise ValueError #except #try #raise ValueError #except blarg #end try #end try""", "blarg\n") class PassDirective(OutputTest): def test1(self): """#pass in a #try / #except block """ self.verify("#try\n#raise ValueError\n#except\n#pass\n#end try", "") def test2(self): """#pass in a #try / #except block + WS """ self.verify(" #try \n #raise ValueError \n #except \n #pass \n #end try", "") class AssertDirective(OutputTest): def test1(self): """simple #assert """ self.verify("#set $x = 1234\n#assert $x == 1234", "") def test2(self): """simple #assert that fails """ def test(self=self): self.verify("#set $x = 1234\n#assert $x == 999", ""), self.failUnlessRaises(AssertionError, test) def test3(self): """simple #assert with WS """ self.verify("#set $x = 1234\n #assert $x == 1234 ", "") class RaiseDirective(OutputTest): def test1(self): """simple #raise ValueError Should raise ValueError """ def test(self=self): self.verify("#raise ValueError", ""), self.failUnlessRaises(ValueError, test) def test2(self): """#raise ValueError in #if block Should raise ValueError """ def test(self=self): self.verify("#if 1\n#raise ValueError\n#end if\n", "") self.failUnlessRaises(ValueError, test) def test3(self): """#raise ValueError in #if block Shouldn't raise ValueError """ self.verify("#if 0\n#raise ValueError\n#else\nblarg#end if\n", "blarg\n") class ImportDirective(OutputTest): def test1(self): """#import math """ self.verify("#import math", "") def test2(self): """#import math + WS Should gobble """ self.verify(" #import math ", "") def test3(self): """#import math + WS + leading text Shouldn't gobble """ self.verify(" -- #import math ", " -- ") def test4(self): """#from math import syn """ self.verify("#from math import cos", "") def test5(self): """#from math import cos + WS Should gobble """ self.verify(" #from math import cos ", "") def test6(self): """#from math import cos + WS + leading text Shouldn't gobble """ self.verify(" -- #from math import cos ", " -- ") def test7(self): """#from math import cos -- use it """ self.verify("#from math import cos\n$cos(0)", "1.0") def test8(self): """#from math import cos,tan,sin -- and use them """ self.verify("#from math import cos, tan, sin\n$cos(0)-$tan(0)-$sin(0)", "1.0-0.0-0.0") def test9(self): """#import os.path -- use it """ self.verify("#import os.path\n$os.path.exists('.')", repr(True)) def test10(self): """#import os.path -- use it with NameMapper turned off """ self.verify("""## #compiler-settings useNameMapper=False #end compiler-settings #import os.path $os.path.exists('.')""", repr(True)) def test11(self): """#from math import * """ self.verify("#from math import *\n$pow(1,2) $log10(10)", "1.0 1.0") class CompilerDirective(OutputTest): def test1(self): """overriding the commentStartToken """ self.verify("""$anInt##comment #compiler commentStartToken = '//' $anInt//comment """, "1\n1\n") def test2(self): """overriding and resetting the commentStartToken """ self.verify("""$anInt##comment #compiler commentStartToken = '//' $anInt//comment #compiler reset $anInt//comment """, "1\n1\n1//comment\n") class CompilerSettingsDirective(OutputTest): def test1(self): """overriding the cheetahVarStartToken """ self.verify("""$anInt #compiler-settings cheetahVarStartToken = @ #end compiler-settings @anInt #compiler-settings reset $anInt """, "1\n1\n1\n") def test2(self): """overriding the directiveStartToken """ self.verify("""#set $x = 1234 $x #compiler-settings directiveStartToken = @ #end compiler-settings @set $x = 1234 $x """, "1234\n1234\n") def test3(self): """overriding the commentStartToken """ self.verify("""$anInt##comment #compiler-settings commentStartToken = // #end compiler-settings $anInt//comment """, "1\n1\n") if sys.platform.startswith('java'): del CompilerDirective del CompilerSettingsDirective class ExtendsDirective(OutputTest): def test1(self): """#extends Cheetah.Templates._SkeletonPage""" self.verify("""#from Cheetah.Templates._SkeletonPage import _SkeletonPage #extends _SkeletonPage #implements respond $spacer() """, '\n') self.verify("""#from Cheetah.Templates._SkeletonPage import _SkeletonPage #extends _SkeletonPage #implements respond(foo=1234) $spacer()$foo """, '1234\n') def test2(self): """#extends Cheetah.Templates.SkeletonPage without #import""" self.verify("""#extends Cheetah.Templates.SkeletonPage #implements respond $spacer() """, '\n') def test3(self): """#extends Cheetah.Templates.SkeletonPage.SkeletonPage without #import""" self.verify("""#extends Cheetah.Templates.SkeletonPage.SkeletonPage #implements respond $spacer() """, '\n') def test4(self): """#extends with globals and searchList test""" self.verify("""#extends Cheetah.Templates.SkeletonPage #set global g="Hello" #implements respond $g $numOne """, 'Hello 1\n') class SuperDirective(OutputTest): def test1(self): tmpl1 = Template.compile('''$foo $bar(99) #def foo: this is base foo #def bar(arg): super-$arg''') tmpl2 = tmpl1.subclass(''' #implements dummy #def foo #super This is child foo #super(trans=trans) $bar(1234) #end def #def bar(arg): #super($arg) ''') expected = ('this is base foo ' 'This is child foo\nthis is base foo ' 'super-1234\n super-99') assert str(tmpl2()).strip()==expected class ImportantExampleCases(OutputTest): def test1(self): """how to make a comma-delimited list""" self.verify("""#set $sep = '' #for $letter in $letterList $sep$letter#slurp #set $sep = ', ' #end for """, "a, b, c") class FilterDirective(OutputTest): convertEOLs=False def _getCompilerSettings(self): return {'useFilterArgsInPlaceholders':True} def test1(self): """#filter Filter """ self.verify("#filter Filter\n$none#end filter", "") self.verify("#filter Filter: $none", "") def test2(self): """#filter ReplaceNone with WS """ self.verify("#filter Filter \n$none#end filter", "") def test3(self): """#filter MaxLen -- maxlen of 5""" self.verify("#filter MaxLen \n${tenDigits, $maxlen=5}#end filter", "12345") def test4(self): """#filter MaxLen -- no maxlen """ self.verify("#filter MaxLen \n${tenDigits}#end filter", "1234567890") def test5(self): """#filter WebSafe -- basic usage """ self.verify("#filter WebSafe \n$webSafeTest#end filter", "abc <=> &") 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} def install_eols(): klasses = [v for v in globals().values() if isinstance(v, type) and issubclass(v, unittest.TestCase)] for klass in klasses: name = klass.__name__ if hasattr(klass, 'convertEOLs') and klass.convertEOLs: win32Src = r"class %(name)s_Win32EOL(%(name)s): _EOLreplacement = '\r\n'"%locals() macSrc = r"class %(name)s_MacEOL(%(name)s): _EOLreplacement = '\r'"%locals() exec(win32Src, globals()) exec(macSrc, globals()) if versionTuple >= (2, 3): src = r"class %(name)s_DiffBaseClass(%(name)s): "%locals() src += " _extraCompileKwArgs = extraCompileKwArgsForDiffBaseclass" exec(src, globals()) del name del klass ################################################## ## if run from the command line ## if __name__ == '__main__': install_eols() unittest.main() # vim: shiftwidth=4 tabstop=4 expandtab Cheetah-2.4.4/cheetah/Tests/Parser.py0000644000175000001440000000234211413255133016450 0ustar tylerusers#!/usr/bin/env python import unittest from Cheetah import Parser class ArgListTest(unittest.TestCase): def setUp(self): super(ArgListTest, self).setUp() self.al = Parser.ArgList() def test_merge1(self): ''' Testing the ArgList case results from Template.Preprocessors.test_complexUsage ''' self.al.add_argument('arg') expect = [('arg', None)] self.assertEquals(expect, self.al.merge()) def test_merge2(self): ''' Testing the ArgList case results from SyntaxAndOutput.BlockDirective.test4 ''' self.al.add_argument('a') self.al.add_default('999') self.al.next() self.al.add_argument('b') self.al.add_default('444') expect = [(u'a', u'999'), (u'b', u'444')] self.assertEquals(expect, self.al.merge()) def test_merge3(self): ''' Testing the ArgList case results from SyntaxAndOutput.BlockDirective.test13 ''' self.al.add_argument('arg') self.al.add_default("'This is my block'") expect = [('arg', "'This is my block'")] self.assertEquals(expect, self.al.merge()) if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/Cheps.py0000644000175000001440000000206611413255133016261 0ustar tylerusers#!/usr/bin/env python import unittest import Cheetah import Cheetah.Parser import Cheetah.Template class Chep_2_Conditionalized_Import_Behavior(unittest.TestCase): def test_ModuleLevelImport(self): ''' Verify module level (traditional) import behavior ''' pass def test_InlineImport(self): ''' Verify (new) inline import behavior works ''' template = ''' #def funky($s) #try #import urllib #except ImportError #pass #end try #return urllib.quote($s) #end def ''' try: template = Cheetah.Template.Template.compile(template) except Cheetah.Parser.ParseError, ex: self.fail('Failed to properly generate code %s' % ex) template = template() rc = tepmlate.funky('abc def') assert rc == 'abc+def' def test_LegacyMode(self): ''' Verify disabling of CHEP #2 works ''' pass if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/Regressions.py0000644000175000001440000002031511413255133017517 0ustar tylerusers#!/usr/bin/env python import Cheetah.NameMapper import Cheetah.Template import sys import unittest majorVer, minorVer = sys.version_info[0], sys.version_info[1] versionTuple = (majorVer, minorVer) def isPython23(): ''' Python 2.3 is still supported by Cheetah, but doesn't support decorators ''' return majorVer == 2 and minorVer < 4 class GetAttrException(Exception): pass class CustomGetAttrClass(object): def __getattr__(self, name): raise GetAttrException('FAIL, %s' % name) class GetAttrTest(unittest.TestCase): ''' Test for an issue occurring when __getatttr__() raises an exception causing NameMapper to raise a NotFound exception ''' def test_ValidException(self): o = CustomGetAttrClass() try: print(o.attr) except GetAttrException, e: # expected return except: self.fail('Invalid exception raised: %s' % e) self.fail('Should have had an exception raised') def test_NotFoundException(self): template = ''' #def raiseme() $obj.attr #end def''' template = Cheetah.Template.Template.compile(template, compilerSettings={}, keepRefToGeneratedCode=True) template = template(searchList=[{'obj' : CustomGetAttrClass()}]) assert template, 'We should have a valid template object by now' self.failUnlessRaises(GetAttrException, template.raiseme) class InlineImportTest(unittest.TestCase): def test_FromFooImportThing(self): ''' Verify that a bug introduced in v2.1.0 where an inline: #from module import class would result in the following code being generated: import class ''' template = ''' #def myfunction() #if True #from os import path #return 17 Hello! #end if #end def ''' template = Cheetah.Template.Template.compile(template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True) template = template(searchList=[{}]) assert template, 'We should have a valid template object by now' rc = template.myfunction() assert rc == 17, (template, 'Didn\'t get a proper return value') def test_ImportFailModule(self): template = ''' #try #import invalidmodule #except #set invalidmodule = dict(FOO='BAR!') #end try $invalidmodule.FOO ''' template = Cheetah.Template.Template.compile(template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True) template = template(searchList=[{}]) assert template, 'We should have a valid template object by now' assert str(template), 'We weren\'t able to properly generate the result from the template' def test_ProperImportOfBadModule(self): template = ''' #from invalid import fail This should totally $fail ''' self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True) def test_AutoImporting(self): template = ''' #extends FakeyTemplate Boo! ''' self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template) def test_StuffBeforeImport_Legacy(self): template = ''' ### ### I like comments before import ### #extends Foo Bar ''' self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template, compilerSettings={'useLegacyImportMode' : True}, keepRefToGeneratedCode=True) class Mantis_Issue_11_Regression_Test(unittest.TestCase): ''' Test case for bug outlined in Mantis issue #11: Output: Traceback (most recent call last): File "test.py", line 12, in t.respond() File "DynamicallyCompiledCheetahTemplate.py", line 86, in respond File "/usr/lib64/python2.6/cgi.py", line 1035, in escape s = s.replace("&", "&") # Must be done first! ''' def test_FailingBehavior(self): import cgi template = Cheetah.Template.Template("$escape($request)", searchList=[{'escape' : cgi.escape, 'request' : 'foobar'}]) assert template self.failUnlessRaises(AttributeError, template.respond) def test_FailingBehaviorWithSetting(self): import cgi template = Cheetah.Template.Template("$escape($request)", searchList=[{'escape' : cgi.escape, 'request' : 'foobar'}], compilerSettings={'prioritizeSearchListOverSelf' : True}) assert template assert template.respond() class Mantis_Issue_21_Regression_Test(unittest.TestCase): ''' Test case for bug outlined in issue #21 Effectively @staticmethod and @classmethod decorated methods in templates don't properly define the _filter local, which breaks when using the NameMapper ''' def runTest(self): if isPython23(): return template = ''' #@staticmethod #def testMethod() This is my $output #end def ''' template = Cheetah.Template.Template.compile(template) assert template assert template.testMethod(output='bug') # raises a NameError: global name '_filter' is not defined class Mantis_Issue_22_Regression_Test(unittest.TestCase): ''' Test case for bug outlined in issue #22 When using @staticmethod and @classmethod in conjunction with the #filter directive the generated code for the #filter is reliant on the `self` local, breaking the function ''' def test_NoneFilter(self): # XXX: Disabling this test for now return if isPython23(): return template = ''' #@staticmethod #def testMethod() #filter None This is my $output #end filter #end def ''' template = Cheetah.Template.Template.compile(template) assert template assert template.testMethod(output='bug') def test_DefinedFilter(self): # XXX: Disabling this test for now return if isPython23(): return template = ''' #@staticmethod #def testMethod() #filter Filter This is my $output #end filter #end def ''' # The generated code for the template's testMethod() should look something # like this in the 'error' case: ''' @staticmethod def testMethod(**KWS): ## CHEETAH: generated from #def testMethod() at line 3, col 13. trans = DummyTransaction() _dummyTrans = True write = trans.response().write SL = [KWS] _filter = lambda x, **kwargs: unicode(x) ######################################## ## START - generated method body _orig_filter_18517345 = _filter filterName = u'Filter' if self._CHEETAH__filters.has_key("Filter"): _filter = self._CHEETAH__currentFilter = self._CHEETAH__filters[filterName] else: _filter = self._CHEETAH__currentFilter = \ self._CHEETAH__filters[filterName] = getattr(self._CHEETAH__filtersLib, filterName)(self).filter write(u' This is my ') _v = VFFSL(SL,"output",True) # u'$output' on line 5, col 32 if _v is not None: write(_filter(_v, rawExpr=u'$output')) # from line 5, col 32. ######################################## ## END - generated method body return _dummyTrans and trans.response().getvalue() or "" ''' template = Cheetah.Template.Template.compile(template) assert template assert template.testMethod(output='bug') if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/__init__.py0000644000175000001440000000000211413255133016742 0ustar tylerusers# Cheetah-2.4.4/cheetah/Tests/Analyzer.py0000644000175000001440000000116211413255133017000 0ustar tylerusers#!/usr/bin/env python import unittest from Cheetah import DirectiveAnalyzer class AnalyzerTests(unittest.TestCase): def test_set(self): template = ''' #set $foo = "bar" Hello ${foo}! ''' calls = DirectiveAnalyzer.analyze(template) self.assertEquals(1, calls.get('set')) def test_compilersettings(self): template = ''' #compiler-settings useNameMapper = False #end compiler-settings ''' calls = DirectiveAnalyzer.analyze(template) self.assertEquals(1, calls.get('compiler-settings')) if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/Misc.py0000644000175000001440000000100311413255133016100 0ustar tylerusers#!/usr/bin/env python import unittest from Cheetah import SettingsManager class SettingsManagerTests(unittest.TestCase): def test_mergeDictionaries(self): left = {'foo' : 'bar', 'abc' : {'a' : 1, 'b' : 2, 'c' : (3,)}} right = {'xyz' : (10, 9)} expect = {'xyz': (10, 9), 'foo': 'bar', 'abc': {'a': 1, 'c': (3,), 'b': 2}} result = SettingsManager.mergeNestedDictionaries(left, right) self.assertEquals(result, expect) if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/Performance.py0000644000175000001440000001625711413255133017467 0ustar tylerusers#!/usr/bin/env python import hotshot import hotshot.stats import os import sys import unittest from test import pystone import time import Cheetah.NameMapper import Cheetah.Template # This can be turned on with the `--debug` flag when running the test # and will cause the tests to all just dump out how long they took # insteasd of asserting on duration DEBUG = False # TOLERANCE in Pystones kPS = 1000 TOLERANCE = 0.5*kPS class DurationError(AssertionError): pass _pystone_calibration_mark = None def _pystone_calibration(): global _pystone_calibration_mark if not _pystone_calibration_mark: _pystone_calibration_mark = pystone.pystones(loops=pystone.LOOPS) return _pystone_calibration_mark def perftest(max_num_pystones, current_pystone=None): ''' Performance test decorator based off the 'timedtest' decorator found in this Active State recipe: http://code.activestate.com/recipes/440700/ ''' if not isinstance(max_num_pystones, float): max_num_pystones = float(max_num_pystones) if not current_pystone: current_pystone = _pystone_calibration() def _test(function): def wrapper(*args, **kw): start_time = time.time() try: return function(*args, **kw) finally: total_time = time.time() - start_time if total_time == 0: pystone_total_time = 0 else: pystone_rate = current_pystone[0] / current_pystone[1] pystone_total_time = total_time / pystone_rate global DEBUG if DEBUG: print('The test "%s" took: %s pystones' % (function.func_name, pystone_total_time)) else: if pystone_total_time > (max_num_pystones + TOLERANCE): raise DurationError((('Test too long (%.2f Ps, ' 'need at most %.2f Ps)') % (pystone_total_time, max_num_pystones))) return wrapper return _test class DynamicTemplatePerformanceTest(unittest.TestCase): loops = 10 #@perftest(1200) def test_BasicDynamic(self): template = ''' #def foo(arg1, arg2) #pass #end def ''' for i in range(self.loops): klass = Cheetah.Template.Template.compile(template) assert klass test_BasicDynamic = perftest(1200)(test_BasicDynamic) class PerformanceTest(unittest.TestCase): iterations = 100000 display = False save = False def runTest(self): self.prof = hotshot.Profile('%s.prof' % self.__class__.__name__) self.prof.start() for i in range(self.iterations): if hasattr(self, 'performanceSample'): self.display = True self.performanceSample() self.prof.stop() self.prof.close() if self.display: print('>>> %s (%d iterations) ' % (self.__class__.__name__, self.iterations)) stats = hotshot.stats.load('%s.prof' % self.__class__.__name__) #stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_stats(50) if not self.save: os.unlink('%s.prof' % self.__class__.__name__) class DynamicMethodCompilationTest(PerformanceTest): def performanceSample(self): template = ''' #import sys #import os #def testMethod() #set foo = [1, 2, 3, 4] #return $foo[0] #end def ''' template = Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False) template = template() value = template.testMethod() class BunchOfWriteCalls(PerformanceTest): iterations = 1000 def performanceSample(self): template = ''' #import sys #import os #for i in range(1000) $i #end for ''' template = Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False) template = template() value = template.respond() del value class DynamicSimpleCompilationTest(PerformanceTest): def performanceSample(self): template = ''' #import sys #import os #set foo = [1,2,3,4] Well hello there! This is basic. Here's an array too: $foo ''' template = Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False) template = template() template = unicode(template) class FilterTest(PerformanceTest): template = None def setUp(self): super(FilterTest, self).setUp() template = ''' #import sys #import os #set foo = [1, 2, 3, 4] $foo, $foo, $foo ''' template = Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False) self.template = template() def performanceSample(self): value = unicode(self.template) class LongCompileTest(PerformanceTest): ''' Test the compilation on a sufficiently large template ''' def compile(self, template): return Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False) def performanceSample(self): template = ''' #import sys #import Cheetah.Template #extends Cheetah.Template.Template #def header()

This is my header

#end def #def footer() #return "Huzzah" #end def #def scripts() #pass #end def #def respond() ${title} $scripts() $header() #for $i in $range(10) This is just some stupid page!
#end for
$footer() #end def ''' return self.compile(template) class LongCompile_CompilerSettingsTest(LongCompileTest): def compile(self, template): return Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False, compilerSettings={'useStackFrames' : True, 'useAutocalling' : True}) class LongCompileAndRun(LongCompileTest): def performanceSample(self): template = super(LongCompileAndRun, self).performanceSample() template = template(searchList=[{'title' : 'foo'}]) template = template.respond() if __name__ == '__main__': if '--debug' in sys.argv: DEBUG = True sys.argv = [arg for arg in sys.argv if not arg == '--debug'] unittest.main() Cheetah-2.4.4/cheetah/Tests/Test.py0000755000175000001440000000277711413255133016152 0ustar tylerusers#!/usr/bin/env python ''' Core module of Cheetah's Unit-testing framework TODO ================================================================================ # combo tests # negative test cases for expected exceptions # black-box vs clear-box testing # do some tests that run the Template for long enough to check that the refresh code works ''' import sys import unittest from Cheetah.Tests import SyntaxAndOutput from Cheetah.Tests import NameMapper from Cheetah.Tests import Misc from Cheetah.Tests import Filters from Cheetah.Tests import Template from Cheetah.Tests import Cheps from Cheetah.Tests import Parser from Cheetah.Tests import Regressions from Cheetah.Tests import Unicode from Cheetah.Tests import CheetahWrapper from Cheetah.Tests import Analyzer SyntaxAndOutput.install_eols() suites = [ unittest.findTestCases(SyntaxAndOutput), unittest.findTestCases(NameMapper), unittest.findTestCases(Filters), unittest.findTestCases(Template), #unittest.findTestCases(Cheps), unittest.findTestCases(Regressions), unittest.findTestCases(Unicode), unittest.findTestCases(Misc), unittest.findTestCases(Parser), unittest.findTestCases(Analyzer), ] if not sys.platform.startswith('java'): suites.append(unittest.findTestCases(CheetahWrapper)) if __name__ == '__main__': runner = unittest.TextTestRunner() if 'xml' in sys.argv: import xmlrunner runner = xmlrunner.XMLTestRunner(filename='Cheetah-Tests.xml') results = runner.run(unittest.TestSuite(suites)) Cheetah-2.4.4/cheetah/Tests/xmlrunner.py0000644000175000001440000003066111413255133017253 0ustar tylerusers""" XML Test Runner for PyUnit """ # Written by Sebastian Rittau and placed in # the Public Domain. With contributions by Paolo Borelli. __revision__ = "$Id: /private/python/stdlib/xmlrunner.py 16654 2007-11-12T12:46:35.368945Z srittau $" import os.path import re import sys import time import traceback import unittest from StringIO import StringIO from xml.sax.saxutils import escape from StringIO import StringIO class _TestInfo(object): """Information about a particular test. Used by _XMLTestResult. """ def __init__(self, test, time): _pieces = test.id().split('.') (self._class, self._method) = ('.'.join(_pieces[:-1]), _pieces[-1]) self._time = time self._error = None self._failure = None def print_report(self, stream): """Print information about this test case in XML format to the supplied stream. """ stream.write(' ' % \ { "class": self._class, "method": self._method, "time": self._time, }) if self._failure != None: self._print_error(stream, 'failure', self._failure) if self._error != None: self._print_error(stream, 'error', self._error) stream.write('\n') def _print_error(self, stream, tagname, error): """Print information from a failure or error to the supplied stream.""" text = escape(str(error[1])) stream.write('\n') stream.write(' <%s type="%s">%s\n' \ % (tagname, issubclass(error[0], Exception) and error[0].__name__ or str(error[0]), text)) tb_stream = StringIO() traceback.print_tb(error[2], None, tb_stream) stream.write(escape(tb_stream.getvalue())) stream.write(' \n' % tagname) stream.write(' ') # Module level functions since Python 2.3 doesn't grok decorators def create_success(test, time): """Create a _TestInfo instance for a successful test.""" return _TestInfo(test, time) def create_failure(test, time, failure): """Create a _TestInfo instance for a failed test.""" info = _TestInfo(test, time) info._failure = failure return info def create_error(test, time, error): """Create a _TestInfo instance for an erroneous test.""" info = _TestInfo(test, time) info._error = error return info class _XMLTestResult(unittest.TestResult): """A test result class that stores result as XML. Used by XMLTestRunner. """ def __init__(self, classname): unittest.TestResult.__init__(self) self._test_name = classname self._start_time = None self._tests = [] self._error = None self._failure = None def startTest(self, test): unittest.TestResult.startTest(self, test) self._error = None self._failure = None self._start_time = time.time() def stopTest(self, test): time_taken = time.time() - self._start_time unittest.TestResult.stopTest(self, test) if self._error: info = create_error(test, time_taken, self._error) elif self._failure: info = create_failure(test, time_taken, self._failure) else: info = create_success(test, time_taken) self._tests.append(info) def addError(self, test, err): unittest.TestResult.addError(self, test, err) self._error = err def addFailure(self, test, err): unittest.TestResult.addFailure(self, test, err) self._failure = err def print_report(self, stream, time_taken, out, err): """Prints the XML report to the supplied stream. The time the tests took to perform as well as the captured standard output and standard error streams must be passed in.a """ stream.write('\n' % \ { "n": self._test_name, "t": self.testsRun, "time": time_taken, }) for info in self._tests: info.print_report(stream) stream.write(' \n' % out) stream.write(' \n' % err) stream.write('\n') class XMLTestRunner(object): """A test runner that stores results in XML format compatible with JUnit. XMLTestRunner(stream=None) -> XML test runner The XML file is written to the supplied stream. If stream is None, the results are stored in a file called TEST-..xml in the current working directory (if not overridden with the path property), where and are the module and class name of the test class. """ def __init__(self, *args, **kwargs): self._stream = kwargs.get('stream') self._filename = kwargs.get('filename') self._path = "." def run(self, test): """Run the given test case or test suite.""" class_ = test.__class__ classname = class_.__module__ + "." + class_.__name__ if self._stream == None: filename = "TEST-%s.xml" % classname if self._filename: filename = self._filename stream = file(os.path.join(self._path, filename), "w") stream.write('\n') else: stream = self._stream result = _XMLTestResult(classname) start_time = time.time() # TODO: Python 2.5: Use the with statement old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = StringIO() sys.stderr = StringIO() try: test(result) try: out_s = sys.stdout.getvalue() except AttributeError: out_s = "" try: err_s = sys.stderr.getvalue() except AttributeError: err_s = "" finally: sys.stdout = old_stdout sys.stderr = old_stderr time_taken = time.time() - start_time result.print_report(stream, time_taken, out_s, err_s) if self._stream == None: stream.close() return result def _set_path(self, path): self._path = path path = property(lambda self: self._path, _set_path, None, """The path where the XML files are stored. This property is ignored when the XML file is written to a file stream.""") class XMLTestRunnerTest(unittest.TestCase): def setUp(self): self._stream = StringIO() def _try_test_run(self, test_class, expected): """Run the test suite against the supplied test class and compare the XML result against the expected XML string. Fail if the expected string doesn't match the actual string. All time attribute in the expected string should have the value "0.000". All error and failure messages are reduced to "Foobar". """ runner = XMLTestRunner(self._stream) runner.run(unittest.makeSuite(test_class)) got = self._stream.getvalue() # Replace all time="X.YYY" attributes by time="0.000" to enable a # simple string comparison. got = re.sub(r'time="\d+\.\d+"', 'time="0.000"', got) # Likewise, replace all failure and error messages by a simple "Foobar" # string. got = re.sub(r'(?s).*?', r'Foobar', got) got = re.sub(r'(?s).*?', r'Foobar', got) self.assertEqual(expected, got) def test_no_tests(self): """Regression test: Check whether a test run without any tests matches a previous run. """ class TestTest(unittest.TestCase): pass self._try_test_run(TestTest, """ """) def test_success(self): """Regression test: Check whether a test run with a successful test matches a previous run. """ class TestTest(unittest.TestCase): def test_foo(self): pass self._try_test_run(TestTest, """ """) def test_failure(self): """Regression test: Check whether a test run with a failing test matches a previous run. """ class TestTest(unittest.TestCase): def test_foo(self): self.assert_(False) self._try_test_run(TestTest, """ Foobar """) def test_error(self): """Regression test: Check whether a test run with a erroneous test matches a previous run. """ class TestTest(unittest.TestCase): def test_foo(self): raise IndexError() self._try_test_run(TestTest, """ Foobar """) def test_stdout_capture(self): """Regression test: Check whether a test run with output to stdout matches a previous run. """ class TestTest(unittest.TestCase): def test_foo(self): print("Test") self._try_test_run(TestTest, """ """) def test_stderr_capture(self): """Regression test: Check whether a test run with output to stderr matches a previous run. """ class TestTest(unittest.TestCase): def test_foo(self): sys.stderr.write('Test\n') self._try_test_run(TestTest, """ """) class NullStream(object): """A file-like object that discards everything written to it.""" def write(self, buffer): pass def test_unittests_changing_stdout(self): """Check whether the XMLTestRunner recovers gracefully from unit tests that change stdout, but don't change it back properly. """ class TestTest(unittest.TestCase): def test_foo(self): sys.stdout = XMLTestRunnerTest.NullStream() runner = XMLTestRunner(self._stream) runner.run(unittest.makeSuite(TestTest)) def test_unittests_changing_stderr(self): """Check whether the XMLTestRunner recovers gracefully from unit tests that change stderr, but don't change it back properly. """ class TestTest(unittest.TestCase): def test_foo(self): sys.stderr = XMLTestRunnerTest.NullStream() runner = XMLTestRunner(self._stream) runner.run(unittest.makeSuite(TestTest)) class XMLTestProgram(unittest.TestProgram): def runTests(self): if self.testRunner is None: self.testRunner = XMLTestRunner() unittest.TestProgram.runTests(self) main = XMLTestProgram if __name__ == "__main__": main(module=None) Cheetah-2.4.4/cheetah/Tests/Filters.py0000644000175000001440000000373111413255133016627 0ustar tylerusers#!/usr/bin/env python import sys import unittest import Cheetah.Template import Cheetah.Filters majorVer, minorVer = sys.version_info[0], sys.version_info[1] versionTuple = (majorVer, minorVer) class BasicMarkdownFilterTest(unittest.TestCase): ''' Test that our markdown filter works ''' def test_BasicHeader(self): template = ''' #from Cheetah.Filters import Markdown #transform Markdown $foo Header ====== ''' expected = '''

bar

Header

''' try: template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}]) template = str(template) assert template == expected except ImportError, ex: print('>>> We probably failed to import markdown, bummer %s' % ex) return except Exception, ex: if ex.__class__.__name__ == 'MarkdownException' and majorVer == 2 and minorVer < 5: print('>>> NOTE: Support for the Markdown filter will be broken for you. Markdown says: %s' % ex) return raise class BasicCodeHighlighterFilterTest(unittest.TestCase): ''' Test that our code highlighter filter works ''' def test_Python(self): template = ''' #from Cheetah.Filters import CodeHighlighter #transform CodeHighlighter def foo(self): return '$foo' ''' template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}]) template = str(template) assert template, (template, 'We should have some content here...') def test_Html(self): template = ''' #from Cheetah.Filters import CodeHighlighter #transform CodeHighlighter $foo ''' template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}]) template = str(template) assert template, (template, 'We should have some content here...') if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/NameMapper.py0000644000175000001440000003521511444460060017247 0ustar tylerusers#!/usr/bin/env python import sys import types import os import os.path import unittest from Cheetah.NameMapper import NotFound, valueForKey, \ valueForName, valueFromSearchList, valueFromFrame, valueFromFrameOrSearchList class DummyClass(object): classVar1 = 123 def __init__(self): self.instanceVar1 = 123 def __str__(self): return 'object' def meth(self, arg="arff"): return str(arg) def meth1(self, arg="doo"): return arg def meth2(self, arg1="a1", arg2="a2"): raise ValueError def meth3(self): """Tests a bug that Jeff Johnson reported on Oct 1, 2001""" x = 'A string' try: for i in [1, 2, 3, 4]: if x == 2: pass if x == 'xx': pass return x except: raise class DummyClassGetAttrRaises(object): def __getattr__(self, name): raise ValueError def dummyFunc(arg="Scooby"): return arg def funcThatRaises(): raise ValueError testNamespace = { 'aStr': 'blarg', 'anInt': 1, 'aFloat': 1.5, 'aDict': {'one': 'item1', 'two': 'item2', 'nestedDict': {'one': 'nestedItem1', 'two': 'nestedItem2', 'funcThatRaises': funcThatRaises, 'aClass': DummyClass, }, 'nestedFunc': dummyFunc, }, 'aClass': DummyClass, 'aFunc': dummyFunc, 'anObj': DummyClass(), 'anObjThatRaises': DummyClassGetAttrRaises(), 'aMeth': DummyClass().meth1, 'none': None, 'emptyString': '', 'funcThatRaises': funcThatRaises, } autoCallResults = {'aFunc': 'Scooby', 'aMeth': 'doo', } results = testNamespace.copy() results.update({'anObj.meth1': 'doo', 'aDict.one': 'item1', 'aDict.nestedDict': testNamespace['aDict']['nestedDict'], 'aDict.nestedDict.one': 'nestedItem1', 'aDict.nestedDict.aClass': DummyClass, 'aDict.nestedFunc': 'Scooby', 'aClass.classVar1': 123, 'anObj.instanceVar1': 123, 'anObj.meth3': 'A string', }) for k in testNamespace.keys(): # put them in the globals for the valueFromFrame tests exec('%s = testNamespace[k]'%k) ################################################## ## TEST BASE CLASSES class NameMapperTest(unittest.TestCase): failureException = NotFound _testNamespace = testNamespace _results = results def namespace(self): return self._testNamespace def VFN(self, name, autocall=True): return valueForName(self.namespace(), name, autocall) def VFS(self, searchList, name, autocall=True): return valueFromSearchList(searchList, name, autocall) # alias to be overriden later get = VFN def check(self, name): got = self.get(name) if name in autoCallResults: expected = autoCallResults[name] else: expected = self._results[name] assert got == expected ################################################## ## TEST CASE CLASSES class VFN(NameMapperTest): def test1(self): """string in dict lookup""" self.check('aStr') def test2(self): """string in dict lookup in a loop""" for i in range(10): self.check('aStr') def test3(self): """int in dict lookup""" self.check('anInt') def test4(self): """int in dict lookup in a loop""" for i in range(10): self.check('anInt') def test5(self): """float in dict lookup""" self.check('aFloat') def test6(self): """float in dict lookup in a loop""" for i in range(10): self.check('aFloat') def test7(self): """class in dict lookup""" self.check('aClass') def test8(self): """class in dict lookup in a loop""" for i in range(10): self.check('aClass') def test9(self): """aFunc in dict lookup""" self.check('aFunc') def test10(self): """aFunc in dict lookup in a loop""" for i in range(10): self.check('aFunc') def test11(self): """aMeth in dict lookup""" self.check('aMeth') def test12(self): """aMeth in dict lookup in a loop""" for i in range(10): self.check('aMeth') def test13(self): """aMeth in dict lookup""" self.check('aMeth') def test14(self): """aMeth in dict lookup in a loop""" for i in range(10): self.check('aMeth') def test15(self): """anObj in dict lookup""" self.check('anObj') def test16(self): """anObj in dict lookup in a loop""" for i in range(10): self.check('anObj') def test17(self): """aDict in dict lookup""" self.check('aDict') def test18(self): """aDict in dict lookup in a loop""" for i in range(10): self.check('aDict') def test17(self): """aDict in dict lookup""" self.check('aDict') def test18(self): """aDict in dict lookup in a loop""" for i in range(10): self.check('aDict') def test19(self): """aClass.classVar1 in dict lookup""" self.check('aClass.classVar1') def test20(self): """aClass.classVar1 in dict lookup in a loop""" for i in range(10): self.check('aClass.classVar1') def test23(self): """anObj.instanceVar1 in dict lookup""" self.check('anObj.instanceVar1') def test24(self): """anObj.instanceVar1 in dict lookup in a loop""" for i in range(10): self.check('anObj.instanceVar1') ## tests 22, 25, and 26 removed when the underscored lookup was removed def test27(self): """anObj.meth1 in dict lookup""" self.check('anObj.meth1') def test28(self): """anObj.meth1 in dict lookup in a loop""" for i in range(10): self.check('anObj.meth1') def test29(self): """aDict.one in dict lookup""" self.check('aDict.one') def test30(self): """aDict.one in dict lookup in a loop""" for i in range(10): self.check('aDict.one') def test31(self): """aDict.nestedDict in dict lookup""" self.check('aDict.nestedDict') def test32(self): """aDict.nestedDict in dict lookup in a loop""" for i in range(10): self.check('aDict.nestedDict') def test33(self): """aDict.nestedDict.one in dict lookup""" self.check('aDict.nestedDict.one') def test34(self): """aDict.nestedDict.one in dict lookup in a loop""" for i in range(10): self.check('aDict.nestedDict.one') def test35(self): """aDict.nestedFunc in dict lookup""" self.check('aDict.nestedFunc') def test36(self): """aDict.nestedFunc in dict lookup in a loop""" for i in range(10): self.check('aDict.nestedFunc') def test37(self): """aDict.nestedFunc in dict lookup - without autocalling""" assert self.get('aDict.nestedFunc', False) == dummyFunc def test38(self): """aDict.nestedFunc in dict lookup in a loop - without autocalling""" for i in range(10): assert self.get('aDict.nestedFunc', False) == dummyFunc def test39(self): """aMeth in dict lookup - without autocalling""" assert self.get('aMeth', False) == self.namespace()['aMeth'] def test40(self): """aMeth in dict lookup in a loop - without autocalling""" for i in range(10): assert self.get('aMeth', False) == self.namespace()['aMeth'] def test41(self): """anObj.meth3 in dict lookup""" self.check('anObj.meth3') def test42(self): """aMeth in dict lookup in a loop""" for i in range(10): self.check('anObj.meth3') def test43(self): """NotFound test""" def test(self=self): self.get('anObj.methX') self.assertRaises(NotFound, test) def test44(self): """NotFound test in a loop""" def test(self=self): self.get('anObj.methX') for i in range(10): self.assertRaises(NotFound, test) def test45(self): """Other exception from meth test""" def test(self=self): self.get('anObj.meth2') self.assertRaises(ValueError, test) def test46(self): """Other exception from meth test in a loop""" def test(self=self): self.get('anObj.meth2') for i in range(10): self.assertRaises(ValueError, test) def test47(self): """None in dict lookup""" self.check('none') def test48(self): """None in dict lookup in a loop""" for i in range(10): self.check('none') def test49(self): """EmptyString in dict lookup""" self.check('emptyString') def test50(self): """EmptyString in dict lookup in a loop""" for i in range(10): self.check('emptyString') def test51(self): """Other exception from func test""" def test(self=self): self.get('funcThatRaises') self.assertRaises(ValueError, test) def test52(self): """Other exception from func test in a loop""" def test(self=self): self.get('funcThatRaises') for i in range(10): self.assertRaises(ValueError, test) def test53(self): """Other exception from func test""" def test(self=self): self.get('aDict.nestedDict.funcThatRaises') self.assertRaises(ValueError, test) def test54(self): """Other exception from func test in a loop""" def test(self=self): self.get('aDict.nestedDict.funcThatRaises') for i in range(10): self.assertRaises(ValueError, test) def test55(self): """aDict.nestedDict.aClass in dict lookup""" self.check('aDict.nestedDict.aClass') def test56(self): """aDict.nestedDict.aClass in dict lookup in a loop""" for i in range(10): self.check('aDict.nestedDict.aClass') def test57(self): """aDict.nestedDict.aClass in dict lookup - without autocalling""" assert self.get('aDict.nestedDict.aClass', False) == DummyClass def test58(self): """aDict.nestedDict.aClass in dict lookup in a loop - without autocalling""" for i in range(10): assert self.get('aDict.nestedDict.aClass', False) == DummyClass def test59(self): """Other exception from func test -- but without autocalling shouldn't raise""" self.get('aDict.nestedDict.funcThatRaises', False) def test60(self): """Other exception from func test in a loop -- but without autocalling shouldn't raise""" for i in range(10): self.get('aDict.nestedDict.funcThatRaises', False) def test61(self): """Accessing attribute where __getattr__ raises shouldn't segfault if something follows it""" def test(self=self): self.get('anObjThatRaises.willraise.anything') self.assertRaises(ValueError, test) class VFS(VFN): _searchListLength = 1 def searchList(self): lng = self._searchListLength if lng == 1: return [self.namespace()] elif lng == 2: return [self.namespace(), {'dummy':1234}] elif lng == 3: # a tuple for kicks return ({'dummy':1234}, self.namespace(), {'dummy':1234}) elif lng == 4: # a generator for more kicks return self.searchListGenerator() def searchListGenerator(self): class Test: pass for i in [Test(), {'dummy':1234}, self.namespace(), {'dummy':1234}]: yield i def get(self, name, autocall=True): return self.VFS(self.searchList(), name, autocall) class VFS_2namespaces(VFS): _searchListLength = 2 class VFS_3namespaces(VFS): _searchListLength = 3 class VFS_4namespaces(VFS): _searchListLength = 4 class VFF(VFN): def get(self, name, autocall=True): ns = self._testNamespace aStr = ns['aStr'] aFloat = ns['aFloat'] none = 'some' return valueFromFrame(name, autocall) def setUp(self): """Mod some of the data """ self._testNamespace = ns = self._testNamespace.copy() self._results = res = self._results.copy() ns['aStr'] = res['aStr'] = 'BLARG' ns['aFloat'] = res['aFloat'] = 0.1234 res['none'] = 'some' res['True'] = True res['False'] = False res['None'] = None res['eval'] = eval def test_VFF_1(self): """Builtins""" self.check('True') self.check('None') self.check('False') assert self.get('eval', False)==eval assert self.get('range', False)==range class VFFSL(VFS): _searchListLength = 1 def setUp(self): """Mod some of the data """ self._testNamespace = ns = self._testNamespace.copy() self._results = res = self._results.copy() ns['aStr'] = res['aStr'] = 'BLARG' ns['aFloat'] = res['aFloat'] = 0.1234 res['none'] = 'some' del ns['anInt'] # will be picked up by globals def VFFSL(self, searchList, name, autocall=True): anInt = 1 none = 'some' return valueFromFrameOrSearchList(searchList, name, autocall) def get(self, name, autocall=True): return self.VFFSL(self.searchList(), name, autocall) class VFFSL_2(VFFSL): _searchListLength = 2 class VFFSL_3(VFFSL): _searchListLength = 3 class VFFSL_4(VFFSL): _searchListLength = 4 if sys.platform.startswith('java'): del VFF, VFFSL, VFFSL_2, VFFSL_3, VFFSL_4 class MapBuiltins(unittest.TestCase): def test_int(self): from Cheetah.Template import Template t = Template(''' #def intify(val) #return $int(val) #end def''', compilerSettings={'useStackFrames' : False}) self.assertEquals(5, t.intify('5')) ################################################## ## if run from the command line ## if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/Unicode.py0000644000175000001440000001623011413255133016603 0ustar tylerusers#!/usr/bin/env python # -*- encoding: utf8 -*- from Cheetah.Template import Template from Cheetah import CheetahWrapper from Cheetah import DummyTransaction import imp import os import sys import tempfile import unittest class CommandLineTest(unittest.TestCase): def createAndCompile(self, source): sourcefile = '-' while sourcefile.find('-') != -1: sourcefile = tempfile.mktemp() fd = open('%s.tmpl' % sourcefile, 'w') fd.write(source) fd.close() wrap = CheetahWrapper.CheetahWrapper() wrap.main(['cheetah', 'compile', '--quiet', '--nobackup', sourcefile]) module_path, module_name = os.path.split(sourcefile) module = loadModule(module_name, [module_path]) template = getattr(module, module_name) return template class JBQ_UTF8_Test1(unittest.TestCase): def runTest(self): t = Template.compile(source="""Main file with |$v| $other""") otherT = Template.compile(source="Other template with |$v|") other = otherT() t.other = other t.v = u'Unicode String' t.other.v = u'Unicode String' assert unicode(t()) class JBQ_UTF8_Test2(unittest.TestCase): def runTest(self): t = Template.compile(source="""Main file with |$v| $other""") otherT = Template.compile(source="Other template with |$v|") other = otherT() t.other = other t.v = u'Unicode String with eacute é' t.other.v = u'Unicode String' assert unicode(t()) class JBQ_UTF8_Test3(unittest.TestCase): def runTest(self): t = Template.compile(source="""Main file with |$v| $other""") otherT = Template.compile(source="Other template with |$v|") other = otherT() t.other = other t.v = u'Unicode String with eacute é' t.other.v = u'Unicode String and an eacute é' assert unicode(t()) class JBQ_UTF8_Test4(unittest.TestCase): def runTest(self): t = Template.compile(source="""#encoding utf-8 Main file with |$v| and eacute in the template é""") t.v = 'Unicode String' assert unicode(t()) class JBQ_UTF8_Test5(unittest.TestCase): def runTest(self): t = Template.compile(source="""#encoding utf-8 Main file with |$v| and eacute in the template é""") t.v = u'Unicode String' assert unicode(t()) def loadModule(moduleName, path=None): if path: assert isinstance(path, list) try: mod = sys.modules[moduleName] except KeyError: fp = None try: fp, pathname, description = imp.find_module(moduleName, path) mod = imp.load_module(moduleName, fp, pathname, description) finally: if fp: fp.close() return mod class JBQ_UTF8_Test6(unittest.TestCase): def runTest(self): source = """#encoding utf-8 #set $someUnicodeString = u"Bébé" Main file with |$v| and eacute in the template é""" t = Template.compile(source=source) t.v = u'Unicode String' assert unicode(t()) class JBQ_UTF8_Test7(CommandLineTest): def runTest(self): source = """#encoding utf-8 #set $someUnicodeString = u"Bébé" Main file with |$v| and eacute in the template é""" template = self.createAndCompile(source) template.v = u'Unicode String' assert unicode(template()) class JBQ_UTF8_Test8(CommandLineTest): def testStaticCompile(self): source = """#encoding utf-8 #set $someUnicodeString = u"Bébé" $someUnicodeString""" template = self.createAndCompile(source)() a = unicode(template).encode("utf-8") self.assertEquals("Bébé", a) def testDynamicCompile(self): source = """#encoding utf-8 #set $someUnicodeString = u"Bébé" $someUnicodeString""" template = Template(source = source) a = unicode(template).encode("utf-8") self.assertEquals("Bébé", a) class EncodeUnicodeCompatTest(unittest.TestCase): """ Taken initially from Red Hat's bugzilla #529332 https://bugzilla.redhat.com/show_bug.cgi?id=529332 """ def runTest(self): t = Template("""Foo ${var}""", filter='EncodeUnicode') t.var = u"Text with some non-ascii characters: åäö" rc = t.respond() assert isinstance(rc, unicode), ('Template.respond() should return unicode', rc) rc = str(t) assert isinstance(rc, str), ('Template.__str__() should return a UTF-8 encoded string', rc) class Unicode_in_SearchList_Test(CommandLineTest): def test_BasicASCII(self): source = '''This is $adjective''' template = self.createAndCompile(source) assert template and issubclass(template, Template) template = template(searchList=[{'adjective' : u'neat'}]) assert template.respond() def test_Thai(self): # The string is something in Thai source = '''This is $foo $adjective''' template = self.createAndCompile(source) assert template and issubclass(template, Template) template = template(searchList=[{'foo' : 'bar', 'adjective' : u'\u0e22\u0e34\u0e19\u0e14\u0e35\u0e15\u0e49\u0e2d\u0e19\u0e23\u0e31\u0e1a'}]) assert template.respond() def test_Thai_utf8(self): utf8 = '\xe0\xb8\xa2\xe0\xb8\xb4\xe0\xb8\x99\xe0\xb8\x94\xe0\xb8\xb5\xe0\xb8\x95\xe0\xb9\x89\xe0\xb8\xad\xe0\xb8\x99\xe0\xb8\xa3\xe0\xb8\xb1\xe0\xb8\x9a' source = '''This is $adjective''' template = self.createAndCompile(source) assert template and issubclass(template, Template) template = template(searchList=[{'adjective' : utf8}]) assert template.respond() class InlineSpanishTest(unittest.TestCase): def setUp(self): super(InlineSpanishTest, self).setUp() self.template = ''' Pagina del vendedor $header

Bienvenido $nombre.




Usted tiene $numpedidos_noconf pedidós sin confirmar.

Bodega tiene fecha para $numpedidos_bodega pedidos.
''' def test_failure(self): """ Test a template lacking a proper #encoding tag """ self.failUnlessRaises(UnicodeDecodeError, Template, self.template, searchList=[{'header' : '', 'nombre' : '', 'numpedidos_bodega' : '', 'numpedidos_noconf' : ''}]) def test_success(self): """ Test a template with a proper #encoding tag """ template = '#encoding utf-8\n%s' % self.template template = Template(template, searchList=[{'header' : '', 'nombre' : '', 'numpedidos_bodega' : '', 'numpedidos_noconf' : ''}]) self.assertTrue(unicode(template)) if __name__ == '__main__': unittest.main() Cheetah-2.4.4/cheetah/Tests/CheetahWrapper.py0000644000175000001440000004536111444460060020127 0ustar tylerusers#!/usr/bin/env python ''' Tests for the 'cheetah' command. Besides unittest usage, recognizes the following command-line options: --list CheetahWrapper.py List all scenarios that are tested. The argument is the path of this script. --nodelete Don't delete scratch directory at end. --output Show the output of each subcommand. (Normally suppressed.) ''' import os import os.path import pdb import re # Used by listTests. import shutil import sys import tempfile import unittest from optparse import OptionParser from Cheetah.CheetahWrapper import CheetahWrapper # Used by NoBackup. try: from subprocess import Popen, PIPE, STDOUT class Popen4(Popen): def __init__(self, cmd, bufsize=-1, shell=True, close_fds=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, **kwargs): super(Popen4, self).__init__(cmd, bufsize=bufsize, shell=shell, close_fds=close_fds, stdin=stdin, stdout=stdout, stderr=stderr, **kwargs) self.tochild = self.stdin self.fromchild = self.stdout self.childerr = self.stderr except ImportError: from popen2 import Popen4 DELETE = True # True to clean up after ourselves, False for debugging. OUTPUT = False # Normally False, True for debugging. BACKUP_SUFFIX = CheetahWrapper.BACKUP_SUFFIX def warn(msg): sys.stderr.write(msg + '\n') class CFBase(unittest.TestCase): """Base class for "cheetah compile" and "cheetah fill" unit tests. """ srcDir = '' # Nonblank to create source directory. subdirs = ('child', 'child/grandkid') # Delete in reverse order. srcFiles = ('a.tmpl', 'child/a.tmpl', 'child/grandkid/a.tmpl') expectError = False # Used by --list option. def inform(self, message): if self.verbose: print(message) def setUp(self): """Create the top-level directories, subdirectories and .tmpl files. """ self.cmd = self.locate_cheetah('cheetah') pythonPath = os.getcwd() if not os.environ.get('PYTHONPATH'): os.environ['PYTHONPATH'] = pythonPath else: os.environ['PYTHONPATH'] = '%s:%s' % (os.environ['PYTHONPATH'], pythonPath) I = self.inform # Step 1: Create the scratch directory and chdir into it. self.scratchDir = scratchDir = tempfile.mktemp() os.mkdir(scratchDir) self.origCwd = os.getcwd() os.chdir(scratchDir) if self.srcDir: os.mkdir(self.srcDir) # Step 2: Create source subdirectories. for dir in self.subdirs: os.mkdir(dir) # Step 3: Create the .tmpl files, each in its proper directory. for fil in self.srcFiles: f = open(fil, 'w') f.write("Hello, world!\n") f.close() def tearDown(self): os.chdir(self.origCwd) if DELETE: shutil.rmtree(self.scratchDir, True) # Ignore errors. if os.path.exists(self.scratchDir): warn("Warning: unable to delete scratch directory %s") else: warn("Warning: not deleting scratch directory %s" % self.scratchDir) def _checkDestFileHelper(self, path, expected, allowSurroundingText, errmsg): """Low-level helper to check a destination file. in : path, string, the destination path. expected, string, the expected contents. allowSurroundingtext, bool, allow the result to contain additional text around the 'expected' substring? errmsg, string, the error message. It may contain the following "%"-operator keys: path, expected, result. out: None """ path = os.path.abspath(path) exists = os.path.exists(path) msg = "destination file missing: %s" % path self.failUnless(exists, msg) f = open(path, 'r') result = f.read() f.close() if allowSurroundingText: success = result.find(expected) != -1 else: success = result == expected msg = errmsg % locals() self.failUnless(success, msg) def checkCompile(self, path): # Raw string to prevent "\n" from being converted to a newline. #expected = R"write('Hello, world!\n')" expected = "Hello, world!" # might output a u'' string errmsg = """\ destination file %(path)s doesn't contain expected substring: %(expected)r""" self._checkDestFileHelper(path, expected, True, errmsg) def checkFill(self, path): expected = "Hello, world!\n" errmsg = """\ destination file %(path)s contains wrong result. Expected %(expected)r Found %(result)r""" self._checkDestFileHelper(path, expected, False, errmsg) def checkSubdirPyInit(self, path): """Verify a destination subdirectory exists and contains an __init__.py file. """ exists = os.path.exists(path) msg = "destination subdirectory %s misssing" % path self.failUnless(exists, msg) initPath = os.path.join(path, "__init__.py") exists = os.path.exists(initPath) msg = "destination init file missing: %s" % initPath self.failUnless(exists, msg) def checkNoBackup(self, path): """Verify 'path' does not exist. (To check --nobackup.) """ exists = os.path.exists(path) msg = "backup file exists in spite of --nobackup: %s" % path self.failIf(exists, msg) def locate_cheetah(self, cmd): paths = os.getenv('PATH') if not paths: return cmd parts = cmd.split(' ') paths = paths.split(':') for p in paths: p = os.path.join(p, cmd) p = os.path.abspath(p) if os.path.isfile(p): return p return cmd def assertWin32Subprocess(self, cmd): _in, _out = os.popen4(cmd) _in.close() output = _out.read() rc = _out.close() if rc is None: rc = 0 return rc, output def assertPosixSubprocess(self, cmd): cmd = cmd.replace('cheetah', self.cmd) process = Popen4(cmd, env=os.environ) process.tochild.close() output = process.fromchild.read() status = process.wait() process.fromchild.close() return status, output def assertSubprocess(self, cmd, nonzero=False): status, output = None, None if sys.platform == 'win32': status, output = self.assertWin32Subprocess(cmd) else: status, output = self.assertPosixSubprocess(cmd) if not nonzero: self.failUnlessEqual(status, 0, '''Subprocess exited with a non-zero status (%d) %s''' % (status, output)) else: self.failIfEqual(status, 0, '''Subprocess exited with a zero status (%d) %s''' % (status, output)) return output def go(self, cmd, expectedStatus=0, expectedOutputSubstring=None): """Run a "cheetah compile" or "cheetah fill" subcommand. in : cmd, string, the command to run. expectedStatus, int, subcommand's expected output status. 0 if the subcommand is expected to succeed, 1-255 otherwise. expectedOutputSubstring, string, substring which much appear in the standard output or standard error. None to skip this test. out: None. """ output = self.assertSubprocess(cmd) if expectedOutputSubstring is not None: msg = "substring %r not found in subcommand output: %s" % \ (expectedOutputSubstring, cmd) substringTest = output.find(expectedOutputSubstring) != -1 self.failUnless(substringTest, msg) class CFIdirBase(CFBase): """Subclass for tests with --idir. """ srcDir = 'SRC' subdirs = ('SRC/child', 'SRC/child/grandkid') # Delete in reverse order. srcFiles = ('SRC/a.tmpl', 'SRC/child/a.tmpl', 'SRC/child/grandkid/a.tmpl') ################################################## ## TEST CASE CLASSES class OneFile(CFBase): def testCompile(self): self.go("cheetah compile a.tmpl") self.checkCompile("a.py") def testFill(self): self.go("cheetah fill a.tmpl") self.checkFill("a.html") def testText(self): self.go("cheetah fill --oext txt a.tmpl") self.checkFill("a.txt") class OneFileNoExtension(CFBase): def testCompile(self): self.go("cheetah compile a") self.checkCompile("a.py") def testFill(self): self.go("cheetah fill a") self.checkFill("a.html") def testText(self): self.go("cheetah fill --oext txt a") self.checkFill("a.txt") class SplatTmpl(CFBase): def testCompile(self): self.go("cheetah compile *.tmpl") self.checkCompile("a.py") def testFill(self): self.go("cheetah fill *.tmpl") self.checkFill("a.html") def testText(self): self.go("cheetah fill --oext txt *.tmpl") self.checkFill("a.txt") class ThreeFilesWithSubdirectories(CFBase): def testCompile(self): self.go("cheetah compile a.tmpl child/a.tmpl child/grandkid/a.tmpl") self.checkCompile("a.py") self.checkCompile("child/a.py") self.checkCompile("child/grandkid/a.py") def testFill(self): self.go("cheetah fill a.tmpl child/a.tmpl child/grandkid/a.tmpl") self.checkFill("a.html") self.checkFill("child/a.html") self.checkFill("child/grandkid/a.html") def testText(self): self.go("cheetah fill --oext txt a.tmpl child/a.tmpl child/grandkid/a.tmpl") self.checkFill("a.txt") self.checkFill("child/a.txt") self.checkFill("child/grandkid/a.txt") class ThreeFilesWithSubdirectoriesNoExtension(CFBase): def testCompile(self): self.go("cheetah compile a child/a child/grandkid/a") self.checkCompile("a.py") self.checkCompile("child/a.py") self.checkCompile("child/grandkid/a.py") def testFill(self): self.go("cheetah fill a child/a child/grandkid/a") self.checkFill("a.html") self.checkFill("child/a.html") self.checkFill("child/grandkid/a.html") def testText(self): self.go("cheetah fill --oext txt a child/a child/grandkid/a") self.checkFill("a.txt") self.checkFill("child/a.txt") self.checkFill("child/grandkid/a.txt") class SplatTmplWithSubdirectories(CFBase): def testCompile(self): self.go("cheetah compile *.tmpl child/*.tmpl child/grandkid/*.tmpl") self.checkCompile("a.py") self.checkCompile("child/a.py") self.checkCompile("child/grandkid/a.py") def testFill(self): self.go("cheetah fill *.tmpl child/*.tmpl child/grandkid/*.tmpl") self.checkFill("a.html") self.checkFill("child/a.html") self.checkFill("child/grandkid/a.html") def testText(self): self.go("cheetah fill --oext txt *.tmpl child/*.tmpl child/grandkid/*.tmpl") self.checkFill("a.txt") self.checkFill("child/a.txt") self.checkFill("child/grandkid/a.txt") class OneFileWithOdir(CFBase): def testCompile(self): self.go("cheetah compile --odir DEST a.tmpl") self.checkSubdirPyInit("DEST") self.checkCompile("DEST/a.py") def testFill(self): self.go("cheetah fill --odir DEST a.tmpl") self.checkFill("DEST/a.html") def testText(self): self.go("cheetah fill --odir DEST --oext txt a.tmpl") self.checkFill("DEST/a.txt") class VarietyWithOdir(CFBase): def testCompile(self): self.go("cheetah compile --odir DEST a.tmpl child/a child/grandkid/*.tmpl") self.checkSubdirPyInit("DEST") self.checkSubdirPyInit("DEST/child") self.checkSubdirPyInit("DEST/child/grandkid") self.checkCompile("DEST/a.py") self.checkCompile("DEST/child/a.py") self.checkCompile("DEST/child/grandkid/a.py") def testFill(self): self.go("cheetah fill --odir DEST a.tmpl child/a child/grandkid/*.tmpl") self.checkFill("DEST/a.html") self.checkFill("DEST/child/a.html") self.checkFill("DEST/child/grandkid/a.html") def testText(self): self.go("cheetah fill --odir DEST --oext txt a.tmpl child/a child/grandkid/*.tmpl") self.checkFill("DEST/a.txt") self.checkFill("DEST/child/a.txt") self.checkFill("DEST/child/grandkid/a.txt") class RecurseExplicit(CFBase): def testCompile(self): self.go("cheetah compile -R child") self.checkCompile("child/a.py") self.checkCompile("child/grandkid/a.py") def testFill(self): self.go("cheetah fill -R child") self.checkFill("child/a.html") self.checkFill("child/grandkid/a.html") def testText(self): self.go("cheetah fill -R --oext txt child") self.checkFill("child/a.txt") self.checkFill("child/grandkid/a.txt") class RecurseImplicit(CFBase): def testCompile(self): self.go("cheetah compile -R") self.checkCompile("child/a.py") self.checkCompile("child/grandkid/a.py") def testFill(self): self.go("cheetah fill -R") self.checkFill("a.html") self.checkFill("child/a.html") self.checkFill("child/grandkid/a.html") def testText(self): self.go("cheetah fill -R --oext txt") self.checkFill("a.txt") self.checkFill("child/a.txt") self.checkFill("child/grandkid/a.txt") class RecurseExplicitWIthOdir(CFBase): def testCompile(self): self.go("cheetah compile -R --odir DEST child") self.checkSubdirPyInit("DEST/child") self.checkSubdirPyInit("DEST/child/grandkid") self.checkCompile("DEST/child/a.py") self.checkCompile("DEST/child/grandkid/a.py") def testFill(self): self.go("cheetah fill -R --odir DEST child") self.checkFill("DEST/child/a.html") self.checkFill("DEST/child/grandkid/a.html") def testText(self): self.go("cheetah fill -R --odir DEST --oext txt child") self.checkFill("DEST/child/a.txt") self.checkFill("DEST/child/grandkid/a.txt") class Flat(CFBase): def testCompile(self): self.go("cheetah compile --flat child/a.tmpl") self.checkCompile("a.py") def testFill(self): self.go("cheetah fill --flat child/a.tmpl") self.checkFill("a.html") def testText(self): self.go("cheetah fill --flat --oext txt child/a.tmpl") self.checkFill("a.txt") class FlatRecurseCollision(CFBase): expectError = True def testCompile(self): self.assertSubprocess("cheetah compile -R --flat", nonzero=True) def testFill(self): self.assertSubprocess("cheetah fill -R --flat", nonzero=True) def testText(self): self.assertSubprocess("cheetah fill -R --flat", nonzero=True) class IdirRecurse(CFIdirBase): def testCompile(self): self.go("cheetah compile -R --idir SRC child") self.checkSubdirPyInit("child") self.checkSubdirPyInit("child/grandkid") self.checkCompile("child/a.py") self.checkCompile("child/grandkid/a.py") def testFill(self): self.go("cheetah fill -R --idir SRC child") self.checkFill("child/a.html") self.checkFill("child/grandkid/a.html") def testText(self): self.go("cheetah fill -R --idir SRC --oext txt child") self.checkFill("child/a.txt") self.checkFill("child/grandkid/a.txt") class IdirOdirRecurse(CFIdirBase): def testCompile(self): self.go("cheetah compile -R --idir SRC --odir DEST child") self.checkSubdirPyInit("DEST/child") self.checkSubdirPyInit("DEST/child/grandkid") self.checkCompile("DEST/child/a.py") self.checkCompile("DEST/child/grandkid/a.py") def testFill(self): self.go("cheetah fill -R --idir SRC --odir DEST child") self.checkFill("DEST/child/a.html") self.checkFill("DEST/child/grandkid/a.html") def testText(self): self.go("cheetah fill -R --idir SRC --odir DEST --oext txt child") self.checkFill("DEST/child/a.txt") self.checkFill("DEST/child/grandkid/a.txt") class IdirFlatRecurseCollision(CFIdirBase): expectError = True def testCompile(self): self.assertSubprocess("cheetah compile -R --flat --idir SRC", nonzero=True) def testFill(self): self.assertSubprocess("cheetah fill -R --flat --idir SRC", nonzero=True) def testText(self): self.assertSubprocess("cheetah fill -R --flat --idir SRC --oext txt", nonzero=True) class NoBackup(CFBase): """Run the command twice each time and verify a backup file is *not* created. """ def testCompile(self): self.go("cheetah compile --nobackup a.tmpl") self.go("cheetah compile --nobackup a.tmpl") self.checkNoBackup("a.py" + BACKUP_SUFFIX) def testFill(self): self.go("cheetah fill --nobackup a.tmpl") self.go("cheetah fill --nobackup a.tmpl") self.checkNoBackup("a.html" + BACKUP_SUFFIX) def testText(self): self.go("cheetah fill --nobackup --oext txt a.tmpl") self.go("cheetah fill --nobackup --oext txt a.tmpl") self.checkNoBackup("a.txt" + BACKUP_SUFFIX) def listTests(cheetahWrapperFile): """cheetahWrapperFile, string, path of this script. XXX TODO: don't print test where expectError is true. """ rx = re.compile( R'self\.go\("(.*?)"\)' ) f = open(cheetahWrapperFile) while True: lin = f.readline() if not lin: break m = rx.search(lin) if m: print(m.group(1)) f.close() def main(): global DELETE, OUTPUT parser = OptionParser() parser.add_option("--list", action="store", dest="listTests") parser.add_option("--nodelete", action="store_true") parser.add_option("--output", action="store_true") # The following options are passed to unittest. parser.add_option("-e", "--explain", action="store_true") parser.add_option("-v", "--verbose", action="store_true") parser.add_option("-q", "--quiet", action="store_true") opts, files = parser.parse_args() if opts.nodelete: DELETE = False if opts.output: OUTPUT = True if opts.listTests: listTests(opts.listTests) else: # Eliminate script-specific command-line arguments to prevent # errors in unittest. del sys.argv[1:] for opt in ("explain", "verbose", "quiet"): if getattr(opts, opt): sys.argv.append("--" + opt) sys.argv.extend(files) unittest.main() if __name__ == '__main__': main() # vim: sw=4 ts=4 expandtab Cheetah-2.4.4/cheetah/SettingsManager.py0000644000175000001440000002370611413255133017214 0ustar tylerusersimport sys import os.path import copy as copyModule from ConfigParser import ConfigParser import re from tokenize import Intnumber, Floatnumber, Number import types import time from StringIO import StringIO # not cStringIO because of unicode support import imp # used by SettingsManager.updateSettingsFromPySrcFile() numberRE = re.compile(Number) complexNumberRE = re.compile('[\(]*' +Number + r'[ \t]*\+[ \t]*' + Number + '[\)]*') ################################################## ## FUNCTIONS ## def mergeNestedDictionaries(dict1, dict2, copy=False, deepcopy=False): """Recursively merge the values of dict2 into dict1. This little function is very handy for selectively overriding settings in a settings dictionary that has a nested structure. """ if copy: dict1 = copyModule.copy(dict1) elif deepcopy: dict1 = copyModule.deepcopy(dict1) for key, val in dict2.iteritems(): if key in dict1 and isinstance(val, dict) and isinstance(dict1[key], dict): dict1[key] = mergeNestedDictionaries(dict1[key], val) else: dict1[key] = val return dict1 def stringIsNumber(S): """Return True if theString represents a Python number, False otherwise. This also works for complex numbers and numbers with +/- in front.""" S = S.strip() if S[0] in '-+' and len(S) > 1: S = S[1:].strip() match = complexNumberRE.match(S) if not match: match = numberRE.match(S) if not match or (match.end() != len(S)): return False else: return True def convStringToNum(theString): """Convert a string representation of a Python number to the Python version""" if not stringIsNumber(theString): raise Error(theString + ' cannot be converted to a Python number') return eval(theString, {}, {}) class Error(Exception): pass class NoDefault(object): pass class ConfigParserCaseSensitive(ConfigParser): """A case sensitive version of the standard Python ConfigParser.""" def optionxform(self, optionstr): """Don't change the case as is done in the default implemenation.""" return optionstr class _SettingsCollector(object): """An abstract base class that provides the methods SettingsManager uses to collect settings from config files and strings. This class only collects settings it doesn't modify the _settings dictionary of SettingsManager instances in any way. """ _ConfigParserClass = ConfigParserCaseSensitive def readSettingsFromModule(self, mod, ignoreUnderscored=True): """Returns all settings from a Python module. """ S = {} attrs = vars(mod) for k, v in attrs.iteritems(): if (ignoreUnderscored and k.startswith('_')): continue else: S[k] = v return S def readSettingsFromPySrcStr(self, theString): """Return a dictionary of the settings in a Python src string.""" globalsDict = {'True': (1==1), 'False': (0==1), } newSettings = {'self':self} exec((theString+os.linesep), globalsDict, newSettings) del newSettings['self'] module = types.ModuleType('temp_settings_module') module.__dict__.update(newSettings) return self.readSettingsFromModule(module) def readSettingsFromConfigFileObj(self, inFile, convert=True): """Return the settings from a config file that uses the syntax accepted by Python's standard ConfigParser module (like Windows .ini files). NOTE: this method maintains case unlike the ConfigParser module, unless this class was initialized with the 'caseSensitive' keyword set to False. All setting values are initially parsed as strings. However, If the 'convert' arg is True this method will do the following value conversions: * all Python numeric literals will be coverted from string to number * The string 'None' will be converted to the Python value None * The string 'True' will be converted to a Python truth value * The string 'False' will be converted to a Python false value * Any string starting with 'python:' will be treated as a Python literal or expression that needs to be eval'd. This approach is useful for declaring lists and dictionaries. If a config section titled 'Globals' is present the options defined under it will be treated as top-level settings. """ p = self._ConfigParserClass() p.readfp(inFile) sects = p.sections() newSettings = {} sects = p.sections() newSettings = {} for s in sects: newSettings[s] = {} for o in p.options(s): if o != '__name__': newSettings[s][o] = p.get(s, o) ## loop through new settings -> deal with global settings, numbers, ## booleans and None ++ also deal with 'importSettings' commands for sect, subDict in newSettings.items(): for key, val in subDict.items(): if convert: if val.lower().startswith('python:'): subDict[key] = eval(val[7:], {}, {}) if val.lower() == 'none': subDict[key] = None if val.lower() == 'true': subDict[key] = True if val.lower() == 'false': subDict[key] = False if stringIsNumber(val): subDict[key] = convStringToNum(val) ## now deal with any 'importSettings' commands if key.lower() == 'importsettings': if val.find(';') < 0: importedSettings = self.readSettingsFromPySrcFile(val) else: path = val.split(';')[0] rest = ''.join(val.split(';')[1:]).strip() parentDict = self.readSettingsFromPySrcFile(path) importedSettings = eval('parentDict["' + rest + '"]') subDict.update(mergeNestedDictionaries(subDict, importedSettings)) if sect.lower() == 'globals': newSettings.update(newSettings[sect]) del newSettings[sect] return newSettings class SettingsManager(_SettingsCollector): """A mixin class that provides facilities for managing application settings. SettingsManager is designed to work well with nested settings dictionaries of any depth. """ def __init__(self): super(SettingsManager, self).__init__() self._settings = {} self._initializeSettings() def _defaultSettings(self): return {} def _initializeSettings(self): """A hook that allows for complex setting initialization sequences that involve references to 'self' or other settings. For example: self._settings['myCalcVal'] = self._settings['someVal'] * 15 This method should be called by the class' __init__() method when needed. The dummy implementation should be reimplemented by subclasses. """ pass ## core post startup methods def setting(self, name, default=NoDefault): """Get a setting from self._settings, with or without a default value.""" if default is NoDefault: return self._settings[name] else: return self._settings.get(name, default) def hasSetting(self, key): """True/False""" return key in self._settings def setSetting(self, name, value): """Set a setting in self._settings.""" self._settings[name] = value def settings(self): """Return a reference to the settings dictionary""" return self._settings def copySettings(self): """Returns a shallow copy of the settings dictionary""" return copyModule.copy(self._settings) def deepcopySettings(self): """Returns a deep copy of the settings dictionary""" return copyModule.deepcopy(self._settings) def updateSettings(self, newSettings, merge=True): """Update the settings with a selective merge or a complete overwrite.""" if merge: mergeNestedDictionaries(self._settings, newSettings) else: self._settings.update(newSettings) ## source specific update methods def updateSettingsFromPySrcStr(self, theString, merge=True): """Update the settings from a code in a Python src string.""" newSettings = self.readSettingsFromPySrcStr(theString) self.updateSettings(newSettings, merge=newSettings.get('mergeSettings', merge) ) def updateSettingsFromConfigFileObj(self, inFile, convert=True, merge=True): """See the docstring for .updateSettingsFromConfigFile() The caller of this method is responsible for closing the inFile file object.""" newSettings = self.readSettingsFromConfigFileObj(inFile, convert=convert) self.updateSettings(newSettings, merge=newSettings.get('mergeSettings', merge)) def updateSettingsFromConfigStr(self, configStr, convert=True, merge=True): """See the docstring for .updateSettingsFromConfigFile() """ configStr = '[globals]\n' + configStr inFile = StringIO(configStr) newSettings = self.readSettingsFromConfigFileObj(inFile, convert=convert) self.updateSettings(newSettings, merge=newSettings.get('mergeSettings', merge)) Cheetah-2.4.4/cheetah/Utils/0000755000175000001440000000000011501314001014623 5ustar tylerusersCheetah-2.4.4/cheetah/Utils/WebInputMixin.py0000644000175000001440000000743511413255133017764 0ustar tylerusers# $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 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 " __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 Cheetah-2.4.4/cheetah/Utils/statprof.py0000644000175000001440000002365011413255133017061 0ustar tylerusers## statprof.py ## Copyright (C) 2004,2005 Andy Wingo ## Copyright (C) 2001 Rob Browning ## This library is free software; you can redistribute it and/or ## modify it under the terms of the GNU Lesser General Public ## License as published by the Free Software Foundation; either ## version 2.1 of the License, or (at your option) any later version. ## ## This library is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## Lesser General Public License for more details. ## ## You should have received a copy of the GNU Lesser General Public ## License along with this program; if not, contact: ## ## Free Software Foundation Voice: +1-617-542-5942 ## 59 Temple Place - Suite 330 Fax: +1-617-542-2652 ## Boston, MA 02111-1307, USA gnu@gnu.org """ statprof is intended to be a fairly simple statistical profiler for python. It was ported directly from a statistical profiler for guile, also named statprof, available from guile-lib [0]. [0] http://wingolog.org/software/guile-lib/statprof/ To start profiling, call statprof.start(): >>> start() Then run whatever it is that you want to profile, for example: >>> import test.pystone; test.pystone.pystones() Then stop the profiling and print out the results: >>> stop() >>> display() % cumulative self time seconds seconds name 26.72 1.40 0.37 pystone.py:79:Proc0 13.79 0.56 0.19 pystone.py:133:Proc1 13.79 0.19 0.19 pystone.py:208:Proc8 10.34 0.16 0.14 pystone.py:229:Func2 6.90 0.10 0.10 pystone.py:45:__init__ 4.31 0.16 0.06 pystone.py:53:copy ... All of the numerical data with the exception of the calls column is statistically approximate. In the following column descriptions, and in all of statprof, "time" refers to execution time (both user and system), not wall clock time. % time The percent of the time spent inside the procedure itself (not counting children). cumulative seconds The total number of seconds spent in the procedure, including children. self seconds The total number of seconds spent in the procedure itself (not counting children). name The name of the procedure. By default statprof keeps the data collected from previous runs. If you want to clear the collected data, call reset(): >>> reset() reset() can also be used to change the sampling frequency. For example, to tell statprof to sample 50 times a second: >>> reset(50) This means that statprof will sample the call stack after every 1/50 of a second of user + system time spent running on behalf of the python process. When your process is idle (for example, blocking in a read(), as is the case at the listener), the clock does not advance. For this reason statprof is not currently not suitable for profiling io-bound operations. The profiler uses the hash of the code object itself to identify the procedures, so it won't confuse different procedures with the same name. They will show up as two different rows in the output. Right now the profiler is quite simplistic. I cannot provide call-graphs or other higher level information. What you see in the table is pretty much all there is. Patches are welcome :-) Threading --------- Because signals only get delivered to the main thread in Python, statprof only profiles the main thread. However because the time reporting function uses per-process timers, the results can be significantly off if other threads' work patterns are not similar to the main thread's work patterns. Implementation notes -------------------- The profiler works by setting the unix profiling signal ITIMER_PROF to go off after the interval you define in the call to reset(). When the signal fires, a sampling routine is run which looks at the current procedure that's executing, and then crawls up the stack, and for each frame encountered, increments that frame's code object's sample count. Note that if a procedure is encountered multiple times on a given stack, it is only counted once. After the sampling is complete, the profiler resets profiling timer to fire again after the appropriate interval. Meanwhile, the profiler keeps track, via os.times(), how much CPU time (system and user -- which is also what ITIMER_PROF tracks), has elapsed while code has been executing within a start()/stop() block. The profiler also tries to avoid counting or timing its own code as much as possible. """ try: import itimer except ImportError: raise ImportError('''statprof requires the itimer python extension. To install it, enter the following commands from a terminal: wget http://www.cute.fi/~torppa/py-itimer/py-itimer.tar.gz tar zxvf py-itimer.tar.gz cd py-itimer sudo python setup.py install ''') import signal import os __all__ = ['start', 'stop', 'reset', 'display'] ########################################################################### ## Utils def clock(): times = os.times() return times[0] + times[1] ########################################################################### ## Collection data structures class ProfileState(object): def __init__(self, frequency=None): self.reset(frequency) def reset(self, frequency=None): # total so far self.accumulated_time = 0.0 # start_time when timer is active self.last_start_time = None # total count of sampler calls self.sample_count = 0 # a float if frequency: self.sample_interval = 1.0/frequency elif not hasattr(self, 'sample_interval'): # default to 100 Hz self.sample_interval = 1.0/100.0 else: # leave the frequency as it was pass self.remaining_prof_time = None # for user start/stop nesting self.profile_level = 0 # whether to catch apply-frame self.count_calls = False # gc time between start() and stop() self.gc_time_taken = 0 def accumulate_time(self, stop_time): self.accumulated_time += stop_time - self.last_start_time state = ProfileState() ## call_data := { code object: CallData } call_data = {} class CallData(object): def __init__(self, code): self.name = code.co_name self.filename = code.co_filename self.lineno = code.co_firstlineno self.call_count = 0 self.cum_sample_count = 0 self.self_sample_count = 0 call_data[code] = self def get_call_data(code): return call_data.get(code, None) or CallData(code) ########################################################################### ## SIGPROF handler def sample_stack_procs(frame): state.sample_count += 1 get_call_data(frame.f_code).self_sample_count += 1 code_seen = {} while frame: code_seen[frame.f_code] = True frame = frame.f_back for code in code_seen.iterkeys(): get_call_data(code).cum_sample_count += 1 def profile_signal_handler(signum, frame): if state.profile_level > 0: state.accumulate_time(clock()) sample_stack_procs(frame) itimer.setitimer(itimer.ITIMER_PROF, state.sample_interval, 0.0) state.last_start_time = clock() ########################################################################### ## Profiling API def is_active(): return state.profile_level > 0 def start(): state.profile_level += 1 if state.profile_level == 1: state.last_start_time = clock() rpt = state.remaining_prof_time state.remaining_prof_time = None signal.signal(signal.SIGPROF, profile_signal_handler) itimer.setitimer(itimer.ITIMER_PROF, rpt or state.sample_interval, 0.0) state.gc_time_taken = 0 # dunno def stop(): state.profile_level -= 1 if state.profile_level == 0: state.accumulate_time(clock()) state.last_start_time = None rpt = itimer.setitimer(itimer.ITIMER_PROF, 0.0, 0.0) signal.signal(signal.SIGPROF, signal.SIG_IGN) state.remaining_prof_time = rpt[0] state.gc_time_taken = 0 # dunno def reset(frequency=None): assert state.profile_level == 0, "Can't reset() while statprof is running" call_data.clear() state.reset(frequency) ########################################################################### ## Reporting API class CallStats(object): def __init__(self, call_data): self_samples = call_data.self_sample_count cum_samples = call_data.cum_sample_count nsamples = state.sample_count secs_per_sample = state.accumulated_time / nsamples basename = os.path.basename(call_data.filename) self.name = '%s:%d:%s' % (basename, call_data.lineno, call_data.name) self.pcnt_time_in_proc = self_samples / nsamples * 100 self.cum_secs_in_proc = cum_samples * secs_per_sample self.self_secs_in_proc = self_samples * secs_per_sample self.num_calls = None self.self_secs_per_call = None self.cum_secs_per_call = None def display(self): print('%6.2f %9.2f %9.2f %s' % (self.pcnt_time_in_proc, self.cum_secs_in_proc, self.self_secs_in_proc, self.name)) def display(): if state.sample_count == 0: print('No samples recorded.') return l = [CallStats(x) for x in call_data.itervalues()] l = [(x.self_secs_in_proc, x.cum_secs_in_proc, x) for x in l] l.sort(reverse=True) l = [x[2] for x in l] print('%5.5s %10.10s %7.7s %-8.8s' % ('% ', 'cumulative', 'self', '')) print('%5.5s %9.9s %8.8s %-8.8s' % ("time", "seconds", "seconds", "name")) for x in l: x.display() print('---') print('Sample count: %d' % state.sample_count) print('Total time: %f seconds' % state.accumulated_time) Cheetah-2.4.4/cheetah/Utils/Indenter.py0000644000175000001440000001006111413255133016757 0ustar tylerusers""" Indentation maker. @@TR: this code is unsupported and largely undocumented ... This version is based directly on code by Robert Kuzelj 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. """ import re import sys def indentize(source): return IndentProcessor().process(source) class IndentProcessor(object): """Preprocess #indent tags.""" LINE_SEP = '\n' ARGS = "args" INDENT_DIR = re.compile(r'[ \t]*#indent[ \t]*(?P.*)') DIRECTIVE = re.compile(r"[ \t]*#") WS = "ws" WHITESPACES = re.compile(r"(?P[ \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(object): """ A class that keeps track of the current indentation level. .indent() returns the appropriate amount of indentation. """ On = 1 Level = 0 Chars = ' ' 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 return " " * _default Cheetah-2.4.4/cheetah/Utils/htmlEncode.py0000644000175000001440000000077411413255133017303 0ustar tylerusers"""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 Cheetah-2.4.4/cheetah/Utils/__init__.py0000644000175000001440000000000211413255133016740 0ustar tylerusers# Cheetah-2.4.4/cheetah/Utils/Misc.py0000644000175000001440000000433011413255133016104 0ustar tylerusers#!/usr/bin/env python """ Miscellaneous functions/objects used by Cheetah but also useful standalone. """ import os # Used in mkdirsWithPyInitFile. 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 isinstance(thing, type) 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 Cheetah-2.4.4/cheetah/Utils/htmlDecode.py0000644000175000001440000000066511413255133017270 0ustar tylerusers"""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

. It is the inverse of htmlEncode().""" for code in codes: s = s.replace(code[1], code[0]) return s Cheetah-2.4.4/cheetah/ImportHooks.py0000755000175000001440000000761711413255133016405 0ustar tylerusers#!/usr/bin/env python """ 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() """ import sys import os.path import types import __builtin__ import imp from threading import RLock import string import traceback import types 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 = RLock() _acquireLock = _lock.acquire _releaseLock = _lock.release templateFileExtensions = ('.tmpl',) def getmod(self, name): self._acquireLock() try: 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 = types.ModuleType(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 isinstance(__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 isinstance(__builtin__.__import__, types.MethodType): __builtin__.__import__ = __oldimport__ global _manager del _manager if __name__ == '__main__': install() Cheetah-2.4.4/cheetah/Templates/0000755000175000001440000000000011501314001015461 5ustar tylerusersCheetah-2.4.4/cheetah/Templates/SkeletonPage.py0000644000175000001440000002357711413255133020446 0ustar tylerusers """A Skeleton HTML page template, that provides basic structure and utility methods. """ ################################################## ## DEPENDENCIES import sys import os import os.path from os.path import getmtime, exists import time import types import __builtin__ from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple from Cheetah.Template import Template from Cheetah.DummyTransaction import DummyTransaction from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList from Cheetah.CacheRegion import CacheRegion import Cheetah.Filters as Filters import Cheetah.ErrorCatchers as ErrorCatchers from Cheetah.Templates._SkeletonPage import _SkeletonPage ################################################## ## MODULE CONSTANTS try: True, False except NameError: True, False = (1==1), (1==0) VFFSL=valueFromFrameOrSearchList VFSL=valueFromSearchList VFN=valueForName currentTime=time.time __CHEETAH_version__ = '2.0rc6' __CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 6) __CHEETAH_genTime__ = 1139107954.3640411 __CHEETAH_genTimestamp__ = 'Sat Feb 4 18:52:34 2006' __CHEETAH_src__ = 'src/Templates/SkeletonPage.tmpl' __CHEETAH_srcLastModified__ = 'Mon Oct 7 11:37:30 2002' __CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine' if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple: raise AssertionError( 'This template was compiled with Cheetah version' ' %s. Templates compiled before version %s must be recompiled.'%( __CHEETAH_version__, RequiredCheetahVersion)) ################################################## ## CLASSES class SkeletonPage(_SkeletonPage): ################################################## ## CHEETAH GENERATED METHODS def __init__(self, *args, **KWs): _SkeletonPage.__init__(self, *args, **KWs) if not self._CHEETAH__instanceInitialized: cheetahKWArgs = {} allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split() for k, v in KWs.items(): if k in allowedKWs: cheetahKWArgs[k] = v self._initCheetahInstance(**cheetahKWArgs) def writeHeadTag(self, **KWS): ## CHEETAH: generated from #block writeHeadTag at line 22, col 1. trans = KWS.get("trans") if (not trans and not self._CHEETAH__isBuffering and not hasattr(self.transaction, '__call__')): trans = self.transaction # is None unless self.awake() was called if not trans: trans = DummyTransaction() _dummyTrans = True else: _dummyTrans = False write = trans.response().write SL = self._CHEETAH__searchList _filter = self._CHEETAH__currentFilter ######################################## ## START - generated method body write('\n') _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('\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\n') ######################################## ## END - generated method body return _dummyTrans and trans.response().getvalue() or "" def writeBody(self, **KWS): ## CHEETAH: generated from #block writeBody at line 36, col 1. trans = KWS.get("trans") if (not trans and not self._CHEETAH__isBuffering and not hasattr(self.transaction, '__call__')): trans = self.transaction # is None unless self.awake() was called if not trans: trans = DummyTransaction() _dummyTrans = True else: _dummyTrans = False write = trans.response().write SL = self._CHEETAH__searchList _filter = self._CHEETAH__currentFilter ######################################## ## START - generated method body write('This skeleton page has no flesh. Its body needs to be implemented.\n') ######################################## ## END - generated method body return _dummyTrans and trans.response().getvalue() or "" def respond(self, trans=None): ## CHEETAH: main method generated for this template if (not trans and not self._CHEETAH__isBuffering and not hasattr(self.transaction, '__call__')): trans = self.transaction # is None unless self.awake() was called if not trans: trans = DummyTransaction() _dummyTrans = True else: _dummyTrans = False write = trans.response().write SL = self._CHEETAH__searchList _filter = self._CHEETAH__currentFilter ######################################## ## START - generated method body ## START CACHE REGION: ID=header. line 6, col 1 in the source. _RECACHE_header = False _cacheRegion_header = self.getCacheRegion(regionID='header', cacheInfo={'type': 2, 'id': 'header'}) if _cacheRegion_header.isNew(): _RECACHE_header = True _cacheItem_header = _cacheRegion_header.getCacheItem('header') if _cacheItem_header.hasExpired(): _RECACHE_header = True if (not _RECACHE_header) and _cacheItem_header.getRefreshTime(): try: _output = _cacheItem_header.renderOutput() except KeyError: _RECACHE_header = True else: write(_output) del _output if _RECACHE_header or not _cacheItem_header.getRefreshTime(): _orig_transheader = trans trans = _cacheCollector_header = DummyTransaction() write = _cacheCollector_header.response().write _v = VFFSL(SL, "docType", True) # '$docType' on line 7, col 1 if _v is not None: write(_filter(_v, rawExpr='$docType')) # from line 7, col 1. write('\n') _v = VFFSL(SL, "htmlTag", True) # '$htmlTag' on line 8, col 1 if _v is not None: write(_filter(_v, rawExpr='$htmlTag')) # from line 8, col 1. write(''' ''') 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(''' ''') ######################################## ## 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() Cheetah-2.4.4/cheetah/Templates/__init__.py0000644000175000001440000000000111413255133017575 0ustar tylerusers Cheetah-2.4.4/cheetah/Templates/_SkeletonPage.py0000644000175000001440000002107011413255133020567 0ustar tylerusers# $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 , Version: $Revision: 1.13 $ Start Date: 2001/04/05 Last Revision Date: $Date: 2002/10/01 17:52:02 $ """ __author__ = "Tavis Rudd " __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 = '' title = '' siteDomainName = 'www.example.com' siteCredits = 'Designed & Implemented by Tavis Rudd' siteCopyrightName = "Tavis Rudd" htmlTag = '' 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 += '\n' if not self._stylesheetsOrder: return stylesheetTagsTxt stylesheetTagsTxt += '\n' return stylesheetTagsTxt def javascriptTags(self): """Return a formatted version of the javascriptTags and javascriptLibs dictionaries. Each value in javascriptTags should be a either a code string to include, or a list containing the JavaScript version number and the code string. The keys can be anything. The same applies for javascriptLibs, but the string should be the SRC filename rather than a code string.""" javascriptTagsTxt = [] for key, details in self._javascriptTags.iteritems(): if not isinstance(details, (list, tuple)): details = ['', details] javascriptTagsTxt += ['\n'] for key, details in self._javascriptLibs.iteritems(): if not isinstance(details, (list, tuple)): details = ['', details] javascriptTagsTxt += ['