[Zope-Checkins] SVN: Zope/trunk/ Merge ajung-zpt-end-game branch.

Philipp von Weitershausen philikon at philikon.de
Mon May 29 06:34:37 EDT 2006


Log message for revision 68333:
  Merge ajung-zpt-end-game branch.
  

Changed:
  U   Zope/trunk/doc/CHANGES.txt
  _U  Zope/trunk/lib/python/
  _U  Zope/trunk/lib/python/Products/
  UU  Zope/trunk/lib/python/Products/PageTemplates/DeferExpr.py
  UU  Zope/trunk/lib/python/Products/PageTemplates/Expressions.py
  U   Zope/trunk/lib/python/Products/PageTemplates/GlobalTranslationService.py
  UU  Zope/trunk/lib/python/Products/PageTemplates/PageTemplate.py
  UU  Zope/trunk/lib/python/Products/PageTemplates/PageTemplateFile.py
  UU  Zope/trunk/lib/python/Products/PageTemplates/PathIterator.py
  UU  Zope/trunk/lib/python/Products/PageTemplates/PythonExpr.py
  D   Zope/trunk/lib/python/Products/PageTemplates/README.txt
  U   Zope/trunk/lib/python/Products/PageTemplates/TALES.py
  D   Zope/trunk/lib/python/Products/PageTemplates/ZPythonExpr.py
  UU  Zope/trunk/lib/python/Products/PageTemplates/ZRPythonExpr.py
  UU  Zope/trunk/lib/python/Products/PageTemplates/ZopePageTemplate.py
  U   Zope/trunk/lib/python/Products/PageTemplates/__init__.py
  D   Zope/trunk/lib/python/Products/PageTemplates/pt/
  U   Zope/trunk/lib/python/Products/PageTemplates/tests/__init__.py
  A   Zope/trunk/lib/python/Products/PageTemplates/tests/input/CheckImportOldStyleClass.html
  U   Zope/trunk/lib/python/Products/PageTemplates/tests/output/CheckI18nTranslateHooked.html
  A   Zope/trunk/lib/python/Products/PageTemplates/tests/output/CheckImportOldStyleClass.html
  U   Zope/trunk/lib/python/Products/PageTemplates/tests/testDTMLTests.py
  U   Zope/trunk/lib/python/Products/PageTemplates/tests/testExpressions.py
  U   Zope/trunk/lib/python/Products/PageTemplates/tests/testHTMLTests.py
  U   Zope/trunk/lib/python/Products/PageTemplates/tests/testTALES.py
  _U  Zope/trunk/lib/python/Products/PageTemplates/tests/testZRPythonExpr.py
  U   Zope/trunk/lib/python/Products/PageTemplates/tests/testZopePageTemplate.py
  U   Zope/trunk/lib/python/Products/PageTemplates/www/ptAdd.zpt
  U   Zope/trunk/lib/python/Products/PageTemplates/www/ptEdit.zpt
  U   Zope/trunk/lib/python/TAL/DummyEngine.py
  U   Zope/trunk/lib/python/TAL/HTMLTALParser.py
  U   Zope/trunk/lib/python/TAL/ITALES.py
  U   Zope/trunk/lib/python/TAL/TALDefs.py
  U   Zope/trunk/lib/python/TAL/TALGenerator.py
  U   Zope/trunk/lib/python/TAL/TALInterpreter.py
  U   Zope/trunk/lib/python/TAL/TALParser.py
  U   Zope/trunk/lib/python/TAL/TranslationContext.py
  U   Zope/trunk/lib/python/TAL/XMLParser.py
  U   Zope/trunk/lib/python/TAL/driver.py
  U   Zope/trunk/lib/python/TAL/ndiff.py
  U   Zope/trunk/lib/python/TAL/runtest.py
  U   Zope/trunk/lib/python/TAL/talgettext.py
  U   Zope/trunk/lib/python/TAL/tests/input/test29.html
  U   Zope/trunk/lib/python/TAL/tests/input/test36.html
  U   Zope/trunk/lib/python/TAL/tests/output/test29.html
  U   Zope/trunk/lib/python/TAL/tests/output/test_metal1.html
  U   Zope/trunk/lib/python/TAL/tests/output/test_metal7.html
  U   Zope/trunk/lib/python/TAL/tests/test_files.py
  U   Zope/trunk/lib/python/TAL/tests/test_htmltalparser.py
  U   Zope/trunk/lib/python/TAL/tests/test_sourcepos.py
  U   Zope/trunk/lib/python/TAL/tests/test_talinterpreter.py
  U   Zope/trunk/lib/python/TAL/tests/test_xmlparser.py
  U   Zope/trunk/lib/python/TAL/timer.py
  U   Zope/trunk/lib/python/ZTUtils/Iterator.py
  U   Zope/trunk/lib/python/ZTUtils/__init__.py
  U   Zope/trunk/lib/python/ZTUtils/tests/testIterator.py
  _U  Zope/trunk/lib/python/zope/

-=-
Modified: Zope/trunk/doc/CHANGES.txt
===================================================================
--- Zope/trunk/doc/CHANGES.txt	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/doc/CHANGES.txt	2006-05-29 10:34:19 UTC (rev 68333)
@@ -18,6 +18,18 @@
 
     Restructuring
 
+      - Products.PageTemplates now uses the Zope 3 ZPT implementation
+        in zope.pagetemplate.
+
+      - The TAL package has been deprecated in favour of the TAL
+        engine from zope.tal.
+
+      - Products.PageTemplates.TALES has been deprecated in favour of
+        the TALES engine from zope.tales.
+
+      - ZTUtils.Iterator has been deprecated in favour of the TALES
+        iterator implementation in zope.tales.tales.
+
       - ZCatalog: removed manage_deleteIndex(), manage_delColumns()
         which were deprecated since Zope 2.4
 


Property changes on: Zope/trunk/lib/python
___________________________________________________________________
Name: svn:externals
   - ZConfig        svn://svn.zope.org/repos/main/ZConfig/tags/ZConfig-2.3.1
BTrees         -r 41153 svn://svn.zope.org/repos/main/ZODB/branches/3.6/src/BTrees
persistent     -r 41153 svn://svn.zope.org/repos/main/ZODB/branches/3.6/src/persistent
ThreadedAsync  -r 41153 svn://svn.zope.org/repos/main/ZODB/branches/3.6/src/ThreadedAsync
transaction    -r 41153 svn://svn.zope.org/repos/main/ZODB/branches/3.6/src/transaction
ZEO            -r 41153 svn://svn.zope.org/repos/main/ZODB/branches/3.6/src/ZEO
ZODB           -r 41153 svn://svn.zope.org/repos/main/ZODB/branches/3.6/src/ZODB
ZopeUndo       -r 41153 svn://svn.zope.org/repos/main/ZODB/branches/3.6/src/ZopeUndo
zdaemon        -r 40792 svn://svn.zope.org/repos/main/zdaemon/trunk/src/zdaemon
pytz           -r 67819 svn://svn.zope.org/repos/main/Zope3/trunk/src/pytz
zodbcode       -r 67819 svn://svn.zope.org/repos/main/Zope3/trunk/src/zodbcode
ClientCookie   -r 67819 svn://svn.zope.org/repos/main/Zope3/trunk/src/ClientCookie
mechanize      -r 67819 svn://svn.zope.org/repos/main/Zope3/trunk/src/mechanize
docutils       svn://svn.zope.org/repos/main/docutils/tags/0.4.0


   + ZConfig        svn://svn.zope.org/repos/main/ZConfig/tags/ZConfig-2.3.1
BTrees         -r 68012 svn://svn.zope.org/repos/main/ZODB/branches/3.7/src/BTrees
persistent     -r 68012 svn://svn.zope.org/repos/main/ZODB/branches/3.7/src/persistent
ThreadedAsync  -r 68012 svn://svn.zope.org/repos/main/ZODB/branches/3.7/src/ThreadedAsync
transaction    -r 68012 svn://svn.zope.org/repos/main/ZODB/branches/3.7/src/transaction
ZEO            -r 68012 svn://svn.zope.org/repos/main/ZODB/branches/3.7/src/ZEO
ZODB           -r 68012 svn://svn.zope.org/repos/main/ZODB/branches/3.7/src/ZODB
ZopeUndo       -r 68012 svn://svn.zope.org/repos/main/ZODB/branches/3.7/src/ZopeUndo
zdaemon        -r 40792 svn://svn.zope.org/repos/main/zdaemon/trunk/src/zdaemon
pytz           -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/pytz
zodbcode       -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zodbcode
ClientCookie   -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/ClientCookie
mechanize      -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/mechanize
docutils       svn://svn.zope.org/repos/main/docutils/tags/0.4.0




Property changes on: Zope/trunk/lib/python/Products
___________________________________________________________________
Name: svn:externals
   - Five     svn://svn.zope.org/repos/main/Products.Five/tags/1.5b

   + Five     -r 68331 svn://svn.zope.org/repos/main/Products.Five/trunk


Modified: Zope/trunk/lib/python/Products/PageTemplates/DeferExpr.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/DeferExpr.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/DeferExpr.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,33 +10,17 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-"""Defer and Lazy expression handler
+"""Lazy expression handler
 
-defer expressions can be usesd for a design pattern called deferred evaluation.
+A lazy expressions is implemented similarly to the defer expression
+but has a different result. While a defer expression is evaluated
+every time it is used according to its context a lazy expression is
+evaluted only the first time it is used. Lazy expression are known
+under the name lazy initialization of variables, too.  A common use
+case for a lazy expression is a lazy binding of a costly expression.
+While one could call an expression only when it's required it makes
+sense to define it only one time when it could be used multiple times.
 
-Example:
-
-    <div tal:define="xis defer:string:x is $x">
-      <p tal:repeat="x python:range(3)"
-         tal:content="xis"></p>
-    </div>
-
-Output:
-
-    <div>
-      <p>x is 0</p>
-      <p>x is 1</p>
-      <p>x is 2</p>
-    </div>
-    
-A lazy expressions is implemented in a similar way but has a different result. While
-a defer expression is evaluated every time it is used according to its context a lazy
-expression is evaluted only the first time it is used. Lazy expression are known
-under the name lazy initialization of variables, too. 
-A common use case for a lazy expression is a lazy binding of a costly expression.
-While one could call an expression only when it's required it makes sense to define
-it only one time when it could be used multiple times.
-
 Example
 
     <div tal:define="lazyvar lazy:here/suckMyCPU">
@@ -45,39 +29,12 @@
         <div tal:condition"python: not (foo or bar)">...</div>
     </div>
 """
-
+from zope.tales.expressions import DeferWrapper, DeferExpr
 _marker = object()
 
-# defer expression
+# TODO These should really be integrated into the Zope 3 ZPT
+# implementation (zope.tales)
 
-class DeferWrapper:
-    """Wrapper for defer: expression
-    """
-    def __init__(self, expr, econtext):
-        self._expr = expr
-        self._econtext = econtext
-
-    def __str__(self):
-        return str(self())
-
-    def __call__(self):
-        return self._expr(self._econtext)
-
-class DeferExpr:
-    """defer: expression handler for deferred evaluation of the context
-    """
-    def __init__(self, name, expr, compiler):
-        self._s = expr = expr.lstrip()
-        self._c = compiler.compile(expr)
-
-    def __call__(self, econtext):
-        return DeferWrapper(self._c, econtext)
-
-    def __repr__(self):
-        return 'defer:%s' % `self._s`
-
-# lazy expression
-
 class LazyWrapper(DeferWrapper):
     """Wrapper for lazy: expression
     """
@@ -99,4 +56,3 @@
 
     def __repr__(self):
         return 'lazy:%s' % `self._s`
-


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/DeferExpr.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: Zope/trunk/lib/python/Products/PageTemplates/Expressions.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/Expressions.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/Expressions.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,73 +10,81 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-
 """Page Template Expression Engine
 
 Page Template-specific implementation of TALES, with handlers
 for Python expressions, string literals, and paths.
+
+$Id$
 """
+from zope.interface import implements
+from zope.tales.tales import Context, Iterator
+from zope.tales.expressions import PathExpr, StringExpr, NotExpr
+from zope.tales.expressions import DeferExpr, SubPathExpr, Undefs
+from zope.tales.pythonexpr import PythonExpr
+from zope.traversing.interfaces import ITraversable
+from zope.traversing.adapters import traversePathElement
+from zope.contentprovider.tales import TALESProviderExpression
+from zope.proxy import removeAllProxies
+import zope.app.pagetemplate.engine
 
-__version__='$Revision: 1.45 $'[11:-2]
+import OFS.interfaces
+from Acquisition import aq_base
+from zExceptions import NotFound, Unauthorized
+from Products.PageTemplates import ZRPythonExpr
+from Products.PageTemplates.DeferExpr import LazyExpr
+from Products.PageTemplates.GlobalTranslationService import getGlobalTranslationService
 
-import re, sys
-from TALES import Engine
-from TALES import CompilerError
-from TALES import _valid_name
-from TALES import NAME_RE
-from TALES import Undefined
-from TALES import Default
-from TALES import _parse_expr
-from Acquisition import aq_base, aq_inner, aq_parent
-from DeferExpr import LazyWrapper
-from DeferExpr import LazyExpr
-from DeferExpr import DeferWrapper
-from DeferExpr import DeferExpr
+SecureModuleImporter = ZRPythonExpr._SecureModuleImporter()
 
-_engine = None
-def getEngine():
-    global _engine
-    if _engine is None:
-        from PathIterator import Iterator
-        _engine = Engine(Iterator)
-        installHandlers(_engine)
-    return _engine
+# BBB 2005/05/01 -- remove after 12 months
+import zope.deprecation
+from zope.deprecation import deprecate
+zope.deprecation.deprecated(
+    ("StringExpr", "NotExpr", "PathExpr", "SubPathExpr", "Undefs"),
+    "Zope 2 uses the Zope 3 ZPT engine now.  Expression types can be "
+    "imported from zope.tales.expressions."
+    )
 
-def installHandlers(engine):
-    reg = engine.registerType
-    pe = PathExpr
-    for pt in ('standard', 'path', 'exists', 'nocall'):
-        reg(pt, pe)
-    reg('string', StringExpr)
-    reg('python', PythonExpr)
-    reg('not', NotExpr)
-    reg('defer', DeferExpr)
-    reg('lazy', LazyExpr)
+# In Zope 2 traversal semantics, NotFound or Unauthorized (the Zope 2
+# versions) indicate that traversal has failed.  By default, Zope 3's
+# TALES engine doesn't recognize them as such which is why we extend
+# Zope 3's list here and make sure our implementation of the TALES
+# Path Expression uses them
+ZopeUndefs = Undefs + (NotFound, Unauthorized)
 
-import AccessControl
-import AccessControl.cAccessControl
-acquisition_security_filter = AccessControl.cAccessControl.aq_validate
-from AccessControl import getSecurityManager
-from AccessControl.ZopeGuards import guarded_getattr
-from AccessControl import Unauthorized
-from ZRPythonExpr import PythonExpr
-from ZRPythonExpr import _SecureModuleImporter
-from ZRPythonExpr import call_with_ns
+def boboAwareZopeTraverse(object, path_items, econtext):
+    """Traverses a sequence of names, first trying attributes then items.
 
-SecureModuleImporter = _SecureModuleImporter()
+    This uses Zope 3 path traversal where possible and interacts
+    correctly with objects providing OFS.interface.ITraversable when
+    necessary (bobo-awareness).
+    """
+    request = getattr(econtext, 'request', None)
+    path_items = list(path_items)
+    path_items.reverse()
 
-Undefs = (Undefined, AttributeError, KeyError,
-          TypeError, IndexError, Unauthorized)
+    while path_items:
+        name = path_items.pop()
+        if OFS.interfaces.ITraversable.providedBy(object):
+            object = object.restrictedTraverse(name)
+        else:
+            object = traversePathElement(object, name, path_items,
+                                         request=request)
+    return object
 
 def render(ob, ns):
+    """Calls the object, possibly a document template, or just returns
+    it if not callable.  (From DT_Util.py)
     """
-    Calls the object, possibly a document template, or just returns it if
-    not callable.  (From DT_Util.py)
-    """
     if hasattr(ob, '__render_with_namespace__'):
-        ob = call_with_ns(ob.__render_with_namespace__, ns)
+        ob = ZRPythonExpr.call_with_ns(ob.__render_with_namespace__, ns)
     else:
+        # items might be acquisition wrapped
         base = aq_base(ob)
+        # item might be proxied (e.g. modules might have a deprecation
+        # proxy)
+        base = removeAllProxies(base)
         if callable(base):
             try:
                 if getattr(base, 'isDocTemp', 0):
@@ -88,278 +96,172 @@
                     raise
     return ob
 
-class SubPathExpr:
-    def __init__(self, path):
-        self._path = path = path.strip().split('/')
-        self._base = base = path.pop(0)
-        if base and not _valid_name(base):
-            raise CompilerError, 'Invalid variable name "%s"' % base
-        # Parse path
-        self._dp = dp = []
-        for i in range(len(path)):
-            e = path[i]
-            if e[:1] == '?' and _valid_name(e[1:]):
-                dp.append((i, e[1:]))
-        dp.reverse()
+class ZopePathExpr(PathExpr):
 
-    def _eval(self, econtext,
-              list=list, isinstance=isinstance, StringType=type('')):
-        vars = econtext.vars
-        path = self._path
-        if self._dp:
-            path = list(path) # Copy!
-            for i, varname in self._dp:
-                val = vars[varname]
-                if isinstance(val, StringType):
-                    path[i] = val
-                else:
-                    # If the value isn't a string, assume it's a sequence
-                    # of path names.
-                    path[i:i+1] = list(val)
-        __traceback_info__ = base = self._base
-        if base == 'CONTEXTS' or not base:
-            ob = econtext.contexts
-        else:
-            ob = vars[base]
-        if isinstance(ob, DeferWrapper):
-            ob = ob()
-        if path:
-            ob = restrictedTraverse(ob, path, getSecurityManager())
-        return ob
-
-class PathExpr:
     def __init__(self, name, expr, engine):
-        self._s = expr
-        self._name = name
-        self._hybrid = 0
-        paths = expr.split('|')
-        self._subexprs = []
-        add = self._subexprs.append
-        for i in range(len(paths)):
-            path = paths[i].lstrip()
-            if _parse_expr(path):
-                # This part is the start of another expression type,
-                # so glue it back together and compile it.
-                add(engine.compile(('|'.join(paths[i:]).lstrip())))
-                self._hybrid = 1
-                break
-            add(SubPathExpr(path)._eval)
+        super(ZopePathExpr, self).__init__(name, expr, engine,
+                                           boboAwareZopeTraverse)
 
-    def _exists(self, econtext):
-        for expr in self._subexprs:
-            try:
-                expr(econtext)
-            except Undefs:
-                pass
-            else:
-                return 1
-        return 0
-
-    def _eval(self, econtext,
-              isinstance=isinstance,
-              BasicTypes=(str, unicode, dict, list, tuple, bool),
-              render=render):
+    # override this to support different call metrics (see bottom of
+    # method) and Zope 2's traversal exceptions (ZopeUndefs instead of
+    # Undefs)
+    def _eval(self, econtext):
         for expr in self._subexprs[:-1]:
             # Try all but the last subexpression, skipping undefined ones.
             try:
                 ob = expr(econtext)
-            except Undefs:
+            except ZopeUndefs: # use Zope 2 expression types
                 pass
             else:
                 break
         else:
-            # On the last subexpression allow exceptions through, and
-            # don't autocall if the expression was not a subpath.
+            # On the last subexpression allow exceptions through.
             ob = self._subexprs[-1](econtext)
             if self._hybrid:
                 return ob
 
-        if self._name == 'nocall' or isinstance(ob, BasicTypes):
+        if self._name == 'nocall':
             return ob
-        # Return the rendered object
+
+        # this is where we are different from our super class:
         return render(ob, econtext.vars)
 
-    def __call__(self, econtext):
-        if self._name == 'exists':
-            return self._exists(econtext)
-        return self._eval(econtext)
+    # override this to support Zope 2's traversal exceptions
+    # (ZopeUndefs instead of Undefs)
+    def _exists(self, econtext):
+        for expr in self._subexprs:
+            try:
+                expr(econtext)
+            except ZopeUndefs: # use Zope 2 expression types
+                pass
+            else:
+                return 1
+        return 0
 
-    def __str__(self):
-        return '%s expression %s' % (self._name, `self._s`)
+class ZopeContext(Context):
 
-    def __repr__(self):
-        return '%s:%s' % (self._name, `self._s`)
+    def translate(self, msgid, domain=None, mapping=None, default=None):
+        context = self.contexts.get('context')
+        return getGlobalTranslationService().translate(
+            domain, msgid, mapping=mapping,
+            context=context, default=default)
 
+class ZopeEngine(zope.app.pagetemplate.engine.ZopeEngine):
 
-_interp = re.compile(r'\$(%(n)s)|\${(%(n)s(?:/[^}]*)*)}' % {'n': NAME_RE})
+    _create_context = ZopeContext
 
-class StringExpr:
-    def __init__(self, name, expr, engine):
-        self._s = expr
-        if '%' in expr:
-            expr = expr.replace('%', '%%')
-        self._vars = vars = []
-        if '$' in expr:
-            parts = []
-            for exp in expr.split('$$'):
-                if parts: parts.append('$')
-                m = _interp.search(exp)
-                while m is not None:
-                    parts.append(exp[:m.start()])
-                    parts.append('%s')
-                    vars.append(PathExpr('path', m.group(1) or m.group(2),
-                                         engine))
-                    exp = exp[m.end():]
-                    m = _interp.search(exp)
-                if '$' in exp:
-                    raise CompilerError, (
-                        '$ must be doubled or followed by a simple path')
-                parts.append(exp)
-            expr = ''.join(parts)
-        self._expr = expr
+class ZopeIterator(Iterator):
 
-    def __call__(self, econtext):
-        vvals = []
-        for var in self._vars:
-            v = var(econtext)
-            # I hope this isn't in use anymore.
-            ## if isinstance(v, Exception):
-            ##     raise v
-            vvals.append(v)
-        return self._expr % tuple(vvals)
+    # The things below used to be attributes in
+    # ZTUtils.Iterator.Iterator, however in zope.tales.tales.Iterator
+    # they're methods.  We need BBB on the Python level so we redefine
+    # them as properties here.  Eventually, we would like to get rid
+    # of them, though, so that we won't have to maintain yet another
+    # iterator class somewhere.
 
-    def __str__(self):
-        return 'string expression %s' % `self._s`
+    @property
+    def index(self):
+        return super(ZopeIterator, self).index()
 
-    def __repr__(self):
-        return 'string:%s' % `self._s`
+    @property
+    def start(self):
+        return super(ZopeIterator, self).start()
 
-class NotExpr:
-    def __init__(self, name, expr, compiler):
-        self._s = expr = expr.lstrip()
-        self._c = compiler.compile(expr)
+    @property
+    def end(self):
+        return super(ZopeIterator, self).end()
 
-    def __call__(self, econtext):
-        # We use the (not x) and 1 or 0 formulation to avoid changing
-        # the representation of the result in Python 2.3, where the
-        # result of "not" becomes an instance of bool.
-        return (not econtext.evaluateBoolean(self._c)) and 1 or 0
+    @property
+    def item(self):
+        return super(ZopeIterator, self).item()
 
-    def __repr__(self):
-        return 'not:%s' % `self._s`
+    # This method was on the old ZTUtils.Iterator.Iterator class but
+    # isn't part of the spec.  We'll support it for a short
+    # deprecation period.
+    # BBB 2005/05/01 -- to be removed after 12 months
+    @property
+    @deprecate("The 'nextIndex' method has been deprecated and will disappear "
+               "in Zope 2.12.  Use 'iterator.index+1' instead.")
+    def nextIndex(self):
+        return self.index + 1
 
-from zope.interface import Interface, implements
-from zope.component import queryMultiAdapter
-from zope.traversing.interfaces import TraversalError
-from zope.traversing.namespace import nsParse, namespaceLookup
-from zope.publisher.interfaces.browser import IBrowserRequest
-from zope.publisher.browser import setDefaultSkin
+    # 'first' and 'last' are Zope 2 enhancements to the TALES iterator
+    # spec.  See help/tal-repeat.stx for more info
+    def first(self, name=None):
+        if self.start:
+            return True
+        return not self.same_part(name, self._last_item, self.item)
 
-class FakeRequest(dict):
-    implements(IBrowserRequest)
+    def last(self, name=None):
+        if self.end:
+            return True
+        return not self.same_part(name, self.item, self._next)
 
-    def getURL(self):
-        return "http://codespeak.net/z3/five"
+    def same_part(self, name, ob1, ob2):
+        if name is None:
+            return ob1 == ob2
+        no = object()
+        return getattr(ob1, name, no) == getattr(ob2, name, no) is not no
 
-def restrictedTraverse(object, path, securityManager,
-                       get=getattr, has=hasattr, N=None, M=[],
-                       TupleType=type(()) ):
+    # 'first' needs to have access to the last item in the loop
+    def next(self):
+        if self._nextIndex > 0:
+            self._last_item = self.item
+        return super(ZopeIterator, self).next()
 
-    REQUEST = FakeRequest()
-    REQUEST['path'] = path
-    REQUEST['TraversalRequestNameStack'] = path = path[:] # Copy!
-    setDefaultSkin(REQUEST)
-    path.reverse()
-    validate = securityManager.validate
-    __traceback_info__ = REQUEST
-    while path:
-        name = path.pop()
+class PathIterator(ZopeIterator):
+    """A TALES Iterator with the ability to use first() and last() on
+    subpaths of elements."""
+    # we want to control our own traversal so that we can deal with
+    # 'first' and 'last' when they appear in path expressions
+    implements(ITraversable)
 
-        if isinstance(name, TupleType):
-            object = object(*name)
-            continue
+    def traverse(self, name, furtherPath):
+        if name in ('first', 'last'):
+            method = getattr(self, name)
+            # it's important that 'name' becomes a copy because we'll
+            # clear out 'furtherPath'
+            name = furtherPath[:]
+            if not name:
+                name = None
+            # make sure that traversal ends here with us
+            furtherPath[:] = []
+            return method(name)
+        return getattr(self, name)
 
-        if not name or name[0] == '_':
-            # Skip directly to item access
-            o = object[name]
-            # Check access to the item.
-            if not validate(object, object, None, o):
-                raise Unauthorized, name
-            object = o
-            continue
+    def same_part(self, name, ob1, ob2):
+        if name is None:
+            return ob1 == ob2
+        if isinstance(name, basestring):
+            name = name.split('/')
+        try:
+            ob1 = boboAwareZopeTraverse(ob1, name, None)
+            ob2 = boboAwareZopeTraverse(ob2, name, None)
+        except ZopeUndefs:
+            return False
+        return ob1 == ob2
 
-        if name=='..':
-            o = get(object, 'aq_parent', M)
-            if o is not M:
-                if not validate(object, object, name, o):
-                    raise Unauthorized, name
-                object=o
-                continue
+def createZopeEngine():
+    e = ZopeEngine()
+    e.iteratorFactory = PathIterator
+    for pt in ZopePathExpr._default_type_names:
+        e.registerType(pt, ZopePathExpr)
+    e.registerType('string', StringExpr)
+    e.registerType('python', ZRPythonExpr.PythonExpr)
+    e.registerType('not', NotExpr)
+    e.registerType('defer', DeferExpr)
+    e.registerType('lazy', LazyExpr)
+    e.registerType('provider', TALESProviderExpression)
+    e.registerBaseName('modules', SecureModuleImporter)
+    return e
 
-        t=get(object, '__bobo_traverse__', N)
-        if name and name[:1] in '@+':
-            # Process URI segment parameters.
-            ns, nm = nsParse(name)
-            if ns:
-                try:
-                    o = namespaceLookup(ns, nm, object, 
-                                           REQUEST).__of__(object)
-                    if not validate(object, object, name, o):
-                        raise Unauthorized, name
-                except TraversalError:
-                    raise AttributeError(name)
-        elif t is not N:
-            o=t(REQUEST, name)
+def createTrustedZopeEngine():
+    # same as createZopeEngine, but use non-restricted Python
+    # expression evaluator
+    e = createZopeEngine()
+    e.types['python'] = PythonExpr
+    return e
 
-            container = None
-            if aq_base(o) is not o:
-                # The object is wrapped, so the acquisition
-                # context determines the container.
-                container = aq_parent(aq_inner(o))
-            elif has(o, 'im_self'):
-                container = o.im_self
-            elif (has(aq_base(object), name) and get(object, name) == o):
-                container = object
-            if not validate(object, container, name, o):
-                raise Unauthorized, name
-        else:
-            # Try an attribute.
-            o = guarded_getattr(object, str(name), M) # failed on u'aq_parent'
-            if o is M:
-                # Try an item.
-                try:
-                    # XXX maybe in Python 2.2 we can just check whether
-                    # the object has the attribute "__getitem__"
-                    # instead of blindly catching exceptions.
-                    try:
-                        o = object[name]
-                    except (AttributeError, KeyError):
-                        # Try to look for a view
-                        o = queryMultiAdapter((object, REQUEST), 
-                                                 Interface, name)
-                        if o is None:
-                            # Didn't find one, reraise the error:
-                            raise
-                        o = o.__of__(object)
-                except AttributeError, exc:
-                    if str(exc).find('__getitem__') >= 0:
-                        # The object does not support the item interface.
-                        # Try to re-raise the original attribute error.
-                        # XXX I think this only happens with
-                        # ExtensionClass instances.
-                        guarded_getattr(object, name)
-                    raise
-                except TypeError, exc:
-                    if str(exc).find('unsubscriptable') >= 0:
-                        # The object does not support the item interface.
-                        # Try to re-raise the original attribute error.
-                        # XXX This is sooooo ugly.
-                        guarded_getattr(object, name)
-                    raise
-                else:
-                    # Check access to the item.
-                    if not validate(object, object, None, o):
-                        raise Unauthorized, name
-        object = o
-
-    return object
+_engine = createZopeEngine()
+def getEngine():
+    return _engine


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/Expressions.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: Zope/trunk/lib/python/Products/PageTemplates/GlobalTranslationService.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/GlobalTranslationService.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/GlobalTranslationService.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -15,12 +15,11 @@
 
 $Id$
 """
-
 import re
 import Products.Five.i18n
 
 from DocumentTemplate.DT_Util import ustr
-from TAL.TALDefs import NAME_RE
+from zope.tal.taldefs import NAME_RE
 
 class DummyTranslationService:
     """Translation service that doesn't know anything about translation."""
@@ -30,13 +29,15 @@
             return ustr(mapping[m.group(m.lastindex)])
         cre = re.compile(r'\$(?:(%s)|\{(%s)\})' % (NAME_RE, NAME_RE))
         return cre.sub(repl, default or msgid)
-    # XXX Not all of Zope2.I18n.ITranslationService is implemented.
 
 #
 # As of Five 1.1, we're by default using Zope 3 Message Catalogs for
 # translation, but we allow fallback translation services such as PTS
 # and Localizer
 #
+# TODO We should really deprecate Zope2-style translation service and
+# only support Zope3-style i18n in the future.
+#
 
 Products.Five.i18n._fallback_translation_service = DummyTranslationService()
 fiveTranslationService = Products.Five.i18n.FiveTranslationService()

Modified: Zope/trunk/lib/python/Products/PageTemplates/PageTemplate.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/PageTemplate.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/PageTemplate.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -12,65 +12,47 @@
 ##############################################################################
 """Page Template module
 
-HTML- and XML-based template objects using TAL, TALES, and METAL.
+$Id$
 """
+import sys
+import ExtensionClass
+import zope.pagetemplate.pagetemplate
+from zope.pagetemplate.pagetemplate import _error_start, PTRuntimeError
+from zope.pagetemplate.pagetemplate import PageTemplateTracebackSupplement
+from zope.tales.expressions import SimpleModuleImporter
+from Products.PageTemplates.Expressions import getEngine
 
-__version__='$Revision: 1.31 $'[11:-2]
+##############################################################################
+# BBB 2005/05/01 -- to be removed after 12 months
+_ModuleImporter = SimpleModuleImporter
+ModuleImporter = SimpleModuleImporter()
+import zope.deprecation
+zope.deprecation.deprecated(
+    ('ModuleImporter', '_ModuleImporter'),
+    "Zope 2 uses the Zope 3 ZPT engine now.  ModuleImporter has moved "
+    "to zope.pagetemplate.pagetemplate.SimpleModuleImporter (this is a "
+    "class, not an instance)."
+    )
+zope.deprecation.deprecated(
+    ('PTRuntimeError', 'PageTemplateTracebackSupplement'),
+    "Zope 2 uses the Zope 3 ZPT engine now.  The object you're importing "
+    "has moved to zope.pagetemplate.pagetemplate.  This reference will "
+    "be gone in Zope 2.12.",
+    )
+##############################################################################
 
-import sys, types
+class PageTemplate(ExtensionClass.Base,
+                   zope.pagetemplate.pagetemplate.PageTemplate):
 
-from TAL.TALParser import TALParser
-from TAL.HTMLTALParser import HTMLTALParser
-from TAL.TALGenerator import TALGenerator
-# Do not use cStringIO here!  It's not unicode aware. :(
-from TAL.TALInterpreter import TALInterpreter, FasterStringIO
-from Expressions import getEngine
-from ExtensionClass import Base
-from ComputedAttribute import ComputedAttribute
+    def pt_getEngine(self):
+        return getEngine()
 
