Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'next'

  • Loading branch information...
commit a753724d68880488a27141d1e4f174880d39e154 2 parents 7b1c2ad + ffa377c
@rtyler rtyler authored
Showing with 9,798 additions and 2,139 deletions.
  1. +9 −0 CHANGES
  2. +4 −3 SetupConfig.py
  3. +9 −15 SetupTools.py
  4. +6 −0 bin/cheetah-analyze
  5. +66 −0 buildandrun
  6. +1 −1  cheetah/CacheRegion.py
  7. +2 −2 cheetah/CacheStore.py
  8. +9 −10 cheetah/CheetahWrapper.py
  9. +64 −78 cheetah/Compiler.py
  10. +98 −0 cheetah/DirectiveAnalyzer.py
  11. +1 −1  cheetah/DummyTransaction.py
  12. +19 −35 cheetah/FileUtils.py
  13. +15 −15 cheetah/Filters.py
  14. +2 −2 cheetah/ImportHooks.py
  15. +15 −39 cheetah/ImportManager.py
  16. +12 −12 cheetah/NameMapper.py
  17. +118 −119 cheetah/Parser.py
  18. +1 −1  cheetah/Servlet.py
  19. +11 −13 cheetah/SettingsManager.py
  20. +3 −16 cheetah/SourceReader.py
  21. +42 −39 cheetah/Template.py
  22. +7 −7 cheetah/TemplateCmdLineIface.py
  23. +15 −15 cheetah/Templates/SkeletonPage.py
  24. +16 −16 cheetah/Templates/_SkeletonPage.py
  25. +29 −0 cheetah/Tests/Analyzer.py
  26. +25 −8 cheetah/Tests/CheetahWrapper.py
  27. +5 −3 cheetah/Tests/Filters.py
  28. +20 −0 cheetah/Tests/Misc.py
  29. +36 −36 cheetah/Tests/NameMapper.py
  30. +49 −0 cheetah/Tests/Parser.py
  31. +8 −8 cheetah/Tests/Performance.py
  32. +1 −1  cheetah/Tests/Regressions.py
  33. +59 −37 cheetah/Tests/SyntaxAndOutput.py
  34. +6 −6 cheetah/Tests/Template.py
  35. +14 −8 cheetah/Tests/Test.py
  36. +40 −1 cheetah/Tests/Unicode.py
  37. +0 −158 cheetah/Tests/VerifyType.py
  38. +0 −978 cheetah/Tests/unittest_local_copy.py
  39. +2 −2 cheetah/Tests/xmlrunner.py
  40. +1 −1  cheetah/Tools/CGITemplate.py
  41. +13 −12 cheetah/Tools/MondoReport.py
  42. +136 −152 cheetah/Tools/SiteHierarchy.py
  43. +4 −4 cheetah/Tools/turbocheetah/cheetahsupport.py
  44. +4 −18 cheetah/Utils/Misc.py
  45. +0 −83 cheetah/Utils/VerifyType.py
  46. +27 −31 cheetah/Utils/memcache.py
  47. +9 −9 cheetah/Utils/statprof.py
  48. +8 −8 cheetah/Version.py
  49. +0 −107 cheetah/c/_verifytype.c
  50. +1 −1  www/conf.py
  51. +6 −0 www/dev_guide/bnf.rst
  52. +404 −0 www/dev_guide/cache.rst
  53. +103 −0 www/dev_guide/comments.rst
  54. +8 −0 www/dev_guide/compiler.rst
  55. +104 −0 www/dev_guide/design.rst
  56. +329 −0 www/dev_guide/errorHandling.rst
  57. +11 −0 www/dev_guide/files.rst
  58. +394 −0 www/dev_guide/flowControl.rst
  59. +94 −0 www/dev_guide/history.rst
  60. +30 −0 www/dev_guide/index.rst
  61. +255 −0 www/dev_guide/inheritanceEtc.rst
  62. +28 −0 www/dev_guide/introduction.rst
  63. +315 −0 www/dev_guide/output.rst
  64. +9 −0 www/dev_guide/parser.rst
  65. +67 −0 www/dev_guide/parserInstructions.rst
  66. +149 −0 www/dev_guide/patching.rst
  67. +489 −0 www/dev_guide/placeholders.rst
  68. +252 −0 www/dev_guide/pyModules.rst
  69. +40 −0 www/dev_guide/safeDelegation.rst
  70. +11 −0 www/dev_guide/template.rst
  71. +1 −3 www/documentation.rst
  72. +5 −5 www/download.rst
  73. +4 −2 www/index.rst
  74. +9 −18 www/roadmap.rst
  75. +101 −0 www/users_guide/comments.rst
  76. +515 −0 www/users_guide/comparisons.rst
  77. +37 −0 www/users_guide/editors.rst
  78. +144 −0 www/users_guide/errorHandling.rst
  79. +27 −0 www/users_guide/examples.rst
  80. +436 −0 www/users_guide/flowControl.rst
  81. +278 −0 www/users_guide/gettingStarted.rst
  82. +99 −0 www/users_guide/glossary.rst
  83. 0  www/users_guide/howItWorks.rst
  84. +28 −0 www/users_guide/index.rst
  85. +517 −0 www/users_guide/inheritanceEtc.rst
  86. +313 −0 www/users_guide/intro.rst
  87. +741 −0 www/users_guide/language.rst
  88. +315 −0 www/users_guide/libraries.rst
  89. +142 −0 www/users_guide/links.rst
  90. +16 −0 www/users_guide/nonHtml.rst
  91. +48 −0 www/users_guide/optikLicense.rst
  92. +101 −0 www/users_guide/otherHtml.rst
  93. +468 −0 www/users_guide/output.rst
  94. +129 −0 www/users_guide/parserInstructions.rst
  95. +586 −0 www/users_guide/tipsAndTricks.rst
  96. +598 −0 www/users_guide/webware.rst
