From 5e1cd72d4db7cf076e34bb6d86fd03b683ab43a2 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 2 Sep 2021 10:30:50 +0200 Subject: Configuring for pure-python --- .coveragerc | 19 ---- .editorconfig | 39 ++++++++ .github/workflows/tests.yml | 63 +++++++++++++ .gitignore | 41 ++++++--- .meta.toml | 20 +++++ .travis.yml | 21 ----- MANIFEST.in | 26 ++---- bootstrap.py | 210 -------------------------------------------- setup.cfg | 11 +++ tox.ini | 86 ++++++++++++++---- 10 files changed, 234 insertions(+), 302 deletions(-) delete mode 100644 .coveragerc create mode 100644 .editorconfig create mode 100644 .github/workflows/tests.yml create mode 100644 .meta.toml delete mode 100644 .travis.yml delete mode 100644 bootstrap.py diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index b5ae109..0000000 --- a/.coveragerc +++ /dev/null @@ -1,19 +0,0 @@ -[run] -source = zope.i18n -omit = - */flycheck_*py - -[paths] -source = - src/ - .tox/*/lib/python*/site-packages/ - .tox/pypy*/site-packages/ - -[report] -precision = 2 -exclude_lines = - pragma: no cover - if __name__ == '__main__': - raise NotImplementedError - self.fail - raise AssertionError diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c5508b9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,39 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +# +# EditorConfig Configuration file, for more details see: +# http://EditorConfig.org +# EditorConfig is a convention description, that could be interpreted +# by multiple editors to enforce common coding conventions for specific +# file types + +# top-most EditorConfig file: +# Will ignore other EditorConfig files in Home directory or upper tree level. +root = true + + +[*] # For All Files +# Unix-style newlines with a newline ending every file +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +# Set default charset +charset = utf-8 +# Indent style default +indent_style = space +# Max Line Length - a hard line wrap, should be disabled +max_line_length = off + +[*.{py,cfg,ini}] +# 4 space indentation +indent_size = 4 + +[*.{yml,zpt,pt,dtml,zcml}] +# 2 space indentation +indent_size = 2 + +[{Makefile,.gitmodules}] +# Tab indentation (no size specified, but view as 4 spaces) +indent_style = tab +indent_size = unset +tab_width = unset diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..9ea114e --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,63 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +name: tests + +on: + push: + pull_request: + schedule: + - cron: '0 12 * * 0' # run once a week on Sunday + # Allow to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build: + strategy: + # We want to see all failures: + fail-fast: false + matrix: + os: + - ubuntu + config: + # [Python version, tox env] + - ["3.8", "lint"] + - ["2.7", "py27"] + - ["3.5", "py35"] + - ["3.6", "py36"] + - ["3.7", "py37"] + - ["3.8", "py38"] + - ["3.9", "py39"] + - ["pypy2", "pypy"] + - ["pypy3", "pypy3"] + - ["3.8", "docs"] + - ["3.8", "coverage"] + + runs-on: ${{ matrix.os }}-latest + name: ${{ matrix.config[1] }} + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.config[0] }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles('setup.*', 'tox.ini') }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.config[0] }}- + ${{ runner.os }}-pip- + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + - name: Test + run: tox -e ${{ matrix.config[1] }} + - name: Coverage + if: matrix.config[1] == 'coverage' + run: | + pip install coveralls coverage-python-version + coveralls --service=github + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index fec8ebe..c724a76 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,31 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +*.dll +*.egg-info/ +*.profraw *.pyc +*.pyo *.so -*.dll -*.mo -__pycache__ -src/*.egg-info - -.installed.cfg -.tox -bin -build -develop-eggs -parts -docs/_build/ .coverage +.coverage.* +.eggs/ +.installed.cfg +.mr.developer.cfg +.tox/ +.vscode/ +__pycache__/ +bin/ +build/ coverage.xml -nosetests.xml -htmlcov/ +develop-eggs/ +develop/ +dist/ +docs/_build +eggs/ +etc/ +lib/ +lib64 +log/ +parts/ +pyvenv.cfg +var/ diff --git a/.meta.toml b/.meta.toml new file mode 100644 index 0000000..4a7e6d4 --- /dev/null +++ b/.meta.toml @@ -0,0 +1,20 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +[meta] +template = "pure-python" +commit-id = "7f5b73fe9d2bcbabafaef5f69dd97408a142d42a" + +[python] +with-appveyor = false +with-windows = false +with-pypy = true +with-future-python = false +with-legacy-python = true +with-docs = true +with-sphinx-doctests = false + +[tox] +use-flake8 = true + +[coverage] +fail-under = 100 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7dccb10..0000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: python -dist: xenial -python: - - 2.7 - - 3.5 - - 3.6 - - 3.7 - - pypy - - pypy3 -install: - - pip install -U pip setuptools - - pip install -U coverage coveralls - - pip install -U -e .[test,docs] -script: - - coverage run -m zope.testrunner --test-path=src - - coverage run -a -m sphinx -b doctest -d docs/_build/doctrees docs docs/_build/doctest -after_success: - - coveralls -notifications: - email: false -cache: pip diff --git a/MANIFEST.in b/MANIFEST.in index e4564d6..38e9c74 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,25 +1,13 @@ -include *.txt +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python include *.rst -include *.py -include *.ini +include *.txt include buildout.cfg -include .travis.yml include tox.ini -include .coveragerc - -recursive-include src *.txt *.py *.dtd *.xml *.html *.po *.mo *.in *.zcml -recursive-include src *.py -recursive-include src *.dtd -recursive-include src *.xml -recursive-include src *.html -recursive-include src *.po -recursive-include src *.mo -recursive-include src *.in -recursive-include src *.zcml -recursive-include src *.rst -recursive-include src/zope/i18n/tests *.mo -recursive-include docs *.rst recursive-include docs *.py -recursive-include docs *.bat +recursive-include docs *.rst +recursive-include docs *.txt recursive-include docs Makefile + +recursive-include src *.py diff --git a/bootstrap.py b/bootstrap.py deleted file mode 100644 index a459921..0000000 --- a/bootstrap.py +++ /dev/null @@ -1,210 +0,0 @@ -############################################################################## -# -# Copyright (c) 2006 Zope Foundation 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. -# -############################################################################## -"""Bootstrap a buildout-based project - -Simply run this script in a directory containing a buildout.cfg. -The script accepts buildout command-line options, so you can -use the -c option to specify an alternate configuration file. -""" - -import os -import shutil -import sys -import tempfile - -from optparse import OptionParser - -__version__ = '2015-07-01' -# See zc.buildout's changelog if this version is up to date. - -tmpeggs = tempfile.mkdtemp(prefix='bootstrap-') - -usage = '''\ -[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] - -Bootstraps a buildout-based project. - -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 --find-links to point to local resources, you can keep -this script from going over the network. -''' - -parser = OptionParser(usage=usage) -parser.add_option("--version", - action="store_true", default=False, - help=("Return bootstrap.py 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")) -parser.add_option("--allow-site-packages", - action="store_true", default=False, - help=("Let bootstrap.py use existing site packages")) -parser.add_option("--buildout-version", - help="Use a specific zc.buildout version") -parser.add_option("--setuptools-version", - help="Use a specific setuptools version") -parser.add_option("--setuptools-to-dir", - help=("Allow for re-use of existing directory of " - "setuptools versions")) - -options, args = parser.parse_args() -if options.version: - print("bootstrap.py version %s" % __version__) - sys.exit(0) - - -###################################################################### -# load/install setuptools - -try: - from urllib.request import urlopen -except ImportError: - from urllib2 import urlopen - -ez = {} -if os.path.exists('ez_setup.py'): - exec(open('ez_setup.py').read(), ez) -else: - exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez) - -if not options.allow_site_packages: - # ez_setup imports site, which adds site packages - # this will remove them from the path to ensure that incompatible versions - # of setuptools are not in the path - import site - # inside a virtualenv, there is no 'getsitepackages'. - # We can't remove these reliably - if hasattr(site, 'getsitepackages'): - for sitepackage_path in site.getsitepackages(): - # Strip all site-packages directories from sys.path that - # are not sys.prefix; this is because on Windows - # sys.prefix is a site-package directory. - if sitepackage_path != sys.prefix: - sys.path[:] = [x for x in sys.path - if sitepackage_path not in x] - -setup_args = dict(to_dir=tmpeggs, download_delay=0) - -if options.setuptools_version is not None: - setup_args['version'] = options.setuptools_version -if options.setuptools_to_dir is not None: - setup_args['to_dir'] = options.setuptools_to_dir - -ez['use_setuptools'](**setup_args) -import setuptools -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 - -setuptools_path = ws.find( - pkg_resources.Requirement.parse('setuptools')).location - -# Fix sys.path here as easy_install.pth added before PYTHONPATH -cmd = [sys.executable, '-c', - 'import sys; sys.path[0:0] = [%r]; ' % setuptools_path + - '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]) - -requirement = 'zc.buildout' -version = options.buildout_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): - try: - return not parsed_version.is_prerelease - except AttributeError: - # Older setuptools - 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=[setuptools_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) != 0: - raise Exception( - "Failed to execute command:\n%s" % repr(cmd)[1:-1]) - -###################################################################### -# Import and run buildout - -ws.add_entry(tmpeggs) -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) diff --git a/setup.cfg b/setup.cfg index 2a9acf1..264b78c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,13 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python [bdist_wheel] universal = 1 + +[flake8] +doctests = 1 + +[check-manifest] +ignore = + .editorconfig + .meta.toml + docs/_build/html/_sources/* diff --git a/tox.ini b/tox.ini index 757b7d4..fd22c86 100644 --- a/tox.ini +++ b/tox.ini @@ -1,32 +1,80 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python [tox] +minversion = 3.18 envlist = - py27,py35,py36,py37,pypy,pypy3,coverage,docs + lint + py27 + py35 + py36 + py37 + py38 + py39 + pypy + pypy3 + docs + coverage [testenv] +usedevelop = true +deps = commands = - zope-testrunner --test-path=src {posargs:-pvc} - sphinx-build -b doctest -d {envdir}/doctrees docs {envdir}/doctest + zope-testrunner --test-path=src {posargs:-vc} extras = test - docs - compile -[testenv:coverage] -usedevelop = true -basepython = - python3.6 -commands = - coverage erase - coverage run -p -m zope.testrunner --test-path=src {posargs:-pvc} - coverage run -p -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest - coverage combine - coverage report --fail-under=100 +[testenv:lint] +basepython = python3 +skip_install = true deps = - coverage -parallel_show_output = true + flake8 + check-manifest + check-python-versions + wheel +commands = + flake8 src setup.py + check-manifest + check-python-versions [testenv:docs] -basepython = - python3.6 +basepython = python3 +skip_install = false +# Until repoze.sphinx.autointerface supports Sphinx 4.x we cannot use it: +deps = Sphinx < 4 +extras = + docs +commands_pre = commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html + +[testenv:coverage] +basepython = python3 +allowlist_externals = + mkdir +deps = + coverage + coverage-python-version +commands = + mkdir -p {toxinidir}/parts/htmlcov + coverage run -m zope.testrunner --test-path=src {posargs:-vc} + coverage html + coverage report -m --fail-under=0 + +[coverage:run] +branch = True +plugins = coverage_python_version +source = zope.i18n + +[coverage:report] +precision = 2 +exclude_lines = + pragma: no cover + pragma: nocover + except ImportError: + raise NotImplementedError + if __name__ == '__main__': + self.fail + raise AssertionError + +[coverage:html] +directory = parts/htmlcov -- cgit v1.2.1 From 4e15ebd90d5b31e6fe5161c5aac14e5d038adc85 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Fri, 3 Sep 2021 10:07:09 +0200 Subject: autopep8 --- docs/conf.py | 6 +-- setup.py | 7 +++- src/zope/i18n/compile.py | 5 ++- src/zope/i18n/config.py | 3 +- src/zope/i18n/format.py | 43 +++++++++++----------- src/zope/i18n/interfaces/__init__.py | 3 -- src/zope/i18n/interfaces/locales.py | 16 +++++--- src/zope/i18n/locales/__init__.py | 10 +++-- src/zope/i18n/locales/fallbackcollator.py | 1 + src/zope/i18n/locales/inheritance.py | 9 ++--- src/zope/i18n/locales/provider.py | 2 +- src/zope/i18n/locales/tests/test_docstrings.py | 4 +- .../i18n/locales/tests/test_fallbackcollator.py | 8 ++-- src/zope/i18n/locales/tests/test_locales.py | 2 + src/zope/i18n/locales/tests/test_xmlfactory.py | 10 ++--- src/zope/i18n/locales/xmlfactory.py | 38 ++++++------------- src/zope/i18n/testmessagecatalog.py | 5 ++- src/zope/i18n/tests/test.py | 1 + src/zope/i18n/tests/test_formats.py | 12 +++--- src/zope/i18n/tests/test_gettextmessagecatalog.py | 1 - src/zope/i18n/tests/test_imessagecatalog.py | 4 +- src/zope/i18n/tests/test_itranslationdomain.py | 5 ++- src/zope/i18n/tests/test_negotiator.py | 16 ++++---- src/zope/i18n/tests/test_plurals.py | 6 +-- src/zope/i18n/tests/test_testmessagecatalog.py | 2 + src/zope/i18n/tests/test_translationdomain.py | 2 +- src/zope/i18n/tests/test_zcml.py | 1 + src/zope/i18n/tests/testi18nawareobject.py | 4 +- src/zope/i18n/zcml.py | 4 +- 29 files changed, 120 insertions(+), 110 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 0ed66d4..f6fff3f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ import pkg_resources # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) +# sys.path.append(os.path.abspath('.')) sys.path.append(os.path.abspath('../src')) rqmt = pkg_resources.require('zope.i18n')[0] @@ -183,8 +183,8 @@ htmlhelp_basename = 'zopei18ndoc' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'zopei18n.tex', u'zope.i18n Documentation', - u'Zope Foundation and Contributors', 'manual'), + ('index', 'zopei18n.tex', u'zope.i18n Documentation', + u'Zope Foundation and Contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/setup.py b/setup.py index dc3b83c..297b18d 100644 --- a/setup.py +++ b/setup.py @@ -21,10 +21,12 @@ import os from setuptools import setup, find_packages + def read(*rnames): with open(os.path.join(os.path.dirname(__file__), *rnames)) as f: return f.read() + def alltests(): import sys import unittest @@ -39,6 +41,7 @@ def alltests(): suites = list(zope.testrunner.find.find_suites(options)) return unittest.TestSuite(suites) + COMPILE_REQUIRES = [ # python-gettext used to be here, but it's now # a fixed requirement. Keep the extra to avoid @@ -93,7 +96,7 @@ setup( url='https://github.com/zopefoundation/zope.i18n', packages=find_packages('src'), package_dir={'': 'src'}, - namespace_packages=['zope',], + namespace_packages=['zope', ], install_requires=[ 'setuptools', 'python-gettext', @@ -116,4 +119,4 @@ setup( test_suite='__main__.alltests', include_package_data=True, zip_safe=False, - ) +) diff --git a/src/zope/i18n/compile.py b/src/zope/i18n/compile.py index 834bf24..441523d 100644 --- a/src/zope/i18n/compile.py +++ b/src/zope/i18n/compile.py @@ -11,12 +11,14 @@ logger = logging.getLogger('zope.i18n') HAS_PYTHON_GETTEXT = True + def _safe_mtime(path): try: return os.path.getmtime(path) except (IOError, OSError): return None + def compile_mo_file(domain, lc_messages_path): """Creates or updates a mo file in the locales folder.""" @@ -44,6 +46,7 @@ def compile_mo_file(domain, lc_messages_path): with open(mofile, 'wb') as fd: fd.write(mo.read()) except PoSyntaxError as err: - logger.warning('Syntax error while compiling %s (%s).', pofile, err.msg) + logger.warning( + 'Syntax error while compiling %s (%s).', pofile, err.msg) except (IOError, OSError) as err: logger.warning('Error while compiling %s (%s).', pofile, err) diff --git a/src/zope/i18n/config.py b/src/zope/i18n/config.py index 1636083..b0068c5 100644 --- a/src/zope/i18n/config.py +++ b/src/zope/i18n/config.py @@ -45,4 +45,5 @@ def _parse_languages(value): #: A set of languages that `zope.i18n.negotiate` will pass to the #: `zope.i18n.interfaces.INegotiator` utility. If this is None, #: no utility will be used. -ALLOWED_LANGUAGES = _parse_languages(os.environ.get(ALLOWED_LANGUAGES_KEY, None)) +ALLOWED_LANGUAGES = _parse_languages( + os.environ.get(ALLOWED_LANGUAGES_KEY, None)) diff --git a/src/zope/i18n/format.py b/src/zope/i18n/format.py index abc3e50..7b9ba4a 100644 --- a/src/zope/i18n/format.py +++ b/src/zope/i18n/format.py @@ -31,7 +31,7 @@ NATIVE_NUMBER_TYPES = (int, float) try: NATIVE_NUMBER_TYPES += (long,) except NameError: - pass # Py3 + pass # Py3 def roundHalfUp(n): @@ -139,10 +139,11 @@ class DateTimeFormat(object): if not ampm_entry: raise DateTimeParseError( 'Cannot handle 12-hour format without am/pm marker.') - ampm = self.calendar.pm == results[bin_pattern.index(ampm_entry[0])] + ampm = self.calendar.pm == results[bin_pattern.index( + ampm_entry[0])] if hour == 12: ampm = not ampm - ordered[3] = (hour + 12*ampm)%24 + ordered[3] = (hour + 12*ampm) % 24 # Shortcut for the simple int functions dt_fields_map = {'d': 2, 'H': 3, 'm': 4, 's': 5, 'S': 6} @@ -155,7 +156,7 @@ class DateTimeFormat(object): # Handle timezones tzinfo = None - pytz_tzinfo = False # If True, we should use pytz specific syntax + pytz_tzinfo = False # If True, we should use pytz specific syntax tz_entry = _findFormattingCharacterInPattern('z', bin_pattern) if ordered[3:] != [None, None, None, None] and tz_entry: length = tz_entry[0][1] @@ -189,7 +190,7 @@ class DateTimeFormat(object): datetime.date.today(), datetime.time(*[e or 0 for e in ordered[3:]]))).timetz() return datetime.time( - *[e or 0 for e in ordered[3:]], **{'tzinfo' :tzinfo} + *[e or 0 for e in ordered[3:]], **{'tzinfo': tzinfo} ) if pytz_tzinfo: @@ -198,7 +199,7 @@ class DateTimeFormat(object): )) return datetime.datetime( - *[e or 0 for e in ordered], **{'tzinfo' :tzinfo} + *[e or 0 for e in ordered], **{'tzinfo': tzinfo} ) def format(self, obj, pattern=None): @@ -282,19 +283,19 @@ class NumberFormat(object): if bin_pattern[sign][GROUPING]: regex += self.symbols['group'] min_size += min_size/3 - regex += ']{%i,100}' %(min_size) + regex += ']{%i,100}' % (min_size) if bin_pattern[sign][FRACTION]: max_precision = len(bin_pattern[sign][FRACTION]) min_precision = bin_pattern[sign][FRACTION].count('0') regex += '['+self.symbols['decimal']+']?' - regex += '[0-9]{%i,%i}' %(min_precision, max_precision) + regex += '[0-9]{%i,%i}' % (min_precision, max_precision) if bin_pattern[sign][EXPONENTIAL] != '': regex += self.symbols['exponential'] min_exp_size = bin_pattern[sign][EXPONENTIAL].count('0') pre_symbols = self.symbols['minusSign'] if bin_pattern[sign][EXPONENTIAL][0] == '+': pre_symbols += self.symbols['plusSign'] - regex += '[%s]?[0-9]{%i,100}' %(pre_symbols, min_exp_size) + regex += '[%s]?[0-9]{%i,100}' % (pre_symbols, min_exp_size) regex += ')' if bin_pattern[sign][PADDING3] is not None: regex += '[' + bin_pattern[sign][PADDING3] + ']+' @@ -353,7 +354,7 @@ class NumberFormat(object): fractionLen = len(fraction) rounded = int(fraction) + 1 fraction = ('%0' + str(fractionLen) + 'i') % rounded - if len(fraction) > fractionLen: # rounded fraction >= 1 + if len(fraction) > fractionLen: # rounded fraction >= 1 roundInt = True fraction = fraction[1:] else: @@ -494,7 +495,7 @@ class NumberFormat(object): if bin_pattern[PADDING2] is not None and pre_padding > 0: if bin_pattern[PADDING1] is not None: text += bin_pattern[PADDING2] - else: # pragma: no cover + else: # pragma: no cover text += bin_pattern[PADDING2] * pre_padding text += number if bin_pattern[PADDING3] is not None and post_padding > 0: @@ -578,7 +579,7 @@ def parseDateTimePattern(pattern, DATETIMECHARS="aGyMdEDFwWhHmsSkKz"): # Some cleaning up if state == IN_QUOTE: - if quote_start == -1: # pragma: no cover + if quote_start == -1: # pragma: no cover # It should not be possible to get into this state. # The only time we set quote_start to -1 we also set the state # to DEFAULT. @@ -605,7 +606,7 @@ def buildDateTimeParseInfo(calendar, pattern): for entry in _findFormattingCharacterInPattern(field, pattern): # The maximum amount of digits should be infinity, but 1000 is # close enough here. - info[entry] = r'([0-9]{%i,1000})' %entry[1] + info[entry] = r'([0-9]{%i,1000})' % entry[1] # year (Number) for entry in _findFormattingCharacterInPattern('y', pattern): @@ -618,12 +619,12 @@ def buildDateTimeParseInfo(calendar, pattern): # am/pm marker (Text) for entry in _findFormattingCharacterInPattern('a', pattern): - info[entry] = r'(%s|%s)' %(calendar.am, calendar.pm) + info[entry] = r'(%s|%s)' % (calendar.am, calendar.pm) # era designator (Text) # TODO: works for gregorian only right now for entry in _findFormattingCharacterInPattern('G', pattern): - info[entry] = r'(%s|%s)' %(calendar.eras[1][1], calendar.eras[2][1]) + info[entry] = r'(%s|%s)' % (calendar.eras[1][1], calendar.eras[2][1]) # time zone (Text) for entry in _findFormattingCharacterInPattern('z', pattern): @@ -676,7 +677,7 @@ def buildDateTimeInfo(dt, calendar, pattern): else: ampm = calendar.am - h = dt.hour%12 + h = dt.hour % 12 if h == 0: h = 12 @@ -693,7 +694,7 @@ def buildDateTimeInfo(dt, calendar, pattern): tz_mins = int(math.fabs(tz_secs % 3600 / 60)) tz_hours = int(math.fabs(tz_secs / 3600)) tz_sign = '-' if tz_secs < 0 else '+' - tz_defaultname = "%s%i%.2i" %(tz_sign, tz_hours, tz_mins) + tz_defaultname = "%s%i%.2i" % (tz_sign, tz_hours, tz_mins) tz_name = tzinfo.tzname(dt) or tz_defaultname tz_fullname = getattr(tzinfo, 'zone', None) or tz_name @@ -705,12 +706,12 @@ def buildDateTimeInfo(dt, calendar, pattern): # Generic Numbers for field, value in (('d', dt.day), ('D', int(dt.strftime('%j'))), ('F', day_of_week_in_month), ('k', dt.hour or 24), - ('K', dt.hour%12), ('h', h), ('H', dt.hour), + ('K', dt.hour % 12), ('h', h), ('H', dt.hour), ('m', dt.minute), ('s', dt.second), ('S', dt.microsecond), ('w', int(dt.strftime('%W'))), ('W', week_in_month)): for entry in _findFormattingCharacterInPattern(field, pattern): - info[entry] = (u"%%.%ii" %entry[1]) %value + info[entry] = (u"%%.%ii" % entry[1]) % value # am/pm marker (Text) for entry in _findFormattingCharacterInPattern('a', pattern): @@ -724,9 +725,9 @@ def buildDateTimeInfo(dt, calendar, pattern): # time zone (Text) for entry in _findFormattingCharacterInPattern('z', pattern): if entry[1] == 1: - info[entry] = u"%s%i%.2i" %(tz_sign, tz_hours, tz_mins) + info[entry] = u"%s%i%.2i" % (tz_sign, tz_hours, tz_mins) elif entry[1] == 2: - info[entry] = u"%s%.2i:%.2i" %(tz_sign, tz_hours, tz_mins) + info[entry] = u"%s%.2i:%.2i" % (tz_sign, tz_hours, tz_mins) elif entry[1] == 3: info[entry] = tz_name else: diff --git a/src/zope/i18n/interfaces/__init__.py b/src/zope/i18n/interfaces/__init__.py index c5a3328..e717108 100644 --- a/src/zope/i18n/interfaces/__init__.py +++ b/src/zope/i18n/interfaces/__init__.py @@ -203,7 +203,6 @@ class IMessageImportFilter(Interface): Classes implementing this interface should usually be Adaptors, as they adapt the IEditableTranslationService interface.""" - def importMessages(domains, languages, file): """Import all messages that are defined in the specified domains and languages. @@ -254,7 +253,6 @@ class IMessageExportFilter(Interface): Classes implementing this interface should usually be Adaptors, as they adapt the IEditableTranslationService interface.""" - def exportMessages(domains, languages): """Export all messages that are defined in the specified domains and languages. @@ -326,7 +324,6 @@ class IFormat(Interface): """Format an object to a string using the pattern as a rule.""" - class INumberFormat(IFormat): r"""Specific number formatting interface. Here are the formatting rules (I modified the rules from ICU a bit, since I think they did not diff --git a/src/zope/i18n/interfaces/locales.py b/src/zope/i18n/interfaces/locales.py index f6017ad..01c9cbe 100644 --- a/src/zope/i18n/interfaces/locales.py +++ b/src/zope/i18n/interfaces/locales.py @@ -17,7 +17,7 @@ import datetime import re from zope.interface import Interface, Attribute from zope.schema import \ - Field, Text, TextLine, Int, Bool, Tuple, List, Dict, Date + Field, Text, TextLine, Int, Bool, Tuple, List, Dict, Date from zope.schema import Choice @@ -188,7 +188,6 @@ class ILocaleTimeZone(Interface): required=True, readonly=True) - names = Dict( title=u"Time Zone Names", description=u"Various names of the timezone.", @@ -230,7 +229,7 @@ class ILocaleFormatLength(Interface): title=u"Format Length Type", description=u"Name of the format length", values=(u"full", u"long", u"medium", u"short") - ) + ) default = TextLine( title=u"Default Format", @@ -491,6 +490,7 @@ class ILocaleCurrency(Interface): symbolChoice = Bool(title=u"Symbol Choice") + class ILocaleNumbers(Interface): """This object contains various data about numbers and currencies.""" @@ -556,7 +556,6 @@ class ILocaleNumbers(Interface): description=u"Name of the format length"), value_type=Field(title=u"ILocaleCurrency object")) - def getFormatter(category, length=None, name=u""): """Get the NumberFormat based on the category, length and name of the format. @@ -577,8 +576,11 @@ class ILocaleNumbers(Interface): def getDefaultCurrency(): """Get the default currency.""" + _orientations = [u"left-to-right", u"right-to-left", u"top-to-bottom", u"bottom-to-top"] + + class ILocaleOrientation(Interface): """Information about the orientation of text.""" @@ -586,13 +588,14 @@ class ILocaleOrientation(Interface): title=u"Orientation of characters", values=_orientations, default=u"left-to-right" - ) + ) lines = Choice( title=u"Orientation of characters", values=_orientations, default=u"top-to-bottom" - ) + ) + class ILocale(Interface): """This class contains all important information about the locale. @@ -699,6 +702,7 @@ class IDictionaryInheritance(ILocaleInheritance): object is consulted. """ + class ICollator(Interface): """Provide support for collating text strings diff --git a/src/zope/i18n/locales/__init__.py b/src/zope/i18n/locales/__init__.py index 030c453..9da515a 100644 --- a/src/zope/i18n/locales/__init__.py +++ b/src/zope/i18n/locales/__init__.py @@ -29,7 +29,7 @@ from zope.i18n.interfaces.locales import ILocaleOrientation from zope.i18n.interfaces.locales import ILocaleDayContext, ILocaleMonthContext from zope.i18n.format import NumberFormat, DateTimeFormat from zope.i18n.locales.inheritance import \ - AttributeInheritance, InheritingDictionary, NoParentException + AttributeInheritance, InheritingDictionary, NoParentException from zope.i18n.locales.provider import LocaleProvider, LoadLocaleError @@ -73,6 +73,7 @@ calendarAliases = {'islamic': ('arabic',), 'islamic-civil': ('civil-arabic',), 'buddhist': ('thai-buddhist', )} + @implementer(ILocaleIdentity) class LocaleIdentity(object): """Represents a unique identification of the locale @@ -112,7 +113,7 @@ class LocaleIdentity(object): def __repr__(self): """See zope.i18n.interfaces.ILocaleIdentity """ - return "" %( + return "" % ( self.language, self.script, self.territory, self.variant) @@ -158,6 +159,7 @@ class LocaleVersion(object): return ((self.generationDate, self.number) == (other.generationDate, other.number)) + @implementer(ILocaleDisplayNames) class LocaleDisplayNames(AttributeInheritance): """Locale display names with inheritable data. @@ -233,7 +235,6 @@ class LocaleFormatLength(AttributeInheritance): """Specifies one of the format lengths of a specific quantity, like numbers, dates, times and datetimes.""" - def __init__(self, type=None): """Initialize the object.""" self.type = type @@ -652,6 +653,7 @@ class LocaleOrientation(AttributeInheritance): """Implementation of ILocaleOrientation """ + @implementer(ILocale) class Locale(AttributeInheritance): """Implementation of the ILocale interface.""" @@ -690,7 +692,7 @@ class Locale(AttributeInheritance): # Notice that 'pieces' is always empty. pieces = [key + '=' + type for (key, type) in ()] assert not pieces - if pieces: # pragma: no cover + if pieces: # pragma: no cover id_string += '@' + ','.join(pieces) return id_string diff --git a/src/zope/i18n/locales/fallbackcollator.py b/src/zope/i18n/locales/fallbackcollator.py index fc76a58..55c9b77 100644 --- a/src/zope/i18n/locales/fallbackcollator.py +++ b/src/zope/i18n/locales/fallbackcollator.py @@ -16,6 +16,7 @@ from unicodedata import normalize + class FallbackCollator: def __init__(self, locale): diff --git a/src/zope/i18n/locales/inheritance.py b/src/zope/i18n/locales/inheritance.py index 912d8c9..e597b78 100644 --- a/src/zope/i18n/locales/inheritance.py +++ b/src/zope/i18n/locales/inheritance.py @@ -24,11 +24,13 @@ from zope.deprecation import deprecate from zope.interface import implementer from zope.i18n.interfaces.locales import \ - ILocaleInheritance, IAttributeInheritance, IDictionaryInheritance + ILocaleInheritance, IAttributeInheritance, IDictionaryInheritance + class NoParentException(AttributeError): pass + @implementer(ILocaleInheritance) class Inheritance(object): """A simple base version of locale inheritance. @@ -37,7 +39,6 @@ class Inheritance(object): 'ILocaleInheritance' implementations. """ - # See zope.i18n.interfaces.locales.ILocaleInheritance __parent__ = None @@ -100,7 +101,6 @@ class AttributeInheritance(Inheritance): True """ - def __setattr__(self, name, value): """See zope.i18n.interfaces.locales.ILocaleInheritance""" # If we have a value that can also inherit data from other locales, we @@ -111,7 +111,6 @@ class AttributeInheritance(Inheritance): value.__name__ = name super(AttributeInheritance, self).__setattr__(name, value) - def __getattr__(self, name): """See zope.i18n.interfaces.locales.ILocaleInheritance""" try: @@ -134,7 +133,6 @@ class AttributeInheritance(Inheritance): return value - @implementer(IDictionaryInheritance) class InheritingDictionary(Inheritance, dict): """Implementation of a dictionary that can also inherit values. @@ -197,7 +195,6 @@ class InheritingDictionary(Inheritance, dict): `value` is a deprecated synonym for `values` """ - def __setitem__(self, name, value): """See zope.i18n.interfaces.locales.ILocaleInheritance""" if ILocaleInheritance.providedBy(value): diff --git a/src/zope/i18n/locales/provider.py b/src/zope/i18n/locales/provider.py index 3864b7a..9e7f66b 100644 --- a/src/zope/i18n/locales/provider.py +++ b/src/zope/i18n/locales/provider.py @@ -20,6 +20,7 @@ import os from zope.interface import implementer from zope.i18n.interfaces.locales import ILocaleProvider + class LoadLocaleError(Exception): """This error is raised if a locale cannot be loaded.""" @@ -28,7 +29,6 @@ class LoadLocaleError(Exception): class LocaleProvider(object): """A locale provider that gets its data from the XML data.""" - def __init__(self, locale_dir): self._locales = {} self._locale_dir = locale_dir diff --git a/src/zope/i18n/locales/tests/test_docstrings.py b/src/zope/i18n/locales/tests/test_docstrings.py index fa52078..9f75b44 100644 --- a/src/zope/i18n/locales/tests/test_docstrings.py +++ b/src/zope/i18n/locales/tests/test_docstrings.py @@ -20,6 +20,7 @@ from zope.i18n.locales.inheritance import NoParentException from zope.i18n.testing import unicode_checker + class LocaleInheritanceStub(AttributeInheritance): def __init__(self, nextLocale=None): @@ -36,7 +37,8 @@ def test_suite(): 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__': unittest.main() diff --git a/src/zope/i18n/locales/tests/test_fallbackcollator.py b/src/zope/i18n/locales/tests/test_fallbackcollator.py index 7e10b50..e7c84a8 100644 --- a/src/zope/i18n/locales/tests/test_fallbackcollator.py +++ b/src/zope/i18n/locales/tests/test_fallbackcollator.py @@ -17,11 +17,13 @@ import doctest from zope.i18n.testing import unicode_checker + def test_suite(): return unittest.TestSuite(( - doctest.DocFileSuite('../fallbackcollator.txt', checker=unicode_checker), - )) + doctest.DocFileSuite('../fallbackcollator.txt', + checker=unicode_checker), + )) + if __name__ == '__main__': unittest.main(defaultTest='test_suite') - diff --git a/src/zope/i18n/locales/tests/test_locales.py b/src/zope/i18n/locales/tests/test_locales.py index 2b100b8..523b1d2 100644 --- a/src/zope/i18n/locales/tests/test_locales.py +++ b/src/zope/i18n/locales/tests/test_locales.py @@ -24,6 +24,7 @@ from zope.i18n.locales.provider import LocaleProvider, LoadLocaleError import zope.i18n datadir = os.path.join(os.path.dirname(zope.i18n.__file__), 'locales', 'data') + class AbstractTestILocaleProviderMixin(object): """Test the functionality of an implmentation of the ILocaleProvider interface.""" @@ -143,6 +144,7 @@ class TestGlobalLocaleProvider(TestCase): self.assertEqual(locale.id.territory, 'GB') self.assertEqual(locale.id.variant, None) + class TestRootLocale(TestCase): """There were some complaints that the root locale does not work correctly, so make sure it does.""" diff --git a/src/zope/i18n/locales/tests/test_xmlfactory.py b/src/zope/i18n/locales/tests/test_xmlfactory.py index 792c96d..6b52dd2 100644 --- a/src/zope/i18n/locales/tests/test_xmlfactory.py +++ b/src/zope/i18n/locales/tests/test_xmlfactory.py @@ -19,6 +19,7 @@ from unittest import TestCase, TestSuite from zope.i18n.locales.xmlfactory import LocaleFactory import zope.i18n + class LocaleXMLFileTestCase(TestCase): """This test verifies that every locale XML file can be loaded.""" @@ -33,14 +34,14 @@ class LocaleXMLFileTestCase(TestCase): # XXX: The tests below are commented out because it's not # necessary for the xml files to have all format definitions. - ## Making sure all number format patterns parse - #for category in (u'decimal', u'scientific', u'percent', u'currency'): + # Making sure all number format patterns parse + # for category in (u'decimal', u'scientific', u'percent', u'currency'): # for length in getattr(locale.numbers, category+'Formats').values(): # for format in length.formats.values(): # self.assert_(parseNumberPattern(format.pattern) is not None) - ## Making sure all datetime patterns parse - #for calendar in locale.dates.calendars.values(): + # Making sure all datetime patterns parse + # for calendar in locale.dates.calendars.values(): # for category in ('date', 'time', 'dateTime'): # for length in getattr(calendar, category+'Formats').values(): # for format in length.formats.values(): @@ -48,7 +49,6 @@ class LocaleXMLFileTestCase(TestCase): # parseDateTimePattern(format.pattern) is not None) - def test_suite(): suite = TestSuite() locale_dir = os.path.join(os.path.dirname(zope.i18n.__file__), diff --git a/src/zope/i18n/locales/xmlfactory.py b/src/zope/i18n/locales/xmlfactory.py index 5b2dbf5..5dbcee0 100644 --- a/src/zope/i18n/locales/xmlfactory.py +++ b/src/zope/i18n/locales/xmlfactory.py @@ -41,7 +41,6 @@ class LocaleFactory(object): rc = rc + node.data return rc - def _extractVersion(self, identity_node): """Extract the Locale's version info based on data from the DOM tree. @@ -81,7 +80,6 @@ class LocaleFactory(object): return LocaleVersion(number, generationDate, notes) - def _extractIdentity(self): """Extract the Locale's identity object based on info from the DOM tree. @@ -119,7 +117,7 @@ class LocaleFactory(object): # Retrieve the language of the locale nodes = identity.getElementsByTagName('language') if nodes != []: - id.language = nodes[0].getAttribute('type') or None + id.language = nodes[0].getAttribute('type') or None # Retrieve the territory of the locale nodes = identity.getElementsByTagName('territory') if nodes != []: @@ -132,7 +130,6 @@ class LocaleFactory(object): id.version = self._extractVersion(identity) return id - def _extractTypes(self, names_node): """Extract all types from the names_node. @@ -179,7 +176,6 @@ class LocaleFactory(object): types[(type, key)] = self._getText(type_node.childNodes) return types - def _extractDisplayNames(self): """Extract all display names from the DOM tree. @@ -285,7 +281,6 @@ class LocaleFactory(object): displayNames.types = types return displayNames - def _extractMonths(self, months_node, calendar): """Extract all month entries from cal_node and store them in calendar. @@ -385,14 +380,15 @@ class LocaleFactory(object): defaultMonthContext_node = months_node.getElementsByTagName('default') if defaultMonthContext_node: - calendar.defaultMonthContext = defaultMonthContext_node[0].getAttribute('type') + calendar.defaultMonthContext = defaultMonthContext_node[0].getAttribute( + 'type') monthContext_nodes = months_node.getElementsByTagName('monthContext') if not monthContext_nodes: return calendar.monthContexts = InheritingDictionary() - names_node = abbrs_node = None # BBB + names_node = abbrs_node = None # BBB for node in monthContext_nodes: context_type = node.getAttribute('type') @@ -441,7 +437,6 @@ class LocaleFactory(object): calendar.months[type] = (names.get(type, None), abbrs.get(type, None)) - def _extractDays(self, days_node, calendar): """Extract all day entries from cal_node and store them in calendar. @@ -529,14 +524,15 @@ class LocaleFactory(object): defaultDayContext_node = days_node.getElementsByTagName('default') if defaultDayContext_node: - calendar.defaultDayContext = defaultDayContext_node[0].getAttribute('type') + calendar.defaultDayContext = defaultDayContext_node[0].getAttribute( + 'type') dayContext_nodes = days_node.getElementsByTagName('dayContext') if not dayContext_nodes: return calendar.dayContexts = InheritingDictionary() - names_node = abbrs_node = None # BBB + names_node = abbrs_node = None # BBB for node in dayContext_nodes: context_type = node.getAttribute('type') @@ -584,7 +580,6 @@ class LocaleFactory(object): calendar.days[type] = (names.get(type, None), abbrs.get(type, None)) - def _extractWeek(self, cal_node, calendar): """Extract all week entries from cal_node and store them in calendar. @@ -644,7 +639,6 @@ class LocaleFactory(object): time_args = map(int, node.getAttribute('time').split(':')) calendar.week['weekendEnd'] = (day, time(*time_args)) - def _extractEras(self, cal_node, calendar): """Extract all era entries from cal_node and store them in calendar. @@ -703,8 +697,8 @@ class LocaleFactory(object): calendar.eras = InheritingDictionary() for type in abbrs.keys(): - calendar.eras[type] = (names.get(type, None), abbrs.get(type, None)) - + calendar.eras[type] = (names.get(type, None), + abbrs.get(type, None)) def _extractFormats(self, formats_node, lengthNodeName, formatNodeName): """Extract all format entries from formats_node and return a @@ -772,7 +766,8 @@ class LocaleFactory(object): format.pattern = self._getText(pattern_node.childNodes) name_nodes = format_node.getElementsByTagName('displayName') if name_nodes: - format.displayName = self._getText(name_nodes[0].childNodes) + format.displayName = self._getText( + name_nodes[0].childNodes) length.formats[format.type] = format lengths[length.type] = length @@ -925,7 +920,6 @@ class LocaleFactory(object): return calendars - def _extractTimeZones(self, dates_node): """Extract all timezone information for the locale from the DOM tree. @@ -1009,7 +1003,6 @@ class LocaleFactory(object): return zones - def _extractDates(self): """Extract all date information from the DOM tree""" dates_nodes = self._data.getElementsByTagName('dates') @@ -1025,7 +1018,6 @@ class LocaleFactory(object): dates.timezones = timezones return dates - def _extractSymbols(self, numbers_node): """Extract all week entries from cal_node and store them in calendar. @@ -1081,7 +1073,6 @@ class LocaleFactory(object): return symbols - def _extractNumberFormats(self, numbers_node, numbers): """Extract all number formats from the numbers_node and save the data in numbers. @@ -1174,7 +1165,6 @@ class LocaleFactory(object): setattr(numbers, defaultName, default) setattr(numbers, formatsName, formats) - def _extractCurrencies(self, numbers_node): """Extract all currency definitions and their information from the Locale's DOM tree. @@ -1232,7 +1222,7 @@ class LocaleFactory(object): if nodes: currency.symbol = self._getText(nodes[0].childNodes) currency.symbolChoice = \ - nodes[0].getAttribute('choice') == u"true" + nodes[0].getAttribute('choice') == u"true" nodes = curr_node.getElementsByTagName('displayName') if nodes: @@ -1242,7 +1232,6 @@ class LocaleFactory(object): return currencies - def _extractNumbers(self): """Extract all number information from the DOM tree""" numbers_nodes = self._data.getElementsByTagName('numbers') @@ -1259,7 +1248,6 @@ class LocaleFactory(object): numbers.currencies = currencies return numbers - def _extractDelimiters(self): """Extract all delimiter entries from the DOM tree. @@ -1315,7 +1303,6 @@ class LocaleFactory(object): return delimiters - def _extractOrientation(self): """Extract orientation information. @@ -1345,7 +1332,6 @@ class LocaleFactory(object): setattr(orientation, name, value) return orientation - def __call__(self): """Create the Locale.""" locale = Locale(self._extractIdentity()) diff --git a/src/zope/i18n/testmessagecatalog.py b/src/zope/i18n/testmessagecatalog.py index 8420c58..a06b15a 100644 --- a/src/zope/i18n/testmessagecatalog.py +++ b/src/zope/i18n/testmessagecatalog.py @@ -18,6 +18,7 @@ from zope import interface import zope.i18n.interfaces from zope.i18n.translationdomain import TranslationDomain + @interface.implementer(zope.i18n.interfaces.IGlobalMessageCatalog) class TestMessageCatalog(object): @@ -43,13 +44,15 @@ class TestMessageCatalog(object): def reload(self): pass + @interface.implementer(zope.i18n.interfaces.ITranslationDomain) def TestMessageFallbackDomain(domain_id=u""): domain = TranslationDomain(domain_id) domain.addCatalog(TestMessageCatalog(domain_id)) return domain + interface.directlyProvides( TestMessageFallbackDomain, zope.i18n.interfaces.IFallbackTranslationDomainFactory, - ) +) diff --git a/src/zope/i18n/tests/test.py b/src/zope/i18n/tests/test.py index 4fb4f4c..05e1366 100644 --- a/src/zope/i18n/tests/test.py +++ b/src/zope/i18n/tests/test.py @@ -22,6 +22,7 @@ from zope.i18n.testing import unicode_checker def test_suite(): options = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS + def suite(name): return doctest.DocTestSuite( name, diff --git a/src/zope/i18n/tests/test_formats.py b/src/zope/i18n/tests/test_formats.py index 83c9129..24791b4 100644 --- a/src/zope/i18n/tests/test_formats.py +++ b/src/zope/i18n/tests/test_formats.py @@ -34,6 +34,7 @@ from zope.i18n.format import NumberPatternParseError class LocaleStub(object): pass + class LocaleCalendarStub(object): type = u"gregorian" @@ -102,13 +103,13 @@ class LocaleCalendarStub(object): class _TestCase(TestCase): # Avoid deprecation warnings in Python 3 by making the preferred # method name available for Python 2. - assertRaisesRegex = getattr(TestCase, 'assertRaisesRegex', TestCase.assertRaisesRegexp) + assertRaisesRegex = getattr( + TestCase, 'assertRaisesRegex', TestCase.assertRaisesRegexp) class TestDateTimePatternParser(_TestCase): """Extensive tests for the ICU-based-syntax datetime pattern parser.""" - def testParseSimpleTimePattern(self): self.assertEqual(parseDateTimePattern('HH'), [('H', 2)]) @@ -217,7 +218,8 @@ class TestBuildDateTimeParseInfo(_TestCase): for char in 'dDFkKhHmsSwW': for length in range(1, 6): self.assertEqual(self.info((char, length)), - '([0-9]{%i,1000})' %length) + '([0-9]{%i,1000})' % length) + def testYear(self): self.assertEqual(self.info(('y', 2)), '([0-9]{2})') self.assertEqual(self.info(('y', 4)), '([0-9]{4})') @@ -674,7 +676,6 @@ class TestDateTimeFormat(_TestCase): "F. EEEE 'im' MMMM, yyyy"), u"2. Freitag im Januar, 2003") - def testFormatGregorianEra(self): self.assertEqual( self.format.format(datetime.date(2017, 12, 17), 'G'), @@ -1329,7 +1330,7 @@ class TestNumberFormat(_TestCase): def testFormatBadThousandSeparator(self): self.assertRaises(ValueError, - self.format.format, 23341, '0,') + self.format.format, 23341, '0,') def testFormatDecimal(self): self.assertEqual(self.format.format(23341.02357, '###0.0#'), @@ -1348,7 +1349,6 @@ class TestNumberFormat(_TestCase): self.assertEqual(self.format.format(1.9999, '0.000'), '2.000') self.assertEqual(self.format.format(1.9999, '0.0000'), '1.9999') - def testFormatScientificDecimal(self): self.assertEqual(self.format.format(23341.02357, '0.00####E00'), '2.334102E04') diff --git a/src/zope/i18n/tests/test_gettextmessagecatalog.py b/src/zope/i18n/tests/test_gettextmessagecatalog.py index 07a0932..5bd93df 100644 --- a/src/zope/i18n/tests/test_gettextmessagecatalog.py +++ b/src/zope/i18n/tests/test_gettextmessagecatalog.py @@ -27,6 +27,5 @@ class GettextMessageCatalogTest(test_imessagecatalog.TestIMessageCatalog): catalog = GettextMessageCatalog('en', 'default', self._path) return catalog - def _getUniqueIndentifier(self): return self._path diff --git a/src/zope/i18n/tests/test_imessagecatalog.py b/src/zope/i18n/tests/test_imessagecatalog.py index 803d4f0..36fb43c 100644 --- a/src/zope/i18n/tests/test_imessagecatalog.py +++ b/src/zope/i18n/tests/test_imessagecatalog.py @@ -21,7 +21,6 @@ from zope.schema import getValidationErrors class TestIMessageCatalog(unittest.TestCase): - # This should be overridden by every class that inherits this test def _getMessageCatalog(self): raise NotImplementedError() @@ -29,7 +28,6 @@ class TestIMessageCatalog(unittest.TestCase): def _getUniqueIndentifier(self): raise NotImplementedError() - def setUp(self): self._catalog = self._getMessageCatalog() @@ -63,4 +61,4 @@ class TestIMessageCatalog(unittest.TestCase): def test_suite(): - return unittest.TestSuite() # Deliberately empty + return unittest.TestSuite() # Deliberately empty diff --git a/src/zope/i18n/tests/test_itranslationdomain.py b/src/zope/i18n/tests/test_itranslationdomain.py index 79c385f..85e4c6a 100644 --- a/src/zope/i18n/tests/test_itranslationdomain.py +++ b/src/zope/i18n/tests/test_itranslationdomain.py @@ -28,16 +28,17 @@ from zope.i18n.interfaces import ITranslationDomain text_type = str if bytes is not str else unicode + @implementer(IUserPreferredLanguages) class Environment(object): - def __init__(self, langs=()): self.langs = langs def getPreferredLanguages(self): return self.langs + class TestITranslationDomain(PlacelessSetup): # This should be overwritten by every class that inherits this test @@ -108,4 +109,4 @@ class TestITranslationDomain(PlacelessSetup): def test_suite(): - return unittest.TestSuite() # Deliberately empty + return unittest.TestSuite() # Deliberately empty diff --git a/src/zope/i18n/tests/test_negotiator.py b/src/zope/i18n/tests/test_negotiator.py index f8a0336..ff855e2 100644 --- a/src/zope/i18n/tests/test_negotiator.py +++ b/src/zope/i18n/tests/test_negotiator.py @@ -20,6 +20,7 @@ from zope.i18n.interfaces import IUserPreferredLanguages from zope.component.testing import PlacelessSetup from zope.interface import implementer + @implementer(IUserPreferredLanguages) class Env(object): @@ -39,12 +40,12 @@ class NegotiatorTest(PlacelessSetup, unittest.TestCase): def test_findLanguages(self): _cases = ( - (('en','de'), ('en','de','fr'), 'en'), - (('en'), ('it','de','fr'), None), - (('pt-br','de'), ('pt_BR','de','fr'), 'pt_BR'), - (('pt-br','en'), ('pt', 'en', 'fr'), 'pt'), - (('pt-br','en-us', 'de'), ('de', 'en', 'fr'), 'en'), - ) + (('en', 'de'), ('en', 'de', 'fr'), 'en'), + (('en'), ('it', 'de', 'fr'), None), + (('pt-br', 'de'), ('pt_BR', 'de', 'fr'), 'pt_BR'), + (('pt-br', 'en'), ('pt', 'en', 'fr'), 'pt'), + (('pt-br', 'en-us', 'de'), ('de', 'en', 'fr'), 'en'), + ) for user_pref_langs, obj_langs, expected in _cases: env = Env(user_pref_langs) @@ -55,7 +56,8 @@ class NegotiatorTest(PlacelessSetup, unittest.TestCase): def test_suite(): return unittest.TestSuite(( unittest.makeSuite(NegotiatorTest), - )) + )) + if __name__ == '__main__': unittest.main(defaultTest='test_suite') diff --git a/src/zope/i18n/tests/test_plurals.py b/src/zope/i18n/tests/test_plurals.py index d4f57c7..bc97bf3 100644 --- a/src/zope/i18n/tests/test_plurals.py +++ b/src/zope/i18n/tests/test_plurals.py @@ -160,18 +160,18 @@ class TestPlurals(unittest.TestCase): self.assertEqual(catalog.getPluralMessage( 'The item is rated 1/5 star.', 'The item is rated %s/5 stars.', 3.5), - 'The item is rated 3.5/5 stars.') + 'The item is rated 3.5/5 stars.') # It's cast either to an int or a float because of the %s in # the translation string. self.assertEqual(catalog.getPluralMessage( 'There is %d chance.', 'There are %f chances.', 1.5), - 'There are 1.500000 chances.') + 'There are 1.500000 chances.') self.assertEqual(catalog.getPluralMessage( 'There is %d chance.', 'There are %f chances.', 3.5), - 'There are 3.500000 chances.') + 'There are 3.500000 chances.') def test_translate_without_defaults(self): domain = self._getTranslationDomain('en') diff --git a/src/zope/i18n/tests/test_testmessagecatalog.py b/src/zope/i18n/tests/test_testmessagecatalog.py index ce5adc6..df426fc 100644 --- a/src/zope/i18n/tests/test_testmessagecatalog.py +++ b/src/zope/i18n/tests/test_testmessagecatalog.py @@ -15,10 +15,12 @@ import unittest import doctest + def test_suite(): return unittest.TestSuite(( doctest.DocFileSuite('../testmessagecatalog.rst') )) + if __name__ == '__main__': unittest.main(defaultTest='test_suite') diff --git a/src/zope/i18n/tests/test_translationdomain.py b/src/zope/i18n/tests/test_translationdomain.py index f8efbd9..550ec85 100644 --- a/src/zope/i18n/tests/test_translationdomain.py +++ b/src/zope/i18n/tests/test_translationdomain.py @@ -18,7 +18,7 @@ import os from zope.i18n.translationdomain import TranslationDomain from zope.i18n.gettextmessagecatalog import GettextMessageCatalog from zope.i18n.tests.test_itranslationdomain import \ - TestITranslationDomain, Environment + TestITranslationDomain, Environment from zope.i18nmessageid import MessageFactory from zope.i18n.interfaces import ITranslationDomain diff --git a/src/zope/i18n/tests/test_zcml.py b/src/zope/i18n/tests/test_zcml.py index 52ee437..e04362d 100644 --- a/src/zope/i18n/tests/test_zcml.py +++ b/src/zope/i18n/tests/test_zcml.py @@ -37,6 +37,7 @@ template = """\ %s """ + class DirectivesTest(PlacelessSetup, unittest.TestCase): # This test suite needs the [zcml] and [compile] extra dependencies diff --git a/src/zope/i18n/tests/testi18nawareobject.py b/src/zope/i18n/tests/testi18nawareobject.py index 21a61f4..996416b 100644 --- a/src/zope/i18n/tests/testi18nawareobject.py +++ b/src/zope/i18n/tests/testi18nawareobject.py @@ -54,6 +54,7 @@ class I18nAwareContentObject(object): # ############################################################ + class AbstractTestII18nAwareMixin(object): def setUp(self): @@ -73,7 +74,8 @@ class AbstractTestII18nAwareMixin(object): self.assertEqual(self.object.getDefaultLanguage(), 'lt') def testGetAvailableLanguages(self): - self.assertEqual(sorted(self.object.getAvailableLanguages()), ['en', 'fr', 'lt']) + self.assertEqual(sorted(self.object.getAvailableLanguages()), [ + 'en', 'fr', 'lt']) class TestI18nAwareObject(AbstractTestII18nAwareMixin, unittest.TestCase): diff --git a/src/zope/i18n/zcml.py b/src/zope/i18n/zcml.py index 4df9ccb..6934485 100644 --- a/src/zope/i18n/zcml.py +++ b/src/zope/i18n/zcml.py @@ -45,14 +45,14 @@ class IRegisterTranslationsDirective(Interface): title=u"Directory", description=u"Directory containing the translations", required=True - ) + ) domain = TextLine( title=u"Domain", description=(u"Translation domain to register. If not specified, " u"all domains found in the directory are registered"), required=False - ) + ) def allow_language(lang): -- cgit v1.2.1 From 171ecc86e49776b238e5b36af98efddb892053ab Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Fri, 3 Sep 2021 10:09:45 +0200 Subject: More aggressive autopep8. With `--ignore W690,E711,E721 --aggressive` --- docs/conf.py | 9 ++++---- src/zope/i18n/format.py | 42 ++++++++++++++++++---------------- src/zope/i18n/locales/__init__.py | 13 +++++++---- src/zope/i18n/locales/xmlfactory.py | 13 ++++++----- src/zope/i18n/tests/test_formats.py | 41 ++++++++++++++++++--------------- src/zope/i18n/tests/test_negotiator.py | 10 ++++---- src/zope/i18n/translationdomain.py | 2 +- 7 files changed, 70 insertions(+), 60 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f6fff3f..02f419e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ import pkg_resources sys.path.append(os.path.abspath('../src')) rqmt = pkg_resources.require('zope.i18n')[0] -# -- General configuration ----------------------------------------------------- +# -- General configuration ----------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. @@ -77,7 +77,8 @@ release = rqmt.version # for source files. exclude_trees = ['_build'] -# The reST default role (used for this markup: `text`) to use for all documents. +# The reST default role (used for this markup: `text`) to use for all +# documents. default_role = 'obj' # If true, '()' will be appended to :func: etc. cross-reference text. @@ -98,7 +99,7 @@ pygments_style = 'sphinx' #modindex_common_prefix = [] -# -- Options for HTML output --------------------------------------------------- +# -- Options for HTML output --------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. @@ -172,7 +173,7 @@ html_static_path = ['_static'] htmlhelp_basename = 'zopei18ndoc' -# -- Options for LaTeX output -------------------------------------------------- +# -- Options for LaTeX output -------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' diff --git a/src/zope/i18n/format.py b/src/zope/i18n/format.py index 7b9ba4a..eaec5d1 100644 --- a/src/zope/i18n/format.py +++ b/src/zope/i18n/format.py @@ -143,7 +143,7 @@ class DateTimeFormat(object): ampm_entry[0])] if hour == 12: ampm = not ampm - ordered[3] = (hour + 12*ampm) % 24 + ordered[3] = (hour + 12 * ampm) % 24 # Shortcut for the simple int functions dt_fields_map = {'d': 2, 'H': 3, 'm': 4, 's': 5, 'S': 6} @@ -236,7 +236,7 @@ class NumberFormat(object): self.symbols = { u"decimal": u".", u"group": u",", - u"list": u";", + u"list": u";", u"percentSign": u"%", u"nativeZeroDigit": u"0", u"patternDigit": u"#", @@ -282,12 +282,12 @@ class NumberFormat(object): min_size = bin_pattern[sign][INTEGER].count('0') if bin_pattern[sign][GROUPING]: regex += self.symbols['group'] - min_size += min_size/3 + min_size += min_size / 3 regex += ']{%i,100}' % (min_size) if bin_pattern[sign][FRACTION]: max_precision = len(bin_pattern[sign][FRACTION]) min_precision = bin_pattern[sign][FRACTION].count('0') - regex += '['+self.symbols['decimal']+']?' + regex += '[' + self.symbols['decimal'] + ']?' regex += '[0-9]{%i,%i}' % (min_precision, max_precision) if bin_pattern[sign][EXPONENTIAL] != '': regex += self.symbols['exponential'] @@ -327,13 +327,14 @@ class NumberFormat(object): num_str = num_str.replace(self.symbols['exponential'], 'E') if self.type: type = self.type - return sign*type(num_str) + return sign * type(num_str) def _format_integer(self, integer, pattern): size = len(integer) min_size = pattern.count('0') if size < min_size: - integer = self.symbols['nativeZeroDigit']*(min_size-size) + integer + integer = self.symbols['nativeZeroDigit'] * \ + (min_size - size) + integer return integer def _format_fraction(self, fraction, pattern, rounding=True): @@ -362,8 +363,8 @@ class NumberFormat(object): roundInt = True if precision < min_precision: - fraction += self.symbols['nativeZeroDigit']*(min_precision - - precision) + fraction += self.symbols['nativeZeroDigit'] * (min_precision - + precision) if fraction != '': fraction = self.symbols['decimal'] + fraction return fraction, roundInt @@ -440,16 +441,16 @@ class NumberFormat(object): # abs() of number smaller 1 if len(obj_int_frac) > 1: res = re.match('(0*)[0-9]*', obj_int_frac[1]).groups()[0] - exponent = self._format_integer(str(len(res)+1), + exponent = self._format_integer(str(len(res) + 1), exp_bin_pattern) - exponent = self.symbols['minusSign']+exponent + exponent = self.symbols['minusSign'] + exponent number = obj_int_frac[1][len(res):] else: # We have exactly 0 exponent = self._format_integer('0', exp_bin_pattern) number = self.symbols['nativeZeroDigit'] else: - exponent = self._format_integer(str(len(obj_int_frac[0])-1), + exponent = self._format_integer(str(len(obj_int_frac[0]) - 1), exp_bin_pattern) number = ''.join(obj_int_frac) @@ -484,13 +485,13 @@ class NumberFormat(object): if bin_pattern[GROUPING]: integer = self._group(integer, bin_pattern[GROUPING]) pre_padding = len(bin_pattern[INTEGER]) - len(integer) - post_padding = len(bin_pattern[FRACTION]) - len(fraction)+1 + post_padding = len(bin_pattern[FRACTION]) - len(fraction) + 1 number = integer + fraction # Put it all together text = '' if bin_pattern[PADDING1] is not None and pre_padding > 0: - text += bin_pattern[PADDING1]*pre_padding + text += bin_pattern[PADDING1] * pre_padding text += bin_pattern[PREFIX] if bin_pattern[PADDING2] is not None and pre_padding > 0: if bin_pattern[PADDING1] is not None: @@ -502,10 +503,10 @@ class NumberFormat(object): if bin_pattern[PADDING4] is not None: text += bin_pattern[PADDING3] else: - text += bin_pattern[PADDING3]*post_padding + text += bin_pattern[PADDING3] * post_padding text += bin_pattern[SUFFIX] if bin_pattern[PADDING4] is not None and post_padding > 0: - text += bin_pattern[PADDING4]*post_padding + text += bin_pattern[PADDING4] * post_padding # TODO: Need to make sure unicode is everywhere return text_type(text) @@ -644,9 +645,10 @@ def buildDateTimeParseInfo(calendar, pattern): elif entry[1] == 2: info[entry] = r'([0-9]{2})' elif entry[1] == 3: - info[entry] = r'('+'|'.join(calendar.getMonthAbbreviations())+')' + info[entry] = r'(' + \ + '|'.join(calendar.getMonthAbbreviations()) + ')' else: - info[entry] = r'('+'|'.join(calendar.getMonthNames())+')' + info[entry] = r'(' + '|'.join(calendar.getMonthNames()) + ')' # day in week (Text and Number) for entry in _findFormattingCharacterInPattern('E', pattern): @@ -655,9 +657,9 @@ def buildDateTimeParseInfo(calendar, pattern): elif entry[1] == 2: info[entry] = r'([0-9]{2})' elif entry[1] == 3: - info[entry] = r'('+'|'.join(calendar.getDayAbbreviations())+')' + info[entry] = r'(' + '|'.join(calendar.getDayAbbreviations()) + ')' else: - info[entry] = r'('+'|'.join(calendar.getDayNames())+')' + info[entry] = r'(' + '|'.join(calendar.getDayNames()) + ')' return info @@ -965,7 +967,7 @@ def parseNumberPattern(pattern): last_index = -1 for index, char in enumerate(reversed(integer)): if char == ",": - grouping += (index-last_index-1,) + grouping += (index - last_index - 1,) last_index = index # use last group ad infinitum grouping += (0,) diff --git a/src/zope/i18n/locales/__init__.py b/src/zope/i18n/locales/__init__.py index 9da515a..82159ff 100644 --- a/src/zope/i18n/locales/__init__.py +++ b/src/zope/i18n/locales/__init__.py @@ -103,7 +103,8 @@ class LocaleIdentity(object): """ - def __init__(self, language=None, script=None, territory=None, variant=None): + def __init__(self, language=None, script=None, + territory=None, variant=None): """Initialize object.""" self.language = language self.script = script @@ -344,7 +345,8 @@ class LocaleCalendar(AttributeInheritance): def getMonthNames(self): """See zope.i18n.interfaces.ILocaleCalendar""" - return [self.months.get(type, (None, None))[0] for type in range(1, 13)] + return [self.months.get(type, (None, None))[0] + for type in range(1, 13)] def getMonthTypeFromName(self, name): """See zope.i18n.interfaces.ILocaleCalendar""" @@ -354,7 +356,8 @@ class LocaleCalendar(AttributeInheritance): def getMonthAbbreviations(self): """See zope.i18n.interfaces.ILocaleCalendar""" - return [self.months.get(type, (None, None))[1] for type in range(1, 13)] + return [self.months.get(type, (None, None))[1] + for type in range(1, 13)] def getMonthTypeFromAbbreviation(self, abbr): """See zope.i18n.interfaces.ILocaleCalendar""" @@ -506,11 +509,11 @@ class LocaleDates(AttributeInheritance): cal = self.calendars[calendar] - formats = getattr(cal, category+'Formats') + formats = getattr(cal, category + 'Formats') if length is None: length = getattr( cal, - 'default'+category[0].upper()+category[1:]+'Format', + 'default' + category[0].upper() + category[1:] + 'Format', list(formats.keys())[0]) # 'datetime' is always a bit special; we often do not have a length diff --git a/src/zope/i18n/locales/xmlfactory.py b/src/zope/i18n/locales/xmlfactory.py index 5dbcee0..5710d19 100644 --- a/src/zope/i18n/locales/xmlfactory.py +++ b/src/zope/i18n/locales/xmlfactory.py @@ -759,7 +759,8 @@ class LocaleFactory(object): if length_node.getElementsByTagName(formatNodeName): length.formats = InheritingDictionary() - for format_node in length_node.getElementsByTagName(formatNodeName): + for format_node in length_node.getElementsByTagName( + formatNodeName): format = LocaleFormat() format.type = format_node.getAttribute('type') or None pattern_node = format_node.getElementsByTagName('pattern')[0] @@ -909,7 +910,7 @@ class LocaleFactory(object): default, formats = self._extractFormats( formats_nodes[0], lengthName, formatName) setattr(calendar, - 'default'+formatName[0].upper()+formatName[1:], + 'default' + formatName[0].upper() + formatName[1:], default) setattr(calendar, formatsName, formats) @@ -1153,10 +1154,10 @@ class LocaleFactory(object): """ for category in ('decimal', 'scientific', 'percent', 'currency'): - formatsName = category+'Formats' - lengthName = category+'FormatLength' - formatName = category+'Format' - defaultName = 'default'+formatName[0].upper()+formatName[1:] + formatsName = category + 'Formats' + lengthName = category + 'FormatLength' + formatName = category + 'Format' + defaultName = 'default' + formatName[0].upper() + formatName[1:] formats_nodes = numbers_node.getElementsByTagName(formatsName) if formats_nodes: diff --git a/src/zope/i18n/tests/test_formats.py b/src/zope/i18n/tests/test_formats.py index 24791b4..4ca039e 100644 --- a/src/zope/i18n/tests/test_formats.py +++ b/src/zope/i18n/tests/test_formats.py @@ -72,7 +72,8 @@ class LocaleCalendarStub(object): week = {'firstDay': 1, 'minDays': 1} def getMonthNames(self): - return [self.months.get(type, (None, None))[0] for type in range(1, 13)] + return [self.months.get(type, (None, None))[0] + for type in range(1, 13)] def getMonthTypeFromName(self, name): for item in self.months.items(): @@ -80,7 +81,8 @@ class LocaleCalendarStub(object): return item[0] def getMonthAbbreviations(self): - return [self.months.get(type, (None, None))[1] for type in range(1, 13)] + return [self.months.get(type, (None, None))[1] + for type in range(1, 13)] def getMonthTypeFromAbbreviation(self, abbr): for item in self.months.items(): @@ -230,7 +232,8 @@ class TestBuildDateTimeParseInfo(_TestCase): def testAMPMMarker(self): names = ['vorm.', 'nachm.'] for length in range(1, 6): - self.assertEqual(self.info(('a', length)), '('+'|'.join(names)+')') + self.assertEqual(self.info(('a', length)), + '(' + '|'.join(names) + ')') def testEra(self): self.assertEqual(self.info(('G', 1)), '(v. Chr.|n. Chr.)') @@ -250,12 +253,12 @@ class TestBuildDateTimeParseInfo(_TestCase): names = [u"Januar", u"Februar", u"Maerz", u"April", u"Mai", u"Juni", u"Juli", u"August", u"September", u"Oktober", u"November", u"Dezember"] - self.assertEqual(self.info(('M', 4)), '('+'|'.join(names)+')') + self.assertEqual(self.info(('M', 4)), '(' + '|'.join(names) + ')') def testMonthAbbr(self): names = ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'] - self.assertEqual(self.info(('M', 3)), '('+'|'.join(names)+')') + self.assertEqual(self.info(('M', 3)), '(' + '|'.join(names) + ')') def testWeekdayNumber(self): self.assertEqual(self.info(('E', 1)), '([0-9])') @@ -264,13 +267,13 @@ class TestBuildDateTimeParseInfo(_TestCase): def testWeekdayNames(self): names = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'] - self.assertEqual(self.info(('E', 4)), '('+'|'.join(names)+')') - self.assertEqual(self.info(('E', 5)), '('+'|'.join(names)+')') - self.assertEqual(self.info(('E', 10)), '('+'|'.join(names)+')') + self.assertEqual(self.info(('E', 4)), '(' + '|'.join(names) + ')') + self.assertEqual(self.info(('E', 5)), '(' + '|'.join(names) + ')') + self.assertEqual(self.info(('E', 10)), '(' + '|'.join(names) + ')') def testWeekdayAbbr(self): names = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'] - self.assertEqual(self.info(('E', 3)), '('+'|'.join(names)+')') + self.assertEqual(self.info(('E', 3)), '(' + '|'.join(names) + ')') class TestDateTimeFormat(_TestCase): @@ -468,10 +471,10 @@ class TestDateTimeFormat(_TestCase): for day in range(1, 8): self.assertEqual( self.format.format( - datetime.datetime(2003, 1, 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)) + self.format.calendar.days[day][0], day + 5)) def testFormatTimeZone(self): self.assertEqual( @@ -712,7 +715,7 @@ class TestNumberPatternParser(_TestCase): self.assertEqual( parseNumberPattern('###0;#0'), ((None, '', None, '###0', '', '', None, '', None, ()), - (None, '', None, '#0', '', '', None, '', None, ()))) + (None, '', None, '#0', '', '', None, '', None, ()))) def testParsePrefixedIntegerPattern(self): self.assertEqual( @@ -754,7 +757,7 @@ class TestNumberPatternParser(_TestCase): self.assertEqual( parseNumberPattern('###0.00#;#0.0#'), ((None, '', None, '###0', '00#', '', None, '', None, ()), - (None, '', None, '#0', '0#', '', None, '', None, ()))) + (None, '', None, '#0', '0#', '', None, '', None, ()))) def testParsePosNegFractionPattern(self): self.assertEqual( @@ -1426,27 +1429,27 @@ class TestNumberFormat(_TestCase): def testFormatHighPrecisionNumbers(self): self.assertEqual( self.format.format( - 1+1e-7, '(#0.00#####);(-#0.00#####)'), + 1 + 1e-7, '(#0.00#####);(-#0.00#####)'), '(1.0000001)') self.assertEqual( self.format.format( - 1+1e-7, '(#0.00###)'), + 1 + 1e-7, '(#0.00###)'), '(1.00000)') self.assertEqual( self.format.format( - 1+1e-9, '(#0.00#######);(-#0.00#######)'), + 1 + 1e-9, '(#0.00#######);(-#0.00#######)'), '(1.000000001)') self.assertEqual( self.format.format( - 1+1e-9, '(#0.00###)'), + 1 + 1e-9, '(#0.00###)'), '(1.00000)') self.assertEqual( self.format.format( - 1+1e-12, '(#0.00##########);(-#0.00##########)'), + 1 + 1e-12, '(#0.00##########);(-#0.00##########)'), '(1.000000000001)') self.assertEqual( self.format.format( - 1+1e-12, '(#0.00###)'), + 1 + 1e-12, '(#0.00###)'), '(1.00000)') def testNoRounding(self): diff --git a/src/zope/i18n/tests/test_negotiator.py b/src/zope/i18n/tests/test_negotiator.py index ff855e2..ef6a470 100644 --- a/src/zope/i18n/tests/test_negotiator.py +++ b/src/zope/i18n/tests/test_negotiator.py @@ -40,11 +40,11 @@ class NegotiatorTest(PlacelessSetup, unittest.TestCase): def test_findLanguages(self): _cases = ( - (('en', 'de'), ('en', 'de', 'fr'), 'en'), - (('en'), ('it', 'de', 'fr'), None), - (('pt-br', 'de'), ('pt_BR', 'de', 'fr'), 'pt_BR'), - (('pt-br', 'en'), ('pt', 'en', 'fr'), 'pt'), - (('pt-br', 'en-us', 'de'), ('de', 'en', 'fr'), 'en'), + (('en', 'de'), ('en', 'de', 'fr'), 'en'), + (('en'), ('it', 'de', 'fr'), None), + (('pt-br', 'de'), ('pt_BR', 'de', 'fr'), 'pt_BR'), + (('pt-br', 'en'), ('pt', 'en', 'fr'), 'pt'), + (('pt-br', 'en-us', 'de'), ('de', 'en', 'fr'), 'en'), ) for user_pref_langs, obj_langs, expected in _cases: diff --git a/src/zope/i18n/translationdomain.py b/src/zope/i18n/translationdomain.py index b9287f0..155e6c2 100644 --- a/src/zope/i18n/translationdomain.py +++ b/src/zope/i18n/translationdomain.py @@ -85,7 +85,7 @@ class TranslationDomain(object): msgid_plural, default_plural, number) def _recursive_translate(self, msgid, mapping, target_language, default, - context, msgid_plural, default_plural, number, + context, msgid_plural, default_plural, number, seen=None): """Recursively translate msg.""" # MessageID attributes override arguments -- cgit v1.2.1 From 55532a6b34e9aafc7cd44044c0fbb762351b147c Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Fri, 3 Sep 2021 10:10:42 +0200 Subject: autopep8 in full aggressive mode. --- src/zope/i18n/testmessagecatalog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zope/i18n/testmessagecatalog.py b/src/zope/i18n/testmessagecatalog.py index a06b15a..b88b3d7 100644 --- a/src/zope/i18n/testmessagecatalog.py +++ b/src/zope/i18n/testmessagecatalog.py @@ -29,7 +29,7 @@ class TestMessageCatalog(object): def queryMessage(self, msgid, default=None): default = getattr(msgid, 'default', default) - if default != None and default != msgid: + if default is not None and default != msgid: msg = u"%s (%s)" % (msgid, default) else: msg = msgid -- cgit v1.2.1 From 332629aa14660a10d1e37f02d35847f3229f0844 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 2 Sep 2021 10:50:47 +0200 Subject: Manually fix other lint errors. --- src/zope/i18n/__init__.py | 4 +++- src/zope/i18n/compile.py | 11 ++++++----- src/zope/i18n/interfaces/__init__.py | 6 +++--- src/zope/i18n/locales/__init__.py | 4 +++- src/zope/i18n/locales/tests/test_xmlfactory.py | 13 ++++++++----- src/zope/i18n/locales/xmlfactory.py | 6 ++++-- src/zope/i18n/negotiator.py | 4 ++-- src/zope/i18n/tests/test_zcml.py | 3 ++- 8 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/zope/i18n/__init__.py b/src/zope/i18n/__init__.py index dd525ea..aed9ded 100644 --- a/src/zope/i18n/__init__.py +++ b/src/zope/i18n/__init__.py @@ -16,7 +16,9 @@ import re from zope.component import queryUtility -from zope.i18nmessageid import MessageFactory, Message +from zope.i18nmessageid import Message +# I expect that MessageFactory might be there for BBB reasons, but not sure. +from zope.i18nmessageid import MessageFactory # noqa from zope.i18n.config import ALLOWED_LANGUAGES from zope.i18n.interfaces import INegotiator diff --git a/src/zope/i18n/compile.py b/src/zope/i18n/compile.py index 441523d..81a6a17 100644 --- a/src/zope/i18n/compile.py +++ b/src/zope/i18n/compile.py @@ -36,11 +36,12 @@ def compile_mo_file(domain, lc_messages_path): if po_mtime > mo_mtime: try: - # Msgfmt.getAsFile returns io.BytesIO on Python 3, and cStringIO.StringIO - # on Python 2; sadly StringIO isn't a proper context manager, so we have to - # wrap it with `closing`. Also, Msgfmt doesn't properly close a file - # it opens for reading if you pass the path, but it does if you pass - # the file. + # Msgfmt.getAsFile returns io.BytesIO on Python 3, + # and cStringIO.StringIO on Python 2; + # sadly StringIO isn't a proper context manager, so we have to + # wrap it with `closing`. Also, Msgfmt doesn't properly close a + # file it opens for reading if you pass the path, + # but it does if you pass the file. with open(pofile, 'rb') as pofd: with closing(Msgfmt(pofd, domain).getAsFile()) as mo: with open(mofile, 'wb') as fd: diff --git a/src/zope/i18n/interfaces/__init__.py b/src/zope/i18n/interfaces/__init__.py index e717108..025c477 100644 --- a/src/zope/i18n/interfaces/__init__.py +++ b/src/zope/i18n/interfaces/__init__.py @@ -370,9 +370,9 @@ class INumberFormat(IFormat): \u00A4 This is the currency sign. it will be replaced by a currency symbol. If it is present in a pattern, the monetary decimal separator is used instead of the decimal separator. - \u00A4\u00A4 This is the international currency sign. It will be replaced - by an international currency symbol. If it is present in a - pattern, the monetary decimal separator is used instead of + \u00A4\u00A4 This is the international currency sign. It will be + replaced by an international currency symbol. If it is present + in a pattern, the monetary decimal separator is used instead of the decimal separator. X Any other characters can be used in the prefix or suffix ' Used to quote special characters in a prefix or suffix diff --git a/src/zope/i18n/locales/__init__.py b/src/zope/i18n/locales/__init__.py index 82159ff..12009a6 100644 --- a/src/zope/i18n/locales/__init__.py +++ b/src/zope/i18n/locales/__init__.py @@ -30,7 +30,9 @@ from zope.i18n.interfaces.locales import ILocaleDayContext, ILocaleMonthContext from zope.i18n.format import NumberFormat, DateTimeFormat from zope.i18n.locales.inheritance import \ AttributeInheritance, InheritingDictionary, NoParentException -from zope.i18n.locales.provider import LocaleProvider, LoadLocaleError +# LoadLocaleError is not used, but might be imported from here by others. +from zope.i18n.locales.provider import LoadLocaleError # noqa +from zope.i18n.locales.provider import LocaleProvider # Setup the locale directory diff --git a/src/zope/i18n/locales/tests/test_xmlfactory.py b/src/zope/i18n/locales/tests/test_xmlfactory.py index 6b52dd2..0dc070e 100644 --- a/src/zope/i18n/locales/tests/test_xmlfactory.py +++ b/src/zope/i18n/locales/tests/test_xmlfactory.py @@ -42,11 +42,14 @@ class LocaleXMLFileTestCase(TestCase): # Making sure all datetime patterns parse # for calendar in locale.dates.calendars.values(): - # for category in ('date', 'time', 'dateTime'): - # for length in getattr(calendar, category+'Formats').values(): - # for format in length.formats.values(): - # self.assert_( - # parseDateTimePattern(format.pattern) is not None) + # for category in ('date', 'time', 'dateTime'): + # for length in getattr( + # calendar, category + 'Formats' + # ).values(): + # for format in length.formats.values(): + # self.assert_( + # parseDateTimePattern(format.pattern) is not None + # ) def test_suite(): diff --git a/src/zope/i18n/locales/xmlfactory.py b/src/zope/i18n/locales/xmlfactory.py index 5710d19..0520c2d 100644 --- a/src/zope/i18n/locales/xmlfactory.py +++ b/src/zope/i18n/locales/xmlfactory.py @@ -345,7 +345,8 @@ class LocaleFactory(object): >>> names[7:] [u'August', u'September', u'Oktober', u'November', u'Dezember'] - >>> abbrs = [ctx.months[u"abbreviated"][type] for type in range(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:] @@ -1312,7 +1313,8 @@ class LocaleFactory(object): >>> xml = u''' ... ... - ... + ... ... ... ''' >>> dom = parseString(xml) diff --git a/src/zope/i18n/negotiator.py b/src/zope/i18n/negotiator.py index 3c5fa17..3ece221 100644 --- a/src/zope/i18n/negotiator.py +++ b/src/zope/i18n/negotiator.py @@ -29,8 +29,8 @@ def normalize_langs(langs): # Make a mapping from normalized->original so we keep can match # the normalized lang and return the original string. n_langs = {} - for l in langs: - n_langs[normalize_lang(l)] = l + for lang in langs: + n_langs[normalize_lang(lang)] = lang return n_langs diff --git a/src/zope/i18n/tests/test_zcml.py b/src/zope/i18n/tests/test_zcml.py index e04362d..0467a40 100644 --- a/src/zope/i18n/tests/test_zcml.py +++ b/src/zope/i18n/tests/test_zcml.py @@ -157,7 +157,8 @@ class DirectivesTest(PlacelessSetup, unittest.TestCase): xmlconfig.string( template % ''' - + ''', self.context) path = os.path.join(os.path.dirname(zope.i18n.tests.__file__), -- cgit v1.2.1 From 74cf43f3dd2d3108548fa0ecc091711ef2ab4eb2 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 2 Sep 2021 11:15:07 +0200 Subject: Add _compat module to define text_type on Py 2 and 3. The old way worked, but gave a linting error because unicode is not defined. --- src/zope/i18n/__init__.py | 5 +++-- src/zope/i18n/_compat.py | 8 ++++++++ src/zope/i18n/format.py | 3 ++- src/zope/i18n/simpletranslationdomain.py | 4 +--- src/zope/i18n/tests/test_itranslationdomain.py | 3 +-- src/zope/i18n/tests/test_zcml.py | 2 +- src/zope/i18n/translationdomain.py | 3 +-- 7 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 src/zope/i18n/_compat.py diff --git a/src/zope/i18n/__init__.py b/src/zope/i18n/__init__.py index aed9ded..b737d00 100644 --- a/src/zope/i18n/__init__.py +++ b/src/zope/i18n/__init__.py @@ -17,15 +17,16 @@ import re from zope.component import queryUtility from zope.i18nmessageid import Message -# I expect that MessageFactory might be there for BBB reasons, but not sure. +# MessageFactory is not used, but it might be here for BBB reasons, +# as it could be imported by other packages. from zope.i18nmessageid import MessageFactory # noqa +from zope.i18n._compat import text_type from zope.i18n.config import ALLOWED_LANGUAGES from zope.i18n.interfaces import INegotiator from zope.i18n.interfaces import ITranslationDomain from zope.i18n.interfaces import IFallbackTranslationDomainFactory -text_type = str if bytes is not str else unicode # Set up regular expressions for finding interpolation variables in text. # NAME_RE must exactly match the expression of the same name in the diff --git a/src/zope/i18n/_compat.py b/src/zope/i18n/_compat.py new file mode 100644 index 0000000..00fb20f --- /dev/null +++ b/src/zope/i18n/_compat.py @@ -0,0 +1,8 @@ +# This gives a linting error because unicode is not defined on Python 3: +# text_type = str if bytes is not str else unicode +try: + # Python 3 + text_type = unicode +except NameError: + # Python 2 + text_type = str diff --git a/src/zope/i18n/format.py b/src/zope/i18n/format.py index eaec5d1..05431e0 100644 --- a/src/zope/i18n/format.py +++ b/src/zope/i18n/format.py @@ -23,10 +23,11 @@ import datetime import pytz import pytz.reference +from zope.i18n._compat import text_type from zope.i18n.interfaces import IDateTimeFormat, INumberFormat from zope.interface import implementer -text_type = str if bytes is not str else unicode + NATIVE_NUMBER_TYPES = (int, float) try: NATIVE_NUMBER_TYPES += (long,) diff --git a/src/zope/i18n/simpletranslationdomain.py b/src/zope/i18n/simpletranslationdomain.py index b093db8..b20385a 100644 --- a/src/zope/i18n/simpletranslationdomain.py +++ b/src/zope/i18n/simpletranslationdomain.py @@ -15,13 +15,11 @@ """ from zope.interface import implementer from zope.component import getUtility +from zope.i18n._compat import text_type from zope.i18n.interfaces import ITranslationDomain, INegotiator from zope.i18n import interpolate -text_type = str if bytes is not str else unicode - - @implementer(ITranslationDomain) class SimpleTranslationDomain(object): """This is the simplest implementation of the ITranslationDomain I diff --git a/src/zope/i18n/tests/test_itranslationdomain.py b/src/zope/i18n/tests/test_itranslationdomain.py index 85e4c6a..bea5360 100644 --- a/src/zope/i18n/tests/test_itranslationdomain.py +++ b/src/zope/i18n/tests/test_itranslationdomain.py @@ -22,12 +22,11 @@ from zope.component.testing import PlacelessSetup from zope.schema import getValidationErrors +from zope.i18n._compat import text_type from zope.i18n.negotiator import negotiator from zope.i18n.interfaces import INegotiator, IUserPreferredLanguages from zope.i18n.interfaces import ITranslationDomain -text_type = str if bytes is not str else unicode - @implementer(IUserPreferredLanguages) class Environment(object): diff --git a/src/zope/i18n/tests/test_zcml.py b/src/zope/i18n/tests/test_zcml.py index 0467a40..cd3d2b4 100644 --- a/src/zope/i18n/tests/test_zcml.py +++ b/src/zope/i18n/tests/test_zcml.py @@ -25,10 +25,10 @@ from zope.component.testing import PlacelessSetup from zope.configuration import xmlconfig import zope.i18n.tests +from zope.i18n._compat import text_type from zope.i18n.interfaces import ITranslationDomain from zope.i18n import config -text_type = str if bytes is not str else unicode template = """\ Date: Thu, 2 Sep 2021 11:59:39 +0200 Subject: Add meta.toml rules for manifest and check-manifest. --- .meta.toml | 26 +++++++++++++++++++++++++- MANIFEST.in | 9 +++++++++ setup.cfg | 9 +++++++++ tox.ini | 2 +- 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/.meta.toml b/.meta.toml index 4a7e6d4..63ff7ae 100644 --- a/.meta.toml +++ b/.meta.toml @@ -5,7 +5,6 @@ template = "pure-python" commit-id = "7f5b73fe9d2bcbabafaef5f69dd97408a142d42a" [python] -with-appveyor = false with-windows = false with-pypy = true with-future-python = false @@ -18,3 +17,28 @@ use-flake8 = true [coverage] fail-under = 100 + +[manifest] +additional-rules = [ + "recursive-include docs *.bat", + "recursive-include src *.dtd", + "recursive-include src *.html", + "recursive-include src *.in", + "recursive-include src *.po", + "recursive-include src *.rst", + "recursive-include src *.txt", + "recursive-include src *.xml", + "recursive-include src *.zcml", + ] + +[check-manifest] +ignore-bad-ideas = [ + "src/zope/i18n/tests/de-default.mo", + "src/zope/i18n/tests/en-alt.mo", + "src/zope/i18n/tests/en-default.mo", + "src/zope/i18n/tests/locale/de/LC_MESSAGES/zope-i18n.mo", + "src/zope/i18n/tests/locale/en/LC_MESSAGES/zope-i18n.mo", + "src/zope/i18n/tests/locale2/en/LC_MESSAGES/zope-i18n.mo", + "src/zope/i18n/tests/locale3/en/LC_MESSAGES/zope-i18n.mo", + "src/zope/i18n/tests/pl-default.mo", + ] diff --git a/MANIFEST.in b/MANIFEST.in index 38e9c74..b2b9c96 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -11,3 +11,12 @@ recursive-include docs *.txt recursive-include docs Makefile recursive-include src *.py +recursive-include docs *.bat +recursive-include src *.dtd +recursive-include src *.html +recursive-include src *.in +recursive-include src *.po +recursive-include src *.rst +recursive-include src *.txt +recursive-include src *.xml +recursive-include src *.zcml diff --git a/setup.cfg b/setup.cfg index 264b78c..c703c58 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,3 +11,12 @@ ignore = .editorconfig .meta.toml docs/_build/html/_sources/* +ignore-bad-ideas = + src/zope/i18n/tests/de-default.mo + src/zope/i18n/tests/en-alt.mo + src/zope/i18n/tests/en-default.mo + src/zope/i18n/tests/locale/de/LC_MESSAGES/zope-i18n.mo + src/zope/i18n/tests/locale/en/LC_MESSAGES/zope-i18n.mo + src/zope/i18n/tests/locale2/en/LC_MESSAGES/zope-i18n.mo + src/zope/i18n/tests/locale3/en/LC_MESSAGES/zope-i18n.mo + src/zope/i18n/tests/pl-default.mo diff --git a/tox.ini b/tox.ini index fd22c86..cf1d7e5 100644 --- a/tox.ini +++ b/tox.ini @@ -58,7 +58,7 @@ commands = mkdir -p {toxinidir}/parts/htmlcov coverage run -m zope.testrunner --test-path=src {posargs:-vc} coverage html - coverage report -m --fail-under=0 + coverage report -m --fail-under=100 [coverage:run] branch = True -- cgit v1.2.1 From 183ab0df50dbbe6e21dad801a3b8650dc7962712 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 2 Sep 2021 12:15:21 +0200 Subject: Include sphinx doctests. --- .meta.toml | 2 +- setup.cfg | 1 + tox.ini | 10 ++++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.meta.toml b/.meta.toml index 63ff7ae..e8e5c84 100644 --- a/.meta.toml +++ b/.meta.toml @@ -10,7 +10,7 @@ with-pypy = true with-future-python = false with-legacy-python = true with-docs = true -with-sphinx-doctests = false +with-sphinx-doctests = true [tox] use-flake8 = true diff --git a/setup.cfg b/setup.cfg index c703c58..43050e9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,6 +11,7 @@ ignore = .editorconfig .meta.toml docs/_build/html/_sources/* + docs/_build/doctest/* ignore-bad-ideas = src/zope/i18n/tests/de-default.mo src/zope/i18n/tests/en-alt.mo diff --git a/tox.ini b/tox.ini index cf1d7e5..68e58b0 100644 --- a/tox.ini +++ b/tox.ini @@ -18,10 +18,14 @@ envlist = [testenv] usedevelop = true deps = + # Until repoze.sphinx.autointerface supports Sphinx 4.x we cannot use it: + Sphinx < 4 commands = zope-testrunner --test-path=src {posargs:-vc} + !py27-!pypy: sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest extras = test + docs [testenv:lint] basepython = python3 @@ -41,11 +45,10 @@ basepython = python3 skip_install = false # Until repoze.sphinx.autointerface supports Sphinx 4.x we cannot use it: deps = Sphinx < 4 -extras = - docs commands_pre = commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html + sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest [testenv:coverage] basepython = python3 @@ -54,9 +57,12 @@ allowlist_externals = deps = coverage coverage-python-version + # Until repoze.sphinx.autointerface supports Sphinx 4.x we cannot use it: + Sphinx < 4 commands = mkdir -p {toxinidir}/parts/htmlcov coverage run -m zope.testrunner --test-path=src {posargs:-vc} + coverage run -a -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest coverage html coverage report -m --fail-under=100 -- cgit v1.2.1 From 7205ea65d1734863437c8a7ff2993f532f0ba02e Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 2 Sep 2021 12:45:19 +0200 Subject: Removed 'name = main' code from tests. This is not called during the tests, and this results in less coverage. --- src/zope/i18n/locales/tests/test_docstrings.py | 4 ---- src/zope/i18n/locales/tests/test_fallbackcollator.py | 4 ---- src/zope/i18n/tests/test.py | 4 ---- src/zope/i18n/tests/test_negotiator.py | 4 ---- src/zope/i18n/tests/test_simpletranslationdomain.py | 4 ---- src/zope/i18n/tests/test_testmessagecatalog.py | 4 ---- 6 files changed, 24 deletions(-) diff --git a/src/zope/i18n/locales/tests/test_docstrings.py b/src/zope/i18n/locales/tests/test_docstrings.py index 9f75b44..faa4e97 100644 --- a/src/zope/i18n/locales/tests/test_docstrings.py +++ b/src/zope/i18n/locales/tests/test_docstrings.py @@ -38,7 +38,3 @@ def test_suite(): DocTestSuite('zope.i18n.locales.inheritance', checker=unicode_checker), DocTestSuite('zope.i18n.locales.xmlfactory', checker=unicode_checker), )) - - -if __name__ == '__main__': - unittest.main() diff --git a/src/zope/i18n/locales/tests/test_fallbackcollator.py b/src/zope/i18n/locales/tests/test_fallbackcollator.py index e7c84a8..ad78b72 100644 --- a/src/zope/i18n/locales/tests/test_fallbackcollator.py +++ b/src/zope/i18n/locales/tests/test_fallbackcollator.py @@ -23,7 +23,3 @@ def test_suite(): doctest.DocFileSuite('../fallbackcollator.txt', checker=unicode_checker), )) - - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/src/zope/i18n/tests/test.py b/src/zope/i18n/tests/test.py index 05e1366..62082c3 100644 --- a/src/zope/i18n/tests/test.py +++ b/src/zope/i18n/tests/test.py @@ -35,7 +35,3 @@ def test_suite(): suite("zope.i18n.config"), suite("zope.i18n.testing"), ]) - - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/src/zope/i18n/tests/test_negotiator.py b/src/zope/i18n/tests/test_negotiator.py index ef6a470..9267332 100644 --- a/src/zope/i18n/tests/test_negotiator.py +++ b/src/zope/i18n/tests/test_negotiator.py @@ -57,7 +57,3 @@ def test_suite(): return unittest.TestSuite(( unittest.makeSuite(NegotiatorTest), )) - - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/src/zope/i18n/tests/test_simpletranslationdomain.py b/src/zope/i18n/tests/test_simpletranslationdomain.py index 7c87c40..2f233d6 100644 --- a/src/zope/i18n/tests/test_simpletranslationdomain.py +++ b/src/zope/i18n/tests/test_simpletranslationdomain.py @@ -42,7 +42,3 @@ def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestSimpleTranslationDomain)) return suite - - -if __name__ == '__main__': - unittest.TextTestRunner().run(test_suite()) diff --git a/src/zope/i18n/tests/test_testmessagecatalog.py b/src/zope/i18n/tests/test_testmessagecatalog.py index df426fc..e5c8e57 100644 --- a/src/zope/i18n/tests/test_testmessagecatalog.py +++ b/src/zope/i18n/tests/test_testmessagecatalog.py @@ -20,7 +20,3 @@ def test_suite(): return unittest.TestSuite(( doctest.DocFileSuite('../testmessagecatalog.rst') )) - - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') -- cgit v1.2.1 From 0ed53e0d825290d41d6bb1e048ebc111272753b2 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 2 Sep 2021 12:36:53 +0200 Subject: Set minimum coverage at 99 percent. We had 100% test coverage previously, but this dropped to around 99.11 percent when using the new default in tox.ini: ``` [coverage:run] branch = True ``` With branch=False, the coverage would be back at 100 percent, but I don't see a way to configure this in meta.toml, and it may be better to see the actual coverage. We should add more tests to cover the untested branches. For now, we lower our expectations. --- .meta.toml | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.meta.toml b/.meta.toml index e8e5c84..877be7c 100644 --- a/.meta.toml +++ b/.meta.toml @@ -16,7 +16,7 @@ with-sphinx-doctests = true use-flake8 = true [coverage] -fail-under = 100 +fail-under = 99 [manifest] additional-rules = [ diff --git a/tox.ini b/tox.ini index 68e58b0..da82bb1 100644 --- a/tox.ini +++ b/tox.ini @@ -64,7 +64,7 @@ commands = coverage run -m zope.testrunner --test-path=src {posargs:-vc} coverage run -a -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest coverage html - coverage report -m --fail-under=100 + coverage report -m --fail-under=99 [coverage:run] branch = True -- cgit v1.2.1 From cd25a3832b303ca93ddfbea38b17e81500acfaa1 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 2 Sep 2021 12:49:37 +0200 Subject: Add Python 3.8 and 3.9 to classifiers. --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 297b18d..6a7c83e 100644 --- a/setup.py +++ b/setup.py @@ -86,6 +86,8 @@ setup( 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Natural Language :: English', -- cgit v1.2.1 From 72a8f425cc67f5215ef3583f06ea943a95fb798d Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 2 Sep 2021 18:03:05 +0200 Subject: Add changelog entry. --- CHANGES.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 013bb05..c554ca2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,8 @@ 4.7.1 (unreleased) ================== -- Nothing changed yet. +- Support and test Python 3.8 and 3.9. + Full supported list is now: 2.7, 3.5, 3.6, 3.7, 3.8, 3.9, PyPy, PyPy3. 4.7.0 (2019-07-10) -- cgit v1.2.1 From a2d344672595e30b4329944342e61a6819705275 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Fri, 3 Sep 2021 08:55:26 +0200 Subject: Apply suggestions from code review I mixed up Python 2 and 3 in the try/except comment. Co-authored-by: Michael Howitz --- src/zope/i18n/_compat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zope/i18n/_compat.py b/src/zope/i18n/_compat.py index 00fb20f..f6bf93b 100644 --- a/src/zope/i18n/_compat.py +++ b/src/zope/i18n/_compat.py @@ -1,8 +1,8 @@ # This gives a linting error because unicode is not defined on Python 3: # text_type = str if bytes is not str else unicode try: - # Python 3 + # Python 2 text_type = unicode except NameError: - # Python 2 + # Python 3 text_type = str -- cgit v1.2.1 From 51480fc597fa04b2a044b873605cb114efacf9f6 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Fri, 3 Sep 2021 10:52:13 +0200 Subject: Fixed more linting errors. --- src/zope/i18n/format.py | 3 ++- src/zope/i18n/locales/tests/test_xmlfactory.py | 10 ++++++---- src/zope/i18n/locales/xmlfactory.py | 11 ++++++----- src/zope/i18n/tests/test_formats.py | 9 ++++++--- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/zope/i18n/format.py b/src/zope/i18n/format.py index 05431e0..2a2421c 100644 --- a/src/zope/i18n/format.py +++ b/src/zope/i18n/format.py @@ -189,7 +189,8 @@ class DateTimeFormat(object): return tzinfo.localize( datetime.datetime.combine( datetime.date.today(), - datetime.time(*[e or 0 for e in ordered[3:]]))).timetz() + datetime.time(*[e or 0 for e in ordered[3:]])) + ).timetz() return datetime.time( *[e or 0 for e in ordered[3:]], **{'tzinfo': tzinfo} ) diff --git a/src/zope/i18n/locales/tests/test_xmlfactory.py b/src/zope/i18n/locales/tests/test_xmlfactory.py index 0dc070e..e11097c 100644 --- a/src/zope/i18n/locales/tests/test_xmlfactory.py +++ b/src/zope/i18n/locales/tests/test_xmlfactory.py @@ -36,9 +36,11 @@ class LocaleXMLFileTestCase(TestCase): # Making sure all number format patterns parse # for category in (u'decimal', u'scientific', u'percent', u'currency'): - # for length in getattr(locale.numbers, category+'Formats').values(): + # for length in getattr( + # locale.numbers, category + 'Formats' + # ).values(): # for format in length.formats.values(): - # self.assert_(parseNumberPattern(format.pattern) is not None) + # self.assertIsNotNone(parseNumberPattern(format.pattern) # Making sure all datetime patterns parse # for calendar in locale.dates.calendars.values(): @@ -47,8 +49,8 @@ class LocaleXMLFileTestCase(TestCase): # calendar, category + 'Formats' # ).values(): # for format in length.formats.values(): - # self.assert_( - # parseDateTimePattern(format.pattern) is not None + # self.assertIsNotNone( + # parseDateTimePattern(format.pattern) # ) diff --git a/src/zope/i18n/locales/xmlfactory.py b/src/zope/i18n/locales/xmlfactory.py index 0520c2d..f1ed219 100644 --- a/src/zope/i18n/locales/xmlfactory.py +++ b/src/zope/i18n/locales/xmlfactory.py @@ -381,8 +381,8 @@ class LocaleFactory(object): defaultMonthContext_node = months_node.getElementsByTagName('default') if defaultMonthContext_node: - calendar.defaultMonthContext = defaultMonthContext_node[0].getAttribute( - 'type') + calendar.defaultMonthContext = defaultMonthContext_node[ + 0].getAttribute('type') monthContext_nodes = months_node.getElementsByTagName('monthContext') if not monthContext_nodes: @@ -525,8 +525,8 @@ class LocaleFactory(object): defaultDayContext_node = days_node.getElementsByTagName('default') if defaultDayContext_node: - calendar.defaultDayContext = defaultDayContext_node[0].getAttribute( - 'type') + calendar.defaultDayContext = defaultDayContext_node[ + 0].getAttribute('type') dayContext_nodes = days_node.getElementsByTagName('dayContext') if not dayContext_nodes: @@ -904,7 +904,8 @@ class LocaleFactory(object): for formatsName, lengthName, formatName in ( ('dateFormats', 'dateFormatLength', 'dateFormat'), ('timeFormats', 'timeFormatLength', 'timeFormat'), - ('dateTimeFormats', 'dateTimeFormatLength', 'dateTimeFormat')): + ('dateTimeFormats', 'dateTimeFormatLength', + 'dateTimeFormat')): formats_nodes = cal_node.getElementsByTagName(formatsName) if formats_nodes: diff --git a/src/zope/i18n/tests/test_formats.py b/src/zope/i18n/tests/test_formats.py index 4ca039e..a266de6 100644 --- a/src/zope/i18n/tests/test_formats.py +++ b/src/zope/i18n/tests/test_formats.py @@ -787,7 +787,8 @@ class TestNumberPatternParser(_TestCase): self.assertEqual( parseNumberPattern('#,##,##0.###;-#,##,##0.###'), ((None, '', None, '#####0', '###', '', None, '', None, (3, 2, 0)), - (None, '-', None, '#####0', '###', '', None, '', None, (3, 2, 0)))) + (None, '-', None, '#####0', '###', '', None, '', None, + (3, 2, 0)))) self.assertEqual( parseNumberPattern('#,##0.##;-#,##0.##'), @@ -812,7 +813,8 @@ class TestNumberPatternParser(_TestCase): self.assertEqual( parseNumberPattern('##,##,##0.###;-##,##,##0.###'), ((None, '', None, '######0', '###', '', None, '', None, (3, 2, 0)), - (None, '-', None, '######0', '###', '', None, '', None, (3, 2, 0)))) + (None, '-', None, '######0', '###', '', None, '', None, + (3, 2, 0)))) self.assertEqual( parseNumberPattern('##,##0.##;-##,##0.##'), @@ -862,7 +864,8 @@ class TestNumberPatternParser(_TestCase): self.assertEqual( parseNumberPattern('##,##,##0.00;-##,##,##0.00'), ((None, '', None, '######0', '00', '', None, '', None, (3, 2, 0)), - (None, '-', None, '######0', '00', '', None, '', None, (3, 2, 0)))) + (None, '-', None, '######0', '00', '', None, '', None, + (3, 2, 0)))) self.assertEqual( parseNumberPattern('###0.00;-###0.00'), -- cgit v1.2.1