-
-class PageTemplate(Base):
-    "Page Templates using TAL, TALES, and METAL"
-
-    content_type = 'text/html'
-    expand = 0
-    _v_errors = ()
-    _v_warnings = ()
-    _v_program = None
-    _v_macros = None
-    _v_cooked = 0
-    id = '(unknown)'
-    _text = ''
-    _error_start = '<!-- Page Template Diagnostics'
-
-    def StringIO(self):
-        # Third-party products wishing to provide a full Unicode-aware
-        # StringIO can do so by monkey-patching this method.
-        return FasterStringIO()
-
-    def macros(self):
-        return self.pt_macros()
-    macros = ComputedAttribute(macros, 1)
-
-    def pt_edit(self, text, content_type):
-        if content_type:
-            self.content_type = str(content_type)
-        if hasattr(text, 'read'):
-            text = text.read()
-        charset = getattr(self, 'management_page_charset', None)
-        if charset and type(text) == types.StringType:
-            try:
-                unicode(text,'us-ascii')
-            except UnicodeDecodeError:
-                text = unicode(text, charset)
-        self.write(text)
-
     def pt_getContext(self):
         c = {'template': self,
              'options': {},
              'nothing': None,
              'request': None,
-             'modules': ModuleImporter,
+             'modules': SimpleModuleImporter(),
              }
         parent = getattr(self, 'aq_parent', None)
         if parent is not None:
@@ -83,145 +65,65 @@
             c['root'] = self
         return c
 
-    def pt_render(self, source=0, extra_context={}):
-        """Render this Page Template"""
-        if not self._v_cooked:
-            self._cook()
+    @property
+    def macros(self):
+        return self.pt_macros()
 
-        __traceback_supplement__ = (PageTemplateTracebackSupplement, self)
-
+    # sub classes may override this to do additional stuff for macro access
+    def pt_macros(self):
+        self._cook_check()
         if self._v_errors:
-            e = str(self._v_errors)
+            __traceback_supplement__ = (PageTemplateTracebackSupplement, self, {})
             raise PTRuntimeError, (
-                'Page Template %s has errors: %s' % (self.id, e))
-        output = self.StringIO()
+                'Page Template %s has errors: %s' % (
+                self.id, self._v_errors
+                ))
+        return self._v_macros
+
+    # these methods are reimplemented or duplicated here because of
+    # different call signatures in the Zope 2 world
+
+    def pt_render(self, source=False, extra_context={}):
         c = self.pt_getContext()
         c.update(extra_context)
+        return super(PageTemplate, self).pt_render(c, source=source)
 
-        TALInterpreter(self._v_program, self._v_macros,
-                       getEngine().getContext(c),
-                       output,
-                       tal=not source, strictinsert=0)()
-        return output.getvalue()
-
-    def __call__(self, *args, **kwargs):
-        if not kwargs.has_key('args'):
-            kwargs['args'] = args
-        return self.pt_render(extra_context={'options': kwargs})
-
-    def pt_errors(self):
-        if not self._v_cooked:
-            self._cook()
+    def pt_errors(self, namespace={}):
+        self._cook_check()
         err = self._v_errors
         if err:
             return err
-        if not self.expand: return
         try:
-            self.pt_render(source=1)
+            self.pt_render(source=True, extra_context=namespace)
         except:
             return ('Macro expansion failed', '%s: %s' % sys.exc_info()[:2])
 
-    def pt_warnings(self):
-        if not self._v_cooked:
-            self._cook()
-        return self._v_warnings
+    def __call__(self, *args, **kwargs):
+        if not kwargs.has_key('args'):
+            kwargs['args'] = args
+        return self.pt_render(extra_context={'options': kwargs})
 
-    def pt_macros(self):
-        if not self._v_cooked:
-            self._cook()
-        if self._v_errors:
-            __traceback_supplement__ = (PageTemplateTracebackSupplement, self)
-            raise PTRuntimeError, (
-                'Page Template %s has errors: %s' % (
-                self.id,
-                self._v_errors
-                ))
-        return self._v_macros
-
-    def pt_source_file(self):
-        return None  # Unknown.
-
-    def write(self, text):
-        assert type(text) in types.StringTypes
-        if text[:len(self._error_start)] == self._error_start:
-            errend = text.find('-->')
-            if errend >= 0:
-                text = text[errend + 4:]
-        if self._text != text:
-            self._text = text
-        self._cook()
-
     def read(self):
         self._cook_check()
         if not self._v_errors:
             if not self.expand:
                 return self._text
             try:
-                return self.pt_render(source=1)
+                return self.pt_render(source=True)
             except:
                 return ('%s\n Macro expansion failed\n %s\n-->\n%s' %
-                        (self._error_start, "%s: %s" % sys.exc_info()[:2],
+                        (_error_start, "%s: %s" % sys.exc_info()[:2],
                          self._text) )
 
-        return ('%s\n %s\n-->\n%s' % (self._error_start,
+        return ('%s\n %s\n-->\n%s' % (_error_start,
                                       '\n '.join(self._v_errors),
                                       self._text))
 
-    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.
-        """
-        source_file = self.pt_source_file()
-        if self.html():
-            gen = TALGenerator(getEngine(), xml=0, source_file=source_file)
-            parser = HTMLTALParser(gen)
-        else:
-            gen = TALGenerator(getEngine(), 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_warnings = parser.getWarnings()
-        self._v_cooked = 1
-
+    # convenience method for the ZMI which allows to explicitly
+    # specify the HTMLness of a template.  The old Zope 2
+    # implementation had this as well, but arguably on the wrong class
+    # (this should be a ZopePageTemplate thing if at all)
     def html(self):
         if not hasattr(getattr(self, 'aq_base', self), 'is_html'):
             return self.content_type == 'text/html'
         return self.is_html
-
-class _ModuleImporter:
-    def __getitem__(self, module):
-        mod = __import__(module)
-        path = module.split('.')
-        for name in path[1:]:
-            mod = getattr(mod, name)
-        return mod
-
-ModuleImporter = _ModuleImporter()
-
-class PTRuntimeError(RuntimeError):
-    '''The Page Template has template errors that prevent it from rendering.'''
-    pass
-
-
-class PageTemplateTracebackSupplement:
-    #__implements__ = ITracebackSupplement
-
-    def __init__(self, pt):
-        self.object = pt
-        w = pt.pt_warnings()
-        e = pt.pt_errors()
-        if e:
-            w = list(w) + list(e)
-        self.warnings = w
-


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/PageTemplate.py
___________________________________________________________________
Name: svn:executable
   - *
Name: svn:keywords
   + Id

Modified: Zope/trunk/lib/python/Products/PageTemplates/PageTemplateFile.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/PageTemplateFile.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/PageTemplateFile.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,33 +10,36 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-"""Filesystem Page Template module
 
-Zope object encapsulating a Page Template from the filesystem.
-"""
+import os
+from logging import getLogger
 
-__version__ = '$Revision: 1.30 $'[11:-2]
-
-import os, AccessControl
-from logging import getLogger
-from Globals import package_home, DevelopmentMode
+import AccessControl
+from Globals import package_home, InitializeClass, DevelopmentMode
+from App.config import getConfiguration
+from Acquisition import aq_parent, aq_inner
+from ComputedAttribute import ComputedAttribute
+from OFS.SimpleItem import SimpleItem
+from OFS.Traversable import Traversable
 from Shared.DC.Scripts.Script import Script
 from Shared.DC.Scripts.Signature import FuncCode
-from AccessControl import getSecurityManager
-from OFS.Traversable import Traversable
-from PageTemplate import PageTemplate
-from Expressions import SecureModuleImporter
-from ComputedAttribute import ComputedAttribute
-from Acquisition import aq_parent, aq_inner
-from App.config import getConfiguration
-from OFS.SimpleItem import Item_w__name__
+from Products.PageTemplates.Expressions import SecureModuleImporter
+from Products.PageTemplates.PageTemplate import PageTemplate
 
+from zope.contenttype import guess_content_type
+from zope.pagetemplate.pagetemplatefile import sniff_type
 
 LOG = getLogger('PageTemplateFile')
 
-class PageTemplateFile(Item_w__name__, Script, PageTemplate, Traversable):
-    "Zope wrapper for filesystem Page Template using TAL, TALES, and METAL"
+def guess_type(filename, text):
+    content_type, dummy = guess_content_type(filename, text)
+    if content_type in ('text/html', 'text/xml'):
+        return content_type
+    return sniff_type(text) or 'text/html'
 
+class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable):
+    """Zope 2 implementation of a PageTemplate loaded from a file."""
+
     meta_type = 'Page Template (File)'
 
     func_defaults = None
@@ -53,29 +56,35 @@
     security.declareProtected('View management screens',
       'read', 'document_src')
 
+    _default_bindings = {'name_subpath': 'traverse_subpath'}
+
     def __init__(self, filename, _prefix=None, **kw):
-        self.ZBindings_edit(self._default_bindings)
-        if _prefix is None:
-            _prefix = getConfiguration().softwarehome
-        elif not isinstance(_prefix, str):
-            _prefix = package_home(_prefix)
-        name = kw.get('__name__')
+        name = None
+        if kw.has_key('__name__'):
+            name = kw['__name__']
+            del kw['__name__'] 
+
         basepath, ext = os.path.splitext(filename)
+
         if name:
-            self._need__name__ = 0
-            self.__name__ = name
+            self.id = self.__name__ = name
         else:
-            self.__name__ = os.path.basename(basepath)
+            self.id = self.__name__ = os.path.basename(basepath)
+
+        if _prefix:
+            if isinstance(_prefix, str):
+                filename = os.path.join(_prefix, filename)
+            else:
+                filename = os.path.join(package_home(_prefix), filename)
+
         if not ext:
-            # XXX This is pretty bogus, but can't be removed since
-            # it's been released this way.
             filename = filename + '.zpt'
-        self.filename = os.path.join(_prefix, filename)
 
-    def getId(self):
-        """return the ID of this object"""
-        return self.__name__
-    
+        self.filename = filename
+
+        content = open(filename).read()
+        self.pt_edit( content, guess_type(filename, content))
+
     def pt_getContext(self):
         root = self.getPhysicalRoot()
         context = self._getContext()
@@ -106,10 +115,13 @@
             pass
 
         # Execute the template in a new security context.
-        security = getSecurityManager()
+        security = AccessControl.getSecurityManager()
         bound_names['user'] = security.getUser()
         security.addContext(self)
+
         try:
+            context = self.pt_getContext()
+            context.update(bound_names)
             return self.pt_render(extra_context=bound_names)
         finally:
             security.removeContext(self)
@@ -187,6 +199,7 @@
         raise StorageError, ("Instance of AntiPersistent class %s "
                              "cannot be stored." % self.__class__.__name__)
 
+InitializeClass(PageTemplateFile)
 
 XML_PREFIXES = [
     "<?xml",                      # ascii, utf-8


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/PageTemplateFile.py
___________________________________________________________________
Name: svn:executable
   - *

Modified: Zope/trunk/lib/python/Products/PageTemplates/PathIterator.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/PathIterator.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/PathIterator.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,37 +10,16 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-
 """Path Iterator
 
-A TALES Iterator with the ability to use first() and last() on
-subpaths of elements.
-"""
+BBB 2005/05/01 -- to be removed after 12 months
 
-__version__='$Revision: 1.4 $'[11:-2]
-
-import TALES
-from Expressions import restrictedTraverse, Undefs, getSecurityManager
-
-class Iterator(TALES.Iterator):
-    def __bobo_traverse__(self, REQUEST, name):
-        if name in ('first', 'last'):
-            path = REQUEST['TraversalRequestNameStack']
-            names = list(path)
-            names.reverse()
-            path[:] = [tuple(names)]
-        return getattr(self, name)
-
-    def same_part(self, name, ob1, ob2):
-        if name is None:
-            return ob1 == ob2
-        if isinstance(name, type('')):
-            name = name.split('/')
-        name = filter(None, name)
-        securityManager = getSecurityManager()
-        try:
-            ob1 = restrictedTraverse(ob1, name, securityManager)
-            ob2 = restrictedTraverse(ob2, name, securityManager)
-        except Undefs:
-            return 0
-        return ob1 == ob2
+$Id$
+"""
+import zope.deferredimport
+zope.deferredimport.deprecated(
+    "It has been renamed to PathIterator and moved to the "
+    "Products.PageTemplates.Expressions module.  This reference will be "
+    "gone in Zope 2.12.",
+    PathIterator = "Products.PageTemplates.Expressions:PathIterator"
+    )


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/PathIterator.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: Zope/trunk/lib/python/Products/PageTemplates/PythonExpr.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/PythonExpr.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/PythonExpr.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,77 +10,10 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-
 """Generic Python Expression Handler
-"""
 
-__version__='$Revision: 1.13 $'[11:-2]
-
-from TALES import CompilerError
-from sys import exc_info
-from DeferExpr import DeferWrapper
-
-class getSecurityManager:
-    '''Null security manager'''
-    def validate(self, *args, **kwargs):
-        return 1
-    addContext = removeContext = validate
-
-class PythonExpr:
-    def __init__(self, name, expr, engine):
-        self.expr = expr = expr.strip().replace('\n', ' ')
-        try:
-            d = {}
-            exec 'def f():\n return %s\n' % expr.strip() in d
-            self._f = d['f']
-        except:
-            raise CompilerError, ('Python expression error:\n'
-                                  '%s: %s') % exc_info()[:2]
-        self._get_used_names()
-
-    def _get_used_names(self):
-        self._f_varnames = vnames = []
-        for vname in self._f.func_code.co_names:
-            if vname[0] not in '$_':
-                vnames.append(vname)
-
-    def _bind_used_names(self, econtext, _marker=[]):
-        # Bind template variables
-        names = {'CONTEXTS': econtext.contexts}
-        vars = econtext.vars
-        getType = econtext.getCompiler().getTypes().get
-        for vname in self._f_varnames:
-            val = vars.get(vname, _marker)
-            if val is _marker:
-                has = val = getType(vname)
-                if has:
-                    val = ExprTypeProxy(vname, val, econtext)
-                    names[vname] = val
-            else:
-                names[vname] = val
-        for key, val in names.items():
-            if isinstance(val, DeferWrapper):
-                names[key] = val()
-        return names
-
-    def __call__(self, econtext):
-        __traceback_info__ = self.expr
-        f = self._f
-        f.func_globals.update(self._bind_used_names(econtext))
-        return f()
-
-    def __str__(self):
-        return 'Python expression "%s"' % self.expr
-    def __repr__(self):
-        return '<PythonExpr %s>' % self.expr
-
-class ExprTypeProxy:
-    '''Class that proxies access to an expression type handler'''
-    def __init__(self, name, handler, econtext):
-        self._name = name
-        self._handler = handler
-        self._econtext = econtext
-    def __call__(self, text):
-        return self._handler(self._name, text,
-                             self._econtext.getCompiler())(self._econtext)
-
+$Id$
+"""
+# BBB 2005/05/01 -- remove after 12 months
+import zope.deprecation
+zope.deprecation.moved("zope.tales.pythonexpr", "2.12")


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/PythonExpr.py
___________________________________________________________________
Name: svn:keywords
   + Id

Deleted: Zope/trunk/lib/python/Products/PageTemplates/README.txt
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/README.txt	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/README.txt	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,7 +0,0 @@
-See <a href="http://dev.zope.org/Wikis/DevSite/Projects/ZPT">the
-ZPT project Wiki</a> for more information about Page Templates, or
-<a href="http://www.zope.org/Members/4am/ZPT">the download page</a>
-for installation instructions and the most recent version of the software.
-
-This Product requires the TAL and ZTUtils packages to be installed in
-your Python path (not Products).  See the links above for more information.

Modified: Zope/trunk/lib/python/Products/PageTemplates/TALES.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/TALES.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/TALES.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -12,40 +12,15 @@
 ##############################################################################
 """TALES
 
-An implementation of a generic TALES engine
+BBB 2005/05/01 -- to be removed after 12 months
+
+$Id$
 """
+from zope.tales.tests.simpleexpr import SimpleExpr
+from zope.tales.tales import ExpressionEngine as Engine
+from zope.tales.tales import _default as Default
 
-__version__='$Revision: 1.39 $'[11:-2]
-
-import re, sys, ZTUtils
-from weakref import ref
 from MultiMapping import MultiMapping
-from DocumentTemplate.DT_Util import ustr
-from GlobalTranslationService import getGlobalTranslationService
-from zExceptions import Unauthorized
-
-StringType = type('')
-
-NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*"
-_parse_expr = re.compile(r"(%s):" % NAME_RE).match
-_valid_name = re.compile('%s$' % NAME_RE).match
-
-class TALESError(Exception):
-    """Error during TALES expression evaluation"""
-
-class Undefined(TALESError):
-    '''Exception raised on traversal of an undefined path'''
-
-class RegistrationError(Exception):
-    '''TALES Type Registration Error'''
-
-class CompilerError(Exception):
-    '''TALES Compiler Error'''
-
-class Default:
-    '''Retain Default'''
-Default = Default()
-
 class SafeMapping(MultiMapping):
     '''Mapping with security declarations and limited method exposure.
 
@@ -60,241 +35,5 @@
     _push = MultiMapping.push
     _pop = MultiMapping.pop
 
-
-class Iterator(ZTUtils.Iterator):
-    def __init__(self, name, seq, context):
-        ZTUtils.Iterator.__init__(self, seq)
-        self.name = name
-        self._context_ref = ref(context)
-
-    def next(self):
-        if ZTUtils.Iterator.next(self):
-            context = self._context_ref()
-            if context is not None:
-                context.setLocal(self.name, self.item)
-            return 1
-        return 0
-
-
-class ErrorInfo:
-    """Information about an exception passed to an on-error handler."""
-    __allow_access_to_unprotected_subobjects__ = 1
-
-    def __init__(self, err, position=(None, None)):
-        if isinstance(err, Exception):
-            self.type = err.__class__
-            self.value = err
-        else:
-            self.type = err
-            self.value = None
-        self.lineno = position[0]
-        self.offset = position[1]
-
-
-class Engine:
-    '''Expression Engine
-
-    An instance of this class keeps a mutable collection of expression
-    type handlers.  It can compile expression strings by delegating to
-    these handlers.  It can provide an expression Context, which is
-    capable of holding state and evaluating compiled expressions.
-    '''
-    Iterator = Iterator
-
-    def __init__(self, Iterator=None):
-        self.types = {}
-        if Iterator is not None:
-            self.Iterator = Iterator
-
-    def registerType(self, name, handler):
-        if not _valid_name(name):
-            raise RegistrationError, 'Invalid Expression type "%s".' % name
-        types = self.types
-        if types.has_key(name):
-            raise RegistrationError, (
-                'Multiple registrations for Expression type "%s".' %
-                name)
-        types[name] = handler
-
-    def getTypes(self):
-        return self.types
-
-    def compile(self, expression):
-        m = _parse_expr(expression)
-        if m:
-            type = m.group(1)
-            expr = expression[m.end():]
-        else:
-            type = "standard"
-            expr = expression
-        try:
-            handler = self.types[type]
-        except KeyError:
-            raise CompilerError, (
-                'Unrecognized expression type "%s".' % type)
-        return handler(type, expr, self)
-
-    def getContext(self, contexts=None, **kwcontexts):
-        if contexts is not None:
-            if kwcontexts:
-                kwcontexts.update(contexts)
-            else:
-                kwcontexts = contexts
-        return Context(self, kwcontexts)
-
-    def getCompilerError(self):
-        return CompilerError
-
-class Context:
-    '''Expression Context
-
-    An instance of this class holds context information that it can
-    use to evaluate compiled expressions.
-    '''
-
-    _context_class = SafeMapping
-    position = (None, None)
-    source_file = None
-
-    def __init__(self, compiler, contexts):
-        self._compiler = compiler
-        self.contexts = contexts
-        contexts['nothing'] = None
-        contexts['default'] = Default
-
-        self.repeat_vars = rv = {}
-        # Wrap this, as it is visible to restricted code
-        contexts['repeat'] = rep =  self._context_class(rv)
-        contexts['loop'] = rep # alias
-
-        self.global_vars = gv = contexts.copy()
-        self.local_vars = lv = {}
-        self.vars = self._context_class(gv, lv)
-
-        # Keep track of what needs to be popped as each scope ends.
-        self._scope_stack = []
-
-    def getCompiler(self):
-        return self._compiler
-
-    def beginScope(self):
-        self._scope_stack.append([self.local_vars.copy()])
-
-    def endScope(self):
-        scope = self._scope_stack.pop()
-        self.local_vars = lv = scope[0]
-        v = self.vars
-        v._pop()
-        v._push(lv)
-        # Pop repeat variables, if any
-        i = len(scope) - 1
-        while i:
-            name, value = scope[i]
-            if value is None:
-                del self.repeat_vars[name]
-            else:
-                self.repeat_vars[name] = value
-            i = i - 1
-
-    def setLocal(self, name, value):
-        self.local_vars[name] = value
-
-    def setGlobal(self, name, value):
-        self.global_vars[name] = value
-
-    def setRepeat(self, name, expr):
-        expr = self.evaluate(expr)
-        if not expr:
-            return self._compiler.Iterator(name, (), self)
-        it = self._compiler.Iterator(name, expr, self)
-        old_value = self.repeat_vars.get(name)
-        self._scope_stack[-1].append((name, old_value))
-        self.repeat_vars[name] = it
-        return it
-
-    def evaluate(self, expression,
-                 isinstance=isinstance, StringType=StringType):
-        if isinstance(expression, StringType):
-            expression = self._compiler.compile(expression)
-        __traceback_supplement__ = (
-            TALESTracebackSupplement, self, expression)
-        return expression(self)
-
-    evaluateValue = evaluate
-    evaluateBoolean = evaluate
-
-    def evaluateText(self, expr):
-        text = self.evaluate(expr)
-        if text is Default or text is None:
-            return text
-        return ustr(text)
-
-    def evaluateStructure(self, expr):
-        return self.evaluate(expr)
-    evaluateStructure = evaluate
-
-    def evaluateMacro(self, expr):
-        # XXX Should return None or a macro definition
-        return self.evaluate(expr)
-    evaluateMacro = evaluate
-
-    def createErrorInfo(self, err, position):
-        return ErrorInfo(err, position)
-
-    def getDefault(self):
-        return Default
-
-    def setSourceFile(self, source_file):
-        self.source_file = source_file
-
-    def setPosition(self, position):
-        self.position = position
-
-    def translate(self, domain, msgid, mapping=None,
-                  context=None, target_language=None, default=None):
-        if context is None:
-            context = self.contexts.get('here')
-        return getGlobalTranslationService().translate(
-            domain, msgid, mapping=mapping,
-            context=context,
-            default=default,
-            target_language=target_language)
-    
-    def getValue(self, name, default=None):
-        return self.vars.get(name, default)
-
-class TALESTracebackSupplement:
-    """Implementation of ITracebackSupplement"""
-    def __init__(self, context, expression):
-        self.context = context
-        self.source_url = context.source_file
-        self.line = context.position[0]
-        self.column = context.position[1]
-        self.expression = repr(expression)
-
-    def getInfo(self, as_html=0):
-        import pprint
-        from cgi import escape
-        data = self.context.contexts.copy()
-        try:
-            s = pprint.pformat(data)
-        except Unauthorized, e:
-            s = '   - %s: %s' % (getattr(e, '__class__', type(e)), e)
-            if as_html:
-                s = escape(s)
-            return s
-        if not as_html:
-            return '   - Names:\n      %s' % s.replace('\n', '\n      ')
-        else:
-            return '<b>Names:</b><pre>%s</pre>' % (escape(s))
-
-
-class SimpleExpr:
-    '''Simple example of an expression type handler'''
-    def __init__(self, name, expr, engine):
-        self._name = name
-        self._expr = expr
-    def __call__(self, econtext):
-        return self._name, self._expr
-    def __repr__(self):
-        return '<SimpleExpr %s %s>' % (self._name, `self._expr`)
+import zope.deprecation
+zope.deprecation.moved("zope.tales.tales", "2.12")

Deleted: Zope/trunk/lib/python/Products/PageTemplates/ZPythonExpr.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/ZPythonExpr.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/ZPythonExpr.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,66 +0,0 @@
-##############################################################################
-#
-# 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
-#
-##############################################################################
-
-"""Old Zope-specific Python Expression Handler
-
-Handler for Python expressions, using the pre-Python 2.1 restriction
-machinery from PythonScripts.
-"""
-
-__version__='$Revision: 1.8 $'[11:-2]
-
-from AccessControl import getSecurityManager
-from Products.PythonScripts.Guarded import _marker, \
-     GuardedBlock, theGuard, safebin, WriteGuard, ReadGuard, UntupleFunction
-from TALES import CompilerError
-
-from PythonExpr import PythonExpr
-
-class PythonExpr(PythonExpr):
-    def __init__(self, name, expr, engine):
-        self.expr = expr = expr.strip().replace('\n', ' ')
-        blk = GuardedBlock('def f():\n return \\\n %s\n' % expr)
-        if blk.errors:
-            raise CompilerError, ('Python expression error:\n%s' %
-                                  '\n'.join(blk.errors) )
-        guards = {'$guard': theGuard, '$write_guard': WriteGuard,
-                  '$read_guard': ReadGuard, '__debug__': __debug__}
-        self._f = UntupleFunction(blk.t, guards, __builtins__=safebin)
-        self._get_used_names()
-
-class _SecureModuleImporter:
-    __allow_access_to_unprotected_subobjects__ = 1
-    def __getitem__(self, module):
-        mod = safebin['__import__'](module)
-        path = module.split('.')
-        for name in path[1:]:
-            mod = getattr(mod, name)
-        return mod
-
-from DocumentTemplate.DT_Util import TemplateDict, InstanceDict
-def validate(accessed, container, name, value, dummy):
-    return getSecurityManager().validate(accessed, container, name, value)
-def call_with_ns(f, ns, arg=1):
-    td = TemplateDict()
-    td.validate = validate
-    td.this = ns['here']
-    td._push(ns['request'])
-    td._push(InstanceDict(td.this, td))
-    td._push(ns)
-    try:
-        if arg==2:
-            return f(None, td)
-        else:
-            return f(td)
-    finally:
-        td._pop(3)

Modified: Zope/trunk/lib/python/Products/PageTemplates/ZRPythonExpr.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/ZRPythonExpr.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/ZRPythonExpr.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,44 +10,41 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-
 """Zope-specific Python Expression Handler
 
 Handler for Python expressions that uses the RestrictedPython package.
-"""
 
-__version__='$Revision: 1.11 $'[11:-2]
-
+$Id$
+"""
 from AccessControl import safe_builtins
 from AccessControl.ZopeGuards import guarded_getattr, get_safe_globals
 from RestrictedPython import compile_restricted_eval
-from TALES import CompilerError
+from zope.tales.tales import CompilerError
+from zope.tales.pythonexpr import PythonExpr
 
-from PythonExpr import PythonExpr
-
 class PythonExpr(PythonExpr):
     _globals = get_safe_globals()
     _globals['_getattr_'] = guarded_getattr
     _globals['__debug__' ] = __debug__
 
     def __init__(self, name, expr, engine):
-        self.expr = expr = expr.strip().replace('\n', ' ')
-        code, err, warn, use = compile_restricted_eval(expr, str(self))
+        self.text = text = expr.strip().replace('\n', ' ')
+        code, err, warn, use = compile_restricted_eval(text, str(self))
         if err:
-            raise CompilerError, ('Python expression error:\n%s' %
-                                  '\n'.join(err) )
-        self._f_varnames = use.keys()
+            raise engine.getCompilerError()('Python expression error:\n%s' %
+                                            '\n'.join(err))            
+        self._varnames = use.keys()
         self._code = code
 
     def __call__(self, econtext):
-        __traceback_info__ = self.expr
-        code = self._code
-        g = self._bind_used_names(econtext)
-        g.update(self._globals)
-        return eval(code, g, {})
+        __traceback_info__ = self.text
+        vars = self._bind_used_names(econtext, {})
+        vars.update(self._globals)
+        return eval(self._code, vars, {})
 
 class _SecureModuleImporter:
-    __allow_access_to_unprotected_subobjects__ = 1
+    __allow_access_to_unprotected_subobjects__ = True
+
     def __getitem__(self, module):
         mod = safe_builtins['__import__'](module)
         path = module.split('.')


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/ZRPythonExpr.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: Zope/trunk/lib/python/Products/PageTemplates/ZopePageTemplate.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/ZopePageTemplate.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/ZopePageTemplate.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,58 +10,56 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
+"""Zope Page Template module (wrapper for the Zope 3 ZPT implementation)
 
-""" Zope Page Template module (wrapper for the Zope 3 ZPT implementation) """
-
-__version__='$Revision: 1.48 $'[11:-2]
-
+$Id$
+"""
 import re
 import os
 import Acquisition 
 from Globals import ImageFile, package_home, InitializeClass
-from OFS.SimpleItem import SimpleItem
-from zope.contenttype import guess_content_type
 from DateTime.DateTime import DateTime
 from Shared.DC.Scripts.Script import Script 
 from Shared.DC.Scripts.Signature import FuncCode
 
+from OFS.SimpleItem import SimpleItem
 from OFS.History import Historical, html_diff
 from OFS.Cache import Cacheable
 from OFS.Traversable import Traversable
 from OFS.PropertyManager import PropertyManager
 
 from AccessControl import getSecurityManager, safe_builtins, ClassSecurityInfo
-from AccessControl.Permissions import view, ftp_access, change_page_templates, view_management_screens
+from AccessControl.Permissions import view, ftp_access, change_page_templates
+from AccessControl.Permissions import view_management_screens
 
 from webdav.Lockable import ResourceLockedError
 from webdav.WriteLockInterface import WriteLockInterface
-from zope.pagetemplate.pagetemplate import PageTemplate 
-from zope.pagetemplate.pagetemplatefile import sniff_type
 
-from Products.PageTemplates.Expressions import getEngine
+from Products.PageTemplates.PageTemplate import PageTemplate
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PageTemplates.PageTemplateFile import guess_type
+from Products.PageTemplates.Expressions import SecureModuleImporter
 
 # regular expression to extract the encoding from the XML preamble
-encoding_reg= re.compile('<\?xml.*?encoding="(.*?)".*?\?>', re.M)
+encoding_reg = re.compile('<\?xml.*?encoding="(.*?)".*?\?>', re.M)
 
 preferred_encodings = ['utf-8', 'iso-8859-15']
 if os.environ.has_key('ZPT_PREFERRED_ENCODING'):
     preferred_encodings.insert(0, os.environ['ZPT_PREFERRED_ENCODING'])
 
-class SecureModuleImporter:
-    __allow_access_to_unprotected_subobjects__ = 1
-    def __getitem__(self, module):
-        mod = safe_builtins['__import__'](module)
-        path = module.split('.')
-        for name in path[1:]:
-            mod = getattr(mod, name)
-        return mod
+def sniffEncoding(text, default_encoding='utf-8'):
+    """Try to determine the encoding from html or xml"""
+    if text.startswith('<?xml'):
+        mo = encoding_reg.search(text)
+        if mo:
+            return mo.group(1)
+    return default_encoding
 
-
 class Src(Acquisition.Explicit):
     """ I am scary code """
 
-    index_html = None
     PUT = document_src = Acquisition.Acquired
+    index_html = None
 
     def __before_publishing_traverse__(self, ob, request):
         if getattr(request, '_hacked_path', 0):
@@ -71,32 +69,9 @@
         " "
         return self.document_src(REQUEST)
 
-
-def sniffEncoding(text, default_encoding='utf-8'):
-    """ try to determine the encoding from html or xml """
-
-    if text.startswith('<?xml'):
-        mo = encoding_reg.search(text)
-        if mo:
-            return mo.group(1)
-    return default_encoding
-
-
-def guess_type(filename, text):
-
-    content_type, dummy = guess_content_type(filename, text)
-    if content_type in ('text/html', 'text/xml'):
-        return content_type
-
-    return sniff_type(text) or 'text/html'
-
-
-_default_content_fn = os.path.join(package_home(globals()), 'pt', 'default.html')
-  
-
 class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
                        Traversable, PropertyManager):
-    """ Z2 wrapper class for Zope 3 page templates """
+    "Zope wrapper for Page Template using TAL, TALES, and METAL"
 
     __implements__ = (WriteLockInterface,)
 
@@ -106,7 +81,8 @@
     func_code = FuncCode((), 0)
 
     _default_bindings = {'name_subpath': 'traverse_subpath'}
-    _default_content_fn = os.path.join(package_home(globals()), 'www', 'default.html')
+    _default_content_fn = os.path.join(package_home(globals()),
+                                       'www', 'default.html')
 
     manage_options = (
         {'label':'Edit', 'action':'pt_editForm',
@@ -125,36 +101,40 @@
 
     security = ClassSecurityInfo()
     security.declareObjectProtected(view)
+
+    # protect methods from base class(es)
     security.declareProtected(view, '__call__')
+    security.declareProtected(view_management_screens,
+                              'read', 'ZScriptHTML_tryForm')
 
-    def __init__(self, id, text=None, content_type=None, encoding='utf-8', strict=False):
+    def __init__(self, id, text=None, content_type=None, encoding='utf-8',
+                 strict=False):
         self.id = id
         self.expand = 0                                                               
         self.strict = strict
         self.ZBindings_edit(self._default_bindings)
+        if not text:
+            text = open(self._default_content_fn).read()
+            encoding = 'utf-8'
+            content_type = 'text/html'
         self.pt_edit(text, content_type, encoding)
 
-    def pt_render(self, namespace, source=False, sourceAnnotations=False,
-                  showtal=False):
-        if namespace is None:
-            namespace = self.pt_getContext()
-        return super(ZopePageTemplate, self).pt_render(namespace, source, sourceAnnotations,
-                  showtal)
-
-
-    def pt_getEngine(self):
-        return getEngine()
-
     security.declareProtected(change_page_templates, 'pt_edit')
     def pt_edit(self, text, content_type, encoding='utf-8'):
-
         text = text.strip()
         if self.strict and not isinstance(text, unicode):
             text = unicode(text, encoding)
 
         self.ZCacheable_invalidate()
-        PageTemplate.pt_edit(self, text, content_type)
+        super(ZopePageTemplate, self).pt_edit(text, content_type)
 
+    pt_editForm = PageTemplateFile('www/ptEdit', globals(),
+                                   __name__='pt_editForm')
+    pt_editForm._owner = None
+    manage = manage_main = pt_editForm
+
+    source_dot_xml = Src()
+
     security.declareProtected(change_page_templates, 'pt_editAction')
     def pt_editAction(self, REQUEST, title, text, content_type, encoding, expand):
         """Change the title and document."""
@@ -174,20 +154,17 @@
                        % '<br>'.join(self._v_warnings))
         return self.pt_editForm(manage_tabs_message=message)
 
-
     security.declareProtected(change_page_templates, 'pt_setTitle')
     def pt_setTitle(self, title, encoding='utf-8'):
         if self.strict and not isinstance(title, unicode):
             title = unicode(title, encoding)
         self._setPropValue('title', title)
 
-
     def _setPropValue(self, id, value):
         """ set a property and invalidate the cache """
         PropertyManager._setPropValue(self, id, value)
         self.ZCacheable_invalidate()
 
-
     security.declareProtected(change_page_templates, 'pt_upload')
     def pt_upload(self, REQUEST, file='', encoding='utf-8'):
         """Replace the document with the text in file."""
@@ -239,12 +216,12 @@
         """Parameters to test the script with."""
         return []
 
-#    def manage_historyCompare(self, rev1, rev2, REQUEST,
-#                              historyComparisonResults=''):
-#        return ZopePageTemplate.inheritedAttribute(
-#            'manage_historyCompare')(
-#            self, rev1, rev2, REQUEST,
-#            historyComparisonResults=html_diff(rev1._text, rev2._text) )
+    def manage_historyCompare(self, rev1, rev2, REQUEST,
+                              historyComparisonResults=''):
+        return ZopePageTemplate.inheritedAttribute(
+            'manage_historyCompare')(
+            self, rev1, rev2, REQUEST,
+            historyComparisonResults=html_diff(rev1._text, rev2._text) )
 
     def pt_getContext(self, *args, **kw):
         root = self.getPhysicalRoot()
@@ -257,12 +234,13 @@
              'options': {},
              'root': root,
              'request': getattr(root, 'REQUEST', None),
-             'modules': SecureModuleImporter(),
+             'modules': SecureModuleImporter,
              }
         return c
 
-    security.declareProtected(view_management_screens, 'read',
-      'ZScriptHTML_tryForm')
+    def write(self, text):
+        self.ZCacheable_invalidate()
+        ZopePageTemplate.inheritedAttribute('write')(self, text)
 
     def _exec(self, bound_names, args, kw):
         """Call a Page Template"""
@@ -295,11 +273,7 @@
         security.addContext(self)
 
         try:
-            # XXX: check the parameters for pt_render()! (aj)
-            result = self.pt_render(self.pt_getContext())
-        
-
-#            result = self.pt_render(extra_context=bound_names)
+            result = self.pt_render(extra_context=bound_names)
             if keyset is not None:
                 # Store the result in the cache.
                 self.ZCacheable_set(result, keywords=keyset)
@@ -316,7 +290,7 @@
         """ Handle HTTP PUT requests """
         self.dav__init(REQUEST, RESPONSE)
         self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1)
-        ## XXX:this should be unicode or we must pass an encoding
+        ## XXX this should be unicode or we must pass an encoding
         self.pt_edit(REQUEST.get('BODY', ''))
         RESPONSE.setStatus(204)
         return RESPONSE
@@ -325,7 +299,6 @@
     manage_FTPput = PUT
 
     security.declareProtected(ftp_access, 'manage_FTPstat','manage_FTPlist')
-
     security.declareProtected(ftp_access, 'manage_FTPget')
     def manage_FTPget(self):
         "Get source for FTP download"
@@ -369,7 +342,6 @@
                               'title': 'This template has an error'},)
         return icons
 
