Skip to content

Commit

Permalink
Merge pull request #7 from zopefoundation/issue2
Browse files Browse the repository at this point in the history
Reach 100% coverage.
  • Loading branch information
jamadden committed Jun 2, 2017
2 parents 6897484 + b06f728 commit dc1b513
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 41 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -6,3 +6,4 @@ __pycache__
coverage.xml
docs/_build
htmlcov/
.coverage.py*
5 changes: 5 additions & 0 deletions CHANGES.rst
Expand Up @@ -8,6 +8,11 @@ Changes

- Claim support for Python 3.5.

- Reach 100% test coverage.

- ``AttributeAnnotations`` is now always a
``collections.MutableMapping``. Previously on Python 2 it was a
``UserDict.DictMixin``.

4.4.1 (2015-01-09)
------------------
Expand Down
2 changes: 1 addition & 1 deletion src/zope/__init__.py
@@ -1 +1 @@
__import__('pkg_resources').declare_namespace(__name__)
__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover
40 changes: 11 additions & 29 deletions src/zope/annotation/attribute.py
Expand Up @@ -15,21 +15,18 @@
import logging

try:
from BTrees.OOBTree import OOBTree
except ImportError:
logging.getLogger(__name__).warn(
from BTrees.OOBTree import OOBTree as _STORAGE
except ImportError: # pragma: no cover
logging.getLogger(__name__).warning(
'BTrees not available: falling back to dict for attribute storage')
_STORAGE = dict
else:
_STORAGE = OOBTree

from zope import component, interface
from zope.annotation import interfaces

try:
from UserDict import DictMixin
except ImportError:
from collections import MutableMapping as DictMixin
from collections import MutableMapping as DictMixin

_EMPTY_STORAGE = _STORAGE()

@interface.implementer(interfaces.IAnnotations)
@component.adapter(interfaces.IAttributeAnnotatable)
Expand All @@ -50,38 +47,23 @@ def __bool__(self):

def get(self, key, default=None):
"""See zope.annotation.interfaces.IAnnotations"""
annotations = getattr(self.obj, '__annotations__', None)
if not annotations:
return default

annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
return annotations.get(key, default)

def __getitem__(self, key):
annotations = getattr(self.obj, '__annotations__', None)
if annotations is None:
raise KeyError(key)

annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
return annotations[key]

def keys(self):
annotations = getattr(self.obj, '__annotations__', None)
if annotations is None:
return []

annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
return annotations.keys()

def __iter__(self):
annotations = getattr(self.obj, '__annotations__', None)
if annotations is None:
return iter([])

annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
return iter(annotations)

def __len__(self):
annotations = getattr(self.obj, '__annotations__', None)
if annotations is None:
return 0

annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
return len(annotations)

def __setitem__(self, key, value):
Expand Down
24 changes: 20 additions & 4 deletions src/zope/annotation/tests/annotations.py
Expand Up @@ -25,16 +25,16 @@ class AnnotationsTestBase(object):
The test case class expects the 'IAnnotations' implementer to be in
'self.annotations'.
"""
def setUp(self):
super(AnnotationsTestBase, self).setUp()
self.obj = {1:2, 3:4}

annotations = None
obj = None

def test_nonzero(self):
self.assertFalse(self.annotations)
self.annotations['unittest'] = self.obj
self.assertTrue(self.annotations)
del self.annotations['unittest']
self.assertFalse(self.annotations)
self.assertFalse(self.annotations)

def testInterfaceVerifies(self):
verifyObject(IAnnotations, self.annotations)
Expand Down Expand Up @@ -69,6 +69,22 @@ def testDel(self):
self.annotations['unittest'] = self.obj
del self.annotations['unittest']
self.assertEqual(None, self.annotations.get('unittest'))
self.assertEqual([], list(self.annotations.keys()))
self.assertEqual([], list(self.annotations))
self.assertEqual(0, len(self.annotations))

def testDelRaisesKeyError(self):
self.assertRaises(KeyError, self.annotations.__delitem__, 'unittest')

def testKeys(self):
self.assertEqual([], list(self.annotations.keys()))
self.annotations['unittest'] = self.obj
self.assertEqual(1, len(self.annotations))
self.assertEqual(['unittest'], list(self.annotations.keys()))

def testIter(self):
self.assertEqual([], list(self.annotations))
self.annotations['unittest'] = self.obj
self.assertEqual(1, len(self.annotations))
self.assertEqual(['unittest'], list(self.annotations))
self.assertEqual(1, len(self.annotations))
4 changes: 1 addition & 3 deletions src/zope/annotation/tests/test_attributeannotations.py
Expand Up @@ -38,6 +38,4 @@ def tearDown(test=None):


def test_suite():
return unittest.TestSuite((
unittest.makeSuite(AttributeAnnotationsTest),
))
return unittest.defaultTestLoader.loadTestsFromName(__name__)
5 changes: 1 addition & 4 deletions src/zope/annotation/tests/test_configure.py
Expand Up @@ -21,10 +21,7 @@ def test_configure_zcml_should_be_loadable(self):
from zope.configuration.xmlconfig import XMLConfig
import zope.annotation as MUT

try:
XMLConfig('configure.zcml', MUT)()
except Exception as err:
self.fail(err)
XMLConfig('configure.zcml', MUT)()

def test_configure_should_register_n_components(self):
from zope.component import getGlobalSiteManager
Expand Down
117 changes: 117 additions & 0 deletions src/zope/annotation/tests/test_factory.py
@@ -0,0 +1,117 @@
##############################################################################
#
# Copyright (c) 2017 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.
#
##############################################################################

import unittest

from zope.annotation import factory

from zope import interface
from zope import component
from zope.location.interfaces import ILocation

from zope.annotation.interfaces import IAnnotations


class ITarget(interface.Interface):
pass

class IContext(IAnnotations):
pass

@interface.implementer(ITarget)
@component.adapter(IContext)
class Target(object):
pass

@interface.implementer(IContext)
class Context(dict):
pass

class TestFactory(unittest.TestCase):

def test_no_adapts(self):
self.assertRaisesRegexp(TypeError, "Missing.*on annotation",
factory, TestFactory)

def test_factory_no_location(self):

getAnnotation = factory(Target)

context = Context()
target = getAnnotation(context)

# Several things have happened now.
# First, we have an annotation, derived from
# our class name
key = 'zope.annotation.tests.test_factory.Target'
self.assertEqual([key],
list(context))

# Second, a target object is stored at that location.
self.assertEqual(type(context[key]), Target)

# Third, the returned object is an ILocation, rooted at the
# parent and having the given name.
self.assertTrue(ILocation.providedBy(target))
self.assertIs(target.__parent__, context)
self.assertEqual(target.__name__, key)

# But it's a proxy.
self.assertNotEqual(type(target), Target)
self.assertTrue(ITarget.providedBy(target))

def test_factory_location(self):
# Given an object that is a location,
# it is not proxied
@interface.implementer(ILocation)
class LocatedTarget(Target):
__name__ = None
__parent__ = None

getAnnotation = factory(LocatedTarget)

context = Context()
target = getAnnotation(context)

key = 'zope.annotation.tests.test_factory.LocatedTarget'
self.assertEqual([key],
list(context))

# Second, a target object is stored at that location.
self.assertEqual(type(context[key]), LocatedTarget)

# Third, the returned object is an ILocation, rooted at the
# parent and having the given name.
self.assertTrue(ILocation.providedBy(target))
self.assertIs(target.__parent__, context)
self.assertEqual(target.__name__, key)

# And it's not a proxy.
self.assertEqual(type(target), LocatedTarget)
self.assertTrue(ITarget.providedBy(target))
self.assertIs(target, context[key])

def test_factory_with_key(self):

key = 'testkey'
getAnnotation = factory(Target, key)

context = Context()
getAnnotation(context)

self.assertEqual([key],
list(context))

# Second, a target object is stored at that location.
self.assertEqual(type(context[key]), Target)

0 comments on commit dc1b513

Please sign in to comment.