diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..af40312 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,6 @@ +[run] +source = src + +[report] +exclude_lines = + pragma: no cover diff --git a/.gitignore b/.gitignore index 5149542..6bacfe5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ build/ dist/ *.egg-info/ .tox/ +.coverage +htmlcov/ diff --git a/.travis.yml b/.travis.yml index 02dca11..dc7e4b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,20 @@ language: python +sudo: false python: - 2.7 + - pypy-5.4.1 + - 3.5 + - 3.6 install: - - pip install . + - pip install -U pip setuptools + - pip install -U coverage coveralls + - pip install -U -e .[test] script: - - python setup.py test -q + - coverage run -m zope.testrunner --test-path=src --auto-color --auto-progress notifications: email: false +after_success: + - coveralls +cache: pip +before_cache: + - rm -f $HOME/.cache/pip/log/debug.log diff --git a/CHANGES.txt b/CHANGES.rst similarity index 81% rename from CHANGES.txt rename to CHANGES.rst index ad26321..3a52fd6 100644 --- a/CHANGES.txt +++ b/CHANGES.rst @@ -2,9 +2,13 @@ CHANGES ======= -3.5.2 (unreleased) +4.0.0 (unreleased) ------------------ +- Add support for Python 3.5 and 3.6 and PyPy. + +- Removed support for Python 2.6. + - Added `tox.ini` and manifest. - Removed zope.app.testing dependency. diff --git a/MANIFEST.in b/MANIFEST.in index 61dad0f..de58807 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,7 +2,7 @@ include *.rst include *.txt include tox.ini include bootstrap.py -include buildout.cfg +include *.cfg recursive-include src * diff --git a/README.txt b/README.rst similarity index 100% rename from README.txt rename to README.rst diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..2a9acf1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = 1 diff --git a/setup.py b/setup.py index ed8a981..3bff94b 100644 --- a/setup.py +++ b/setup.py @@ -17,55 +17,70 @@ # Zope Toolkit policies as described by this documentation. ############################################################################## """Setup for zope.app.dependable package - -$Id$ """ import os from setuptools import setup, find_packages def read(*rnames): - return open(os.path.join(os.path.dirname(__file__), *rnames)).read() + with open(os.path.join(os.path.dirname(__file__), *rnames)) as f: + return f.read() + +version = '4.0.0.dev0' +tests_require = [ + 'zope.container', + 'zope.testing', + 'zope.testrunner', +] setup(name='zope.app.dependable', - version = '3.5.2dev', + version=version, author='Zope Corporation and Contributors', author_email='zope-dev@zope.org', description='Simple Dependency API', long_description=( - read('README.txt') + read('README.rst') + '\n\n' + - read('CHANGES.txt') + read('CHANGES.rst') ), - keywords = "zope3 dependency", - classifiers = [ + keywords="zope3 dependency", + classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', - 'Framework :: Zope3'], - url='http://pypi.python.org/pypi/zope.app.dependable', + 'Framework :: Zope3', + ], + url='http://github.com/zopefoundation/zope.app.dependable', license='ZPL 2.1', packages=find_packages('src'), - package_dir = {'': 'src'}, + package_dir={'': 'src'}, namespace_packages=['zope', 'zope.app'], - extras_require=dict(test=[]), - install_requires=['setuptools', - 'zope.annotation', - 'zope.exceptions', - 'zope.i18nmessageid', - 'zope.interface', - 'zope.lifecycleevent', - 'zope.location', - 'zope.traversing', - ], - include_package_data = True, - zip_safe = False, + extras_require={ + 'test': tests_require, + }, + tests_require=tests_require, + install_requires=[ + 'setuptools', + 'zope.annotation', + 'zope.exceptions', + 'zope.i18nmessageid', + 'zope.interface', + 'zope.lifecycleevent', + 'zope.location', + 'zope.traversing', + ], + include_package_data=True, + zip_safe=False, + test_suite='zope.app.dependable.tests', ) diff --git a/src/zope/__init__.py b/src/zope/__init__.py index bf99a9d..155a31d 100644 --- a/src/zope/__init__.py +++ b/src/zope/__init__.py @@ -1,8 +1,2 @@ # this is a namespace package -try: - import pkg_resources - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) - +__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover diff --git a/src/zope/app/__init__.py b/src/zope/app/__init__.py index bf99a9d..155a31d 100644 --- a/src/zope/app/__init__.py +++ b/src/zope/app/__init__.py @@ -1,8 +1,2 @@ # this is a namespace package -try: - import pkg_resources - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) - +__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover diff --git a/src/zope/app/dependable/__init__.py b/src/zope/app/dependable/__init__.py index 7b69dba..b715241 100644 --- a/src/zope/app/dependable/__init__.py +++ b/src/zope/app/dependable/__init__.py @@ -13,11 +13,11 @@ ############################################################################## """Dependable Framework. -$Id$ """ + __docformat__ = 'restructuredtext' -from zope.interface import implements +from zope.interface import implementer from zope.traversing.api import getParent, canonicalPath, getPath from zope.annotation.interfaces import IAnnotations @@ -37,6 +37,7 @@ def __init__(self, context): parent = getParent(self.context) except TypeError: parent = None + if parent is not None: try: pp = getPath(parent) @@ -53,7 +54,7 @@ def addPath(self, path): path = self._make_relative(path) annotations = IAnnotations(self.context) old = annotations.get(self.key, ()) - fixed = map(self._make_relative, old) + fixed = [self._make_relative(o) for o in old] if path not in fixed: fixed.append(path) new = tuple(fixed) @@ -65,7 +66,7 @@ def removePath(self, path): annotations = IAnnotations(self.context) old = annotations.get(self.key, ()) if old: - fixed = map(self._make_relative, old) + fixed = [self._make_relative(o) for o in old] fixed = [loc for loc in fixed if loc != path] new = tuple(fixed) if new != old: @@ -84,8 +85,15 @@ def _make_relative(self, path): path = canonicalPath(path) if path.startswith(self.pp): path = path[self.pplen:] - while path.startswith("/"): - path = path[1:] + # Now, the path should not actually begin with a /. + # canonicalPath doesn't allow trailing / in a path + # segment, and we already cut off the whole length of + # the parent, which we guaranteed to begin and end + # with a /. But it's possible that older dependencies + # than we test with could produce this scenario, so we + # leave it for BWC. + path = path.lstrip("/") + return path def _make_absolute(self, path): @@ -93,12 +101,10 @@ def _make_absolute(self, path): path = self.pp + path return path - +@implementer(IDependable) class Dependable(PathSetAnnotation): """See `IDependable`.""" - implements(IDependable) - key = "zope.app.dependable.Dependents" addDependent = PathSetAnnotation.addPath diff --git a/src/zope/app/dependable/configure.zcml b/src/zope/app/dependable/configure.zcml index e236c6c..fc19784 100644 --- a/src/zope/app/dependable/configure.zcml +++ b/src/zope/app/dependable/configure.zcml @@ -3,6 +3,8 @@ xmlns:zcml="http://namespaces.zope.org/zcml" > + +