[Checkins] SVN: zope.tales/trunk/ Python 3.3 and PyPY support.
Stephen Richter
cvs-admin at zope.org
Fri Feb 15 01:31:15 UTC 2013
Log message for revision 129421:
Python 3.3 and PyPY support.
Changed:
_U zope.tales/trunk/
U zope.tales/trunk/CHANGES.txt
A zope.tales/trunk/MANIFEST.in
U zope.tales/trunk/bootstrap.py
U zope.tales/trunk/buildout.cfg
U zope.tales/trunk/setup.py
U zope.tales/trunk/src/zope/tales/expressions.py
U zope.tales/trunk/src/zope/tales/interfaces.py
U zope.tales/trunk/src/zope/tales/pythonexpr.py
U zope.tales/trunk/src/zope/tales/tales.py
U zope.tales/trunk/src/zope/tales/tests/simpleexpr.py
U zope.tales/trunk/src/zope/tales/tests/test_expressions.py
U zope.tales/trunk/src/zope/tales/tests/test_tales.py
U zope.tales/trunk/src/zope/tales/tests/test_traverser.py
A zope.tales/trunk/tox.ini
-=-
Property changes on: zope.tales/trunk
___________________________________________________________________
Modified: svn:ignore
- bin
build
dist
lib
develop-eggs
eggs
parts
.installed.cfg
+ .coverage
.installed.cfg
.tox
bin
build
coverage
dist
lib
develop-eggs
eggs
parts
*.xml
Modified: zope.tales/trunk/CHANGES.txt
===================================================================
--- zope.tales/trunk/CHANGES.txt 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/CHANGES.txt 2013-02-15 01:31:14 UTC (rev 129421)
@@ -4,29 +4,38 @@
4.0.0 (unreleased)
------------------
+- Removed hard dependency on ``zope.tal``, which was already conditionalized
+ but required via ``setup.py``.
+
+- Added Python 3.3 and PyPY 1.9 support.
+
- Replaced deprecated ``zope.interface.implements`` usage with equivalent
``zope.interface.implementer`` decorator.
- Dropped support for Python 2.4 and 2.5.
- Fixed documentation link in README.txt
-
+
+
3.5.2 (2012-05-23)
------------------
-
+
- Subexpressions of a 'string:' expression can be only path expressions.
https://bugs.launchpad.net/zope.tales/+bug/1002242
+
3.5.1 (2010-04-30)
------------------
- Removed use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest.
+
3.5.0 (2010-01-01)
------------------
- Ported the lazy expression from Products.PageTemplates.
+
3.4.0 (2007-10-03)
------------------
@@ -34,6 +43,7 @@
- Initial release outside the Zope 3 trunk.
+
3.2.0 (2006-01-05)
------------------
@@ -42,6 +52,7 @@
- Documentation / test fixes.
+
3.0.0 (2004-11-07)
------------------
Added: zope.tales/trunk/MANIFEST.in
===================================================================
--- zope.tales/trunk/MANIFEST.in (rev 0)
+++ zope.tales/trunk/MANIFEST.in 2013-02-15 01:31:14 UTC (rev 129421)
@@ -0,0 +1,9 @@
+include *.rst
+include *.txt
+include tox.ini
+include bootstrap.py
+include buildout.cfg
+
+recursive-include src *
+
+global-exclude *.pyc
Modified: zope.tales/trunk/bootstrap.py
===================================================================
--- zope.tales/trunk/bootstrap.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/bootstrap.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -18,102 +18,148 @@
use the -c option to specify an alternate configuration file.
"""
-import os, shutil, sys, tempfile, urllib2
+import os, shutil, sys, tempfile
from optparse import OptionParser
tmpeggs = tempfile.mkdtemp()
-is_jython = sys.platform.startswith('java')
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
-# parsing arguments
-parser = OptionParser()
-parser.add_option("-v", "--version", dest="version",
- help="use a specific zc.buildout version")
-parser.add_option("-d", "--distribute",
- action="store_true", dest="distribute", default=False,
- help="Use Disribute rather than Setuptools.")
+Bootstraps a buildout-based project.
-parser.add_option("-c", None, action="store", dest="config_file",
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", help="use a specific zc.buildout version")
+
+parser.add_option("-t", "--accept-buildout-test-releases",
+ dest='accept_buildout_test_releases',
+ action="store_true", default=False,
+ help=("Normally, if you do not specify a --version, the "
+ "bootstrap script and buildout gets the newest "
+ "*final* versions of zc.buildout and its recipes and "
+ "extensions for you. If you use this flag, "
+ "bootstrap and buildout will get the newest releases "
+ "even if they are alphas or betas."))
+parser.add_option("-c", "--config-file",
help=("Specify the path to the buildout configuration "
"file to be used."))
+parser.add_option("-f", "--find-links",
+ help=("Specify a URL to search for buildout releases"))
+
options, args = parser.parse_args()
-# if -c was provided, we push it back into args for buildout' main function
-if options.config_file is not None:
- args += ['-c', options.config_file]
+######################################################################
+# load/install distribute
-if options.version is not None:
- VERSION = '==%s' % options.version
-else:
- VERSION = ''
-
-USE_DISTRIBUTE = options.distribute
-args = args + ['bootstrap']
-
to_reload = False
try:
- import pkg_resources
+ import pkg_resources, setuptools
if not hasattr(pkg_resources, '_distribute'):
to_reload = True
raise ImportError
except ImportError:
ez = {}
- if USE_DISTRIBUTE:
- exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py'
- ).read() in ez
- ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
- else:
- exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
- ).read() in ez
- ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+ try:
+ from urllib.request import urlopen
+ except ImportError:
+ from urllib2 import urlopen
+
+ exec(urlopen('http://python-distribute.org/distribute_setup.py').read(), ez)
+ setup_args = dict(to_dir=tmpeggs, download_delay=0, no_fake=True)
+ ez['use_setuptools'](**setup_args)
+
if to_reload:
reload(pkg_resources)
- else:
- import pkg_resources
+ import pkg_resources
+ # This does not (always?) update the default working set. We will
+ # do it.
+ for path in sys.path:
+ if path not in pkg_resources.working_set.entries:
+ pkg_resources.working_set.add_entry(path)
-if sys.platform == 'win32':
- def quote(c):
- if ' ' in c:
- return '"%s"' % c # work around spawn lamosity on windows
- else:
- return c
-else:
- def quote (c):
- return c
+######################################################################
+# Install buildout
-cmd = 'from setuptools.command.easy_install import main; main()'
ws = pkg_resources.working_set
-if USE_DISTRIBUTE:
- requirement = 'distribute'
-else:
- requirement = 'setuptools'
+cmd = [sys.executable, '-c',
+ 'from setuptools.command.easy_install import main; main()',
+ '-mZqNxd', tmpeggs]
-if is_jython:
- import subprocess
+find_links = os.environ.get(
+ 'bootstrap-testing-find-links',
+ options.find_links or
+ ('http://downloads.buildout.org/'
+ if options.accept_buildout_test_releases else None)
+ )
+if find_links:
+ cmd.extend(['-f', find_links])
- assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
- quote(tmpeggs), 'zc.buildout' + VERSION],
- env=dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse(requirement)).location
- ),
- ).wait() == 0
+distribute_path = ws.find(
+ pkg_resources.Requirement.parse('distribute')).location
-else:
- assert os.spawnle(
- os.P_WAIT, sys.executable, quote (sys.executable),
- '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
- dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse(requirement)).location
- ),
- ) == 0
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+ # Figure out the most recent final version of zc.buildout.
+ import setuptools.package_index
+ _final_parts = '*final-', '*final'
+ def _final_version(parsed_version):
+ for part in parsed_version:
+ if (part[:1] == '*') and (part not in _final_parts):
+ return False
+ return True
+ index = setuptools.package_index.PackageIndex(
+ search_path=[distribute_path])
+ if find_links:
+ index.add_find_links((find_links,))
+ req = pkg_resources.Requirement.parse(requirement)
+ if index.obtain(req) is not None:
+ best = []
+ bestv = None
+ for dist in index[req.project_name]:
+ distv = dist.parsed_version
+ if _final_version(distv):
+ if bestv is None or distv > bestv:
+ best = [dist]
+ bestv = distv
+ elif distv == bestv:
+ best.append(dist)
+ if best:
+ best.sort()
+ version = best[-1].version
+if version:
+ requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+import subprocess
+if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=distribute_path)) != 0:
+ raise Exception(
+ "Failed to execute command:\n%s",
+ repr(cmd)[1:-1])
+
+######################################################################
+# Import and run buildout
+
ws.add_entry(tmpeggs)
-ws.require('zc.buildout' + VERSION)
+ws.require(requirement)
import zc.buildout.buildout
+
+if not [a for a in args if '=' not in a]:
+ args.append('bootstrap')
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+ args[0:0] = ['-c', options.config_file]
+
zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)
Modified: zope.tales/trunk/buildout.cfg
===================================================================
--- zope.tales/trunk/buildout.cfg 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/buildout.cfg 2013-02-15 01:31:14 UTC (rev 129421)
@@ -1,6 +1,7 @@
[buildout]
develop = .
parts = test
+prefer-final = true
[test]
recipe = zc.recipe.testrunner
Modified: zope.tales/trunk/setup.py
===================================================================
--- zope.tales/trunk/setup.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/setup.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -24,6 +24,21 @@
def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+def alltests():
+ import os
+ import sys
+ import unittest
+ # use the zope.testrunner machinery to find all the
+ # test suites we've put under ourselves
+ import zope.testrunner.find
+ import zope.testrunner.options
+ here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src'))
+ args = sys.argv[:]
+ defaults = ["--test-path", here]
+ options = zope.testrunner.options.get_options(args, defaults)
+ suites = list(zope.testrunner.find.find_suites(options))
+ return unittest.TestSuite(suites)
+
setup(name='zope.tales',
version = '4.0.0dev',
author='Zope Foundation and Contributors',
@@ -45,6 +60,10 @@
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: Implementation :: CPython',
+ 'Programming Language :: Python :: Implementation :: PyPy',
'Natural Language :: English',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
@@ -55,12 +74,13 @@
package_dir = {'': 'src'},
namespace_packages=['zope'],
extras_require = dict(
- test=['zope.testing',
- ]),
+ test=['zope.testing'],
+ tal=['zope.tal']),
install_requires=[
'setuptools',
- 'zope.interface',
- 'zope.tal'],
+ 'zope.interface'],
+ tests_require = ['zope.testing', 'zope.testrunner'],
+ test_suite = '__main__.alltests',
include_package_data = True,
zip_safe = False,
)
Modified: zope.tales/trunk/src/zope/tales/expressions.py
===================================================================
--- zope.tales/trunk/src/zope/tales/expressions.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/src/zope/tales/expressions.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -13,7 +13,10 @@
##############################################################################
"""Basic Page Template expression types.
"""
-import re, types
+import re
+import six
+import sys
+import types
from zope.interface import implementer
from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined
@@ -24,6 +27,8 @@
_marker = object()
namespace_re = re.compile(r'(\w+):(.+)')
+PY2 = sys.version_info[0] == 2
+
def simpleTraverse(object, path_items, econtext):
"""Traverses a sequence of names, first trying attributes then items.
"""
@@ -91,7 +96,7 @@
# check for initial function
raise engine.getCompilerError()(
'Namespace function specified in first subpath element')
- elif isinstance(first, basestring):
+ elif isinstance(first, six.string_types):
# check for initial ?
raise engine.getCompilerError()(
'Dynamic name specified in first subpath element')
@@ -120,11 +125,11 @@
for element in compiled_path:
if isinstance(element, tuple):
ob = self._traverser(ob, element, econtext)
- elif isinstance(element, basestring):
+ elif isinstance(element, six.string_types):
val = vars[element]
# If the value isn't a string, assume it's a sequence
# of path names.
- if isinstance(val, basestring):
+ if isinstance(val, six.string_types):
val = (val,)
ob = self._traverser(ob, val, econtext)
elif callable(element):
@@ -204,9 +209,10 @@
# eats babies, err, exceptions. In addition to that, we
# support calling old style classes which don't have a
# __call__.
- if (getattr(ob, '__call__', _marker) is not _marker
- or isinstance(ob, types.ClassType)):
+ if getattr(ob, '__call__', _marker) is not _marker:
return ob()
+ if PY2 and isinstance(ob, types.ClassType):
+ return ob()
return ob
def __call__(self, econtext):
@@ -215,10 +221,10 @@
return self._eval(econtext)
def __str__(self):
- return '%s expression (%s)' % (self._name, `self._s`)
+ return '%s expression (%s)' % (self._name, repr(self._s))
def __repr__(self):
- return '<PathExpr %s:%s>' % (self._name, `self._s`)
+ return '<PathExpr %s:%s>' % (self._name, repr(self._s))
@@ -263,10 +269,10 @@
return self._expr % tuple(vvals)
def __str__(self):
- return 'string expression (%s)' % `self._s`
+ return 'string expression (%s)' % repr(self._s)
def __repr__(self):
- return '<StringExpr %s>' % `self._s`
+ return '<StringExpr %s>' % repr(self._s)
@implementer(ITALESExpression)
@@ -280,7 +286,7 @@
return int(not econtext.evaluateBoolean(self._c))
def __repr__(self):
- return '<NotExpr %s>' % `self._s`
+ return '<NotExpr %s>' % repr(self._s)
class DeferWrapper(object):
@@ -306,7 +312,7 @@
return DeferWrapper(self._c, econtext)
def __repr__(self):
- return '<DeferExpr %s>' % `self._s`
+ return '<DeferExpr %s>' % repr(self._s)
class LazyWrapper(DeferWrapper):
@@ -329,7 +335,7 @@
return LazyWrapper(self._c, econtext)
def __repr__(self):
- return 'lazy:%s' % `self._s`
+ return 'lazy:%s' % repr(self._s)
class SimpleModuleImporter(object):
Modified: zope.tales/trunk/src/zope/tales/interfaces.py
===================================================================
--- zope.tales/trunk/src/zope/tales/interfaces.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/src/zope/tales/interfaces.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -16,17 +16,21 @@
from zope.interface import Interface
try:
- from zope import tal
+ from zope.tal.interfaces import ITALIterator
except ImportError:
- tal = None
+ class ITALIterator(Interface):
+ """Stub: See zope.tal.interfaces.ITALIterator"""
+ def next():
+ """Advance to the next value in the iteration, if possible"""
+
class ITALESFunctionNamespace(Interface):
"""Function namespaces can be used in TALES path expressions to extract
information in non-default ways."""
def setEngine(engine):
- """Sets the engine that is used to evaluate TALES expressions."""
+ """Sets the engine that is used to evaluate TALES expressions."""
class ITALESExpression(Interface):
"""TALES expression
@@ -40,75 +44,72 @@
context 'econtext' and return computed value.
"""
-if tal is not None:
- from zope.tal.interfaces import ITALIterator
+class ITALESIterator(ITALIterator):
+ """TAL Iterator provided by TALES
- class ITALESIterator(ITALIterator):
- """TAL Iterator provided by TALES
+ Values of this iterator are assigned to items in the repeat namespace.
- Values of this iterator are assigned to items in the repeat namespace.
+ For example, with a TAL statement like: tal:repeat="item items",
+ an iterator will be assigned to "repeat/item". The iterator
+ provides a number of handy methods useful in writing TAL loops.
- For example, with a TAL statement like: tal:repeat="item items",
- an iterator will be assigned to "repeat/item". The iterator
- provides a number of handy methods useful in writing TAL loops.
+ The results are undefined of calling any of the methods except
+ 'length' before the first iteration.
+ """
- The results are undefined of calling any of the methods except
- 'length' before the first iteration.
+ def index():
+ """Return the position (starting with "0") within the iteration
"""
- def index():
- """Return the position (starting with "0") within the iteration
- """
+ def number():
+ """Return the position (starting with "1") within the iteration
+ """
- def number():
- """Return the position (starting with "1") within the iteration
- """
+ def even():
+ """Return whether the current position is even
+ """
- def even():
- """Return whether the current position is even
- """
+ def odd():
+ """Return whether the current position is odd
+ """
- def odd():
- """Return whether the current position is odd
- """
+ def parity():
+ """Return 'odd' or 'even' depending on the position's parity
- def parity():
- """Return 'odd' or 'even' depending on the position's parity
+ Useful for assigning CSS class names to table rows.
+ """
- Useful for assigning CSS class names to table rows.
- """
+ def start():
+ """Return whether the current position is the first position
+ """
- def start():
- """Return whether the current position is the first position
- """
+ def end():
+ """Return whether the current position is the last position
+ """
- def end():
- """Return whether the current position is the last position
- """
+ def letter():
+ """Return the position (starting with "a") within the iteration
+ """
- def letter():
- """Return the position (starting with "a") within the iteration
- """
+ def Letter():
+ """Return the position (starting with "A") within the iteration
+ """
- def Letter():
- """Return the position (starting with "A") within the iteration
- """
+ def roman():
+ """Return the position (starting with "i") within the iteration
+ """
- def roman():
- """Return the position (starting with "i") within the iteration
- """
+ def Roman():
+ """Return the position (starting with "I") within the iteration
+ """
- def Roman():
- """Return the position (starting with "I") within the iteration
- """
+ def item():
+ """Return the item at the current position
+ """
- def item():
- """Return the item at the current position
- """
+ def length():
+ """Return the length of the sequence
- def length():
- """Return the length of the sequence
-
- Note that this may fail if the TAL iterator was created on a Python
- iterator.
- """
+ Note that this may fail if the TAL iterator was created on a Python
+ iterator.
+ """
Modified: zope.tales/trunk/src/zope/tales/pythonexpr.py
===================================================================
--- zope.tales/trunk/src/zope/tales/pythonexpr.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/src/zope/tales/pythonexpr.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -21,7 +21,7 @@
self.text = text
try:
code = self._compile(text, '<string>')
- except SyntaxError, e:
+ except SyntaxError as e:
raise engine.getCompilerError()(str(e))
self._code = code
self._varnames = code.co_names
Modified: zope.tales/trunk/src/zope/tales/tales.py
===================================================================
--- zope.tales/trunk/src/zope/tales/tales.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/src/zope/tales/tales.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -19,6 +19,7 @@
import re
from zope.interface import implementer
+import six
try:
from zope.tal.interfaces import ITALExpressionEngine
@@ -106,7 +107,7 @@
# but we can't know that without trying to get it. :(
self._last = False
try:
- self._next = i.next()
+ self._next = six.advance_iterator(i)
except StopIteration:
self._done = True
else:
@@ -158,7 +159,7 @@
return False
self._item = v = self._next
try:
- self._next = self._iter.next()
+ self._next = six.advance_iterator(self._iter)
except StopIteration:
self._done = True
self._last = True
@@ -292,7 +293,7 @@
"""
index = self._nextIndex - 1
if index < 0:
- raise TypeError("No iteration position")
+ raise TypeError("No iteration position")
s = ''
while 1:
index, off = divmod(index, radix)
@@ -449,7 +450,7 @@
"""
if self._nextIndex == 0:
- raise TypeError("No iteration position")
+ raise TypeError("No iteration position")
return self._item
def length(self):
@@ -471,17 +472,19 @@
>>> class MyIter(object):
... def __init__(self, seq):
- ... self._next = iter(seq).next
+ ... self._iter = iter(seq)
... def __iter__(self):
... return self
- ... def next(self):
- ... return self._next()
+ ... def __next__(self):
+ ... return next(self._iter)
+ ... next = __next__
>>> it = Iterator('foo', MyIter({"apple":1, "pear":2}), context)
- >>> it.length()
- Traceback (most recent call last):
- ...
- TypeError: len() of unsized object
-
+ >>> try:
+ ... it.length()
+ ... except TypeError:
+ ... pass
+ ... else:
+ ... print('Expected TypeError')
"""
return len(self._seq)
@@ -520,13 +523,13 @@
def registerFunctionNamespace(self, namespacename, namespacecallable):
"""Register a function namespace
- namespace - a string containing the name of the namespace to
+ namespace - a string containing the name of the namespace to
be registered
namespacecallable - a callable object which takes the following
parameter:
- context - the object on which the functions
+ context - the object on which the functions
provided by this namespace will
be called
@@ -639,7 +642,7 @@
def beginScope(self):
self.vars = vars = self.vars.copy()
- self._vars_stack.append(vars)
+ self._vars_stack.append(vars)
self._scope_stack.append([])
def endScope(self):
@@ -648,7 +651,7 @@
scope = self._scope_stack.pop()
# Pop repeat variables, if any
- i = len(scope)
+ i = len(scope)
while i:
i = i - 1
name, value = scope[i]
Modified: zope.tales/trunk/src/zope/tales/tests/simpleexpr.py
===================================================================
--- zope.tales/trunk/src/zope/tales/tests/simpleexpr.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/src/zope/tales/tests/simpleexpr.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -25,4 +25,4 @@
def __call__(self, econtext):
return self._name, self._expr
def __repr__(self):
- return '<SimpleExpr %s %s>' % (self._name, `self._expr`)
+ return '<SimpleExpr %s %s>' % (self._name, repr(self._expr))
Modified: zope.tales/trunk/src/zope/tales/tests/test_expressions.py
===================================================================
--- zope.tales/trunk/src/zope/tales/tests/test_expressions.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/src/zope/tales/tests/test_expressions.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -14,6 +14,7 @@
##############################################################################
"""Default TALES expression implementations tests.
"""
+import sys
import unittest
from zope.tales.engine import Engine
@@ -21,6 +22,14 @@
from zope.tales.tales import Undefined
from zope.interface import implementer
+try:
+ unicode
+except NameError:
+ # Py3: Make the unicode name available again.
+ unicode = str
+
+PY3 = sys.version_info[0] == 3
+
class Data(object):
def __init__(self, **kw):
@@ -33,11 +42,11 @@
class ErrorGenerator:
def __getitem__(self, name):
- import __builtin__
+ from six.moves import builtins
if name == 'Undefined':
e = Undefined
else:
- e = getattr(__builtin__, name, None)
+ e = getattr(builtins, name, None)
if e is None:
e = SystemError
raise e('mess')
@@ -65,7 +74,7 @@
B = 2,
adapterTest = at,
dynamic = 'z',
- eightBits = 'déjà vu',
+ eightBits = u'déjà vu'.encode('utf-8'),
ErrorGenerator = ErrorGenerator(),
)
)
@@ -73,7 +82,7 @@
self.engine = Engine
-class ExpressionTests(ExpressionTestBase):
+class ExpressionTests(ExpressionTestBase):
def testSimple(self):
expr = self.engine.compile('x')
@@ -104,12 +113,12 @@
expr = self.engine.compile('x/y/?dynamic')
context=self.context
self.assertEqual(expr(context),context.vars['x'].y.z)
-
+
def testBadInitalDynamic(self):
from zope.tales.tales import CompilerError
try:
self.engine.compile('?x')
- except CompilerError,e:
+ except CompilerError as e:
self.assertEqual(e.args[0],
'Dynamic name specified in first subpath element')
else:
@@ -121,7 +130,7 @@
self.context.vars['oldstyleclass'] = AnOldStyleClass
expr = self.engine.compile('oldstyleclass')
self.assert_(isinstance(expr(self.context), AnOldStyleClass))
-
+
def testString(self):
expr = self.engine.compile('string:Fred')
context=self.context
@@ -151,9 +160,12 @@
self.assertRaises(CompilerError,
self.engine.compile,
'string:${nothig/nothing|python:1}')
-
+
def testString8Bits(self):
- # Simple eight bit string interpolation should just work.
+ # Simple eight bit string interpolation should just work.
+ if PY3:
+ # Py3: We simply do not handle 8-bit strings.
+ return
expr = self.engine.compile('string:a ${eightBits}')
context=self.context
self.assertEqual(expr(context), 'a déjà vu')
@@ -169,6 +181,9 @@
def testStringFailureWhenMixed(self):
# Mixed Unicode and 8bit string interpolation fails with a
# UnicodeDecodeError, assuming there is no default encoding
+ if PY3:
+ # Py3: We simply do not handle 8-bit strings.
+ return
expr = self.engine.compile(u'string:a ${eightBits}')
self.assertRaises(UnicodeDecodeError, expr, self.context)
@@ -277,8 +292,8 @@
def __getitem__(self,key):
if key=='jump':
return self.context._d
- raise KeyError,key
-
+ raise KeyError(key)
+
self.TestNameSpace = TestNameSpace
self.engine.registerFunctionNamespace('namespace', self.TestNameSpace)
@@ -287,7 +302,7 @@
def testSetEngine(self):
expr = self.engine.compile('adapterTest/namespace:engine')
self.assertEqual(expr(self.context), self.context)
-
+
def testGetFunctionNamespace(self):
self.assertEqual(
self.engine.getFunctionNamespace('namespace'),
@@ -306,7 +321,7 @@
from zope.tales.tales import CompilerError
try:
self.engine.compile('adapterTest/badnamespace:title')
- except CompilerError,e:
+ except CompilerError as e:
self.assertEqual(e.args[0],'Unknown namespace "badnamespace"')
else:
self.fail('Engine accepted unknown namespace')
@@ -335,7 +350,7 @@
from zope.tales.tales import CompilerError
try:
self.engine.compile('adapterTest/1foo:bar')
- except CompilerError,e:
+ except CompilerError as e:
self.assertEqual(e.args[0],
'Invalid namespace name "1foo"')
else:
@@ -346,13 +361,13 @@
try:
expr = self.engine.compile('adapterTest/namespace:title')
expr(self.context)
- except KeyError,e:
+ except KeyError as e:
self.assertEquals(e.args[0],'title')
else:
self.fail('Engine accepted unknown function')
## runtime tests
-
+
def testNormalFunction(self):
expr = self.engine.compile('adapterTest/namespace:upper')
self.assertEqual(expr(self.context), 'YIKES')
Modified: zope.tales/trunk/src/zope/tales/tests/test_tales.py
===================================================================
--- zope.tales/trunk/src/zope/tales/tests/test_tales.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/src/zope/tales/tests/test_tales.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -84,7 +84,7 @@
e.registerType('simple', SimpleExpr)
ce = e.compile('simple:x')
self.assert_( ce(None) == ('simple', 'x'), (
- 'Improperly compiled expression %s.' % `ce`))
+ 'Improperly compiled expression %s.' % repr(ce)))
def testGetContext(self):
# Test Context creation
@@ -95,13 +95,13 @@
def getContext(self, **kws):
e = tales.ExpressionEngine()
e.registerType('simple', SimpleExpr)
- return apply(e.getContext, (), kws)
+ return e.getContext(*(), **kws)
def testContext0(self):
# Test use of Context
se = self.getContext().evaluate('simple:x')
self.assert_( se == ('simple', 'x'), (
- 'Improperly evaluated expression %s.' % `se`))
+ 'Improperly evaluated expression %s.' % repr(se)))
def testVariables(self):
# Test variables
Modified: zope.tales/trunk/src/zope/tales/tests/test_traverser.py
===================================================================
--- zope.tales/trunk/src/zope/tales/tests/test_traverser.py 2013-02-14 18:53:49 UTC (rev 129420)
+++ zope.tales/trunk/src/zope/tales/tests/test_traverser.py 2013-02-15 01:31:14 UTC (rev 129421)
@@ -13,7 +13,6 @@
##############################################################################
""" Tests for zope.tales.expressions.simpleTraverse
"""
-
from unittest import TestCase, TestSuite, makeSuite, main
from zope.tales.expressions import simpleTraverse
@@ -27,7 +26,7 @@
def __getitem__(self, name):
if name == 'attr':
return 'foo'
- raise KeyError, name
+ raise KeyError(name)
class AllTraversable(AttrTraversable, ItemTraversable):
"""Traversable by attribute and item access"""
@@ -43,7 +42,7 @@
except KeyError:
if default is not _marker:
return default
- raise KeyError, name
+ raise KeyError(name)
else:
return item
Added: zope.tales/trunk/tox.ini
===================================================================
--- zope.tales/trunk/tox.ini (rev 0)
+++ zope.tales/trunk/tox.ini 2013-02-15 01:31:14 UTC (rev 129421)
@@ -0,0 +1,30 @@
+[tox]
+envlist = py26,py27,py33,pypy
+
+[testenv]
+commands =
+ python setup.py test -q
+# without explicit deps, setup.py test will download a bunch of eggs into $PWD
+deps =
+ zope.interface
+ zope.testing
+ zope.testrunner
+
+
+[testenv:coverage]
+basepython =
+ python2.7
+commands =
+# The installed version messes up nose's test discovery / coverage reporting
+# So, we uninstall that from the environment, and then install the editable
+# version, before running nosetests.
+ pip uninstall -y zope.tales
+ pip install -e .
+ nosetests --with-xunit --with-xcoverage
+deps =
+ nose
+ coverage
+ nosexcover
+ zope.interface
+ zope.testing
+ zope.testrunner
More information about the checkins
mailing list