diff options
24 files changed, 277 insertions, 162 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 0583318..1a4546e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,6 +5,8 @@ CHANGES 4.0.0 (unreleased) ------------------ +- Support for python-3.3 added + - log DEBUG when loading translations from directories. - Replaced deprecated ``zope.interface.implements`` usage with equivalent diff --git a/bootstrap.py b/bootstrap.py index a6da5d3..ec3757a 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -18,102 +18,148 @@ The script accepts buildout command-line options, so you can 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] -if options.version is not None: - VERSION = '==%s' % options.version -else: - VERSION = '' +options, args = parser.parse_args() -USE_DISTRIBUTE = options.distribute -args = args + ['bootstrap'] +###################################################################### +# load/install distribute 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 - -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 - -cmd = 'from setuptools.command.easy_install import main; main()' + 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) + +###################################################################### +# Install buildout + ws = pkg_resources.working_set -if USE_DISTRIBUTE: - requirement = 'distribute' -else: - requirement = 'setuptools' - -if is_jython: - import subprocess - - 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 - -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 +cmd = [sys.executable, '-c', + 'from setuptools.command.easy_install import main; main()', + '-mZqNxd', tmpeggs] + +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]) + +distribute_path = ws.find( + pkg_resources.Requirement.parse('distribute')).location + +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) @@ -48,6 +48,8 @@ setup( "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', diff --git a/src/zope/i18n/__init__.py b/src/zope/i18n/__init__.py index aeb1c91..ca4974e 100644 --- a/src/zope/i18n/__init__.py +++ b/src/zope/i18n/__init__.py @@ -13,6 +13,7 @@ ############################################################################## """i18n support. """ +import sys import re from zope.component import queryUtility @@ -23,6 +24,10 @@ from zope.i18n.interfaces import INegotiator from zope.i18n.interfaces import ITranslationDomain from zope.i18n.interfaces import IFallbackTranslationDomainFactory +PY3 = sys.version_info[0] == 3 +if PY3: + unicode = str + # Set up regular expressions for finding interpolation variables in text. # NAME_RE must exactly match the expression of the same name in the # zope.tal.taldefs module: diff --git a/src/zope/i18n/format.py b/src/zope/i18n/format.py index 101bd7e..51d64f1 100644 --- a/src/zope/i18n/format.py +++ b/src/zope/i18n/format.py @@ -16,6 +16,7 @@ This module implements basic object formatting functionality, such as date/time, number and money formatting. """ +import sys import re import math import datetime @@ -25,6 +26,18 @@ import pytz.reference from zope.i18n.interfaces import IDateTimeFormat, INumberFormat from zope.interface import implementer +PY3 = sys.version_info[0] == 3 +if PY3: + unicode = str + +def roundHalfUp(n): + """Works like round() in python2.x + + Implementation of round() was changed in python3 - it rounds halfs to + nearest even number, so that round(0.5) == 0. This function is here to + unify behaviour between python 2.x and 3.x for the purposes of this module. + """ + return math.floor(n + math.copysign(0.5, n)) def _findFormattingCharacterInPattern(char, pattern): return [entry for entry in pattern @@ -86,7 +99,7 @@ class DateTimeFormat(object): # Map the parsing results to a datetime object ordered = [None, None, None, None, None, None, None] - bin_pattern = filter(lambda x: isinstance(x, tuple), bin_pattern) + bin_pattern = list(filter(lambda x: isinstance(x, tuple), bin_pattern)) # Handle years; note that only 'yy' and 'yyyy' are allowed if ('y', 2) in bin_pattern: @@ -408,7 +421,7 @@ class NumberFormat(object): fraction = '' roundInt = False if roundInt: - obj = round(obj) + obj = roundHalfUp(obj) integer = self._format_integer(str(int(math.fabs(obj))), bin_pattern[INTEGER]) # Adding grouping @@ -599,7 +612,7 @@ def buildDateTimeInfo(dt, calendar, pattern): """Create the bits and pieces of the datetime object that can be put together.""" if isinstance(dt, datetime.time): - dt = datetime.datetime(1969, 01, 01, dt.hour, dt.minute, dt.second, + dt = datetime.datetime(1969, 1, 1, dt.hour, dt.minute, dt.second, dt.microsecond) elif (isinstance(dt, datetime.date) and not isinstance(dt, datetime.datetime)): diff --git a/src/zope/i18n/gettextmessagecatalog.py b/src/zope/i18n/gettextmessagecatalog.py index b121298..1376d11 100644 --- a/src/zope/i18n/gettextmessagecatalog.py +++ b/src/zope/i18n/gettextmessagecatalog.py @@ -13,21 +13,23 @@ ############################################################################## """A simple implementation of a Message Catalog. """ +import sys from gettext import GNUTranslations from zope.i18n.interfaces import IGlobalMessageCatalog from zope.interface import implementer +PY2 = sys.version_info[0] == 2 class _KeyErrorRaisingFallback(object): def ugettext(self, message): raise KeyError(message) + gettext = ugettext @implementer(IGlobalMessageCatalog) class GettextMessageCatalog(object): """A message catalog based on GNU gettext and Python's gettext module.""" - def __init__(self, language, domain, path_to_file): """Initialize the message catalog""" self.language = language @@ -35,6 +37,10 @@ class GettextMessageCatalog(object): self._path_to_file = path_to_file self.reload() self._catalog.add_fallback(_KeyErrorRaisingFallback()) + if PY2: + self._gettext = self._catalog.ugettext + else: + self._gettext = self._catalog.gettext def reload(self): 'See IMessageCatalog' @@ -46,12 +52,12 @@ class GettextMessageCatalog(object): def getMessage(self, id): 'See IMessageCatalog' - return self._catalog.ugettext(id) + return self._gettext(id) def queryMessage(self, id, default=None): 'See IMessageCatalog' try: - return self._catalog.ugettext(id) + return self._gettext(id) except KeyError: return default diff --git a/src/zope/i18n/locales/__init__.py b/src/zope/i18n/locales/__init__.py index d6d0d05..da83db3 100644 --- a/src/zope/i18n/locales/__init__.py +++ b/src/zope/i18n/locales/__init__.py @@ -124,21 +124,21 @@ class LocaleVersion(object): Examples:: - >>> cmp(LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes'), + >>> (LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes') == ... LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes again')) - 0 + True - >>> cmp(LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes'), + >>> (LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes') < ... LocaleVersion('1.0', datetime(2004, 1, 2), 'no notes again')) - -1 + True - >>> cmp(LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes'), + >>> (LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes') < ... LocaleVersion('0.9', datetime(2004, 1, 2), 'no notes again')) - -1 + True - >>> cmp(LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes'), + >>> (LocaleVersion('1.0', datetime(2004, 1, 1), 'no notes') > ... LocaleVersion('0.9', datetime(2004, 1, 1), 'no notes again')) - 1 + True """ @@ -149,11 +149,13 @@ class LocaleVersion(object): self.generationDate = generationDate self.notes = notes - def __cmp__(self, other): - "See zope.i18n.interfaces.ILocaleVersion" - return cmp((self.generationDate, self.number), - (other.generationDate, other.number)) + def __lt__(self, other): + return ((self.generationDate, self.number) < + (other.generationDate, other.number)) + def __eq__(self, other): + return ((self.generationDate, self.number) == + (other.generationDate, other.number)) @implementer(ILocaleDisplayNames) class LocaleDisplayNames(AttributeInheritance): @@ -413,11 +415,11 @@ class LocaleDates(AttributeInheritance): >>> cal.defaultDateFormat = 'medium' >>> formatter = dates.getFormatter('date') - >>> formatter.format(date(2004, 02, 04)) + >>> formatter.format(date(2004, 2, 4)) u'04.02.2004' >>> formatter = dates.getFormatter('date', length='full') - >>> formatter.format(date(2004, 02, 04)) + >>> formatter.format(date(2004, 2, 4)) u'Mittwoch, 4. Februar 2004' Let's also test the time formatter:: @@ -453,11 +455,11 @@ class LocaleDates(AttributeInheritance): >>> cal.dateTimeFormats = {None: length} >>> formatter = dates.getFormatter('dateTime') - >>> formatter.format(datetime(2004, 02, 04, 12, 15, 00)) + >>> formatter.format(datetime(2004, 2, 4, 12, 15, 00)) u'04.02.2004 12:15:00' >>> formatter = dates.getFormatter('dateTime', length='full') - >>> formatter.format(datetime(2004, 02, 04, 12, 15, 00)) + >>> formatter.format(datetime(2004, 2, 4, 12, 15, 00)) u'Mittwoch, 4. Februar 2004 12:15 Uhr +000' Finally, we'll test some invalid input:: @@ -495,7 +497,7 @@ class LocaleDates(AttributeInheritance): length = getattr( cal, 'default'+category[0].upper()+category[1:]+'Format', - formats.keys()[0]) + list(formats.keys())[0]) # 'datetime' is always a bit special; we often do not have a length # specification, but we need it for looking up the date and time @@ -621,7 +623,7 @@ class LocaleNumbers(AttributeInheritance): length = getattr( self, 'default'+category[0].upper()+category[1:]+'Format', - formats.keys()[0]) + list(formats.keys())[0]) formatLength = formats[length] if name is None: diff --git a/src/zope/i18n/locales/fallbackcollator.py b/src/zope/i18n/locales/fallbackcollator.py index 0cf2679..fc76a58 100644 --- a/src/zope/i18n/locales/fallbackcollator.py +++ b/src/zope/i18n/locales/fallbackcollator.py @@ -26,4 +26,7 @@ class FallbackCollator: return s.lower(), s def cmp(self, s1, s2): - return cmp(self.key(s1), self.key(s2)) + k1, k2 = self.key(s1), self.key(s2) + if k1 == k2: + return 0 + return -1 if k1 < k2 else 1 diff --git a/src/zope/i18n/locales/inheritance.py b/src/zope/i18n/locales/inheritance.py index 3201081..29c1fef 100644 --- a/src/zope/i18n/locales/inheritance.py +++ b/src/zope/i18n/locales/inheritance.py @@ -176,7 +176,7 @@ class InheritingDictionary(Inheritance, dict): True >>> locale.data.keys() [1, 2, 3] - >>> locale.data.items() + >>> list(locale.data.items()) [(1, 'eins'), (2, 'two'), (3, 'three')] """ @@ -190,7 +190,7 @@ class InheritingDictionary(Inheritance, dict): def __getitem__(self, name): """See zope.i18n.interfaces.locales.ILocaleInheritance""" - if not self.has_key(name): + if name not in self: try: selfUp = self.getInheritedSelf() except NoParentException: diff --git a/src/zope/i18n/locales/provider.py b/src/zope/i18n/locales/provider.py index a39247e..391a130 100644 --- a/src/zope/i18n/locales/provider.py +++ b/src/zope/i18n/locales/provider.py @@ -72,6 +72,6 @@ class LocaleProvider(object): country = country.upper() if variant: variant = variant.upper() - if not self._locales.has_key((language, country, variant)): + if (language, country, variant) not in self._locales: self.loadLocale(language, country, variant) return self._locales[(language, country, variant)] diff --git a/src/zope/i18n/locales/tests/test_docstrings.py b/src/zope/i18n/locales/tests/test_docstrings.py index 3cfad9b..fa52078 100644 --- a/src/zope/i18n/locales/tests/test_docstrings.py +++ b/src/zope/i18n/locales/tests/test_docstrings.py @@ -18,6 +18,8 @@ from doctest import DocTestSuite from zope.i18n.locales.inheritance import AttributeInheritance from zope.i18n.locales.inheritance import NoParentException +from zope.i18n.testing import unicode_checker + class LocaleInheritanceStub(AttributeInheritance): def __init__(self, nextLocale=None): @@ -31,9 +33,9 @@ class LocaleInheritanceStub(AttributeInheritance): def test_suite(): return unittest.TestSuite(( - DocTestSuite('zope.i18n.locales'), - DocTestSuite('zope.i18n.locales.inheritance'), - DocTestSuite('zope.i18n.locales.xmlfactory'), + DocTestSuite('zope.i18n.locales', checker=unicode_checker), + DocTestSuite('zope.i18n.locales.inheritance', checker=unicode_checker), + DocTestSuite('zope.i18n.locales.xmlfactory', checker=unicode_checker), )) if __name__ == '__main__': diff --git a/src/zope/i18n/locales/tests/test_fallbackcollator.py b/src/zope/i18n/locales/tests/test_fallbackcollator.py index 6bbffcc..7e10b50 100644 --- a/src/zope/i18n/locales/tests/test_fallbackcollator.py +++ b/src/zope/i18n/locales/tests/test_fallbackcollator.py @@ -15,9 +15,11 @@ import unittest import doctest +from zope.i18n.testing import unicode_checker + def test_suite(): return unittest.TestSuite(( - doctest.DocFileSuite('../fallbackcollator.txt'), + doctest.DocFileSuite('../fallbackcollator.txt', checker=unicode_checker), )) if __name__ == '__main__': diff --git a/src/zope/i18n/locales/tests/test_locales.py b/src/zope/i18n/locales/tests/test_locales.py index 2668669..663c0e4 100644 --- a/src/zope/i18n/locales/tests/test_locales.py +++ b/src/zope/i18n/locales/tests/test_locales.py @@ -66,7 +66,8 @@ class TestLocaleProvider(TestILocaleProvider): def test_loadLocale(self): self.locales.loadLocale(None, None, None) - self.assertEqual(self.locales._locales.keys(), [(None, None, None)]) + self.assertEqual(list(self.locales._locales.keys()), + [(None, None, None)]) self.locales.loadLocale('en', None, None) self.assert_(('en', None, None) in self.locales._locales.keys()) @@ -97,19 +98,19 @@ class TestLocaleAndProvider(TestCase): def test_getDateFormatter(self): formatter = self.locale.dates.getFormatter('date', 'medium') self.assertEqual(formatter.getPattern(), 'MMM d, yyyy') - self.assertEqual(formatter.format(datetime.date(2003, 01, 02)), + self.assertEqual(formatter.format(datetime.date(2003, 1, 2)), 'Jan 2, 2003') self.assertEqual(formatter.parse('Jan 2, 2003'), - datetime.date(2003, 01, 02)) + datetime.date(2003, 1, 2)) def test_getDateTimeFormatter(self): formatter = self.locale.dates.getFormatter('dateTime', 'medium') self.assertEqual(formatter.getPattern(), 'MMM d, yyyy h:mm:ss a') self.assertEqual( - formatter.format(datetime.datetime(2003, 01, 02, 12, 30)), + formatter.format(datetime.datetime(2003, 1, 2, 12, 30)), 'Jan 2, 2003 12:30:00 PM') self.assertEqual(formatter.parse('Jan 2, 2003 12:30:00 PM'), - datetime.datetime(2003, 01, 02, 12, 30)) + datetime.datetime(2003, 1, 2, 12, 30)) def test_getNumberFormatter(self): formatter = self.locale.numbers.getFormatter('decimal') @@ -124,13 +125,13 @@ class TestGlobalLocaleProvider(TestCase): def testLoading(self): locales.loadLocale(None, None, None) - self.assert_(locales._locales.has_key((None, None, None))) + self.assert_((None, None, None) in locales._locales) locales.loadLocale('en', None, None) - self.assert_(locales._locales.has_key(('en', None, None))) + self.assert_(('en', None, None) in locales._locales) locales.loadLocale('en', 'US', None) - self.assert_(locales._locales.has_key(('en', 'US', None))) + self.assert_(('en', 'US', None) in locales._locales) locales.loadLocale('en', 'US', 'POSIX') - self.assert_(locales._locales.has_key(('en', 'US', 'POSIX'))) + self.assert_(('en', 'US', 'POSIX') in locales._locales) def test_getLocale(self): locale = locales.getLocale('en', 'GB') diff --git a/src/zope/i18n/locales/xmlfactory.py b/src/zope/i18n/locales/xmlfactory.py index 4d4712f..1276d7b 100644 --- a/src/zope/i18n/locales/xmlfactory.py +++ b/src/zope/i18n/locales/xmlfactory.py @@ -343,13 +343,13 @@ class LocaleFactory(object): >>> ctx.defaultWidth u'wide' - >>> names = [ctx.months[u'wide'][type] for type in xrange(1,13)] + >>> names = [ctx.months[u'wide'][type] for type in range(1,13)] >>> names[:7] [u'Januar', u'Februar', u'Maerz', u'April', u'Mai', u'Juni', u'Juli'] >>> names[7:] [u'August', u'September', u'Oktober', u'November', u'Dezember'] - >>> abbrs = [ctx.months[u'abbreviated'][type] for type in xrange(1,13)] + >>> abbrs = [ctx.months[u'abbreviated'][type] for type in range(1,13)] >>> abbrs[:6] [u'Jan', u'Feb', u'Mrz', u'Apr', u'Mai', u'Jun'] >>> abbrs[6:] @@ -428,7 +428,7 @@ class LocaleFactory(object): # Put the info together calendar.months = InheritingDictionary() - for type in xrange(1, 13): + for type in range(1, 13): calendar.months[type] = (names.get(type, None), abbrs.get(type, None)) @@ -482,13 +482,13 @@ class LocaleFactory(object): >>> ctx.defaultWidth u'wide' - >>> names = [ctx.days[u'wide'][type] for type in xrange(1,8)] + >>> names = [ctx.days[u'wide'][type] for type in range(1,8)] >>> names[:4] [u'Montag', u'Dienstag', u'Mittwoch', u'Donnerstag'] >>> names[4:] [u'Freitag', u'Samstag', u'Sonntag'] - >>> abbrs = [ctx.days[u'abbreviated'][type] for type in xrange(1,8)] + >>> abbrs = [ctx.days[u'abbreviated'][type] for type in range(1,8)] >>> abbrs [u'Mo', u'Di', u'Mi', u'Do', u'Fr', u'Sa', u'So'] @@ -496,14 +496,14 @@ class LocaleFactory(object): abbreviations:: >>> names = [calendar.days.get(type, (None, None))[0] - ... for type in xrange(1, 8)] + ... for type in range(1, 8)] >>> names[:4] [u'Montag', u'Dienstag', u'Mittwoch', u'Donnerstag'] >>> names[4:] [u'Freitag', u'Samstag', u'Sonntag'] >>> abbrs = [calendar.days.get(type, (None, None))[1] - ... for type in xrange(1, 8)] + ... for type in range(1, 8)] >>> abbrs [u'Mo', u'Di', u'Mi', u'Do', u'Fr', u'Sa', u'So'] """ @@ -561,7 +561,7 @@ class LocaleFactory(object): # Put the info together calendar.days = InheritingDictionary() - for type in xrange(1, 13): + for type in range(1, 13): calendar.days[type] = (names.get(type, None), abbrs.get(type, None)) diff --git a/src/zope/i18n/simpletranslationdomain.py b/src/zope/i18n/simpletranslationdomain.py index 448da5e..1fb16f5 100644 --- a/src/zope/i18n/simpletranslationdomain.py +++ b/src/zope/i18n/simpletranslationdomain.py @@ -13,11 +13,16 @@ ############################################################################## """This is a simple implementation of the ITranslationDomain interface. """ +import sys + from zope.interface import implementer from zope.component import getUtility from zope.i18n.interfaces import ITranslationDomain, INegotiator from zope.i18n import interpolate +PY3 = sys.version_info[0] == 3 +if PY3: + unicode = str @implementer(ITranslationDomain) class SimpleTranslationDomain(object): diff --git a/src/zope/i18n/testing.py b/src/zope/i18n/testing.py index ca09d08..293928b 100644 --- a/src/zope/i18n/testing.py +++ b/src/zope/i18n/testing.py @@ -13,15 +13,15 @@ ############################################################################## """Unit test logic for setting up and tearing down basic infrastructure """ -import zope.component -from zope.publisher.browser import BrowserLanguages -from zope.publisher.http import HTTPCharsets +import sys +import re -def setUp(test=None): - zope.component.provideAdapter(HTTPCharsets) - zope.component.provideAdapter(BrowserLanguages) - -class PlacelessSetup(object): - - def setUp(self): - setUp() +if sys.version_info[0] == 2: + import doctest + unicode_checker = doctest.OutputChecker() +else: + from zope.testing import renormalizing + rules = [(re.compile("u('.*?')"), r"\1"), + (re.compile('u(".*?")'), r"\1"), + ] + unicode_checker = renormalizing.RENormalizing(rules) diff --git a/src/zope/i18n/tests/test.py b/src/zope/i18n/tests/test.py index 0333dc1..998bd6e 100644 --- a/src/zope/i18n/tests/test.py +++ b/src/zope/i18n/tests/test.py @@ -17,10 +17,12 @@ import unittest import doctest from zope.component.testing import setUp, tearDown +from zope.i18n.testing import unicode_checker def test_suite(): - return doctest.DocTestSuite("zope.i18n", setUp=setUp, tearDown=tearDown) + return doctest.DocTestSuite("zope.i18n", setUp=setUp, tearDown=tearDown, + checker=unicode_checker) if __name__ == '__main__': diff --git a/src/zope/i18n/tests/test_formats.py b/src/zope/i18n/tests/test_formats.py index 114a771..0c260b4 100644 --- a/src/zope/i18n/tests/test_formats.py +++ b/src/zope/i18n/tests/test_formats.py @@ -171,13 +171,13 @@ class TestDateTimePatternParser(TestCase): # Quote not closed try: parseDateTimePattern("HH' Uhr") - except DateTimePatternParseError, err: + except DateTimePatternParseError as err: self.assertEqual( str(err), 'The quote starting at character 2 is not closed.') # Test correct length of characters in datetime fields try: parseDateTimePattern("HHHHH") - except DateTimePatternParseError, err: + except DateTimePatternParseError as err: self.assert_(str(err).endswith('You have: 5')) @@ -261,20 +261,20 @@ class TestDateTimeFormat(TestCase): # German short self.assertEqual( self.format.parse('02.01.03 21:48', 'dd.MM.yy HH:mm'), - datetime.datetime(2003, 01, 02, 21, 48)) + datetime.datetime(2003, 1, 2, 21, 48)) def testParseRealDateTime(self): # German medium self.assertEqual( self.format.parse('02.01.2003 21:48:01', 'dd.MM.yyyy HH:mm:ss'), - datetime.datetime(2003, 01, 02, 21, 48, 01)) + datetime.datetime(2003, 1, 2, 21, 48, 1)) # German long # TODO: The parser does not support timezones yet. self.assertEqual(self.format.parse( '2. Januar 2003 21:48:01 +100', 'd. MMMM yyyy HH:mm:ss z'), - datetime.datetime(2003, 01, 02, 21, 48, 01, + datetime.datetime(2003, 1, 2, 21, 48, 1, tzinfo=pytz.timezone('Europe/Berlin'))) # German full @@ -282,13 +282,13 @@ class TestDateTimeFormat(TestCase): self.assertEqual(self.format.parse( 'Donnerstag, 2. Januar 2003 21:48 Uhr +100', "EEEE, d. MMMM yyyy H:mm' Uhr 'z"), - datetime.datetime(2003, 01, 02, 21, 48, + datetime.datetime(2003, 1, 2, 21, 48, tzinfo=pytz.timezone('Europe/Berlin'))) def testParseAMPMDateTime(self): self.assertEqual( self.format.parse('02.01.03 09:48 nachm.', 'dd.MM.yy hh:mm a'), - datetime.datetime(2003, 01, 02, 21, 48)) + datetime.datetime(2003, 1, 2, 21, 48)) def testParseTimeZone(self): dt = self.format.parse('09:48 -600', 'HH:mm z') @@ -352,28 +352,28 @@ class TestDateTimeFormat(TestCase): def testParse12PM(self): self.assertEqual( self.format.parse('01.01.03 12:00 nachm.', 'dd.MM.yy hh:mm a'), - datetime.datetime(2003, 01, 01, 12, 00, 00, 00)) + datetime.datetime(2003, 1, 1, 12, 00, 00, 00)) def testParseUnusualFormats(self): self.assertEqual( self.format.parse('001. Januar 03 0012:00', 'ddd. MMMMM yy HHHH:mm'), - datetime.datetime(2003, 01, 01, 12, 00, 00, 00)) + datetime.datetime(2003, 1, 1, 12, 00, 00, 00)) self.assertEqual( self.format.parse('0001. Jan 2003 0012:00 vorm.', 'dddd. MMM yyyy hhhh:mm a'), - datetime.datetime(2003, 01, 01, 00, 00, 00, 00)) + datetime.datetime(2003, 1, 1, 00, 00, 00, 00)) def testFormatSimpleDateTime(self): # German short self.assertEqual( - self.format.format(datetime.datetime(2003, 01, 02, 21, 48), + self.format.format(datetime.datetime(2003, 1, 2, 21, 48), 'dd.MM.yy HH:mm'), '02.01.03 21:48') def testFormatRealDateTime(self): tz = pytz.timezone('Europe/Berlin') - dt = datetime.datetime(2003, 01, 02, 21, 48, 01, tzinfo=tz) + dt = datetime.datetime(2003, 1, 2, 21, 48, 1, tzinfo=tz) # German medium self.assertEqual( self.format.format(dt, 'dd.MM.yyyy HH:mm:ss'), @@ -391,47 +391,47 @@ class TestDateTimeFormat(TestCase): def testFormatAMPMDateTime(self): self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 21, 48), + datetime.datetime(2003, 1, 2, 21, 48), 'dd.MM.yy hh:mm a'), '02.01.03 09:48 nachm.') def testFormatAllWeekdays(self): for day in range(1, 8): self.assertEqual(self.format.format( - datetime.datetime(2003, 01, day+5, 21, 48), + datetime.datetime(2003, 1, day+5, 21, 48), "EEEE, d. MMMM yyyy H:mm' Uhr 'z"), '%s, %i. Januar 2003 21:48 Uhr +000' %( self.format.calendar.days[day][0], day+5)) def testFormatTimeZone(self): self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 12, 00), 'z'), + datetime.datetime(2003, 1, 2, 12, 00), 'z'), '+000') self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 12, 00), 'zz'), + datetime.datetime(2003, 1, 2, 12, 00), 'zz'), '+00:00') self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 12, 00), 'zzz'), + datetime.datetime(2003, 1, 2, 12, 00), 'zzz'), 'UTC') self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 12, 00), 'zzzz'), + datetime.datetime(2003, 1, 2, 12, 00), 'zzzz'), 'UTC') tz = pytz.timezone('US/Eastern') self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 12, tzinfo=tz), 'z'), + datetime.datetime(2003, 1, 2, 12, tzinfo=tz), 'z'), '-500') self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 12, tzinfo=tz), 'zz'), + datetime.datetime(2003, 1, 2, 12, tzinfo=tz), 'zz'), '-05:00') self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 12, tzinfo=tz), 'zzz'), + datetime.datetime(2003, 1, 2, 12, tzinfo=tz), 'zzz'), 'EST') self.assertEqual(self.format.format( - datetime.datetime(2003, 01, 02, 12, tzinfo=tz), 'zzzz'), + datetime.datetime(2003, 1, 2, 12, tzinfo=tz), 'zzzz'), 'US/Eastern') def testFormatWeekDay(self): - date = datetime.date(2003, 01, 02) + date = datetime.date(2003, 1, 2) self.assertEqual(self.format.format(date, "E"), '4') self.assertEqual(self.format.format(date, "EE"), @@ -455,7 +455,7 @@ class TestDateTimeFormat(TestCase): '05') def testFormatDayOfWeekInMonth(self): - date = datetime.date(2003, 01, 02) + date = datetime.date(2003, 1, 2) self.assertEqual(self.format.format(date, "F"), '1') self.assertEqual(self.format.format(date, "FF"), @@ -526,11 +526,11 @@ class TestDateTimeFormat(TestCase): def testFormatSimpleHourRepresentation(self): self.assertEqual( - self.format.format(datetime.datetime(2003, 01, 02, 23, 00), + self.format.format(datetime.datetime(2003, 1, 2, 23, 00), 'dd.MM.yy h:mm:ss a'), '02.01.03 11:00:00 nachm.') self.assertEqual( - self.format.format(datetime.datetime(2003, 01, 02, 02, 00), + self.format.format(datetime.datetime(2003, 1, 2, 2, 00), 'dd.MM.yy h:mm:ss a'), '02.01.03 2:00:00 vorm.') self.assertEqual( diff --git a/src/zope/i18n/tests/test_itranslationdomain.py b/src/zope/i18n/tests/test_itranslationdomain.py index 93d457e..9e1775c 100644 --- a/src/zope/i18n/tests/test_itranslationdomain.py +++ b/src/zope/i18n/tests/test_itranslationdomain.py @@ -13,6 +13,7 @@ ############################################################################## """This is an 'abstract' test for the ITranslationDomain interface. """ +import sys import unittest from zope.interface.verify import verifyObject from zope.interface import implementer @@ -24,6 +25,9 @@ from zope.i18n.negotiator import negotiator from zope.i18n.interfaces import INegotiator, IUserPreferredLanguages from zope.i18n.interfaces import ITranslationDomain +PY3 = sys.version_info[0] == 3 +if PY3: + unicode = str @implementer(IUserPreferredLanguages) class Environment(object): diff --git a/src/zope/i18n/tests/test_testmessagecatalog.py b/src/zope/i18n/tests/test_testmessagecatalog.py index e868310..62c2dd8 100644 --- a/src/zope/i18n/tests/test_testmessagecatalog.py +++ b/src/zope/i18n/tests/test_testmessagecatalog.py @@ -15,9 +15,11 @@ import unittest import doctest +from zope.i18n.testing import unicode_checker + def test_suite(): return unittest.TestSuite(( - doctest.DocFileSuite('../testmessagecatalog.txt'), + doctest.DocFileSuite('../testmessagecatalog.txt', checker=unicode_checker), )) if __name__ == '__main__': diff --git a/src/zope/i18n/tests/test_zcml.py b/src/zope/i18n/tests/test_zcml.py index c32e087..fc9d90c 100644 --- a/src/zope/i18n/tests/test_zcml.py +++ b/src/zope/i18n/tests/test_zcml.py @@ -13,6 +13,7 @@ ############################################################################## """Test the gts ZCML namespace directives. """ +import sys import doctest import os import shutil @@ -27,6 +28,10 @@ import zope.i18n.tests from zope.i18n.interfaces import ITranslationDomain from zope.i18n import config +PY3 = sys.version_info[0] == 3 +if PY3: + unicode = str + template = """\ <configure xmlns='http://namespaces.zope.org/zope' diff --git a/src/zope/i18n/tests/testii18naware.py b/src/zope/i18n/tests/testii18naware.py index 83e0864..cc37ef8 100644 --- a/src/zope/i18n/tests/testii18naware.py +++ b/src/zope/i18n/tests/testii18naware.py @@ -15,10 +15,6 @@ """ import unittest -def sorted(list): - list.sort() - return list - class TestII18nAware(unittest.TestCase): def setUp(self): diff --git a/src/zope/i18n/translationdomain.py b/src/zope/i18n/translationdomain.py index dfc7f41..6629c9e 100644 --- a/src/zope/i18n/translationdomain.py +++ b/src/zope/i18n/translationdomain.py @@ -13,6 +13,8 @@ ############################################################################## """Global Translation Service for providing I18n to file-based code. """ +import sys + import zope.component from zope.i18nmessageid import Message from zope.i18n import translate, interpolate @@ -29,6 +31,9 @@ from zope.i18n.interfaces import ITranslationDomain, INegotiator # message in a catalog is not translated, tough luck, you get the msgid. LANGUAGE_FALLBACKS = ['en'] +PY3 = sys.version_info[0] == 3 +if PY3: + unicode = str class TranslationDomain(SimpleTranslationDomain): @@ -0,0 +1,12 @@ +# content of: tox.ini , put in same dir as setup.py +[tox] +envlist = py26,py27,py33 + +[testenv] +deps=zope.testrunner + zope.testing + python-gettext + zope.configuration + zope.security + +commands=zope-testrunner --all --test-path=src -v |