summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SetupConfig.py28
-rw-r--r--bin/.gitattributes1
-rw-r--r--bin/cheetah.bat1
-rw-r--r--cheetah/Filters.py29
-rw-r--r--cheetah/Template.py99
-rwxr-xr-xcheetah/Tests/Test.py4
-rw-r--r--cheetah/Utils/Indenter.py35
-rw-r--r--cheetah/Utils/VerifyType.py2
-rw-r--r--cheetah/c/Cheetah.h47
-rw-r--r--cheetah/c/_filters.c93
-rw-r--r--cheetah/c/_namemapper.c (renamed from cheetah/_namemapper.c)0
-rw-r--r--cheetah/c/_template.c52
-rw-r--r--cheetah/c/_verifytype.c107
-rw-r--r--src/Tests/Performance.py220
-rw-r--r--src/Tests/VerifyType.py157
15 files changed, 771 insertions, 104 deletions
diff --git a/SetupConfig.py b/SetupConfig.py
index d974418..bcf5ca3 100644
--- a/SetupConfig.py
+++ b/SetupConfig.py
@@ -33,24 +33,30 @@ package_dir = {'Cheetah':'cheetah'}
import os
import os.path
+import sys
from distutils.core import Extension
-## we only assume the presence of a c compiler on Posix systems, NT people will
-# have to enable this manually.
-if os.name == 'posix':
- ext_modules=[Extension("Cheetah._namemapper", [os.path.join("cheetah" ,"_namemapper.c")]
- )
- ]
-else:
- ext_modules=[]
-
+ext_modules=[
+ Extension("Cheetah._namemapper",
+ [os.path.join('cheetah', 'c', '_namemapper.c')]),
+ Extension("Cheetah._verifytype",
+ [os.path.join('cheetah', 'c', '_verifytype.c')]),
+ Extension("Cheetah._filters",
+ [os.path.join('cheetah', 'c', '_filters.c')]),
+ Extension('Cheetah._template',
+ [os.path.join('cheetah', 'c', '_template.c')]),
+ ]
## Data Files and Scripts
scripts = ['bin/cheetah-compile',
'bin/cheetah',
]
-data_files = ['recursive: cheetah *.tmpl *.txt LICENSE README TODO CHANGES',
- ]
+
+if sys.platform == "win32":
+ scripts.append('bin/cheetah.bat')
+
+data_files = ['recursive: src *.tmpl *.txt LICENSE README TODO CHANGES',]
+
if not os.getenv('CHEETAH_INSTALL_WITHOUT_SETUPTOOLS'):
try:
from setuptools import setup
diff --git a/bin/.gitattributes b/bin/.gitattributes
new file mode 100644
index 0000000..5bebad2
--- /dev/null
+++ b/bin/.gitattributes
@@ -0,0 +1 @@
+cheetah.bat -crlf
diff --git a/bin/cheetah.bat b/bin/cheetah.bat
new file mode 100644
index 0000000..3f6cf2a
--- /dev/null
+++ b/bin/cheetah.bat
@@ -0,0 +1 @@
+@"%~dp0..\python" "%~dpn0" %*
diff --git a/cheetah/Filters.py b/cheetah/Filters.py
index 09ffa4e..dd65f28 100644
--- a/cheetah/Filters.py
+++ b/cheetah/Filters.py
@@ -22,30 +22,26 @@ class Filter(object):
"""
self.template = template
- def filter(self, val,
- #encoding='utf8',
- encoding=None,
- str=str,
- **kw):
- """Pass Unicode strings through unmolested, unless an encoding is specified.
- """
+ def filter(self, val, encoding=None, str=str, **kw):
+ '''
+ Pass Unicode strings through unmolested, unless an encoding is specified.
+ '''
+ if val is None:
+ return u''
if isinstance(val, unicode):
if encoding:
- filtered = val.encode(encoding)
+ return val.encode(encoding)
else:
- filtered = val
- elif val is None:
- filtered = ''
+ return val
else:
try:
- filtered = str(val)
+ return str(val)
except UnicodeEncodeError:
- filtered = unicode(val)
- return filtered
+ return unicode(val)
+ return u''
RawOrEncodedUnicode = Filter
-
class EncodeUnicode(Filter):
def filter(self, val,
encoding='utf8',
@@ -231,6 +227,7 @@ def test():
print "Unicode:", `EncodeUnicode().filter(u'aoeu12345\u1234')`
-if __name__ == "__main__": test()
+if __name__ == "__main__":
+ test()
# vim: shiftwidth=4 tabstop=4 expandtab
diff --git a/cheetah/Template.py b/cheetah/Template.py
index 4bf6799..eeeeb95 100644
--- a/cheetah/Template.py
+++ b/cheetah/Template.py
@@ -25,11 +25,6 @@ try:
from types import StringTypes
except ImportError:
StringTypes = (types.StringType,types.UnicodeType)
-try:
- from types import BooleanType
- boolTypeAvailable = True
-except ImportError:
- boolTypeAvailable = False
try:
from threading import Lock
@@ -56,7 +51,14 @@ from Cheetah.Compiler import Compiler, DEFAULT_COMPILER_SETTINGS
from Cheetah import ErrorCatchers # for placeholder tags
from Cheetah import Filters # the output filters
from Cheetah.convertTmplPathToModuleName import convertTmplPathToModuleName
-from Cheetah.Utils import VerifyType # Used in Template.__init__
+
+try:
+ from Cheetah._verifytype import *
+except ImportError:
+ from Cheetah.Utils import VerifyType
+ verifyType = VerifyType.VerifyType
+ verifyTypeClass = VerifyType.VerifyTypeClass
+
from Cheetah.Utils.Misc import checkKeywords # Used in Template.__init__
from Cheetah.Utils.Indenter import Indenter # Used in Template.__init__ and for
# placeholders
@@ -117,11 +119,14 @@ def _genUniqueModuleName(baseModuleName):
# This is only relavent to templates used as CGI scripts.
_formUsedByWebInput = None
-# used in Template.compile()
-def valOrDefault(val, default):
- if val is not Unspecified:
- return val
- return default
+try:
+ from Cheetah._template import valOrDefault
+except ImportError:
+ # used in Template.compile()
+ def valOrDefault(val, default):
+ if val is not Unspecified:
+ return val
+ return default
def updateLinecache(filename, src):
import linecache
@@ -592,46 +597,43 @@ class Template(Servlet):
##################################################
## normalize and validate args
try:
- vt = VerifyType.VerifyType
- vtc = VerifyType.VerifyTypeClass
+ vt = verifyType
+ vtc = verifyTypeClass
N = types.NoneType; S = types.StringType; U = types.UnicodeType
D = types.DictType; F = types.FileType
C = types.ClassType; M = types.ModuleType
- I = types.IntType
+ I = types.IntType; B = types.BooleanType
- if boolTypeAvailable:
- B = types.BooleanType
-
- vt(source, 'source', [N,S,U], 'string or None')
- vt(file, 'file',[N,S,U,F], 'string, file-like object, or None')
+ IB = (I, B)
+ NS = (N, S)
+
+ vt(source, 'source', (N,S,U), 'string or None')
+ vt(file, 'file',(N,S,U,F), 'string, file-like object, or None')
baseclass = valOrDefault(baseclass, klass._CHEETAH_defaultBaseclassForTemplates)
if isinstance(baseclass, Template):
baseclass = baseclass.__class__
- vt(baseclass, 'baseclass', [N,S,C,type], 'string, class or None')
+ vt(baseclass, 'baseclass', (N,S,C,type), 'string, class or None')
cacheCompilationResults = valOrDefault(
cacheCompilationResults, klass._CHEETAH_cacheCompilationResults)
- if boolTypeAvailable:
- vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
+ vt(cacheCompilationResults, 'cacheCompilationResults', IB, 'boolean')
useCache = valOrDefault(useCache, klass._CHEETAH_useCompilationCache)
- if boolTypeAvailable:
- vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
+ vt(useCache, 'useCache', IB, 'boolean')
compilerSettings = valOrDefault(
compilerSettings, klass._getCompilerSettings(source, file) or {})
- vt(compilerSettings, 'compilerSettings', [D], 'dictionary')
+ vt(compilerSettings, 'compilerSettings', (D,), 'dictionary')
compilerClass = valOrDefault(compilerClass, klass._getCompilerClass(source, file))
preprocessors = valOrDefault(preprocessors, klass._CHEETAH_preprocessors)
keepRefToGeneratedCode = valOrDefault(
keepRefToGeneratedCode, klass._CHEETAH_keepRefToGeneratedCode)
- if boolTypeAvailable:
- vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
-
- vt(moduleName, 'moduleName', [N,S], 'string or None')
+ vt(keepRefToGeneratedCode, 'keepRefToGeneratedCode', IB, 'boolean')
+
+ vt(moduleName, 'moduleName', NS, 'string or None')
__orig_file__ = None
if not moduleName:
if file and type(file) in StringTypes:
@@ -639,27 +641,26 @@ class Template(Servlet):
__orig_file__ = file
else:
moduleName = klass._CHEETAH_defaultModuleNameForTemplates
-
+
className = valOrDefault(
className, klass._CHEETAH_defaultClassNameForTemplates)
- vt(className, 'className', [N,S], 'string or None')
+ vt(className, 'className', NS, 'string or None')
className = className or moduleName
mainMethodName = valOrDefault(
mainMethodName, klass._CHEETAH_defaultMainMethodNameForTemplates)
- vt(mainMethodName, 'mainMethodName', [N,S], 'string or None')
+ vt(mainMethodName, 'mainMethodName', NS, 'string or None')
moduleGlobals = valOrDefault(
moduleGlobals, klass._CHEETAH_defaultModuleGlobalsForTemplates)
cacheModuleFilesForTracebacks = valOrDefault(
cacheModuleFilesForTracebacks, klass._CHEETAH_cacheModuleFilesForTracebacks)
- if boolTypeAvailable:
- vt(cacheModuleFilesForTracebacks, 'cacheModuleFilesForTracebacks', [I,B], 'boolean')
-
+ vt(cacheModuleFilesForTracebacks, 'cacheModuleFilesForTracebacks', IB, 'boolean')
+
cacheDirForModuleFiles = valOrDefault(
cacheDirForModuleFiles, klass._CHEETAH_cacheDirForModuleFiles)
- vt(cacheDirForModuleFiles, 'cacheDirForModuleFiles', [N,S], 'string or None')
+ vt(cacheDirForModuleFiles, 'cacheDirForModuleFiles', NS, 'string or None')
except TypeError, reason:
raise TypeError(reason)
@@ -1144,26 +1145,24 @@ class Template(Servlet):
D = types.DictType; F = types.FileType
C = types.ClassType; M = types.ModuleType
N = types.NoneType
- vt = VerifyType.VerifyType
- vtc = VerifyType.VerifyTypeClass
+ vt = verifyType
+ vtc = verifyTypeClass
try:
- vt(source, 'source', [N,S,U], 'string or None')
- vt(file, 'file', [N,S,U,F], 'string, file open for reading, or None')
- vtc(filter, 'filter', [S,C,type], 'string or class',
+ vt(source, 'source', (N,S,U), 'string or None')
+ vt(file, 'file', (N,S,U,F), 'string, file open for reading, or None')
+ vtc(filter, 'filter', (S,C,type), 'string or class',
Filters.Filter,
'(if class, must be subclass of Cheetah.Filters.Filter)')
- vt(filtersLib, 'filtersLib', [S,M], 'string or module',
+ vt(filtersLib, 'filtersLib', (S,M), 'string or module',
'(if module, must contain subclasses of Cheetah.Filters.Filter)')
- vtc(errorCatcher, 'errorCatcher', [N,S,C,type], 'string, class or None',
+ vtc(errorCatcher, 'errorCatcher', (N,S,C,type), 'string, class or None',
ErrorCatchers.ErrorCatcher,
'(if class, must be subclass of Cheetah.ErrorCatchers.ErrorCatcher)')
if compilerSettings is not Unspecified:
- vt(compilerSettings, 'compilerSettings', [D], 'dictionary')
+ vt(compilerSettings, 'compilerSettings', (D,), 'dictionary')
- except TypeError, reason:
- # Re-raise the exception here so that the traceback will end in
- # this function rather than in some utility function.
- raise TypeError(reason)
+ except TypeError:
+ raise
if source is not None and file is not None:
raise TypeError("you must supply either a source string or the" +
@@ -1463,7 +1462,7 @@ class Template(Servlet):
# @@TR: consider allowing simple callables as the filter argument
self._CHEETAH__filtersLib = filtersLib
self._CHEETAH__filters = {}
- if type(filter) in StringTypes:
+ if isinstance(filter, basestring):
filterName = filter
klass = getattr(self._CHEETAH__filtersLib, filterName)
else:
@@ -1474,7 +1473,7 @@ class Template(Servlet):
self._CHEETAH__errorCatchers = {}
if errorCatcher:
- if type(errorCatcher) in StringTypes:
+ if isinstance(errorCatcher, basestring):
errorCatcherClass = getattr(ErrorCatchers, errorCatcher)
elif type(errorCatcher) == ClassType:
errorCatcherClass = errorCatcher
diff --git a/cheetah/Tests/Test.py b/cheetah/Tests/Test.py
index e168fc9..fe97ff4 100755
--- a/cheetah/Tests/Test.py
+++ b/cheetah/Tests/Test.py
@@ -41,7 +41,3 @@ if __name__ == '__main__':
results = runner.run(unittest.TestSuite(suites))
-
-
-
-
diff --git a/cheetah/Utils/Indenter.py b/cheetah/Utils/Indenter.py
index 91f50ed..52c142d 100644
--- a/cheetah/Utils/Indenter.py
+++ b/cheetah/Utils/Indenter.py
@@ -1,5 +1,5 @@
-# $Id: Indenter.py,v 1.7 2006/01/08 01:09:30 tavis_rudd Exp $
-"""Indentation maker.
+"""
+Indentation maker.
@@TR: this code is unsupported and largely undocumented ...
This version is based directly on code by Robert Kuzelj
@@ -8,18 +8,7 @@ attributes have been renamed. Indentation is output via
$self._CHEETAH__indenter.indent() to prevent '_indenter' being looked up on the
searchList and another one being found. The directive syntax will
soon be changed somewhat.
-
-Meta-Data
-================================================================================
-Author: Mike Orr <iron@mso.oz.net>
-License: This software is released for unlimited distribution under the
- terms of the MIT license. See the LICENSE file.
-Version: $Revision: 1.7 $
-Start Date: 2001/11/07
-Last Revision Date: $Date: 2006/01/08 01:09:30 $
"""
-__author__ = "Mike Orr <iron@mso.oz.net>"
-__revision__ = "$Revision: 1.7 $"[11:-2]
import re
import sys
@@ -27,7 +16,7 @@ import sys
def indentize(source):
return IndentProcessor().process(source)
-class IndentProcessor:
+class IndentProcessor(object):
"""Preprocess #indent tags."""
LINE_SEP = '\n'
ARGS = "args"
@@ -88,15 +77,16 @@ class IndentProcessor:
return self.LINE_SEP.join(result)
-class Indenter:
- """A class that keeps track of the current indentation level.
+class Indenter(object):
+ """
+ A class that keeps track of the current indentation level.
.indent() returns the appropriate amount of indentation.
"""
- def __init__(self):
- self.On = 1
- self.Level = 0
- self.Chars = " "*4
- self.LevelStack = []
+ On = 1
+ Level = 0
+ Chars = ' '
+ LevelStack = []
+
def on(self):
self.On = 1
def off(self):
@@ -129,6 +119,5 @@ class Indenter:
def indent(self, _default=0):
if self.On:
return self.Chars * self.Level
- else:
- return " " * _default
+ return " " * _default
diff --git a/cheetah/Utils/VerifyType.py b/cheetah/Utils/VerifyType.py
index 520148b..11a435d 100644
--- a/cheetah/Utils/VerifyType.py
+++ b/cheetah/Utils/VerifyType.py
@@ -51,6 +51,7 @@ def VerifyType(arg, argname, legalTypes, ltd, errmsgExtra=''):
if type(arg) not in legalTypes:
m = _errmsg(argname, ltd, errmsgExtra)
raise TypeError(m)
+ return True
def VerifyTypeClass(arg, argname, legalTypes, ltd, klass, errmsgExtra=''):
@@ -71,6 +72,7 @@ def VerifyTypeClass(arg, argname, legalTypes, ltd, klass, errmsgExtra=''):
# Must test for "is class type" to avoid TypeError from issubclass().
m = _errmsg(argname, ltd, errmsgExtra)
raise TypeError(m)
+ return True
# @@MO: Commented until we determine whether it's useful.
#def VerifyClass(arg, argname, klass, ltd):
diff --git a/cheetah/c/Cheetah.h b/cheetah/c/Cheetah.h
new file mode 100644
index 0000000..d149c15
--- /dev/null
+++ b/cheetah/c/Cheetah.h
@@ -0,0 +1,47 @@
+/*
+ * (c) 2009, R. Tyler Ballance <tyler@slide.com>
+ */
+
+#ifndef _CHEETAH_H_
+#define _CHEETAH_H_
+
+#include <Python.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Python 2.3 compatibility
+ */
+#ifndef Py_RETURN_TRUE
+#define Py_RETURN_TRUE Py_INCREF(Py_True);\
+ return Py_True
+#endif
+#ifndef Py_RETURN_FALSE
+#define Py_RETURN_FALSE Py_INCREF(Py_False);\
+ return Py_False
+#endif
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE Py_INCREF(Py_None);\
+ return Py_None
+#endif
+
+
+/*
+ * Filter Module
+ */
+typedef struct {
+ PyObject_HEAD
+ /* type specific fields */
+} PyFilter;
+
+/*
+ * End Filter Module
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cheetah/c/_filters.c b/cheetah/c/_filters.c
new file mode 100644
index 0000000..c81b3bd
--- /dev/null
+++ b/cheetah/c/_filters.c
@@ -0,0 +1,93 @@
+/*
+ * C-version of the src/Filters.py module
+ *
+ * (c) 2009, R. Tyler Ballance <tyler@slide.com>
+ */
+#include <Python.h>
+
+#include "Cheetah.h"
+
+#if __STDC_VERSION__ >= 199901L
+#include <stdbool.h>
+#else
+typedef enum { false, true } bool;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+static PyObject *py_filter(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ Py_RETURN_FALSE;
+}
+
+static const char _filtersdoc[] = "\
+\n\
+";
+static struct PyMethodDef py_filtermethods[] = {
+ {"filter", (PyCFunction)(py_filter), METH_VARARGS | METH_KEYWORDS,
+ PyDoc_STR("Filter stuff")},
+ {NULL},
+};
+static PyTypeObject PyFilterType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_filters.Filter", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "Filter object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ py_filtermethods, /* tp_methods */
+#if 0
+ py_filtermembers, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Noddy_init, /* tp_init */
+ 0, /* tp_alloc */
+ NULL, /* tp_new */
+#endif
+};
+
+PyMODINIT_FUNC init_filters()
+{
+ PyObject *module = Py_InitModule3("_filters", py_filtermethods, _filtersdoc);
+
+ PyFilterType.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&PyFilterType) < 0)
+ return;
+
+ Py_INCREF(&PyFilterType);
+
+ PyModule_AddObject(module, "Filter", (PyObject *)(&PyFilterType));
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/cheetah/_namemapper.c b/cheetah/c/_namemapper.c
index d07769e..d07769e 100644
--- a/cheetah/_namemapper.c
+++ b/cheetah/c/_namemapper.c
diff --git a/cheetah/c/_template.c b/cheetah/c/_template.c
new file mode 100644
index 0000000..2345336
--- /dev/null
+++ b/cheetah/c/_template.c
@@ -0,0 +1,52 @@
+/*
+ * Implementing a few of the functions needed for Template.py in C
+ *
+ * (c) 2009, R. Tyler Ballance <tyler@slide.com>
+ */
+#include <Python.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static PyObject *unspecifiedModule = NULL;
+static PyObject *unspecified = NULL;
+
+static PyObject *py_valordefault(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *value, *def;
+
+ if (!PyArg_ParseTuple(args, "OO", &value, &def))
+ return NULL;
+
+ if (value == unspecified) {
+ Py_XINCREF(def);
+ return def;
+ }
+ Py_XINCREF(value);
+ return value;
+}
+
+static const char _template_doc[] = "\
+\n\
+";
+static struct PyMethodDef _template_methods[] = {
+ {"valOrDefault", (PyCFunction)py_valordefault, METH_VARARGS, NULL},
+ {NULL}
+};
+
+PyMODINIT_FUNC init_template()
+{
+ PyObject *module = Py_InitModule3("_template", _template_methods,
+ _template_doc);
+ unspecifiedModule = PyImport_ImportModule("Cheetah.Unspecified");
+ if ( (PyErr_Occurred()) || (!unspecifiedModule) )
+ return;
+ unspecified = PyObject_GetAttrString(unspecifiedModule, "Unspecified");
+ if (PyErr_Occurred())
+ return;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/cheetah/c/_verifytype.c b/cheetah/c/_verifytype.c
new file mode 100644
index 0000000..6dadf22
--- /dev/null
+++ b/cheetah/c/_verifytype.c
@@ -0,0 +1,107 @@
+/*
+ * C-version of the src/Utils/VerifyType.py module.
+ *
+ * (c) 2009, R. Tyler Ballance <tyler@slide.com>
+ */
+#include <Python.h>
+#if __STDC_VERSION__ >= 199901L
+#include <stdbool.h>
+#else
+typedef enum { false, true } bool;
+#endif
+
+#include "Cheetah.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static PyObject *_errorMessage(char *arg, char *legalTypes, char *extra)
+{
+ return PyString_FromFormat("Argument '%s' must be %s\n", arg, legalTypes);
+}
+
+static PyObject *py_verifytype(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *argument, *legalTypes;
+ char *arg_string, *types_string, *extra;
+ PyObject *iterator, *item;
+ bool rc = false;
+ char *kwlist[] = {"argument", "argument_name", "legalType",
+ "types_string", "errmsgExtra", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OsOs|s", kwlist, &argument,
+ &arg_string, &legalTypes, &types_string, &extra))
+ return NULL;
+
+ iterator = PyObject_GetIter(legalTypes);
+ if (iterator == NULL) {
+ return NULL;
+ }
+
+ while (item = PyIter_Next(iterator)) {
+ if ((PyObject *)argument->ob_type == item) {
+ rc = true;
+ Py_DECREF(item);
+ break;
+ }
+ Py_DECREF(item);
+ }
+ Py_DECREF(iterator);
+
+ if (rc)
+ Py_RETURN_TRUE;
+
+ PyErr_SetObject(PyExc_TypeError, _errorMessage(arg_string,
+ types_string, extra));
+ return NULL;
+}
+
+static PyObject *py_verifytypeclass(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *argument, *legalTypes, *klass;
+ PyObject *verifyTypeArgs, *v;
+ char *arg_string, *types_string, *extra;
+ bool rc = false;
+
+ char *kwlist[] = {"argument", "argument_name", "legalTypes",
+ "types_string", "klass", "errmsgExtra", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OsOsO|s", kwlist, &argument,
+ &arg_string, &legalTypes, &types_string, &klass, &extra))
+ return NULL;
+
+ verifyTypeArgs = Py_BuildValue("OsOs", argument, arg_string, legalTypes,
+ types_string);
+ v = py_verifytype(self, verifyTypeArgs, NULL);
+
+ if (v == NULL)
+ return NULL;
+ Py_DECREF(v);
+
+ if (PyClass_Check(argument) && (!PyClass_IsSubclass(argument, klass)) ) {
+ PyErr_SetObject(PyExc_TypeError, _errorMessage(arg_string,
+ types_string, extra));
+ return NULL;
+ }
+ Py_RETURN_TRUE;
+}
+
+static const char _verifytypedoc[] = "\
+\n\
+";
+static struct PyMethodDef _verifytype_methods[] = {
+ {"verifyType", (PyCFunction)py_verifytype, METH_VARARGS | METH_KEYWORDS, NULL},
+ {"verifyTypeClass", (PyCFunction)py_verifytypeclass, METH_VARARGS | METH_KEYWORDS, NULL},
+ {NULL}
+};
+
+PyMODINIT_FUNC init_verifytype()
+{
+ PyObject *module = Py_InitModule3("_verifytype", _verifytype_methods,
+ _verifytypedoc);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/Tests/Performance.py b/src/Tests/Performance.py
new file mode 100644
index 0000000..db721f9
--- /dev/null
+++ b/src/Tests/Performance.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python
+
+import Cheetah.NameMapper
+import Cheetah.Template
+from Cheetah.Utils import statprof
+
+import os
+import sys
+import unittest
+
+from test import pystone
+import time
+
+# This can be turned on with the `--debug` flag when running the test
+# and will cause the tests to all just dump out how long they took
+# insteasd of asserting on duration
+DEBUG = False
+
+# TOLERANCE in Pystones
+kPS = 1000
+TOLERANCE = 0.5*kPS
+
+class DurationError(AssertionError):
+ pass
+
+_pystone_calibration_mark = None
+def _pystone_calibration():
+ global _pystone_calibration_mark
+ if not _pystone_calibration_mark:
+ _pystone_calibration_mark = pystone.pystones(loops=pystone.LOOPS)
+ return _pystone_calibration_mark
+
+def perftest(max_num_pystones, current_pystone=None):
+ '''
+ Performance test decorator based off the 'timedtest'
+ decorator found in this Active State recipe:
+ http://code.activestate.com/recipes/440700/
+ '''
+ if not isinstance(max_num_pystones, float):
+ max_num_pystones = float(max_num_pystones)
+
+ if not current_pystone:
+ current_pystone = _pystone_calibration()
+
+ def _test(function):
+ def wrapper(*args, **kw):
+ start_time = time.time()
+ try:
+ return function(*args, **kw)
+ finally:
+ total_time = time.time() - start_time
+ if total_time == 0:
+ pystone_total_time = 0
+ else:
+ pystone_rate = current_pystone[0] / current_pystone[1]
+ pystone_total_time = total_time / pystone_rate
+ global DEBUG
+ if DEBUG:
+ print 'The test "%s" took: %s pystones' % (function.func_name,
+ pystone_total_time)
+ else:
+ if pystone_total_time > (max_num_pystones + TOLERANCE):
+ raise DurationError((('Test too long (%.2f Ps, '
+ 'need at most %.2f Ps)')
+ % (pystone_total_time,
+ max_num_pystones)))
+ return wrapper
+ return _test
+
+
+class DynamicTemplatePerformanceTest(unittest.TestCase):
+ loops = 10
+ @perftest(1200)
+ def test_BasicDynamic(self):
+ template = '''
+ #def foo(arg1, arg2)
+ #pass
+ #end def
+ '''
+ for i in xrange(self.loops):
+ klass = Cheetah.Template.Template.compile(template)
+ assert klass
+
+class PerformanceTest(unittest.TestCase):
+ iterations = 1000000
+ display = False
+ def setUp(self):
+ super(PerformanceTest, self).setUp()
+ statprof.start()
+
+ def runTest(self):
+ for i in xrange(self.iterations):
+ if hasattr(self, 'performanceSample'):
+ self.display = True
+ self.performanceSample()
+
+ def tearDown(self):
+ super(PerformanceTest, self).tearDown()
+ statprof.stop()
+ if self.display:
+ print '>>> %s (%d iterations) ' % (self.__class__.__name__,
+ self.iterations)
+ statprof.display()
+
+class DynamicMethodCompilationTest(PerformanceTest):
+ def performanceSample(self):
+ template = '''
+ #import sys
+ #import os
+ #def testMethod()
+ #set foo = [1, 2, 3, 4]
+ #return $foo[0]
+ #end def
+ '''
+ template = Cheetah.Template.Template.compile(template,
+ keepRefToGeneratedCode=False)
+ template = template()
+ value = template.testMethod()
+
+class DynamicSimpleCompilationTest(PerformanceTest):
+ def performanceSample(self):
+ template = '''
+ #import sys
+ #import os
+ #set foo = [1,2,3,4]
+
+ Well hello there! This is basic.
+
+ Here's an array too: $foo
+ '''
+ template = Cheetah.Template.Template.compile(template,
+ keepRefToGeneratedCode=False)
+ template = template()
+ template = unicode(template)
+
+
+class FilterTest(PerformanceTest):
+ template = None
+ def setUp(self):
+ super(FilterTest, self).setUp()
+ template = '''
+ #import sys
+ #import os
+ #set foo = [1, 2, 3, 4]
+
+ $foo, $foo, $foo
+ '''
+ template = Cheetah.Template.Template.compile(template,
+ keepRefToGeneratedCode=False)
+ self.template = template()
+
+ def performanceSample(self):
+ value = unicode(self.template)
+
+
+class LongCompileTest(PerformanceTest):
+ ''' Test the compilation on a sufficiently large template '''
+ def compile(self, template):
+ return Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False)
+
+ def performanceSample(self):
+ template = '''
+ #import sys
+ #import Cheetah.Template
+
+ #extends Cheetah.Template.Template
+
+ #def header()
+ <center><h2>This is my header</h2></center>
+ #end def
+
+ #def footer()
+ #return "Huzzah"
+ #end def
+
+ #def scripts()
+ #pass
+ #end def
+
+ #def respond()
+ <html>
+ <head>
+ <title>${title}</title>
+
+ $scripts()
+ </head>
+ <body>
+ $header()
+
+ #for $i in $xrange(10)
+ This is just some stupid page!
+ <br/>
+ #end for
+
+ <br/>
+ $footer()
+ </body>
+ </html>
+ #end def
+
+ '''
+ return self.compile(template)
+
+class LongCompile_CompilerSettingsTest(LongCompileTest):
+ def compile(self, template):
+ return Cheetah.Template.Template.compile(template, keepRefToGeneratedCode=False,
+ compilerSettings={'useStackFrames' : True, 'useAutocalling' : True})
+
+class LongCompileAndRun(LongCompileTest):
+ def performanceSample(self):
+ template = super(LongCompileAndRun, self).performanceSample()
+ template = template(searchList=[{'title' : 'foo'}])
+ template = template.respond()
+
+
+if __name__ == '__main__':
+ if '--debug' in sys.argv:
+ DEBUG = True
+ sys.argv = [arg for arg in sys.argv if not arg == '--debug']
+ unittest.main()
diff --git a/src/Tests/VerifyType.py b/src/Tests/VerifyType.py
new file mode 100644
index 0000000..7cab587
--- /dev/null
+++ b/src/Tests/VerifyType.py
@@ -0,0 +1,157 @@
+import unittest
+
+from Cheetah.Utils import VerifyType
+from Cheetah import _verifytype
+
+class VerifyType_Test(unittest.TestCase):
+ def test_Verified(self):
+ arg = 'foo'
+ legalTypes = [str, unicode]
+ try:
+ rc = VerifyType.VerifyType(arg, 'arg', legalTypes, 'string')
+ assert rc
+ except TypeError:
+ self.fail('Should not have raised a TypeError here')
+
+ try:
+ rc = _verifytype.verifyType(arg, 'arg', legalTypes, 'string')
+ assert rc
+ except TypeError:
+ self.fail('Should not have raised a TypeError here')
+
+ def test_Unverified(self):
+ arg = 'foo'
+ legalTypes = [list, dict]
+ self.failUnlessRaises(TypeError, VerifyType.VerifyType, arg,
+ 'arg', legalTypes, 'list or dict')
+ self.failUnlessRaises(TypeError, _verifytype.verifyType, arg,
+ 'arg', legalTypes, 'list or dict')
+
+ def test_IncorrectNumberOfArgs(self):
+ arg = 'foo'
+ legalTypes = [str, unicode]
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyType)
+ self.failUnlessRaises(TypeError, _verifytype.verifyType)
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyType, arg)
+ self.failUnlessRaises(TypeError, _verifytype.verifyType, arg)
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyType, arg,
+ 'arg')
+ self.failUnlessRaises(TypeError, _verifytype.verifyType, arg,
+ 'arg')
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyType, arg,
+ 'arg', legalTypes)
+ self.failUnlessRaises(TypeError, _verifytype.verifyType, arg,
+ 'arg', legalTypes)
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyType, arg,
+ 'arg', legalTypes, 'string', 'errmsgExtra', 'one more')
+ self.failUnlessRaises(TypeError, _verifytype.verifyType, arg,
+ 'arg', legalTypes, 'string', 'errmsgExtra', 'one more')
+
+ def test_LegalTypesNotIterable(self):
+ arg = 'foo'
+ legalTypes = 1
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyType, arg,
+ 'arg', legalTypes, 'string')
+ self.failUnlessRaises(TypeError, _verifytype.verifyType, arg,
+ 'arg', legalTypes, 'string')
+
+class FakeClass(dict):
+ pass
+
+class VerifyTypeClass_Test(unittest.TestCase):
+ def test_VerifiedClass(self):
+ arg = FakeClass
+ legalTypes = [type]
+ try:
+ rc = VerifyType.VerifyTypeClass(arg, 'arg', legalTypes, '', dict)
+ assert rc
+ except TypeError:
+ self.fail('Should not have raised a TypeError here')
+
+ try:
+ rc = _verifytype.verifyTypeClass(arg, 'arg', legalTypes, 'foo', dict)
+ assert rc
+ except TypeError:
+ self.fail('Should not have raised a TypeError here')
+
+ def test_UnverifiedClass(self):
+ arg = FakeClass
+ legalTypes = [type]
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass, arg,
+ legalTypes, 'subclass of list', list)
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass, arg,
+ legalTypes, 'subclass of list', list)
+
+ def test_Verified(self):
+ arg = 'foo'
+ legalTypes = [str, unicode]
+ try:
+ rc = VerifyType.VerifyTypeClass(arg, 'arg', legalTypes, 'string', int)
+ assert rc
+ except TypeError:
+ self.fail('Should not have raised a TypeError here')
+
+ try:
+ rc = _verifytype.verifyTypeClass(arg, 'arg', legalTypes, 'string', int)
+ assert rc
+ except TypeError:
+ self.fail('Should not have raised a TypeError here')
+
+ def test_Unverified(self):
+ arg = 'foo'
+ legalTypes = [list, dict]
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass, arg,
+ 'arg', legalTypes, 'list or dict', int)
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass, arg,
+ 'arg', legalTypes, 'list or dict', int)
+
+ def test_IncorrectNumberOfArgs(self):
+ arg = 'foo'
+ legalTypes = [str, unicode]
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass)
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass)
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass, arg)
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass, arg)
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass, arg,
+ 'arg')
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass, arg,
+ 'arg')
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass, arg,
+ 'arg', legalTypes)
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass, arg,
+ 'arg', legalTypes)
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass, arg,
+ 'arg', legalTypes, 'string')
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass, arg,
+ 'arg', legalTypes, 'string')
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass, arg,
+ 'arg', legalTypes, 'string', int, 'errmsgExtra', 'one more')
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass, arg,
+ 'arg', legalTypes, 'string', int, 'errmsgExtra', 'one more')
+
+ def test_LegalTypesNotIterable(self):
+ arg = 'foo'
+ legalTypes = 1
+
+ self.failUnlessRaises(TypeError, VerifyType.VerifyTypeClass, arg,
+ 'arg', legalTypes, 'string', int)
+ self.failUnlessRaises(TypeError, _verifytype.verifyTypeClass, arg,
+ 'arg', legalTypes, 'string', int)
+
+
+
+
+if __name__ == '__main__':
+ unittest.main()