-
     security.declareProtected(view, 'pt_source_file')
     def pt_source_file(self):
         """Returns a file name to be compiled into the TAL code."""
@@ -383,24 +355,17 @@
     def wl_isLocked(self):
         return 0
 
-    security.declareProtected(view, 'strictUnicode')
-    def strictUnicode(self):
-        """ Return True if the ZPT enforces the use of unicode,
-            False otherwise.
-        """
-        return self.strict
-
-
-    def manage_convertUnicode(self, preferred_encodings=preferred_encodings, RESPONSE=None):
-        """ convert non-unicode templates to unicode """
-
+    def manage_convertUnicode(self, preferred_encodings=preferred_encodings,
+                              RESPONSE=None):
+        """Convert non-unicode templates to unicode"""
         if not isinstance(self._text, unicode):
-
             for encoding in preferred_encodings:
                 try:
                     self._text = unicode(self._text, encoding)
                     if RESPONSE:
-                        return RESPONSE.redirect(self.absolute_url() + '/pt_editForm?manage_tabs_message=ZPT+successfully+converted')
+                        return RESPONSE.redirect(self.absolute_url() +
+                                                 '/pt_editForm?manage_tabs_message='
+                                                 'ZPT+successfully+converted')
                     else:
                         return
                 except UnicodeDecodeError:
@@ -410,49 +375,23 @@
 
         else:
             if RESPONSE:
-                return RESPONSE.redirect(self.absolute_url() + '/pt_editForm?manage_tabs_message=ZPT+already+converted')
+                return RESPONSE.redirect(self.absolute_url() +
+                                         '/pt_editForm?manage_tabs_message='
+                                         'ZPT+already+converted')
             else:
                 return
 
-
-    security.declareProtected(view_management_screens, 'getSource')
-    getSource = Src()
-    source_dot_xml = Src()
-
 InitializeClass(ZopePageTemplate)
 
-
 setattr(ZopePageTemplate, 'source.xml',  ZopePageTemplate.source_dot_xml)
 setattr(ZopePageTemplate, 'source.html', ZopePageTemplate.source_dot_xml)
 
+# Product registration and Add support
+manage_addPageTemplateForm = PageTemplateFile(
+    'www/ptAdd', globals(), __name__='manage_addPageTemplateForm')
 
-def _newZPT(id, filename):
-    """ factory to generate ZPT instances from the file-system
-        based templates (basically for internal purposes)
-    """
-    zpt = ZopePageTemplate(id, open(filename).read(), 'text/html')
-    zpt.__name__= id
-    return zpt
-
-class FSZPT(ZopePageTemplate):
-    """ factory to generate ZPT instances from the file-system
-        based templates (basically for internal purposes)
-    """
-
-    def __init__(self, id, filename):
-        ZopePageTemplate.__init__(self, id, open(filename).read(), 'text/html')
-        self.__name__= id
-
-InitializeClass(FSZPT)
-
-
-ZopePageTemplate.pt_editForm = FSZPT('pt_editForm', os.path.join(package_home(globals()),'pt', 'ptEdit.pt'))
-# this is scary, do we need this?
-ZopePageTemplate.manage = ZopePageTemplate.pt_editForm
-
-manage_addPageTemplateForm= FSZPT('manage_addPageTemplateForm', os.path.join(package_home(globals()), 'pt', 'ptAdd.pt'))
-
-def manage_addPageTemplate(self, id, title='', text='', encoding='utf-8', submit=None, REQUEST=None, RESPONSE=None):
+def manage_addPageTemplate(self, id, title='', text='', encoding='utf-8',
+                           submit=None, REQUEST=None, RESPONSE=None):
     "Add a Page Template with optional file content."
 
     filename = ''
@@ -480,11 +419,6 @@
                 content_type = guess_type(filename, text) 
         encoding = sniffEncoding(text, encoding)
 
-    if not text:
-        text = open(_default_content_fn).read()
-        encoding = 'utf-8'
-        content_type = 'text/html'
-
     zpt = ZopePageTemplate(id, text, content_type, encoding)
     zpt.pt_setTitle(title, encoding)
     self._setObject(id, zpt)
@@ -499,7 +433,7 @@
         return zpt
 
 from Products.PageTemplates import misc_
-misc_['exclamation.gif'] = ImageFile('pt/exclamation.gif', globals())
+misc_['exclamation.gif'] = ImageFile('www/exclamation.gif', globals())
 
 def initialize(context):
     context.registerClass(
@@ -507,7 +441,7 @@
         permission='Add Page Templates',
         constructors=(manage_addPageTemplateForm,
                       manage_addPageTemplate),
-        icon='pt/zpt.gif',
+        icon='www/zpt.gif',
         )
     context.registerHelp()
     context.registerHelpTitle('Zope Help')


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/ZopePageTemplate.py
___________________________________________________________________
Name: svn:executable
   - *
Name: svn:keywords
   + Id

Modified: Zope/trunk/lib/python/Products/PageTemplates/__init__.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/__init__.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/__init__.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,15 +10,14 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-__doc__='''Package wrapper for Page Templates
+"""Package wrapper for Page Templates
 
 This wrapper allows the Page Template modules to be segregated in a
 separate package.
 
-$Id$'''
-__version__='$$'[11:-2]
+$Id$
+"""
 
-
 # Placeholder for Zope Product data
 misc_ = {}
 

Modified: Zope/trunk/lib/python/Products/PageTemplates/tests/__init__.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/tests/__init__.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/tests/__init__.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,36 +1 @@
-def all():
-    import testTALES
-    return testTALES.test_suite()
-
-class harness1:
-    def __init__(self):
-        self.__callstack = []
-
-    def _assert_(self, name, *args, **kwargs):
-        self.__callstack.append((name, args, kwargs))
-
-    def _complete_(self):
-        assert len(self.__callstack) == 0, "Harness methods called"
-
-    def __getattr__(self, name):
-        cs = self.__callstack
-        assert len(cs), 'Unexpected harness method call "%s".' % name
-        assert cs[0][0] == name, (
-            'Harness method name "%s" called, "%s" expected.' %
-            (name, cs[0][0]) )
-        return self._method_
-
-    def _method_(self, *args, **kwargs):
-        name, aargs, akwargs = self.__callstack.pop(0)
-        assert aargs == args, "Harness method arguments"
-        assert akwargs == kwargs, "Harness method keyword args"
-
-class harness2(harness1):
-    def _assert_(self, name, result, *args, **kwargs):
-        self.__callstack.append((name, result, args, kwargs))
-
-    def _method_(self, *args, **kwargs):
-        name, result, aargs, akwargs = self.__callstack.pop(0)
-        assert aargs == args, "Harness method arguments"
-        assert akwargs == kwargs, "Harness method keyword args"
-        return result
+# make this directory a package

Copied: Zope/trunk/lib/python/Products/PageTemplates/tests/input/CheckImportOldStyleClass.html (from rev 68332, Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/tests/input/CheckImportOldStyleClass.html)

Modified: Zope/trunk/lib/python/Products/PageTemplates/tests/output/CheckI18nTranslateHooked.html
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/tests/output/CheckI18nTranslateHooked.html	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/tests/output/CheckI18nTranslateHooked.html	2006-05-29 10:34:19 UTC (rev 68333)
@@ -4,7 +4,7 @@
    <p>[foo](bar/{})</p>
    <a href="foo" alt="[default](alttext/{})">link</a>
    <p>[dom](${name} was born in ${country}./{'country':'Antarctica','name':'Lomax'})</p>
-   <p>[default](hmm/{'age':'25'})</p>
+   <p>[default](hmm/{'age':u'25'})</p>
 </head>
 </body>
 </html>

Copied: Zope/trunk/lib/python/Products/PageTemplates/tests/output/CheckImportOldStyleClass.html (from rev 68332, Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/tests/output/CheckImportOldStyleClass.html)

Modified: Zope/trunk/lib/python/Products/PageTemplates/tests/testDTMLTests.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/tests/testDTMLTests.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/tests/testDTMLTests.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -11,8 +11,10 @@
 #
 ##############################################################################
 
-import os, sys, unittest
+import unittest
 
+import zope.component.testing
+from zope.traversing.adapters import DefaultTraversable
 from Products.PageTemplates.tests import util
 from Products.PageTemplates.PageTemplate import PageTemplate
 from Acquisition import Implicit
@@ -43,16 +45,20 @@
     def checkPermission( self, permission, object, context) :
         return 1
 
-class DTMLTests(unittest.TestCase):
+class DTMLTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
 
     def setUp(self):
-        self.t=(AqPageTemplate())
+        super(DTMLTests, self).setUp()
+        zope.component.provideAdapter(DefaultTraversable, (None,))
+
+        self.t = AqPageTemplate()
         self.policy = UnitTestSecurityPolicy()
-        self.oldPolicy = SecurityManager.setSecurityPolicy( self.policy )
+        self.oldPolicy = SecurityManager.setSecurityPolicy(self.policy)
         noSecurityManager()  # Use the new policy.
 
     def tearDown(self):
-        SecurityManager.setSecurityPolicy( self.oldPolicy )
+        super(DTMLTests, self).tearDown()
+        SecurityManager.setSecurityPolicy(self.oldPolicy)
         noSecurityManager()  # Reset to old policy.
 
     def check1(self):

Modified: Zope/trunk/lib/python/Products/PageTemplates/tests/testExpressions.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/tests/testExpressions.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/tests/testExpressions.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,5 +1,8 @@
-import os, sys, unittest
+import unittest
 
+import zope.component.testing
+from zope.traversing.adapters import DefaultTraversable
+
 from Products.PageTemplates import Expressions
 from Products.PageTemplates.DeferExpr import LazyWrapper
 from Products.PageTemplates.DeferExpr import DeferWrapper
@@ -9,9 +12,12 @@
     def __call__(self):
         return 'dummy'
 
-class ExpressionTests(unittest.TestCase):
+class ExpressionTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
 
     def setUp(self):
+        super(ExpressionTests, self).setUp()
+        zope.component.provideAdapter(DefaultTraversable, (None,))
+
         self.e = e = Expressions.getEngine()
         self.ec = e.getContext(
             one = 1,
@@ -20,9 +26,6 @@
             dummy = Dummy()
             )
 
-    def tearDown(self):
-        del self.e, self.ec
-
     def testCompile(self):
         '''Test expression compilation'''
         e = self.e
@@ -50,9 +53,11 @@
         '''Test advanced expression evaluation 1'''
         ec = self.ec
         assert ec.evaluate('x | nothing') is None
-        assert ec.evaluate('d/') == 'blank'
+        # empty path elements aren't supported anymore, for the lack
+        # of a use case
+        #assert ec.evaluate('d/') == 'blank'
         assert ec.evaluate('d/_') == 'under'
-        assert ec.evaluate('d/ | nothing') == 'blank'
+        #assert ec.evaluate('d/ | nothing') == 'blank'
         assert ec.evaluate('d/?blank') == 'blank'
 
     def testHybrid(self):
@@ -63,7 +68,7 @@
         assert ec.evaluate('x | string:x') == 'x'
         assert ec.evaluate('x | string:$one') == '1'
         assert ec.evaluate('x | not:exists:x')
-        
+
     def testWrappers(self):
         """Test if defer and lazy are returning their wrappers
         """

Modified: Zope/trunk/lib/python/Products/PageTemplates/tests/testHTMLTests.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/tests/testHTMLTests.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/tests/testHTMLTests.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -11,8 +11,10 @@
 #
 ##############################################################################
 
-import os, sys, unittest
+import unittest
 
+import zope.component.testing
+from zope.traversing.adapters import DefaultTraversable
 from Products.PageTemplates.tests import util
 from Products.PageTemplates.PageTemplate import PageTemplate
 from Products.PageTemplates.GlobalTranslationService import \
@@ -59,9 +61,12 @@
     def checkPermission( self, permission, object, context) :
         return 1
 
-class HTMLTests(unittest.TestCase):
+class HTMLTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
 
     def setUp(self):
+        super(HTMLTests, self).setUp()
+        zope.component.provideAdapter(DefaultTraversable, (None,))
+
         self.folder = f = Folder()
         f.laf = AqPageTemplate()
         f.t = AqPageTemplate()
@@ -70,6 +75,7 @@
         noSecurityManager()  # Use the new policy.
 
     def tearDown(self):
+        super(HTMLTests, self).tearDown()
         SecurityManager.setSecurityPolicy( self.oldPolicy )
         noSecurityManager()  # Reset to old policy.
 
@@ -156,6 +162,9 @@
         self.assert_expected(self.folder.t, 'CheckI18nTranslateHooked.html')
         setGlobalTranslationService(old_ts)
 
+    def checkImportOldStyleClass(self):
+        self.assert_expected(self.folder.t, 'CheckImportOldStyleClass.html')
+
 def test_suite():
     return unittest.makeSuite(HTMLTests, 'check')
 

Modified: Zope/trunk/lib/python/Products/PageTemplates/tests/testTALES.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/tests/testTALES.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/tests/testTALES.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,9 +1,19 @@
-import os, sys, unittest
+import unittest
 
+# BBB 2005/05/01 -- to be changed after 12 months
+# ignore deprecation warnings on import for now
+import warnings
+showwarning = warnings.showwarning
+warnings.showwarning = lambda *a, **k: None
+# this old import should remain here until the TALES.py module is
+# completely removed, so that API backward compatibility is properly
+# tested
 from Products.PageTemplates import TALES
-from Products.PageTemplates.tests import harness1
-import string
+# restore warning machinery
+warnings.showwarning = showwarning
 
+from zope.tales.tests.test_tales import Harness
+
 class DummyUnicodeExpr:
     '''Dummy expression type handler returning unicode'''
     def __init__(self, name, expr, engine):
@@ -18,14 +28,14 @@
 
     def testIterator0(self):
         '''Test sample Iterator class'''
-        context = harness1()
+        context = Harness(self)
         it = TALES.Iterator('name', (), context)
         assert not it.next(), "Empty iterator"
         context._complete_()
 
     def testIterator1(self):
         '''Test sample Iterator class'''
-        context = harness1()
+        context = Harness(self)
         it = TALES.Iterator('name', (1,), context)
         context._assert_('setLocal', 'name', 1)
         assert it.next() and not it.next(), "Single-element iterator"
@@ -33,7 +43,7 @@
 
     def testIterator2(self):
         '''Test sample Iterator class'''
-        context = harness1()
+        context = Harness(self)
         it = TALES.Iterator('text', 'text', context)
         for c in 'text':
             context._assert_('setLocal', 'text', c)
@@ -104,23 +114,25 @@
     def testVariables(self):
         '''Test variables'''
         ctxt = self.getContext()
-        c = ctxt.vars
         ctxt.beginScope()
         ctxt.setLocal('v1', 1)
         ctxt.setLocal('v2', 2)
 
+        c = ctxt.vars
         assert c['v1'] == 1, 'Variable "v1"'
 
         ctxt.beginScope()
         ctxt.setLocal('v1', 3)
         ctxt.setGlobal('g', 1)
 
+        c = ctxt.vars
         assert c['v1'] == 3, 'Inner scope'
         assert c['v2'] == 2, 'Outer scope'
         assert c['g'] == 1, 'Global'
 
         ctxt.endScope()
 
+        c = ctxt.vars
         assert c['v1'] == 1, "Uncovered local"
         assert c['g'] == 1, "Global from inner scope"
 


Property changes on: Zope/trunk/lib/python/Products/PageTemplates/tests/testZRPythonExpr.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: Zope/trunk/lib/python/Products/PageTemplates/tests/testZopePageTemplate.py
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/tests/testZopePageTemplate.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/tests/testZopePageTemplate.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -10,9 +10,9 @@
 import unittest
 import Zope2
 import transaction
-
+import zope.component.testing
+from zope.traversing.adapters import DefaultTraversable
 from Testing.makerequest import makerequest
-from Products.PageTemplates.ZopePageTemplate import _default_content_fn
 
 class ZPTRegressions(unittest.TestCase):
 
@@ -35,7 +35,7 @@
 
     def testAddWithoutParams(self):
         pt = self._addPT('pt1')
-        default_text = open(_default_content_fn).read()
+        default_text = open(pt._default_content_fn).read()
         self.assertEqual(pt.title, '')
         self.assertEqual(pt.document_src().strip(), default_text.strip())
 
@@ -58,8 +58,12 @@
         pt = self.app.pt1
         self.assertEqual(pt.document_src(), self.text)
 
-class ZPTMacros(unittest.TestCase):
+class ZPTMacros(zope.component.testing.PlacelessSetup, unittest.TestCase):
+
     def setUp(self):
+        super(ZPTMacros, self).setUp()
+        zope.component.provideAdapter(DefaultTraversable, (None,))
+
         transaction.begin()
         self.app = makerequest(Zope2.app())
         f = self.app.manage_addProduct['PageTemplates'].manage_addPageTemplate
@@ -86,8 +90,14 @@
     This is in the slot
   </p>
 </div>
-"""       
+"""
 
+    def tearDown(self):
+        super(ZPTMacros, self).tearDown()
+
+        transaction.abort()
+        self.app._p_jar.close()
+
     def testMacroExpansion(self):
         request = self.app.REQUEST        
         self._addPT('pt1', text=self.text, REQUEST=request)
@@ -98,9 +108,9 @@
         request = self.app.REQUEST        
         self._addPT('pt1', text=self.text, REQUEST=request)
         pt = self.app.pt1
-        pt.pt_render(None, source=1)
-        self.assertEqual(pt.pt_errors(None), None)
-        
+        pt.pt_render(source=True)
+        self.assertEqual(pt.pt_errors(), None)
+
 class DummyFileUpload:
 
     def __init__(self, data='', filename='', content_type=''):

Modified: Zope/trunk/lib/python/Products/PageTemplates/www/ptAdd.zpt
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/www/ptAdd.zpt	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/www/ptAdd.zpt	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,50 +1,51 @@
 <h1 tal:replace="structure here/manage_page_header">Header</h1>
-
 <h2 tal:define="form_title string:Add Page Template"
     tal:replace="structure here/manage_form_title">Form Title</h2>
 
-<p class="form-help">
-Page Templates allow you to use simple HTML or XML attributes to
-create dynamic templates.  You may choose to upload the template text
-from a local file by typing the file name or using the <em>browse</em>
-button.
-</p>
+<p class="form-help">Page Templates allow you to use simple HTML or
+XML attributes to create dynamic templates.  You may choose to upload
+the template text from a local file by typing the file name or using
+the <em>browse</em> button.</p>
 
 <form action="manage_addPageTemplate" method="post" 
- enctype="multipart/form-data">
+      enctype="multipart/form-data">
 <table cellspacing="0" cellpadding="2" border="0">
   <tr>
     <td align="left" valign="top">
-    <div class="form-label">
-    Id
-    </div>
+      <div class="form-label">Id</div>
     </td>
     <td align="left" valign="top">
-    <input type="text" name="id" size="40" />
+      <input type="text" name="id" size="40" />
     </td>
   </tr>
   <tr>
     <td align="left" valign="top">
-    <div class="form-optional">
-    File
-    </div>
+      <div class="form-optional">File</div>
     </td>
     <td align="left" valign="top">
-    <input type="file" name="file" size="25" value="" />
+      <input type="file" name="file" size="25" value="" />
     </td>
   </tr>
   <tr>
     <td align="left" valign="top">
+      <div class="form-optional">Encoding</div>
     </td>
     <td align="left" valign="top">
-    <div class="form-element">
-    <input class="form-element" type="submit" name="submit" 
-     value=" Add " /> 
-    <input class="form-element" type="submit" name="submit" 
-     value=" Add and Edit " />
-    </div>
+      <input type="text" name="encoding" size="25" value="utf-8" />
+      <em>(only used for non-XML and non-HTML content)</em>
     </td>
   </tr>
+  <tr>
+    <td align="left" valign="top"></td>
+    <td align="left" valign="top">
+      <div class="form-element">
+        <input class="form-element" type="submit" name="submit" 
+               value=" Add " /> 
+        <input class="form-element" type="submit" name="submit" 
+               value=" Add and Edit " />
+      </div>
+    </td>
+  </tr>
 </table>
 </form>
 

Modified: Zope/trunk/lib/python/Products/PageTemplates/www/ptEdit.zpt
===================================================================
--- Zope/trunk/lib/python/Products/PageTemplates/www/ptEdit.zpt	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/Products/PageTemplates/www/ptEdit.zpt	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,148 +1,138 @@
-<h1 tal:replace="structure here/manage_page_header">Header</h1>
+<h1 tal:replace="structure python:context.manage_page_header(management_page_charset='utf-8')">Header</h1>
 <h2 tal:define="manage_tabs_message options/manage_tabs_message | nothing"
-    tal:replace="structure here/manage_tabs">Tabs</h2>
+    tal:replace="structure context/manage_tabs">Tabs</h2>
 
 <tal:block define="global body request/other/text | request/form/text
-| here/read" /> 
+                                                  | context/read" /> 
 <form action="" method="post" tal:attributes="action request/URL1">
-<input type="hidden" name=":default_method" value="pt_changePrefs">
+<input type="hidden" name=":default_method" value="pt_changePrefs" />
+<input type="hidden" name="encoding" value="utf-8" />
 <table width="100%" cellspacing="0" cellpadding="2" border="0">
   <tr>
     <td align="left" valign="middle">
-    <div class="form-optional">
-    Title
-    </div>
+      <div class="form-optional">Title</div>
     </td>
     <td align="left" valign="middle">
-    <input type="text" name="title" size="40" 
-           tal:attributes="value request/title | here/title" />
+      <input type="text" name="title" size="40" 
+             tal:attributes="value request/title | context/title" />
     </td>
     <td align="left" valign="middle">
-    <div class="form-optional">
-    Content-Type
-    </div>
+      <div class="form-label">Content-Type</div>
     </td>
     <td align="left" valign="middle">
-    <input type="text" name="content_type" size="14" 
-           tal:attributes="value request/content_type | here/content_type" />
+      <input type="text" name="content_type" size="14" 
+             tal:attributes="value request/content_type | context/content_type" />
     </td>
   </tr>
   <tr>
     <td align="left" valign="middle">
-    <div class="form-label">
-    Last Modified
-    </div>
+      <div class="form-label">Last Modified</div>
     </td>
     <td align="left" valign="middle">
-    <div class="form-text" 
-     tal:content="python:here.bobobase_modification_time().strftime('%Y-%m-%d %I:%M %p')">1/1/2000
-    </div>
+      <div class="form-text" 
+       tal:content="python:context.bobobase_modification_time().strftime('%Y-%m-%d %I:%M %p')">1/1/2000
+      </div>
     </td>
-    <td align="left" valign="top" colspan=2>
-      <a href="source.html" tal:condition="here/html">Browse HTML source</a>
-      <a href="source.xml" tal:condition="not:here/html">Browse XML source</a>
-      <br>
-      <input type="hidden" name="expand:int:default" value="0">
+    <td align="left" valign="top" colspan="2">
+      <a href="source.html" tal:condition="context/html">Browse HTML source</a>
+      <a href="source.xml" tal:condition="not:context/html">Browse XML source</a>
+      <br />
+      <input type="hidden" name="expand:int:default" value="0" />
       <input type="checkbox" value="1" name="expand:int"
-       tal:attributes="checked request/expand | here/expand">
+             tal:attributes="checked request/expand | context/expand" />
       Expand macros when editing
     </td>
   </tr>
 
-  <tr tal:define="errors here/pt_errors" tal:condition="errors">
-    <tal:block define="global body python:here.document_src({'raw':1})"/>
+  <tr tal:define="errors context/pt_errors" tal:condition="errors">
+    <tal:block define="global body python:context.document_src({'raw':1})" />
     <td align="left" valign="middle" class="form-label">Errors</td>
     <td align="left" valign="middle" style="background-color: #FFDDDD"
-    colspan="3">
-<pre tal:content="python:modules['string'].join(errors, '\n')">errors</pre>
+        colspan="3">
+<pre tal:content="python:'\n'.join(errors)">errors</pre>
     </td>
   </tr>
 
-  <tr tal:define="warnings here/pt_warnings" tal:condition="warnings">
+  <tr tal:define="warnings context/pt_warnings" tal:condition="warnings">
     <td align="left" valign="middle" class="form-label">Warnings</td>
     <td align="left" valign="middle" style="background-color: #FFEEDD"
-     colspan="3">
-<pre tal:content="python:modules['string'].join(warnings, '\n')">errors</pre>
+        colspan="3">
+<pre tal:content="python:'\n'.join(warnings)">errors</pre>
     </td>
   </tr>
 
   <tr>
     <td align="left" valign="top" colspan="4"
-      tal:define="width request/dtpref_cols | string:100%;
-                  relative_width python:str(width).endswith('%')">
+        tal:define="width request/dtpref_cols | string:100%;
+                    relative_width python:str(width).endswith('%')">
       <textarea name="text:text" wrap="off" style="width: 100%;" rows="20"
-        tal:condition="relative_width"
-        tal:attributes="style string:width: $width;;;
-                        rows request/dtpref_rows | default"
-        tal:content="body">Template Body</textarea>
+                tal:condition="relative_width"
+                tal:attributes="style string:width: $width;;;
+                                rows request/dtpref_rows | default"
+                tal:content="body">Template Body</textarea>
       <textarea name="text:text" wrap="off" rows="20" cols="50"
-        tal:condition="not:relative_width"
-        tal:attributes="cols width; rows request/dtpref_rows | default"
-        tal:content="body">Template Body</textarea>
+                tal:condition="not:relative_width"
+                tal:attributes="cols width; rows request/dtpref_rows | default"
+                tal:content="body">Template Body</textarea>
     </td>
   </tr>
 
 <tr>
   <td align="left" valign="top" colspan="4">
   <div class="form-element">
-    <em tal:condition="here/wl_isLocked">Locked by WebDAV</em>
-    <input tal:condition="not:here/wl_isLocked"
-     class="form-element" type="submit" 
-     name="pt_editAction:method" value="Save Changes">
-  &nbsp;&nbsp;
-  <input class="form-element" type="submit" name="height" value="Taller">
-  <input class="form-element" type="submit" name="height" value="Shorter">
-  <input class="form-element" type="submit" name="width" value="Wider">
-  <input class="form-element" type="submit" name="width" value="Narrower">
+    <em tal:condition="context/wl_isLocked">Locked by WebDAV</em>
+    <input tal:condition="not:context/wl_isLocked"
+           class="form-element" type="submit" 
+           name="pt_editAction:method" value="Save Changes">
+    &nbsp;&nbsp;
+    <input class="form-element" type="submit" name="height" value="Taller" />
+    <input class="form-element" type="submit" name="height" value="Shorter" />
+    <input class="form-element" type="submit" name="width" value="Wider" />
+    <input class="form-element" type="submit" name="width" value="Narrower" />
   </div>
   </td>
 </tr>
 </table>
 </form>
 
-<p class="form-help">
-You can upload the text for <span tal:replace="here/title_and_id" />
-using the following form.
-Choose an existing HTML or XML file from your local computer by clicking
-<em>browse</em>.  You can also <a href="document_src">click here</a>
-to view or download the current text.
-</p>
+<p class="form-help">You can upload the text for
+<span tal:replace="context/title_and_id" /> using the following form.
+Choose an existing HTML or XML file from your local computer by
+clicking <em>browse</em>.  You can also <a href="document_src">click
+context</a> to view or download the current text.</p>
 
-<form action="pt_upload" method="post" 
- enctype="multipart/form-data">
+<form action="pt_upload" method="post" enctype="multipart/form-data">
 <table cellpadding="2" cellspacing="0" border="0">
 <tr>
   <td align="left" valign="top">
-  <div class="form-label">
-  File &nbsp;
-  </div>
+    <div class="form-label">File &nbsp;</div>
   </td>
   <td align="left" valign="top">
-  <input type="file" name="file" size="25" value="">
+    <input type="file" name="file" size="40" value="" />
   </td>
 </tr>
-<tr tal:condition="context/management_page_charset|nothing">
+<tr>
   <td align="left" valign="top">
-    <div class="form-label">
-      Encoding &nbsp;
-    </div>
+    <div class="form-label">Encoding &nbsp;</div>
   </td>
-  <td align="left" valign="top">
-    <input name="charset" value=""
-      tal:attributes="value here/management_page_charset|default" />
+  <td align="left" valign="top" colspan="2">
+    <input name="encoding" value="utf-8" />
   </td>
+  <td align="left" valign="top" colspan="1">
+    <em>(only used for non-XML and non-XHTML content)</em>
+  </td>
 </tr>
 <tr>
   <td></td>
   <td align="left" valign="top">
   <div class="form-element">
-    <em tal:condition="here/wl_isLocked">Locked by WebDAV</em>
-    <input tal:condition="not:here/wl_isLocked"
-    class="form-element" type="submit" value="Upload File">
+    <em tal:condition="context/wl_isLocked">Locked by WebDAV</em>
+    <input tal:condition="not:context/wl_isLocked"
+           class="form-element" type="submit" value="Upload File" />
   </div>
   </td>
 </tr>
 </table>
 </form>
 
-<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
+<h1 tal:replace="structure context/manage_page_footer">Footer</h1>

Modified: Zope/trunk/lib/python/TAL/DummyEngine.py
===================================================================
--- Zope/trunk/lib/python/TAL/DummyEngine.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/DummyEngine.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -13,239 +13,14 @@
 ##############################################################################
 """
 Dummy TALES engine so that I can test out the TAL implementation.
