Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1 from zopefoundation/py3
Browse files Browse the repository at this point in the history
Python 3 port
  • Loading branch information
jamadden committed Apr 22, 2017
2 parents a5f907e + a3fbc9c commit 60b48d8
Show file tree
Hide file tree
Showing 16 changed files with 150 additions and 93 deletions.
6 changes: 6 additions & 0 deletions .coveragerc
@@ -0,0 +1,6 @@
[run]
source = src

[report]
exclude_lines =
pragma: no cover
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -9,3 +9,5 @@ build/
dist/
*.egg-info/
.tox/
.coverage
htmlcov/
15 changes: 13 additions & 2 deletions .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
6 changes: 5 additions & 1 deletion CHANGES.txt → CHANGES.rst
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Expand Up @@ -2,7 +2,7 @@ include *.rst
include *.txt
include tox.ini
include bootstrap.py
include buildout.cfg
include *.cfg

recursive-include src *

Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions setup.cfg
@@ -0,0 +1,2 @@
[bdist_wheel]
universal = 1
63 changes: 39 additions & 24 deletions setup.py
Expand Up @@ -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',
)
8 changes: 1 addition & 7 deletions 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
8 changes: 1 addition & 7 deletions 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
24 changes: 15 additions & 9 deletions src/zope/app/dependable/__init__.py
Expand Up @@ -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

Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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:
Expand All @@ -84,21 +85,26 @@ 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):
if not path.startswith("/") and self.pp:
path = self.pp + path
return path


@implementer(IDependable)
class Dependable(PathSetAnnotation):
"""See `IDependable`."""

implements(IDependable)

key = "zope.app.dependable.Dependents"

addDependent = PathSetAnnotation.addPath
Expand Down
2 changes: 2 additions & 0 deletions src/zope/app/dependable/configure.zcml
Expand Up @@ -3,6 +3,8 @@
xmlns:zcml="http://namespaces.zope.org/zcml"
>

<include package="zope.component" file="meta.zcml" />

<adapter
factory="zope.app.dependable.Dependable"
provides="zope.app.dependable.interfaces.IDependable"
Expand Down
3 changes: 2 additions & 1 deletion src/zope/app/dependable/dependency.py
Expand Up @@ -16,6 +16,8 @@
on an object having dependencies. It raises an exception if it's the
case.
"""


__docformat__ = 'restructuredtext'

from zope.i18nmessageid import Message
Expand Down Expand Up @@ -44,4 +46,3 @@ def CheckDependency(event):
"dependents": ", ".join(dependents)
}
raise DependencyError(Message(exception_msg, mapping=mapping))

3 changes: 1 addition & 2 deletions src/zope/app/dependable/interfaces.py
Expand Up @@ -12,9 +12,8 @@
#
##############################################################################
"""Dependable framework interfaces
$Id$
"""

__docformat__ = 'restructuredtext'

from zope.interface import Interface
Expand Down
71 changes: 57 additions & 14 deletions src/zope/app/dependable/tests.py
Expand Up @@ -12,16 +12,20 @@
#
##############################################################################
"""Unit tests for Dependable class.
$Id$
"""
from unittest import TestCase, TestSuite, main, makeSuite

import unittest

from zope.annotation.attribute import AttributeAnnotations
from zope.location.interfaces import ILocationInfo
from zope.interface import implements, verify
from zope.interface import implementer, verify, directlyProvides
from zope.lifecycleevent import ObjectRemovedEvent

from zope.location.interfaces import ILocationInfo

from zope.testing.cleanup import CleanUp

import zope.app.dependable
from zope.app.dependable.dependency import CheckDependency
from zope.app.dependable.interfaces import IDependable, DependencyError

Expand All @@ -30,22 +34,21 @@ class C(object):
pass


@implementer(IDependable, ILocationInfo)
class DummyObject(object):

implements(IDependable, ILocationInfo)

def dependents(self):
return ['dependency1', 'dependency2']

def getPath(self):
return '/dummy-object'


class Test(TestCase):
class TestDependable(unittest.TestCase):

def factory(self):
def factory(self, obj=None):
from zope.app.dependable import Dependable
return Dependable(AttributeAnnotations(C()))
return Dependable(obj if obj is not None else AttributeAnnotations(C()))

def testVerifyInterface(self):
object = self.factory()
Expand Down Expand Up @@ -90,11 +93,51 @@ def testCheckDependency(self):
event = ObjectRemovedEvent(obj, parent, 'oldName')
self.assertRaises(DependencyError, CheckDependency, event)

def testWithParent(self):
grandparent = C()
grandparent.__name__ = 'root'

parent = C()
parent.__name__ = 'parent'
parent.__parent__ = grandparent

obj = AttributeAnnotations(C())
obj.__parent__ = parent
obj.__name__ = 'obj'

from zope.traversing.api import getPath

# If we can't get the parent path, it's just /
dependable = self.factory(obj)
self.assertEqual('/', dependable.pp)

# If we can, it's whatever it reported, always with a
# trailing /
directlyProvides(parent, ILocationInfo)
parent.getPath = lambda: '/root/parent'
dependable = self.factory(obj)
self.assertEqual('/root/parent/', dependable.pp)

parent.getPath = lambda: '/root/parent/'
dependable = self.factory(obj)
self.assertEqual('/root/parent/', dependable.pp)


dependable.addDependent('/root/parent/sibling/nephew')
dependents = list(dependable.dependents())
self.assertEqual(dependents, ['/root/parent/sibling/nephew'])


class TestConfiguration(CleanUp, unittest.TestCase):

def test_configuration(self):
from zope.configuration import xmlconfig
xmlconfig.file('configure.zcml', package=zope.app.dependable)


def test_suite():
return TestSuite((
makeSuite(Test),
))
return unittest.defaultTestLoader.loadTestsFromName(__name__)


if __name__=='__main__':
main(defaultTest='test_suite')
if __name__=='__main__': # pragma: no cover
unittest.main(defaultTest='test_suite')

0 comments on commit 60b48d8

Please sign in to comment.