Skip to content
This repository
Browse code

Merge commit 'origin/next' into slide-compat

Le sigh

Conflicts:
	cheetah/Version.py
  • Loading branch information...
commit 290f5e45c04f82034d700cf016d71e6256f1058e 2 parents 4490f68 + 9bc0b37
R. Tyler Croy authored

Showing 119 changed files with 2,162 additions and 5,434 deletions. Show diff stats Hide diff stats

  1. +1 1  BUGS
  2. +11 0 CHANGES
  3. +37 20 SetupConfig.py
  4. +2 18 SetupTools.py
  5. +1 1  TODO
  6. +2 2 bin/cheetah
  7. +2 4 bin/cheetah-compile
  8. 0  {src → cheetah}/CacheRegion.py
  9. 0  {src → cheetah}/CacheStore.py
  10. +23 2 {src → cheetah}/CheetahWrapper.py
  11. +45 40 {src → cheetah}/Compiler.py
  12. +16 0 cheetah/Django.py
  13. +0 1  {src → cheetah}/DummyTransaction.py
  14. +0 1  {src → cheetah}/ErrorCatchers.py
  15. +0 1  {src → cheetah}/FileUtils.py
  16. +15 23 {src → cheetah}/Filters.py
  17. +0 1  {src → cheetah}/ImportHooks.py
  18. +0 1  {src → cheetah}/ImportManager.py
  19. 0  {src → cheetah}/Macros/I18n.py
  20. 0  {src → cheetah}/Macros/__init__.py
  21. +5 1 {src → cheetah}/NameMapper.py
  22. +38 2 {src → cheetah}/Parser.py
  23. +5 6 {src → cheetah}/Servlet.py
  24. +3 31 {src → cheetah}/SettingsManager.py
  25. +0 1  {src → cheetah}/SourceReader.py
  26. +49 51 {src → cheetah}/Template.py
  27. +0 1  {src → cheetah}/TemplateCmdLineIface.py
  28. +0 1  {src → cheetah}/Templates/SkeletonPage.py
  29. 0  {src → cheetah}/Templates/SkeletonPage.tmpl
  30. +0 1  {src → cheetah}/Templates/_SkeletonPage.py
  31. +1 0  cheetah/Templates/__init__.py
  32. +46 51 {src → cheetah}/Tests/CheetahWrapper.py
  33. +39 0 cheetah/Tests/Cheps.py
  34. +4 1 {src → cheetah}/Tests/Filters.py
  35. +3 16 {src → cheetah}/Tests/NameMapper.py
  36. +106 0 {src → cheetah}/Tests/Regressions.py
  37. +2 11 {src → cheetah}/Tests/SyntaxAndOutput.py
  38. +18 33 {src → cheetah}/Tests/Template.py
  39. +2 4 {src → cheetah}/Tests/Test.py
  40. +23 2 {src → cheetah}/Tests/Unicode.py
  41. 0  {src → cheetah}/Tests/__init__.py
  42. 0  {src → cheetah}/Tests/unittest_local_copy.py
  43. 0  {src → cheetah}/Tests/xmlrunner.py
  44. +0 1  {src → cheetah}/Tools/CGITemplate.py
  45. +0 1  {src → cheetah}/Tools/MondoReport.py
  46. 0  {src → cheetah}/Tools/MondoReportDoc.txt
  47. +0 1  {src → cheetah}/Tools/RecursiveNull.py
  48. +0 1  {src → cheetah}/Tools/SiteHierarchy.py
  49. 0  {src → cheetah}/Tools/__init__.py
  50. 0  {src → cheetah}/Tools/turbocheetah/__init__.py
  51. 0  {src → cheetah}/Tools/turbocheetah/cheetahsupport.py
  52. 0  {src → cheetah}/Tools/turbocheetah/tests/__init__.py
  53. 0  {src → cheetah}/Tools/turbocheetah/tests/test_template.py
  54. 0  {src → cheetah}/Unspecified.py
  55. +12 24 {src → cheetah}/Utils/Indenter.py
  56. +0 1  {src → cheetah}/Utils/Misc.py
  57. +2 1  {src → cheetah}/Utils/VerifyType.py
  58. +0 1  {src → cheetah}/Utils/WebInputMixin.py
  59. 0  {src → cheetah}/Utils/__init__.py
  60. 0  {src → cheetah}/Utils/htmlDecode.py
  61. 0  {src → cheetah}/Utils/htmlEncode.py
  62. +0 1  {src → cheetah}/Utils/memcache.py
  63. 0  {src → cheetah}/Utils/statprof.py
  64. +2 2 {src → cheetah}/Version.py
  65. +0 2  {src → cheetah}/__init__.py
  66. +47 0 cheetah/c/Cheetah.h
  67. +93 0 cheetah/c/_filters.c
  68. +5 2 {src → cheetah/c}/_namemapper.c
  69. +52 0 cheetah/c/_template.c
  70. +107 0 cheetah/c/_verifytype.c
  71. 0  {src → cheetah}/convertTmplPathToModuleName.py
  72. +0 1  src/Templates/__init__.py
  73. +220 0 src/Tests/Performance.py
  74. +157 0 src/Tests/VerifyType.py
  75. 0  src/contrib/__init__.py
  76. +0 30 src/contrib/markdown/LICENSE
  77. +0 603 src/contrib/markdown/__init__.py
  78. +0 95 src/contrib/markdown/blockparser.py
  79. +0 460 src/contrib/markdown/blockprocessors.py
  80. +0 96 src/contrib/markdown/commandline.py
  81. +0 33 src/contrib/markdown/etree_loader.py
  82. 0  src/contrib/markdown/extensions/__init__.py
  83. +0 95 src/contrib/markdown/extensions/abbr.py
  84. +0 224 src/contrib/markdown/extensions/codehilite.py
  85. +0 104 src/contrib/markdown/extensions/def_list.py
  86. +0 49 src/contrib/markdown/extensions/extra.py
  87. +0 117 src/contrib/markdown/extensions/fenced_code.py
  88. +0 293 src/contrib/markdown/extensions/footnotes.py
  89. +0 195 src/contrib/markdown/extensions/headerid.py
  90. +0 62 src/contrib/markdown/extensions/html_tidy.py
  91. +0 119 src/contrib/markdown/extensions/imagelinks.py
  92. +0 468 src/contrib/markdown/extensions/legacy.py
  93. +0 90 src/contrib/markdown/extensions/meta.py
  94. +0 114 src/contrib/markdown/extensions/rss.py
  95. +0 97 src/contrib/markdown/extensions/tables.py
  96. +0 140 src/contrib/markdown/extensions/toc.py
  97. +0 155 src/contrib/markdown/extensions/wikilinks.py
  98. +0 274 src/contrib/markdown/html4.py
  99. +0 371 src/contrib/markdown/inlinepatterns.py
  100. +0 162 src/contrib/markdown/odict.py
  101. +0 77 src/contrib/markdown/postprocessors.py
  102. +0 214 src/contrib/markdown/preprocessors.py
  103. +0 329 src/contrib/markdown/treeprocessors.py
  104. +88 0 www/Makefile
  105. +17 0 www/chep.rst
  106. +26 0 www/cheps/1_chep.rst
  107. +122 0 www/cheps/2_import.rst
  108. +36 0 www/cheps/3_super.rst
  109. +197 0 www/conf.py
  110. +49 0 www/developers.rst
  111. +12 0 www/documentation.rst
  112. +19 0 www/download.rst
  113. +82 0 www/index.rst
  114. +112 0 www/make.bat
  115. +62 0 www/recipes/inheritance.rst
  116. +59 0 www/recipes/precompiled.rst
  117. +54 0 www/recipes/staticmethod.rst
  118. +4 0 www/recipes/writing_a_recipe.rst
  119. +27 0 www/roadmap.rst
