summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Howitz <mh@gocept.com>2021-05-31 08:22:37 +0200
committerGitHub <noreply@github.com>2021-05-31 08:22:37 +0200
commit94bc3003f888118c8b03dc9827ff3a26a2abdf99 (patch)
treed46357e8d209c49dac8514ef41e2eb9feb01b3cf
parent874b0dba1c83323489d618698f42ce36c2c90610 (diff)
parentb30e9f44d6d99d6e1fcba78530bce41d49882f45 (diff)
downloadzope-tales-94bc3003f888118c8b03dc9827ff3a26a2abdf99.tar.gz
Merge branch 'master' into issue19
-rw-r--r--.coveragerc15
-rw-r--r--.editorconfig39
-rw-r--r--.github/workflows/tests.yml61
-rw-r--r--.gitignore40
-rw-r--r--.meta.toml18
-rw-r--r--.travis.yml28
-rw-r--r--CHANGES.rst26
-rw-r--r--MANIFEST.in15
-rw-r--r--README.rst4
-rw-r--r--bootstrap.py210
-rw-r--r--setup.cfg10
-rw-r--r--setup.py11
-rw-r--r--src/zope/__init__.py2
-rw-r--r--src/zope/tales/expressions.py23
-rw-r--r--src/zope/tales/tests/test_expressions.py37
-rw-r--r--tox.ini89
16 files changed, 321 insertions, 307 deletions
diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index 9cb9a8c..0000000
--- a/.coveragerc
+++ /dev/null
@@ -1,15 +0,0 @@
-[run]
-source = zope.tales
-plugins = coverage_python_version
-omit =
- */flycheck_*py
-
-[report]
-precision = 2
-exclude_lines =
- pragma: no cover
- if __name__ == '__main__':
- raise NotImplementedError
- self.fail
- raise AssertionError
- raise unittest.Skip
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..f3e46f5
--- /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}]
+# 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..38cb0de
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,61 @@
+# 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:
+ 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: ubuntu-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 605e07a..9a9e9b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,29 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/pure-python
+*.egg-info/
+*.profraw
*.pyc
-*.so
-*.dll
-__pycache__
-src/*.egg-info
-
-.installed.cfg
-.tox
-bin
-build
-develop-eggs
-parts
+*.pyo
.coverage
-htmlcov/
-docs/_build/
+.coverage.*
+.eggs/
+.installed.cfg
+.mr.developer.cfg
+.tox/
+.vscode/
+__pycache__/
+bin/
+build/
+coverage.xml
+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..2cd2e91
--- /dev/null
+++ b/.meta.toml
@@ -0,0 +1,18 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/pure-python
+[meta]
+template = "pure-python"
+commit-id = "20bd2b81e77d10768865fa8ec7840352a7ebab8f"
+
+[python]
+with-appveyor = false
+with-pypy = true
+with-legacy-python = true
+with-docs = true
+with-sphinx-doctests = false
+
+[tox]
+use-flake8 = true
+
+[coverage]
+fail-under = 99
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 21df3ff..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-language: python
-python:
- - 2.7
- - 3.5
- - 3.6
- - pypy
- - pypy3
-matrix:
- include:
- - python: "3.7"
- dist: xenial
- - python: "3.8"
- dist: xenial
- - name: "flake8"
- install: pip install flake8
- script: flake8 src setup.py
- after_success:
-install:
- - pip install -U pip setuptools
- - pip install -U coverage coverage-python-version coveralls
- - pip install -U -e .[test]
-script:
- - coverage run -m zope.testrunner --test-path=src
-after_success:
- - coveralls
-notifications:
- email: false
-cache: pip
diff --git a/CHANGES.rst b/CHANGES.rst
index 985bf1c..e16a376 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -2,13 +2,37 @@
Changes
=========
-5.0.2 (unreleased)
+5.1.1 (unreleased)
==================
- ``tales.Context.getValue`` now returns the innermost (not outermost)
value for the given variable. Fixes
`#19 <https://github.com/zopefoundation/zope.tales/issues/19>`_.
+- Add support for Python 3.9.
+
+
+5.1 (2020-07-06)
+================
+
+- Packaging and test configuration cleanups
+
+- Improve `PathExpr` reusability
+ Provide customizable support for the use of builtins in path expressions
+ (`#23 <https://github.com/zopefoundation/zope.tales/issues/23>`_)
+
+
+5.0.2 (2020-03-27)
+==================
+
+- Cleanups for Plone 5.2:
+
+ * in path alternatives, whitespace can now surround ``|``,
+
+ * non-ASCII in ``SubPathExpr`` now raises a ``CompilerError``
+ (instead of a ``UnicodeEncodeError``; to be compatible with
+ the ``chameleon`` template engine).
+
5.0.1 (2019-06-26)
==================
diff --git a/MANIFEST.in b/MANIFEST.in
index 7b9f311..38e9c74 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,16 +1,13 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/pure-python
include *.rst
include *.txt
-include tox.ini
-include bootstrap.py
include buildout.cfg
-include .travis.yml
-include .coveragerc
-
-recursive-include src *
+include tox.ini
-recursive-include docs *.rst
recursive-include docs *.py
+recursive-include docs *.rst
+recursive-include docs *.txt
recursive-include docs Makefile
-recursive-include docs make.bat
-global-exclude *.pyc
+recursive-include src *.py
diff --git a/README.rst b/README.rst
index 9c6ebaa..442a7fa 100644
--- a/README.rst
+++ b/README.rst
@@ -10,8 +10,8 @@
:target: https://pypi.org/project/zope.tales/
:alt: Supported Python versions
-.. image:: https://travis-ci.org/zopefoundation/zope.tales.svg?branch=master
- :target: https://travis-ci.org/zopefoundation/zope.tales
+.. image:: https://travis-ci.com/zopefoundation/zope.tales.svg?branch=master
+ :target: https://travis-ci.com/zopefoundation/zope.tales
.. image:: https://coveralls.io/repos/github/zopefoundation/zope.tales/badge.svg?branch=master
:target: https://coveralls.io/github/zopefoundation/zope.tales?branch=master
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 c1e4c65..264b78c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,13 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/pure-python
[bdist_wheel]
universal = 1
[flake8]
-doctests = yes
+doctests = 1
+
+[check-manifest]
+ignore =
+ .editorconfig
+ .meta.toml
+ docs/_build/html/_sources/*
diff --git a/setup.py b/setup.py
index e8788ec..d8df934 100644
--- a/setup.py
+++ b/setup.py
@@ -35,7 +35,7 @@ TESTS_REQUIRE = [
setup(
name='zope.tales',
- version='5.0.2.dev0',
+ version='5.1.1.dev0',
author='Zope Foundation and Contributors',
author_email='zope-dev@zope.org',
description='Zope Template Application Language Expression Syntax '
@@ -58,14 +58,23 @@ 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',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
'Framework :: Zope :: 3',
+ 'Framework :: Zope :: 4',
+ 'Framework :: Zope :: 5',
],
url='https://github.com/zopefoundation/zope.tales',
+ project_urls={
+ 'Documentation': 'https://zopetales.readthedocs.io/',
+ 'Issue Tracker': 'https://github.com/zopefoundation/zope.tales/issues',
+ 'Sources': 'https://github.com/zopefoundation/zope.tales',
+ },
license='ZPL 2.1',
packages=find_packages('src'),
package_dir={'': 'src'},
diff --git a/src/zope/__init__.py b/src/zope/__init__.py
index de40ea7..656dc0f 100644
--- a/src/zope/__init__.py
+++ b/src/zope/__init__.py
@@ -1 +1 @@
-__import__('pkg_resources').declare_namespace(__name__)
+__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover
diff --git a/src/zope/tales/expressions.py b/src/zope/tales/expressions.py
index 81a626b..dd8980c 100644
--- a/src/zope/tales/expressions.py
+++ b/src/zope/tales/expressions.py
@@ -60,6 +60,8 @@ class SubPathExpr(object):
Implementation of a single path expression.
"""
+ ALLOWED_BUILTINS = {}
+
def __init__(self, path, traverser, engine):
self._traverser = traverser
self._engine = engine
@@ -67,7 +69,13 @@ class SubPathExpr(object):
# Parse path
compiledpath = []
currentpath = []
- for element in str(path).strip().split('/'):
+ try:
+ path = str(path)
+ except Exception as e:
+ raise engine.getCompilerError()(
+ 'could not convert %r to `str`: %s: %s'
+ % (path, e.__class__.__name__, str(e)))
+ for element in path.strip().split('/'):
if not element:
raise engine.getCompilerError()(
'Path element may not be empty in %r' % path)
@@ -131,7 +139,12 @@ class SubPathExpr(object):
if base == 'CONTEXTS' or not base: # Special base name
ob = econtext.contexts
else:
- ob = vars[base]
+ try:
+ ob = vars[base]
+ except KeyError:
+ ob = self.ALLOWED_BUILTINS.get(base, _marker)
+ if ob is _marker:
+ raise
if isinstance(ob, DeferWrapper):
ob = ob()
@@ -171,6 +184,8 @@ class PathExpr(object):
'nocall',
)
+ SUBEXPR_FACTORY = SubPathExpr
+
def __init__(self, name, expr, engine, traverser=simpleTraverse):
self._s = expr
self._name = name
@@ -186,7 +201,7 @@ class PathExpr(object):
add(engine.compile('|'.join(paths[i:]).lstrip()))
self._hybrid = True
break
- add(SubPathExpr(path, traverser, engine)._eval)
+ add(self.SUBEXPR_FACTORY(path, traverser, engine)._eval)
def _exists(self, econtext):
for expr in self._subexprs:
@@ -242,7 +257,7 @@ class PathExpr(object):
_interp = re.compile(
- r'\$(%(n)s)|\${(%(n)s(?:/[^}|]*)*(?:\|%(n)s(?:/[^}|]*)*)*)}'
+ r'\$(%(n)s)|\${(%(n)s(?:/[^}|]*)*(?:\|\s*%(n)s(?:/[^}|]*)*)*)}'
% {'n': NAME_RE})
diff --git a/src/zope/tales/tests/test_expressions.py b/src/zope/tales/tests/test_expressions.py
index 1996445..1653c29 100644
--- a/src/zope/tales/tests/test_expressions.py
+++ b/src/zope/tales/tests/test_expressions.py
@@ -161,6 +161,20 @@ class TestParsedExpressions(ExpressionTestBase):
expr = self.engine.compile('path:ErrorGenerator/%s|b|c/d/e' % e)
self._check_evals_to(expr, 'boot')
+ def testOrPathWithSpaces(self):
+ expr = self.engine.compile('path:a | b | c/d/e')
+ self._check_evals_to(expr, 'boot')
+
+ for e in 'Undefined', 'AttributeError', 'LookupError', 'TypeError':
+ expr = self.engine.compile(
+ 'path:ErrorGenerator/%s | b | c/d/e' % e)
+ self._check_evals_to(expr, 'boot')
+
+ def testNonAsciiPath(self):
+ error = self.engine.getCompilerError()
+ with self.assertRaises(error):
+ self.engine.compile(u'path: รค')
+
def test_path_CONTEXTS(self):
self.context.contexts = 42
self._check_evals_to('CONTEXTS', 42)
@@ -373,6 +387,29 @@ class TestParsedExpressions(ExpressionTestBase):
"Invalid variable name"
)
+ def test_builtins_in_path(self):
+ from ..tales import ExpressionEngine
+ from ..expressions import PathExpr, SubPathExpr
+
+ class MySubPathExpr(SubPathExpr):
+ ALLOWED_BUILTINS = {'True': True, 'False': False, 'x': None}
+
+ class MyPathExpr(PathExpr):
+ SUBEXPR_FACTORY = MySubPathExpr
+
+ engine = ExpressionEngine()
+ for pt in MyPathExpr._default_type_names:
+ engine.registerType(pt, MyPathExpr)
+
+ def eval(expr):
+ return engine.compile(expr)(self.context)
+
+ self.assertTrue(eval("True"))
+ self.assertFalse(eval("False"))
+ with self.assertRaises(KeyError):
+ eval("None")
+ self.assertIsNotNone(eval("x")) # variable before builtin
+
class FunctionTests(ExpressionTestBase):
diff --git a/tox.ini b/tox.ini
index 5413964..a30fca4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,36 +1,81 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/pure-python
[tox]
+minversion = 3.18
envlist =
- flake8,py27,py35,py36,py37,py38,pypy,pypy3,coverage,docs
+ lint
+ py27
+ py35
+ py36
+ py37
+ py38
+ py39
+ pypy
+ pypy3
+ docs
+ coverage
[testenv]
-commands =
- zope-testrunner --test-path=src []
-deps =
- .[test]
-
-[testenv:coverage]
usedevelop = true
-basepython =
- python3.7
+deps =
+ zope.testrunner
commands =
- coverage run -m zope.testrunner --test-path=src []
- coverage report --show-missing --fail-under=100
+ zope-testrunner --test-path=src {posargs:-vc}
+extras =
+ test
+
+[testenv:lint]
+basepython = python3
+skip_install = true
deps =
- {[testenv]deps}
- coverage
- coverage-python-version
+ flake8
+ check-manifest
+ check-python-versions
+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 =
- {[testenv]deps}
- .[docs]
+ coverage
+ coverage-python-version
+ zope.testrunner
+commands =
+ mkdir -p {toxinidir}/parts/htmlcov
+ coverage run -m zope.testrunner --test-path=src {posargs:-vc}
+ coverage html
+ coverage report -m --fail-under=99
+
+[coverage:run]
+branch = True
+plugins = coverage_python_version
+source = src
+[coverage:report]
+precision = 2
+exclude_lines =
+ pragma: no cover
+ pragma: nocover
+ except ImportError:
+ raise NotImplementedError
+ if __name__ == '__main__':
+ self.fail
+ raise AssertionError
-[testenv:flake8]
-deps = flake8
-skipinstall = true
-commands = flake8 setup.py src
+[coverage:html]
+directory = parts/htmlcov