+
+BBB 2005/05/01 -- to be removed after 12 months
 """
+import zope.deprecation
+zope.deprecation.moved('zope.tal.dummyengine', '2.12')
 
-import re
-import sys
+from zope.tal.dummyengine import DummyTranslationDomain as DummyDomain
 
-from TALDefs import NAME_RE, TALESError, ErrorInfo
-from ITALES import ITALESCompiler, ITALESEngine
-from DocumentTemplate.DT_Util import ustr
-
-class _Default:
-    pass
-Default = _Default()
-
-name_match = re.compile(r"(?s)(%s):(.*)\Z" % NAME_RE).match
-
-class CompilerError(Exception):
-    pass
-
-class DummyEngine:
-
-    position = None
-    source_file = None
-
-    __implements__ = ITALESCompiler, ITALESEngine
-
-    def __init__(self, macros=None):
-        if macros is None:
-            macros = {}
-        self.macros = macros
-        dict = {'nothing': None, 'default': Default}
-        self.locals = self.globals = dict
-        self.stack = [dict]
-        self.translationService = DummyTranslationService()
-
-    def getCompilerError(self):
-        return CompilerError
-
-    def getCompiler(self):
-        return self
-
-    def setSourceFile(self, source_file):
-        self.source_file = source_file
-
-    def setPosition(self, position):
-        self.position = position
-
-    def compile(self, expr):
-        return "$%s$" % expr
-
-    def uncompile(self, expression):
-        assert (expression.startswith("$") and expression.endswith("$"),
-            expression)
-        return expression[1:-1]
-
-    def beginScope(self):
-        self.stack.append(self.locals)
-
-    def endScope(self):
-        assert len(self.stack) > 1, "more endScope() than beginScope() calls"
-        self.locals = self.stack.pop()
-
-    def setLocal(self, name, value):
-        if self.locals is self.stack[-1]:
-            # Unmerge this scope's locals from previous scope of first set
-            self.locals = self.locals.copy()
-        self.locals[name] = value
-
-    def setGlobal(self, name, value):
-        self.globals[name] = value
-
-    def evaluate(self, expression):
-        assert (expression.startswith("$") and expression.endswith("$"),
-            expression)
-        expression = expression[1:-1]
-        m = name_match(expression)
-        if m:
-            type, expr = m.group(1, 2)
-        else:
-            type = "path"
-            expr = expression
-        if type in ("string", "str"):
-            return expr
-        if type in ("path", "var", "global", "local"):
-            return self.evaluatePathOrVar(expr)
-        if type == "not":
-            return not self.evaluate(expr)
-        if type == "exists":
-            return self.locals.has_key(expr) or self.globals.has_key(expr)
-        if type == "python":
-            try:
-                return eval(expr, self.globals, self.locals)
-            except:
-                raise TALESError("evaluation error in %s" % `expr`)
-        if type == "position":
-            # Insert the current source file name, line number,
-            # and column offset.
-            if self.position:
-                lineno, offset = self.position
-            else:
-                lineno, offset = None, None
-            return '%s (%s,%s)' % (self.source_file, lineno, offset)
-        raise TALESError("unrecognized expression: " + `expression`)
-
-    def evaluatePathOrVar(self, expr):
-        expr = expr.strip()
-        if self.locals.has_key(expr):
-            return self.locals[expr]
-        elif self.globals.has_key(expr):
-            return self.globals[expr]
-        else:
-            raise TALESError("unknown variable: %s" % `expr`)
-
-    def evaluateValue(self, expr):
-        return self.evaluate(expr)
-
-    def evaluateBoolean(self, expr):
-        return self.evaluate(expr)
-
-    def evaluateText(self, expr):
-        text = self.evaluate(expr)
-        if text is not None and text is not Default:
-            text = ustr(text)
-        return text
-
-    def evaluateStructure(self, expr):
-        # XXX Should return None or a DOM tree
-        return self.evaluate(expr)
-
-    def evaluateSequence(self, expr):
-        # XXX Should return a sequence
-        return self.evaluate(expr)
-
-    def evaluateMacro(self, macroName):
-        assert (macroName.startswith("$") and macroName.endswith("$"),
-            macroName)
-        macroName = macroName[1:-1]
-        file, localName = self.findMacroFile(macroName)
-        if not file:
-            # Local macro
-            macro = self.macros[localName]
-        else:
-            # External macro
-            import driver
-            program, macros = driver.compilefile(file)
-            macro = macros.get(localName)
-            if not macro:
-                raise TALESError("macro %s not found in file %s" %
-                                 (localName, file))
-        return macro
-
-    def findMacroDocument(self, macroName):
-        file, localName = self.findMacroFile(macroName)
-        if not file:
-            return file, localName
-        import driver
-        doc = driver.parsefile(file)
-        return doc, localName
-
-    def findMacroFile(self, macroName):
-        if not macroName:
-            raise TALESError("empty macro name")
-        i = macroName.rfind('/')
-        if i < 0:
-            # No slash -- must be a locally defined macro
-            return None, macroName
-        else:
-            # Up to last slash is the filename
-            fileName = macroName[:i]
-            localName = macroName[i+1:]
-            return fileName, localName
-
-    def setRepeat(self, name, expr):
-        seq = self.evaluateSequence(expr)
-        return Iterator(name, seq, self)
-
-    def createErrorInfo(self, err, position):
-        return ErrorInfo(err, position)
-
-    def getDefault(self):
-        return Default
-
-    def translate(self, domain, msgid, mapping, default=None):
-        return self.translationService.translate(domain, msgid, mapping,
-                                                 default=default)
-
-
-class Iterator:
-
-    # This is not an implementation of a Python iterator.  The next()
-    # method returns true or false to indicate whether another item is
-    # available; if there is another item, the iterator instance calls
-    # setLocal() on the evaluation engine passed to the constructor.
-
-    def __init__(self, name, seq, engine):
-        self.name = name
-        self.seq = seq
-        self.engine = engine
-        self.nextIndex = 0
-
-    def next(self):
-        i = self.nextIndex
-        try:
-            item = self.seq[i]
-        except IndexError:
-            return 0
-        self.nextIndex = i+1
-        self.engine.setLocal(self.name, item)
-        return 1
-
-class DummyDomain:
-
-    def translate(self, msgid, mapping=None, context=None,
-                  target_language=None, default=None):
-        # This is a fake translation service which simply uppercases non
-        # ${name} placeholder text in the message id.
-        #
-        # First, transform a string with ${name} placeholders into a list of
-        # substrings.  Then upcase everything but the placeholders, then glue
-        # things back together.
-
-        # simulate an unknown msgid by returning None
-        text = msgid
-        if msgid == "don't translate me":
-            if default is not None:
-                text = default
-        else:
-            text = msgid.upper()
-
-        def repl(m, mapping=mapping):
-            return ustr(mapping[m.group(m.lastindex).lower()])
-        cre = re.compile(r'\$(?:(%s)|\{(%s)\})' % (NAME_RE, NAME_RE))
-        return cre.sub(repl, text)
-
 class DummyTranslationService:
 
     def translate(self, domain, msgid, mapping=None, context=None,

Modified: Zope/trunk/lib/python/TAL/HTMLTALParser.py
===================================================================
--- Zope/trunk/lib/python/TAL/HTMLTALParser.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/HTMLTALParser.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -13,303 +13,8 @@
 ##############################################################################
 """
 Parse HTML and compile to TALInterpreter intermediate code.
-"""
 
-import sys
-
-from TALGenerator import TALGenerator
-from HTMLParser import HTMLParser, HTMLParseError
-from TALDefs import \
-     ZOPE_METAL_NS, ZOPE_TAL_NS, ZOPE_I18N_NS, METALError, TALError, I18NError
-
-BOOLEAN_HTML_ATTRS = [
-    # List of Boolean attributes in HTML that may be given in
-    # minimized form (e.g. <img ismap> rather than <img ismap="">)
-    # From http://www.w3.org/TR/xhtml1/#guidelines (C.10)
-    "compact", "nowrap", "ismap", "declare", "noshade", "checked",
-    "disabled", "readonly", "multiple", "selected", "noresize",
-    "defer"
-    ]
-
-EMPTY_HTML_TAGS = [
-    # List of HTML tags with an empty content model; these are
-    # rendered in minimized form, e.g. <img />.
-    # From http://www.w3.org/TR/xhtml1/#dtds
-    "base", "meta", "link", "hr", "br", "param", "img", "area",
-    "input", "col", "basefont", "isindex", "frame",
-    ]
-
-PARA_LEVEL_HTML_TAGS = [
-    # List of HTML elements that close open paragraph-level elements
-    # and are themselves paragraph-level.
-    "h1", "h2", "h3", "h4", "h5", "h6", "p",
-    ]
-
-BLOCK_CLOSING_TAG_MAP = {
-    "tr": ("tr", "td", "th"),
-    "td": ("td", "th"),
-    "th": ("td", "th"),
-    "li": ("li",),
-    "dd": ("dd", "dt"),
-    "dt": ("dd", "dt"),
-    }
-
-BLOCK_LEVEL_HTML_TAGS = [
-    # List of HTML tags that denote larger sections than paragraphs.
-    "blockquote", "table", "tr", "th", "td", "thead", "tfoot", "tbody",
-    "noframe", "ul", "ol", "li", "dl", "dt", "dd", "div",
-    ]
-
-TIGHTEN_IMPLICIT_CLOSE_TAGS = (PARA_LEVEL_HTML_TAGS
-                               + BLOCK_CLOSING_TAG_MAP.keys())
-
-
-class NestingError(HTMLParseError):
-    """Exception raised when elements aren't properly nested."""
-
-    def __init__(self, tagstack, endtag, position=(None, None)):
-        self.endtag = endtag
-        if tagstack:
-            if len(tagstack) == 1:
-                msg = ('Open tag <%s> does not match close tag </%s>'
-                       % (tagstack[0], endtag))
-            else:
-                msg = ('Open tags <%s> do not match close tag </%s>'
-                       % ('>, <'.join(tagstack), endtag))
-        else:
-            msg = 'No tags are open to match </%s>' % endtag
-        HTMLParseError.__init__(self, msg, position)
-
-class EmptyTagError(NestingError):
-    """Exception raised when empty elements have an end tag."""
-
-    def __init__(self, tag, position=(None, None)):
-        self.tag = tag
-        msg = 'Close tag </%s> should be removed' % tag
-        HTMLParseError.__init__(self, msg, position)
-
-class OpenTagError(NestingError):
-    """Exception raised when a tag is not allowed in another tag."""
-
-    def __init__(self, tagstack, tag, position=(None, None)):
-        self.tag = tag
-        msg = 'Tag <%s> is not allowed in <%s>' % (tag, tagstack[-1])
-        HTMLParseError.__init__(self, msg, position)
-
-class HTMLTALParser(HTMLParser):
-
-    # External API
-
-    def __init__(self, gen=None):
-        HTMLParser.__init__(self)
-        if gen is None:
-            gen = TALGenerator(xml=0)
-        self.gen = gen
-        self.tagstack = []
-        self.nsstack = []
-        self.nsdict = {'tal': ZOPE_TAL_NS,
-                       'metal': ZOPE_METAL_NS,
-                       'i18n': ZOPE_I18N_NS,
-                       }
-
-    def parseFile(self, file):
-        f = open(file)
-        data = f.read()
-        f.close()
-        try:
-            self.parseString(data)
-        except TALError, e:
-            e.setFile(file)
-            raise
-
-    def parseString(self, data):
-        self.feed(data)
-        self.close()
-        while self.tagstack:
-            self.implied_endtag(self.tagstack[-1], 2)
-        assert self.nsstack == [], self.nsstack
-
-    def getCode(self):
-        return self.gen.getCode()
-
-    def getWarnings(self):
-        return ()
-
-    # Overriding HTMLParser methods
-
-    def handle_starttag(self, tag, attrs):
-        self.close_para_tags(tag)
-        self.scan_xmlns(attrs)
-        tag, attrlist, taldict, metaldict, i18ndict \
-             = self.process_ns(tag, attrs)
-        if tag in EMPTY_HTML_TAGS and taldict.get("content"):
-            raise TALError(
-                "empty HTML tags cannot use tal:content: %s" % `tag`,
-                self.getpos())
-        self.tagstack.append(tag)
-        self.gen.emitStartElement(tag, attrlist, taldict, metaldict, i18ndict,
-                                  self.getpos())
-        if tag in EMPTY_HTML_TAGS:
-            self.implied_endtag(tag, -1)
-
-    def handle_startendtag(self, tag, attrs):
-        self.close_para_tags(tag)
-        self.scan_xmlns(attrs)
-        tag, attrlist, taldict, metaldict, i18ndict \
-             = self.process_ns(tag, attrs)
-        if taldict.get("content"):
-            if tag in EMPTY_HTML_TAGS:
-                raise TALError(
-                    "empty HTML tags cannot use tal:content: %s" % `tag`,
-                    self.getpos())
-            self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
-                                      i18ndict, self.getpos())
-            self.gen.emitEndElement(tag, implied=-1)
-        else:
-            self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
-                                      i18ndict, self.getpos(), isend=1)
-        self.pop_xmlns()
-
-    def handle_endtag(self, tag):
-        if tag in EMPTY_HTML_TAGS:
-            # </img> etc. in the source is an error
-            raise EmptyTagError(tag, self.getpos())
-        self.close_enclosed_tags(tag)
-        self.gen.emitEndElement(tag)
-        self.pop_xmlns()
-        self.tagstack.pop()
-
-    def close_para_tags(self, tag):
-        if tag in EMPTY_HTML_TAGS:
-            return
-        close_to = -1
-        if BLOCK_CLOSING_TAG_MAP.has_key(tag):
-            blocks_to_close = BLOCK_CLOSING_TAG_MAP[tag]
-            for i in range(len(self.tagstack)):
-                t = self.tagstack[i]
-                if t in blocks_to_close:
-                    if close_to == -1:
-                        close_to = i
-                elif t in BLOCK_LEVEL_HTML_TAGS:
-                    close_to = -1
-        elif tag in PARA_LEVEL_HTML_TAGS + BLOCK_LEVEL_HTML_TAGS:
-            i = len(self.tagstack) - 1
-            while i >= 0:
-                closetag = self.tagstack[i]
-                if closetag in BLOCK_LEVEL_HTML_TAGS:
-                    break
-                if closetag in PARA_LEVEL_HTML_TAGS:
-                    if closetag != "p":
-                        raise OpenTagError(self.tagstack, tag, self.getpos())
-                    close_to = i
-                i = i - 1
-        if close_to >= 0:
-            while len(self.tagstack) > close_to:
-                self.implied_endtag(self.tagstack[-1], 1)
-
-    def close_enclosed_tags(self, tag):
-        if tag not in self.tagstack:
-            raise NestingError(self.tagstack, tag, self.getpos())
-        while tag != self.tagstack[-1]:
-            self.implied_endtag(self.tagstack[-1], 1)
-        assert self.tagstack[-1] == tag
-
-    def implied_endtag(self, tag, implied):
-        assert tag == self.tagstack[-1]
-        assert implied in (-1, 1, 2)
-        isend = (implied < 0)
-        if tag in TIGHTEN_IMPLICIT_CLOSE_TAGS:
-            # Pick out trailing whitespace from the program, and
-            # insert the close tag before the whitespace.
-            white = self.gen.unEmitWhitespace()
-        else:
-            white = None
-        self.gen.emitEndElement(tag, isend=isend, implied=implied)
-        if white:
-            self.gen.emitRawText(white)
-        self.tagstack.pop()
-        self.pop_xmlns()
-
-    def handle_charref(self, name):
-        self.gen.emitRawText("&#%s;" % name)
-
-    def handle_entityref(self, name):
-        self.gen.emitRawText("&%s;" % name)
-
-    def handle_data(self, data):
-        self.gen.emitRawText(data)
-
-    def handle_comment(self, data):
-        self.gen.emitRawText("<!--%s-->" % data)
-
-    def handle_decl(self, data):
-        self.gen.emitRawText("<!%s>" % data)
-
-    def handle_pi(self, data):
-        self.gen.emitRawText("<?%s>" % data)
-
-    # Internal thingies
-
-    def scan_xmlns(self, attrs):
-        nsnew = {}
-        for key, value in attrs:
-            if key.startswith("xmlns:"):
-                nsnew[key[6:]] = value
-        if nsnew:
-            self.nsstack.append(self.nsdict)
-            self.nsdict = self.nsdict.copy()
-            self.nsdict.update(nsnew)
-        else:
-            self.nsstack.append(self.nsdict)
-
-    def pop_xmlns(self):
-        self.nsdict = self.nsstack.pop()
-
-    def fixname(self, name):
-        if ':' in name:
-            prefix, suffix = name.split(':', 1)
-            if prefix == 'xmlns':
-                nsuri = self.nsdict.get(suffix)
-                if nsuri in (ZOPE_TAL_NS, ZOPE_METAL_NS, ZOPE_I18N_NS):
-                    return name, name, prefix
-            else:
-                nsuri = self.nsdict.get(prefix)
-                if nsuri == ZOPE_TAL_NS:
-                    return name, suffix, 'tal'
-                elif nsuri == ZOPE_METAL_NS:
-                    return name, suffix,  'metal'
-                elif nsuri == ZOPE_I18N_NS:
-                    return name, suffix, 'i18n'
-        return name, name, 0
-
-    def process_ns(self, name, attrs):
-        attrlist = []
-        taldict = {}
-        metaldict = {}
-        i18ndict = {}
-        name, namebase, namens = self.fixname(name)
-        for item in attrs:
-            key, value = item
-            key, keybase, keyns = self.fixname(key)
-            ns = keyns or namens # default to tag namespace
-            if ns and ns != 'unknown':
-                item = (key, value, ns)
-            if ns == 'tal':
-                if taldict.has_key(keybase):
-                    raise TALError("duplicate TAL attribute " +
-                                   `keybase`, self.getpos())
-                taldict[keybase] = value
-            elif ns == 'metal':
-                if metaldict.has_key(keybase):
-                    raise METALError("duplicate METAL attribute " +
-                                     `keybase`, self.getpos())
-                metaldict[keybase] = value
-            elif ns == 'i18n':
-                if i18ndict.has_key(keybase):
-                    raise I18NError("duplicate i18n attribute " +
-                                    `keybase`, self.getpos())
-                i18ndict[keybase] = value
-            attrlist.append(item)
-        if namens in ('metal', 'tal'):
-            taldict['tal tag'] = namens
-        return name, attrlist, taldict, metaldict, i18ndict
+BBB 2005/05/01 -- to be removed after 12 months
+"""
+import zope.deprecation
+zope.deprecation.moved('zope.tal.htmltalparser', '2.12')

Modified: Zope/trunk/lib/python/TAL/ITALES.py
===================================================================
--- Zope/trunk/lib/python/TAL/ITALES.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/ITALES.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,156 +1,11 @@
 """Interface that a TALES engine provides to the METAL/TAL implementation."""
 
-try:
-    from Interface import Interface
-    from Interface.Attribute import Attribute
-except:
-    # Before 2.7
-    class Interface: pass
-    def Attribute(*args): pass
+import zope.deferredimport
+zope.deferredimport.deprecatedFrom(
+    "The TAL implementation has moved to zope.tal.  Import expression "
+    "interfaces from zope.tal.interfaces.  The old references will be "
+    "gone in Zope 2.12.",
+    'zope.tal.interfaces'
+    'ITALExpressionCompiler', 'ITALExpressionEngine', 'ITALExpressionErrorInfo'
+    )
 
-
-class ITALESCompiler(Interface):
-    """Compile-time interface provided by a TALES implementation.
-
-    The TAL compiler needs an instance of this interface to support
-    compilation of TALES expressions embedded in documents containing
-    TAL and METAL constructs.
-    """
-
-    def getCompilerError():
-        """Return the exception class raised for compilation errors.
-        """
-
-    def compile(expression):
-        """Return a compiled form of 'expression' for later evaluation.
-
-        'expression' is the source text of the expression.
-
-        The return value may be passed to the various evaluate*()
-        methods of the ITALESEngine interface.  No compatibility is
-        required for the values of the compiled expression between
-        different ITALESEngine implementations.
-        """
-
-
-class ITALESEngine(Interface):
-    """Render-time interface provided by a TALES implementation.
-
-    The TAL interpreter uses this interface to TALES to support
-    evaluation of the compiled expressions returned by
-    ITALESCompiler.compile().
-    """
-
-    def getCompiler():
-        """Return an object that supports ITALESCompiler."""
-
-    def getDefault():
-        """Return the value of the 'default' TALES expression.
-
-        Checking a value for a match with 'default' should be done
-        using the 'is' operator in Python.
-        """
-
-    def setPosition((lineno, offset)):
-        """Inform the engine of the current position in the source file.
-
-        This is used to allow the evaluation engine to report
-        execution errors so that site developers can more easily
-        locate the offending expression.
-        """
-
-    def setSourceFile(filename):
-        """Inform the engine of the name of the current source file.
-
-        This is used to allow the evaluation engine to report
-        execution errors so that site developers can more easily
-        locate the offending expression.
-        """
-
-    def beginScope():
-        """Push a new scope onto the stack of open scopes.
-        """
-
-    def endScope():
-        """Pop one scope from the stack of open scopes.
-        """
-
-    def evaluate(compiled_expression):
-        """Evaluate an arbitrary expression.
-
-        No constraints are imposed on the return value.
-        """
-
-    def evaluateBoolean(compiled_expression):
-        """Evaluate an expression that must return a Boolean value.
-        """
-
-    def evaluateMacro(compiled_expression):
-        """Evaluate an expression that must return a macro program.
-        """
-
-    def evaluateStructure(compiled_expression):
-        """Evaluate an expression that must return a structured
-        document fragment.
-
-        The result of evaluating 'compiled_expression' must be a
-        string containing a parsable HTML or XML fragment.  Any TAL
-        markup cnotained in the result string will be interpreted.
-        """
-
-    def evaluateText(compiled_expression):
-        """Evaluate an expression that must return text.
-
-        The returned text should be suitable for direct inclusion in
-        the output: any HTML or XML escaping or quoting is the
-        responsibility of the expression itself.
-        """
-
-    def evaluateValue(compiled_expression):
-        """Evaluate an arbitrary expression.
-
-        No constraints are imposed on the return value.
-        """
-
-    def createErrorInfo(exception, (lineno, offset)):
-        """Returns an ITALESErrorInfo object.
-
-        The returned object is used to provide information about the
-        error condition for the on-error handler.
-        """
-
-    def setGlobal(name, value):
-        """Set a global variable.
-
-        The variable will be named 'name' and have the value 'value'.
-        """
-
-    def setLocal(name, value):
-        """Set a local variable in the current scope.
-
-        The variable will be named 'name' and have the value 'value'.
-        """
-
-    def setRepeat(name, compiled_expression):
-        """
-        """
-
-    def translate(domain, msgid, mapping, default=None):
-        """
-        See ITranslationService.translate()
-        """
-
-
-class ITALESErrorInfo(Interface):
-
-    type = Attribute("type",
-                     "The exception class.")
-
-    value = Attribute("value",
-                      "The exception instance.")
-
-    lineno = Attribute("lineno",
-                       "The line number the error occurred on in the source.")
-
-    offset = Attribute("offset",
-                       "The character offset at which the error occurred.")

Modified: Zope/trunk/lib/python/TAL/TALDefs.py
===================================================================
--- Zope/trunk/lib/python/TAL/TALDefs.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/TALDefs.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -13,179 +13,16 @@
 ##############################################################################
 """
 Common definitions used by TAL and METAL compilation an transformation.
+
+BBB 2005/05/01 -- to be removed after 12 months
 """
+import zope.deprecation
+zope.deprecation.moved('zope.tal.taldefs', '2.12')
 
-from types import ListType, TupleType
-
-from ITALES import ITALESErrorInfo
-
-TAL_VERSION = "1.5"
-
-XML_NS = "http://www.w3.org/XML/1998/namespace" # URI for XML namespace
-XMLNS_NS = "http://www.w3.org/2000/xmlns/" # URI for XML NS declarations
-
-ZOPE_TAL_NS = "http://xml.zope.org/namespaces/tal"
-ZOPE_METAL_NS = "http://xml.zope.org/namespaces/metal"
-ZOPE_I18N_NS = "http://xml.zope.org/namespaces/i18n"
-
-# This RE must exactly match the expression of the same name in the
-# zope.i18n.simpletranslationservice module:
-NAME_RE = "[a-zA-Z_][-a-zA-Z0-9_]*"
-
-KNOWN_METAL_ATTRIBUTES = [
-    "define-macro",
-    "use-macro",
-    "define-slot",
-    "fill-slot",
-    "slot",
-    ]
-
-KNOWN_TAL_ATTRIBUTES = [
-    "define",
-    "condition",
-    "content",
-    "replace",
-    "repeat",
-    "attributes",
-    "on-error",
-    "omit-tag",
-    "tal tag",
-    ]
-
-KNOWN_I18N_ATTRIBUTES = [
-    "translate",
-    "domain",
-    "target",
-    "source",
-    "attributes",
-    "data",
-    "name",
-    ]
-
-class TALError(Exception):
-
-    def __init__(self, msg, position=(None, None)):
-        assert msg != ""
-        self.msg = msg
-        self.lineno = position[0]
-        self.offset = position[1]
-        self.filename = None
-
-    def setFile(self, filename):
-        self.filename = filename
-
-    def __str__(self):
-        result = self.msg
-        if self.lineno is not None:
-            result = result + ", at line %d" % self.lineno
-        if self.offset is not None:
-            result = result + ", column %d" % (self.offset + 1)
-        if self.filename is not None:
-            result = result + ', in file %s' % self.filename
-        return result
-
-class METALError(TALError):
-    pass
-
-class TALESError(TALError):
-    pass
-
-class I18NError(TALError):
-    pass
-
-
-class ErrorInfo:
-
-    __implements__ = ITALESErrorInfo
-
-    def __init__(self, err, position=(None, None)):
-        if isinstance(err, Exception):
-            self.type = err.__class__
-            self.value = err
-        else:
-            self.type = err
-            self.value = None
-        self.lineno = position[0]
-        self.offset = position[1]
-
-
-
-import re
-_attr_re = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S)
-_subst_re = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S)
-del re
-
-def parseAttributeReplacements(arg, xml):
-    dict = {}
-    for part in splitParts(arg):
-        m = _attr_re.match(part)
-        if not m:
-            raise TALError("Bad syntax in attributes: " + `part`)
-        name, expr = m.group(1, 2)
-        if not xml:
-            name = name.lower()
-        if dict.has_key(name):
-            raise TALError("Duplicate attribute name in attributes: " + `part`)
-        dict[name] = expr
-    return dict
-
-def parseSubstitution(arg, position=(None, None)):
-    m = _subst_re.match(arg)
-    if not m:
-        raise TALError("Bad syntax in substitution text: " + `arg`, position)
-    key, expr = m.group(1, 2)
-    if not key:
-        key = "text"
-    return key, expr
-
-def splitParts(arg):
-    # Break in pieces at undoubled semicolons and
-    # change double semicolons to singles:
-    arg = arg.replace(";;", "\0")
-    parts = arg.split(';')
-    parts = [p.replace("\0", ";") for p in parts]
-    if len(parts) > 1 and not parts[-1].strip():
-        del parts[-1] # It ended in a semicolon
-    return parts
-
-def isCurrentVersion(program):
-    version = getProgramVersion(program)
-    return version == TAL_VERSION
-
-def getProgramMode(program):
-    version = getProgramVersion(program)
-    if (version == TAL_VERSION and isinstance(program[1], TupleType) and
-        len(program[1]) == 2):
-        opcode, mode = program[1]
-        if opcode == "mode":
-            return mode
-    return None
-
-def getProgramVersion(program):
-    if (len(program) >= 2 and
-        isinstance(program[0], TupleType) and len(program[0]) == 2):
-        opcode, version = program[0]
-        if opcode == "version":
-            return version
-    return None
-
-import re
-_ent1_re = re.compile('&(?![A-Z#])', re.I)
-_entch_re = re.compile('&([A-Z][A-Z0-9]*)(?![A-Z0-9;])', re.I)
-_entn1_re = re.compile('&#(?![0-9X])', re.I)
-_entnx_re = re.compile('&(#X[A-F0-9]*)(?![A-F0-9;])', re.I)
-_entnd_re = re.compile('&(#[0-9][0-9]*)(?![0-9;])')
-del re
-
-def attrEscape(s):
-    """Replace special characters '&<>' by character entities,
-    except when '&' already begins a syntactically valid entity."""
-    s = _ent1_re.sub('&amp;', s)
-    s = _entch_re.sub(r'&amp;\1', s)
-    s = _entn1_re.sub('&amp;#', s)
-    s = _entnx_re.sub(r'&amp;\1', s)
-    s = _entnd_re.sub(r'&amp;\1', s)
-    s = s.replace('<', '&lt;')
-    s = s.replace('>', '&gt;')
-    s = s.replace('"', '&quot;')
-    return s
+import zope.deferredimport
+zope.deferredimport.deprecated(
+    "TALESError has been renamed TALExpressionError and should be "
+    "imported from zope.tal.taldefs.  This reference will be gone in "
+    "Zope 2.12.",
+    TALESError = 'zope.tal.taldefs.TALExpressionError'
+    )

Modified: Zope/trunk/lib/python/TAL/TALGenerator.py
===================================================================
--- Zope/trunk/lib/python/TAL/TALGenerator.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/TALGenerator.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -13,880 +13,8 @@
 ##############################################################################
 """
 Code generator for TALInterpreter intermediate code.