View
9 CHANGES
@@ -1,3 +1,12 @@
+2.4.1 (December 19th, 2009)
+ - --quiet flag added to `cheetah` to silence printing to stdout (abbeyj)
+ - Refactoring to minimize the amount of forked code for Python3 (rtyler)
+ - Template.compile() will no longer create class names with numerous leading
+ underscores (rtyler; reported by Kirill Uhanov)
+ - DirectiveAnalyzer (cheetah-analyze script) added to report directive usage in templates (rtyler)
+ - Older LaTeX docs converted to rst for Sphinx (rtyler)
+ - Prevent #raw blocks from evaluating $-placeholders and escaped strings (karmix0)
+ - New tests added to verify PSP behavior and other untested internals (rtyler)
2.4.0 (October 24th, 2009)
- Fix a major performance regression in Template.__init__()
View
7 SetupConfig.py
@@ -49,9 +49,10 @@
]
## Data Files and Scripts
-scripts = ['bin/cheetah-compile',
+scripts = ('bin/cheetah-compile',
'bin/cheetah',
- ]
+ 'bin/cheetah-analyze',
+ )
data_files = ['recursive: cheetah *.tmpl *.txt LICENSE README TODO CHANGES',]
@@ -71,7 +72,7 @@
]
}
except ImportError:
- print 'Not using setuptools, so we cannot install the Markdown dependency'
+ print('Not using setuptools, so we cannot install the Markdown dependency')
description = "Cheetah is a template engine and code generation tool."
View
24 SetupTools.py
@@ -77,8 +77,8 @@ def run (self):
data_files = self.get_inputs()
for entry in data_files:
- if type(entry) != types.StringType:
- raise ValueError, 'The entries in "data_files" must be strings'
+ if not isinstance(entry, basestring):
+ raise ValueError('The entries in "data_files" must be strings')
entry = string.join(string.split(entry, '/'), os.sep)
# entry is a filename or glob pattern
@@ -137,13 +137,7 @@ def run_setup(configurations):
for configuration in configurations:
kws.update(vars(configuration))
for name, value in kws.items():
- if name[:1] == '_' or \
- type(value) not in (types.StringType,
- types.ListType,
- types.TupleType,
- types.DictType,
- types.IntType,
- ):
+ if name[:1] == '_' or not isinstance(value, (basestring, list, tuple, dict, int)):
del kws[name]
# Add setup extensions
@@ -158,14 +152,14 @@ def run_setup(configurations):
try:
apply(setup, (), kws)
except BuildFailed, x:
- print "One or more C extensions failed to build."
- print "Details: %s" % x
- print "Retrying without C extensions enabled."
+ print("One or more C extensions failed to build.")
+ print("Details: %s" % x)
+ print("Retrying without C extensions enabled.")
del kws['ext_modules']
apply(setup, (), kws)
- print "One or more C extensions failed to build."
- print "Performance enhancements will not be available."
- print "Pure Python installation succeeded."
+ print("One or more C extensions failed to build.")
+ print("Performance enhancements will not be available.")
+ print("Pure Python installation succeeded.")
View
6 bin/cheetah-analyze
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+from Cheetah import DirectiveAnalyzer
+
+if __name__ == '__main__':
+ DirectiveAnalyzer.main()
View
66 buildandrun
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+import logging
+import os
+import os.path
+import subprocess
+import sys
+
+from optparse import OptionParser
+
+if os.getenv('DEBUG'):
+ logging.basicConfig(level=logging.DEBUG)
+
+def recursiverm(d):
+ for root, dirs, files in os.walk(d):
+ for f in files:
+ f = root + os.path.sep + f
+ logging.debug('Removing file: %s' % f)
+ os.unlink(f)
+
+def main():
+ op = OptionParser()
+ op.add_option('-c', '--clean', dest='clean', action='store_true',
+ help='Remove the contents of the build directory')
+ opts, args = op.parse_args()
+ if not args:
+ print('Specify a test script')
+ return
+
+
+ if opts.clean:
+ logging.debug('Removing build/')
+ recursiverm('build')
+
+ logging.debug('Building Cheetah')
+ rc = subprocess.call(('python', 'setup.py', 'build'))
+
+ if rc:
+ logging.debug('Build failed!')
+ return
+
+ logging.debug('Adjusting PATH and PYTHONPATH')
+ cwd = os.getcwd()
+
+ libdir = None
+ scriptdir = None
+
+ for sub in os.listdir('build'):
+ if sub.startswith('scripts'):
+ scriptdir = os.path.sep.join((cwd, 'build', sub))
+ if sub.startswith('lib'):
+ libdir = os.path.sep.join((cwd, 'build', sub))
+
+ newpath = '%s:%s' % (scriptdir, os.getenv('PATH'))
+ logging.debug('Setting PATH to: %s' % newpath)
+ os.putenv('PATH', newpath)
+ logging.debug('Setting PYTHONPATH to: %s' % libdir)
+ os.putenv('PYTHONPATH', libdir)
+
+ rc = subprocess.call( ['python',] + args )
+
+
+
+if __name__ == '__main__':
+ main()
+
View
2  cheetah/CacheRegion.py
@@ -128,7 +128,7 @@ def getCacheItem(self, cacheItemID):
"""
cacheItemID = md5(str(cacheItemID)).hexdigest()
- if not self._cacheItems.has_key(cacheItemID):
+ if cacheItemID not in self._cacheItems:
cacheItem = self._cacheItemClass(
cacheItemID=cacheItemID, cacheStore=self._wrappedCacheDataStore)
self._cacheItems[cacheItemID] = cacheItem
View
4 cheetah/CacheStore.py
@@ -46,12 +46,12 @@ def set(self, key, val, time=0):
self._data[key] = (val, time)
def add(self, key, val, time=0):
- if self._data.has_key(key):
+ if key in self._data:
raise Error('a value for key %r is already in the cache'%key)
self._data[key] = (val, time)
def replace(self, key, val, time=0):
- if self._data.has_key(key):
+ if key in self._data:
raise Error('a value for key %r is already in the cache'%key)
self._data[key] = (val, time)
View
19 cheetah/CheetahWrapper.py
@@ -161,7 +161,8 @@ def parseOpts(self, args):
pao("--iext", action="store", dest="iext", default=".tmpl", help='File input extension (defaults: compile: .tmpl, fill: .tmpl)')
pao("--oext", action="store", dest="oext", default=defaultOext, help='File output extension (defaults: compile: .py, fill: .html)')
pao("-R", action="store_true", dest="recurse", default=False, help='Recurse through subdirectories looking for input files')
- pao("--stdout", "-p", action="store_true", dest="stdout", default=False, help='Verbosely print informational messages to stdout')
+ pao("--stdout", "-p", action="store_true", dest="stdout", default=False, help='Send output to stdout instead of writing to a file')
+ pao("--quiet", action="store_false", dest="verbose", default=True, help='Do not print informational messages to stdout')
pao("--debug", action="store_true", dest="debug", default=False, help='Print diagnostic/debug information to stderr')
pao("--env", action="store_true", dest="env", default=False, help='Pass the environment into the search list')
pao("--pickle", action="store", dest="pickle", default="", help='Unpickle FILE and pass it through in the search list')
@@ -194,14 +195,14 @@ def parseOpts(self, args):
if opts.print_settings:
- print
- print '>> Available Cheetah compiler settings:'
+ print()
+ print('>> Available Cheetah compiler settings:')
from Cheetah.Compiler import _DEFAULT_COMPILER_SETTINGS
listing = _DEFAULT_COMPILER_SETTINGS
listing.sort(key=lambda l: l[0][0].lower())
for l in listing:
- print '\t%s (default: "%s")\t%s' % l
+ print('\t%s (default: "%s")\t%s' % l)
sys.exit(0)
#cleanup trailing path separators
@@ -222,7 +223,6 @@ def parseOpts(self, args):
unpickled = pickle.load(f)
f.close()
self.searchList.insert(0, unpickled)
- opts.verbose = not opts.stdout
##################################################
## COMMAND METHODS
@@ -266,7 +266,7 @@ def test(self):
runner.run(unittest.TestSuite(Test.suites))
def version(self):
- print Version
+ print(Version)
# If you add a command, also add it to the 'meths' variable in main().
@@ -387,12 +387,11 @@ def _checkForCollisions(self, bundles):
isError = False
dstSources = {}
for b in bundles:
- if dstSources.has_key(b.dst):
+ if b.dst in dstSources:
dstSources[b.dst].append(b.src)
else:
dstSources[b.dst] = [b.src]
- keys = dstSources.keys()
- keys.sort()
+ keys = sorted(dstSources.keys())
for dst in keys:
sources = dstSources[dst]
if len(sources) > 1:
@@ -537,7 +536,7 @@ def getkws(**kws):
return kws
if self.opts.compilerSettingsString:
try:
- exec 'settings = getkws(%s)'%self.opts.compilerSettingsString
+ exec('settings = getkws(%s)'%self.opts.compilerSettingsString)
except:
self.error("There's an error in your --settings option."
"It must be valid Python syntax.\n"
View
142 cheetah/Compiler.py
@@ -25,8 +25,8 @@
from Cheetah import ErrorCatchers
from Cheetah import NameMapper
from Cheetah.Parser import Parser, ParseError, specialVarRE, \
- STATIC_CACHE, REFRESH_CACHE, SET_LOCAL, SET_GLOBAL,SET_MODULE, \
- unicodeDirectiveRE, encodingDirectiveRE,escapedNewlineRE
+ STATIC_CACHE, REFRESH_CACHE, SET_LOCAL, SET_GLOBAL, SET_MODULE, \
+ unicodeDirectiveRE, encodingDirectiveRE, escapedNewlineRE
from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
VFFSL=valueFromFrameOrSearchList
@@ -56,8 +56,8 @@ class Error(Exception): pass
('commentOffset', 1, ''),
('outputRowColComments', True, ''),
('includeBlockMarkers', False, 'Wrap #block\'s in a comment in the template\'s output'),
- ('blockMarkerStart', ('\n<!-- START BLOCK: ',' -->\n'), ''),
- ('blockMarkerEnd', ('\n<!-- END BLOCK: ',' -->\n'), ''),
+ ('blockMarkerStart', ('\n<!-- START BLOCK: ', ' -->\n'), ''),
+ ('blockMarkerEnd', ('\n<!-- END BLOCK: ', ' -->\n'), ''),
('defDocStrMsg', 'Autogenerated by Cheetah: The Python-Powered Template Engine', ''),
('setup__str__method', False, ''),
('mainMethodName', 'respond', ''),
@@ -379,13 +379,13 @@ def docString(self):
ind = self._indent*2
docStr = (ind + '"""\n' + ind +
- ('\n' + ind).join([ln.replace('"""',"'''") for ln in self._docStringLines]) +
+ ('\n' + ind).join([ln.replace('"""', "'''") for ln in self._docStringLines]) +
'\n' + ind + '"""\n')
return docStr
## methods for adding code
def addMethDocString(self, line):
- self._docStringLines.append(line.replace('%','%%'))
+ self._docStringLines.append(line.replace('%', '%%'))
def addChunk(self, chunk):
self.commitStrConst()
@@ -418,7 +418,7 @@ def addFilteredChunk(self, chunk, filterArgs=None, rawExpr=None, lineCol=None):
self.addChunk("if _v is not None: write(str(_v))")
else:
if self.setting('useFilters'):
- self.addChunk("write(_filter(%s%s))"%(chunk,filterArgs))
+ self.addChunk("write(_filter(%s%s))"%(chunk, filterArgs))
else:
self.addChunk("write(str(%s))"%chunk)
@@ -428,48 +428,35 @@ def _appendToPrevStrConst(self, strConst):
else:
self._pendingStrConstChunks = [strConst]
- def _unescapeCheetahVars(self, theString):
- """Unescape any escaped Cheetah \$vars in the string.
- """
-
- token = self.setting('cheetahVarStartToken')
- return theString.replace('\\' + token, token)
-
- def _unescapeDirectives(self, theString):
- """Unescape any escaped Cheetah \$vars in the string.
- """
-
- token = self.setting('directiveStartToken')
- return theString.replace('\\' + token, token)
-
def commitStrConst(self):
"""Add the code for outputting the pending strConst without chopping off
any whitespace from it.
"""
- if self._pendingStrConstChunks:
- strConst = self._unescapeCheetahVars(''.join(self._pendingStrConstChunks))
- strConst = self._unescapeDirectives(strConst)
- self._pendingStrConstChunks = []
- if not strConst:
- return
- else:
- reprstr = repr(strConst).replace('\\012','\n')
- i = 0
- out = []
- if reprstr.startswith('u'):
- i = 1
- out = ['u']
- body = escapedNewlineRE.sub('\n', reprstr[i+1:-1])
-
- if reprstr[i]=="'":
- out.append("'''")
- out.append(body)
- out.append("'''")
- else:
- out.append('"""')
- out.append(body)
- out.append('"""')
- self.addWriteChunk(''.join(out))
+ if not self._pendingStrConstChunks:
+ return
+
+ strConst = ''.join(self._pendingStrConstChunks)
+ self._pendingStrConstChunks = []
+ if not strConst:
+ return
+
+ reprstr = repr(strConst)
+ i = 0
+ out = []
+ if reprstr.startswith('u'):
+ i = 1
+ out = ['u']
+ body = escapedNewlineRE.sub('\\1\n', reprstr[i+1:-1])
+
+ if reprstr[i]=="'":
+ out.append("'''")
+ out.append(body)
+ out.append("'''")
+ else:
+ out.append('"""')
+ out.append(body)
+ out.append('"""')
+ self.addWriteChunk(''.join(out))
def handleWSBeforeDirective(self):
"""Truncate the pending strCont to the beginning of the current line.
@@ -545,7 +532,7 @@ def addSet(self, expr, exprComponents, setStyle):
splitPos2 = LVALUE.find('[')
if splitPos1 > 0 and splitPos2==-1:
splitPos = splitPos1
- elif splitPos1 > 0 and splitPos1 < max(splitPos2,0):
+ elif splitPos1 > 0 and splitPos1 < max(splitPos2, 0):
splitPos = splitPos1
else:
splitPos = splitPos2
@@ -579,7 +566,7 @@ def addFor(self, expr, lineCol=None):
def addRepeat(self, expr, lineCol=None):
#the _repeatCount stuff here allows nesting of #repeat directives
self._repeatCount = getattr(self, "_repeatCount", -1) + 1
- self.addFor('for __i%s in range(%s)' % (self._repeatCount,expr), lineCol=lineCol)
+ self.addFor('for __i%s in range(%s)' % (self._repeatCount, expr), lineCol=lineCol)
def addIndentingDirective(self, expr, lineCol=None):
if expr and not expr[-1] == ':':
@@ -623,7 +610,7 @@ def addTernaryExpr(self, conditionExpr, trueExpr, falseExpr, lineCol=None):
self.dedent()
def addElse(self, expr, dedent=True, lineCol=None):
- expr = re.sub(r'else[ \f\t]+if','elif', expr)
+ expr = re.sub(r'else[ \f\t]+if', 'elif', expr)
self.addReIndentingDirective(expr, dedent=dedent, lineCol=lineCol)
def addElif(self, expr, dedent=True, lineCol=None):
@@ -660,7 +647,7 @@ def addReturn(self, expr):
def addYield(self, expr):
assert not self._hasReturnStatement
self._isGenerator = True
- if expr.replace('yield','').strip():
+ if expr.replace('yield', '').strip():
self.addChunk(expr)
else:
self.addChunk('if _dummyTrans:')
@@ -727,9 +714,9 @@ def startCacheRegion(self, cacheInfo, lineCol, rawPlaceholder=None):
# @@TR: we should add some runtime logging to this
ID = self.nextCacheID()
- interval = cacheInfo.get('interval',None)
- test = cacheInfo.get('test',None)
- customID = cacheInfo.get('id',None)
+ interval = cacheInfo.get('interval', None)
+ test = cacheInfo.get('test', None)
+ customID = cacheInfo.get('id', None)
if customID:
ID = customID
varyBy = cacheInfo.get('varyBy', repr(ID))
@@ -896,7 +883,7 @@ class CaptureDetails: pass
captureDetails.assignTo = assignTo
captureDetails.lineCol = lineCol
- self._captureRegionsStack.append((ID,captureDetails)) # attrib of current methodCompiler
+ self._captureRegionsStack.append((ID, captureDetails)) # attrib of current methodCompiler
self.addChunk('## START CAPTURE REGION: '+ID
+' '+assignTo
+' at line %s, col %s'%lineCol + ' in the source.')
@@ -982,13 +969,13 @@ class AutoMethodCompiler(MethodCompiler):
def _setupState(self):
MethodCompiler._setupState(self)
- self._argStringList = [ ("self",None) ]
+ self._argStringList = [ ("self", None) ]
self._streamingEnabled = True
self._isClassMethod = None
self._isStaticMethod = None
def _useKWsDictArgForPassingTrans(self):
- alreadyHasTransArg = [argname for argname,defval in self._argStringList
+ alreadyHasTransArg = [argname for argname, defval in self._argStringList
if argname=='trans']
return (self.methodName()!='respond'
and not alreadyHasTransArg
@@ -1015,12 +1002,12 @@ def cleanupState(self):
if self._streamingEnabled:
kwargsName = None
positionalArgsListName = None
- for argname,defval in self._argStringList:
+ for argname, defval in self._argStringList:
if argname.strip().startswith('**'):
- kwargsName = argname.strip().replace('**','')
+ kwargsName = argname.strip().replace('**', '')
break
elif argname.strip().startswith('*'):
- positionalArgsListName = argname.strip().replace('*','')
+ positionalArgsListName = argname.strip().replace('*', '')
if not kwargsName and self._useKWsDictArgForPassingTrans():
kwargsName = 'KWS'
@@ -1100,7 +1087,7 @@ def addStop(self, expr=None):
self.addChunk('return _dummyTrans and trans.response().getvalue() or ""')
def addMethArg(self, name, defVal=None):
- self._argStringList.append( (name,defVal) )
+ self._argStringList.append( (name, defVal) )
def methodSignature(self):
argStringChunks = []
@@ -1136,7 +1123,7 @@ def methodSignature(self):
for k,v in KWs.items():
if k in allowedKWs: cheetahKWArgs[k] = v
self._initCheetahInstance(**cheetahKWArgs)
-""".replace('\n','\n'+' '*8)
+""".replace('\n', '\n'+' '*8)
class ClassCompiler(GenUtils):
methodCompilerClass = AutoMethodCompiler
@@ -1173,14 +1160,14 @@ def __getattr__(self, name):
from the methods of this class!!! or you will be assigning to attributes
of this object instead."""
- if self.__dict__.has_key(name):
+ if name in self.__dict__:
return self.__dict__[name]
elif hasattr(self.__class__, name):
return getattr(self.__class__, name)
elif self._activeMethodsList and hasattr(self._activeMethodsList[-1], name):
return getattr(self._activeMethodsList[-1], name)
else:
- raise AttributeError, name
+ raise AttributeError(name)
def _setupState(self):
self._classDef = None
@@ -1333,9 +1320,9 @@ def addDecorator(self, decoratorExpr):
self._decoratorsForNextMethod.append(decoratorExpr)
def addClassDocString(self, line):
- self._classDocStringLines.append( line.replace('%','%%'))
+ self._classDocStringLines.append( line.replace('%', '%%'))
- def addChunkToInit(self,chunk):
+ def addChunkToInit(self, chunk):
self._initMethChunks.append(chunk)
def addAttribute(self, attribExpr):
@@ -1364,7 +1351,7 @@ def addSuper(self, argsList, parserComment=None):
'super(%(className)s, self).%(methodName)s(%(argString)s)'%locals())
def addErrorCatcherCall(self, codeChunk, rawCode='', lineCol=''):
- if self._placeholderToErrorCatcherMap.has_key(rawCode):
+ if rawCode in self._placeholderToErrorCatcherMap:
methodName = self._placeholderToErrorCatcherMap[rawCode]
if not self.setting('outputRowColComments'):
self._methodsIndex[methodName].addMethDocString(
@@ -1601,14 +1588,14 @@ def __getattr__(self, name):
from the methods of this class!!! or you will be assigning to attributes
of this object instead.
"""
- if self.__dict__.has_key(name):
+ if name in self.__dict__:
return self.__dict__[name]
elif hasattr(self.__class__, name):
return getattr(self.__class__, name)
elif self._activeClassesList and hasattr(self._activeClassesList[-1], name):
return getattr(self._activeClassesList[-1], name)
else:
- raise AttributeError, name
+ raise AttributeError(name)
def _initializeSettings(self):
self.updateSettings(copy.deepcopy(DEFAULT_COMPILER_SETTINGS))
@@ -1848,7 +1835,7 @@ def addAttribute(self, attribName, expr):
self._getActiveClassCompiler().addAttribute(attribName + ' =' + expr)
def addComment(self, comm):
- if re.match(r'#+$',comm): # skip bar comments
+ if re.match(r'#+$', comm): # skip bar comments
return
specialVarMatch = specialVarRE.match(comm)
@@ -1935,14 +1922,14 @@ def wrapModuleDef(self):
templateAPIClass._addCheetahPlumbingCodeToClass(%(mainClassName)s)
%(footer)s
-""" % {'header':self.moduleHeader(),
- 'docstring':self.moduleDocstring(),
- 'specialVars':self.specialVars(),
- 'imports':self.importStatements(),
- 'constants':self.moduleConstants(),
- 'classes':self.classDefs(),
- 'footer':self.moduleFooter(),
- 'mainClassName':self._mainClassName,
+""" % {'header': self.moduleHeader(),
+ 'docstring': self.moduleDocstring(),
+ 'specialVars': self.specialVars(),
+ 'imports': self.importStatements(),
+ 'constants': self.moduleConstants(),
+ 'classes': self.classDefs(),
+ 'footer': self.moduleFooter(),
+ 'mainClassName': self._mainClassName,
}
self._moduleDef = moduleDef
@@ -1976,8 +1963,7 @@ def moduleDocstring(self):
def specialVars(self):
chunks = []
theVars = self._specialVars
- keys = theVars.keys()
- keys.sort()
+ keys = sorted(theVars.keys())
for key in keys:
chunks.append(key + ' = ' + repr(theVars[key]) )
return '\n'.join(chunks)
View
98 cheetah/DirectiveAnalyzer.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+import os
+import pprint
+
+try:
+ from functools import reduce
+except ImportError:
+ # Assume we have reduce
+ pass
+
+from Cheetah import Parser
+from Cheetah import Compiler
+from Cheetah import Template
+
+class Analyzer(Parser.Parser):
+ def __init__(self, *args, **kwargs):
+ self.calls = {}
+ super(Analyzer, self).__init__(*args, **kwargs)
+
+ def eatDirective(self):
+ directive = self.matchDirective()
+ try:
+ self.calls[directive] += 1
+ except KeyError:
+ self.calls[directive] = 1
+ super(Analyzer, self).eatDirective()
+
+class AnalysisCompiler(Compiler.ModuleCompiler):
+ parserClass = Analyzer
+
+
+def analyze(source):
+ klass = Template.Template.compile(source, compilerClass=AnalysisCompiler)
+ return klass._CHEETAH_compilerInstance._parser.calls
+
+def main_file(f):
+ fd = open(f, 'r')
+ try:
+ print u'>>> Analyzing %s' % f
+ calls = analyze(fd.read())
+ return calls
+ finally:
+ fd.close()
+
+
+def _find_templates(directory, suffix):
+ for root, dirs, files in os.walk(directory):
+ for f in files:
+ if not f.endswith(suffix):
+ continue
+ yield root + os.path.sep + f
+
+def _analyze_templates(iterable):
+ for template in iterable:
+ yield main_file(template)
+
+def main_dir(opts):
+ results = _analyze_templates(_find_templates(opts.dir, opts.suffix))
+ totals = {}
+ for series in results:
+ if not series:
+ continue
+ for k, v in series.iteritems():
+ try:
+ totals[k] += v
+ except KeyError:
+ totals[k] = v
+ return totals
+
+
+def main():
+ from optparse import OptionParser
+ op = OptionParser()
+ op.add_option('-f', '--file', dest='file', default=None,
+ help='Specify a single file to analyze')
+ op.add_option('-d', '--dir', dest='dir', default=None,
+ help='Specify a directory of templates to analyze')
+ op.add_option('--suffix', default='tmpl', dest='suffix',
+ help='Specify a custom template file suffix for the -d option (default: "tmpl")')
+ opts, args = op.parse_args()
+
+ if not opts.file and not opts.dir:
+ op.print_help()
+ return
+
+ results = None
+ if opts.file:
+ results = main_file(opts.file)
+ if opts.dir:
+ results = main_dir(opts)
+
+ pprint.pprint(results)
+
+
+if __name__ == '__main__':
+ main()
+
View
2  cheetah/DummyTransaction.py
@@ -92,7 +92,7 @@ def getvalue(self, **kwargs):
output = super(TransformerResponse, self).getvalue(**kwargs)
if self._filter:
_filter = self._filter
- if isinstance(_filter, types.TypeType):
+ if isinstance(_filter, type):
_filter = _filter()
return _filter.filter(output)
return output
View
54 cheetah/FileUtils.py
@@ -1,30 +1,14 @@
-# $Id: FileUtils.py,v 1.12 2005/11/02 22:26:07 tavis_rudd Exp $
-"""File utitilies for Python:
-
-Meta-Data
-================================================================================
-Author: Tavis Rudd <tavis@damnsimple.com>
-License: This software is released for unlimited distribution under the
- terms of the MIT license. See the LICENSE file.
-Version: $Revision: 1.12 $
-Start Date: 2001/09/26
-Last Revision Date: $Date: 2005/11/02 22:26:07 $
-"""
-__author__ = "Tavis Rudd <tavis@damnsimple.com>"
-__revision__ = "$Revision: 1.12 $"[11:-2]
-
from glob import glob
import os
from os import listdir
import os.path
import re
-from types import StringType
from tempfile import mktemp
def _escapeRegexChars(txt,
escapeRE=re.compile(r'([\$\^\*\+\.\?\{\}\[\]\(\)\|\\])')):
- return escapeRE.sub(r'\\\1' , txt)
+ return escapeRE.sub(r'\\\1', txt)
def findFiles(*args, **kw):
"""Recursively find all the files matching a glob pattern.
@@ -70,7 +54,7 @@ class FileFinder:
def __init__(self, rootPath,
globPatterns=('*',),
- ignoreBasenames=('CVS','.svn'),
+ ignoreBasenames=('CVS', '.svn'),
ignoreDirs=(),
):
@@ -220,7 +204,7 @@ def code(self):
return "def subber(m):\n\treturn ''.join([%s])\n" % (self.codeBody())
def subberFunc(self):
- exec self.code()
+ exec(self.code())
return subber
@@ -238,11 +222,11 @@ def __init__(self, files, patternOrRE, replacement,
recordResults=True):
- if type(patternOrRE) == StringType:
+ if isinstance(patternOrRE, basestring):
self._regex = re.compile(patternOrRE)
else:
self._regex = patternOrRE
- if type(replacement) == StringType:
+ if isinstance(replacement, basestring):
self._subber = _GenSubberFunc(replacement).subberFunc()
else:
self._subber = replacement
@@ -279,7 +263,7 @@ def _run(self):
self._currFile = file
found = False
- if locals().has_key('orig'):
+ if 'orig' in locals():
del orig
if self._usePgrep:
if os.popen('pgrep "' + pattern + '" ' + file ).read():
@@ -289,23 +273,23 @@ def _run(self):
if regex.search(orig):
found = True
if found:
- if not locals().has_key('orig'):
+ if 'orig' not in locals():
orig = open(file).read()
new = regex.sub(subber, orig)
open(file, 'w').write(new)
def _subDispatcher(self, match):
if self._recordResults:
- if not self._results.has_key(self._currFile):
+ if self._currFile not in self._results:
res = self._results[self._currFile] = {}
res['count'] = 0
res['matches'] = []
else:
res = self._results[self._currFile]
res['count'] += 1
- res['matches'].append({'contents':match.group(),
- 'start':match.start(),
- 'end':match.end(),
+ res['matches'].append({'contents': match.group(),
+ 'start': match.start(),
+ 'end': match.end(),
}
)
return self._subber(match)
@@ -337,10 +321,10 @@ def summary(self):
commentLines += fileStats['commentLines']
totalLines += fileStats['totalLines']
- stats = {'codeLines':codeLines,
- 'blankLines':blankLines,
- 'commentLines':commentLines,
- 'totalLines':totalLines,
+ stats = {'codeLines': codeLines,
+ 'blankLines': blankLines,
+ 'commentLines': commentLines,
+ 'totalLines': totalLines,
}
return stats
@@ -364,10 +348,10 @@ def getFileStats(self, fileName):
else:
codeLines += 1
- stats = {'codeLines':codeLines,
- 'blankLines':blankLines,
- 'commentLines':commentLines,
- 'totalLines':totalLines,
+ stats = {'codeLines': codeLines,
+ 'blankLines': blankLines,
+ 'commentLines': commentLines,
+ 'totalLines': totalLines,
}
return stats
View
30 cheetah/Filters.py
@@ -65,9 +65,9 @@ def filter(self, value, **kwargs):
try:
import markdown
except ImportError:
- print '>>> Exception raised importing the "markdown" module'
- print '>>> Are you sure you have the ElementTree module installed?'
- print ' http://effbot.org/downloads/#elementtree'
+ print('>>> Exception raised importing the "markdown" module')
+ print('>>> Are you sure you have the ElementTree module installed?')
+ print(' http://effbot.org/downloads/#elementtree')
raise
encoded = super(Markdown, self).filter(value, **kwargs)
@@ -97,8 +97,8 @@ def filter(self, source, **kwargs):
from pygments import lexers
from pygments import formatters
except ImportError, ex:
- print '<%s> - Failed to import pygments! (%s)' % (self.__class__.__name__, ex)
- print '-- You may need to install it from: http://pygments.org'
+ print('<%s> - Failed to import pygments! (%s)' % (self.__class__.__name__, ex))
+ print('-- You may need to install it from: http://pygments.org')
return encoded
lexer = None
@@ -121,7 +121,7 @@ def filter(self, val, **kw):
"""Replace None with '' and cut off at maxlen."""
output = super(MaxLen, self).filter(val, **kw)
- if kw.has_key('maxlen') and len(output) > kw['maxlen']:
+ if 'maxlen' in kw and len(output) > kw['maxlen']:
return output[:kw['maxlen']]
return output
@@ -135,7 +135,7 @@ def filter(self, val, **kw):
s = s.replace("<", "&lt;")
s = s.replace(">", "&gt;")
# Process the additional transformations if any.
- if kw.has_key('also'):
+ if 'also' in kw:
also = kw['also']
entities = webSafeEntities # Global variable.
for k in also:
@@ -166,7 +166,7 @@ def filter(self, val, **kw):
s = super(Strip, self).filter(val, **kw)
result = []
start = 0 # The current line will be s[start:end].
- while 1: # Loop through each line.
+ while True: # Loop through each line.
end = s.find('\n', start) # Find next newline.
if end == -1: # If no more newlines.
break
@@ -196,15 +196,15 @@ def filter(self, val, **kw):
def test():
s1 = "abc <=> &"
s2 = " asdf \n\t 1 2 3\n"
- print "WebSafe INPUT:", `s1`
- print " WebSafe:", `WebSafe().filter(s1)`
+ print("WebSafe INPUT:", repr(s1))
+ print(" WebSafe:", repr(WebSafe().filter(s1)))
- print
- print " Strip INPUT:", `s2`
- print " Strip:", `Strip().filter(s2)`
- print "StripSqueeze:", `StripSqueeze().filter(s2)`
+ print()
+ print(" Strip INPUT:", repr(s2))
+ print(" Strip:", repr(Strip().filter(s2)))
+ print("StripSqueeze:", repr(StripSqueeze().filter(s2)))
- print "Unicode:", `EncodeUnicode().filter(u'aoeu12345\u1234')`
+ print("Unicode:", repr(EncodeUnicode().filter(u'aoeu12345\u1234')))
if __name__ == "__main__":
test()
View
4 cheetah/ImportHooks.py
@@ -114,7 +114,7 @@ def install(templateFileExtensions=('.tmpl',)):
if not _installed:
CheetahDirOwner.templateFileExtensions = templateFileExtensions
import __builtin__
- if type(__builtin__.__import__) == types.BuiltinFunctionType:
+ if isinstance(__builtin__.__import__, types.BuiltinFunctionType):
global __oldimport__
__oldimport__ = __builtin__.__import__
ImportManager._globalOwnerTypes.insert(0, CheetahDirOwner)
@@ -129,7 +129,7 @@ def uninstall():
global _installed
if not _installed:
import __builtin__
- if type(__builtin__.__import__) == types.MethodType:
+ if isinstance(__builtin__.__import__, types.MethodType):
__builtin__.__import__ = __oldimport__
global _manager
del _manager
View
54 cheetah/ImportManager.py
@@ -1,6 +1,5 @@
-# $Id: ImportManager.py,v 1.6 2007/04/03 01:56:24 tavis_rudd Exp $
-
-"""Provides an emulator/replacement for Python's standard import system.
+"""
+Provides an emulator/replacement for Python's standard import system.
@@TR: Be warned that Import Hooks are in the deepest, darkest corner of Python's
jungle. If you need to start hacking with this, be prepared to get lost for a
@@ -18,37 +17,14 @@
- reorganized the code layout to enhance readability
-Meta-Data
-================================================================================
-Author: Tavis Rudd <tavis@damnsimple.com> based on Gordon McMillan's iu.py
-License: This software is released for unlimited distribution under the
- terms of the MIT license. See the LICENSE file.
-Version: $Revision: 1.6 $
-Start Date: 2001/03/30
-Last Revision Date: $Date: 2007/04/03 01:56:24 $
"""
-__author__ = "Tavis Rudd <tavis@damnsimple.com>"
-__revision__ = "$Revision: 1.6 $"[11:-2]
-
-##################################################
-## DEPENDENCIES
import sys
import imp
import marshal
-##################################################
-## CONSTANTS & GLOBALS
-
-try:
- True,False
-except NameError:
- True, False = (1==1),(1==0)
-
_installed = False
-STRINGTYPE = type('')
-
# _globalOwnerTypes is defined at the bottom of this file
_os_stat = _os_path_join = _os_getcwd = _os_path_dirname = None
@@ -85,7 +61,7 @@ def join(a, b):
a = a + ':'
return a + b
else:
- raise ImportError, 'no os specific module found'
+ raise ImportError('no os specific module found')
if join is None:
def join(a, b, sep=sep):
@@ -184,7 +160,7 @@ def __init__(self, path):
if path == '':
path = _os_getcwd()
if not pathIsDir(path):
- raise ValueError, "%s is not a directory" % path
+ raise ValueError("%s is not a directory" % path)
Owner.__init__(self, path)
def getmod(self, nm,
@@ -217,14 +193,14 @@ def getmod(self, nm,
break
if py is None and pyc is None:
return None
- while 1:
+ while True:
if pyc is None or py and pyc[1][8] < py[1][8]:
try:
co = compile(open(py[0], 'r').read()+'\n', py[0], 'exec')
break
except SyntaxError, e:
- print "Invalid syntax in %s" % py[0]
- print e.args
+ print("Invalid syntax in %s" % py[0])
+ print(e.args)
raise
elif pyc:
stuff = open(pyc[0], 'rb').read()
@@ -260,7 +236,7 @@ def __init__(self):
def getmod(self, nm, isbuiltin=imp.is_builtin):
if isbuiltin(nm):
- mod = imp.load_module(nm, None, nm, ('','',imp.C_BUILTIN))
+ mod = imp.load_module(nm, None, nm, ('', '', imp.C_BUILTIN))
return mod
return None
@@ -273,7 +249,7 @@ def __init__(self):
def getmod(self, nm,
isFrozen=imp.is_frozen, loadMod=imp.load_module):
if isFrozen(nm):
- mod = loadMod(nm, None, nm, ('','',imp.PY_FROZEN))
+ mod = loadMod(nm, None, nm, ('', '', imp.PY_FROZEN))
if hasattr(mod, '__path__'):
mod.__importsub__ = lambda name, pname=nm, owner=self: owner.getmod(pname+'.'+name)
return mod
@@ -345,7 +321,7 @@ def __init__(self, pathlist=None, importers=None, ownertypes=None):
def getmod(self, nm):
mod = None
for thing in self.path:
- if type(thing) is STRINGTYPE:
+ if isinstance(thing, basestring):
owner = self._shadowPath.get(thing, -1)
if owner == -1:
owner = self._shadowPath[thing] = self._makeOwner(thing)
@@ -420,11 +396,11 @@ def importHook(self, name, globals=None, locals=None, fromlist=None, level=-1):
importernm = globals.get('__name__', '')
if importernm:
if hasattr(_sys_modules_get(importernm), '__path__'):
- contexts.insert(0,importernm)
+ contexts.insert(0, importernm)
else:
pkgnm = packageName(importernm)
if pkgnm:
- contexts.insert(0,pkgnm)
+ contexts.insert(0, pkgnm)
# so contexts is [pkgnm, None] or just [None]
# now break the name being imported up so we get:
# a.b.c -> [a, b, c]
@@ -462,7 +438,7 @@ def importHook(self, name, globals=None, locals=None, fromlist=None, level=-1):
#print "importHook done with %s %s %s (case 1)" % (name, globals['__name__'], fromlist)
return sys.modules[nmparts[0]]
del sys.modules[fqname]
- raise ImportError, "No module named %s" % fqname
+ raise ImportError("No module named %s" % fqname)
if fromlist is None:
#print "importHook done with %s %s %s (case 2)" % (name, globals['__name__'], fromlist)
if context:
@@ -487,7 +463,7 @@ def importHook(self, name, globals=None, locals=None, fromlist=None, level=-1):
if self.threaded:
self._release()
if not mod:
- raise ImportError, "%s not found in %s" % (nm, ctx)
+ raise ImportError("%s not found in %s" % (nm, ctx))
#print "importHook done with %s %s %s (case 3)" % (name, globals['__name__'], fromlist)
return bottommod
@@ -519,7 +495,7 @@ def doimport(self, nm, parentnm, fqname):
if hasattr(mod, '__co__'):
co = mod.__co__
del mod.__co__
- exec co in mod.__dict__
+ exec(co, mod.__dict__)
if fqname == 'thread' and not self.threaded:
## print "thread detected!"
self.setThreaded()
View
24 cheetah/NameMapper.py
@@ -138,7 +138,7 @@
Start Date: 2001/04/03
Last Revision Date: $Date: 2007/12/10 19:20:09 $
"""
-from __future__ import generators
+
__author__ = "Tavis Rudd <tavis@damnsimple.com>," +\
"\nChuck Esterbrook <echuck@mindspring.com>"
__revision__ = "$Revision: 1.32 $"[11:-2]
@@ -211,7 +211,7 @@ def _isInstanceOrClass(obj):
def hasKey(obj, key):
"""Determine if 'obj' has 'key' """
- if hasattr(obj,'has_key') and obj.has_key(key):
+ if hasattr(obj, 'has_key') and key in obj:
return True
elif hasattr(obj, key):
return True
@@ -219,7 +219,7 @@ def hasKey(obj, key):
return False
def valueForKey(obj, key):
- if hasattr(obj, 'has_key') and obj.has_key(key):
+ if hasattr(obj, 'has_key') and key in obj:
return obj[key]
elif hasattr(obj, key):
return getattr(obj, key)
@@ -230,7 +230,7 @@ def _valueForName(obj, name, executeCallables=False):
nameChunks=name.split('.')
for i in range(len(nameChunks)):
key = nameChunks[i]
- if hasattr(obj, 'has_key') and obj.has_key(key):
+ if hasattr(obj, 'has_key') and key in obj:
nextObj = obj[key]
else:
try:
@@ -238,7 +238,7 @@ def _valueForName(obj, name, executeCallables=False):
except AttributeError:
_raiseNotFoundException(key, obj)
- if executeCallables and callable(nextObj) and not _isInstanceOrClass(nextObj):
+ if executeCallables and hasattr(nextObj, '__call__') and not _isInstanceOrClass(nextObj):
obj = nextObj()
else:
obj = nextObj
@@ -364,13 +364,13 @@ def function(whichOne='default'):
}
b = 'this is local b'
- print valueForKey(a.dic,'subDict')
- print valueForName(a, 'dic.item')
- print valueForName(vars(), 'b')
- print valueForName(__builtins__, 'dir')()
- print valueForName(vars(), 'a.classVar')
- print valueForName(vars(), 'a.dic.func', executeCallables=True)
- print valueForName(vars(), 'a.method2.item1', executeCallables=True)
+ print(valueForKey(a.dic, 'subDict'))
+ print(valueForName(a, 'dic.item'))
+ print(valueForName(vars(), 'b'))
+ print(valueForName(__builtins__, 'dir')())
+ print(valueForName(vars(), 'a.classVar'))
+ print(valueForName(vars(), 'a.dic.func', executeCallables=True))
+ print(valueForName(vars(), 'a.method2.item1', executeCallables=True))
if __name__ == '__main__':
example()
View
237 cheetah/Parser.py
@@ -1,21 +1,12 @@
-# $Id: Parser.py,v 1.137 2008/03/10 05:25:13 tavis_rudd Exp $
-"""Parser classes for Cheetah's Compiler
+"""
+Parser classes for Cheetah's Compiler
Classes:
ParseError( Exception )
_LowLevelParser( Cheetah.SourceReader.SourceReader ), basically a lexer
_HighLevelParser( _LowLevelParser )
Parser === _HighLevelParser (an alias)
-
-Meta-Data
-================================================================================
-Author: Tavis Rudd <tavis@damnsimple.com>
-Version: $Revision: 1.137 $
-Start Date: 2001/08/01
-Last Revision Date: $Date: 2008/03/10 05:25:13 $
"""
-__author__ = "Tavis Rudd <tavis@damnsimple.com>"
-__revision__ = "$Revision: 1.137 $"[11:-2]
import os
import sys
@@ -46,13 +37,13 @@ def escapeRegexChars(txt,
"""Return a txt with all special regular expressions chars escaped."""
- return escapeRE.sub(r'\\\1' , txt)
+ return escapeRE.sub(r'\\\1', txt)
def group(*choices): return '(' + '|'.join(choices) + ')'
def nongroup(*choices): return '(?:' + '|'.join(choices) + ')'
def namedGroup(name, *choices): return '(P:<' + name +'>' + '|'.join(choices) + ')'
-def any(*choices): return apply(group, choices) + '*'
-def maybe(*choices): return apply(group, choices) + '?'
+def any(*choices): return group(*choices) + '*'
+def maybe(*choices): return group(*choices) + '?'
##################################################
## CONSTANTS & GLOBALS ##
@@ -76,22 +67,22 @@ def maybe(*choices): return apply(group, choices) + '?'
#operators
powerOp = '**'
unaryArithOps = ('+', '-', '~')
-binaryArithOps = ('+', '-', '/', '//','%')
-shiftOps = ('>>','<<')
-bitwiseOps = ('&','|','^')
+binaryArithOps = ('+', '-', '/', '//', '%')
+shiftOps = ('>>', '<<')
+bitwiseOps = ('&', '|', '^')
assignOp = '='
-augAssignOps = ('+=','-=','/=','*=', '**=','^=','%=',
- '>>=','<<=','&=','|=', )
+augAssignOps = ('+=', '-=', '/=', '*=', '**=', '^=', '%=',
+ '>>=', '<<=', '&=', '|=', )
assignmentOps = (assignOp,) + augAssignOps
-compOps = ('<','>','==','!=','<=','>=', '<>', 'is', 'in',)
-booleanOps = ('and','or','not')
+compOps = ('<', '>', '==', '!=', '<=', '>=', '<>', 'is', 'in',)
+booleanOps = ('and', 'or', 'not')
operators = (powerOp,) + unaryArithOps + binaryArithOps \
+ shiftOps + bitwiseOps + assignmentOps \
+ compOps + booleanOps
-delimeters = ('(',')','{','}','[',']',
- ',','.',':',';','=','`') + augAssignOps
+delimeters = ('(', ')', '{', '}', '[', ']',
+ ',', '.', ':', ';', '=', '`') + augAssignOps
keywords = ('and', 'del', 'for', 'is', 'raise',
@@ -140,7 +131,7 @@ def makeTripleQuoteRe(start, end):
WS = r'[ \f\t]*'
EOL = r'\r\n|\n|\r'
EOLZ = EOL + r'|\Z'
-escCharLookBehind = nongroup(r'(?<=\A)',r'(?<!\\)')
+escCharLookBehind = nongroup(r'(?<=\A)', r'(?<!\\)')
nameCharLookAhead = r'(?=[A-Za-z_])'
identRE=re.compile(r'[a-zA-Z_][a-zA-Z_0-9]*')
EOLre=re.compile(r'(?:\r\n|\r|\n)')
@@ -153,12 +144,12 @@ def makeTripleQuoteRe(start, end):
encodingDirectiveRE = re.compile(
r'(?:^|\r\n|\r|\n)\s*#\s{0,5}encoding[:\s]*([-\w.]*)\s*(?:\r\n|\r|\n)', re.MULTILINE)
-escapedNewlineRE = re.compile(r'(?<!\\)\\n')
+escapedNewlineRE = re.compile(r'(?<!\\)((\\\\)*)\\(n|012)')
directiveNamesAndParsers = {
# importing and inheritance
- 'import':None,
- 'from':None,
+ 'import': None,
+ 'from': None,
'extends': 'eatExtends',
'implements': 'eatImplements',
'super': 'eatSuper',
@@ -171,7 +162,7 @@ def makeTripleQuoteRe(start, end):
'filter': 'eatFilter',
'echo': None,
'silent': None,
- 'transform' : 'eatTransform',
+ 'transform': 'eatTransform',
'call': 'eatCall',
'arg': 'eatCallArg',
@@ -235,7 +226,7 @@ def makeTripleQuoteRe(start, end):
'call': None, # has short-form
'capture': None, # has short-form
'filter': None,
- 'errorCatcher':None,
+ 'errorCatcher': None,
'while': None, # has short-form
'for': None, # has short-form
'if': None, # has short-form
@@ -279,16 +270,16 @@ def report(self):
## get the surrounding lines
lines = stream.splitlines()
prevLines = [] # (rowNum, content)
- for i in range(1,4):
+ for i in range(1, 4):
if row-1-i <=0:
break
- prevLines.append( (row-i,lines[row-1-i]) )
+ prevLines.append( (row-i, lines[row-1-i]) )
nextLines = [] # (rowNum, content)
- for i in range(1,4):
+ for i in range(1, 4):
if not row-1+i < len(lines):
break
- nextLines.append( (row+i,lines[row-1+i]) )
+ nextLines.append( (row+i, lines[row-1+i]) )
nextLines.reverse()
## print the main message
@@ -311,11 +302,14 @@ def report(self):
return report
-class ForbiddenSyntax(ParseError): pass
-class ForbiddenExpression(ForbiddenSyntax): pass
-class ForbiddenDirective(ForbiddenSyntax): pass
+class ForbiddenSyntax(ParseError):
+ pass
+class ForbiddenExpression(ForbiddenSyntax):
+ pass
+class ForbiddenDirective(ForbiddenSyntax):
+ pass
-class CheetahVariable:
+class CheetahVariable(object):
def __init__(self, nameChunks, useNameMapper=True, cacheToken=None,
rawSource=None):
self.nameChunks = nameChunks
@@ -323,36 +317,33 @@ def __init__(self, nameChunks, useNameMapper=True, cacheToken=None,
self.cacheToken = cacheToken
self.rawSource = rawSource
-class Placeholder(CheetahVariable): pass
+class Placeholder(CheetahVariable):
+ pass
-class ArgList:
+class ArgList(object):
"""Used by _LowLevelParser.getArgList()"""
def __init__(self):
- self.argNames = []
- self.defVals = []
- self.i = 0
+ self.arguments = []
+ self.defaults = []
+ self.count = 0
- def addArgName(self, name):
- self.argNames.append( name )
- self.defVals.append( None )
+ def add_argument(self, name):
+ self.arguments.append(name)
+ self.defaults.append(None)
def next(self):
- self.i += 1
+ self.count += 1
- def addToDefVal(self, token):
- i = self.i
- if self.defVals[i] == None:
- self.defVals[i] = ''
- self.defVals[i] += token
+ def add_default(self, token):
+ count = self.count
+ if self.defaults[count] is None:
+ self.defaults[count] = ''
+ self.defaults[count] += token
def merge(self):
- defVals = self.defVals
- for i in range(len(defVals)):
- if type(defVals[i]) == StringType:
- defVals[i] = defVals[i].strip()
-
- return map(None, [i.strip() for i in self.argNames], defVals)
+ defaults = (isinstance(d, basestring) and d.strip() or None for d in self.defaults)
+ return list(map(None, (a.strip() for a in self.arguments), defaults))
def __str__(self):
return str(self.merge())
@@ -519,6 +510,19 @@ def _makePspREs(self):
endTokenEsc = escapeRegexChars(endToken)
self.PSPEndTokenRE = cachedRegex(escCharLookBehind + endTokenEsc)
+ def _unescapeCheetahVars(self, theString):
+ """Unescape any escaped Cheetah \$vars in the string.
+ """
+
+ token = self.setting('cheetahVarStartToken')
+ return theString.replace('\\' + token, token)
+
+ def _unescapeDirectives(self, theString):
+ """Unescape any escaped Cheetah directives in the string.
+ """
+
+ token = self.setting('directiveStartToken')
+ return theString.replace('\\' + token, token)
def isLineClearToStartToken(self, pos=None):
return self.isLineClearToPos(pos)
@@ -942,7 +946,7 @@ def getCallArgString(self,
argStringBits = ['(']
addBit = argStringBits.append
- while 1:
+ while True:
if self.atEnd():
open = enclosures[-1][0]
close = closurePairsRev[open]
@@ -987,7 +991,7 @@ def getCallArgString(self,
else:
beforeTokenPos = self.pos()
token = self.getPyToken()
- if token in ('{','(','['):
+ if token in ('{', '(', '['):
self.rev()
token = self.getExpression(enclosed=True)
token = self.transformToken(token, beforeTokenPos)
@@ -1027,7 +1031,7 @@ def getDefArgList(self, exitPos=None, useNameMapper=False):
useNameMapper_orig = self.setting('useNameMapper')
self.setSetting('useNameMapper', useNameMapper)
- while 1:
+ while True:
if self.atEnd():
raise ParseError(
self, msg="EOF was reached before a matching ')'"+
@@ -1043,7 +1047,7 @@ def getDefArgList(self, exitPos=None, useNameMapper=False):
break
elif c in " \t\f\r\n":
if onDefVal:
- argList.addToDefVal(c)
+ argList.add_default(c)
self.advance()
elif c == '=':
onDefVal = True
@@ -1055,7 +1059,7 @@ def getDefArgList(self, exitPos=None, useNameMapper=False):
elif self.startswith(self.cheetahVarStartToken) and not onDefVal:
self.advance(len(self.cheetahVarStartToken))
elif self.matchIdentifier() and not onDefVal:
- argList.addArgName( self.getIdentifier() )
+ argList.add_argument( self.getIdentifier() )
elif onDefVal:
if self.matchCheetahVarInExpressionStartToken():
token = self.getCheetahVar()
@@ -1065,11 +1069,11 @@ def getDefArgList(self, exitPos=None, useNameMapper=False):
else:
beforeTokenPos = self.pos()
token = self.getPyToken()
- if token in ('{','(','['):
+ if token in ('{', '(', '['):
self.rev()
token = self.getExpression(enclosed=True)
token = self.transformToken(token, beforeTokenPos)
- argList.addToDefVal(token)
+ argList.add_default(token)
elif c == '*' and not onDefVal:
varName = self.getc()
if self.peek() == '*':
@@ -1077,7 +1081,7 @@ def getDefArgList(self, exitPos=None, useNameMapper=False):
if not self.matchIdentifier():
raise ParseError(self)
varName += self.getIdentifier()
- argList.addArgName(varName)
+ argList.add_argument(varName)
else:
raise ParseError(self)
@@ -1106,7 +1110,7 @@ def getExpressionParts(self,
srcLen = len(self)
exprBits = []
- while 1:
+ while True:
if self.atEnd():
if enclosures:
open = enclosures[-1][0]
@@ -1224,7 +1228,6 @@ def transformToken(self, token, beforeTokenPos):
startPosIdx = 3
else:
startPosIdx = 1
- #print 'CHEETAH STRING', nextToken, theStr, startPosIdx
self.setPos(beforeTokenPos+startPosIdx+1)
outputExprs = []
strConst = ''
@@ -1240,8 +1243,6 @@ def transformToken(self, token, beforeTokenPos):
self.setPos(endPos)
if strConst:
outputExprs.append(repr(strConst))
- #if not self.atEnd() and self.matches('.join('):
- # print 'DEBUG***'
token = "''.join(["+','.join(outputExprs)+"])"
return token
@@ -1318,8 +1319,8 @@ def getPlaceholder(self, allowCacheTokens=False, plain=False, returnEverything=F
expr = expr[:-1]
rawPlaceholder=self[startPos: self.pos()]
- expr = self._applyExpressionFilters(expr,'placeholder',
- rawExpr=rawPlaceholder,startPos=startPos)
+ expr = self._applyExpressionFilters(expr, 'placeholder',
+ rawExpr=rawPlaceholder, startPos=startPos)
for callback in self.setting('postparsePlaceholderHooks'):
callback(parser=self)
@@ -1336,7 +1337,7 @@ class _HighLevelParser(_LowLevelParser):
Cheetah.Compiler.Compiler.
"""
def __init__(self, src, filename=None, breakPoint=None, compiler=None):
- _LowLevelParser.__init__(self, src, filename=filename, breakPoint=breakPoint)
+ super(_HighLevelParser, self).__init__(src, filename=filename, breakPoint=breakPoint)
self.setSettingsManager(compiler)
self._compiler = compiler
self.setupState()
@@ -1357,16 +1358,16 @@ def cleanup(self):
self._macroDetails.clear()
def configureParser(self):
- _LowLevelParser.configureParser(self)
+ super(_HighLevelParser, self).configureParser()
self._initDirectives()
def _initDirectives(self):
def normalizeParserVal(val):
- if isinstance(val, (str,unicode)):
+ if isinstance(val, (str, unicode)):
handler = getattr(self, val)
elif type(val) in (ClassType, TypeType):
handler = val(self)
- elif callable(val):
+ elif hasattr(val, '__call__'):
handler = val
elif val is None:
handler = val
@@ -1377,11 +1378,11 @@ def normalizeParserVal(val):
normalizeHandlerVal = normalizeParserVal
_directiveNamesAndParsers = directiveNamesAndParsers.copy()
- customNamesAndParsers = self.setting('directiveNamesAndParsers',{})
+ customNamesAndParsers = self.setting('directiveNamesAndParsers', {})
_directiveNamesAndParsers.update(customNamesAndParsers)
_endDirectiveNamesAndHandlers = endDirectiveNamesAndHandlers.copy()
- customNamesAndHandlers = self.setting('endDirectiveNamesAndHandlers',{})
+ customNamesAndHandlers = self.setting('endDirectiveNamesAndHandlers', {})
_endDirectiveNamesAndHandlers.update(customNamesAndHandlers)
self._directiveNamesAndParsers = {}
@@ -1396,21 +1397,21 @@ def normalizeParserVal(val):
continue
self._endDirectiveNamesAndHandlers[name] = normalizeHandlerVal(val)
- self._closeableDirectives = ['def','block','closure','defmacro',
+ self._closeableDirectives = ['def', 'block', 'closure', 'defmacro',
'call',
'capture',
'cache',
'filter',
- 'if','unless',
- 'for','while','repeat',
+ 'if', 'unless',
+ 'for', 'while', 'repeat',
'try',
]
- for directiveName in self.setting('closeableDirectives',[]):
+ for directiveName in self.setting('closeableDirectives', []):
self._closeableDirectives.append(directiveName)
- macroDirectives = self.setting('macroDirectives',{})
+ macroDirectives = self.setting('macroDirectives', {})
macroDirectives['i18n'] = I18n
@@ -1509,6 +1510,8 @@ def eatPlainText(self):
else:
self.advance()
strConst = self.readTo(self.pos(), start=startPos)
+ strConst = self._unescapeCheetahVars(strConst)
+ strConst = self._unescapeDirectives(strConst)
self._compiler.addStrConst(strConst)
return match
@@ -1527,7 +1530,7 @@ def eatMultiLineComment(self):
self.getMultiLineCommentStartToken()
endPos = startPos = self.pos()
level = 1
- while 1:
+ while True:
endPos = self.pos()
if self.atEnd():
break
@@ -1594,8 +1597,8 @@ def eatPSP(self):
del assert raise
silent echo
import from'''.split()
- _directiveHandlerNames = {'import':'addImportStatement',
- 'from':'addImportStatement', }
+ _directiveHandlerNames = {'import': 'addImportStatement',
+ 'from': 'addImportStatement', }
def eatDirective(self):
directiveName = self.matchDirective()
self._filterDisabledDirectives(directiveName)
@@ -1854,13 +1857,11 @@ def eatCompiler(self):
try:
self._compiler.setCompilerSetting(settingName, valueExpr)
except:
- out = sys.stderr
- print >> out, 'An error occurred while processing the following #compiler directive.'
- print >> out, '-'*80
- print >> out, self[startPos:endPos]
- print >> out, '-'*80
- print >> out, 'Please check the syntax of these settings.'
- print >> out, 'A full Python exception traceback follows.'
+ sys.stderr.write('An error occurred while processing the following #compiler directive.\n')
+ sys.stderr.write('----------------------------------------------------------------------\n')
+ sys.stderr.write('%s\n' % self[startPos:endPos])
+ sys.stderr.write('----------------------------------------------------------------------\n')
+ sys.stderr.write('Please check the syntax of these settings.\n\n')
raise
@@ -1890,13 +1891,11 @@ def eatCompilerSettings(self):
try:
self._compiler.setCompilerSettings(keywords=keywords, settingsStr=settingsStr)
except:
- out = sys.stderr
- print >> out, 'An error occurred while processing the following compiler settings.'
- print >> out, '-'*80
- print >> out, settingsStr.strip()
- print >> out, '-'*80
- print >> out, 'Please check the syntax of these settings.'
- print >> out, 'A full Python exception traceback follows.'
+ sys.stderr.write('An error occurred while processing the following compiler settings.\n')
+ sys.stderr.write('----------------------------------------------------------------------\n')
+ sys.stderr.write('%s\n' % settingsStr.strip())
+ sys.stderr.write('----------------------------------------------------------------------\n')
+ sys.stderr.write('Please check the syntax of these settings.\n\n')
raise
def eatAttr(self):
@@ -1946,8 +1945,8 @@ def eatBlock(self):
startPos = self.pos()
methodName, rawSignature = self._eatDefOrBlock('block')
self._compiler._blockMetaData[methodName] = {
- 'raw':rawSignature,
- 'lineCol':self.getRowCol(startPos),
+ 'raw': rawSignature,
+ 'lineCol': self.getRowCol(startPos),
}
def eatClosure(self):
@@ -1956,7 +1955,7 @@ def eatClosure(self):
def _eatDefOrBlock(self, directiveName):
# filtered
- assert directiveName in ('def','block','closure')
+ assert directiveName in ('def', 'block', 'closure')
isLineClearToStartToken = self.isLineClearToStartToken()
endOfFirstLinePos = self.findEOL()
startPos = self.pos()
@@ -2249,15 +2248,15 @@ def eatDefMacro(self):
else:
argsList=[]
- assert not self._directiveNamesAndParsers.has_key(macroName)
- argsList.insert(0, ('src',None))
- argsList.append(('parser','None'))
- argsList.append(('macros','None'))
- argsList.append(('compilerSettings','None'))
- argsList.append(('isShortForm','None'))
- argsList.append(('EOLCharsInShortForm','None'))
- argsList.append(('startPos','None'))
- argsList.append(('endPos','None'))
+ assert macroName not in self._directiveNamesAndParsers
+ argsList.insert(0, ('src', None))
+ argsList.append(('parser', 'None'))
+ argsList.append(('macros', 'None'))
+ argsList.append(('compilerSettings', 'None'))
+ argsList.append(('isShortForm', 'None'))
+ argsList.append(('EOLCharsInShortForm', 'None'))
+ argsList.append(('startPos', 'None'))
+ argsList.append(('endPos', 'None'))
if self.matchColonForSingleLineShortFormDirective():
self.advance() # skip over :
@@ -2273,8 +2272,8 @@ def eatDefMacro(self):
#print argsList
normalizedMacroSrc = ''.join(
- ['%def callMacro('+','.join([defv and '%s=%s'%(n,defv) or n
- for n,defv in argsList])
+ ['%def callMacro('+','.join([defv and '%s=%s'%(n, defv) or n
+ for n, defv in argsList])
+')\n',
macroSrc,
'%end def'])
@@ -2285,9 +2284,9 @@ def eatDefMacro(self):
compilerSettings = self.setting('compilerSettingsForDefMacro', default={})
searchListForMacros = self.setting('searchListForDefMacro', default=[])
searchListForMacros = list(searchListForMacros) # copy to avoid mutation bugs
- searchListForMacros.append({'macros':self._macros,
- 'parser':self,
- 'compilerSettings':self.settings(),
+ searchListForMacros.append({'macros': self._macros,
+ 'parser': self,
+ 'compilerSettings': self.settings(),
})
templateAPIClass._updateSettingsWithPreprocessTokens(
@@ -2347,12 +2346,12 @@ def eatMacroCall(self):
else:
def getArgs(*pargs, **kws):
return pargs, kws
- exec 'positionalArgs, kwArgs = getArgs(%(args)s)'%locals()
+ exec('positionalArgs, kwArgs = getArgs(%(args)s)'%locals())
- assert not kwArgs.has_key('src')
+ assert 'src' not in kwArgs
kwArgs['src'] = srcBlock
- if type(macro)==new.instancemethod:
+ if isinstance(macro, new.instancemethod):
co = macro.im_func.func_code
elif (hasattr(macro, '__call__')
and hasattr(macro.__call__, 'im_func')):
View
2  cheetah/Servlet.py
@@ -103,7 +103,7 @@ def serverSidePath(self, path=None,
if self._CHEETAH__isControlledByWebKit:
return super(Servlet, self).serverSidePath(path)
elif path:
- return normpath(abspath(path.replace("\\",'/')))
+ return normpath(abspath(path.replace("\\", '/')))
elif hasattr(self, '_filePath') and self._filePath:
return normpath(abspath(self._filePath))
else:
View
24 cheetah/SettingsManager.py
@@ -34,10 +34,8 @@ def mergeNestedDictionaries(dict1, dict2, copy=False, deepcopy=False):
elif deepcopy:
dict1 = copyModule.deepcopy(dict1)
- for key,val in dict2.items():
- if dict1.has_key(key) and type(val) == types.DictType and \
- type(dict1[key]) == types.DictType:
-
+ 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
@@ -96,7 +94,7 @@ def readSettingsFromModule(self, mod, ignoreUnderscored=True):
"""
S = {}
attrs = vars(mod)
- for k, v in attrs.items():
+ for k, v in attrs.iteritems():
if (ignoreUnderscored and k.startswith('_')):
continue
else:
@@ -106,11 +104,11 @@ def readSettingsFromModule(self, mod, ignoreUnderscored=True):
def readSettingsFromPySrcStr(self, theString):
"""Return a dictionary of the settings in a Python src string."""
- globalsDict = {'True':(1==1),
- 'False':(0==1),
+ globalsDict = {'True': (1==1),
+ 'False': (0==1),
}
newSettings = {'self':self}
- exec (theString+os.linesep) in globalsDict, newSettings
+ exec((theString+os.linesep), globalsDict, newSettings)
del newSettings['self']
module =</