2  BUGS
... ... @@ -1,2 +1,2 @@
1   -Please see http://bugs.communitycheetah.org
  1 +Please see http://bugs.cheetahtemplate.org
2 2
11 CHANGES
... ... @@ -1,4 +1,15 @@
1 1
  2 +2.2.2 (Unreleased)
  3 + - Prevent _namemapper.c from segfaulting when PyImport_ImportModule fails for some reason (Bogdano Arendartchuk <debogdano@gmail.com>)
  4 + - Removal of the contrib/markdown module (in favor of a setuptools dependency)
  5 + - Default setup.py to use setuptools by default, failing that, fall back to distutils
  6 +
  7 +2.2.1 (June 1st, 2009)
  8 + - 0000020: [Templates] Builtin support for using Cheetah with Django (rtyler)
  9 + - 0000021: [Compiler] @static and @classmethod don't properly define the _filter local (rtyler)
  10 + - 0000023: [Compiler] Update Template super calls to use super() (rtyler)
  11 + - Update all references to communitycheetah.org to point back at cheetahtemplate.org
  12 +
2 13 2.2.0 (May 17th, 2009)
3 14 - Switch all internal representations of template code to unicode objects instead of str() objects
4 15 - Convert unicode compiled template to an utf8 char buffer when writing to a file (Jean-Baptiste Quenot <jbq@caraldi.com>)
57 SetupConfig.py
... ... @@ -1,18 +1,16 @@
1 1 #-------Main Package Settings-----------#
2   -name = "Cheetah"
3   -from src.Version import Version as version
  2 +name = 'Cheetah'
  3 +from cheetah.Version import Version as version
4 4 maintainer = "R. Tyler Ballance"
5 5 author = "Tavis Rudd"
6 6 author_email = "cheetahtemplate-discuss@lists.sf.net"
7   -url = "http://www.communitycheetah.org/"
  7 +url = "http://www.cheetahtemplate.org/"
8 8 packages = ['Cheetah',
9 9 'Cheetah.Macros',
10 10 'Cheetah.Templates',
11 11 'Cheetah.Tests',
12 12 'Cheetah.Tools',
13 13 'Cheetah.Utils',
14   - 'Cheetah.contrib',
15   - 'Cheetah.contrib.markdown',
16 14 ]
17 15 classifiers = [line.strip() for line in '''\
18 16 #Development Status :: 4 - Beta
@@ -31,28 +29,47 @@
31 29 Topic :: Text Processing'''.splitlines() if not line.strip().startswith('#')]
32 30 del line
33 31
34   -package_dir = {'Cheetah':'src'}
  32 +package_dir = {'Cheetah':'cheetah'}
35 33
36 34 import os
37 35 import os.path
38 36 from distutils.core import Extension
39 37
40   -## we only assume the presence of a c compiler on Posix systems, NT people will
41   -# have to enable this manually.
42   -if os.name == 'posix':
43   - ext_modules=[Extension("Cheetah._namemapper", [os.path.join("src" ,"_namemapper.c")]
44   - )
45   - ]
46   -else:
47   - ext_modules=[]
48   -
  38 +ext_modules=[
  39 + Extension("Cheetah._namemapper",
  40 + [os.path.join('cheetah', 'c', '_namemapper.c')]),
  41 + Extension("Cheetah._verifytype",
  42 + [os.path.join('cheetah', 'c', '_verifytype.c')]),
  43 + Extension("Cheetah._filters",
  44 + [os.path.join('cheetah', 'c', '_filters.c')]),
  45 + Extension('Cheetah._template',
  46 + [os.path.join('cheetah', 'c', '_template.c')]),
  47 + ]
49 48
50 49 ## Data Files and Scripts
51 50 scripts = ['bin/cheetah-compile',
52 51 'bin/cheetah',
53 52 ]
54   -data_files = ['recursive: src *.tmpl *.txt LICENSE README TODO CHANGES',
55   - ]
  53 +
  54 +data_files = ['recursive: src *.tmpl *.txt LICENSE README TODO CHANGES',]
  55 +
  56 +if not os.getenv('CHEETAH_INSTALL_WITHOUT_SETUPTOOLS'):
  57 + try:
  58 + from setuptools import setup
  59 + install_requires = [
  60 + "Markdown >= 2.0.1",
  61 + ]
  62 + # use 'entry_points' instead of 'scripts'
  63 + del scripts
  64 + entry_points = {
  65 + 'console_scripts': [
  66 + 'cheetah = Cheetah.CheetahWrapper:_cheetah',
  67 + 'cheetah-compile = Cheetah.CheetahWrapper:_cheetah_compile',
  68 + ]
  69 + }
  70 + except ImportError:
  71 + print 'Not using setuptools, so we cannot install the Markdown dependency'
  72 +
56 73
57 74 description = "Cheetah is a template engine and code generation tool."
58 75
@@ -65,7 +82,7 @@
65 82 Documentation
66 83 ================================================================================
67 84 For a high-level introduction to Cheetah please refer to the User\'s Guide
68   -at http://www.communitycheetah.org/learn.html
  85 +at http://www.cheetahtemplate.org/learn.html
69 86
70 87 Mailing list
71 88 ================================================================================
@@ -74,10 +91,10 @@
74 91
75 92 Credits
76 93 ================================================================================
77   -http://www.communitycheetah.org/credits.html
  94 +http://www.cheetahtemplate.org/credits.html
78 95
79 96 Recent Changes
80 97 ================================================================================
81   -See http://www.communitycheetah.org/CHANGES.txt for full details
  98 +See http://www.cheetahtemplate.org/CHANGES.txt for full details