-"""
 
-import re
-import cgi
-
-import TALDefs
-
-from TALDefs import NAME_RE, TAL_VERSION
-from TALDefs import I18NError, METALError, TALError
-from TALDefs import parseSubstitution
-from TranslationContext import TranslationContext, DEFAULT_DOMAIN
-
-I18N_REPLACE = 1
-I18N_CONTENT = 2
-I18N_EXPRESSION = 3
-
-_name_rx = re.compile(NAME_RE)
-
-
-class TALGenerator:
-
-    inMacroUse = 0
-    inMacroDef = 0
-    source_file = None
-
-    def __init__(self, expressionCompiler=None, xml=1, source_file=None):
-        if not expressionCompiler:
-            from DummyEngine import DummyEngine
-            expressionCompiler = DummyEngine()
-        self.expressionCompiler = expressionCompiler
-        self.CompilerError = expressionCompiler.getCompilerError()
-        # This holds the emitted opcodes representing the input
-        self.program = []
-        # The program stack for when we need to do some sub-evaluation for an
-        # intermediate result.  E.g. in an i18n:name tag for which the
-        # contents describe the ${name} value.
-        self.stack = []
-        # Another stack of postponed actions.  Elements on this stack are a
-        # dictionary; key/values contain useful information that
-        # emitEndElement needs to finish its calculations
-        self.todoStack = []
-        self.macros = {}
-        self.slots = {}
-        self.slotStack = []
-        self.xml = xml
-        self.emit("version", TAL_VERSION)
-        self.emit("mode", xml and "xml" or "html")
-        if source_file is not None:
-            self.source_file = source_file
-            self.emit("setSourceFile", source_file)
-        self.i18nContext = TranslationContext()
-        self.i18nLevel = 0
-
-    def getCode(self):
-        assert not self.stack
-        assert not self.todoStack
-        return self.optimize(self.program), self.macros
-
-    def optimize(self, program):
-        output = []
-        collect = []
-        cursor = 0
-        if self.xml:
-            endsep = "/>"
-        else:
-            endsep = " />"
-        for cursor in xrange(len(program)+1):
-            try:
-                item = program[cursor]
-            except IndexError:
-                item = (None, None)
-            opcode = item[0]
-            if opcode == "rawtext":
-                collect.append(item[1])
-                continue
-            if opcode == "endTag":
-                collect.append("</%s>" % item[1])
-                continue
-            if opcode == "startTag":
-                if self.optimizeStartTag(collect, item[1], item[2], ">"):
-                    continue
-            if opcode == "startEndTag":
-                if self.optimizeStartTag(collect, item[1], item[2], endsep):
-                    continue
-            if opcode in ("beginScope", "endScope"):
-                # Push *Scope instructions in front of any text instructions;
-                # this allows text instructions separated only by *Scope
-                # instructions to be joined together.
-                output.append(self.optimizeArgsList(item))
-                continue
-            if opcode == 'noop':
-                # This is a spacer for end tags in the face of i18n:name
-                # attributes.  We can't let the optimizer collect immediately
-                # following end tags into the same rawtextOffset.
-                opcode = None
-                pass
-            text = "".join(collect)
-            if text:
-                i = text.rfind("\n")
-                if i >= 0:
-                    i = len(text) - (i + 1)
-                    output.append(("rawtextColumn", (text, i)))
-                else:
-                    output.append(("rawtextOffset", (text, len(text))))
-            if opcode != None:
-                output.append(self.optimizeArgsList(item))
-            collect = []
-        return self.optimizeCommonTriple(output)
-
-    def optimizeArgsList(self, item):
-        if len(item) == 2:
-            return item
-        else:
-            return item[0], tuple(item[1:])
-
-    # These codes are used to indicate what sort of special actions
-    # are needed for each special attribute.  (Simple attributes don't
-    # get action codes.)
-    #
-    # The special actions (which are modal) are handled by
-    # TALInterpreter.attrAction() and .attrAction_tal().
-    #
-    # Each attribute is represented by a tuple:
-    #
-    # (name, value)                 -- a simple name/value pair, with
-    #                                  no special processing
-    #
-    # (name, value, action, *extra) -- attribute with special
-    #                                  processing needs, action is a
-    #                                  code that indicates which
-    #                                  branch to take, and *extra
-    #                                  contains additional,
-    #                                  action-specific information
-    #                                  needed by the processing
-    #
-    def optimizeStartTag(self, collect, name, attrlist, end):
-        # return true if the tag can be converted to plain text
-        if not attrlist:
-            collect.append("<%s%s" % (name, end))
-            return 1
-        opt = 1
-        new = ["<" + name]
-        for i in range(len(attrlist)):
-            item = attrlist[i]
-            if len(item) > 2:
-                opt = 0
-                name, value, action = item[:3]
-                attrlist[i] = (name, value, action) + item[3:]
-            else:
-                if item[1] is None:
-                    s = item[0]
-                else:
-                    s = '%s="%s"' % (item[0], TALDefs.attrEscape(item[1]))
-                attrlist[i] = item[0], s
-                new.append(" " + s)
-        # if no non-optimizable attributes were found, convert to plain text
-        if opt:
-            new.append(end)
-            collect.extend(new)
-        return opt
-
-    def optimizeCommonTriple(self, program):
-        if len(program) < 3:
-            return program
-        output = program[:2]
-        prev2, prev1 = output
-        for item in program[2:]:
-            if ( item[0] == "beginScope"
-                 and prev1[0] == "setPosition"
-                 and prev2[0] == "rawtextColumn"):
-                position = output.pop()[1]
-                text, column = output.pop()[1]
-                prev1 = None, None
-                closeprev = 0
-                if output and output[-1][0] == "endScope":
-                    closeprev = 1
-                    output.pop()
-                item = ("rawtextBeginScope",
-                        (text, column, position, closeprev, item[1]))
-            output.append(item)
-            prev2 = prev1
-            prev1 = item
-        return output
-
-    def todoPush(self, todo):
-        self.todoStack.append(todo)
-
-    def todoPop(self):
-        return self.todoStack.pop()
-
-    def compileExpression(self, expr):
-        try:
-            return self.expressionCompiler.compile(expr)
-        except self.CompilerError, err:
-            raise TALError('%s in expression %s' % (err.args[0], `expr`),
-                           self.position)
-
-    def pushProgram(self):
-        self.stack.append(self.program)
-        self.program = []
-
-    def popProgram(self):
-        program = self.program
-        self.program = self.stack.pop()
-        return self.optimize(program)
-
-    def pushSlots(self):
-        self.slotStack.append(self.slots)
-        self.slots = {}
-
-    def popSlots(self):
-        slots = self.slots
-        self.slots = self.slotStack.pop()
-        return slots
-
-    def emit(self, *instruction):
-        self.program.append(instruction)
-
-    def emitStartTag(self, name, attrlist, isend=0):
-        if isend:
-            opcode = "startEndTag"
-        else:
-            opcode = "startTag"
-        self.emit(opcode, name, attrlist)
-
-    def emitEndTag(self, name):
-        if self.xml and self.program and self.program[-1][0] == "startTag":
-            # Minimize empty element
-            self.program[-1] = ("startEndTag",) + self.program[-1][1:]
-        else:
-            self.emit("endTag", name)
-
-    def emitOptTag(self, name, optTag, isend):
-        program = self.popProgram() #block
-        start = self.popProgram() #start tag
-        if (isend or not program) and self.xml:
-            # Minimize empty element
-            start[-1] = ("startEndTag",) + start[-1][1:]
-            isend = 1
-        cexpr = optTag[0]
-        if cexpr:
-            cexpr = self.compileExpression(optTag[0])
-        self.emit("optTag", name, cexpr, optTag[1], isend, start, program)
-
-    def emitRawText(self, text):
-        self.emit("rawtext", text)
-
-    def emitText(self, text):
-        self.emitRawText(cgi.escape(text))
-
-    def emitDefines(self, defines):
-        for part in TALDefs.splitParts(defines):
-            m = re.match(
-                r"(?s)\s*(?:(global|local)\s+)?(%s)\s+(.*)\Z" % NAME_RE, part)
-            if not m:
-                raise TALError("invalid define syntax: " + `part`,
-                               self.position)
-            scope, name, expr = m.group(1, 2, 3)
-            scope = scope or "local"
-            cexpr = self.compileExpression(expr)
-            if scope == "local":
-                self.emit("setLocal", name, cexpr)
-            else:
-                self.emit("setGlobal", name, cexpr)
-
-    def emitOnError(self, name, onError, TALtag, isend):
-        block = self.popProgram()
-        key, expr = parseSubstitution(onError)
-        cexpr = self.compileExpression(expr)
-        if key == "text":
-            self.emit("insertText", cexpr, [])
-        else:
-            assert key == "structure"
-            self.emit("insertStructure", cexpr, {}, [])
-        if TALtag:
-            self.emitOptTag(name, (None, 1), isend)
-        else:
-            self.emitEndTag(name)
-        handler = self.popProgram()
-        self.emit("onError", block, handler)
-
-    def emitCondition(self, expr):
-        cexpr = self.compileExpression(expr)
-        program = self.popProgram()
-        self.emit("condition", cexpr, program)
-
-    def emitRepeat(self, arg):
-        m = re.match("(?s)\s*(%s)\s+(.*)\Z" % NAME_RE, arg)
-        if not m:
-            raise TALError("invalid repeat syntax: " + `arg`,
-                           self.position)
-        name, expr = m.group(1, 2)
-        cexpr = self.compileExpression(expr)
-        program = self.popProgram()
-        self.emit("loop", name, cexpr, program)
-
-    def emitSubstitution(self, arg, attrDict={}):
-        key, expr = parseSubstitution(arg)
-        cexpr = self.compileExpression(expr)
-        program = self.popProgram()
-        if key == "text":
-            self.emit("insertText", cexpr, program)
-        else:
-            assert key == "structure"
-            self.emit("insertStructure", cexpr, attrDict, program)
-
-    def emitI18nVariable(self, stuff):
-        # Used for i18n:name attributes.  arg is extra information describing
-        # how the contents of the variable should get filled in, and it will
-        # either be a 1-tuple or a 2-tuple.  If arg[0] is None, then the
-        # i18n:name value is taken implicitly from the contents of the tag,
-        # e.g. "I live in <span i18n:name="country">the USA</span>".  In this
-        # case, arg[1] is the opcode sub-program describing the contents of
-        # the tag.
-        #
-        # When arg[0] is not None, it contains the tal expression used to
-        # calculate the contents of the variable, e.g.
-        # "I live in <span i18n:name="country"
-        #                  tal:replace="here/countryOfOrigin" />"
-        varname, action, expression = stuff
-        m = _name_rx.match(varname)
-        if m is None or m.group() != varname:
-            raise TALError("illegal i18n:name: %r" % varname, self.position)
-        key = cexpr = None
-        program = self.popProgram()
-        if action == I18N_REPLACE:
-            # This is a tag with an i18n:name and a tal:replace (implicit or
-            # explicit).  Get rid of the first and last elements of the
-            # program, which are the start and end tag opcodes of the tag.
-            program = program[1:-1]
-        elif action == I18N_CONTENT:
-            # This is a tag with an i18n:name and a tal:content
-            # (explicit-only).  Keep the first and last elements of the
-            # program, so we keep the start and end tag output.
-            pass
-        else:
-            assert action == I18N_EXPRESSION
-            key, expr = parseSubstitution(expression)
-            cexpr = self.compileExpression(expr)
-        self.emit('i18nVariable',
-                  varname, program, cexpr, int(key == "structure"))
-
-    def emitTranslation(self, msgid, i18ndata):
-        program = self.popProgram()
-        if i18ndata is None:
-            self.emit('insertTranslation', msgid, program)
-        else:
-            key, expr = parseSubstitution(i18ndata)
-            cexpr = self.compileExpression(expr)
-            assert key == 'text'
-            self.emit('insertTranslation', msgid, program, cexpr)
-
-    def emitDefineMacro(self, macroName):
-        program = self.popProgram()
-        macroName = macroName.strip()
-        if self.macros.has_key(macroName):
-            raise METALError("duplicate macro definition: %s" % `macroName`,
-                             self.position)
-        if not re.match('%s$' % NAME_RE, macroName):
-            raise METALError("invalid macro name: %s" % `macroName`,
-                             self.position)
-        self.macros[macroName] = program
-        self.inMacroDef = self.inMacroDef - 1
-        self.emit("defineMacro", macroName, program)
-
-    def emitUseMacro(self, expr):
-        cexpr = self.compileExpression(expr)
-        program = self.popProgram()
-        self.inMacroUse = 0
-        self.emit("useMacro", expr, cexpr, self.popSlots(), program)
-
-    def emitDefineSlot(self, slotName):
-        program = self.popProgram()
-        slotName = slotName.strip()
-        if not re.match('%s$' % NAME_RE, slotName):
-            raise METALError("invalid slot name: %s" % `slotName`,
-                             self.position)
-        self.emit("defineSlot", slotName, program)
-
-    def emitFillSlot(self, slotName):
-        program = self.popProgram()
-        slotName = slotName.strip()
-        if self.slots.has_key(slotName):
-            raise METALError("duplicate fill-slot name: %s" % `slotName`,
-                             self.position)
-        if not re.match('%s$' % NAME_RE, slotName):
-            raise METALError("invalid slot name: %s" % `slotName`,
-                             self.position)
-        self.slots[slotName] = program
-        self.inMacroUse = 1
-        self.emit("fillSlot", slotName, program)
-
-    def unEmitWhitespace(self):
-        collect = []
-        i = len(self.program) - 1
-        while i >= 0:
-            item = self.program[i]
-            if item[0] != "rawtext":
-                break
-            text = item[1]
-            if not re.match(r"\A\s*\Z", text):
-                break
-            collect.append(text)
-            i = i-1
-        del self.program[i+1:]
-        if i >= 0 and self.program[i][0] == "rawtext":
-            text = self.program[i][1]
-            m = re.search(r"\s+\Z", text)
-            if m:
-                self.program[i] = ("rawtext", text[:m.start()])
-                collect.append(m.group())
-        collect.reverse()
-        return "".join(collect)
-
-    def unEmitNewlineWhitespace(self):
-        collect = []
-        i = len(self.program)
-        while i > 0:
-            i = i-1
-            item = self.program[i]
-            if item[0] != "rawtext":
-                break
-            text = item[1]
-            if re.match(r"\A[ \t]*\Z", text):
-                collect.append(text)
-                continue
-            m = re.match(r"(?s)^(.*)(\n[ \t]*)\Z", text)
-            if not m:
-                break
-            text, rest = m.group(1, 2)
-            collect.reverse()
-            rest = rest + "".join(collect)
-            del self.program[i:]
-            if text:
-                self.emit("rawtext", text)
-            return rest
-        return None
-
-    def replaceAttrs(self, attrlist, repldict):
-        # Each entry in attrlist starts like (name, value).
-        # Result is (name, value, action, expr, xlat) if there is a
-        # tal:attributes entry for that attribute.  Additional attrs
-        # defined only by tal:attributes are added here.
-        #
-        # (name, value, action, expr, xlat)
-        if not repldict:
-            return attrlist
-        newlist = []
-        for item in attrlist:
-            key = item[0]
-            if repldict.has_key(key):
-                expr, xlat, msgid = repldict[key]
-                item = item[:2] + ("replace", expr, xlat, msgid)
-                del repldict[key]
-            newlist.append(item)
-        # Add dynamic-only attributes
-        for key, (expr, xlat, msgid) in repldict.items():
-            newlist.append((key, None, "insert", expr, xlat, msgid))
-        return newlist
-
-    def emitStartElement(self, name, attrlist, taldict, metaldict, i18ndict,
-                         position=(None, None), isend=0):
-        if not taldict and not metaldict and not i18ndict:
-            # Handle the simple, common case
-            self.emitStartTag(name, attrlist, isend)
-            self.todoPush({})
-            if isend:
-                self.emitEndElement(name, isend)
-            return
-
-        self.position = position
-        for key, value in taldict.items():
-            if key not in TALDefs.KNOWN_TAL_ATTRIBUTES:
-                raise TALError("bad TAL attribute: " + `key`, position)
-            if not (value or key == 'omit-tag'):
-                raise TALError("missing value for TAL attribute: " +
-                               `key`, position)
-        for key, value in metaldict.items():
-            if key not in TALDefs.KNOWN_METAL_ATTRIBUTES:
-                raise METALError("bad METAL attribute: " + `key`,
-                                 position)
-            if not value:
-                raise TALError("missing value for METAL attribute: " +
-                               `key`, position)
-        for key, value in i18ndict.items():
-            if key not in TALDefs.KNOWN_I18N_ATTRIBUTES:
-                raise I18NError("bad i18n attribute: " + `key`, position)
-            if not value and key in ("attributes", "data", "id"):
-                raise I18NError("missing value for i18n attribute: " +
-                                `key`, position)
-        todo = {}
-        defineMacro = metaldict.get("define-macro")
-        useMacro = metaldict.get("use-macro")
-        defineSlot = metaldict.get("define-slot")
-        fillSlot = metaldict.get("fill-slot")
-        define = taldict.get("define")
-        condition = taldict.get("condition")
-        repeat = taldict.get("repeat")
-        content = taldict.get("content")
-        replace = taldict.get("replace")
-        attrsubst = taldict.get("attributes")
-        onError = taldict.get("on-error")
-        omitTag = taldict.get("omit-tag")
-        TALtag = taldict.get("tal tag")
-        i18nattrs = i18ndict.get("attributes")
-        # Preserve empty string if implicit msgids are used.  We'll generate
-        # code with the msgid='' and calculate the right implicit msgid during
-        # interpretation phase.
-        msgid = i18ndict.get("translate")
-        varname = i18ndict.get('name')
-        i18ndata = i18ndict.get('data')
-
-        if varname and not self.i18nLevel:
-            raise I18NError(
-                "i18n:name can only occur inside a translation unit",
-                position)
-
-        if i18ndata and not msgid:
-            raise I18NError("i18n:data must be accompanied by i18n:translate",
-                            position)
-
-        if len(metaldict) > 1 and (defineMacro or useMacro):
-            raise METALError("define-macro and use-macro cannot be used "
-                             "together or with define-slot or fill-slot",
-                             position)
-        if replace:
-            if content:
-                raise TALError(
-                    "tal:content and tal:replace are mutually exclusive",
-                    position)
-            if msgid is not None:
-                raise I18NError(
-                    "i18n:translate and tal:replace are mutually exclusive",
-                    position)
-
-        repeatWhitespace = None
-        if repeat:
-            # Hack to include preceding whitespace in the loop program
-            repeatWhitespace = self.unEmitNewlineWhitespace()
-        if position != (None, None):
-            # XXX at some point we should insist on a non-trivial position
-            self.emit("setPosition", position)
-        if self.inMacroUse:
-            if fillSlot:
-                self.pushProgram()
-                if self.source_file is not None:
-                    self.emit("setSourceFile", self.source_file)
-                todo["fillSlot"] = fillSlot
-                self.inMacroUse = 0
-        else:
-            if fillSlot:
-                raise METALError("fill-slot must be within a use-macro",
-                                 position)
-        if not self.inMacroUse:
-            if defineMacro:
-                self.pushProgram()
-                self.emit("version", TAL_VERSION)
-                self.emit("mode", self.xml and "xml" or "html")
-                if self.source_file is not None:
-                    self.emit("setSourceFile", self.source_file)
-                todo["defineMacro"] = defineMacro
-                self.inMacroDef = self.inMacroDef + 1
-            if useMacro:
-                self.pushSlots()
-                self.pushProgram()
-                todo["useMacro"] = useMacro
-                self.inMacroUse = 1
-            if defineSlot:
-                if not self.inMacroDef:
-                    raise METALError(
-                        "define-slot must be within a define-macro",
-                        position)
-                self.pushProgram()
-                todo["defineSlot"] = defineSlot
-
-        if defineSlot or i18ndict:
-
-            domain = i18ndict.get("domain") or self.i18nContext.domain
-            source = i18ndict.get("source") or self.i18nContext.source
-            target = i18ndict.get("target") or self.i18nContext.target
-            if (  domain != DEFAULT_DOMAIN
-                  or source is not None
-                  or target is not None):
-                self.i18nContext = TranslationContext(self.i18nContext,
-                                                      domain=domain,
-                                                      source=source,
-                                                      target=target)
-                self.emit("beginI18nContext",
-                          {"domain": domain, "source": source,
-                           "target": target})
-                todo["i18ncontext"] = 1
-        if taldict or i18ndict:
-            dict = {}
-            for item in attrlist:
-                key, value = item[:2]
-                dict[key] = value
-            self.emit("beginScope", dict)
-            todo["scope"] = 1
-        if onError:
-            self.pushProgram() # handler
-            if TALtag:
-                self.pushProgram() # start
-            self.emitStartTag(name, list(attrlist)) # Must copy attrlist!
-            if TALtag:
-                self.pushProgram() # start
-            self.pushProgram() # block
-            todo["onError"] = onError
-        if define:
-            self.emitDefines(define)
-            todo["define"] = define
-        if condition:
-            self.pushProgram()
-            todo["condition"] = condition
-        if repeat:
-            todo["repeat"] = repeat
-            self.pushProgram()
-            if repeatWhitespace:
-                self.emitText(repeatWhitespace)
-        if content:
-            if varname:
-                todo['i18nvar'] = (varname, I18N_CONTENT, None)
-                todo["content"] = content
-                self.pushProgram()
-            else:
-                todo["content"] = content
-        elif replace:
-            # tal:replace w/ i18n:name has slightly different semantics.  What
-            # we're actually replacing then is the contents of the ${name}
-            # placeholder.
-            if varname:
-                todo['i18nvar'] = (varname, I18N_EXPRESSION, replace)
-            else:
-                todo["replace"] = replace
-            self.pushProgram()
-        # i18n:name w/o tal:replace uses the content as the interpolation
-        # dictionary values
-        elif varname:
-            todo['i18nvar'] = (varname, I18N_REPLACE, None)
-            self.pushProgram()
-        if msgid is not None:
-            self.i18nLevel += 1
-            todo['msgid'] = msgid
-        if i18ndata:
-            todo['i18ndata'] = i18ndata
-        optTag = omitTag is not None or TALtag
-        if optTag:
-            todo["optional tag"] = omitTag, TALtag
-            self.pushProgram()
-        if attrsubst or i18nattrs:
-            if attrsubst:
-                repldict = TALDefs.parseAttributeReplacements(attrsubst,
-                                                              self.xml)
-            else:
-                repldict = {}
-            if i18nattrs:
-                i18nattrs = _parseI18nAttributes(i18nattrs, attrlist, repldict,
-                                                 self.position, self.xml,
-                                                 self.source_file)
-            else:
-                i18nattrs = {}
-            # Convert repldict's name-->expr mapping to a
-            # name-->(compiled_expr, translate) mapping
-            for key, value in repldict.items():
-                if i18nattrs.get(key, None):
-                    raise I18NError(
-                      ("attribute [%s] cannot both be part of tal:attributes" +
-                      " and have a msgid in i18n:attributes") % key,
-                    position)
-                ce = self.compileExpression(value)
-                repldict[key] = ce, key in i18nattrs, i18nattrs.get(key)
-            for key in i18nattrs:
-                if not repldict.has_key(key):
-                    repldict[key] = None, 1, i18nattrs.get(key)
-        else:
-            repldict = {}
-        if replace:
-            todo["repldict"] = repldict
-            repldict = {}
-        self.emitStartTag(name, self.replaceAttrs(attrlist, repldict), isend)
-        if optTag:
-            self.pushProgram()
-        if content and not varname:
-            self.pushProgram()
-        if msgid is not None:
-            self.pushProgram()
-        if content and varname:
-            self.pushProgram()
-        if todo and position != (None, None):
-            todo["position"] = position
-        self.todoPush(todo)
-        if isend:
-            self.emitEndElement(name, isend)
-
-    def emitEndElement(self, name, isend=0, implied=0):
-        todo = self.todoPop()
-        if not todo:
-            # Shortcut
-            if not isend:
-                self.emitEndTag(name)
-            return
-
-        self.position = position = todo.get("position", (None, None))
-        defineMacro = todo.get("defineMacro")
-        useMacro = todo.get("useMacro")
-        defineSlot = todo.get("defineSlot")
-        fillSlot = todo.get("fillSlot")
-        repeat = todo.get("repeat")
-        content = todo.get("content")
-        replace = todo.get("replace")
-        condition = todo.get("condition")
-        onError = todo.get("onError")
-        repldict = todo.get("repldict", {})
-        scope = todo.get("scope")
-        optTag = todo.get("optional tag")
-        msgid = todo.get('msgid')
-        i18ncontext = todo.get("i18ncontext")
-        varname = todo.get('i18nvar')
-        i18ndata = todo.get('i18ndata')
-
-        if implied > 0:
-            if defineMacro or useMacro or defineSlot or fillSlot:
-                exc = METALError
-                what = "METAL"
-            else:
-                exc = TALError
-                what = "TAL"
-            raise exc("%s attributes on <%s> require explicit </%s>" %
-                      (what, name, name), position)
-
-        # If there's no tal:content or tal:replace in the tag with the
-        # i18n:name, tal:replace is the default.
-        if content:
-            self.emitSubstitution(content, {})
-        # If we're looking at an implicit msgid, emit the insertTranslation
-        # opcode now, so that the end tag doesn't become part of the implicit
-        # msgid.  If we're looking at an explicit msgid, it's better to emit
-        # the opcode after the i18nVariable opcode so we can better handle
-        # tags with both of them in them (and in the latter case, the contents
-        # would be thrown away for msgid purposes).
-        #
-        # Still, we should emit insertTranslation opcode before i18nVariable
-        # in case tal:content, i18n:translate and i18n:name in the same tag
-        if msgid is not None:
-            if (not varname) or (
-                varname and (varname[1] == I18N_CONTENT)):
-                self.emitTranslation(msgid, i18ndata)
-            self.i18nLevel -= 1
-        if optTag:
-            self.emitOptTag(name, optTag, isend)
-        elif not isend:
-            # If we're processing the end tag for a tag that contained
-            # i18n:name, we need to make sure that optimize() won't collect
-            # immediately following end tags into the same rawtextOffset, so
-            # put a spacer here that the optimizer will recognize.
-            if varname:
-                self.emit('noop')
-            self.emitEndTag(name)
-        # If i18n:name appeared in the same tag as tal:replace then we're
-        # going to do the substitution a little bit differently.  The results
-        # of the expression go into the i18n substitution dictionary.
-        if replace:
-            self.emitSubstitution(replace, repldict)
-        elif varname:
-            # o varname[0] is the variable name
-            # o varname[1] is either
-            #   - I18N_REPLACE for implicit tal:replace
-            #   - I18N_CONTENT for tal:content
-            #   - I18N_EXPRESSION for explicit tal:replace
-            # o varname[2] will be None for the first two actions and the
-            #   replacement tal expression for the third action.  This
-            #   can include a 'text' or 'structure' indicator.
-            assert (varname[1]
-                    in [I18N_REPLACE, I18N_CONTENT, I18N_EXPRESSION])
-            self.emitI18nVariable(varname)
-        # Do not test for "msgid is not None", i.e. we only want to test for
-        # explicit msgids here.  See comment above.
-        if msgid is not None: 
-            # in case tal:content, i18n:translate and i18n:name in the
-            # same tag insertTranslation opcode has already been
-            # emitted
-            if varname and (varname[1] <> I18N_CONTENT):
-                self.emitTranslation(msgid, i18ndata)
-        if repeat:
-            self.emitRepeat(repeat)
-        if condition:
-            self.emitCondition(condition)
-        if onError:
-            self.emitOnError(name, onError, optTag and optTag[1], isend)
-        if scope:
-            self.emit("endScope")
-        if i18ncontext:
-            self.emit("endI18nContext")
-            assert self.i18nContext.parent is not None
-            self.i18nContext = self.i18nContext.parent
-        if defineSlot:
-            self.emitDefineSlot(defineSlot)
-        if fillSlot:
-            self.emitFillSlot(fillSlot)
-        if useMacro:
-            self.emitUseMacro(useMacro)
-        if defineMacro:
-            self.emitDefineMacro(defineMacro)
-
-
-def _parseI18nAttributes(i18nattrs, attrlist, repldict, position,
-                         xml, source_file):
-
-    def addAttribute(dic, attr, msgid, position, xml):
-        if not xml:
-            attr = attr.lower()
-        if attr in dic:
-            raise TALError(
-                "attribute may only be specified once in i18n:attributes: "
-                + attr,
-                position)
-        dic[attr] = msgid
-
-    d = {}
-    if ';' in i18nattrs:
-        i18nattrlist = i18nattrs.split(';')
-        i18nattrlist = [attr.strip().split() 
-                        for attr in i18nattrlist if attr.strip()]
-        for parts in i18nattrlist:
-            if len(parts) > 2:
-                raise TALError("illegal i18n:attributes specification: %r"
-                                % parts, position)
-            if len(parts) == 2:
-                attr, msgid = parts
-            else:
-                # len(parts) == 1
-                attr = parts[0]
-                msgid = None
-            addAttribute(d, attr, msgid, position, xml)
-    else:
-        i18nattrlist = i18nattrs.split()
-        if len(i18nattrlist) == 1:
-            addAttribute(d, i18nattrlist[0], None, position, xml)
-        elif len(i18nattrlist) == 2:
-            staticattrs = [attr[0] for attr in attrlist if len(attr) == 2]
-            if (not i18nattrlist[1] in staticattrs) and (
-                not i18nattrlist[1] in repldict):
-                attr, msgid = i18nattrlist
-                addAttribute(d, attr, msgid, position, xml)    
-            else:
-                import warnings
-                warnings.warn(I18N_ATTRIBUTES_WARNING
-                % (source_file, str(position), i18nattrs)
-                , DeprecationWarning)
-                msgid = None
-                for attr in i18nattrlist:
-                    addAttribute(d, attr, msgid, position, xml)    
-        else:    
-            import warnings
-            warnings.warn(I18N_ATTRIBUTES_WARNING
-            % (source_file, str(position), i18nattrs)
-            , DeprecationWarning)
-            msgid = None
-            for attr in i18nattrlist:
-                addAttribute(d, attr, msgid, position, xml)    
-    return d
-
-I18N_ATTRIBUTES_WARNING = (
-    'Space separated attributes in i18n:attributes'
-    ' are deprecated (i18n:attributes="value title"). Please use'
-    ' semicolon to separate attributes'
-    ' (i18n:attributes="value; title").'
-    '\nFile %s at row, column %s\nAttributes %s')
-
-def test():
-    t = TALGenerator()
-    t.pushProgram()
-    t.emit("bar")
-    p = t.popProgram()
-    t.emit("foo", p)
-
-if __name__ == "__main__":
-    test()
+BBB 2005/05/01 -- to be removed after 12 months
+"""
+import zope.deprecation
+zope.deprecation.moved('zope.tal.talgenerator', '2.12')

Modified: Zope/trunk/lib/python/TAL/TALInterpreter.py
===================================================================
--- Zope/trunk/lib/python/TAL/TALInterpreter.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/TALInterpreter.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -13,828 +13,16 @@
 ##############################################################################
 """Interpreter for a pre-compiled TAL program.
 
+BBB 2005/05/01 -- to be removed after 12 months
+
 $Id$
 """
-import cgi
-import sys
-import re
+import zope.deprecation
+zope.deprecation.moved('zope.tal.talinterpreter', '2.12')
 
