summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Theune <ct@gocept.com>2007-05-03 22:03:01 +0000
committerChristian Theune <ct@gocept.com>2007-05-03 22:03:01 +0000
commit2ebf067dfa2240dba61d1bea74c6e1512d7a00a3 (patch)
tree61bc6c611597b0482c3b6ad62f79cdbbaa683f37 /src
parent0c2693453c7ee1e834c7f9f9d4242c23fa45f166 (diff)
parenta08873b406e83ca483894ee28b309b106ed22205 (diff)
downloadzope-pagetemplate-2ebf067dfa2240dba61d1bea74c6e1512d7a00a3.tar.gz
Moving code to satellite.
Diffstat (limited to 'src')
-rw-r--r--src/zope/pagetemplate/DEPENDENCIES.cfg3
-rw-r--r--src/zope/pagetemplate/__init__.py17
-rw-r--r--src/zope/pagetemplate/architecture.txt32
-rw-r--r--src/zope/pagetemplate/interfaces.py114
-rw-r--r--src/zope/pagetemplate/pagetemplate.py212
-rw-r--r--src/zope/pagetemplate/pagetemplatefile.py134
-rw-r--r--src/zope/pagetemplate/readme.txt67
-rw-r--r--src/zope/pagetemplate/tests/__init__.py2
-rw-r--r--src/zope/pagetemplate/tests/batch.py118
-rw-r--r--src/zope/pagetemplate/tests/input/__init__.py2
-rw-r--r--src/zope/pagetemplate/tests/input/checknotexpression.html9
-rw-r--r--src/zope/pagetemplate/tests/input/checknothing.html7
-rw-r--r--src/zope/pagetemplate/tests/input/checkpathalt.html17
-rw-r--r--src/zope/pagetemplate/tests/input/checkpathnothing.html7
-rw-r--r--src/zope/pagetemplate/tests/input/checkwithxmlheader.html5
-rw-r--r--src/zope/pagetemplate/tests/input/dtml1.html19
-rw-r--r--src/zope/pagetemplate/tests/input/dtml3.html33
-rw-r--r--src/zope/pagetemplate/tests/input/globalsshadowlocals.html14
-rw-r--r--src/zope/pagetemplate/tests/input/loop1.html15
-rw-r--r--src/zope/pagetemplate/tests/input/stringexpression.html7
-rw-r--r--src/zope/pagetemplate/tests/input/teeshop1.html87
-rw-r--r--src/zope/pagetemplate/tests/input/teeshop2.html5
-rw-r--r--src/zope/pagetemplate/tests/input/teeshoplaf.html73
-rw-r--r--src/zope/pagetemplate/tests/input/translation.html2
-rw-r--r--src/zope/pagetemplate/tests/output/__init__.py2
-rw-r--r--src/zope/pagetemplate/tests/output/checknotexpression.html9
-rw-r--r--src/zope/pagetemplate/tests/output/checknothing.html7
-rw-r--r--src/zope/pagetemplate/tests/output/checkpathalt.html17
-rw-r--r--src/zope/pagetemplate/tests/output/checkpathnothing.html7
-rw-r--r--src/zope/pagetemplate/tests/output/checkwithxmlheader.html4
-rw-r--r--src/zope/pagetemplate/tests/output/dtml1a.html34
-rw-r--r--src/zope/pagetemplate/tests/output/dtml1b.html7
-rw-r--r--src/zope/pagetemplate/tests/output/dtml3.html30
-rw-r--r--src/zope/pagetemplate/tests/output/globalsshadowlocals.html14
-rw-r--r--src/zope/pagetemplate/tests/output/loop1.html25
-rw-r--r--src/zope/pagetemplate/tests/output/stringexpression.html7
-rw-r--r--src/zope/pagetemplate/tests/output/teeshop1.html106
-rw-r--r--src/zope/pagetemplate/tests/output/teeshop2.html50
-rw-r--r--src/zope/pagetemplate/tests/output/teeshoplaf.html73
-rw-r--r--src/zope/pagetemplate/tests/output/translation.html2
-rw-r--r--src/zope/pagetemplate/tests/test_basictemplate.py162
-rw-r--r--src/zope/pagetemplate/tests/test_htmltests.py143
-rw-r--r--src/zope/pagetemplate/tests/test_ptfile.py189
-rw-r--r--src/zope/pagetemplate/tests/testpackage/__init__.py2
-rw-r--r--src/zope/pagetemplate/tests/testpackage/content.py28
-rw-r--r--src/zope/pagetemplate/tests/testpackage/view.pt1
-rw-r--r--src/zope/pagetemplate/tests/util.py111
47 files changed, 2031 insertions, 0 deletions
diff --git a/src/zope/pagetemplate/DEPENDENCIES.cfg b/src/zope/pagetemplate/DEPENDENCIES.cfg
new file mode 100644
index 0000000..bcd721a
--- /dev/null
+++ b/src/zope/pagetemplate/DEPENDENCIES.cfg
@@ -0,0 +1,3 @@
+zope.interface
+zope.tal
+zope.tales
diff --git a/src/zope/pagetemplate/__init__.py b/src/zope/pagetemplate/__init__.py
new file mode 100644
index 0000000..0824ece
--- /dev/null
+++ b/src/zope/pagetemplate/__init__.py
@@ -0,0 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Page Templates
+
+$Id$
+"""
diff --git a/src/zope/pagetemplate/architecture.txt b/src/zope/pagetemplate/architecture.txt
new file mode 100644
index 0000000..637b028
--- /dev/null
+++ b/src/zope/pagetemplate/architecture.txt
@@ -0,0 +1,32 @@
+=====================================
+ZPT (Zope Page-Template) Architecture
+=====================================
+
+There are a number of major components that make up the page-template
+architecture:
+
+- The TAL *compiler* and *interpreter*. This is responsible for
+ compiling source files and for executing compiled templates. See
+ the `zope.tal` package for more information.
+
+- An *expression engine* is responsible for compiling expressions and
+ for creating expression execution contexts. It is common for
+ applications to override expression engines to provide custom
+ expression support or to change the way expressions are implemented.
+ The `zope.app.pagetemplate` package uses this to implement trusted
+ and untrusted evaluation; a different engine is used for each, with
+ different implementations of the same type of expressions.
+
+ Expression contexts support execution of expressions and provide
+ APIs for setting up variable scopes and setting variables. The
+ expression contexts are passed to the TAL interpreter at execution
+ time.
+
+ The most commonly used expression implementation is that found in
+ `zope.tales`.
+
+- Page templates tie everything together. They assemble an expression
+ engine with the TAL interpreter and orchestrate management of source
+ and compiled template data. See `zope.pagetemplate.interfaces`.
+
+
diff --git a/src/zope/pagetemplate/interfaces.py b/src/zope/pagetemplate/interfaces.py
new file mode 100644
index 0000000..41f7451
--- /dev/null
+++ b/src/zope/pagetemplate/interfaces.py
@@ -0,0 +1,114 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interface that describes the 'macros' attribute of a PageTemplate.
+
+$Id$
+"""
+from zope.interface import Interface, Attribute
+
+
+class IPageTemplate(Interface):
+ """Objects that can render page templates
+ """
+
+ def __call__(*args, **kw):
+ """Render a page template
+
+ The argument handling is specific to particular
+ implementations. Normally, however, positional arguments are
+ bound to the top-level `args` variable and keyword arguments
+ are bound to the top-level `options` variable.
+ """
+
+ def pt_edit(source, content_type):
+ """Set the source and content type
+ """
+
+ def pt_errors(namespace):
+ """Return a sequence of strings that describe errors in the template.
+
+ The errors may occur when the template is compiled or
+ rendered.
+
+ `namespace` is the set of names passed to the TALES expression
+ evaluator, similar to what's returned by pt_getContext().
+
+ This can be used to let a template author know what went wrong
+ when an attempt was made to render the template.
+ """
+
+ def pt_warnings():
+ """Return a sequence of warnings from the parser.
+
+ This can be useful to present to the template author to
+ indication forward compatibility problems with the template.
+ """
+
+ def read():
+ """Get the template source
+ """
+
+ macros = Attribute("An object that implements the __getitem__ "
+ "protocol, containing page template macros.")
+
+class IPageTemplateSubclassing(IPageTemplate):
+ """Behavior that may be overridden or used by subclasses
+ """
+
+
+ def pt_getContext(**kw):
+ """Compute a dictionary of top-level template names
+
+ Responsible for returning the set of
+ top-level names supported in path expressions
+
+ """
+
+ def pt_getEngine():
+ """Returns the TALES expression evaluator.
+ """
+
+ def pt_getEngineContext(namespace):
+ """Return an execution context from the expression engine."""
+
+ def __call__(*args, **kw):
+ """Render a page template
+
+ This is sometimes overridden to provide additional argument
+ binding.
+ """
+
+ def pt_source_file():
+ """return some text describing where a bit of ZPT code came from.
+
+ This could be a file path, a object path, etc.
+ """
+
+ def _cook():
+ """Compile the source
+
+ Results are saved in the variables: _v_errors, _v_warnings,
+ _v_program, and _v_macros, and the flag _v_cooked is set.
+ """
+ def _cook_check():
+ """Compiles the source if necessary
+
+ Subclasses might override this to influence the decision about
+ whether compilation is necessary.
+ """
+
+ content_type = Attribute("The content-type of the generated output")
+
+ expand = Attribute(
+ "Flag indicating whether the read method should expand macros")
diff --git a/src/zope/pagetemplate/pagetemplate.py b/src/zope/pagetemplate/pagetemplate.py
new file mode 100644
index 0000000..ea26cc1
--- /dev/null
+++ b/src/zope/pagetemplate/pagetemplate.py
@@ -0,0 +1,212 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Page Template module
+
+HTML- and XML-based template objects using TAL, TALES, and METAL.
+
+$Id$
+"""
+import sys
+from zope.tal.talparser import TALParser
+from zope.tal.htmltalparser import HTMLTALParser
+from zope.tal.talgenerator import TALGenerator
+from zope.tal.talinterpreter import TALInterpreter
+from zope.tales.engine import Engine
+# Don't use cStringIO here! It's not unicode aware.
+from StringIO import StringIO
+
+from zope.pagetemplate.interfaces import IPageTemplateSubclassing
+from zope.interface import implements
+
+
+_default_options = {}
+_error_start = '<!-- Page Template Diagnostics'
+
+class PageTemplate(object):
+ """Page Templates using TAL, TALES, and METAL.
+
+ Subclassing
+ -----------
+
+ The following methods have certain internal responsibilities.
+
+ pt_getContext(**keywords)
+ Should ignore keyword arguments that it doesn't care about,
+ and construct the namespace passed to the TALES expression
+ engine. This method is free to use the keyword arguments it
+ receives.
+
+ pt_render(namespace, source=False, sourceAnnotations=False, showtal=False)
+ Responsible the TAL interpreter to perform the rendering. The
+ namespace argument is a mapping which defines the top-level
+ namespaces passed to the TALES expression engine.
+
+ __call__(*args, **keywords)
+ Calls pt_getContext() to construct the top-level namespace
+ passed to the TALES expression engine, then calls pt_render()
+ to perform the rendering.
+ """
+
+ implements(IPageTemplateSubclassing)
+
+ content_type = 'text/html'
+ expand = 1
+ _v_errors = ()
+ _v_program = None
+ _v_macros = None
+ _v_cooked = 0
+ _text = ''
+
+ def macros(self):
+ self._cook_check()
+ return self._v_macros
+
+ macros = property(macros)
+
+ def pt_edit(self, text, content_type):
+ if content_type:
+ self.content_type = str(content_type)
+ if hasattr(text, 'read'):
+ text = text.read()
+ self.write(text)
+
+ def pt_getContext(self, args=(), options=_default_options, **ignored):
+ rval = {'template': self,
+ 'options': options,
+ 'args': args,
+ 'nothing': None,
+ }
+ rval.update(self.pt_getEngine().getBaseNames())
+ return rval
+
+ def __call__(self, *args, **kwargs):
+ return self.pt_render(self.pt_getContext(args, kwargs))
+
+ def pt_getEngineContext(self, namespace):
+ return self.pt_getEngine().getContext(namespace)
+
+ def pt_getEngine(self):
+ return Engine
+
+ def pt_render(self, namespace, source=False, sourceAnnotations=False,
+ showtal=False):
+ """Render this Page Template"""
+ self._cook_check()
+ __traceback_supplement__ = (PageTemplateTracebackSupplement,
+ self, namespace)
+ if self._v_errors:
+ raise PTRuntimeError(str(self._v_errors))
+
+ output = StringIO(u'')
+ context = self.pt_getEngineContext(namespace)
+ TALInterpreter(self._v_program, self._v_macros,
+ context, output, tal=not source, showtal=showtal,
+ strictinsert=0, sourceAnnotations=sourceAnnotations)()
+ return output.getvalue()
+
+ def pt_errors(self, namespace):
+ self._cook_check()
+ err = self._v_errors
+ if err:
+ return err
+ try:
+ self.pt_render(namespace, source=1)
+ except:
+ return ('Macro expansion failed', '%s: %s' % sys.exc_info()[:2])
+
+ def write(self, text):
+ # We accept both, since the text can either come from a file (and the
+ # parser will take care of the encoding) or from a TTW template, in
+ # which case we already have unicode.
+ assert isinstance(text, (str, unicode))
+
+ if text.startswith(_error_start):
+ errend = text.find('-->')
+ if errend >= 0:
+ text = text[errend + 3:]
+ if text[:1] == "\n":
+ text = text[1:]
+ if self._text != text:
+ self._text = text
+
+ # Always cook on an update, even if the source is the same;
+ # the content-type might have changed.
+ self._cook()
+
+ def read(self, request=None):
+ """Gets the source, sometimes with macros expanded."""
+ self._cook_check()
+ if not self._v_errors:
+ if not self.expand:
+ return self._text
+ try:
+ # This gets called, if macro expansion is turned on.
+ # Note that an empty dictionary is fine for the context at
+ # this point, since we are not evaluating the template.
+ return self.pt_render(self.pt_getContext(self, request), source=1)
+ except:
+ return ('%s\n Macro expansion failed\n %s\n-->\n%s' %
+ (_error_start, "%s: %s" % sys.exc_info()[:2],
+ self._text) )
+
+ return ('%s\n %s\n-->\n%s' % (_error_start,
+ '\n'.join(self._v_errors),
+ self._text))
+
+ def pt_source_file(self):
+ """To be overridden."""
+ return None
+
+ def _cook_check(self):
+ if not self._v_cooked:
+ self._cook()
+
+ def _cook(self):
+ """Compile the TAL and METAL statments.
+
+ Cooking must not fail due to compilation errors in templates.
+ """
+ engine = self.pt_getEngine()
+ source_file = self.pt_source_file()
+ if self.content_type == 'text/html':
+ gen = TALGenerator(engine, xml=0, source_file=source_file)
+ parser = HTMLTALParser(gen)
+ else:
+ gen = TALGenerator(engine, source_file=source_file)
+ parser = TALParser(gen)
+
+ self._v_errors = ()
+ try:
+ parser.parseString(self._text)
+ self._v_program, self._v_macros = parser.getCode()
+ except:
+ self._v_errors = ["Compilation failed",
+ "%s: %s" % sys.exc_info()[:2]]
+ self._v_cooked = 1
+
+
+class PTRuntimeError(RuntimeError):
+ '''The Page Template has template errors that prevent it from rendering.'''
+ pass
+
+
+class PageTemplateTracebackSupplement(object):
+ #implements(ITracebackSupplement)
+
+ def __init__(self, pt, namespace):
+ self.manageable_object = pt
+ self.warnings = []
+ e = pt.pt_errors(namespace)
+ if e:
+ self.warnings.extend(e)
diff --git a/src/zope/pagetemplate/pagetemplatefile.py b/src/zope/pagetemplate/pagetemplatefile.py
new file mode 100644
index 0000000..4fe6f0f
--- /dev/null
+++ b/src/zope/pagetemplate/pagetemplatefile.py
@@ -0,0 +1,134 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Filesystem Page Template module
+
+Zope object encapsulating a Page Template from the filesystem.
+
+$Id$
+"""
+
+__all__ = ("PageTemplateFile",)
+
+import os
+import sys
+import re
+import logging
+
+from zope.pagetemplate.pagetemplate import PageTemplate
+
+DEFAULT_ENCODING = "utf-8"
+
+meta_pattern = re.compile(
+ r'\s*<meta\s+http-equiv=["\']?Content-Type["\']?'
+ r'\s+content=["\']?([^;]+);\s*charset=([^"\']+)["\']?\s*/?\s*>\s*',
+ re.IGNORECASE)
+
+def package_home(gdict):
+ filename = gdict["__file__"]
+ return os.path.dirname(filename)
+
+class PageTemplateFile(PageTemplate):
+ "Zope wrapper for filesystem Page Template using TAL, TALES, and METAL"
+
+ _v_last_read = 0
+
+ def __init__(self, filename, _prefix=None):
+ path = self.get_path_from_prefix(_prefix)
+ self.filename = os.path.join(path, filename)
+ if not os.path.isfile(self.filename):
+ raise ValueError("No such file", self.filename)
+
+ def get_path_from_prefix(self, _prefix):
+ if isinstance(_prefix, str):
+ path = _prefix
+ else:
+ if _prefix is None:
+ _prefix = sys._getframe(2).f_globals
+ path = package_home(_prefix)
+ return path
+
+ def _prepare_html(self, text):
+ match = meta_pattern.search(text)
+ if match is not None:
+ type_, encoding = match.groups()
+ # TODO: Shouldn't <meta>/<?xml?> stripping
+ # be in PageTemplate.__call__()?
+ text = meta_pattern.sub("", text)
+ else:
+ type_ = None
+ encoding = DEFAULT_ENCODING
+ return unicode(text, encoding), type_
+
+ def _read_file(self):
+ __traceback_info__ = self.filename
+ f = open(self.filename, "rb")
+ try:
+ text = f.read(XML_PREFIX_MAX_LENGTH)
+ except:
+ f.close()
+ raise
+ type_ = sniff_type(text)
+ if type_ == "text/xml":
+ text += f.read()
+ else:
+ # For HTML, we really want the file read in text mode:
+ f.close()
+ f = open(self.filename)
+ text = f.read()
+ text, type_ = self._prepare_html(text)
+ f.close()
+ return text, type_
+
+ def _cook_check(self):
+ if self._v_last_read and not __debug__:
+ return
+ __traceback_info__ = self.filename
+ try:
+ mtime = os.path.getmtime(self.filename)
+ except OSError:
+ mtime = 0
+ if self._v_program is not None and mtime == self._v_last_read:
+ return
+ text, type_ = self._read_file()
+ self.pt_edit(text, type_)
+ self._cook()
+ if self._v_errors:
+ logging.error('PageTemplateFile: Error in template %s: %s',
+ self.filename, '\n'.join(self._v_errors))
+ return
+ self._v_last_read = mtime
+
+ def pt_source_file(self):
+ return self.filename
+
+ def __getstate__(self):
+ raise TypeError("non-picklable object")
+
+XML_PREFIXES = [
+ "<?xml", # ascii, utf-8
+ "\xef\xbb\xbf<?xml", # utf-8 w/ byte order mark
+ "\0<\0?\0x\0m\0l", # utf-16 big endian
+ "<\0?\0x\0m\0l\0", # utf-16 little endian
+ "\xfe\xff\0<\0?\0x\0m\0l", # utf-16 big endian w/ byte order mark
+ "\xff\xfe<\0?\0x\0m\0l\0", # utf-16 little endian w/ byte order mark
+ ]
+
+XML_PREFIX_MAX_LENGTH = max(map(len, XML_PREFIXES))
+
+def sniff_type(text):
+ """Return 'text/xml' if text appears to be XML, otherwise return None."""
+ for prefix in XML_PREFIXES:
+ if text.startswith(prefix):
+ return "text/xml"
+ return None
diff --git a/src/zope/pagetemplate/readme.txt b/src/zope/pagetemplate/readme.txt
new file mode 100644
index 0000000..e73b916
--- /dev/null
+++ b/src/zope/pagetemplate/readme.txt
@@ -0,0 +1,67 @@
+==============
+Page Templates
+==============
+
+:Author: Kapil Thangavelu <hazmat at objectrealms.net>
+
+.. contents::
+
+
+Introduction
+------------
+
+Page Templates provide an elegant templating mechanism that achieves a
+clean separation of presentation and application logic while allowing
+for designers to work with templates in their visual editing tools
+(FrontPage, Dreamweaver, GoLive, etc.).
+
+This document focuses on usage of Page Templates outside of a Zope
+context, it does *not* explain how to write page templates as there
+are several resources on the web which do so.
+
+Simple Usage
+------------
+
+Using Page Templates outside of Zope3 is very easy and straight
+forward. A quick example::
+
+ >>> from zope.pagetemplate.pagetemplatefile import PageTemplateFile
+ >>> my_pt = PageTemplateFile('hello_world.pt')
+ >>> my_pt()
+ u'<html><body>Hello World</body></html>'
+
+Subclassing PageTemplates
+-------------------------
+
+Lets say we want to alter page templates such that keyword arguments
+appear as top level items in the namespace. We can subclass
+`PageTemplate` and alter the default behavior of `pt_getContext()` to
+add them in::
+
+ from zope.pagetemplate.pagetemplate import PageTemplate
+
+ class mypt(PageTemplate):
+ def pt_getContext(self, args=(), options={}, **kw):
+ rval = PageTemplate.pt_getContext(self, args=args)
+ options.update(rval)
+ return options
+
+ class foo:
+ def getContents(self): return 'hi'
+
+So now we can bind objects in a more arbitrary fashion, like the
+following::
+
+ template = """
+ <html>
+ <body>
+ <b tal:replace="das_object/getContents">Good Stuff Here</b>
+ </body>
+ </html>
+ """
+
+ pt = mypt()
+ pt.write(template)
+ pt(das_object=foo())
+
+See `interfaces.py`.
diff --git a/src/zope/pagetemplate/tests/__init__.py b/src/zope/pagetemplate/tests/__init__.py
new file mode 100644
index 0000000..b711d36
--- /dev/null
+++ b/src/zope/pagetemplate/tests/__init__.py
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
diff --git a/src/zope/pagetemplate/tests/batch.py b/src/zope/pagetemplate/tests/batch.py
new file mode 100644
index 0000000..ec1057c
--- /dev/null
+++ b/src/zope/pagetemplate/tests/batch.py
@@ -0,0 +1,118 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Batching support tests
+
+$Id$
+"""
+
+class batch(object):
+ """Create a sequence batch"""
+
+ def __init__(self, sequence, size, start=0, end=0,
+ orphan=3, overlap=0):
+
+ start=start+1
+
+ start,end,sz=opt(start,end,size,orphan,sequence)
+
+ self._last=end-1
+ self._first=start-1
+
+ self._sequence=sequence
+ self._size=size
+ self._start=start
+ self._end=end
+ self._orphan=orphan
+ self._overlap=overlap
+
+ def previous_sequence(self): return self._first
+
+ def previous_sequence_end_number(self):
+ start,end,spam=opt(0, self._start-1+self._overlap,
+ self._size, self._orphan, self._sequence)
+ return end
+
+ def previous_sequence_start_number(self):
+ start,end,spam=opt(0, self._start-1+self._overlap,
+ self._size, self._orphan, self._sequence)
+ return start
+
+ def previous_sequence_end_item(self):
+ start,end,spam=opt(0, self._start-1+self._overlap,
+ self._size, self._orphan, self._sequence)
+ return self._sequence[end-1]
+
+ def previous_sequence_start_item(self):
+ start,end,spam=opt(0, self._start-1+self._overlap,
+ self._size, self._orphan, self._sequence)
+ return self._sequence[start-1]
+
+ def next_sequence_end_number(self):
+ start,end,spam=opt(self._end+1-self._overlap, 0,
+ self._size, self._orphan, self._sequence)
+ return end
+
+ def next_sequence_start_number(self):
+ start,end,spam=opt(self._end+1-self._overlap, 0,
+ self._size, self._orphan, self._sequence)
+ return start
+
+ def next_sequence_end_item(self):
+ start,end,spam=opt(self._end+1-self._overlap, 0,
+ self._size, self._orphan, self._sequence)
+ return self._sequence[end-1]
+
+ def next_sequence_start_item(self):
+ start,end,spam=opt(self._end+1-self._overlap, 0,
+ self._size, self._orphan, self._sequence)
+ return self._sequence[start-1]
+
+
+ def next_sequence(self):
+ try: self._sequence[self._end]
+ except IndexError: return 0
+ else: return 1
+
+ def __getitem__(self, index):
+ if index > self._last: raise IndexError(index)
+ return self._sequence[index+self._first]
+
+def opt(start,end,size,orphan,sequence):
+ if size < 1:
+ if start > 0 and end > 0 and end >= start:
+ size=end+1-start
+ else: size=7
+
+ if start > 0:
+
+ try: sequence[start-1]
+ except: start=len(sequence)
+
+ if end > 0:
+ if end < start: end=start
+ else:
+ end=start+size-1
+ try: sequence[end+orphan-1]
+ except: end=len(sequence)
+ elif end > 0:
+ try: sequence[end-1]
+ except: end=len(sequence)
+ start=end+1-size
+ if start - 1 < orphan: start=1
+ else:
+ start=1
+ end=start+size-1
+ try: sequence[end+orphan-1]
+ except: end=len(sequence)
+ return start,end,size
diff --git a/src/zope/pagetemplate/tests/input/__init__.py b/src/zope/pagetemplate/tests/input/__init__.py
new file mode 100644
index 0000000..b711d36
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/__init__.py
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
diff --git a/src/zope/pagetemplate/tests/input/checknotexpression.html b/src/zope/pagetemplate/tests/input/checknotexpression.html
new file mode 100644
index 0000000..81f3735
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/checknotexpression.html
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<div tal:condition="not:python:0">not:python:0</div>
+<div tal:condition="not:python:1">not:python:1</div>
+<div tal:condition="not: python:1">not: python:1</div>
+<div tal:condition="not:python:range(1,20)">not:python:range(1,20)</div>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/checknothing.html b/src/zope/pagetemplate/tests/input/checknothing.html
new file mode 100644
index 0000000..bb531ba
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/checknothing.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<head>
+ <title tal:content="nothing">Hello World!</title>
+</head>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/checkpathalt.html b/src/zope/pagetemplate/tests/input/checkpathalt.html
new file mode 100644
index 0000000..3026cda
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/checkpathalt.html
@@ -0,0 +1,17 @@
+<html>
+<body>
+ <div tal:define="x string:X;nil string:">
+ <p tal:content="x">1</p>
+ <p tal:content="x | nil">2</p>
+ <p tal:content="python:nil or x">3</p>
+ <p tal:content="y/z | x">4</p>
+ <p tal:content="y/z | x | nil">5</p>
+
+ <p tal:attributes="name nil">Z</p>
+ <p tal:attributes="name y/z | nil">Z</p>
+ <p tal:attributes="name y/z | nothing">Z</p>
+
+ <p tal:on-error="python:str(error.value[0])" tal:content="a/b | c/d">Z</p>
+ </div>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/checkpathnothing.html b/src/zope/pagetemplate/tests/input/checkpathnothing.html
new file mode 100644
index 0000000..99f88be
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/checkpathnothing.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<head>
+ <title tal:content="path:nothing">Hello World!</title>
+</head>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/checkwithxmlheader.html b/src/zope/pagetemplate/tests/input/checkwithxmlheader.html
new file mode 100644
index 0000000..c184b36
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/checkwithxmlheader.html
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<html>
+<body tal:content="string:Hello!">
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/dtml1.html b/src/zope/pagetemplate/tests/input/dtml1.html
new file mode 100644
index 0000000..421a1b1
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/dtml1.html
@@ -0,0 +1,19 @@
+<html xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <head><title>Test of documentation templates</title></head>
+ <body>
+ <span tal:replace="nothing"> blah </span>
+ <dl tal:condition="options/content/args">
+ <dt>The arguments to this test program were:</dt>
+ <dd>
+ <ul>
+ <li tal:repeat="arg options/content/args">
+ Argument number <span tal:replace="arg/num">99</span>
+ is <span tal:replace="arg/arg">default</span>
+ </li>
+ </ul>
+ </dd>
+ </dl>
+ <p tal:condition="not:options/content/args">No arguments were given.</p>
+ And thats da trooth.
+ </body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/dtml3.html b/src/zope/pagetemplate/tests/input/dtml3.html
new file mode 100644
index 0000000..d3c84b2
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/dtml3.html
@@ -0,0 +1,33 @@
+<head><title>Test of documentation templates</title></head>
+<body>
+ <div tal:condition="options/content/args">
+ The arguments were:
+ <span tal:condition="options/batch/previous_sequence">
+ (<span
+ tal:replace="options/batch/previous_sequence_start_item"
+ >previous start item</span>-<span
+ tal:replace="options/batch/previous_sequence_end_item"
+ >previous end item</span>)
+ </span>
+ <dl>
+ <span tal:repeat="arg options/batch">
+ <dt><span tal:replace="arg">??</span>.</dt>
+ <dd>Argument <span tal:define="num arg/num"
+ tal:replace="string: $num"
+ >99</span> was <span tal:replace="arg"
+ >??</span></dd>
+ </span>
+ </dl>
+ <span tal:condition="options/batch/next_sequence">
+ (<span
+ tal:replace="options/batch/next_sequence_start_item"
+ >next start item</span>-<span
+ tal:replace="options/batch/next_sequence_end_item"
+ >next end item</span>)
+ </span>
+ </div>
+ <p tal:condition="not:options/content/args">
+ No arguments were given.
+ </p>
+ And I am 100% sure!
+</body>
diff --git a/src/zope/pagetemplate/tests/input/globalsshadowlocals.html b/src/zope/pagetemplate/tests/input/globalsshadowlocals.html
new file mode 100644
index 0000000..c3f99e7
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/globalsshadowlocals.html
@@ -0,0 +1,14 @@
+<html tal:define="global x python:1">
+<head></head>
+<body>
+ <div tal:define="x python:2">
+ <span tal:content="x">Should be 2 here!</span>
+ </div>
+ <div>
+ <span tal:content="x">Should be 1 here!</span>
+ </div>
+ <div tal:define="global x python:3">
+ <span tal:content="x">Should be 3 here!</span>
+ </div>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/loop1.html b/src/zope/pagetemplate/tests/input/loop1.html
new file mode 100644
index 0000000..a4d0118
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/loop1.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<title>Loop doc</title>
+</head>
+<body>
+<p>Choose your type:</p>
+<ul>
+ <li tal:repeat="type python:'digital', 'analog', 'organic'">
+ <a href="dummy" tal:attributes="href string:/mach/$type">
+ <span tal:replace="repeat/type/number">1</span>.
+ <span tal:replace="type">selection</span></a>
+ </li>
+</ul>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/stringexpression.html b/src/zope/pagetemplate/tests/input/stringexpression.html
new file mode 100644
index 0000000..a60e72d
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/stringexpression.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<head>
+ <title tal:content="string:Hello World!">This is the title</title>
+</head>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/teeshop1.html b/src/zope/pagetemplate/tests/input/teeshop1.html
new file mode 100644
index 0000000..111381b
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/teeshop1.html
@@ -0,0 +1,87 @@
+<html metal:use-macro="options/laf/macros/page">
+<head>
+<title>Zope Stuff</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="/common.css">
+</head>
+
+<body bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
+<table width="100%" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#0000CC" align="center">
+ <td>
+ <table width="200" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#FFFFFF">
+ <td><img src="/images/lside.gif" width="52" height="94"><img src="/images/swlogo.gif" width="150" height="89"><img src="/images/rside.gif" width="52" height="94"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+<br>
+<table width="300" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr align="center">
+ <td width="25%" class="boldbodylist">apparel</td>
+ <td width="25%" class="boldbodylist">mugs</td>
+ <td width="25%" class="boldbodylist">toys</td>
+ <td width="25%" class="boldbodylist">misc</td>
+ </tr>
+</table>
+<br>
+<br>
+<div metal:fill-slot="body">
+<table width="500" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr>
+ <td bgcolor="#0000CC">
+ <table width="100%" border="0" cellspacing="1" cellpadding="3">
+ <tr bgcolor="#FFFFFF" align="center">
+ <td><img src="/images/welcome.gif" width="293" height="28"></td>
+ </tr>
+ <tr bgcolor="#FFFFFF" align="center" valign="top"
+ tal:repeat="product options/getProducts">
+ <td>
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td colspan="2" class="bodylist" height="200" valign="top"><b>Description:
+ </b><span tal:replace="product/description">This is the tee for those who LOVE Zope. Show your heart
+ on your tee.</span></td>
+ <td align="right" width="1%" rowspan="2">
+ <p><img src="/images/smlatee.jpg" width="200" height="200"
+ tal:attributes="src string:/images/${product/image}"></p>
+ </td>
+ </tr>
+ <tr>
+ <td class="bodylist"><img src="images/clear.gif" width="150" height="10"></td>
+ <td class="bodylist"><b>Price</b>:<span tal:replace="product/price">12.99</span></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF" align="center" valign="top">
+ <td>
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td align="center"><img src="images/buttons/submit.gif" width="87" height="30"></td>
+ <td align="center"><img src="images/buttons/cancel.gif" width="87" height="30"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</div>
+<p>&nbsp;</p><table width="100%" border="0" cellspacing="1" cellpadding="3" align="center">
+ <tr >
+ <td align="center" bgcolor="#FFFFFF" class="bodylist"> Copyright © 2000 <a href="http://www.4-am.com">4AM
+ Productions, Inc.</a>. All rights reserved. <br>
+ Questions or problems should be directed to <a href="mailto:webmaster@teamzonline.com">
+ the webmaster</a>, 254-412-0846. </td>
+ </tr>
+ <tr>
+ <td align="center"><img src="/images/zopelogos/buildzope.gif" width="54" height="54"></td>
+ </tr>
+</table>
+<p>&nbsp;</p>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/teeshop2.html b/src/zope/pagetemplate/tests/input/teeshop2.html
new file mode 100644
index 0000000..7ca0cf1
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/teeshop2.html
@@ -0,0 +1,5 @@
+<html metal:use-macro="options/laf/macros/page">
+<div metal:fill-slot="body">
+Body
+</div>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/teeshoplaf.html b/src/zope/pagetemplate/tests/input/teeshoplaf.html
new file mode 100644
index 0000000..f9477c3
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/teeshoplaf.html
@@ -0,0 +1,73 @@
+<html metal:define-macro="page">
+<head>
+<title>Zope Stuff</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="/common.css">
+</head>
+
+<body bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
+<table width="100%" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#0000CC" align="center">
+ <td>
+ <table width="200" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#FFFFFF">
+ <td><img src="/images/lside.gif" width="52" height="94"><img src="/images/swlogo.gif" width="150" height="89"><img src="/images/rside.gif" width="52" height="94"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+<br>
+<table width="300" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr align="center">
+ <td width="25%" class="boldbodylist">apparel</td>
+ <td width="25%" class="boldbodylist">mugs</td>
+ <td width="25%" class="boldbodylist">toys</td>
+ <td width="25%" class="boldbodylist">misc</td>
+ </tr>
+</table>
+<br>
+<br>
+<div metal:define-slot="body">
+<table width="500" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr>
+ <td bgcolor="#0000CC">
+ <table width="100%" border="0" cellspacing="1" cellpadding="3">
+ <tr bgcolor="#FFFFFF" align="center">
+ <td><img src="/images/welcome.gif" width="293" height="28"></td>
+ </tr>
+ <tr bgcolor="#FFFFFF" align="center" valign="top">
+ <td> <br>
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td>This is the tee for those who LOVE Zope. Show your heart on
+ your tee.</td>
+ <td align="right" width="1%">
+ <p><img src="/images/smlatee.jpg" width="200" height="200"></p>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</div>
+<br><br>
+<table width="100%" border="0" cellspacing="1" cellpadding="3" align="center">
+ <tr>
+ <td align="center" bgcolor="#FFFFFF" class="bodylist">
+ Copyright &copy; 2000
+ <a href="http://www.4-am.com">4AM Productions, Inc.</a>.
+ All rights reserved. <br>
+ Questions or problems should be directed to
+ <a href="mailto:webmaster@teamzonline.com">the webmaster</a>,
+ 254-412-0846.</td>
+ </tr>
+ <tr>
+ <td align="center"><img src="/images/zopelogos/buildzope.gif" width="54" height="54"></td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/input/translation.html b/src/zope/pagetemplate/tests/input/translation.html
new file mode 100644
index 0000000..1df9bd5
--- /dev/null
+++ b/src/zope/pagetemplate/tests/input/translation.html
@@ -0,0 +1,2 @@
+<p i18n:translate="">Define and translate message id in ZPT</p>
+<p tal:content="options/msg">Insert Message object here</p>
diff --git a/src/zope/pagetemplate/tests/output/__init__.py b/src/zope/pagetemplate/tests/output/__init__.py
new file mode 100644
index 0000000..b711d36
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/__init__.py
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
diff --git a/src/zope/pagetemplate/tests/output/checknotexpression.html b/src/zope/pagetemplate/tests/output/checknotexpression.html
new file mode 100644
index 0000000..48e2ba0
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/checknotexpression.html
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<div>not:python:0</div>
+
+
+
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/checknothing.html b/src/zope/pagetemplate/tests/output/checknothing.html
new file mode 100644
index 0000000..c65a966
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/checknothing.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<head>
+ <title></title>
+</head>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/checkpathalt.html b/src/zope/pagetemplate/tests/output/checkpathalt.html
new file mode 100644
index 0000000..ba33be1
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/checkpathalt.html
@@ -0,0 +1,17 @@
+<html>
+<body>
+ <div>
+ <p>X</p>
+ <p>X</p>
+ <p>X</p>
+ <p>X</p>
+ <p>X</p>
+
+ <p name="">Z</p>
+ <p name="">Z</p>
+ <p>Z</p>
+
+ <p>c</p>
+ </div>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/checkpathnothing.html b/src/zope/pagetemplate/tests/output/checkpathnothing.html
new file mode 100644
index 0000000..c65a966
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/checkpathnothing.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<head>
+ <title></title>
+</head>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/checkwithxmlheader.html b/src/zope/pagetemplate/tests/output/checkwithxmlheader.html
new file mode 100644
index 0000000..d2afeb0
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/checkwithxmlheader.html
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<html>
+<body>Hello!</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/dtml1a.html b/src/zope/pagetemplate/tests/output/dtml1a.html
new file mode 100644
index 0000000..f146b34
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/dtml1a.html
@@ -0,0 +1,34 @@
+<html>
+ <head><title>Test of documentation templates</title></head>
+ <body>
+
+ <dl>
+ <dt>The arguments to this test program were:</dt>
+ <dd>
+ <ul>
+ <li>
+ Argument number 1
+ is one
+ </li><li>
+ Argument number 2
+ is two
+ </li><li>
+ Argument number 3
+ is three
+ </li><li>
+ Argument number 4
+ is cha
+ </li><li>
+ Argument number 5
+ is cha
+ </li><li>
+ Argument number 6
+ is cha
+ </li>
+ </ul>
+ </dd>
+ </dl>
+
+ And thats da trooth.
+ </body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/dtml1b.html b/src/zope/pagetemplate/tests/output/dtml1b.html
new file mode 100644
index 0000000..edc7637
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/dtml1b.html
@@ -0,0 +1,7 @@
+<html>
+ <head><title>Test of documentation templates</title></head>
+ <body>
+ <p>No arguments were given.</p>
+ And thats da trooth.
+ </body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/dtml3.html b/src/zope/pagetemplate/tests/output/dtml3.html
new file mode 100644
index 0000000..fd774e1
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/dtml3.html
@@ -0,0 +1,30 @@
+<head><title>Test of documentation templates</title></head>
+<body>
+ <div>
+ The arguments were:
+
+ <dl>
+ <span>
+ <dt>one.</dt>
+ <dd>Argument 1 was one</dd>
+ </span><span>
+ <dt>two.</dt>
+ <dd>Argument 2 was two</dd>
+ </span><span>
+ <dt>three.</dt>
+ <dd>Argument 3 was three</dd>
+ </span><span>
+ <dt>four.</dt>
+ <dd>Argument 4 was four</dd>
+ </span><span>
+ <dt>five.</dt>
+ <dd>Argument 5 was five</dd>
+ </span>
+ </dl>
+ <span>
+ (six-ten)
+ </span>
+ </div>
+
+ And I am 100% sure!
+</body>
diff --git a/src/zope/pagetemplate/tests/output/globalsshadowlocals.html b/src/zope/pagetemplate/tests/output/globalsshadowlocals.html
new file mode 100644
index 0000000..e22e59b
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/globalsshadowlocals.html
@@ -0,0 +1,14 @@
+<html>
+<head></head>
+<body>
+ <div>
+ <span>2</span>
+ </div>
+ <div>
+ <span>1</span>
+ </div>
+ <div>
+ <span>3</span>
+ </div>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/loop1.html b/src/zope/pagetemplate/tests/output/loop1.html
new file mode 100644
index 0000000..f16ea89
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/loop1.html
@@ -0,0 +1,25 @@
+<html>
+<head>
+<title>Loop doc</title>
+</head>
+<body>
+<p>Choose your type:</p>
+<ul>
+ <li>
+ <a href="/mach/digital">
+ 1.
+ digital</a>
+ </li>
+ <li>
+ <a href="/mach/analog">
+ 2.
+ analog</a>
+ </li>
+ <li>
+ <a href="/mach/organic">
+ 3.
+ organic</a>
+ </li>
+</ul>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/stringexpression.html b/src/zope/pagetemplate/tests/output/stringexpression.html
new file mode 100644
index 0000000..58b55f5
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/stringexpression.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<head>
+ <title>Hello World!</title>
+</head>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/teeshop1.html b/src/zope/pagetemplate/tests/output/teeshop1.html
new file mode 100644
index 0000000..e5a3c43
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/teeshop1.html
@@ -0,0 +1,106 @@
+<html>
+<head>
+<title>Zope Stuff</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="/common.css">
+</head>
+
+<body bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
+<table width="100%" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#0000CC" align="center">
+ <td>
+ <table width="200" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#FFFFFF">
+ <td><img src="/images/lside.gif" width="52" height="94"><img src="/images/swlogo.gif" width="150" height="89"><img src="/images/rside.gif" width="52" height="94"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+<br>
+<table width="300" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr align="center">
+ <td width="25%" class="boldbodylist">apparel</td>
+ <td width="25%" class="boldbodylist">mugs</td>
+ <td width="25%" class="boldbodylist">toys</td>
+ <td width="25%" class="boldbodylist">misc</td>
+ </tr>
+</table>
+<br>
+<br>
+<div>
+<table width="500" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr>
+ <td bgcolor="#0000CC">
+ <table width="100%" border="0" cellspacing="1" cellpadding="3">
+ <tr bgcolor="#FFFFFF" align="center">
+ <td><img src="/images/welcome.gif" width="293" height="28"></td>
+ </tr>
+ <tr bgcolor="#FFFFFF" align="center" valign="top">
+ <td>
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td colspan="2" class="bodylist" height="200" valign="top"><b>Description:
+ </b>This is the tee for those who LOVE Zope. Show your heart on your tee.</td>
+ <td align="right" width="1%" rowspan="2">
+ <p><img src="/images/smlatee.jpg"
+ width="200" height="200"></p>
+ </td>
+ </tr>
+ <tr>
+ <td class="bodylist"><img src="images/clear.gif" width="150" height="10"></td>
+ <td class="bodylist"><b>Price</b>:12.99</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF" align="center" valign="top">
+ <td>
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td colspan="2" class="bodylist" height="200" valign="top"><b>Description:
+ </b>This is the tee for Jim Fulton. He's the Zope Pope!</td>
+ <td align="right" width="1%" rowspan="2">
+ <p><img src="/images/smpztee.jpg"
+ width="200" height="200"></p>
+ </td>
+ </tr>
+ <tr>
+ <td class="bodylist"><img src="images/clear.gif" width="150" height="10"></td>
+ <td class="bodylist"><b>Price</b>:11.99</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF" align="center" valign="top">
+ <td>
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td align="center"><img src="images/buttons/submit.gif" width="87" height="30"></td>
+ <td align="center"><img src="images/buttons/cancel.gif" width="87" height="30"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</div>
+<br><br>
+<table width="100%" border="0" cellspacing="1" cellpadding="3" align="center">
+ <tr>
+ <td align="center" bgcolor="#FFFFFF" class="bodylist">
+ Copyright &copy; 2000
+ <a href="http://www.4-am.com">4AM Productions, Inc.</a>.
+ All rights reserved. <br>
+ Questions or problems should be directed to
+ <a href="mailto:webmaster@teamzonline.com">the webmaster</a>,
+ 254-412-0846.</td>
+ </tr>
+ <tr>
+ <td align="center"><img src="/images/zopelogos/buildzope.gif" width="54" height="54"></td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/teeshop2.html b/src/zope/pagetemplate/tests/output/teeshop2.html
new file mode 100644
index 0000000..9eef0f2
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/teeshop2.html
@@ -0,0 +1,50 @@
+<html>
+<head>
+<title>Zope Stuff</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="/common.css">
+</head>
+
+<body bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
+<table width="100%" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#0000CC" align="center">
+ <td>
+ <table width="200" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#FFFFFF">
+ <td><img src="/images/lside.gif" width="52" height="94"><img src="/images/swlogo.gif" width="150" height="89"><img src="/images/rside.gif" width="52" height="94"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+<br>
+<table width="300" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr align="center">
+ <td width="25%" class="boldbodylist">apparel</td>
+ <td width="25%" class="boldbodylist">mugs</td>
+ <td width="25%" class="boldbodylist">toys</td>
+ <td width="25%" class="boldbodylist">misc</td>
+ </tr>
+</table>
+<br>
+<br>
+<div>
+Body
+</div>
+<br><br>
+<table width="100%" border="0" cellspacing="1" cellpadding="3" align="center">
+ <tr>
+ <td align="center" bgcolor="#FFFFFF" class="bodylist">
+ Copyright &copy; 2000
+ <a href="http://www.4-am.com">4AM Productions, Inc.</a>.
+ All rights reserved. <br>
+ Questions or problems should be directed to
+ <a href="mailto:webmaster@teamzonline.com">the webmaster</a>,
+ 254-412-0846.</td>
+ </tr>
+ <tr>
+ <td align="center"><img src="/images/zopelogos/buildzope.gif" width="54" height="54"></td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/teeshoplaf.html b/src/zope/pagetemplate/tests/output/teeshoplaf.html
new file mode 100644
index 0000000..547dd6d
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/teeshoplaf.html
@@ -0,0 +1,73 @@
+<html>
+<head>
+<title>Zope Stuff</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="/common.css">
+</head>
+
+<body bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
+<table width="100%" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#0000CC" align="center">
+ <td>
+ <table width="200" border="0" cellspacing="0" cellpadding="0">
+ <tr bgcolor="#FFFFFF">
+ <td><img src="/images/lside.gif" width="52" height="94"><img src="/images/swlogo.gif" width="150" height="89"><img src="/images/rside.gif" width="52" height="94"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+<br>
+<table width="300" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr align="center">
+ <td width="25%" class="boldbodylist">apparel</td>
+ <td width="25%" class="boldbodylist">mugs</td>
+ <td width="25%" class="boldbodylist">toys</td>
+ <td width="25%" class="boldbodylist">misc</td>
+ </tr>
+</table>
+<br>
+<br>
+<div>
+<table width="500" border="0" cellspacing="0" cellpadding="0" align="center">
+ <tr>
+ <td bgcolor="#0000CC">
+ <table width="100%" border="0" cellspacing="1" cellpadding="3">
+ <tr bgcolor="#FFFFFF" align="center">
+ <td><img src="/images/welcome.gif" width="293" height="28"></td>
+ </tr>
+ <tr bgcolor="#FFFFFF" align="center" valign="top">
+ <td> <br>
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td>This is the tee for those who LOVE Zope. Show your heart on
+ your tee.</td>
+ <td align="right" width="1%">
+ <p><img src="/images/smlatee.jpg" width="200" height="200"></p>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</div>
+<br><br>
+<table width="100%" border="0" cellspacing="1" cellpadding="3" align="center">
+ <tr>
+ <td align="center" bgcolor="#FFFFFF" class="bodylist">
+ Copyright &copy; 2000
+ <a href="http://www.4-am.com">4AM Productions, Inc.</a>.
+ All rights reserved. <br>
+ Questions or problems should be directed to
+ <a href="mailto:webmaster@teamzonline.com">the webmaster</a>,
+ 254-412-0846.</td>
+ </tr>
+ <tr>
+ <td align="center"><img src="/images/zopelogos/buildzope.gif" width="54" height="54"></td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/src/zope/pagetemplate/tests/output/translation.html b/src/zope/pagetemplate/tests/output/translation.html
new file mode 100644
index 0000000..4335d11
--- /dev/null
+++ b/src/zope/pagetemplate/tests/output/translation.html
@@ -0,0 +1,2 @@
+<p>Define and translate message id in ZPT</p>
+<p>Translate this!</p>
diff --git a/src/zope/pagetemplate/tests/test_basictemplate.py b/src/zope/pagetemplate/tests/test_basictemplate.py
new file mode 100644
index 0000000..376a8d6
--- /dev/null
+++ b/src/zope/pagetemplate/tests/test_basictemplate.py
@@ -0,0 +1,162 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Basic Page Template tests
+
+$Id$
+"""
+import unittest
+
+from zope.pagetemplate.tests import util
+from zope.pagetemplate.pagetemplate import PageTemplate
+
+class BasicTemplateTests(unittest.TestCase):
+
+ def setUp(self):
+ self.t = PageTemplate()
+
+ def test_if_in_var(self):
+ # DTML test 1: if, in, and var:
+ pass # for unittest
+ """
+ %(comment)[ blah %(comment)]
+ <html><head><title>Test of documentation templates</title></head>
+ <body>
+ %(if args)[
+ <dl><dt>The arguments to this test program were:<p>
+ <dd>
+ <ul>
+ %(in args)[
+ <li>Argument number %(num)d was %(arg)s
+ %(in args)]
+ </ul></dl><p>
+ %(if args)]
+ %(else args)[
+ No arguments were given.<p>
+ %(else args)]
+ And thats da trooth.
+ </body></html>
+ """
+ tal = util.read_input('dtml1.html')
+ self.t.write(tal)
+
+ aa = util.argv(('one', 'two', 'three', 'cha', 'cha', 'cha'))
+ o = self.t(content=aa)
+ expect = util.read_output('dtml1a.html')
+
+ util.check_xml(expect, o)
+
+ aa = util.argv(())
+ o = self.t(content=aa)
+ expect = util.read_output('dtml1b.html')
+ util.check_xml(expect, o)
+
+ def test_batches_and_formatting(self):
+ # DTML test 3: batches and formatting:
+ pass # for unittest
+ """
+ <html><head><title>Test of documentation templates</title></head>
+ <body>
+ <!--#if args-->
+ The arguments were:
+ <!--#in args size=size end=end-->
+ <!--#if previous-sequence-->
+ (<!--#var previous-sequence-start-arg-->-
+ <!--#var previous-sequence-end-arg-->)
+ <!--#/if previous-sequence-->
+ <!--#if sequence-start-->
+ <dl>
+ <!--#/if sequence-start-->
+ <dt><!--#var sequence-arg-->.</dt>
+ <dd>Argument <!--#var num fmt=d--> was <!--#var arg--></dd>
+ <!--#if next-sequence-->
+ (<!--#var next-sequence-start-arg-->-
+ <!--#var next-sequence-end-arg-->)
+ <!--#/if next-sequence-->
+ <!--#/in args-->
+ </dl>
+ <!--#else args-->
+ No arguments were given.<p>
+ <!--#/if args-->
+ And I\'m 100% sure!
+ </body></html>
+ """
+ tal = util.read_input('dtml3.html')
+ self.t.write(tal)
+
+ aa = util.argv(('one', 'two', 'three', 'four', 'five',
+ 'six', 'seven', 'eight', 'nine', 'ten',
+ 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
+ 'sixteen', 'seventeen', 'eighteen', 'nineteen',
+ 'twenty',
+ ))
+ from zope.pagetemplate.tests import batch
+ o = self.t(content=aa, batch=batch.batch(aa.args, 5))
+
+ expect = util.read_output('dtml3.html')
+ util.check_xml(expect, o)
+
+ def test_on_error_in_slot_filler(self):
+ # The `here` isn't defined, so the macro definition is
+ # expected to catch the error that gets raised.
+ text = '''\
+ <div metal:define-macro="foo">
+ <div tal:on-error="string:eek">
+ <div metal:define-slot="slot" />
+ cool
+ </div>
+ </div>
+
+ <div metal:use-macro="template/macros/foo">
+ <div metal:fill-slot="slot">
+ <p tal:content="here/xxx" />
+ </div>
+ </div>
+ '''
+ self.t.write(text)
+ self.t()
+
+ def test_on_error_in_slot_default(self):
+ # The `here` isn't defined, so the macro definition is
+ # expected to catch the error that gets raised.
+ text = '''\
+ <div metal:define-macro="foo">
+ <div tal:on-error="string:eek">
+ <div metal:define-slot="slot">
+ <div tal:content="here/xxx" />
+ </div>
+ </div>
+ </div>
+
+ <div metal:use-macro="template/macros/foo">
+ </div>
+ '''
+ self.t.write(text)
+ self.t()
+
+ def test_unicode_html(self):
+ text = u'<p>\xe4\xf6\xfc\xdf</p>'
+
+ # test with HTML parser
+ self.t.pt_edit(text, 'text/html')
+ self.assertEquals(self.t().strip(), text)
+
+ # test with XML parser
+ self.t.pt_edit(text, 'text/xml')
+ self.assertEquals(self.t().strip(), text)
+
+def test_suite():
+ return unittest.makeSuite(BasicTemplateTests)
+
+if __name__ == '__main__':
+ unittest.TextTestRunner().run(test_suite())
diff --git a/src/zope/pagetemplate/tests/test_htmltests.py b/src/zope/pagetemplate/tests/test_htmltests.py
new file mode 100644
index 0000000..cc76d11
--- /dev/null
+++ b/src/zope/pagetemplate/tests/test_htmltests.py
@@ -0,0 +1,143 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Page Template HTML Tests
+
+$Id$
+"""
+import unittest
+
+from zope.pagetemplate.tests import util
+from zope.pagetemplate.pagetemplate import PageTemplate
+
+
+class Folder(object):
+ context = property(lambda self: self)
+
+class HTMLTests(unittest.TestCase):
+
+ def setUp(self):
+ self.folder = f = Folder()
+ f.laf = PageTemplate()
+ f.t = PageTemplate()
+
+ def getProducts(self):
+ return [
+ {'description': 'This is the tee for those who LOVE Zope. '
+ 'Show your heart on your tee.',
+ 'price': 12.99, 'image': 'smlatee.jpg'
+ },
+ {'description': 'This is the tee for Jim Fulton. '
+ 'He\'s the Zope Pope!',
+ 'price': 11.99, 'image': 'smpztee.jpg'
+ },
+ ]
+
+ def test_1(self):
+ laf = self.folder.laf
+ laf.write(util.read_input('teeshoplaf.html'))
+ expect = util.read_output('teeshoplaf.html')
+ util.check_html(expect, laf())
+
+ def test_2(self):
+ self.folder.laf.write(util.read_input('teeshoplaf.html'))
+
+ t = self.folder.t
+ t.write(util.read_input('teeshop2.html'))
+ expect = util.read_output('teeshop2.html')
+ out = t(laf = self.folder.laf, getProducts = self.getProducts)
+ util.check_html(expect, out)
+
+
+ def test_3(self):
+ self.folder.laf.write(util.read_input('teeshoplaf.html'))
+
+ t = self.folder.t
+ t.write(util.read_input('teeshop1.html'))
+ expect = util.read_output('teeshop1.html')
+ out = t(laf = self.folder.laf, getProducts = self.getProducts)
+ util.check_html(expect, out)
+
+ def test_SimpleLoop(self):
+ t = self.folder.t
+ t.write(util.read_input('loop1.html'))
+ expect = util.read_output('loop1.html')
+ out = t()
+ util.check_html(expect, out)
+
+ def test_GlobalsShadowLocals(self):
+ t = self.folder.t
+ t.write(util.read_input('globalsshadowlocals.html'))
+ expect = util.read_output('globalsshadowlocals.html')
+ out = t()
+ util.check_html(expect, out)
+
+ def test_StringExpressions(self):
+ t = self.folder.t
+ t.write(util.read_input('stringexpression.html'))
+ expect = util.read_output('stringexpression.html')
+ out = t()
+ util.check_html(expect, out)
+
+ def test_ReplaceWithNothing(self):
+ t = self.folder.t
+ t.write(util.read_input('checknothing.html'))
+ expect = util.read_output('checknothing.html')
+ out = t()
+ util.check_html(expect, out)
+
+ def test_WithXMLHeader(self):
+ t = self.folder.t
+ t.write(util.read_input('checkwithxmlheader.html'))
+ expect = util.read_output('checkwithxmlheader.html')
+ out = t()
+ util.check_html(expect, out)
+
+ def test_NotExpression(self):
+ t = self.folder.t
+ t.write(util.read_input('checknotexpression.html'))
+ expect = util.read_output('checknotexpression.html')
+ out = t()
+ util.check_html(expect, out)
+
+ def test_PathNothing(self):
+ t = self.folder.t
+ t.write(util.read_input('checkpathnothing.html'))
+ expect = util.read_output('checkpathnothing.html')
+ out = t()
+ util.check_html(expect, out)
+
+ def test_PathAlt(self):
+ t = self.folder.t
+ t.write(util.read_input('checkpathalt.html'))
+ expect = util.read_output('checkpathalt.html')
+ out = t()
+ util.check_html(expect, out)
+
+ def test_translation(self):
+ from zope.i18nmessageid import MessageFactory
+ _ = MessageFactory('pttest')
+ msg = _("Translate this!")
+
+ t = self.folder.t
+ t.write(util.read_input('translation.html'))
+ expect = util.read_output('translation.html')
+ out = t(msg=msg)
+ util.check_html(expect, out)
+
+
+def test_suite():
+ return unittest.makeSuite(HTMLTests)
+
+if __name__=='__main__':
+ unittest.TextTestRunner().run(test_suite())
diff --git a/src/zope/pagetemplate/tests/test_ptfile.py b/src/zope/pagetemplate/tests/test_ptfile.py
new file mode 100644
index 0000000..078bba5
--- /dev/null
+++ b/src/zope/pagetemplate/tests/test_ptfile.py
@@ -0,0 +1,189 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests of PageTemplateFile.
+
+$Id$
+"""
+import os
+import tempfile
+import unittest
+
+from zope.pagetemplate.pagetemplatefile import PageTemplateFile
+
+
+class TypeSniffingTestCase(unittest.TestCase):
+
+ TEMPFILENAME = tempfile.mktemp()
+
+ def tearDown(self):
+ if os.path.exists(self.TEMPFILENAME):
+ os.unlink(self.TEMPFILENAME)
+
+ def get_pt(self, text):
+ f = open(self.TEMPFILENAME, "wb")
+ f.write(text)
+ f.close()
+ pt = PageTemplateFile(self.TEMPFILENAME)
+ pt.read()
+ return pt
+
+ def check_content_type(self, text, expected_type):
+ pt = self.get_pt(text)
+ self.assertEqual(pt.content_type, expected_type)
+
+ def test_sniffer_xml_ascii(self):
+ self.check_content_type(
+ "<?xml version='1.0' encoding='ascii'?><doc/>",
+ "text/xml")
+ self.check_content_type(
+ "<?xml\tversion='1.0' encoding='ascii'?><doc/>",
+ "text/xml")
+
+ def test_sniffer_xml_utf8(self):
+ # w/out byte order mark
+ self.check_content_type(
+ "<?xml version='1.0' encoding='utf-8'?><doc/>",
+ "text/xml")
+ self.check_content_type(
+ "<?xml\tversion='1.0' encoding='utf-8'?><doc/>",
+ "text/xml")
+ # with byte order mark
+ self.check_content_type(
+ "\xef\xbb\xbf<?xml version='1.0' encoding='utf-8'?><doc/>",
+ "text/xml")
+ self.check_content_type(
+ "\xef\xbb\xbf<?xml\tversion='1.0' encoding='utf-8'?><doc/>",
+ "text/xml")
+
+ def test_sniffer_xml_utf16_be(self):
+ # w/out byte order mark
+ self.check_content_type(
+ "\0<\0?\0x\0m\0l\0 \0v\0e\0r\0s\0i\0o\0n\0=\0'\01\0.\0000\0'"
+ "\0 \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\08\0'\0?\0>"
+ "\0<\0d\0o\0c\0/\0>",
+ "text/xml")
+ self.check_content_type(
+ "\0<\0?\0x\0m\0l\0\t\0v\0e\0r\0s\0i\0o\0n\0=\0'\01\0.\0000\0'"
+ "\0 \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\08\0'\0?\0>"
+ "\0<\0d\0o\0c\0/\0>",
+ "text/xml")
+ # with byte order mark
+ self.check_content_type(
+ "\xfe\xff"
+ "\0<\0?\0x\0m\0l\0 \0v\0e\0r\0s\0i\0o\0n\0=\0'\01\0.\0000\0'"
+ "\0 \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\08\0'\0?\0>"
+ "\0<\0d\0o\0c\0/\0>",
+ "text/xml")
+ self.check_content_type(
+ "\xfe\xff"
+ "\0<\0?\0x\0m\0l\0\t\0v\0e\0r\0s\0i\0o\0n\0=\0'\01\0.\0000\0'"
+ "\0 \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\08\0'\0?\0>"
+ "\0<\0d\0o\0c\0/\0>",
+ "text/xml")
+
+ def test_sniffer_xml_utf16_le(self):
+ # w/out byte order mark
+ self.check_content_type(
+ "<\0?\0x\0m\0l\0 \0v\0e\0r\0s\0i\0o\0n\0=\0'\01\0.\0000\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\08\0'\0?\0>\0"
+ "<\0d\0o\0c\0/\0>\n",
+ "text/xml")
+ self.check_content_type(
+ "<\0?\0x\0m\0l\0\t\0v\0e\0r\0s\0i\0o\0n\0=\0'\01\0.\0000\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\08\0'\0?\0>\0"
+ "<\0d\0o\0c\0/\0>\0",
+ "text/xml")
+ # with byte order mark
+ self.check_content_type(
+ "\xff\xfe"
+ "<\0?\0x\0m\0l\0 \0v\0e\0r\0s\0i\0o\0n\0=\0'\01\0.\0000\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\08\0'\0?\0>\0"
+ "<\0d\0o\0c\0/\0>\0",
+ "text/xml")
+ self.check_content_type(
+ "\xff\xfe"
+ "<\0?\0x\0m\0l\0\t\0v\0e\0r\0s\0i\0o\0n\0=\0'\01\0.\0000\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\08\0'\0?\0>\0"
+ "<\0d\0o\0c\0/\0>\0",
+ "text/xml")
+
+ HTML_PUBLIC_ID = "-//W3C//DTD HTML 4.01 Transitional//EN"
+ HTML_SYSTEM_ID = "http://www.w3.org/TR/html4/loose.dtd"
+
+ def test_sniffer_html_ascii(self):
+ self.check_content_type(
+ "<!DOCTYPE html [ SYSTEM '%s' ]><html></html>"
+ % self.HTML_SYSTEM_ID,
+ "text/html")
+ self.check_content_type(
+ "<html><head><title>sample document</title></head></html>",
+ "text/html")
+
+ # TODO: This reflects a case that simply isn't handled by the
+ # sniffer; there are many, but it gets it right more often than
+ # before.
+ def donttest_sniffer_xml_simple(self):
+ self.check_content_type("<doc><element/></doc>",
+ "text/xml")
+
+ def test_html_default_encoding(self):
+ pt = self.get_pt(
+ "<html><head><title>"
+ # 'Test' in russian (utf-8)
+ "\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82"
+ "</title></head></html>")
+ rendered = pt()
+ self.failUnless(isinstance(rendered, unicode))
+ self.failUnlessEqual(rendered,
+ u"<html><head><title>"
+ u"\u0422\u0435\u0441\u0442"
+ u"</title></head></html>\n")
+
+ def test_html_encoding_by_meta(self):
+ pt = self.get_pt(
+ "<html><head><title>"
+ # 'Test' in russian (windows-1251)
+ "\xd2\xe5\xf1\xf2"
+ '</title><meta http-equiv="Content-Type"'
+ ' content="text/html; charset=windows-1251">'
+ "</head></html>")
+ rendered = pt()
+ self.failUnless(isinstance(rendered, unicode))
+ self.failUnlessEqual(rendered,
+ u"<html><head><title>"
+ u"\u0422\u0435\u0441\u0442"
+ u"</title></head></html>\n")
+
+ def test_xhtml(self):
+ pt = self.get_pt(
+ "<html><head><title>"
+ # 'Test' in russian (windows-1251)
+ "\xd2\xe5\xf1\xf2"
+ '</title><meta http-equiv="Content-Type"'
+ ' content="text/html; charset=windows-1251"/>'
+ "</head></html>")
+ rendered = pt()
+ self.failUnless(isinstance(rendered, unicode))
+ self.failUnlessEqual(rendered,
+ u"<html><head><title>"
+ u"\u0422\u0435\u0441\u0442"
+ u"</title></head></html>\n")
+
+
+
+def test_suite():
+ return unittest.makeSuite(TypeSniffingTestCase)
+
+if __name__ == "__main__":
+ unittest.main(defaultTest="test_suite")
diff --git a/src/zope/pagetemplate/tests/testpackage/__init__.py b/src/zope/pagetemplate/tests/testpackage/__init__.py
new file mode 100644
index 0000000..b711d36
--- /dev/null
+++ b/src/zope/pagetemplate/tests/testpackage/__init__.py
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
diff --git a/src/zope/pagetemplate/tests/testpackage/content.py b/src/zope/pagetemplate/tests/testpackage/content.py
new file mode 100644
index 0000000..7d51454
--- /dev/null
+++ b/src/zope/pagetemplate/tests/testpackage/content.py
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Content
+
+$Id$
+"""
+
+class Content(object):
+ def getSomething(self):
+ return 42
+
+
+class PTComponent(object):
+ def __init__(self, content, request):
+ self.content = content
+
+ index = PageTemplateFile("view.pt", engine_name="unrestricted")
diff --git a/src/zope/pagetemplate/tests/testpackage/view.pt b/src/zope/pagetemplate/tests/testpackage/view.pt
new file mode 100644
index 0000000..8ea5029
--- /dev/null
+++ b/src/zope/pagetemplate/tests/testpackage/view.pt
@@ -0,0 +1 @@
+<span tal:replace="context/getSomething"/>
diff --git a/src/zope/pagetemplate/tests/util.py b/src/zope/pagetemplate/tests/util.py
new file mode 100644
index 0000000..481b168
--- /dev/null
+++ b/src/zope/pagetemplate/tests/util.py
@@ -0,0 +1,111 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Utilities
+
+$Id$
+"""
+import os
+import re
+import sys
+
+
+class Bruce(object):
+ __allow_access_to_unprotected_subobjects__=1
+ def __str__(self): return 'bruce'
+ def __int__(self): return 42
+ def __float__(self): return 42.0
+ def keys(self): return ['bruce']*7
+ def values(self): return [self]*7
+ def items(self): return [('bruce',self)]*7
+ def __len__(self): return 7
+ def __getitem__(self,index):
+ if ininstance(index, int) and (index < 0 or index > 6):
+ raise IndexError(index)
+ return self
+ isDocTemp = 0
+ def __getattr__(self,name):
+ if name.startswith('_'):
+ raise AttributeError(name)
+ return self
+
+bruce = Bruce()
+
+class arg(object):
+ __allow_access_to_unprotected_subobjects__ = 1
+ def __init__(self,nn,aa): self.num, self.arg = nn, aa
+ def __str__(self): return str(self.arg)
+
+class argv(object):
+ __allow_access_to_unprotected_subobjects__ = 1
+
+ def __init__(self, argv=sys.argv[1:]):
+ args = self.args = []
+ for aa in argv:
+ args.append(arg(len(args)+1,aa))
+
+ def items(self):
+ return map(lambda a: ('spam%d' % a.num, a), self.args)
+
+ def values(self): return self.args
+
+ def getRoot(self):
+ return self
+
+ context = property(lambda self: self)
+
+def nicerange(lo, hi):
+ if hi <= lo+1:
+ return str(lo+1)
+ else:
+ return "%d,%d" % (lo+1, hi)
+
+def dump(tag, x, lo, hi):
+ for i in xrange(lo, hi):
+ print '%s %s' % (tag, x[i]),
+
+def check_html(s1, s2):
+ s1 = normalize_html(s1)
+ s2 = normalize_html(s2)
+ assert s1==s2, (s1, s2, "HTML Output Changed")
+
+def check_xml(s1, s2):
+ s1 = normalize_xml(s1)
+ s2 = normalize_xml(s2)
+ assert s1==s2, ("XML Output Changed:\n%r\n\n%r" % (s1, s2))
+
+def normalize_html(s):
+ s = re.sub(r"[ \t]+", " ", s)
+ s = re.sub(r"/>", ">", s)
+ return s
+
+def normalize_xml(s):
+ s = re.sub(r"\s+", " ", s)
+ s = re.sub(r"(?s)\s+<", "<", s)
+ s = re.sub(r"(?s)>\s+", ">", s)
+ return s
+
+
+import zope.pagetemplate.tests
+
+dir = os.path.dirname(zope.pagetemplate.tests.__file__)
+input_dir = os.path.join(dir, 'input')
+output_dir = os.path.join(dir, 'output')
+
+def read_input(filename):
+ filename = os.path.join(input_dir, filename)
+ return open(filename, 'r').read()
+
+def read_output(filename):
+ filename = os.path.join(output_dir, filename)
+ return open(filename, 'r').read()