82 99
83 100 '''
20 SetupTools.py
... ... @@ -1,15 +1,4 @@
1 1 #!/usr/bin/env python
2   -# $Id: SetupTools.py,v 1.9 2007/11/03 19:44:38 tavis_rudd Exp $
3   -"""Some tools for extending and working with distutils
4   -
5   -CREDITS: This module borrows code and ideas from M.A. Lemburg's excellent setup
6   -tools for the mxBase package.
7   -
8   -"""
9   -
10   -__author__ = "Tavis Rudd <tavis@damnsimple.com>"
11   -__version__ = "$Revision: 1.9 $"[11:-2]
12   -
13 2 import os
14 3 from os import listdir
15 4 import os.path
@@ -20,13 +9,8 @@
20 9 import traceback
21 10
22 11 from distutils.core import setup
23   -if 'CHEETAH_USE_SETUPTOOLS' in os.environ:
24   - # @@TR: Please note that this is for testing purposes only! PEAK setuptools
25   - # is not required or recommended for installing Cheetah. Downstream
26   - # package managers (linux distros, etc.) should *not* enable this.
  12 +if not os.getenv('CHEETAH_INSTALL_WITHOUT_SETUPTOOLS'):
27 13 try:
28   - # use http://peak.telecommunity.com/DevCenter/setuptools if it's installed
29   - # requires Py >=2.3
30 14 from setuptools import setup
31 15 except ImportError:
32 16 from distutils.core import setup
@@ -35,7 +19,7 @@
35 19 from distutils.command.install_data import install_data
36 20
37 21 #imports from Cheetah ...
38   -from src.FileUtils import findFiles
  22 +from cheetah.FileUtils import findFiles
39 23
40 24 ##################################################
41 25 ## CLASSES ##
2  TODO
... ... @@ -1,4 +1,4 @@
1   -NOTE: Please see http://bugs.communitycheetah.org
  1 +NOTE: Please see http://bugs.cheetahtemplate.org
2 2 for future feature requests/bugs/TODO
3 3
4 4
4 bin/cheetah
... ... @@ -1,3 +1,3 @@
1 1 #!/usr/bin/env python
2   -from Cheetah.CheetahWrapper import CheetahWrapper
3   -CheetahWrapper().main()
  2 +from Cheetah.CheetahWrapper import _cheetah
  3 +_cheetah()
6 bin/cheetah-compile
... ... @@ -1,5 +1,3 @@
1 1 #!/usr/bin/env python
2   -import sys
3   -from Cheetah.CheetahWrapper import CheetahWrapper
4   -sys.argv.insert(1, "compile")
5   -CheetahWrapper().main()
  2 +from Cheetah.CheetahWrapper import _cheetah_compile
  3 +_cheetah_compile()
0  src/CacheRegion.py → cheetah/CacheRegion.py
File renamed without changes
0  src/CacheStore.py → cheetah/CacheStore.py
File renamed without changes
25 src/CheetahWrapper.py → cheetah/CheetahWrapper.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: CheetahWrapper.py,v 1.26 2007/10/02 01:22:04 tavis_rudd Exp $
3 2 """Cheetah command-line interface.
4 3
@@ -174,7 +173,19 @@ def parseOpts(self, args):
174 173 pao("--parallel", action="store", type="int", dest="parallel", default=1, help='Compile/fill templates in parallel, e.g. --parallel=4')
175 174 pao('--shbang', dest='shbang', default='#!/usr/bin/env python', help='Specify the shbang to place at the top of compiled templates, e.g. --shbang="#!/usr/bin/python2.6"')
176 175
177   - self.opts, self.pathArgs = opts, files = self.parser.parse_args(args)
  176 + opts, files = self.parser.parse_args(args)
  177 + self.opts = opts
  178 + if sys.platform == "win32":
  179 + new_files = []
  180 + for spec in files:
  181 + file_list = glob.glob(spec)
  182 + if file_list:
  183 + new_files.extend(file_list)
  184 + else:
  185 + new_files.append(spec)
  186 + files = new_files
  187 + self.pathArgs = files
  188 +
178 189 D("""\
179 190 cheetah compile %s
180 191 Options are
@@ -603,6 +614,16 @@ def _compileOrFillBundle(self, b):
603 614 f.close()
604 615
605 616
  617 +# Called when invoked as `cheetah`
  618 +def _cheetah():
  619 + CheetahWrapper().main()
  620 +
  621 +# Called when invoked as `cheetah-compile`
  622 +def _cheetah_compile():
  623 + sys.argv.insert(1, "compile")
  624 + CheetahWrapper().main()
  625 +
  626 +
606 627 ##################################################
607 628 ## if run from the command line
608 629 if __name__ == '__main__': CheetahWrapper().main()
85 src/Compiler.py → cheetah/Compiler.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 '''
3 2 Compiler classes for Cheetah:
4 3 ModuleCompiler aka 'Compiler'
@@ -106,7 +105,7 @@ class Error(Exception): pass
106 105
107 106
108 107
109   -class GenUtils:
  108 +class GenUtils(object):