-# Do not use cStringIO here!  It's not unicode aware. :(
-from StringIO import StringIO
-from DocumentTemplate.DT_Util import ustr
-from ZODB.POSException import ConflictError
-
-from zope.i18nmessageid import Message
-
-from TALDefs import attrEscape, TAL_VERSION, METALError
-from TALDefs import isCurrentVersion
-from TALDefs import getProgramVersion, getProgramMode
-from TALGenerator import TALGenerator
-from TranslationContext import TranslationContext
-
-I18nMessageTypes = (Message,)
-
-# TODO: In Python 2.4 we can use frozenset() instead of dict.fromkeys()
-BOOLEAN_HTML_ATTRS = dict.fromkeys([
-    # List of Boolean attributes in HTML that should be rendered in
-    # minimized form (e.g. <img ismap> rather than <img ismap="">)
-    # From http://www.w3.org/TR/xhtml1/#guidelines (C.10)
-    # TODO: The problem with this is that this is not valid XML and
-    # can't be parsed back!
-    "compact", "nowrap", "ismap", "declare", "noshade", "checked",
-    "disabled", "readonly", "multiple", "selected", "noresize",
-    "defer"
-])
-
-_nulljoin = ''.join
-_spacejoin = ' '.join
-
-def normalize(text):
-    # Now we need to normalize the whitespace in implicit message ids and
-    # implicit $name substitution values by stripping leading and trailing
-    # whitespace, and folding all internal whitespace to a single space.
-    return _spacejoin(text.split())
-
-
-NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*"
-_interp_regex = re.compile(r'(?<!\$)(\$(?:%(n)s|{%(n)s}))' %({'n': NAME_RE}))
-_get_var_regex = re.compile(r'%(n)s' %({'n': NAME_RE}))
-
-def interpolate(text, mapping):
-    """Interpolate ${keyword} substitutions.
-
-    This is called when no translation is provided by the translation
-    service.
-    """
-    if not mapping:
-        return text
-    # Find all the spots we want to substitute.
-    to_replace = _interp_regex.findall(text)
-    # Now substitute with the variables in mapping.
-    for string in to_replace:
-        var = _get_var_regex.findall(string)[0]
-        if mapping.has_key(var):
-            # Call ustr because we may have an integer for instance.
-            subst = ustr(mapping[var])
-            try:
-                text = text.replace(string, subst)
-            except UnicodeError:
-                # subst contains high-bit chars...
-                # As we have no way of knowing the correct encoding,
-                # substitue something instead of raising an exception.
-                subst = `subst`[1:-1]
-                text = text.replace(string, subst)
-    return text
-
-
-class AltTALGenerator(TALGenerator):
-
-    def __init__(self, repldict, expressionCompiler=None, xml=0):
-        self.repldict = repldict
-        self.enabled = 1
-        TALGenerator.__init__(self, expressionCompiler, xml)
-
-    def enable(self, enabled):
-        self.enabled = enabled
-
-    def emit(self, *args):
-        if self.enabled:
-            TALGenerator.emit(self, *args)
-
-    def emitStartElement(self, name, attrlist, taldict, metaldict, i18ndict,
-                         position=(None, None), isend=0):
-        metaldict = {}
-        taldict = {}
-        i18ndict = {}
-        if self.enabled and self.repldict:
-            taldict["attributes"] = "x x"
-        TALGenerator.emitStartElement(self, name, attrlist,
-                                      taldict, metaldict, i18ndict,
-                                      position, isend)
-
-    def replaceAttrs(self, attrlist, repldict):
-        if self.enabled and self.repldict:
-            repldict = self.repldict
-            self.repldict = None
-        return TALGenerator.replaceAttrs(self, attrlist, repldict)
-
-
-class TALInterpreter:
-    """TAL interpreter.
-    """
-
-    def __init__(self, program, macros, engine, stream=None,
-                 debug=0, wrap=60, metal=1, tal=1, showtal=-1,
-                 strictinsert=1, stackLimit=100, i18nInterpolate=1):
-        """Create a TAL interpreter.
-
-        Optional arguments:
-
-            stream -- output stream (defaults to sys.stdout).
-
-            debug -- enable debugging output to sys.stderr (off by default).
-
-            wrap -- try to wrap attributes on opening tags to this number of
-            column (default: 60).
-
-            metal -- enable METAL macro processing (on by default).
-
-            tal -- enable TAL processing (on by default).
-
-            showtal -- do not strip away TAL directives.  A special value of
-            -1 (which is the default setting) enables showtal when TAL
-            processing is disabled, and disables showtal when TAL processing is
-            enabled.  Note that you must use 0, 1, or -1; true boolean values
-            are not supported (TODO: why?).
-
-            strictinsert -- enable TAL processing and stricter HTML/XML
-            checking on text produced by structure inserts (on by default).
-            Note that Zope turns this value off by default.
-
-            stackLimit -- set macro nesting limit (default: 100).
-
-            i18nInterpolate -- enable i18n translations (default: on).
-
-        """
-        self.program = program
-        self.macros = macros
-        self.engine = engine # Execution engine (aka context)
-        self.Default = engine.getDefault()
-        self._currentTag = ""
-        self._stream_stack = [stream or sys.stdout]
-        self.popStream()
-        self.debug = debug
-        self.wrap = wrap
-        self.metal = metal
-        self.tal = tal
-        if tal:
-            self.dispatch = self.bytecode_handlers_tal
-        else:
-            self.dispatch = self.bytecode_handlers
-        assert showtal in (-1, 0, 1)
-        if showtal == -1:
-            showtal = (not tal)
-        self.showtal = showtal
-        self.strictinsert = strictinsert
-        self.stackLimit = stackLimit
-        self.html = 0
-        self.endsep = "/>"
-        self.endlen = len(self.endsep)
-        self.macroStack = []
-        self.position = None, None  # (lineno, offset)
-        self.col = 0
-        self.level = 0
-        self.scopeLevel = 0
-        self.sourceFile = None
-        self.i18nStack = []
-        self.i18nInterpolate = i18nInterpolate
-        self.i18nContext = TranslationContext()
-
-    def StringIO(self):
-        # Third-party products wishing to provide a full Unicode-aware
-        # StringIO can do so by monkey-patching this method.
-        return FasterStringIO()
-
-    def saveState(self):
-        return (self.position, self.col, self.stream, self._stream_stack,
-                self.scopeLevel, self.level, self.i18nContext)
-
-    def restoreState(self, state):
-        (self.position, self.col, self.stream,
-         self._stream_stack, scopeLevel, level, i18n) = state
-        self._stream_write = self.stream.write
-        assert self.level == level
-        while self.scopeLevel > scopeLevel:
-            self.engine.endScope()
-            self.scopeLevel = self.scopeLevel - 1
-        self.engine.setPosition(self.position)
-        self.i18nContext = i18n
-
-    def restoreOutputState(self, state):
-        (dummy, self.col, self.stream,
-         self._stream_stack, scopeLevel, level, i18n) = state
-        self._stream_write = self.stream.write
-        assert self.level == level
-        assert self.scopeLevel == scopeLevel
-
-    def pushMacro(self, macroName, slots, entering=1):
-        if len(self.macroStack) >= self.stackLimit:
-            raise METALError("macro nesting limit (%d) exceeded "
-                             "by %s" % (self.stackLimit, `macroName`))
-        self.macroStack.append([macroName, slots, entering, self.i18nContext])
-
-    def popMacro(self):
-        return self.macroStack.pop()
-
-    def __call__(self):
-        assert self.level == 0
-        assert self.scopeLevel == 0
-        assert self.i18nContext.parent is None
-        self.interpret(self.program)
-        assert self.level == 0
-        assert self.scopeLevel == 0
-        assert self.i18nContext.parent is None
-        if self.col > 0:
-            self._stream_write("\n")
-            self.col = 0
-
-    def pushStream(self, newstream):
-        self._stream_stack.append(self.stream)
-        self.stream = newstream
-        self._stream_write = self.stream.write
-
-    def popStream(self):
-        self.stream = self._stream_stack.pop()
-        self._stream_write = self.stream.write
-
-    def stream_write(self, s,
-                     len=len):
-        self._stream_write(s)
-        i = s.rfind('\n')
-        if i < 0:
-            self.col = self.col + len(s)
-        else:
-            self.col = len(s) - (i + 1)
-
-    bytecode_handlers = {}
-
-    def interpret(self, program):
-        oldlevel = self.level
-        self.level = oldlevel + 1
-        handlers = self.dispatch
-        try:
-            if self.debug:
-                for (opcode, args) in program:
-                    s = "%sdo_%s(%s)\n" % ("    "*self.level, opcode,
-                                           repr(args))
-                    if len(s) > 80:
-                        s = s[:76] + "...\n"
-                    sys.stderr.write(s)
-                    handlers[opcode](self, args)
-            else:
-                for (opcode, args) in program:
-                    handlers[opcode](self, args)
-        finally:
-            self.level = oldlevel
-
-    def do_version(self, version):
-        assert version == TAL_VERSION
-    bytecode_handlers["version"] = do_version
-
-    def do_mode(self, mode):
-        assert mode in ("html", "xml")
-        self.html = (mode == "html")
-        if self.html:
-            self.endsep = " />"
-        else:
-            self.endsep = "/>"
-        self.endlen = len(self.endsep)
-    bytecode_handlers["mode"] = do_mode
-
-    def do_setSourceFile(self, source_file):
-        self.sourceFile = source_file
-        self.engine.setSourceFile(source_file)
-    bytecode_handlers["setSourceFile"] = do_setSourceFile
-
-    def do_setPosition(self, position):
-        self.position = position
-        self.engine.setPosition(position)
-    bytecode_handlers["setPosition"] = do_setPosition
-
-    def do_startEndTag(self, stuff):
-        self.do_startTag(stuff, self.endsep, self.endlen)
-    bytecode_handlers["startEndTag"] = do_startEndTag
-
-    def do_startTag(self, (name, attrList),
-                    end=">", endlen=1, _len=len):
-        # The bytecode generator does not cause calls to this method
-        # for start tags with no attributes; those are optimized down
-        # to rawtext events.  Hence, there is no special "fast path"
-        # for that case.
-        self._currentTag = name
-        L = ["<", name]
-        append = L.append
-        col = self.col + _len(name) + 1
-        wrap = self.wrap
-        align = col + 1
-        if align >= wrap/2:
-            align = 4  # Avoid a narrow column far to the right
-        attrAction = self.dispatch["<attrAction>"]
-        try:
-            for item in attrList:
-                if _len(item) == 2:
-                    name, s = item
-                else:
-                    # item[2] is the 'action' field:
-                    if item[2] in ('metal', 'tal', 'xmlns', 'i18n'):
-                        if not self.showtal:
-                            continue
-                        ok, name, s = self.attrAction(item)
-                    else:
-                        ok, name, s = attrAction(self, item)
-                    if not ok:
-                        continue
-                slen = _len(s)
-                if (wrap and
-                    col >= align and
-                    col + 1 + slen > wrap):
-                    append("\n")
-                    append(" "*align)
-                    col = align + slen
-                else:
-                    append(" ")
-                    col = col + 1 + slen
-                append(s)
-            append(end)
-            col = col + endlen
-        finally:
-            self._stream_write(_nulljoin(L))
-            self.col = col
-    bytecode_handlers["startTag"] = do_startTag
-
-    def attrAction(self, item):
-        name, value, action = item[:3]
-        if action == 'insert':
-            return 0, name, value
-        macs = self.macroStack
-        if action == 'metal' and self.metal and macs:
-            if len(macs) > 1 or not macs[-1][2]:
-                # Drop all METAL attributes at a use-depth above one.
-                return 0, name, value
-            # Clear 'entering' flag
-            macs[-1][2] = 0
-            # Convert or drop depth-one METAL attributes.
-            i = name.rfind(":") + 1
-            prefix, suffix = name[:i], name[i:]
-            if suffix == "define-macro":
-                # Convert define-macro as we enter depth one.
-                name = prefix + "use-macro"
-                value = macs[-1][0] # Macro name
-            elif suffix == "define-slot":
-                name = prefix + "fill-slot"
-            elif suffix == "fill-slot":
-                pass
-            else:
-                return 0, name, value
-
-        if value is None:
-            value = name
-        else:
-            value = '%s="%s"' % (name, attrEscape(value))
-        return 1, name, value
-
-    def attrAction_tal(self, item):
-        name, value, action = item[:3]
-        ok = 1
-        expr, xlat, msgid = item[3:]
-        if self.html and name.lower() in BOOLEAN_HTML_ATTRS:
-            evalue = self.engine.evaluateBoolean(item[3])
-            if evalue is self.Default:
-                if action == 'insert': # Cancelled insert
-                    ok = 0
-            elif evalue:
-                value = None
-            else:
-                ok = 0
-        elif expr is not None:
-            evalue = self.engine.evaluateText(item[3])
-            if evalue is self.Default:
-                if action == 'insert': # Cancelled insert
-                    ok = 0
-            else:
-                if evalue is None:
-                    ok = 0
-                value = evalue
-        else:
-            evalue = None
-
-        if ok:
-            if xlat:
-                translated = self.translate(msgid or value, value, {})
-                if translated is not None:
-                    value = translated
-            if value is None:
-                value = name
-            elif evalue is self.Default:
-                value = attrEscape(value)
-            else:
-                value = cgi.escape(value, quote=1)
-            value = '%s="%s"' % (name, value)
-        return ok, name, value
-    bytecode_handlers["<attrAction>"] = attrAction
-
-    def no_tag(self, start, program):
-        state = self.saveState()
-        self.stream = stream = self.StringIO()
-        self._stream_write = stream.write
-        self.interpret(start)
-        self.restoreOutputState(state)
-        self.interpret(program)
-
-    def do_optTag(self, (name, cexpr, tag_ns, isend, start, program),
-                  omit=0):
-        if tag_ns and not self.showtal:
-            return self.no_tag(start, program)
-
-        self.interpret(start)
-        if not isend:
-            self.interpret(program)
-            s = '</%s>' % name
-            self._stream_write(s)
-            self.col = self.col + len(s)
-
-    def do_optTag_tal(self, stuff):
-        cexpr = stuff[1]
-        if cexpr is not None and (cexpr == '' or
-                                  self.engine.evaluateBoolean(cexpr)):
-            self.no_tag(stuff[-2], stuff[-1])
-        else:
-            self.do_optTag(stuff)
-    bytecode_handlers["optTag"] = do_optTag
-
-    def do_rawtextBeginScope(self, (s, col, position, closeprev, dict)):
-        self._stream_write(s)
-        self.col = col
-        self.do_setPosition(position)
-        if closeprev:
-            engine = self.engine
-            engine.endScope()
-            engine.beginScope()
-        else:
-            self.engine.beginScope()
-            self.scopeLevel = self.scopeLevel + 1
-
-    def do_rawtextBeginScope_tal(self, (s, col, position, closeprev, dict)):
-        self._stream_write(s)
-        self.col = col
-        engine = self.engine
-        self.position = position
-        engine.setPosition(position)
-        if closeprev:
-            engine.endScope()
-            engine.beginScope()
-        else:
-            engine.beginScope()
-            self.scopeLevel = self.scopeLevel + 1
-        engine.setLocal("attrs", dict)
-    bytecode_handlers["rawtextBeginScope"] = do_rawtextBeginScope
-
-    def do_beginScope(self, dict):
-        self.engine.beginScope()
-        self.scopeLevel = self.scopeLevel + 1
-
-    def do_beginScope_tal(self, dict):
-        engine = self.engine
-        engine.beginScope()
-        engine.setLocal("attrs", dict)
-        self.scopeLevel = self.scopeLevel + 1
-    bytecode_handlers["beginScope"] = do_beginScope
-
-    def do_endScope(self, notused=None):
-        self.engine.endScope()
-        self.scopeLevel = self.scopeLevel - 1
-    bytecode_handlers["endScope"] = do_endScope
-
-    def do_setLocal(self, notused):
-        pass
-
-    def do_setLocal_tal(self, (name, expr)):
-        self.engine.setLocal(name, self.engine.evaluateValue(expr))
-    bytecode_handlers["setLocal"] = do_setLocal
-
-    def do_setGlobal_tal(self, (name, expr)):
-        self.engine.setGlobal(name, self.engine.evaluateValue(expr))
-    bytecode_handlers["setGlobal"] = do_setLocal
-
-    def do_beginI18nContext(self, settings):
-        get = settings.get
-        self.i18nContext = TranslationContext(self.i18nContext,
-                                              domain=get("domain"),
-                                              source=get("source"),
-                                              target=get("target"))
-    bytecode_handlers["beginI18nContext"] = do_beginI18nContext
-
-    def do_endI18nContext(self, notused=None):
-        self.i18nContext = self.i18nContext.parent
-        assert self.i18nContext is not None
-    bytecode_handlers["endI18nContext"] = do_endI18nContext
-
-    def do_insertText(self, stuff):
-        self.interpret(stuff[1])
-
-    def do_insertText_tal(self, stuff):
-        text = self.engine.evaluateText(stuff[0])
-        if text is None:
-            return
-        if text is self.Default:
-            self.interpret(stuff[1])
-            return
-        if isinstance(text, I18nMessageTypes):
-            # Translate this now.
-            text = self.engine.translate(text.domain, text, 
-                                         text.mapping, default=text.default)
-        s = cgi.escape(text)
-        self._stream_write(s)
-        i = s.rfind('\n')
-        if i < 0:
-            self.col = self.col + len(s)
-        else:
-            self.col = len(s) - (i + 1)
-    bytecode_handlers["insertText"] = do_insertText
-
-    def do_i18nVariable(self, stuff):
-        varname, program, expression, structure = stuff
-        if expression is None:
-            # The value is implicitly the contents of this tag, so we have to
-            # evaluate the mini-program to get the value of the variable.
-            state = self.saveState()
-            try:
-                tmpstream = self.StringIO()
-                self.pushStream(tmpstream)
-                try:
-                    self.interpret(program)
-                finally:
-                    self.popStream()
-                if self.html and self._currentTag == "pre":
-                    value = tmpstream.getvalue()
-                else:
-                    value = normalize(tmpstream.getvalue())
-            finally:
-                self.restoreState(state)
-        else:
-            # Evaluate the value to be associated with the variable in the
-            # i18n interpolation dictionary.
-            if structure:
-                value = self.engine.evaluateStructure(expression)
-            else:
-                value = self.engine.evaluate(expression)
-
-            # evaluate() does not do any I18n, so we do it here.
-            if isinstance(value, I18nMessageTypes):
-                # Translate this now.
-                # XXX
-                value = self.engine.translate(value.domain, value,
-                                              value.mapping, value.default)
-
-            if not structure:
-                value = cgi.escape(ustr(value))
-
-        # Either the i18n:name tag is nested inside an i18n:translate in which
-        # case the last item on the stack has the i18n dictionary and string
-        # representation, or the i18n:name and i18n:translate attributes are
-        # in the same tag, in which case the i18nStack will be empty.  In that
-        # case we can just output the ${name} to the stream
-        i18ndict, srepr = self.i18nStack[-1]
-        i18ndict[varname] = value
-        placeholder = '${%s}' % varname
-        srepr.append(placeholder)
-        self._stream_write(placeholder)
-    bytecode_handlers['i18nVariable'] = do_i18nVariable
-
-    def do_insertTranslation(self, stuff):
-        i18ndict = {}
-        srepr = []
-        obj = None
-        self.i18nStack.append((i18ndict, srepr))
-        msgid = stuff[0]
-        # We need to evaluate the content of the tag because that will give us
-        # several useful pieces of information.  First, the contents will
-        # include an implicit message id, if no explicit one was given.
-        # Second, it will evaluate any i18nVariable definitions in the body of
-        # the translation (necessary for $varname substitutions).
-        #
-        # Use a temporary stream to capture the interpretation of the
-        # subnodes, which should /not/ go to the output stream.
-        currentTag = self._currentTag
-        tmpstream = self.StringIO()
-        self.pushStream(tmpstream)
-        try:
-            self.interpret(stuff[1])
-        finally:
-            self.popStream()
-        # We only care about the evaluated contents if we need an implicit
-        # message id.  All other useful information will be in the i18ndict on
-        # the top of the i18nStack.
-        default = tmpstream.getvalue()
-        if not msgid:
-            if self.html and currentTag == "pre":
-                msgid = default
-            else:
-                msgid = normalize(default)
-        self.i18nStack.pop()
-        # See if there is was an i18n:data for msgid
-        if len(stuff) > 2:
-            obj = self.engine.evaluate(stuff[2])
-        xlated_msgid = self.translate(msgid, default, i18ndict, obj)
-        # TODO: I can't decide whether we want to cgi escape the translated
-        # string or not.  OTOH not doing this could introduce a cross-site
-        # scripting vector by allowing translators to sneak JavaScript into
-        # translations.  OTOH, for implicit interpolation values, we don't
-        # want to escape stuff like ${name} <= "<b>Timmy</b>".
-        assert xlated_msgid is not None
-        self._stream_write(xlated_msgid)
-    bytecode_handlers['insertTranslation'] = do_insertTranslation
-
-    def do_insertStructure(self, stuff):
-        self.interpret(stuff[2])
-
-    def do_insertStructure_tal(self, (expr, repldict, block)):
-        structure = self.engine.evaluateStructure(expr)
-        if structure is None:
-            return
-        if structure is self.Default:
-            self.interpret(block)
-            return
-        text = ustr(structure)
-        if not (repldict or self.strictinsert):
-            # Take a shortcut, no error checking
-            self.stream_write(text)
-            return
-        if self.html:
-            self.insertHTMLStructure(text, repldict)
-        else:
-            self.insertXMLStructure(text, repldict)
-    bytecode_handlers["insertStructure"] = do_insertStructure
-
-    def insertHTMLStructure(self, text, repldict):
-        from HTMLTALParser import HTMLTALParser
-        gen = AltTALGenerator(repldict, self.engine.getCompiler(), 0)
-        p = HTMLTALParser(gen) # Raises an exception if text is invalid
-        p.parseString(text)
-        program, macros = p.getCode()
-        self.interpret(program)
-
-    def insertXMLStructure(self, text, repldict):
-        from TALParser import TALParser
-        gen = AltTALGenerator(repldict, self.engine.getCompiler(), 0)
-        p = TALParser(gen)
-        gen.enable(0)
-        p.parseFragment('<!DOCTYPE foo PUBLIC "foo" "bar"><foo>')
-        gen.enable(1)
-        p.parseFragment(text) # Raises an exception if text is invalid
-        gen.enable(0)
-        p.parseFragment('</foo>', 1)
-        program, macros = gen.getCode()
-        self.interpret(program)
-
-    def do_loop(self, (name, expr, block)):
-        self.interpret(block)
-
-    def do_loop_tal(self, (name, expr, block)):
-        iterator = self.engine.setRepeat(name, expr)
-        while iterator.next():
-            self.interpret(block)
-    bytecode_handlers["loop"] = do_loop
-
-    def translate(self, msgid, default, i18ndict, obj=None):
-        if obj:
-            i18ndict.update(obj)
-        if not self.i18nInterpolate:
-            return msgid
-        # TODO: We need to pass in one of context or target_language
-        return self.engine.translate(self.i18nContext.domain,
-                                     msgid, i18ndict, default=default)
-
-    def do_rawtextColumn(self, (s, col)):
-        self._stream_write(s)
-        self.col = col
-    bytecode_handlers["rawtextColumn"] = do_rawtextColumn
-
-    def do_rawtextOffset(self, (s, offset)):
-        self._stream_write(s)
-        self.col = self.col + offset
-    bytecode_handlers["rawtextOffset"] = do_rawtextOffset
-
-    def do_condition(self, (condition, block)):
-        if not self.tal or self.engine.evaluateBoolean(condition):
-            self.interpret(block)
-    bytecode_handlers["condition"] = do_condition
-
-    def do_defineMacro(self, (macroName, macro)):
-        macs = self.macroStack
-        if len(macs) == 1:
-            entering = macs[-1][2]
-            if not entering:
-                macs.append(None)
-                self.interpret(macro)
-                assert macs[-1] is None
-                macs.pop()
-                return
-        self.interpret(macro)
-    bytecode_handlers["defineMacro"] = do_defineMacro
-
-    def do_useMacro(self, (macroName, macroExpr, compiledSlots, block)):
-        if not self.metal:
-            self.interpret(block)
-            return
-        macro = self.engine.evaluateMacro(macroExpr)
-        if macro is self.Default:
-            macro = block
-        else:
-            if not isCurrentVersion(macro):
-                raise METALError("macro %s has incompatible version %s" %
-                                 (`macroName`, `getProgramVersion(macro)`),
-                                 self.position)
-            mode = getProgramMode(macro)
-            if mode != (self.html and "html" or "xml"):
-                raise METALError("macro %s has incompatible mode %s" %
-                                 (`macroName`, `mode`), self.position)
-        self.pushMacro(macroName, compiledSlots)
-        prev_source = self.sourceFile
-        self.interpret(macro)
-        if self.sourceFile != prev_source:
-            self.engine.setSourceFile(prev_source)
-            self.sourceFile = prev_source
-        self.popMacro()
-    bytecode_handlers["useMacro"] = do_useMacro
-
-    def do_fillSlot(self, (slotName, block)):
-        # This is only executed if the enclosing 'use-macro' evaluates
-        # to 'default'.
-        self.interpret(block)
-    bytecode_handlers["fillSlot"] = do_fillSlot
-
-    def do_defineSlot(self, (slotName, block)):
-        if not self.metal:
-            self.interpret(block)
-            return
-        macs = self.macroStack
-        if macs and macs[-1] is not None:
-            macroName, slots = self.popMacro()[:2]
-            slot = slots.get(slotName)
-            if slot is not None:
-                prev_source = self.sourceFile
-                try:
-                    self.interpret(slot)
-                finally:
-                    if self.sourceFile != prev_source:
-                        self.engine.setSourceFile(prev_source)
-                        self.sourceFile = prev_source
-                    self.pushMacro(macroName, slots, entering=0)
-                return
-            self.pushMacro(macroName, slots)
-            # Falling out of the 'if' allows the macro to be interpreted.
-        self.interpret(block)
-    bytecode_handlers["defineSlot"] = do_defineSlot
-
-    def do_onError(self, (block, handler)):
-        self.interpret(block)
-
-    def do_onError_tal(self, (block, handler)):
-        state = self.saveState()
-        self.stream = stream = self.StringIO()
-        self._stream_write = stream.write
-        try:
-            self.interpret(block)
-        except ConflictError:
-            raise
-        except:
-            exc = sys.exc_info()[1]
-            self.restoreState(state)
-            engine = self.engine
-            engine.beginScope()
-            error = engine.createErrorInfo(exc, self.position)
-            engine.setLocal('error', error)
-            try:
-                self.interpret(handler)
-            finally:
-                engine.endScope()
-        else:
-            self.restoreOutputState(state)
-            self.stream_write(stream.getvalue())
-    bytecode_handlers["onError"] = do_onError
-
-    bytecode_handlers_tal = bytecode_handlers.copy()
-    bytecode_handlers_tal["rawtextBeginScope"] = do_rawtextBeginScope_tal
-    bytecode_handlers_tal["beginScope"] = do_beginScope_tal
-    bytecode_handlers_tal["setLocal"] = do_setLocal_tal
-    bytecode_handlers_tal["setGlobal"] = do_setGlobal_tal
-    bytecode_handlers_tal["insertStructure"] = do_insertStructure_tal
-    bytecode_handlers_tal["insertText"] = do_insertText_tal
-    bytecode_handlers_tal["loop"] = do_loop_tal
-    bytecode_handlers_tal["onError"] = do_onError_tal
-    bytecode_handlers_tal["<attrAction>"] = attrAction_tal
-    bytecode_handlers_tal["optTag"] = do_optTag_tal
-
-
-class FasterStringIO(StringIO):
-    """Append-only version of StringIO.
-
-    This let's us have a much faster write() method.
-    """
-    def close(self):
-        if not self.closed:
-            self.write = _write_ValueError
-            StringIO.close(self)
-
-    def seek(self, pos, mode=0):
-        raise RuntimeError("FasterStringIO.seek() not allowed")
-
-    def write(self, s):
-        #assert self.pos == self.len
-        self.buflist.append(s)
-        self.len = self.pos = self.pos + len(s)
-
-
-def _write_ValueError(s):
-    raise ValueError, "I/O operation on closed file"
+import zope.deferredimport
+zope.deferredimport.deprecated(
+    "'interpolate' has moved to zope.i18n.  This reference will be gone "
+    "in Zope 2.12.",
+    interpolate = 'zope.i18n:interpolate'
+    )

Modified: Zope/trunk/lib/python/TAL/TALParser.py
===================================================================
--- Zope/trunk/lib/python/TAL/TALParser.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/TALParser.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -13,131 +13,8 @@
 ##############################################################################
 """
 Parse XML and compile to TALInterpreter intermediate code.
-"""
 
-from XMLParser import XMLParser
-from TALDefs import XML_NS, ZOPE_I18N_NS, ZOPE_METAL_NS, ZOPE_TAL_NS
-from TALGenerator import TALGenerator
-
-class TALParser(XMLParser):
-
-    ordered_attributes = 1
-
-    def __init__(self, gen=None): # Override
-        XMLParser.__init__(self)
-        if gen is None:
-            gen = TALGenerator()
-        self.gen = gen
-        self.nsStack = []
-        self.nsDict = {XML_NS: 'xml'}
-        self.nsNew = []
-
-    def getCode(self):
-        return self.gen.getCode()
-
-    def getWarnings(self):
-        return ()
-
-    def StartNamespaceDeclHandler(self, prefix, uri):
-        self.nsStack.append(self.nsDict.copy())
-        self.nsDict[uri] = prefix
-        self.nsNew.append((prefix, uri))
-
-    def EndNamespaceDeclHandler(self, prefix):
-        self.nsDict = self.nsStack.pop()
-
-    def StartElementHandler(self, name, attrs):
-        if self.ordered_attributes:
-            # attrs is a list of alternating names and values
-            attrlist = []
-            for i in range(0, len(attrs), 2):
-                key = attrs[i]
-                value = attrs[i+1]
-                attrlist.append((key, value))
-        else:
-            # attrs is a dict of {name: value}
-            attrlist = attrs.items()
-            attrlist.sort() # For definiteness
-        name, attrlist, taldict, metaldict, i18ndict \
-              = self.process_ns(name, attrlist)
-        attrlist = self.xmlnsattrs() + attrlist
-        self.gen.emitStartElement(name, attrlist, taldict, metaldict, i18ndict)
-
-    def process_ns(self, name, attrlist):
-        taldict = {}
-        metaldict = {}
-        i18ndict = {}
-        fixedattrlist = []
-        name, namebase, namens = self.fixname(name)
-        for key, value in attrlist:
-            key, keybase, keyns = self.fixname(key)
-            ns = keyns or namens # default to tag namespace
-            item = key, value
-            if ns == 'metal':
-                metaldict[keybase] = value
-                item = item + ("metal",)
-            elif ns == 'tal':
-                taldict[keybase] = value
-                item = item + ("tal",)
-            elif ns == 'i18n':
-                i18ndict[keybase] = value
-                item = item + ('i18n',)
-            fixedattrlist.append(item)
-        if namens in ('metal', 'tal', 'i18n'):
-            taldict['tal tag'] = namens
-        return name, fixedattrlist, taldict, metaldict, i18ndict
-
-    def xmlnsattrs(self):
-        newlist = []
-        for prefix, uri in self.nsNew:
-            if prefix:
-                key = "xmlns:" + prefix
-            else:
-                key = "xmlns"
-            if uri in (ZOPE_METAL_NS, ZOPE_TAL_NS, ZOPE_I18N_NS):
-                item = (key, uri, "xmlns")
-            else:
-                item = (key, uri)
-            newlist.append(item)
-        self.nsNew = []
-        return newlist
-
-    def fixname(self, name):
-        if ' ' in name:
-            uri, name = name.split(' ')
-            prefix = self.nsDict[uri]
-            prefixed = name
-            if prefix:
-                prefixed = "%s:%s" % (prefix, name)
-            ns = 'x'
-            if uri == ZOPE_TAL_NS:
-                ns = 'tal'
-            elif uri == ZOPE_METAL_NS:
-                ns = 'metal'
-            elif uri == ZOPE_I18N_NS:
-                ns = 'i18n'
-            return (prefixed, name, ns)
-        return (name, name, None)
-
-    def EndElementHandler(self, name):
-        name = self.fixname(name)[0]
-        self.gen.emitEndElement(name)
-
-    def DefaultHandler(self, text):
-        self.gen.emitRawText(text)
-
-def test():
-    import sys
-    p = TALParser()
-    file = "tests/input/test01.xml"
-    if sys.argv[1:]:
-        file = sys.argv[1]
-    p.parseFile(file)
-    program, macros = p.getCode()
-    from TALInterpreter import TALInterpreter
-    from DummyEngine import DummyEngine
-    engine = DummyEngine(macros)
-    TALInterpreter(program, macros, engine, sys.stdout, wrap=0)()
-
-if __name__ == "__main__":
-    test()
+BBB 2005/05/01 -- to be removed after 12 months
+"""
+import zope.deprecation
+zope.deprecation.moved('zope.tal.talparser', '2.12')

Modified: Zope/trunk/lib/python/TAL/TranslationContext.py
===================================================================
--- Zope/trunk/lib/python/TAL/TranslationContext.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/TranslationContext.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -13,29 +13,9 @@
 ##############################################################################
 """Translation context object for the TALInterpreter's I18N support.
 
-The translation context provides a container for the information
-needed to perform translation of a marked string from a page template.
+BBB 2005/05/01 -- to be removed after 12 months
 
 $Id$
 """
-
-DEFAULT_DOMAIN = "default"
-
-class TranslationContext:
-    """Information about the I18N settings of a TAL processor."""
-
-    def __init__(self, parent=None, domain=None, target=None, source=None):
-        if parent:
-            if not domain:
-                domain = parent.domain
-            if not target:
-                target = parent.target
-            if not source:
-                source = parent.source
-        elif domain is None:
-            domain = DEFAULT_DOMAIN
-
-        self.parent = parent
-        self.domain = domain
-        self.target = target
-        self.source = source
+import zope.deprecation
+zope.deprecation.moved('zope.tal.translationcontext', '2.12')

Modified: Zope/trunk/lib/python/TAL/XMLParser.py
===================================================================
--- Zope/trunk/lib/python/TAL/XMLParser.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/XMLParser.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -13,75 +13,11 @@
 ##############################################################################
 """
 Generic expat-based XML parser base class.
+
+BBB 2005/05/01 -- to be removed after 12 months
 """
+import zope.deprecation
+zope.deprecation.moved('zope.tal.xmlparser', '2.12')
 
 import xml.parsers.expat
-from logging import getLogger
-
-
-LOG = getLogger('TAL')
-
 XMLParseError = xml.parsers.expat.ExpatError
-
-
-class XMLParser:
-
-    ordered_attributes = 0
-
-    handler_names = [
-        "StartElementHandler",
-        "EndElementHandler",
-        "ProcessingInstructionHandler",
-        "CharacterDataHandler",
-        "UnparsedEntityDeclHandler",
-        "NotationDeclHandler",
-        "StartNamespaceDeclHandler",
-        "EndNamespaceDeclHandler",
-        "CommentHandler",
-        "StartCdataSectionHandler",
-        "EndCdataSectionHandler",
-        "DefaultHandler",
-        "DefaultHandlerExpand",
-        "NotStandaloneHandler",
-        "ExternalEntityRefHandler",
-        "XmlDeclHandler",
-        "StartDoctypeDeclHandler",
-        "EndDoctypeDeclHandler",
-        "ElementDeclHandler",
-        "AttlistDeclHandler"
-        ]
-
-    def __init__(self, encoding=None):
-        self.parser = p = self.createParser()
-        if self.ordered_attributes:
-            try:
-                self.parser.ordered_attributes = self.ordered_attributes
-            except AttributeError:
-                LOG.info("Can't set ordered_attributes")
-                self.ordered_attributes = 0
-        for name in self.handler_names:
-            method = getattr(self, name, None)
-            if method is not None:
-                try:
-                    setattr(p, name, method)
-                except AttributeError:
-                    LOG.error("Can't set expat handler %s" % name)
-
-    def createParser(self, encoding=None):
-        return xml.parsers.expat.ParserCreate(encoding, ' ')
-
-    def parseFile(self, filename):
-        self.parseStream(open(filename))
-
-    def parseString(self, s):
-        self.parser.Parse(s, 1)
-
-    def parseURL(self, url):
-        import urllib
-        self.parseStream(urllib.urlopen(url))
-
-    def parseStream(self, stream):
-        self.parser.ParseFile(stream)
-
-    def parseFragment(self, s, end=0):
-        self.parser.Parse(s, end)

Modified: Zope/trunk/lib/python/TAL/driver.py
===================================================================
--- Zope/trunk/lib/python/TAL/driver.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/driver.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -34,165 +34,11 @@
         Leave TAL/METAL attributes in output
     -i
         Leave I18N substitution strings un-interpolated.
+
+BBB 2005/05/01 -- to be removed after 12 months
 """
+import zope.deprecation
+zope.deprecation.moved('zope.tal.driver', '2.12')
 
-import os
-import sys
-
-import getopt
-
 if __name__ == "__main__":
-    import setpath                      # Local hack to tweak sys.path etc.
-
-# Import local classes
-import TALDefs
-from DummyEngine import DummyEngine
-from DummyEngine import DummyTranslationService
-
-FILE = "tests/input/test01.xml"
-
-class TestTranslations(DummyTranslationService):
-    def translate(self, domain, msgid, mapping=None, context=None,
-                  target_language=None, default=None):
-        if msgid == 'timefmt':
-            return '%(minutes)s minutes after %(hours)s %(ampm)s' % mapping
-        elif msgid == 'jobnum':
-            return '%(jobnum)s is the JOB NUMBER' % mapping
-        elif msgid == 'verify':
-            s = 'Your contact email address is recorded as %(email)s'
-            return s % mapping
-        elif msgid == 'mailto:${request/submitter}':
-            return 'mailto:bperson at dom.ain'
-        elif msgid == 'origin':
-            return '%(name)s was born in %(country)s' % mapping
-        return DummyTranslationService.translate(self, domain, msgid,
-                                                 mapping, context,
-                                                 target_language,
-                                                 default=default)
-
-class TestEngine(DummyEngine):
-    def __init__(self, macros=None):
-        DummyEngine.__init__(self, macros)
-        self.translationService = TestTranslations()
-
-    def evaluatePathOrVar(self, expr):
-        if expr == 'here/currentTime':
-            return {'hours'  : 6,
-                    'minutes': 59,
-                    'ampm'   : 'PM',
-                    }
-        elif expr == 'context/@@object_name':
-            return '7'
-        elif expr == 'request/submitter':
-            return 'aperson at dom.ain'
-        return DummyEngine.evaluatePathOrVar(self, expr)
-
-
-# This is a disgusting hack so that we can use engines that actually know
-# something about certain object paths.  TimeEngine knows about
-# here/currentTime.
-ENGINES = {'test23.html': TestEngine,
-           'test24.html': TestEngine,
-           'test26.html': TestEngine,
-           'test27.html': TestEngine,
-           'test28.html': TestEngine,
-           'test29.html': TestEngine,
-           'test30.html': TestEngine,
-           'test31.html': TestEngine,
-           'test32.html': TestEngine,
-           }
-
-def usage(code, msg=''):
-    # Python 2.1 required
-    print >> sys.stderr, __doc__
-    if msg:
-        print >> sys.stderr, msg
-    sys.exit(code)
-
-def main():
-    macros = 0
-    mode = None
-    showcode = 0
-    showtal = -1
-    strictinsert = 1
-    i18nInterpolate = 1
-    try:
-        opts, args = getopt.getopt(sys.argv[1:], "hHxlmsti",
-                                   ['help', 'html', 'xml'])
-    except getopt.error, msg:
-        usage(2, msg)
-    for opt, arg in opts:
-        if opt in ('-h', '--help'):
-            usage(0)
-        if opt in ('-H', '--html'):
-            if mode == 'xml':
-                usage(1, '--html and --xml are mutually exclusive')
-            mode = "html"
-        if opt == '-l':
-            strictinsert = 0
-        if opt == '-m':
-            macros = 1
-        if opt == '-n':
-            versionTest = 0
-        if opt in ('-x', '--xml'):
-            if mode == 'html':
-                usage(1, '--html and --xml are mutually exclusive')
-            mode = "xml"
-        if opt == '-s':
-            showcode = 1
-        if opt == '-t':
-            showtal = 1
-        if opt == '-i':
-            i18nInterpolate = 0
-    if args:
-        file = args[0]
-    else:
-        file = FILE
-    it = compilefile(file, mode)
-    if showcode:
-        showit(it)
-    else:
-        # See if we need a special engine for this test
-        engine = None
-        engineClass = ENGINES.get(os.path.basename(file))
-        if engineClass is not None:
-            engine = engineClass(macros)
-        interpretit(it, engine=engine,
-                    tal=(not macros), showtal=showtal,
-                    strictinsert=strictinsert,
-                    i18nInterpolate=i18nInterpolate)
-
-def interpretit(it, engine=None, stream=None, tal=1, showtal=-1,
-                strictinsert=1, i18nInterpolate=1):
-    from TALInterpreter import TALInterpreter
-    program, macros = it
-    assert TALDefs.isCurrentVersion(program)
-    if engine is None:
-        engine = DummyEngine(macros)
-    TALInterpreter(program, macros, engine, stream, wrap=0,
-                   tal=tal, showtal=showtal, strictinsert=strictinsert,
-                   i18nInterpolate=i18nInterpolate)()
-
-def compilefile(file, mode=None):
-    assert mode in ("html", "xml", None)
-    if mode is None:
-        ext = os.path.splitext(file)[1]
-        if ext.lower() in (".html", ".htm"):
-            mode = "html"
-        else:
-            mode = "xml"
-    if mode == "html":
-        from HTMLTALParser import HTMLTALParser
-        p = HTMLTALParser()
-    else:
-        from TALParser import TALParser
-        p = TALParser()
-    p.parseFile(file)
-    return p.getCode()
-
-def showit(it):
-    from pprint import pprint
-    pprint(it)
-
-if __name__ == "__main__":
     main()

