[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">
-
- <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">
+
+ <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
- </div>
+ <div class="form-label">File </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
- </div>
+ <div class="form-label">Encoding </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('&', s)
- s = _entch_re.sub(r'&\1', s)
- s = _entn1_re.sub('&#', s)
- s = _entnx_re.sub(r'&\1', s)
- s = _entnd_re.sub(r'&\1', s)
- s = s.replace('<', '<')
- s = s.replace('>', '>')
- s = s.replace('"', '"')
- 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