110 109 """An abstract baseclass for the Compiler classes that provides methods that
111 110 perform generic utility functions or generate pieces of output code from
112 111 information passed in by the Parser baseclass. These methods don't do any
@@ -1077,8 +1076,11 @@ def _addAutoSetupCode(self):
1077 1076 self.addChunk('SL = self._CHEETAH__searchList')
1078 1077 else:
1079 1078 self.addChunk('SL = [KWS]')
1080   - if self.setting('useFilters') and not self.isClassMethod() and not self.isStaticMethod():
1081   - self.addChunk('_filter = self._CHEETAH__currentFilter')
  1079 + if self.setting('useFilters'):
  1080 + if self.isClassMethod() or self.isStaticMethod():
  1081 + self.addChunk('_filter = lambda x, **kwargs: unicode(x)')
  1082 + else:
  1083 + self.addChunk('_filter = self._CHEETAH__currentFilter')
1082 1084 self.addChunk('')
1083 1085 self.addChunk("#" *40)
1084 1086 self.addChunk('## START - generated method body')
@@ -1224,8 +1226,8 @@ def _setupInitMethod(self):
1224 1226 __init__ = self._spawnMethodCompiler('__init__',
1225 1227 klass=self.methodCompilerClassForInit)
1226 1228 __init__.setMethodSignature("def __init__(self, *args, **KWs)")
1227   - __init__.addChunk("%s.__init__(self, *args, **KWs)" % self._baseClass)
1228   - __init__.addChunk(_initMethod_initCheetah%{'className':self._className})
  1229 + __init__.addChunk('super(%s, self).__init__(*args, **KWs)' % self._className)
  1230 + __init__.addChunk(_initMethod_initCheetah % {'className' : self._className})
1229 1231 for chunk in self._initMethChunks:
1230 1232 __init__.addChunk(chunk)
1231 1233 __init__.cleanupState()
@@ -1508,7 +1510,7 @@ def __init__(self, source=None, file=None,
1508 1510 extraImportStatements=None, # list of strings
1509 1511 settings=None # dict
1510 1512 ):
1511   - SettingsManager.__init__(self)
  1513 + super(ModuleCompiler, self).__init__()
1512 1514 if settings:
1513 1515 self.updateSettings(settings)
1514 1516 # disable useStackFrames if the C version of NameMapper isn't compiled
@@ -1706,8 +1708,9 @@ def addImportedVarNames(self, varNames, raw_statement=None):
1706 1708 settings = self.settings()
1707 1709 if not varNames:
1708 1710 return
1709   - if self._methodBodyChunks and raw_statement and not settings.get('useLegacyImportMode'):
1710   - self.addChunk(raw_statement)
  1711 + if not settings.get('useLegacyImportMode'):
  1712 + if raw_statement and getattr(self, '_methodBodyChunks'):
  1713 + self.addChunk(raw_statement)
1711 1714 else:
1712 1715 self._importedVarNames.extend(varNames)
1713 1716
@@ -1736,38 +1739,40 @@ def setBaseClass(self, baseClassName):
1736 1739 # - We also assume that the final . separates the classname from the
1737 1740 # module name. This might break if people do something really fancy
1738 1741 # with their dots and namespaces.
1739   - chunks = baseClassName.split('.')
1740   - if len(chunks)==1:
1741   - self._getActiveClassCompiler().setBaseClass(baseClassName)
1742   - if baseClassName not in self.importedVarNames():
1743   - modName = baseClassName
1744   - # we assume the class name to be the module name
1745   - # and that it's not a builtin:
1746   - importStatement = "from %s import %s" % (modName, baseClassName)
1747   - self.addImportStatement(importStatement)
1748   - self.addImportedVarNames( [baseClassName,] )
1749   - else:
1750   - needToAddImport = True
1751   - modName = chunks[0]
1752   - #print chunks, ':', self.importedVarNames()
1753   - for chunk in chunks[1:-1]:
1754   - if modName in self.importedVarNames():
1755   - needToAddImport = False
1756   - finalBaseClassName = baseClassName.replace(modName+'.', '')
1757   - self._getActiveClassCompiler().setBaseClass(finalBaseClassName)
1758   - break
1759   - else:
1760   - modName += '.'+chunk
1761   - if needToAddImport:
1762   - modName, finalClassName = '.'.join(chunks[:-1]), chunks[-1]
1763   - #if finalClassName != chunks[:-1][-1]:
1764   - if finalClassName != chunks[-2]:
  1742 + baseclasses = baseClassName.split(',')
  1743 + for klass in baseclasses:
  1744 + chunks = klass.split('.')
  1745 + if len(chunks)==1:
  1746 + self._getActiveClassCompiler().setBaseClass(klass)
  1747 + if klass not in self.importedVarNames():
  1748 + modName = klass
1765 1749 # we assume the class name to be the module name
1766   - modName = '.'.join(chunks)
1767   - self._getActiveClassCompiler().setBaseClass(finalClassName)
1768   - importStatement = "from %s import %s" % (modName, finalClassName)
1769   - self.addImportStatement(importStatement)
1770   - self.addImportedVarNames( [finalClassName,] )
  1750 + # and that it's not a builtin:
  1751 + importStatement = "from %s import %s" % (modName, klass)
  1752 + self.addImportStatement(importStatement)
  1753 + self.addImportedVarNames((klass,))
  1754 + else:
  1755 + needToAddImport = True
  1756 + modName = chunks[0]
  1757 + #print chunks, ':', self.importedVarNames()
  1758 + for chunk in chunks[1:-1]:
  1759 + if modName in self.importedVarNames():
  1760 + needToAddImport = False
  1761 + finalBaseClassName = klass.replace(modName+'.', '')
  1762 + self._getActiveClassCompiler().setBaseClass(finalBaseClassName)
  1763 + break
  1764 + else:
  1765 + modName += '.'+chunk
  1766 + if needToAddImport:
  1767 + modName, finalClassName = '.'.join(chunks[:-1]), chunks[-1]
  1768 + #if finalClassName != chunks[:-1][-1]:
  1769 + if finalClassName != chunks[-2]:
  1770 + # we assume the class name to be the module name
  1771 + modName = '.'.join(chunks)
  1772 + self._getActiveClassCompiler().setBaseClass(finalClassName)
  1773 + importStatement = "from %s import %s" % (modName, finalClassName)
  1774 + self.addImportStatement(importStatement)
  1775 + self.addImportedVarNames( [finalClassName,] )
1771 1776
1772 1777 def setCompilerSetting(self, key, valueExpr):
1773 1778 self.setSetting(key, eval(valueExpr) )
16 cheetah/Django.py
... ... @@ -0,0 +1,16 @@
  1 +import Cheetah.Template
  2 +
  3 +def render(template_file, **kwargs):
  4 + '''
  5 + Cheetah.Django.render() takes the template filename
  6 + (the filename should be a file in your Django
  7 + TEMPLATE_DIRS)
  8 +
  9 + Any additional keyword arguments are passed into the
  10 + template are propogated into the template's searchList
  11 + '''
  12 + import django.http
  13 + import django.template.loader
  14 + source, loader = django.template.loader.find_template_source(template_file)
  15 + t = Cheetah.Template.Template(source, searchList=[kwargs])
  16 + return django.http.HttpResponse(t.__str__())
1  src/DummyTransaction.py → cheetah/DummyTransaction.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1
3 2 '''
4 3 Provides dummy Transaction and Response classes is used by Cheetah in place
1  src/ErrorCatchers.py → cheetah/ErrorCatchers.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: ErrorCatchers.py,v 1.7 2005/01/03 19:59:07 tavis_rudd Exp $
3 2 """ErrorCatcher class for Cheetah Templates
4 3
1  src/FileUtils.py → cheetah/FileUtils.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: FileUtils.py,v 1.12 2005/11/02 22:26:07 tavis_rudd Exp $
3 2 """File utitilies for Python:
4 3
38 src/Filters.py → cheetah/Filters.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 '''
3 2 Filters for the #filter directive as well as #transform
4 3
@@ -6,7 +5,6 @@
6 5 #transform results in a filter on the entirety of the output
7 6 '''
8 7 import sys
9   -import Cheetah.contrib
10 8
11 9 # Additional entities WebSafe knows how to transform. No need to include
12 10 # '<', '>' or '&' since those will have been done already.
@@ -24,30 +22,26 @@ def __init__(self, template=None):
24 22 """
25 23 self.template = template
26 24
27   - def filter(self, val,
28   - #encoding='utf8',
29   - encoding=None,
30   - str=str,
31   - **kw):
32   - """Pass Unicode strings through unmolested, unless an encoding is specified.
33   - """
  25 + def filter(self, val, encoding=None, str=str, **kw):
  26 + '''
  27 + Pass Unicode strings through unmolested, unless an encoding is specified.
  28 + '''
  29 + if val is None:
  30 + return u''
34 31 if isinstance(val, unicode):
35 32 if encoding:
36   - filtered = val.encode(encoding)
  33 + return val.encode(encoding)
37 34 else:
38   - filtered = val
39   - elif val is None:
40   - filtered = ''
  35 + return val
41 36 else:
42 37 try:
43   - filtered = str(val)
  38 + return str(val)
44 39 except UnicodeEncodeError:
45   - filtered = unicode(val)
46   - return filtered
  40 + return unicode(val)
  41 + return u''