Modified: Zope/trunk/lib/python/TAL/ndiff.py
===================================================================
--- Zope/trunk/lib/python/TAL/ndiff.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/ndiff.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,625 +1,8 @@
 #! /usr/bin/env python
+# BBB 2005/05/01 -- to be removed after 12 months
+import zope.deprecation
+zope.deprecation.moved('zope.tal.ndiff', '2.12')
 
-# Module ndiff version 1.6.0
-# Released to the public domain 08-Dec-2000,
-# by Tim Peters (tim.one at home.com).
-
-# Provided as-is; use at your own risk; no warranty; no promises; enjoy!
-
-"""ndiff [-q] file1 file2
-    or
-ndiff (-r1 | -r2) < ndiff_output > file1_or_file2
-
-Print a human-friendly file difference report to stdout.  Both inter-
-and intra-line differences are noted.  In the second form, recreate file1
-(-r1) or file2 (-r2) on stdout, from an ndiff report on stdin.
-
-In the first form, if -q ("quiet") is not specified, the first two lines
-of output are
-
--: file1
-+: file2
-
-Each remaining line begins with a two-letter code:
-
-    "- "    line unique to file1
-    "+ "    line unique to file2
-    "  "    line common to both files
-    "? "    line not present in either input file
-
-Lines beginning with "? " attempt to guide the eye to intraline
-differences, and were not present in either input file.  These lines can be
-confusing if the source files contain tab characters.
-
-The first file can be recovered by retaining only lines that begin with
-"  " or "- ", and deleting those 2-character prefixes; use ndiff with -r1.
-
-The second file can be recovered similarly, but by retaining only "  " and
-"+ " lines; use ndiff with -r2; or, on Unix, the second file can be
-recovered by piping the output through
-
-    sed -n '/^[+ ] /s/^..//p'
-
-See module comments for details and programmatic interface.
-"""
-
-__version__ = 1, 5, 0
-
-# SequenceMatcher tries to compute a "human-friendly diff" between
-# two sequences (chiefly picturing a file as a sequence of lines,
-# and a line as a sequence of characters, here).  Unlike e.g. UNIX(tm)
-# diff, the fundamental notion is the longest *contiguous* & junk-free
-# matching subsequence.  That's what catches peoples' eyes.  The
-# Windows(tm) windiff has another interesting notion, pairing up elements
-# that appear uniquely in each sequence.  That, and the method here,
-# appear to yield more intuitive difference reports than does diff.  This
-# method appears to be the least vulnerable to synching up on blocks
-# of "junk lines", though (like blank lines in ordinary text files,
-# or maybe "<P>" lines in HTML files).  That may be because this is
-# the only method of the 3 that has a *concept* of "junk" <wink>.
-#
-# Note that ndiff makes no claim to produce a *minimal* diff.  To the
-# contrary, minimal diffs are often counter-intuitive, because they
-# synch up anywhere possible, sometimes accidental matches 100 pages
-# apart.  Restricting synch points to contiguous matches preserves some
-# notion of locality, at the occasional cost of producing a longer diff.
-#
-# With respect to junk, an earlier version of ndiff simply refused to
-# *start* a match with a junk element.  The result was cases like this:
-#     before: private Thread currentThread;
-#     after:  private volatile Thread currentThread;
-# If you consider whitespace to be junk, the longest contiguous match
-# not starting with junk is "e Thread currentThread".  So ndiff reported
-# that "e volatil" was inserted between the 't' and the 'e' in "private".
-# While an accurate view, to people that's absurd.  The current version
-# looks for matching blocks that are entirely junk-free, then extends the
-# longest one of those as far as possible but only with matching junk.
-# So now "currentThread" is matched, then extended to suck up the
-# preceding blank; then "private" is matched, and extended to suck up the
-# following blank; then "Thread" is matched; and finally ndiff reports
-# that "volatile " was inserted before "Thread".  The only quibble
-# remaining is that perhaps it was really the case that " volatile"
-# was inserted after "private".  I can live with that <wink>.
-#
-# NOTE on junk:  the module-level names
-#    IS_LINE_JUNK
-#    IS_CHARACTER_JUNK
-# can be set to any functions you like.  The first one should accept
-# a single string argument, and return true iff the string is junk.
-# The default is whether the regexp r"\s*#?\s*$" matches (i.e., a
-# line without visible characters, except for at most one splat).
-# The second should accept a string of length 1 etc.  The default is
-# whether the character is a blank or tab (note: bad idea to include
-# newline in this!).
-#
-# After setting those, you can call fcompare(f1name, f2name) with the
-# names of the files you want to compare.  The difference report
-# is sent to stdout.  Or you can call main(args), passing what would
-# have been in sys.argv[1:] had the cmd-line form been used.
-
-TRACE = 0
-
-# define what "junk" means
-import re
-
-def IS_LINE_JUNK(line, pat=re.compile(r"\s*#?\s*$").match):
-    return pat(line) is not None
-
-def IS_CHARACTER_JUNK(ch, ws=" \t"):
-    return ch in ws
-
-del re
-
-class SequenceMatcher:
-    def __init__(self, isjunk=None, a='', b=''):
-        # Members:
-        # a
-        #      first sequence
-        # b
-        #      second sequence; differences are computed as "what do
-        #      we need to do to 'a' to change it into 'b'?"
-        # b2j
-        #      for x in b, b2j[x] is a list of the indices (into b)
-        #      at which x appears; junk elements do not appear
-        # b2jhas
-        #      b2j.has_key
-        # fullbcount
-        #      for x in b, fullbcount[x] == the number of times x
-        #      appears in b; only materialized if really needed (used
-        #      only for computing quick_ratio())
-        # matching_blocks
-        #      a list of (i, j, k) triples, where a[i:i+k] == b[j:j+k];
-        #      ascending & non-overlapping in i and in j; terminated by
-        #      a dummy (len(a), len(b), 0) sentinel
-        # opcodes
-        #      a list of (tag, i1, i2, j1, j2) tuples, where tag is
-        #      one of
-        #          'replace'   a[i1:i2] should be replaced by b[j1:j2]
-        #          'delete'    a[i1:i2] should be deleted
-        #          'insert'    b[j1:j2] should be inserted
-        #          'equal'     a[i1:i2] == b[j1:j2]
-        # isjunk
-        #      a user-supplied function taking a sequence element and
-        #      returning true iff the element is "junk" -- this has
-        #      subtle but helpful effects on the algorithm, which I'll
-        #      get around to writing up someday <0.9 wink>.
-        #      DON'T USE!  Only __chain_b uses this.  Use isbjunk.
-        # isbjunk
-        #      for x in b, isbjunk(x) == isjunk(x) but much faster;
-        #      it's really the has_key method of a hidden dict.
-        #      DOES NOT WORK for x in a!
-
-        self.isjunk = isjunk
-        self.a = self.b = None
-        self.set_seqs(a, b)
-
-    def set_seqs(self, a, b):
-        self.set_seq1(a)
-        self.set_seq2(b)
-
-    def set_seq1(self, a):
-        if a is self.a:
-            return
-        self.a = a
-        self.matching_blocks = self.opcodes = None
-
-    def set_seq2(self, b):
-        if b is self.b:
-            return
-        self.b = b
-        self.matching_blocks = self.opcodes = None
-        self.fullbcount = None
-        self.__chain_b()
-
-    # For each element x in b, set b2j[x] to a list of the indices in
-    # b where x appears; the indices are in increasing order; note that
-    # the number of times x appears in b is len(b2j[x]) ...
-    # when self.isjunk is defined, junk elements don't show up in this
-    # map at all, which stops the central find_longest_match method
-    # from starting any matching block at a junk element ...
-    # also creates the fast isbjunk function ...
-    # note that this is only called when b changes; so for cross-product
-    # kinds of matches, it's best to call set_seq2 once, then set_seq1
-    # repeatedly
-
-    def __chain_b(self):
-        # Because isjunk is a user-defined (not C) function, and we test
-        # for junk a LOT, it's important to minimize the number of calls.
-        # Before the tricks described here, __chain_b was by far the most
-        # time-consuming routine in the whole module!  If anyone sees
-        # Jim Roskind, thank him again for profile.py -- I never would
-        # have guessed that.
-        # The first trick is to build b2j ignoring the possibility
-        # of junk.  I.e., we don't call isjunk at all yet.  Throwing
-        # out the junk later is much cheaper than building b2j "right"
-        # from the start.
-        b = self.b
-        self.b2j = b2j = {}
-        self.b2jhas = b2jhas = b2j.has_key
-        for i in xrange(len(b)):
-            elt = b[i]
-            if b2jhas(elt):
-                b2j[elt].append(i)
-            else:
-                b2j[elt] = [i]
-
-        # Now b2j.keys() contains elements uniquely, and especially when
-        # the sequence is a string, that's usually a good deal smaller
-        # than len(string).  The difference is the number of isjunk calls
-        # saved.
-        isjunk, junkdict = self.isjunk, {}
-        if isjunk:
-            for elt in b2j.keys():
-                if isjunk(elt):
-                    junkdict[elt] = 1   # value irrelevant; it's a set
-                    del b2j[elt]
-
-        # Now for x in b, isjunk(x) == junkdict.has_key(x), but the
-        # latter is much faster.  Note too that while there may be a
-        # lot of junk in the sequence, the number of *unique* junk
-        # elements is probably small.  So the memory burden of keeping
-        # this dict alive is likely trivial compared to the size of b2j.
-        self.isbjunk = junkdict.has_key
-
-    def find_longest_match(self, alo, ahi, blo, bhi):
-        """Find longest matching block in a[alo:ahi] and b[blo:bhi].
-
-        If isjunk is not defined:
-
-        Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
-            alo <= i <= i+k <= ahi
-            blo <= j <= j+k <= bhi
-        and for all (i',j',k') meeting those conditions,
-            k >= k'
-            i <= i'
-            and if i == i', j <= j'
-        In other words, of all maximal matching blocks, return one
-        that starts earliest in a, and of all those maximal matching
-        blocks that start earliest in a, return the one that starts
-        earliest in b.
-
-        If isjunk is defined, first the longest matching block is
-        determined as above, but with the additional restriction that
-        no junk element appears in the block.  Then that block is
-        extended as far as possible by matching (only) junk elements on
-        both sides.  So the resulting block never matches on junk except
-        as identical junk happens to be adjacent to an "interesting"
-        match.
-
-        If no blocks match, return (alo, blo, 0).
-        """
-
-        # CAUTION:  stripping common prefix or suffix would be incorrect.
-        # E.g.,
-        #    ab
-        #    acab
-        # Longest matching block is "ab", but if common prefix is
-        # stripped, it's "a" (tied with "b").  UNIX(tm) diff does so
-        # strip, so ends up claiming that ab is changed to acab by
-        # inserting "ca" in the middle.  That's minimal but unintuitive:
-        # "it's obvious" that someone inserted "ac" at the front.
-        # Windiff ends up at the same place as diff, but by pairing up
-        # the unique 'b's and then matching the first two 'a's.
-
-        a, b, b2j, isbjunk = self.a, self.b, self.b2j, self.isbjunk
-        besti, bestj, bestsize = alo, blo, 0
-        # find longest junk-free match
-        # during an iteration of the loop, j2len[j] = length of longest
-        # junk-free match ending with a[i-1] and b[j]
-        j2len = {}
-        nothing = []
-        for i in xrange(alo, ahi):
-            # look at all instances of a[i] in b; note that because
-            # b2j has no junk keys, the loop is skipped if a[i] is junk
-            j2lenget = j2len.get
-            newj2len = {}
-            for j in b2j.get(a[i], nothing):
-                # a[i] matches b[j]
-                if j < blo:
-                    continue
-                if j >= bhi:
-                    break
-                k = newj2len[j] = j2lenget(j-1, 0) + 1
-                if k > bestsize:
-                    besti, bestj, bestsize = i-k+1, j-k+1, k
-            j2len = newj2len
-
-        # Now that we have a wholly interesting match (albeit possibly
-        # empty!), we may as well suck up the matching junk on each
-        # side of it too.  Can't think of a good reason not to, and it
-        # saves post-processing the (possibly considerable) expense of
-        # figuring out what to do with it.  In the case of an empty
-        # interesting match, this is clearly the right thing to do,
-        # because no other kind of match is possible in the regions.
-        while besti > alo and bestj > blo and \
-              isbjunk(b[bestj-1]) and \
-              a[besti-1] == b[bestj-1]:
-            besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
-        while besti+bestsize < ahi and bestj+bestsize < bhi and \
-              isbjunk(b[bestj+bestsize]) and \
-              a[besti+bestsize] == b[bestj+bestsize]:
-            bestsize = bestsize + 1
-
-        if TRACE:
-            print "get_matching_blocks", alo, ahi, blo, bhi
-            print "    returns", besti, bestj, bestsize
-        return besti, bestj, bestsize
-
-    def get_matching_blocks(self):
-        if self.matching_blocks is not None:
-            return self.matching_blocks
-        self.matching_blocks = []
-        la, lb = len(self.a), len(self.b)
-        self.__helper(0, la, 0, lb, self.matching_blocks)
-        self.matching_blocks.append( (la, lb, 0) )
-        if TRACE:
-            print '*** matching blocks', self.matching_blocks
-        return self.matching_blocks
-
-    # builds list of matching blocks covering a[alo:ahi] and
-    # b[blo:bhi], appending them in increasing order to answer
-
-    def __helper(self, alo, ahi, blo, bhi, answer):
-        i, j, k = x = self.find_longest_match(alo, ahi, blo, bhi)
-        # a[alo:i] vs b[blo:j] unknown
-        # a[i:i+k] same as b[j:j+k]
-        # a[i+k:ahi] vs b[j+k:bhi] unknown
-        if k:
-            if alo < i and blo < j:
-                self.__helper(alo, i, blo, j, answer)
-            answer.append(x)
-            if i+k < ahi and j+k < bhi:
-                self.__helper(i+k, ahi, j+k, bhi, answer)
-
-    def ratio(self):
-        """Return a measure of the sequences' similarity (float in [0,1]).
-
-        Where T is the total number of elements in both sequences, and
-        M is the number of matches, this is 2*M / T.
-        Note that this is 1 if the sequences are identical, and 0 if
-        they have nothing in common.
-        """
-
-        matches = reduce(lambda sum, triple: sum + triple[-1],
-                         self.get_matching_blocks(), 0)
-        return 2.0 * matches / (len(self.a) + len(self.b))
-
-    def quick_ratio(self):
-        """Return an upper bound on ratio() relatively quickly."""
-        # viewing a and b as multisets, set matches to the cardinality
-        # of their intersection; this counts the number of matches
-        # without regard to order, so is clearly an upper bound
-        if self.fullbcount is None:
-            self.fullbcount = fullbcount = {}
-            for elt in self.b:
-                fullbcount[elt] = fullbcount.get(elt, 0) + 1
-        fullbcount = self.fullbcount
-        # avail[x] is the number of times x appears in 'b' less the
-        # number of times we've seen it in 'a' so far ... kinda
-        avail = {}
-        availhas, matches = avail.has_key, 0
-        for elt in self.a:
-            if availhas(elt):
-                numb = avail[elt]
-            else:
-                numb = fullbcount.get(elt, 0)
-            avail[elt] = numb - 1
-            if numb > 0:
-                matches = matches + 1
-        return 2.0 * matches / (len(self.a) + len(self.b))
-
-    def real_quick_ratio(self):
-        """Return an upper bound on ratio() very quickly"""
-        la, lb = len(self.a), len(self.b)
-        # can't have more matches than the number of elements in the
-        # shorter sequence
-        return 2.0 * min(la, lb) / (la + lb)
-
-    def get_opcodes(self):
-        if self.opcodes is not None:
-            return self.opcodes
-        i = j = 0
-        self.opcodes = answer = []
-        for ai, bj, size in self.get_matching_blocks():
-            # invariant:  we've pumped out correct diffs to change
-            # a[:i] into b[:j], and the next matching block is
-            # a[ai:ai+size] == b[bj:bj+size].  So we need to pump
-            # out a diff to change a[i:ai] into b[j:bj], pump out
-            # the matching block, and move (i,j) beyond the match
-            tag = ''
-            if i < ai and j < bj:
-                tag = 'replace'
-            elif i < ai:
-                tag = 'delete'
-            elif j < bj:
-                tag = 'insert'
-            if tag:
-                answer.append( (tag, i, ai, j, bj) )
-            i, j = ai+size, bj+size
-            # the list of matching blocks is terminated by a
-            # sentinel with size 0
-            if size:
-                answer.append( ('equal', ai, i, bj, j) )
-        return answer
-
-# meant for dumping lines
-def dump(tag, x, lo, hi):
-    for i in xrange(lo, hi):
-        print tag, x[i],
-
-def plain_replace(a, alo, ahi, b, blo, bhi):
-    assert alo < ahi and blo < bhi
-    # dump the shorter block first -- reduces the burden on short-term
-    # memory if the blocks are of very different sizes
-    if bhi - blo < ahi - alo:
-        dump('+', b, blo, bhi)
-        dump('-', a, alo, ahi)
-    else:
-        dump('-', a, alo, ahi)
-        dump('+', b, blo, bhi)
-
-# When replacing one block of lines with another, this guy searches
-# the blocks for *similar* lines; the best-matching pair (if any) is
-# used as a synch point, and intraline difference marking is done on
-# the similar pair.  Lots of work, but often worth it.
-
-def fancy_replace(a, alo, ahi, b, blo, bhi):
-    if TRACE:
-        print '*** fancy_replace', alo, ahi, blo, bhi
-        dump('>', a, alo, ahi)
-        dump('<', b, blo, bhi)
-
-    # don't synch up unless the lines have a similarity score of at
-    # least cutoff; best_ratio tracks the best score seen so far
-    best_ratio, cutoff = 0.74, 0.75
-    cruncher = SequenceMatcher(IS_CHARACTER_JUNK)
-    eqi, eqj = None, None   # 1st indices of equal lines (if any)
-
-    # search for the pair that matches best without being identical
-    # (identical lines must be junk lines, & we don't want to synch up
-    # on junk -- unless we have to)
-    for j in xrange(blo, bhi):
-        bj = b[j]
-        cruncher.set_seq2(bj)
-        for i in xrange(alo, ahi):
-            ai = a[i]
-            if ai == bj:
-                if eqi is None:
-                    eqi, eqj = i, j
-                continue
-            cruncher.set_seq1(ai)
-            # computing similarity is expensive, so use the quick
-            # upper bounds first -- have seen this speed up messy
-            # compares by a factor of 3.
-            # note that ratio() is only expensive to compute the first
-            # time it's called on a sequence pair; the expensive part
-            # of the computation is cached by cruncher
-            if cruncher.real_quick_ratio() > best_ratio and \
-                  cruncher.quick_ratio() > best_ratio and \
-                  cruncher.ratio() > best_ratio:
-                best_ratio, best_i, best_j = cruncher.ratio(), i, j
-    if best_ratio < cutoff:
-        # no non-identical "pretty close" pair
-        if eqi is None:
-            # no identical pair either -- treat it as a straight replace
-            plain_replace(a, alo, ahi, b, blo, bhi)
-            return
-        # no close pair, but an identical pair -- synch up on that
-        best_i, best_j, best_ratio = eqi, eqj, 1.0
-    else:
-        # there's a close pair, so forget the identical pair (if any)
-        eqi = None
-
-    # a[best_i] very similar to b[best_j]; eqi is None iff they're not
-    # identical
-    if TRACE:
-        print '*** best_ratio', best_ratio, best_i, best_j
-        dump('>', a, best_i, best_i+1)
-        dump('<', b, best_j, best_j+1)
-
-    # pump out diffs from before the synch point
-    fancy_helper(a, alo, best_i, b, blo, best_j)
-
-    # do intraline marking on the synch pair
-    aelt, belt = a[best_i], b[best_j]
-    if eqi is None:
-        # pump out a '-', '?', '+', '?' quad for the synched lines
-        atags = btags = ""
-        cruncher.set_seqs(aelt, belt)
-        for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
-            la, lb = ai2 - ai1, bj2 - bj1
-            if tag == 'replace':
-                atags = atags + '^' * la
-                btags = btags + '^' * lb
-            elif tag == 'delete':
-                atags = atags + '-' * la
-            elif tag == 'insert':
-                btags = btags + '+' * lb
-            elif tag == 'equal':
-                atags = atags + ' ' * la
-                btags = btags + ' ' * lb
-            else:
-                raise ValueError, 'unknown tag ' + `tag`
-        printq(aelt, belt, atags, btags)
-    else:
-        # the synch pair is identical
-        print ' ', aelt,
-
-    # pump out diffs from after the synch point
-    fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
-
-def fancy_helper(a, alo, ahi, b, blo, bhi):
-    if alo < ahi:
-        if blo < bhi:
-            fancy_replace(a, alo, ahi, b, blo, bhi)
-        else:
-            dump('-', a, alo, ahi)
-    elif blo < bhi:
-        dump('+', b, blo, bhi)
-
-# Crap to deal with leading tabs in "?" output.  Can hurt, but will
-# probably help most of the time.
-
-def printq(aline, bline, atags, btags):
-    common = min(count_leading(aline, "\t"),
-                 count_leading(bline, "\t"))
-    common = min(common, count_leading(atags[:common], " "))
-    print "-", aline,
-    if count_leading(atags, " ") < len(atags):
-        print "?", "\t" * common + atags[common:]
-    print "+", bline,
-    if count_leading(btags, " ") < len(btags):
-        print "?", "\t" * common + btags[common:]
-
-def count_leading(line, ch):
-    i, n = 0, len(line)
-    while i < n and line[i] == ch:
-        i = i + 1
-    return i
-
-def fail(msg):
-    import sys
-    out = sys.stderr.write
-    out(msg + "\n\n")
-    out(__doc__)
-    return 0
-
-# open a file & return the file object; gripe and return 0 if it
-# couldn't be opened
-def fopen(fname):
-    try:
-        return open(fname, 'r')
-    except IOError, detail:
-        return fail("couldn't open " + fname + ": " + str(detail))
-
-# open two files & spray the diff to stdout; return false iff a problem
-def fcompare(f1name, f2name):
-    f1 = fopen(f1name)
-    f2 = fopen(f2name)
-    if not f1 or not f2:
-        return 0
-
-    a = f1.readlines(); f1.close()
-    b = f2.readlines(); f2.close()
-
-    cruncher = SequenceMatcher(IS_LINE_JUNK, a, b)
-    for tag, alo, ahi, blo, bhi in cruncher.get_opcodes():
-        if tag == 'replace':
-            fancy_replace(a, alo, ahi, b, blo, bhi)
-        elif tag == 'delete':
-            dump('-', a, alo, ahi)
-        elif tag == 'insert':
-            dump('+', b, blo, bhi)
-        elif tag == 'equal':
-            dump(' ', a, alo, ahi)
-        else:
-            raise ValueError, 'unknown tag ' + `tag`
-
-    return 1
-
-# crack args (sys.argv[1:] is normal) & compare;
-# return false iff a problem
-
-def main(args):
-    import getopt
-    try:
-        opts, args = getopt.getopt(args, "qr:")
-    except getopt.error, detail:
-        return fail(str(detail))
-    noisy = 1
-    qseen = rseen = 0
-    for opt, val in opts:
-        if opt == "-q":
-            qseen = 1
-            noisy = 0
-        elif opt == "-r":
-            rseen = 1
-            whichfile = val
-    if qseen and rseen:
-        return fail("can't specify both -q and -r")
-    if rseen:
-        if args:
-            return fail("no args allowed with -r option")
-        if whichfile in "12":
-            restore(whichfile)
-            return 1
-        return fail("-r value must be 1 or 2")
-    if len(args) != 2:
-        return fail("need 2 filename args")
-    f1name, f2name = args
-    if noisy:
-        print '-:', f1name
-        print '+:', f2name
-    return fcompare(f1name, f2name)
-
-def restore(which):
-    import sys
-    tag = {"1": "- ", "2": "+ "}[which]
-    prefixes = ("  ", tag)
-    for line in sys.stdin.readlines():
-        if line[:2] in prefixes:
-            print line[2:],
-
 if __name__ == '__main__':
     import sys
     args = sys.argv[1:]

Modified: Zope/trunk/lib/python/TAL/runtest.py
===================================================================
--- Zope/trunk/lib/python/TAL/runtest.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/runtest.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -14,138 +14,11 @@
 ##############################################################################
 """
 Driver program to run METAL and TAL regression tests.
+
+BBB 2005/05/01 -- to be removed after 12 months
 """
+import zope.deprecation
+zope.deprecation.moved('zope.tal.runtest', '2.12')
 
-import sys
-import os
-from cStringIO import StringIO
-import glob
-import traceback
-
 if __name__ == "__main__":
-    import setpath                      # Local hack to tweak sys.path etc.
-
-import driver
-import tests.utils
-
-def showdiff(a, b):
-    import ndiff
-    cruncher = ndiff.SequenceMatcher(ndiff.IS_LINE_JUNK, a, b)
-    for tag, alo, ahi, blo, bhi in cruncher.get_opcodes():
-        if tag == "equal":
-            continue
-        print nicerange(alo, ahi) + tag[0] + nicerange(blo, bhi)
-        ndiff.dump('<', a, alo, ahi)
-        if a and b:
-            print '---'
-        ndiff.dump('>', b, blo, bhi)
-
-def nicerange(lo, hi):
-    if hi <= lo+1:
-        return str(lo+1)
-    else:
-        return "%d,%d" % (lo+1, hi)
-
-def main():
-    opts = []
-    args = sys.argv[1:]
-    quiet = 0
-    unittesting = 0
-    if args and args[0] == "-q":
-        quiet = 1
-        del args[0]
-    if args and args[0] == "-Q":
-        unittesting = 1
-        del args[0]
-    while args and args[0].startswith('-'):
-        opts.append(args[0])
-        del args[0]
-    if not args:
-        prefix = os.path.join("tests", "input", "test*.")
-        if tests.utils.skipxml:
-            xmlargs = []
-        else:
-            xmlargs = glob.glob(prefix + "xml")
-            xmlargs.sort()
-        htmlargs = glob.glob(prefix + "html")
-        htmlargs.sort()
-        args = xmlargs + htmlargs
-        if not args:
-             sys.stderr.write("No tests found -- please supply filenames\n")
-             sys.exit(1)
-    errors = 0
-    for arg in args:
-        locopts = []
-        if arg.find("metal") >= 0 and "-m" not in opts:
-            locopts.append("-m")
-        if not unittesting:
-            print arg,
-            sys.stdout.flush()
-        if tests.utils.skipxml and arg.endswith(".xml"):
-            print "SKIPPED (XML parser not available)"
-            continue
-        save = sys.stdout, sys.argv
-        try:
-            try:
-                sys.stdout = stdout = StringIO()
-                sys.argv = [""] + opts + locopts + [arg]
-                driver.main()
-            finally:
-                sys.stdout, sys.argv = save
-        except SystemExit:
-            raise
-        except:
-            errors = 1
-            if quiet:
-                print sys.exc_type
-                sys.stdout.flush()
-            else:
-                if unittesting:
-                    print
-                else:
-                    print "Failed:"
-                    sys.stdout.flush()
-                traceback.print_exc()
-            continue
-        head, tail = os.path.split(arg)
-        outfile = os.path.join(
-            head.replace("input", "output"),
-            tail)
-        try:
-            f = open(outfile)
-        except IOError:
-            expected = None
-            print "(missing file %s)" % outfile,
-        else:
-            expected = f.readlines()
-            f.close()
-        stdout.seek(0)
-        if hasattr(stdout, "readlines"):
-            actual = stdout.readlines()
-        else:
-            actual = readlines(stdout)
-        if actual == expected:
-            if not unittesting:
-                print "OK"
-        else:
-            if unittesting:
-                print
-            else:
-                print "not OK"
-            errors = 1
-            if not quiet and expected is not None:
-                showdiff(expected, actual)
-    if errors:
-        sys.exit(1)
-
-def readlines(f):
-    L = []
-    while 1:
-        line = f.readline()
-        if not line:
-            break
-        L.append(line)
-    return L
-
-if __name__ == "__main__":
     main()

Modified: Zope/trunk/lib/python/TAL/talgettext.py
===================================================================
--- Zope/trunk/lib/python/TAL/talgettext.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/talgettext.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,318 +1,6 @@
+# BBB 2005/05/01 -- to be removed after 12 months
+import zope.deprecation
+zope.deprecation.moved('zope.tal.talgettext', '2.12')
 
-
-
-#!/usr/bin/env python
-##############################################################################
-#
-# 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.
-#
-##############################################################################
-
-"""Program to extract internationalization markup from Page Templates.
-
-Once you have marked up a Page Template file with i18n: namespace tags, use
-this program to extract GNU gettext .po file entries.
-
-Usage: talgettext.py [options] files
-Options:
-    -h / --help
-        Print this message and exit.
-    -o / --output <file>
-        Output the translation .po file to <file>.
-    -u / --update <file>
-        Update the existing translation <file> with any new translation strings
-        found.
-"""
-
-import sys
-import time
-import getopt
-import traceback
-
-from TAL.HTMLTALParser import HTMLTALParser
-from TAL.TALInterpreter import TALInterpreter
-from TAL.DummyEngine import DummyEngine
-from ITALES import ITALESEngine
-from TAL.TALDefs import TALESError
-
-__version__ = '$Revision: 1.1.2.1 $'
-
-pot_header = '''\
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR ORGANIZATION
-# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\\n"
-"POT-Creation-Date: %(time)s\\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
-"Last-Translator: FULL NAME <EMAIL at ADDRESS>\\n"
-"Language-Team: LANGUAGE <LL at li.org>\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=CHARSET\\n"
-"Content-Transfer-Encoding: ENCODING\\n"
-"Generated-By: talgettext.py %(version)s\\n"
-'''
-
-NLSTR = '"\n"'
-
-try:
-    True
-except NameError:
-    True=1
-    False=0
-
-def usage(code, msg=''):
-    # Python 2.1 required
-    print >> sys.stderr, __doc__
-    if msg:
-        print >> sys.stderr, msg
-    sys.exit(code)
-
-
-class POTALInterpreter(TALInterpreter):
-    def translate(self, msgid, default, i18ndict=None, obj=None):
-        # XXX is this right?
-        if i18ndict is None:
-            i18ndict = {}
-        if obj:
-            i18ndict.update(obj)
-        # XXX Mmmh, it seems that sometimes the msgid is None; is that really
-        # possible?
-        if msgid is None:
-            return None
-        # XXX We need to pass in one of context or target_language
-        return self.engine.translate(msgid, self.i18nContext.domain, i18ndict,
-                                     position=self.position, default=default)
-
-
-class POEngine(DummyEngine):
-    __implements__ = ITALESEngine
-
-    def __init__(self, macros=None):
-        self.catalog = {}
-        DummyEngine.__init__(self, macros)
-
-    def evaluate(*args):
-        return '' # who cares
-
-    def evaluatePathOrVar(*args):
-        return '' # who cares
-
-    def evaluateSequence(self, expr):
-        return (0,) # dummy
-
-    def evaluateBoolean(self, expr):
-        return True # dummy
-
-    def translate(self, msgid, domain=None, mapping=None, default=None,
-                  # XXX position is not part of the ITALESEngine
-                  #     interface
-                  position=None):
-
-        if domain not in self.catalog:
-            self.catalog[domain] = {}
-        domain = self.catalog[domain]
-
-        # ---------------------------------------------
-        # only non-empty msgids are added to dictionary
-        # (changed by heinrichbernd - 2004/09/07)
-        # ---------------------------------------------
-        if msgid:
-            if msgid not in domain:
-                domain[msgid] = []
-            domain[msgid].append((self.file, position))
-        return 'x'
-
-
-class UpdatePOEngine(POEngine):
-    """A slightly-less braindead POEngine which supports loading an existing
-    .po file first."""
-
-    def __init__ (self, macros=None, filename=None):
-        POEngine.__init__(self, macros)
-
-        self._filename = filename
-        self._loadFile()
-        self.base = self.catalog
-        self.catalog = {}
-
-    def __add(self, id, s, fuzzy):
-        "Add a non-fuzzy translation to the dictionary."
-        if not fuzzy and str:
-            # check for multi-line values and munge them appropriately
-            if '\n' in s:
-                lines = s.rstrip().split('\n')
-                s = NLSTR.join(lines)
-            self.catalog[id] = s
-
-    def _loadFile(self):
-        # shamelessly cribbed from Python's Tools/i18n/msgfmt.py
-        # 25-Mar-2003 Nathan R. Yergler (nathan at zope.org)
-        # 14-Apr-2003 Hacked by Barry Warsaw (barry at zope.com)
-
-        ID = 1
-        STR = 2
-
-        try:
-            lines = open(self._filename).readlines()
-        except IOError, msg:
-            print >> sys.stderr, msg
-            sys.exit(1)
-
-        section = None
-        fuzzy = False
-
-        # Parse the catalog
-        lno = 0
-        for l in lines:
-            lno += True
-            # If we get a comment line after a msgstr, this is a new entry
-            if l[0] == '#' and section == STR:
-                self.__add(msgid, msgstr, fuzzy)
-                section = None
-                fuzzy = False
-            # Record a fuzzy mark
-            if l[:2] == '#,' and l.find('fuzzy'):
-                fuzzy = True
-            # Skip comments
-            if l[0] == '#':
-                continue
-            # Now we are in a msgid section, output previous section
-            if l.startswith('msgid'):
-                if section == STR:
-                    self.__add(msgid, msgstr, fuzzy)
-                section = ID
-                l = l[5:]
-                msgid = msgstr = ''
-            # Now we are in a msgstr section
-            elif l.startswith('msgstr'):
-                section = STR
-                l = l[6:]
-            # Skip empty lines
-            if not l.strip():
-                continue
-            # XXX: Does this always follow Python escape semantics?
-            l = eval(l)
-            if section == ID:
-                msgid += l
-            elif section == STR:
-                msgstr += '%s\n' % l
-            else:
-                print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \
-                      'before:'
-                print >> sys.stderr, l
-                sys.exit(1)
-        # Add last entry
-        if section == STR:
-            self.__add(msgid, msgstr, fuzzy)
-
-    def evaluate(self, expression):
-        try:
-            return POEngine.evaluate(self, expression)
-        except TALESError:
-            pass
-
-    def evaluatePathOrVar(self, expr):
-        return 'who cares'
-
-    def translate(self, msgid, domain=None, mapping=None, default=None,
-                  position=None):
-        if msgid not in self.base:
-            POEngine.translate(self, msgid, domain, mapping, default, position)
-        return 'x'
-
-
-def main():
-    try:
-        opts, args = getopt.getopt(
-            sys.argv[1:],
-            'ho:u:',
-            ['help', 'output=', 'update='])
-    except getopt.error, msg:
-        usage(1, msg)
-
-    outfile = None
-    engine = None
-    update_mode = False
-    for opt, arg in opts:
-        if opt in ('-h', '--help'):
-            usage(0)
-        elif opt in ('-o', '--output'):
-            outfile = arg
-        elif opt in ('-u', '--update'):
-            update_mode = True
-            if outfile is None:
-                outfile = arg
-            engine = UpdatePOEngine(filename=arg)
-
-    if not args:
-        print 'nothing to do'
-        return
-
-    # We don't care about the rendered output of the .pt file
-    class Devnull:
-        def write(self, s):
-            pass
-
-    # check if we've already instantiated an engine;
-    # if not, use the stupidest one available
-    if not engine:
-        engine = POEngine()
-
-    # process each file specified
-    for filename in args:
-        try:
-            engine.file = filename
-            p = HTMLTALParser()
-            p.parseFile(filename)
-            program, macros = p.getCode()
-            POTALInterpreter(program, macros, engine, stream=Devnull(),
-                             metal=False)()
-        except: # Hee hee, I love bare excepts!
-            print 'There was an error processing', filename
-            traceback.print_exc()
-
-    # Now output the keys in the engine.  Write them to a file if --output or
-    # --update was specified; otherwise use standard out.
-    if (outfile is None):
-        outfile = sys.stdout
-    else:
-        outfile = file(outfile, update_mode and "a" or "w")
-    catalog = {}
-    for domain in engine.catalog.keys():
-        catalog.update(engine.catalog[domain])
-
-    messages = catalog.copy()
-    try:
-        messages.update(engine.base)
-    except AttributeError:
-        pass
-    if '' not in messages:
-        print >> outfile, pot_header % {'time': time.ctime(),
-                                        'version': __version__}
-
-    msgids = catalog.keys()
-    # XXX: You should not sort by msgid, but by filename and position. (SR)
-    msgids.sort()
-    for msgid in msgids:
-        positions = catalog[msgid]
-        for filename, position in positions:
-            outfile.write('#: %s:%s\n' % (filename, position[0]))
-
-        outfile.write('msgid "%s"\n' % msgid)
-        outfile.write('msgstr ""\n')
-        outfile.write('\n')
-
-
 if __name__ == '__main__':
     main()

Modified: Zope/trunk/lib/python/TAL/tests/input/test29.html
===================================================================
--- Zope/trunk/lib/python/TAL/tests/input/test29.html	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/input/test29.html	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,4 +1,5 @@
 <div i18n:translate="">At the tone the time will be
 <span i18n:data="here/currentTime"
       i18n:translate="timefmt"
-      i18n:name="time">2:32 pm</span>... beep!</div>
+      i18n:name="time"
+      tal:omit-tag="">2:32 pm</span>... beep!</div>

Modified: Zope/trunk/lib/python/TAL/tests/input/test36.html
===================================================================
--- Zope/trunk/lib/python/TAL/tests/input/test36.html	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/input/test36.html	2006-05-29 10:34:19 UTC (rev 68333)
@@ -2,5 +2,5 @@
 <span i18n:translate="">
   <span tal:replace="string:<foo>" i18n:name="name1" />
   <span tal:replace="structure string:<bar />" i18n:name="name2" />
-  <span i18n:name="name3"><b>some</b> <i>text</i></span>
+  <span i18n:name="name3" tal:omit-tag=""><b>some</b> <i>text</i></span>
 </span>

Modified: Zope/trunk/lib/python/TAL/tests/output/test29.html
===================================================================
--- Zope/trunk/lib/python/TAL/tests/output/test29.html	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/output/test29.html	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1 +1 @@
-<div>AT THE TONE THE TIME WILL BE 59 MINUTES AFTER 6 PM... BEEP!</div>
+<div>AT THE TONE THE TIME WILL BE 59 minutes after 6 PM... BEEP!</div>

Modified: Zope/trunk/lib/python/TAL/tests/output/test_metal1.html
===================================================================
--- Zope/trunk/lib/python/TAL/tests/output/test_metal1.html	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/output/test_metal1.html	2006-05-29 10:34:19 UTC (rev 68333)
@@ -22,7 +22,7 @@
 
 <span metal:use-macro="OUTER2">
   AAA
-  <xxx metal:fill-slot="OUTERSLOT">
+  <xxx>
   <span>INNER</span>
   </xxx>
   BBB
@@ -48,7 +48,7 @@
 
 <span metal:use-macro="OUTER3">
   AAA
-  <xxx metal:fill-slot="OUTERSLOT">
+  <xxx>
   <span>INNER
     <xxx>INNERSLOT</xxx>
   </span>
@@ -63,7 +63,7 @@
 </span>
 
 <span metal:use-macro="INNER3">INNER
-    <xxx metal:fill-slot="INNERSLOT">INNERSLOT</xxx>
+    <xxx>INNERSLOT</xxx>
   </span>
 
 <span metal:use-macro="INNER3">INNER

Modified: Zope/trunk/lib/python/TAL/tests/output/test_metal7.html
===================================================================
--- Zope/trunk/lib/python/TAL/tests/output/test_metal7.html	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/output/test_metal7.html	2006-05-29 10:34:19 UTC (rev 68333)
@@ -2,5 +2,5 @@
     <x metal:define-slot="title" />
 </html>
 <html metal:use-macro="page" i18n:domain="zope">
-    <x metal:fill-slot="title" />
+    <x />
 </html>

Modified: Zope/trunk/lib/python/TAL/tests/test_files.py
===================================================================
--- Zope/trunk/lib/python/TAL/tests/test_files.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/test_files.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -8,7 +8,7 @@
 from TAL.tests import utils
 import unittest
 
-from TAL import runtest
+from zope.tal import runtest
 
 class FileTestCase(unittest.TestCase):
 

Modified: Zope/trunk/lib/python/TAL/tests/test_htmltalparser.py
===================================================================
--- Zope/trunk/lib/python/TAL/tests/test_htmltalparser.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/test_htmltalparser.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -21,8 +21,18 @@
 import unittest
 
 
+# BBB 2005/05/01 -- to be changed after 12 months
+# ignore deprecation warnings on import for now
+import warnings
+showwarning = warnings.showwarning
+warnings.showwarning = lambda *a, **k: None
+# this old import should remain here until the TAL package is
+# completely removed, so that API backward compatibility is properly
+# tested
 from TAL import HTMLTALParser
 from TAL.TALDefs import TAL_VERSION, TALError, METALError
+# restore warning machinery
+warnings.showwarning = showwarning
 
 
 class TestCaseBase(unittest.TestCase):
@@ -345,9 +355,13 @@
         self._run_check("<p tal:replace='string:foo'>bar</p>", [
              ('setPosition', (1, 0)),
              ('beginScope', {'tal:replace': 'string:foo'}),
-             ('insertText', ('$string:foo$',
-              [('startTag', ('p', [('tal:replace', 'string:foo', 'tal')])),
-               rawtext('bar</p>')])),
+             ('optTag',
+              ('p',
+               '',
+               None,
+               0,
+               [('startTag', ('p', [('tal:replace', 'string:foo', 'tal')]))],
+               [('insertText', ('$string:foo$', [rawtext('bar')]))])),
              ('endScope', ()),
              ])
 
@@ -355,10 +369,13 @@
         self._run_check("<p tal:replace='text string:foo'>bar</p>", [
              ('setPosition', (1, 0)),
              ('beginScope', {'tal:replace': 'text string:foo'}),
-             ('insertText', ('$string:foo$',
-              [('startTag', ('p',
-                             [('tal:replace', 'text string:foo', 'tal')])),
-               rawtext('bar</p>')])),
+             ('optTag',
+              ('p',
+               '',
+               None,
+               0,
+               [('startTag', ('p', [('tal:replace', 'text string:foo', 'tal')]))],
+               [('insertText', ('$string:foo$', [('rawtextOffset', ('bar', 3))]))])),
              ('endScope', ()),
              ])
 
@@ -366,10 +383,14 @@
         self._run_check("<p tal:replace='structure string:<br>'>bar</p>", [
              ('setPosition', (1, 0)),
              ('beginScope', {'tal:replace': 'structure string:<br>'}),
-             ('insertStructure', ('$string:<br>$', {},
-              [('startTag', ('p',
-                [('tal:replace', 'structure string:<br>', 'tal')])),
-               rawtext('bar</p>')])),
+             ('optTag',
+              ('p',
+               '',
+               None,
+               0,
+               [('startTag', ('p', [('tal:replace', 'structure string:<br>', 'tal')]))],
+               [('insertStructure',
+                 ('$string:<br>$', {}, [('rawtextOffset', ('bar', 3))]))])),
              ('endScope', ()),
              ])
 
@@ -383,9 +404,13 @@
                              [('tal:repeat', 'x python:(1,2,3)', 'tal')])),
                ('setPosition', (1, 33)),
                ('beginScope', {'tal:replace': 'x'}),
-               ('insertText', ('$x$',
-                [('startTag', ('span', [('tal:replace', 'x', 'tal')])),
-                 rawtext('dummy</span>')])),
+               ('optTag',
+                ('span',
+                 '',
+                 None,
+                 0,
+                         [('startTag', ('span', [('tal:replace', 'x', 'tal')]))],
+                 [('insertText', ('$x$', [rawtext('dummy')]))])),
                ('endScope', ()),
                rawtext('</p>')])),
              ('endScope', ()),
@@ -416,14 +441,19 @@
             ('beginScope',
              {'tal:attributes': 'src string:foo.png',
               'tal:replace': 'structure string:<img>'}),
-            ('insertStructure',
-             ('$string:<img>$',
-              {'src': ('$string:foo.png$', 0, None)},
-              [('startTag', ('p',
-                             [('tal:replace', 'structure string:<img>', 'tal'),
-                              ('tal:attributes', 'src string:foo.png',
-                               'tal')])),
-               rawtext('duh</p>')])),
+            ('optTag',
+             ('p',
+              '',
+              None,
+              0,
+              [('startTag',
+                ('p',
+                 [('tal:replace', 'structure string:<img>', 'tal'),
+                  ('tal:attributes', 'src string:foo.png', 'tal')]))],
+              [('insertStructure',
+                ('$string:<img>$',
+                 {'src': ('$string:foo.png$', False, None)},
+                 [rawtext('duh')]))])),
             ('endScope', ()),
             ])
 
@@ -454,11 +484,16 @@
             ('beginScope',
              {'tal:replace': 'notHere', 'tal:on-error': 'string:error'}),
             ('onError',
-             ([('insertText', ('$notHere$',
-                [('startTag', ('p',
-                  [('tal:on-error', 'string:error', 'tal'),
-                   ('tal:replace', 'notHere', 'tal')])),
-                 rawtext('okay</p>')]))],
+             ([('optTag',
+                ('p',
+                 '',
+                 None,
+                 0,
+                 [('startTag',
+                   ('p',
+                    [('tal:on-error', 'string:error', 'tal'),
+                     ('tal:replace', 'notHere', 'tal')]))],
+                 [('insertText', ('$notHere$', [('rawtextOffset', ('okay', 4))]))]))],
               [('startTag', ('p',
                 [('tal:on-error', 'string:error', 'tal'),
                  ('tal:replace', 'notHere', 'tal')])),
@@ -560,10 +595,14 @@
     [('rawtextOffset', ('replaceable ', 12)),
      ('setPosition', (1, 36)),
      ('beginScope', {'tal:replace': 'str:here'}),
-     ('insertText',
-      ('$str:here$',
-       [('startTag', ('p', [('tal:replace', 'str:here', 'tal')])),
-        ('rawtextOffset', ('content</p>', 11))])),
+     ('optTag',
+      ('p',
+       '',
+       None,
+       0,
+       [('startTag', ('p', [('tal:replace', 'str:here', 'tal')]))],
+       [('insertText',
+        ('$str:here$', [rawtext('content')]))])),
      ('endScope', ())])),
   ('endScope', ()),
   ('rawtextColumn', ('</span>\n', 0))
@@ -590,12 +629,18 @@
        {'i18n:name': 'name', 'tal:replace': 'str:Lomax'})),
      ('i18nVariable',
       ('name',
-       [('startEndTag',
+       [('optTag',
          ('span',
-          [('tal:replace', 'str:Lomax', 'tal'),
-           ('i18n:name', 'name', 'i18n')]))],
-       '$str:Lomax$',
-       0)),
+          '',
+          None,
+          1,
+          [('startEndTag',
+            ('span',
+             [('tal:replace', 'str:Lomax', 'tal'),
+              ('i18n:name', 'name', 'i18n')]))],
+          [('insertText', ('$str:Lomax$', []))]))],
+       None,
+       False)),
      ('rawtextBeginScope',
       (' was born in\n  ',
        2,
@@ -604,12 +649,18 @@
        {'i18n:name': 'country', 'tal:replace': 'str:Antarctica'})),
      ('i18nVariable',
       ('country',
-       [('startEndTag',
+       [('optTag',
          ('span',
-          [('tal:replace', 'str:Antarctica', 'tal'),
-           ('i18n:name', 'country', 'i18n')]))],
-       '$str:Antarctica$',
-       0)),
+          '',
+          None,
+          1,
+          [('startEndTag',
+            ('span',
+             [('tal:replace', 'str:Antarctica', 'tal'),
+              ('i18n:name', 'country', 'i18n')]))],
+          [('insertText', ('$str:Antarctica$', []))]))],
+       None,
+       False)),
      ('endScope', ()),
      ('rawtextColumn', ('.\n', 0))])),
   ('endScope', ()),
@@ -664,13 +715,21 @@
    ('',
     [('rawtextBeginScope', ('\n  ', 2, (2, 2), 0, {'i18n:name': 'name'})),
      ('i18nVariable',
-      ('name',
-       [('rawtextOffset', ('<b>Jim</b>', 10))], None, 0)),
-     ('rawtextBeginScope',
-      (' was born in\n  ', 2, (3, 2), 1, {'i18n:name': 'country'})),
-     ('i18nVariable',
-      ('country',
-       [('rawtextOffset', ('the USA', 7))], None, 0)),
+     ('name',
+      [('startTag', ('span', [('i18n:name', 'name', 'i18n')])),
+       ('rawtextOffset', ('<b>Jim</b>', 10)),
+       ('rawtextOffset', ('</span>', 7))],
+      None,
+      False)),
+    ('rawtextBeginScope',
+     (' was born in\n  ', 2, (3, 2), 1, {'i18n:name': 'country'})),
+    ('i18nVariable',
+     ('country',
+      [('startTag', ('span', [('i18n:name', 'country', 'i18n')])),
+       ('rawtextOffset', ('the USA', 7)),
+       ('rawtextOffset', ('</span>', 7))],
+      None,
+      False)),
      ('endScope', ()),
      ('rawtextColumn', ('.\n', 0))])),
   ('endScope', ()),
@@ -778,15 +837,20 @@
       {'i18n:data': 'here/currentTime',
        'i18n:name': 'time',
        'i18n:translate': 'timefmt'})),
-    ('insertTranslation',
-     ('timefmt',
+    ('i18nVariable',
+     ('time',
       [('startTag',
         ('span',
          [('i18n:data', 'here/currentTime', 'i18n'),
           ('i18n:translate', 'timefmt', 'i18n'),
           ('i18n:name', 'time', 'i18n')])),
-       ('i18nVariable', ('time', [], None, 0))],
-      '$here/currentTime$')),
+       ('insertTranslation',
+        ('timefmt',
+         [('rawtextOffset', ('2:32 pm', 7))],
+         '$here/currentTime$')),
+       ('rawtextOffset', ('</span>', 7))],
+      None,
+      False)),
     ('endScope', ()),
     ('rawtextOffset', ('... beep!', 9))])),
  ('endScope', ()),
@@ -813,14 +877,20 @@
        {'i18n:name': 'jobnum', 'tal:replace': 'context/@@object_name'})),
      ('i18nVariable',
       ('jobnum',
-       [('startTag',
-         ('span',
-          [('tal:replace', 'context/@@object_name', 'tal'),
-           ('i18n:name', 'jobnum', 'i18n')])),
-        ('rawtextOffset', ('NN', 2)),
-        ('rawtextOffset', ('</span>', 7))],
-       '$context/@@object_name$',
-       0)),
+      [('optTag',
+        ('span',
+         '',
+         None,
+         0,
+         [('startTag',
+           ('span',
+            [('tal:replace', 'context/@@object_name', 'tal'),
+             ('i18n:name', 'jobnum', 'i18n')]))],
+         [('insertText',
+           ('$context/@@object_name$',
+            [('rawtextOffset', ('NN', 2))]))]))],
+      None,
+      False)),
      ('endScope', ())])),
   ('endScope', ()),
   ('rawtextColumn', ('</span>\n', 0))
@@ -848,7 +918,8 @@
        {'i18n:name': 'email'})),
      ('i18nVariable',
       ('email',
-       [('rawtextBeginScope',
+       [('startTag', ('span', [('i18n:name', 'email', 'i18n')])),
+        ('rawtextBeginScope',
          ('\n    ',
           4,
           (3, 4),
@@ -863,14 +934,14 @@
          ('$request/submitter$',
           [('rawtextOffset', ('user at host.com', 13))])),
         ('endScope', ()),
-        ('rawtextOffset', ('</a>', 4))],
+        ('rawtextOffset', ('</a>', 4)),
+        ('rawtextOffset', ('</span>', 7))],
        None,
-       0)),
+       False)),
      ('endScope', ()),
      ('rawtextColumn', ('\n', 0))])),
   ('endScope', ()),
-  ('rawtextColumn', ('</p>\n', 0))
-  ])
+  ('rawtextColumn', ('</p>\n', 0))])
 
     def check_i18n_name_with_tal_content(self):
         # input/test27.html

Modified: Zope/trunk/lib/python/TAL/tests/test_sourcepos.py
===================================================================
--- Zope/trunk/lib/python/TAL/tests/test_sourcepos.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/test_sourcepos.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -6,10 +6,20 @@
 
 from StringIO import StringIO
 
+# BBB 2005/05/01 -- to be changed after 12 months
+# ignore deprecation warnings on import for now
+import warnings
+showwarning = warnings.showwarning
+warnings.showwarning = lambda *a, **k: None
+# this old import should remain here until the TAL package is
+# completely removed, so that API backward compatibility is properly
+# tested
 from TAL.HTMLTALParser import HTMLTALParser
 from TAL.TALInterpreter import TALInterpreter
 from TAL.TALGenerator import TALGenerator
 from TAL.DummyEngine import DummyEngine
+# restore warning machinery
+warnings.showwarning = showwarning
 
 
 page1 = '''<html metal:use-macro="main"><body>

Modified: Zope/trunk/lib/python/TAL/tests/test_talinterpreter.py
===================================================================
--- Zope/trunk/lib/python/TAL/tests/test_talinterpreter.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/test_talinterpreter.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -21,12 +21,24 @@
 
 from StringIO import StringIO
 
+# BBB 2005/05/01 -- to be changed after 12 months
+# ignore deprecation warnings on import for now
+import warnings
+showwarning = warnings.showwarning
+warnings.showwarning = lambda *a, **k: None
+# this old import should remain here until the TAL package is
+# completely removed, so that API backward compatibility is properly
+# tested
 from TAL.TALDefs import METALError, I18NError
 from TAL.HTMLTALParser import HTMLTALParser
 from TAL.TALParser import TALParser
 from TAL.TALInterpreter import TALInterpreter
 from TAL.DummyEngine import DummyEngine, DummyTranslationService
 from TAL.TALInterpreter import interpolate
+# restore warning machinery
+warnings.showwarning = showwarning
+
+
 from TAL.tests import utils
 from zope.i18nmessageid import Message
 
@@ -105,14 +117,15 @@
     def test_structure_replace_with_messageid_and_i18nname(self):
         program, macros = self._compile(
             '<div i18n:translate="" >'
-            '<span tal:replace="structure foo" i18n:name="foo_name"/>'
+            '<span tal:replace="structure foo" i18n:name="foo_name"'
+            '      i18n:translate=""/>'
             '</div>')
         self._check(program, '<div>FOOVALUE</div>\n')
 
     def test_complex_replace_with_messageid_and_i18nname(self):
         program, macros = self._compile(
             '<div i18n:translate="" >'
-            '<em i18n:name="foo_name">'
+            '<em i18n:name="foo_name" tal:omit-tag="">'
             '<span tal:replace="foo"/>'
             '</em>'
             '</div>')
@@ -146,7 +159,7 @@
                     '<div>THIS IS TEXT FOR <span>BARVALUE</span>.</div>\n')
 
     def test_translate_static_text_as_dynamic_from_bytecode(self):
-        program =  [('version', '1.5'),
+        program =  [('version', '1.6'),
  ('mode', 'html'),
 ('setPosition', (1, 0)),
 ('beginScope', {'i18n:translate': ''}),
@@ -178,23 +191,8 @@
         self._check(program,
                     '<div>THIS IS TEXT FOR <span>BARVALUE</span>.</div>\n')
 
-    def _getCollectingTranslationDomain(self):
-        class CollectingTranslationService(DummyTranslationService):
-            data = []
-
-            def translate(self, domain, msgid, mapping=None,
-                          context=None, target_language=None, default=None):
-                self.data.append((msgid, mapping))
-                return DummyTranslationService.translate(
-                    self,
-                    domain, msgid, mapping, context, target_language, default)
-
-        xlatsvc = CollectingTranslationService()
-        self.engine.translationService = xlatsvc
-        return xlatsvc
-
     def test_for_correct_msgids(self):
-        xlatdmn = self._getCollectingTranslationDomain()
+        self.engine.translationDomain.clearMsgids()
         result = StringIO()
         program, macros = self._compile(
             '<div i18n:translate="">This is text for '
@@ -203,7 +201,7 @@
         self.interpreter = TALInterpreter(program, {}, self.engine,
                                           stream=result)
         self.interpreter()
-        msgids = list(xlatdmn.data)
+        msgids = self.engine.translationDomain.getMsgids('default')
         msgids.sort()
         self.assertEqual(2, len(msgids))
         self.assertEqual('BaRvAlUe', msgids[0][0])
@@ -217,7 +215,7 @@
         # Test for Issue 314: i18n:translate removes line breaks from
         # <pre>...</pre> contents
         # HTML mode
-        xlatdmn = self._getCollectingTranslationDomain()
+        self.engine.translationDomain.clearMsgids()
         result = StringIO()
         program, macros = self._compile(
             '<div i18n:translate=""> This is text\n'
@@ -227,7 +225,7 @@
         self.interpreter = TALInterpreter(program, {}, self.engine,
                                           stream=result)
         self.interpreter()
-        msgids = list(xlatdmn.data)
+        msgids = self.engine.translationDomain.getMsgids('default')
         msgids.sort()
         self.assertEqual(2, len(msgids))
         self.assertEqual(' This is text\n <b>\tfor</b>\n pre. ', msgids[0][0])
@@ -238,7 +236,7 @@
             result.getvalue())
 
         # XML mode
-        xlatdmn = self._getCollectingTranslationDomain()
+        self.engine.translationDomain.clearMsgids()
         result = StringIO()
         parser = TALParser()
         parser.parseString(
@@ -250,7 +248,7 @@
         self.interpreter = TALInterpreter(program, {}, self.engine,
                                           stream=result)
         self.interpreter()
-        msgids = list(xlatdmn.data)
+        msgids = self.engine.translationDomain.getMsgids('default')
         msgids.sort()
         self.assertEqual(1, len(msgids))
         self.assertEqual('This is text <b> for</b> barvalue.', msgids[0][0])
@@ -260,7 +258,7 @@
             result.getvalue())
 
     def test_raw_msgids_and_i18ntranslate_i18nname(self):
-        xlatdmn = self._getCollectingTranslationDomain()
+        self.engine.translationDomain.clearMsgids()
         result = StringIO()
         program, macros = self._compile(
             '<div i18n:translate=""> This is text\n \tfor\n'
@@ -269,7 +267,7 @@
         self.interpreter = TALInterpreter(program, {}, self.engine,
                                           stream=result)
         self.interpreter()
-        msgids = list(xlatdmn.data)
+        msgids = self.engine.translationDomain.getMsgids('default')
         msgids.sort()
         self.assertEqual(2, len(msgids))
         self.assertEqual(' \tRaW\n ', msgids[0][0])
@@ -416,12 +414,13 @@
         expected = u"foo baz"
         self.assertEqual(interpolate(text, mapping), expected)
 
-    def test_unicode_mixed_unknown_encoding(self):
-        # This test assumes that sys.getdefaultencoding is ascii...
-        text = u"foo ${bar}"
-        mapping = {u'bar': 'd\xe9j\xe0'}
-        expected = u"foo d\\xe9j\\xe0"
-        self.assertEqual(interpolate(text, mapping), expected)
+    # this test just tests sick behaviour, we'll disable it
+    #def test_unicode_mixed_unknown_encoding(self):
+    #    # This test assumes that sys.getdefaultencoding is ascii...
+    #    text = u"foo ${bar}"
+    #    mapping = {u'bar': 'd\xe9j\xe0'}
+    #    expected = u"foo d\\xe9j\\xe0"
+    #    self.assertEqual(interpolate(text, mapping), expected)
 
 def test_suite():
     suite = unittest.makeSuite(I18NErrorsTestCase)

Modified: Zope/trunk/lib/python/TAL/tests/test_xmlparser.py
===================================================================
--- Zope/trunk/lib/python/TAL/tests/test_xmlparser.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/tests/test_xmlparser.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -7,7 +7,17 @@
 from TAL.tests import utils
 import unittest
 
+# BBB 2005/05/01 -- to be changed after 12 months
+# ignore deprecation warnings on import for now
+import warnings
+showwarning = warnings.showwarning
+warnings.showwarning = lambda *a, **k: None
+# this old import should remain here until the TAL package is
+# completely removed, so that API backward compatibility is properly
+# tested
 from TAL import XMLParser
+# restore warning machinery
+warnings.showwarning = showwarning
 
 
 class EventCollector(XMLParser.XMLParser):

Modified: Zope/trunk/lib/python/TAL/timer.py
===================================================================
--- Zope/trunk/lib/python/TAL/timer.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/TAL/timer.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -14,44 +14,11 @@
 ##############################################################################
 """
 Helper program to time compilation and interpretation
+
+BBB 2005/05/01 -- to be removed after 12 months
 """
+import zope.deprecation
+zope.deprecation.moved('zope.tal.timer', '2.12')
 
-import sys
-import time
-import getopt
-from cPickle import dumps, loads
-from cStringIO import StringIO
-
-from driver import FILE, compilefile, interpretit
-
-def main():
-    count = 10
-    try:
-        opts, args = getopt.getopt(sys.argv[1:], "n:")
-    except getopt.error, msg:
-        print msg
-        sys.exit(2)
-    for o, a in opts:
-        if o == "-n":
-            count = int(a)
-    if not args:
-        args = [FILE]
-    for file in args:
-        print file
-        dummyfile = StringIO()
-        it = timefunc(count, compilefile, file)
-        timefunc(count, interpretit, it, None, dummyfile)
-
-def timefunc(count, func, *args):
-    sys.stderr.write("%-14s: " % func.__name__)
-    sys.stderr.flush()
-    t0 = time.clock()
-    for i in range(count):
-        result = func(*args)
-    t1 = time.clock()
-    sys.stderr.write("%6.3f secs for %d calls, i.e. %4.0f msecs per call\n"
-                     % ((t1-t0), count, 1000*(t1-t0)/count))
-    return result
-
 if __name__ == "__main__":
     main()

Modified: Zope/trunk/lib/python/ZTUtils/Iterator.py
===================================================================
--- Zope/trunk/lib/python/ZTUtils/Iterator.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/ZTUtils/Iterator.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -12,14 +12,17 @@
 ##############################################################################
 """Iterator class
 
-Unlike the builtin iterators of Python 2.2+, these classes are
-designed to maintain information about the state of an iteration.
-The Iterator() function accepts either a sequence or a Python
-iterator.  The next() method fetches the next item, and returns
-true if it succeeds.
+BBB 2005/05/01 -- to be removed after 12 months
 
 $Id$
 """
+import zope.deprecation
+zope.deprecation.deprecated(
+    'Iterator',
+    'Iterator has been deprecated and will be removed in Zope 2.12.  '
+    'PageTemplates now use the Zope 3 implementation.  Use ZopeIterator '
+    'from Products.PageTemplates.Expressions instead.'
+    )
 
 class Iterator:
     '''Simple Iterator class'''

Modified: Zope/trunk/lib/python/ZTUtils/__init__.py
===================================================================
--- Zope/trunk/lib/python/ZTUtils/__init__.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/ZTUtils/__init__.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -14,8 +14,12 @@
 
 $Id$
 """
+# BBB 2005/05/01 -- to be removed after 12 months
+import zope.deferredimport
+zope.deferredimport.define(
+    Iterator = 'ZTUtils.Iterator:Iterator'
+    )
 
-from Iterator import Iterator
 from Tree import encodeExpansion, decodeExpansion, a2b, b2a
 from SimpleTree import SimpleTreeMaker
 

Modified: Zope/trunk/lib/python/ZTUtils/tests/testIterator.py
===================================================================
--- Zope/trunk/lib/python/ZTUtils/tests/testIterator.py	2006-05-29 09:50:59 UTC (rev 68332)
+++ Zope/trunk/lib/python/ZTUtils/tests/testIterator.py	2006-05-29 10:34:19 UTC (rev 68333)
@@ -1,7 +1,10 @@
 from __future__ import generators
 import os, sys, unittest
 
+import zope.deprecation
+zope.deprecation.__show__.off()
 from ZTUtils import Iterator
+zope.deprecation.__show__.on()
 
 try:
     iter


Property changes on: Zope/trunk/lib/python/zope
___________________________________________________________________
Name: svn:externals
   - app              -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/app
cachedescriptors -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/cachedescriptors
component        -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/component
configuration    -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/configuration
documenttemplate -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/documenttemplate
event            -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/event
exceptions       -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/exceptions
hookable         -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/hookable
i18n             -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/i18n
i18nmessageid    -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/i18nmessageid
interface        -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/interface
modulealias      -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/modulealias
pagetemplate     -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/pagetemplate
proxy            -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/proxy
publisher        -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/publisher
schema           -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/schema
security         -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/security
server           -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/server
structuredtext   -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/structuredtext
tal              -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/tal
tales            -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/tales
testing          -r 67760 svn://svn.zope.org/repos/main/zope.testing/trunk/src/zope/testing
thread           -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/thread
deprecation      -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/deprecation
dottedname       -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/dottedname
formlib          -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/formlib
index            -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/index
testbrowser      -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/testbrowser
contentprovider  -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/contentprovider
viewlet          -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/viewlet
annotation       -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/annotation
contenttype      -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/contenttype
copypastemove    -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/copypastemove
datetime         -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/datetime
decorator        -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/decorator
deferredimport   -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/deferredimport
dublincore       -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/dublincore
filerepresentation -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/filerepresentation
lifecycleevent   -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/lifecycleevent
location         -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/location
rdb              -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/rdb
sendmail         -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/sendmail
size             -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/size
traversing       -r 67855 svn://svn.zope.org/repos/main/Zope3/trunk/src/zope/traversing

   + app              -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/app
cachedescriptors -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/cachedescriptors
component        -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/component
configuration    -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/configuration
documenttemplate -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/documenttemplate
event            -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/event
exceptions       -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/exceptions
hookable         -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/hookable
i18n             -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/i18n
i18nmessageid    -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/i18nmessageid
interface        -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/interface
modulealias      -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/modulealias
pagetemplate     -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/pagetemplate
proxy            -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/proxy
publisher        -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/publisher
schema           -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/schema
security         -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/security
server           -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/server
structuredtext   -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/structuredtext
tal              -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/tal
tales            -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/tales
testing          -r 67760 svn://svn.zope.org/repos/main/zope.testing/trunk/src/zope/testing
thread           -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/thread
deprecation      -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/deprecation
dottedname       -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/dottedname
formlib          -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/formlib
index            -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/index
testbrowser      -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/testbrowser
contentprovider  -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/contentprovider
viewlet          -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/viewlet
annotation       -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/annotation
contenttype      -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/contenttype
copypastemove    -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/copypastemove
datetime         -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/datetime
decorator        -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/decorator
deferredimport   -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/deferredimport
dublincore       -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/dublincore
filerepresentation -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/filerepresentation
lifecycleevent   -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/lifecycleevent
location         -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/location
rdb              -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/rdb
sendmail         -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/sendmail
size             -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/size
traversing       -r 68324 svn://svn.zope.org/repos/main/Zope3/branches/3.3/src/zope/traversing




More information about the Zope-Checkins mailing list