47 42
48 43 RawOrEncodedUnicode = Filter
49 44
50   -
51 45 class EncodeUnicode(Filter):
52 46 def filter(self, val,
53 47 encoding='utf8',
@@ -90,11 +84,8 @@ class Markdown(EncodeUnicode):
90 84 def filter(self, value, **kwargs):
91 85 # This is a bit of a hack to allow outright embedding of the markdown module
92 86 try:
93   - markdown_path = '/'.join(Cheetah.contrib.__file__.split('/')[:-1])
94   - sys.path.append(markdown_path)
95   - from Cheetah.contrib import markdown
96   - sys.path.pop()
97   - except:
  87 + import markdown
  88 + except ImportError:
98 89 print '>>> Exception raised importing the "markdown" module'
99 90 print '>>> Are you sure you have the ElementTree module installed?'
100 91 print ' http://effbot.org/downloads/#elementtree'
@@ -236,6 +227,7 @@ def test():
236 227
237 228 print "Unicode:", `EncodeUnicode().filter(u'aoeu12345\u1234')`
238 229
239   -if __name__ == "__main__": test()
  230 +if __name__ == "__main__":
  231 + test()
240 232
241 233 # vim: shiftwidth=4 tabstop=4 expandtab
1  src/ImportHooks.py → cheetah/ImportHooks.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: ImportHooks.py,v 1.27 2007/11/16 18:28:47 tavis_rudd Exp $
3 2
4 3 """Provides some import hooks to allow Cheetah's .tmpl files to be imported
1  src/ImportManager.py → cheetah/ImportManager.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: ImportManager.py,v 1.6 2007/04/03 01:56:24 tavis_rudd Exp $
3 2
4 3 """Provides an emulator/replacement for Python's standard import system.
0  src/Macros/I18n.py → cheetah/Macros/I18n.py
File renamed without changes
0  src/Macros/__init__.py → cheetah/Macros/__init__.py
File renamed without changes
6 src/NameMapper.py → cheetah/NameMapper.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: NameMapper.py,v 1.32 2007/12/10 19:20:09 tavis_rudd Exp $
3 2
4 3 """This module supports Cheetah's optional NameMapper syntax.
@@ -160,6 +159,11 @@
160 159 'valueFromFrame',
161 160 ]
162 161
  162 +if not hasattr(inspect.imp, 'get_suffixes'):
  163 + # This is to fix broken behavior of the inspect module under the
  164 + # Google App Engine, see the following issue:
  165 + # http://bugs.communitycheetah.org/view.php?id=10
  166 + setattr(inspect.imp, 'get_suffixes', lambda: [('.py', 'U', 1)])
163 167
164 168 ## N.B. An attempt is made at the end of this module to import C versions of
165 169 ## these functions. If _namemapper.c has been compiled succesfully and the
40 src/Parser.py → cheetah/Parser.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: Parser.py,v 1.137 2008/03/10 05:25:13 tavis_rudd Exp $
3 2 """Parser classes for Cheetah's Compiler
4 3
@@ -597,6 +596,42 @@ def getMultiLineCommentEndToken(self):
597 596 if not match:
598 597 raise ParseError(self, msg='Invalid multi-line comment end token')
599 598 return self.readTo(match.end())
  599 +
  600 + def getCommaSeparatedSymbols(self):
  601 + """
  602 + Loosely based on getDottedName to pull out comma separated
  603 + named chunks
  604 + """
  605 + srcLen = len(self)
  606 + pieces = []
  607 + nameChunks = []
  608 +
  609 + if not self.peek() in identchars:
  610 + raise ParseError(self)
  611 +
  612 + while self.pos() < srcLen:
  613 + c = self.peek()
  614 + if c in namechars:
  615 + nameChunk = self.getIdentifier()
  616 + nameChunks.append(nameChunk)
  617 + elif c == '.':
  618 + if self.pos()+1 <srcLen and self.peek(1) in identchars:
  619 + nameChunks.append(self.getc())
  620 + else:
  621 + break
  622 + elif c == ',':
  623 + self.getc()
  624 + pieces.append(''.join(nameChunks))
  625 + nameChunks = []
  626 + elif c in (' ', '\t'):
  627 + self.getc()
  628 + else:
  629 + break
  630 +
  631 + if nameChunks:
  632 + pieces.append(''.join(nameChunks))
  633 +
  634 + return pieces
600 635
601 636 def getDottedName(self):
602 637 srcLen = len(self)
@@ -2038,7 +2073,8 @@ def eatExtends(self):
2038 2073 if self.setting('allowExpressionsInExtendsDirective'):
2039 2074 baseName = self.getExpression()
2040 2075 else:
2041   - baseName = self.getDottedName()
  2076 + baseName = self.getCommaSeparatedSymbols()
  2077 + baseName = ', '.join(baseName)
2042 2078
2043 2079 baseName = self._applyExpressionFilters(baseName, 'extends', startPos=startPos)
2044 2080 self._compiler.setBaseClass(baseName) # in compiler
11 src/Servlet.py → cheetah/Servlet.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 '''
3 2 Provides an abstract Servlet baseclass for Cheetah's Template class
4 3 '''
@@ -49,8 +48,8 @@ class Servlet(BaseServlet):
49 48 request = None
50 49 session = None
51 50
52   - def __init__(self):
53   - super(Servlet, self).__init__()
  51 + def __init__(self, *args, **kwargs):
  52 + super(Servlet, self).__init__(*args, **kwargs)
54 53
55 54 # this default will be changed by the .awake() method
56 55 self._CHEETAH__isControlledByWebKit = False
@@ -58,7 +57,7 @@ def __init__(self):
58 57 ## methods called by Webware during the request-response
59 58
60 59 def awake(self, transaction):
61   - BaseServlet.awake(self, transaction)
  60 + super(Servlet, self).awake(transaction)
62 61
63 62 # a hack to signify that the servlet is being run directly from WebKit
64 63 self._CHEETAH__isControlledByWebKit = True
@@ -86,7 +85,7 @@ def respond(self, trans=None):
86 85 definition.""")
87 86
88 87 def sleep(self, transaction):
89   - BaseServlet.sleep(self, transaction)
  88 + super(Servlet, self).sleep(transaction)
90 89 self.session = None
91 90 self.request = None
92 91 self._request = None
@@ -102,7 +101,7 @@ def serverSidePath(self, path=None,
102 101 ):
103 102
104 103 if self._CHEETAH__isControlledByWebKit:
105   - return BaseServlet.serverSidePath(self, path)
  104 + return super(Servlet, self).serverSidePath(path)
106 105 elif path:
107 106 return normpath(abspath(path.replace("\\",'/')))
108 107 elif hasattr(self, '_filePath') and self._filePath:
34 src/SettingsManager.py → cheetah/SettingsManager.py
... ... @@ -1,17 +1,3 @@
1   -"""Provides a mixin/base class for collecting and managing application settings
2   -
3   -Meta-Data
4   -==========
5   -Author: Tavis Rudd <tavis@damnsimple.com>
6   -Version: $Revision: 1.30 $
7   -Start Date: 2001/05/30
8   -Last Revision Date: $Date: 2008/02/14 03:03:16 $
9   -"""
10   -
11   -# $Id: SettingsManager.py,v 1.30 2008/02/14 03:03:16 tavis_rudd Exp $
12   -__author__ = "Tavis Rudd <tavis@damnsimple.com>"
13   -__revision__ = "$Revision: 1.30 $"[11:-2]
14   -
15 1 import sys
16 2 import os.path
17 3 import copy as copyModule
@@ -25,13 +11,6 @@
25 11 from StringIO import StringIO # not cStringIO because of unicode support
26 12 import imp # used by SettingsManager.updateSettingsFromPySrcFile()
27 13
28   -##################################################
29   -## CONSTANTS & GLOBALS ##
30   -
31   -try:
32   - True,False
33   -except NameError:
34   - True, False = (1==1),(1==0)
35 14
36 15 numberRE = re.compile(Number)
37 16 complexNumberRE = re.compile('[\(]*' +Number + r'[ \t]*\+[ \t]*' + Number + '[\)]*')
@@ -89,13 +68,10 @@ def convStringToNum(theString):
89 68 return eval(theString, {}, {})
90 69
91 70
92   -##################################################
93   -## CLASSES ##
94   -
95 71 class Error(Exception):
96 72 pass
97 73
98   -class NoDefault:
  74 +class NoDefault(object):
99 75 pass
100 76
101 77 class ConfigParserCaseSensitive(ConfigParser):
@@ -105,7 +81,7 @@ def optionxform(self, optionstr):
105 81 """Don't change the case as is done in the default implemenation."""
106 82 return optionstr
107 83
108   -class _SettingsCollector:
  84 +class _SettingsCollector(object):
109 85 """An abstract base class that provides the methods SettingsManager uses to
110 86 collect settings from config files and strings.
111 87
@@ -115,9 +91,6 @@ class _SettingsCollector:
115 91
116 92 _ConfigParserClass = ConfigParserCaseSensitive
117 93
118   - def __init__(self):
119   - pass
120   -
121 94 def readSettingsFromModule(self, mod, ignoreUnderscored=True):
122 95 """Returns all settings from a Python module.
123 96 """
@@ -230,8 +203,7 @@ class SettingsManager(_SettingsCollector):
230 203 """
231 204
232 205 def __init__(self):
233   - """MUST BE CALLED BY SUBCLASSES"""
234   - _SettingsCollector.__init__(self)
  206 + super(SettingsManager, self).__init__()
235 207 self._settings = {}
236 208 self._initializeSettings()
237 209
1  src/SourceReader.py → cheetah/SourceReader.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: SourceReader.py,v 1.15 2007/04/03 01:57:42 tavis_rudd Exp $
3 2 """SourceReader class for Cheetah's Parser and CodeGenerator
4 3
100 src/Template.py → cheetah/Template.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 '''
3 2 Provides the core API for Cheetah.
4 3
@@ -26,11 +25,6 @@
26 25 from types import StringTypes
27 26 except ImportError:
28 27 StringTypes = (types.StringType,types.UnicodeType)
29   -try:
30   - from types import BooleanType
31   - boolTypeAvailable = True
32   -except ImportError:
33   - boolTypeAvailable = False
34 28
35 29 try:
36 30 from threading import Lock
@@ -57,7 +51,14 @@ def release(self):
57 51 from Cheetah import ErrorCatchers # for placeholder tags
58 52 from Cheetah import Filters # the output filters
59 53 from Cheetah.convertTmplPathToModuleName import convertTmplPathToModuleName
60   -from Cheetah.Utils import VerifyType # Used in Template.__init__
  54 +
  55 +try:
  56 + from Cheetah._verifytype import *
  57 +except ImportError:
  58 + from Cheetah.Utils import VerifyType
  59 + verifyType = VerifyType.VerifyType
  60 + verifyTypeClass = VerifyType.VerifyTypeClass
  61 +
61 62 from Cheetah.Utils.Misc import checkKeywords # Used in Template.__init__
62 63 from Cheetah.Utils.Indenter import Indenter # Used in Template.__init__ and for
63 64 # placeholders
@@ -118,11 +119,14 @@ def _genUniqueModuleName(baseModuleName):
118 119 # This is only relavent to templates used as CGI scripts.
119 120 _formUsedByWebInput = None
120 121
121   -# used in Template.compile()
122   -def valOrDefault(val, default):
123   - if val is not Unspecified:
124   - return val
125   - return default
  122 +try:
  123 + from Cheetah._template import valOrDefault
  124 +except ImportError:
  125 + # used in Template.compile()
  126 + def valOrDefault(val, default):
  127 + if val is not Unspecified:
  128 + return val
  129 + return default
126 130
127 131 def updateLinecache(filename, src):
128 132 import linecache
@@ -593,46 +597,43 @@ def __str__(self): return self.respond()
593 597 ##################################################
594 598 ## normalize and validate args
595 599 try:
596   - vt = VerifyType.VerifyType
597   - vtc = VerifyType.VerifyTypeClass
  600 + vt = verifyType
  601 + vtc = verifyTypeClass
598 602 N = types.NoneType; S = types.StringType; U = types.UnicodeType
599 603 D = types.DictType; F = types.FileType
600 604 C = types.ClassType; M = types.ModuleType
601   - I = types.IntType
  605 + I = types.IntType; B = types.BooleanType
602 606
603   - if boolTypeAvailable:
604   - B = types.BooleanType
605   -
606   - vt(source, 'source', [N,S,U], 'string or None')
607   - vt(file, 'file',[N,S,U,F], 'string, file-like object, or None')
  607 + IB = (I, B)
  608 + NS = (N, S)
  609 +
  610 + vt(source, 'source', (N,S,U), 'string or None')
  611 + vt(file, 'file',(N,S,U,F), 'string, file-like object, or None')
608 612
609 613 baseclass = valOrDefault(baseclass, klass._CHEETAH_defaultBaseclassForTemplates)
610 614 if isinstance(baseclass, Template):
611 615 baseclass = baseclass.__class__
612   - vt(baseclass, 'baseclass', [N,S,C,type], 'string, class or None')
  616 + vt(baseclass, 'baseclass', (N,S,C,type), 'string, class or None')
613 617
614 618 cacheCompilationResults = valOrDefault(
615 619 cacheCompilationResults, klass._CHEETAH_cacheCompilationResults)
616   - if boolTypeAvailable:
617   - vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
  620 + vt(cacheCompilationResults, 'cacheCompilationResults', IB, 'boolean')
618 621
619 622 useCache = valOrDefault(useCache, klass._CHEETAH_useCompilationCache)
620   - if boolTypeAvailable:
621   - vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
  623 + vt(useCache, 'useCache', IB, 'boolean')
622 624
623 625 compilerSettings = valOrDefault(
624 626 compilerSettings, klass._getCompilerSettings(source, file) or {})
625   - vt(compilerSettings, 'compilerSettings', [D], 'dictionary')
  627 + vt(compilerSettings, 'compilerSettings', (D,), 'dictionary')
626 628
627 629 compilerClass = valOrDefault(compilerClass, klass._getCompilerClass(source, file))
628 630 preprocessors = valOrDefault(preprocessors, klass._CHEETAH_preprocessors)
629 631
630 632 keepRefToGeneratedCode = valOrDefault(
631 633 keepRefToGeneratedCode, klass._CHEETAH_keepRefToGeneratedCode)
632   - if boolTypeAvailable:
633   - vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
634   -
635   - vt(moduleName, 'moduleName', [N,S], 'string or None')
  634 + vt(keepRefToGeneratedCode, 'keepRefToGeneratedCode', IB, 'boolean')
  635 +
  636 + vt(moduleName, 'moduleName', NS, 'string or None')
636 637 __orig_file__ = None
637 638 if not moduleName:
638 639 if file and type(file) in StringTypes:
@@ -640,27 +641,26 @@ def __str__(self): return self.respond()
640 641 __orig_file__ = file
641 642 else:
642 643 moduleName = klass._CHEETAH_defaultModuleNameForTemplates
643   -
  644 +
644 645 className = valOrDefault(
645 646 className, klass._CHEETAH_defaultClassNameForTemplates)
646   - vt(className, 'className', [N,S], 'string or None')
  647 + vt(className, 'className', NS, 'string or None')
647 648 className = className or moduleName
648 649
649 650 mainMethodName = valOrDefault(
650 651 mainMethodName, klass._CHEETAH_defaultMainMethodNameForTemplates)
651   - vt(mainMethodName, 'mainMethodName', [N,S], 'string or None')
  652 + vt(mainMethodName, 'mainMethodName', NS, 'string or None')
652 653
653 654 moduleGlobals = valOrDefault(
654 655 moduleGlobals, klass._CHEETAH_defaultModuleGlobalsForTemplates)
655 656
656 657 cacheModuleFilesForTracebacks = valOrDefault(
657 658 cacheModuleFilesForTracebacks, klass._CHEETAH_cacheModuleFilesForTracebacks)
658   - if boolTypeAvailable:
659   - vt(cacheModuleFilesForTracebacks, 'cacheModuleFilesForTracebacks', [I,B], 'boolean')
660   -
  659 + vt(cacheModuleFilesForTracebacks, 'cacheModuleFilesForTracebacks', IB, 'boolean')
  660 +
661 661 cacheDirForModuleFiles = valOrDefault(
662 662 cacheDirForModuleFiles, klass._CHEETAH_cacheDirForModuleFiles)
663   - vt(cacheDirForModuleFiles, 'cacheDirForModuleFiles', [N,S], 'string or None')
  663 + vt(cacheDirForModuleFiles, 'cacheDirForModuleFiles', NS, 'string or None')
664 664
665 665 except TypeError, reason:
666 666 raise TypeError(reason)
@@ -1145,26 +1145,24 @@ def __init__(self, source=None,
1145 1145 D = types.DictType; F = types.FileType
1146 1146 C = types.ClassType; M = types.ModuleType
1147 1147 N = types.NoneType
1148   - vt = VerifyType.VerifyType
1149   - vtc = VerifyType.VerifyTypeClass
  1148 + vt = verifyType
  1149 + vtc = verifyTypeClass
1150 1150 try:
1151   - vt(source, 'source', [N,S,U], 'string or None')
1152   - vt(file, 'file', [N,S,U,F], 'string, file open for reading, or None')
1153   - vtc(filter, 'filter', [S,C,type], 'string or class',
  1151 + vt(source, 'source', (N,S,U), 'string or None')
  1152 + vt(file, 'file', (N,S,U,F), 'string, file open for reading, or None')
  1153 + vtc(filter, 'filter', (S,C,type), 'string or class',
1154 1154 Filters.Filter,
1155 1155 '(if class, must be subclass of Cheetah.Filters.Filter)')
1156   - vt(filtersLib, 'filtersLib', [S,M], 'string or module',
  1156 + vt(filtersLib, 'filtersLib', (S,M), 'string or module',
1157 1157 '(if module, must contain subclasses of Cheetah.Filters.Filter)')
1158   - vtc(errorCatcher, 'errorCatcher', [N,S,C,type], 'string, class or None',
  1158 + vtc(errorCatcher, 'errorCatcher', (N,S,C,type), 'string, class or None',
1159 1159 ErrorCatchers.ErrorCatcher,
1160 1160 '(if class, must be subclass of Cheetah.ErrorCatchers.ErrorCatcher)')
1161 1161 if compilerSettings is not Unspecified:
1162   - vt(compilerSettings, 'compilerSettings', [D], 'dictionary')
  1162 + vt(compilerSettings, 'compilerSettings', (D,), 'dictionary')
1163 1163
1164   - except TypeError, reason:
1165   - # Re-raise the exception here so that the traceback will end in
1166   - # this function rather than in some utility function.
1167   - raise TypeError(reason)
  1164 + except TypeError:
  1165 + raise
1168 1166
1169 1167 if source is not None and file is not None:
1170 1168 raise TypeError("you must supply either a source string or the" +
@@ -1465,7 +1463,7 @@ def _initCheetahInstance(self,
1465 1463 # @@TR: consider allowing simple callables as the filter argument
1466 1464 self._CHEETAH__filtersLib = filtersLib
1467 1465 self._CHEETAH__filters = {}
1468   - if type(filter) in StringTypes:
  1466 + if isinstance(filter, basestring):
1469 1467 filterName = filter
1470 1468 klass = getattr(self._CHEETAH__filtersLib, filterName)
1471 1469 else:
@@ -1476,7 +1474,7 @@ def _initCheetahInstance(self,
1476 1474
1477 1475 self._CHEETAH__errorCatchers = {}
1478 1476 if errorCatcher:
1479   - if type(errorCatcher) in StringTypes:
  1477 + if isinstance(errorCatcher, basestring):
1480 1478 errorCatcherClass = getattr(ErrorCatchers, errorCatcher)
1481 1479 elif type(errorCatcher) == ClassType:
1482 1480 errorCatcherClass = errorCatcher
1  src/TemplateCmdLineIface.py → cheetah/TemplateCmdLineIface.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: TemplateCmdLineIface.py,v 1.13 2006/01/10 20:34:35 tavis_rudd Exp $
3 2
4 3 """Provides a command line interface to compiled Cheetah template modules.
1  src/Templates/SkeletonPage.py → cheetah/Templates/SkeletonPage.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1
3 2
4 3 """A Skeleton HTML page template, that provides basic structure and utility methods.
0  src/Templates/SkeletonPage.tmpl → cheetah/Templates/SkeletonPage.tmpl
File renamed without changes
1  src/Templates/_SkeletonPage.py → cheetah/Templates/_SkeletonPage.py
... ... @@ -1,4 +1,3 @@
1   -#!/usr/bin/env python
2 1 # $Id: _SkeletonPage.py,v 1.13 2002/10/01 17:52:02 tavis_rudd Exp $
3 2 """A baseclass for the SkeletonPage template
4 3
1  cheetah/Templates/__init__.py
... ... @@ -0,0 +1 @@
  1 +
97 src/Tests/CheetahWrapper.py → cheetah/Tests/CheetahWrapper.py
@@ -11,10 +11,14 @@
11 11 --output
12 12 Show the output of each subcommand. (Normally suppressed.)
13 13 '''
14   -import commands, os, shutil, sys, tempfile
15   -import unittest_local_copy as unittest
16   -
  14 +import os
  15 +import popen2
17 16 import re # Used by listTests.
  17 +import shutil
  18 +import sys
  19 +import tempfile
  20 +import unittest
  21 +
18 22 from optparse import OptionParser
19 23 from Cheetah.CheetahWrapper import CheetahWrapper # Used by NoBackup.
20 24
@@ -137,6 +141,38 @@ def checkNoBackup(self, path):
137 141 msg = "backup file exists in spite of --nobackup: %s" % path
138 142 self.failIf(exists, msg)
139 143
  144 +
  145 + def assertWin32Subprocess(self, cmd):
  146 + _in, _out = os.popen4(cmd)
  147 + _in.close()
  148 + output = _out.read()
  149 + rc = _out.close()
  150 + if rc is None:
  151 + rc = 0
  152 + return rc, output
  153 +
  154 + def assertPosixSubprocess(self, cmd):
  155 + process = popen2.Popen4(cmd)
  156 + process.tochild.close()
  157 + output = process.fromchild.read()
  158 + status = process.wait()
  159 + process.fromchild.close()
  160 + return status, output
  161 +
  162 + def assertSubprocess(self, cmd, nonzero=False):
  163 + status, output = None, None
  164 + if sys.platform == 'win32':
  165 + status, output = self.assertWin32Subprocess(cmd)
  166 + else:
  167 + status, output = self.assertPosixSubprocess(cmd)
  168 +
  169 + if not nonzero:
  170 + self.failUnlessEqual(status, 0, '''Subprocess exited with a non-zero status (%d)
  171 + %s''' % (status, output))
  172 + else:
  173 + self.failIfEqual(status, 0, '''Subprocess exited with a zero status (%d)
  174 + %s''' % (status, output))
  175 + return output
140 176
141 177 def go(self, cmd, expectedStatus=0, expectedOutputSubstring=None):
142 178 """Run a "cheetah compile" or "cheetah fill" subcommand.
@@ -149,24 +185,7 @@ def go(self, cmd, expectedStatus=0, expectedOutputSubstring=None):
149 185 test.
150 186 out: None.
151 187 """
152   - # Use commands.getstatusoutput instead of os.system so
153   - # that we can mimic ">/dev/null 2>/dev/null" even on
154   - # non-Unix platforms.
155   - exit, output = commands.getstatusoutput(cmd)
156   - status, signal = divmod(exit, 256)
157   - if OUTPUT:
158   - if output.endswith("\n"):
159   - output = output[:-1]
160   - print
161   - print "SUBCOMMAND:", cmd
162   - print output
163   - print
164   - msg = "subcommand killed by signal %d: %s" % (signal, cmd)
165   - self.failUnlessEqual(signal, 0, msg)
166   - msg = "subcommand exit status %d: %s" % (status, cmd)
167   - if status!=expectedStatus:
168   - print output
169   - self.failUnlessEqual(status, expectedStatus, msg)
  188 + output = self.assertSubprocess(cmd)
170 189 if expectedOutputSubstring is not None:
171 190 msg = "substring %r not found in subcommand output: %s" % \
172 191 (expectedOutputSubstring, cmd)
@@ -174,30 +193,6 @@ def go(self, cmd, expectedStatus=0, expectedOutputSubstring=None):
174 193 self.failUnless(substringTest, msg)
175 194
176 195
177   - def goExpectError(self, cmd):
178   - """Run a subcommand and expect it to fail.
179   -
180   - in : cmd, string, the command to run.
181   - out: None.
182   - """
183   - # Use commands.getstatusoutput instead of os.system so
184   - # that we can mimic ">/dev/null 2>/dev/null" even on
185   - # non-Unix platforms.
186   - exit, output = commands.getstatusoutput(cmd)
187   - status, signal = divmod(exit, 256)
188   - msg = "subcommand killed by signal %s: %s" % (signal, cmd)
189   - self.failUnlessEqual(signal, 0, msg) # Signal must be 0.
190   - msg = "subcommand exit status %s: %s" % (status, cmd)
191   - self.failIfEqual(status, 0, msg) # Status must *not* be 0.
192   - if OUTPUT:
193   - if output.endswith("\n"):
194   - output = output[:-1]
195   - print
196   - print "SUBCOMMAND:", cmd
197   - print output
198   - print
199   -
200   -
201 196 class CFIdirBase(CFBase):
202 197 """Subclass for tests with --idir.
203 198 """
@@ -422,13 +417,13 @@ class FlatRecurseCollision(CFBase):
422 417 expectError = True
423 418
424 419 def testCompile(self):
425   - self.goExpectError("cheetah compile -R --flat")
  420 + self.assertSubprocess("cheetah compile -R --flat", nonzero=True)
426 421
427 422 def testFill(self):
428   - self.goExpectError("cheetah fill -R --flat")
  423 + self.assertSubprocess("cheetah fill -R --flat", nonzero=True)
429 424
430 425 def testText(self):
431   - self.goExpectError("cheetah fill -R --flat")
  426 + self.assertSubprocess("cheetah fill -R --flat", nonzero=True)
432 427
433 428
434 429 class IdirRecurse(CFIdirBase):
@@ -473,13 +468,13 @@ class IdirFlatRecurseCollision(CFIdirBase):
473 468 expectError = True
474 469
475 470 def testCompile(self):
476   - self.goExpectError("cheetah compile -R --flat --idir SRC")
  471 + self.assertSubprocess("cheetah compile -R --flat --idir SRC", nonzero=True)
477 472
478 473 def testFill(self):
479   - self.goExpectError("cheetah fill -R --flat --idir SRC")
  474 + self.assertSubprocess("cheetah fill -R --flat --idir SRC", nonzero=True)
480 475
481 476 def testText(self):
482   - self.goExpectError("cheetah fill -R --flat --idir SRC --oext txt")
  477 + self.assertSubprocess("cheetah fill -R --flat --idir SRC --oext txt", nonzero=True)
483 478
484 479
485 480 class NoBackup(CFBase):
39 cheetah/Tests/Cheps.py
... ... @@ -0,0 +1,39 @@
  1 +#!/usr/bin/env python
  2 +
  3 +import unittest
  4 +
  5 +import Cheetah
  6 +import Cheetah.Parser
  7 +import Cheetah.Template
  8 +
  9 +class Chep_2_Conditionalized_Import_Behavior(unittest.TestCase):
  10 + def test_ModuleLevelImport(self):