diff --git a/.coveragerc b/.coveragerc
index 524acac..fdbb39f 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -7,3 +7,4 @@ exclude_lines =
     if __name__ == '__main__':
     raise NotImplementedError
     self.fail
+    raise AssertionError
diff --git a/CHANGES.rst b/CHANGES.rst
index e6ef488..b8dc77a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -9,6 +9,26 @@
 
 - Drop support for Python 2.6 and 3.3.
 
+- Make ``OrderedContainer`` properly store the decoded text keys for
+  maintaining order instead of the raw bytes. Also make it able to
+  accept raw bytes under Python 3 in the first place. Fixes
+  https://github.com/zopefoundation/zope.container/issues/17
+
+- Fix ``OrderedContainer`` becoming inconsistent if an event
+  subscriber threw an exception when adding an item. See
+  https://github.com/zopefoundation/zope.container/issues/18
+
+- Attain 100% test coverage. See
+  https://github.com/zopefoundation/zope.container/issues/15
+
+- Make the default ``NameChooser`` always decode bytes using ASCII instead of
+  whatever the current system codec happens to be.
+
+- Make the default ``NameChooser`` stop catching ``KeyboardInterrupt``
+  and other ``BaseException`` types when it potentially calls
+  user-defined code to convert a name to a text string. Instead, just
+  catch ``Exception``.
+
 4.1.0 (2015-05-22)
 ==================
 
diff --git a/src/zope/container/constraints.py b/src/zope/container/constraints.py
index d6ea5a3..4a58c93 100644
--- a/src/zope/container/constraints.py
+++ b/src/zope/container/constraints.py
@@ -184,13 +184,12 @@ def checkObject(container, name, object):
 
     # check the constraint on __parent__
     __parent__ = providedBy(object).get('__parent__')
-    if __parent__ is not None:
-        try:
-            validate = __parent__.validate
-        except AttributeError:
-            pass
-        else:
-            validate(container)
+    try:
+        validate = __parent__.validate
+    except AttributeError:
+        pass
+    else:
+        validate(container)
 
 
     if not containerProvided.extends(IContainer):
@@ -201,31 +200,29 @@ def checkObject(container, name, object):
 
 def checkFactory(container, name, factory):
     __setitem__ = providedBy(container).get('__setitem__')
-    if __setitem__ is not None:
+
+    try:
         precondition = __setitem__.queryTaggedValue('precondition')
-        if precondition is not None:
-            try:
-                precondition = precondition.factory
-            except AttributeError:
-                pass
-            else:
-                try:
-                    precondition(container, name, factory)
-                except zope.interface.Invalid:
-                    return False
+        precondition = precondition.factory
+    except AttributeError:
+        pass
+    else:
+        try:
+            precondition(container, name, factory)
+        except zope.interface.Invalid:
+            return False
 
     # check the constraint on __parent__
     __parent__ = factory.getInterfaces().get('__parent__')
-    if __parent__ is not None:
+    try:
+        validate = __parent__.validate
+    except AttributeError:
+        pass
+    else:
         try:
-            validate = __parent__.validate
-        except AttributeError:
-            pass
-        else:
-            try:
-                validate(container)
-            except zope.interface.Invalid:
-                return False
+            validate(container)
+        except zope.interface.Invalid:
+            return False
 
     return True
 
@@ -341,7 +338,7 @@ class ItemTypePrecondition(_TypesBased):
 
         for iface in self.types:
             if implemented.isOrExtends(iface):
-               return
+                return
         raise InvalidItemType(container, factory, self.types)
 
 
@@ -378,11 +375,15 @@ def contains(*types):
     if not (f_locals is not f_globals
             and f_locals.get('__module__')
             and f_locals.get('__module__') == f_globals.get('__name__')
-            ):
+    ):
         raise TypeError("contains not called from suite")
 
     def __setitem__(key, value):
-        pass
+        """
+        This serves as a copy of IContainer.__setitem__ to hold
+        the ``precondition`` attribute. Note that it replaces a local
+        __setitem__ defined before.
+        """
     __setitem__.__doc__ = IContainer['__setitem__'].__doc__
     __setitem__.precondition = ItemTypePrecondition(
         *types,
@@ -426,11 +427,10 @@ class ContainerTypesConstraint(_TypesBased):
     True
     """
     def __call__(self, object):
-       for iface in self.types:
-           if iface.providedBy(object):
-               return True
-       else:
-           raise InvalidContainerType(object, self.types)
+        for iface in self.types:
+            if iface.providedBy(object):
+                return True
+        raise InvalidContainerType(object, self.types)
 
 
 def containers(*types):
@@ -468,13 +468,13 @@ def containers(*types):
     if not (f_locals is not f_globals
             and f_locals.get('__module__')
             and f_locals.get('__module__') == f_globals.get('__name__')
-            ):
+    ):
         raise TypeError("containers not called from suite")
 
     __parent__ = zope.schema.Field(
-        constraint = ContainerTypesConstraint(
+        constraint=ContainerTypesConstraint(
             *types,
             **dict(module=f_globals['__name__'])
-            )
         )
+    )
     f_locals['__parent__'] = __parent__
diff --git a/src/zope/container/contained.py b/src/zope/container/contained.py
index 4c90b67..cab0ea2 100644
--- a/src/zope/container/contained.py
+++ b/src/zope/container/contained.py
@@ -32,8 +32,10 @@ from zope.container.interfaces import IContainerModifiedEvent
 try:
     from zope.container._zope_container_contained import ContainedProxyBase
     from zope.container._zope_container_contained import getProxiedObject
+    from zope.container._zope_container_contained import setProxiedObject
 except ImportError: # PyPy
     from zope.container._proxy import py_getProxiedObject as getProxiedObject
+    from zope.container._proxy import py_setProxiedObject as setProxiedObject
     from zope.container._proxy import PyContainedProxyBase as ContainedProxyBase
 
 from zope.lifecycleevent import ObjectMovedEvent
@@ -46,11 +48,7 @@ except ImportError:
     class IBroken(Interface):
         pass
 
-try:
-    unicode
-except NameError:
-    # Py3: Define unicode type.
-    unicode = str
+from six import text_type
 
 PY3 = sys.version_info[0] >= 3
 
@@ -157,8 +155,7 @@ def dispatchToSublocations(object, event):
     subs = ISublocations(object, None)
     if subs is not None:
         for sub in subs.sublocations():
-            for ignored in zope.component.subscribers((sub, event), None):
-                pass # They do work in the adapter fetch
+            zope.component.handle(sub, event)
 
 class ContainerSublocations(object):
     """Get the sublocations for a container
@@ -553,7 +550,7 @@ def setitem(container, setitemf, name, object):
             name = name.decode('ascii')
         except UnicodeError:
             raise TypeError("name not unicode or ascii string")
-    elif not isinstance(name, unicode):
+    elif not isinstance(name, text_type):
         raise TypeError("name not unicode or ascii string")
 
     if not name:
@@ -757,8 +754,8 @@ class NameChooser(object):
         """
 
         if isinstance(name, bytes):
-            name = name.decode()
-        elif not isinstance(name, unicode):
+            name = name.decode('ascii')
+        elif not isinstance(name, text_type):
             raise TypeError("Invalid name type", type(name))
 
         if not name:
@@ -826,18 +823,18 @@ class NameChooser(object):
 
         # convert to unicode and remove characters that checkName does not allow
         if isinstance(name, bytes):
-            name = name.decode()
-        if not isinstance(name, unicode):
+            name = name.decode('ascii')
+        if not isinstance(name, text_type):
             try:
-                name = unicode(name)
-            except:
+                name = text_type(name)
+            except Exception:
                 name = u''
         name = name.replace('/', '-').lstrip('+@')
 
         if not name:
             name = object.__class__.__name__
             if isinstance(name, bytes):
-                name = name.decode()
+                name = name.decode('ascii')
 
         # for an existing name, append a number.
         # We should keep client's os.path.extsep (not ours), we assume it's '.'
@@ -878,7 +875,6 @@ class DecoratorSpecificationDescriptor(
     ... class D1(ContainedProxy):
     ...   pass
 
-
     >>> @implementer(I2)
     ... class D2(ContainedProxy):
     ...   pass
@@ -905,43 +901,77 @@ class DecoratorSpecificationDescriptor(
     ['I4', 'I3', 'I1', 'IContained', 'IPersistent', 'I2']
     """
     def __get__(self, inst, cls=None):
-        if inst is None:
+        if inst is None: # pragma: no cover (Not sure how we can get here)
             return getObjectSpecification(cls)
-        else:
-            provided = providedBy(getProxiedObject(inst))
 
-            # Use type rather than __class__ because inst is a proxy and
-            # will return the proxied object's class.
-            cls = type(inst)
-            return ObjectSpecification(provided, cls)
+        provided = providedBy(getProxiedObject(inst))
+
+        # Use type rather than __class__ because inst is a proxy and
+        # will return the proxied object's class.
+        cls = type(inst)
+        return ObjectSpecification(provided, cls)
 
 
 class DecoratedSecurityCheckerDescriptor(object):
-    """Descriptor for a Decorator that provides a decorated security checker.
+    """
+    Descriptor for a Decorator that provides a decorated security
+    checker.
+
+    >>> class WithChecker(object):
+    ...     __Security_checker__ = object()
+
+    >>> class D1(ContainedProxy):
+    ...    pass
+
+
+    >>> d = D1(object())
+    >>> d.__Security_checker__ # doctest: +ELLIPSIS
+    <...Checker...>
+
+    An existing checker is added to this one:
+
+    >>> d = D1(WithChecker())
+    >>> d.__Security_checker__ # doctest: +ELLIPSIS
+    <...CombinedChecker...>
     """
     def __get__(self, inst, cls=None):
-        if inst is None:
+        if inst is None: # pragma: no cover (Not sure how we can get here)
             return self
-        else:
-            proxied_object = getProxiedObject(inst)
-            checker = getattr(proxied_object, '__Security_checker__', None)
-            if checker is None:
-                checker = selectChecker(proxied_object)
-            wrapper_checker = selectChecker(inst)
-            if wrapper_checker is None:
-                return checker
-            elif checker is None:
-                return wrapper_checker
-            else:
-                return CombinedChecker(wrapper_checker, checker)
 
-class ContainedProxyClassProvides(zope.interface.declarations.ClassProvides):
+        proxied_object = getProxiedObject(inst)
+        checker = getattr(proxied_object, '__Security_checker__', None)
+        if checker is None:
+            checker = selectChecker(proxied_object)
+        wrapper_checker = selectChecker(inst)
+        if wrapper_checker is None: # pragma: no cover
+            return checker
+        if checker is None:
+            return wrapper_checker
+        return CombinedChecker(wrapper_checker, checker)
 
+class ContainedProxyClassProvides(zope.interface.declarations.ClassProvides):
+    """
+    Delegates __provides__ to the instance.
+
+    >>> class D1(ContainedProxy):
+    ...    pass
+    >>> class Base(object):
+    ...    pass
+    >>> base = Base()
+    >>> d = D1(base)
+    >>> d.__provides__ = 42
+    >>> base.__provides__
+    42
+    >>> del d.__provides__
+    >>> hasattr(base, '__provides__')
+    False
+    """
     def __set__(self, inst, value):
         inst = getProxiedObject(inst)
         inst.__provides__ = value
 
     def __delete__(self, inst):
+        # CPython can hit this, PyPy/PURE_PYTHON cannot
         inst = getProxiedObject(inst)
         del inst.__provides__
 
diff --git a/src/zope/container/ordered.py b/src/zope/container/ordered.py
index bb13541..f256010 100644
--- a/src/zope/container/ordered.py
+++ b/src/zope/container/ordered.py
@@ -14,7 +14,7 @@
 """Ordered container implementation.
 """
 __docformat__ = 'restructuredtext'
-import six
+
 from persistent import Persistent
 from persistent.dict import PersistentDict
 from persistent.list import PersistentList
@@ -160,6 +160,11 @@ class OrderedContainer(Persistent, Contained):
 
     has_key = __contains__
 
+    def _setitemf(self, key, value):
+        if key not in self._data:
+            self._order.append(key)
+        self._data[key] = value
+
     def __setitem__(self, key, object):
         """ See `IOrderedContainer`.
 
@@ -182,40 +187,11 @@ class OrderedContainer(Persistent, Contained):
         >>> oc._order
         ['foo', 'baz']
         """
-
-        existed = key in self._data
-
-        bad = False
-        if isinstance(key, six.string_types):
-            try:
-                key.decode()
-            except AttributeError:
-                # Py3 str cannot decode.
-                pass
-            except UnicodeError:
-                bad = True
-        else:
-            bad = True
-        if bad:
-            raise TypeError("'%s' is invalid, the key must be an "
-                            "ascii or unicode string" % key)
-        if len(key) == 0:
-            raise ValueError("The key cannot be an empty string")
-
-        # We have to first update the order, so that the item is available,
-        # otherwise most API functions will lie about their available values
-        # when an event subscriber tries to do something with the container.
-        if not existed:
-            self._order.append(key)
-
-        # This function creates a lot of events that other code listens to.
-        try:
-            setitem(self, self._data.__setitem__, key, object)
-        except Exception:
-            if not existed:
-                self._order.remove(key)
-            raise
-
+        # This function creates a lot of events that other code
+        # listens to. None of them are fired (notified) though, before
+        # _setitemf is called. At that point we need to be sure that
+        # we have the key in _order too.
+        setitem(self, self._setitemf, key, object)
         return key
 
     def __delitem__(self, key):
@@ -290,8 +266,7 @@ class OrderedContainer(Persistent, Contained):
         0
         """
 
-        if not isinstance(order, list) and \
-            not isinstance(order, tuple):
+        if not isinstance(order, (list, tuple)):
             raise TypeError('order must be a tuple or a list.')
 
         if len(order) != len(self._order):
@@ -301,10 +276,10 @@ class OrderedContainer(Persistent, Contained):
         will_be_dict = {}
         new_order = PersistentList()
 
-        for i in range(len(order)):
+        for i, obj in enumerate(order):
             was_dict[self._order[i]] = 1
-            will_be_dict[order[i]] = 1
-            new_order.append(order[i])
+            will_be_dict[obj] = 1
+            new_order.append(obj)
 
         if will_be_dict != was_dict:
             raise ValueError("Incompatible key set.")

OrderedContainer uses the wrong name in `self._order` and rejects ascii keys under Python 3
It uses `z.c.contained.setitem()` to put the data in `self._data`. That function will decode a `bytes` key if needed before storing it with the provided `__setitem__` function. But OrderedContainer stores the original value, not the decoded value. When you then go to delete the item, it removes it from `_order` by the key that you provide. 

This is more-or-less fine on Python 2 because of the implicit conversions between bytes and unicode---assuming the default locale stays the same everywhere:
```pycon
>>> from zope.container.ordered import OrderedContainer
>>> oc = OrderedContainer()
>>> oc[b'abc'] = 1
>>> del oc[u'abc']
```

On Python 3 there is an explicit pre-check that prevents bytes from even getting into `setitem`:
```pycon
>>> from zope.container.ordered import OrderedContainer
>>> oc = OrderedContainer()
>>> oc[b'abc'] = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "//.tox/py36/lib/python3.6/site-packages/zope/container/ordered.py", line 201, in __setitem__
    "ascii or unicode string" % key)
TypeError: 'b'abc'' is invalid, the key must be an ascii or unicode string
```

This pre-check is not actually tested. If we remove the pre-check so that `setitem` can do its decoding thing, then we can't remove the data:
```
>>> from zope.container.ordered import OrderedContainer
>>> oc = OrderedContainer()
>>> oc[b'abc'] = 1
>>> del oc[u'abc']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "//.tox/py36/lib/python3.6/site-packages/zope/container/ordered.py", line 244, in __delitem__
    self._order.remove(key)
  File "//.tox/py36/lib/python3.6/site-packages/persistent/list.py", line 84, in remove
    self.__super_remove(item)
  File "//.tox/py36/lib/python3.6/collections/__init__.py", line 1084, in remove
    def remove(self, item): self.data.remove(item)
ValueError: list.remove(x): x not in list
```

This is a pretty easy fix

diff --git a/src/zope/container/tests/directory.rst b/src/zope/container/tests/directory.rst
index d47f8bd..5a91e9a 100644
--- a/src/zope/container/tests/directory.rst
+++ b/src/zope/container/tests/directory.rst
@@ -30,6 +30,20 @@ The new folder isn't a site manager and doesn't have any entries:
   >>> 'test' in fs_folder
   False
 
+If we pretend that our folder is a site, we have that entry:
+
+  >>> from zope.component.interfaces import ISite
+  >>> from zope.interface import alsoProvides
+  >>> alsoProvides(folder, ISite)
+  >>> folder.getSiteManager = lambda: 42
+  >>> list(fs_folder.keys())
+  ['++etc++site']
+  >>> fs_folder['++etc++site']
+  42
+  >>> len(fs_folder)
+  1
+
+
 This is a short regression test for #728: we get a KeyError when trying to
 access non-existing entries:
 
@@ -40,4 +54,3 @@ access non-existing entries:
   >>> print(proxied_fs_folder['i dont exist'])
   Traceback (most recent call last):
   KeyError: 'i dont exist'
-
diff --git a/src/zope/container/tests/test_btree.py b/src/zope/container/tests/test_btree.py
index da2d59b..e3125a8 100644
--- a/src/zope/container/tests/test_btree.py
+++ b/src/zope/container/tests/test_btree.py
@@ -13,10 +13,10 @@
 ##############################################################################
 """BTree Container Tests
 """
-from doctest import DocTestSuite
-from unittest import TestCase, main, makeSuite, TestSuite
+import unittest
+
 from zope.interface.verify import verifyObject
-from zope.component.testing import setUp, tearDown
+
 from zope.container.tests.test_icontainer import TestSampleContainer
 from zope.container.btree import BTreeContainer
 from zope.container.interfaces import IBTreeContainer
@@ -25,18 +25,22 @@ from zope.container.contained import Contained
 from zope.lifecycleevent.interfaces import IObjectRemovedEvent
 
 
-class TestBTreeContainer(TestSampleContainer, TestCase):
+class TestBTreeContainer(TestSampleContainer, unittest.TestCase):
 
     def makeTestObject(self):
         return BTreeContainer()
 
 
-class TestBTreeSpecials(TestCase):
+class TestBTreeSpecials(unittest.TestCase):
 
     def testStoredLength(self):
-        # This is lazy for backward compatibility.  If the len is not
+        # This is a lazy property for backward compatibility.  If the len is not
         # stored already we set it to the length of the underlying
         # btree.
+        lazy = BTreeContainer._BTreeContainer__len
+        self.assertIs(lazy, BTreeContainer.__dict__['_BTreeContainer__len'])
+        self.assertTrue(hasattr(lazy, '__get__'))
+
         bc = BTreeContainer()
         self.assertEqual(bc.__dict__['_BTreeContainer__len'](), 0)
         del bc.__dict__['_BTreeContainer__len']
@@ -45,6 +49,12 @@ class TestBTreeSpecials(TestCase):
         self.assertEqual(len(bc), 1)
         self.assertEqual(bc.__dict__['_BTreeContainer__len'](), 1)
 
+        del bc.__dict__['_BTreeContainer__len']
+        self.assertFalse('_BTreeContainer__len' in bc.__dict__)
+        self.assertEqual(len(bc), 1)
+        self.assertEqual(bc.__dict__['_BTreeContainer__len'](), 1)
+
+
     # The tests which follow test the additional signatures and declarations
     # for the BTreeContainer that allow it to provide the IBTreeContainer
     # interface.
@@ -164,7 +174,7 @@ class TestBTreeSpecials(TestCase):
         self.assertEqual(list(iterable), first_time)
 
 
-class TestBTreeEvents(TestCase):
+class TestBTreeEvents(unittest.TestCase):
 
     def setUp(self):
         from zope.event import subscribers
@@ -198,11 +208,7 @@ class TestBTreeEvents(TestCase):
 
 
 def test_suite():
-    return TestSuite((
-        makeSuite(TestBTreeContainer),
-        makeSuite(TestBTreeSpecials),
-        makeSuite(TestBTreeEvents),
-        ))
-
-if __name__=='__main__':
-    main(defaultTest='test_suite')
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
diff --git a/src/zope/container/tests/test_constraints.py b/src/zope/container/tests/test_constraints.py
index 7ea9c7e..e377675 100644
--- a/src/zope/container/tests/test_constraints.py
+++ b/src/zope/container/tests/test_constraints.py
@@ -15,10 +15,57 @@
 """
 import unittest
 
+class TestUnaddableError(unittest.TestCase):
+
+    def test_str(self):
+        from zope.container.interfaces import UnaddableError
+        e = UnaddableError("'container'", "'obj'", "Extra")
+        self.assertEqual(str(e),
+                         "'obj' cannot be added to 'container': Extra")
+
+class TestCheckObject(unittest.TestCase):
+
+    def test_non_container(self):
+        from zope.container.constraints import checkObject
+
+        with self.assertRaisesRegexp(TypeError,
+                                     "Container is not a valid Zope container."):
+            checkObject({}, 'foo', 42)
+
+
+class TestCheckFactory(unittest.TestCase):
+
+    def test_no_validate_on_parent(self):
+        # Does nothing if no constraints are provided
+        from zope.container.constraints import checkFactory
+
+        class Factory(object):
+            def getInterfaces(self):
+                return {}
+
+        result = checkFactory({}, 'name', Factory())
+        self.assertTrue(result)
+
+
+class TestTypesBased(unittest.TestCase):
+
+    def test_raw_types(self):
+        from zope.container.constraints import _TypesBased
+
+        t = _TypesBased('.TestTypesBased', module=__name__)
+        self.assertEqual(t.types, [TestTypesBased])
+
+    def test_raw_types_property(self):
+        from zope.container.constraints import _TypesBased
+
+        t = _TypesBased.types
+        self.assertTrue(hasattr(t, '__get__'))
+
 def test_suite():
     import doctest
     from zope.container import testing
     return unittest.TestSuite((
+        unittest.defaultTestLoader.loadTestsFromName(__name__),
         doctest.DocTestSuite(
             'zope.container.constraints',
             checker=testing.checker),
diff --git a/src/zope/container/tests/test_contained.py b/src/zope/container/tests/test_contained.py
index 2c7f0c3..cc103e2 100644
--- a/src/zope/container/tests/test_contained.py
+++ b/src/zope/container/tests/test_contained.py
@@ -13,9 +13,9 @@
 ##############################################################################
 """Contained Tests
 """
-
+from __future__ import absolute_import
 import doctest
-import gc
+
 import unittest
 
 from persistent import Persistent
@@ -23,7 +23,10 @@ from persistent import Persistent
 import zope.interface
 import zope.component
 
-from zope.container.contained import ContainedProxy, NameChooser
+from zope.container.contained import ContainedProxy
+from zope.container.contained import NameChooser
+from zope.container.contained import contained
+from zope.container.contained import uncontained
 from zope.container.sample import SampleContainer
 from zope.container import testing
 from zope.container.interfaces import NameReserved, IContainer, IReservedNames
@@ -31,114 +34,108 @@ from zope.container.interfaces import NameReserved, IContainer, IReservedNames
 class MyOb(Persistent):
     pass
 
-def test_basic_proxy_attribute_management_and_picklability():
-    """Contained-object proxy
-
-    This is a picklable proxy that can be put around objects that
-    don't implement IContained.
-
-    >>> l = [1, 2, 3]
-    >>> p = ContainedProxy(l)
-    >>> p.__parent__ = 'Dad'
-    >>> p.__name__ = 'p'
-    >>> p
-    [1, 2, 3]
-    >>> p.__parent__
-    'Dad'
-    >>> p.__name__
-    'p'
 
-    >>> import pickle
-    >>> p2 = pickle.loads(pickle.dumps(p))
-    >>> p2
-    [1, 2, 3]
-    >>> p2.__parent__
-    'Dad'
-    >>> p2.__name__
-    'p'
-    """
+class TestContainedProxy(unittest.TestCase):
+
+    def test_basic_proxy_attribute_management_and_picklability(self):
+        # Contained-object proxy
+
+        # This is a picklable proxy that can be put around objects that
+        # don't implement IContained.
+
+        l = [1, 2, 3]
+        p = ContainedProxy(l)
+        p.__parent__ = 'Dad'
+        p.__name__ = 'p'
+        self.assertEqual([1, 2, 3], p)
+        self.assertEqual('Dad', p.__parent__)
+        self.assertEqual('p', p.__name__)
+
+        import pickle
+        p2 = pickle.loads(pickle.dumps(p))
+        self.assertEqual([1, 2, 3], p2)
+        self.assertEqual('Dad', p2.__parent__)
+        self.assertEqual('p', p2.__name__)
+
+    def test_declarations_on_ContainedProxy(self):
+        # It is possible to make declarations on ContainedProxy objects.
+        from zope.container.interfaces import IContained
+        from persistent.interfaces import IPersistent
+
+        class I1(zope.interface.Interface):
+            pass
+        @zope.interface.implementer(I1)
+        class C(object):
+            pass
+
+        c = C()
+        p = ContainedProxy(c)
 
-def test_declarations_on_ContainedProxy():
-    r"""
+        # ContainedProxy provides no interfaces on it's own:
 
-    It is possible to make declarations on ContainedProxy objects.
+        self.assertEqual((),
+                         tuple(zope.interface.providedBy(ContainedProxy)))
 
-      >>> class I1(zope.interface.Interface):
-      ...     pass
-      >>> @zope.interface.implementer(I1)
-      ... class C(object):
-      ...     pass
 
-      >>> c = C()
-      >>> p = ContainedProxy(c)
+        # It implements IContained and IPersistent:
+        self.assertEqual((IContained, IPersistent),
+                         tuple(zope.interface.implementedBy(ContainedProxy)))
 
-    ContainedProxy provides no interfaces on it's own:
+        # A proxied object has IContainer, in addition to what the unproxied
+        # object has:
+        self.assertEqual(tuple(zope.interface.providedBy(p)),
+                         (I1, IContained, IPersistent))
 
-      >>> tuple(zope.interface.providedBy(ContainedProxy))
-      ()
+        class I2(zope.interface.Interface):
+            pass
+        zope.interface.directlyProvides(c, I2)
+        self.assertEqual(tuple(zope.interface.providedBy(p)),
+                         (I2, I1, IContained, IPersistent))
 
-    It implements IContained and IPersistent:
+        # We can declare interfaces through the proxy:
 
-      >>> tuple(zope.interface.implementedBy(ContainedProxy))
-      (<InterfaceClass zope.location.interfaces.IContained>,
-       <InterfaceClass persistent.interfaces.IPersistent>)
+        class I3(zope.interface.Interface):
+            pass
+        zope.interface.directlyProvides(p, I3)
+        self.assertEqual(tuple(zope.interface.providedBy(p)),
+                         (I3, I1, IContained, IPersistent))
 
-    A proxied object has IContainer, in addition to what the unproxied
-    object has:
 
-      >>> tuple(zope.interface.providedBy(p))
-      (<InterfaceClass zope.container.tests.test_contained.I1>,
-       <InterfaceClass zope.location.interfaces.IContained>,
-       <InterfaceClass persistent.interfaces.IPersistent>)
+    def test_ContainedProxy_instances_have_no_instance_dictionaries(self):
+        # Make sure that proxies don't introduce extra instance dictionaries
+        class C(object):
+            pass
 
-      >>> class I2(zope.interface.Interface):
-      ...     pass
-      >>> zope.interface.directlyProvides(c, I2)
-      >>> tuple(zope.interface.providedBy(p))
-      (<InterfaceClass zope.container.tests.test_contained.I2>,
-       <InterfaceClass zope.container.tests.test_contained.I1>,
-       <InterfaceClass zope.location.interfaces.IContained>,
-       <InterfaceClass persistent.interfaces.IPersistent>)
+        c = C()
+        c.x = 1
+        self.assertEqual(dict(c.__dict__), {'x': 1})
 
-    We can declare interfaces through the proxy:
+        p = ContainedProxy(c)
+        self.assertEqual(dict(p.__dict__), {'x': 1})
 
-      >>> class I3(zope.interface.Interface):
-      ...     pass
-      >>> zope.interface.directlyProvides(p, I3)
-      >>> tuple(zope.interface.providedBy(p))
-      (<InterfaceClass zope.container.tests.test_contained.I3>,
-       <InterfaceClass zope.container.tests.test_contained.I1>,
-       <InterfaceClass zope.location.interfaces.IContained>,
-       <InterfaceClass persistent.interfaces.IPersistent>)
+        p.y = 3
+        self.assertEqual(dict(p.__dict__), {'x': 1, 'y': 3})
+        self.assertEqual(dict(c.__dict__), {'x': 1, 'y': 3})
 
-    """
+        self.assertIs(p.__dict__, c.__dict__)
 
+    def test_get_set_ProxiedObject(self):
+        from zope.container.contained import getProxiedObject
+        from zope.container.contained import setProxiedObject
 
-def test_ContainedProxy_instances_have_no_instance_dictionaries():
-    """Make sure that proxies don't introduce extra instance dictionaries
+        proxy = ContainedProxy(self)
+        self.assertIs(self, getProxiedObject(proxy))
 
-    >>> from zope.container.contained import ContainedProxy
-    >>> class C:
-    ...     pass
+        o = object()
+        self.assertIs(o, getProxiedObject(o))
 
-    >>> c = C()
-    >>> c.x = 1
-    >>> c.__dict__
-    {'x': 1}
+        old = setProxiedObject(proxy, o)
+        self.assertIs(self, old)
+        self.assertIs(o, getProxiedObject(proxy))
+
+        with self.assertRaises(TypeError):
+            setProxiedObject(self, 1)
 
-    >>> p = ContainedProxy(c)
-    >>> p.__dict__
-    {'x': 1}
-    >>> p.y = 3
-    >>> sorted(p.__dict__.items())
-    [('x', 1), ('y', 3)]
-    >>> sorted(c.__dict__.items())
-    [('x', 1), ('y', 3)]
-
-    >>> p.__dict__ is c.__dict__
-    True
-
-    """
 
 
 class TestNameChooser(unittest.TestCase):
@@ -216,7 +213,7 @@ class TestNameChooser(unittest.TestCase):
         self.assertEqual(nc.chooseName(None, None), u'None-3')
 
         # even if the given name cannot be converted to unicode
-        class BadBoy:
+        class BadBoy(object):
             def __unicode__(self):
                 raise Exception
             # Py3: Support
@@ -224,16 +221,43 @@ class TestNameChooser(unittest.TestCase):
 
         self.assertEqual(nc.chooseName(BadBoy(), set()), u'set')
 
+class TestFunctions(unittest.TestCase):
+
+    def test_contained(self):
+        obj = contained(self, 42, 'name')
+        self.assertEqual(obj, self)
+        self.assertEqual(obj.__name__, 'name')
+        self.assertEqual(obj.__parent__, 42)
+
+    def test_uncontained_no_attr(self):
+        with self.assertRaises(AttributeError):
+            uncontained(self, 42)
+
+    def test_uncontained_no_attr_fixing_up(self):
+        # Causes the attribute error to be ignored
+        import zope.container.contained
+        zope.container.contained.fixing_up = True
+        try:
+            uncontained(self, 42)
+        finally:
+            zope.container.contained.fixing_up = False
+
+
+class TestPlacefulSetup(unittest.TestCase):
+
+    def test_cover(self):
+        # We don't actually use this anywhere in this package, this just makes sure
+        # it's still around.
+        from zope.container.testing import ContainerPlacefulSetup
+        setup = ContainerPlacefulSetup()
+        setup.setUp()
+        setup.buildFolders()
+        setup.tearDown()
 
 def test_suite():
-    suite = unittest.TestSuite((
-            unittest.makeSuite(TestNameChooser),
-            ))
-    suite.addTest(doctest.DocTestSuite(
-            'zope.container.contained',
-            setUp=testing.setUp, tearDown=testing.tearDown,
-            checker=testing.checker))
+    suite = unittest.defaultTestLoader.loadTestsFromName(__name__)
     suite.addTest(doctest.DocTestSuite(
-        optionflags=doctest.NORMALIZE_WHITESPACE,
+        'zope.container.contained',
+        setUp=testing.setUp, tearDown=testing.tearDown,
         checker=testing.checker))
     return suite
diff --git a/src/zope/container/tests/test_contained_zodb.py b/src/zope/container/tests/test_contained_zodb.py
index 3f9280b..0851cf7 100644
--- a/src/zope/container/tests/test_contained_zodb.py
+++ b/src/zope/container/tests/test_contained_zodb.py
@@ -14,7 +14,6 @@
 """Contained Tests
 """
 
-import doctest
 import gc
 import unittest
 
@@ -23,211 +22,183 @@ try:
     from ZODB.DB import DB
     import transaction
     HAVE_ZODB = True
-except ImportError:
+except ImportError: # pragma: no cover
     HAVE_ZODB = False
 
 from persistent import Persistent
 
-import zope.interface
-import zope.component
+from zope.container.contained import ContainedProxy
 
-from zope.container.contained import ContainedProxy, NameChooser
-from zope.container.sample import SampleContainer
-from zope.container import testing
-from zope.container.interfaces import NameReserved, IContainer, IReservedNames
 
 class MyOb(Persistent):
     pass
 
+@unittest.skipUnless(HAVE_ZODB, "Needs ZODB")
+class TestContainedZODB(unittest.TestCase):
 
-def test_basic_persistent_w_non_persistent_proxied():
-    """
-    >>> p = ContainedProxy([1])
-    >>> p.__parent__ = 2
-    >>> p.__name__ = 'test'
-    >>> db = DB(DemoStorage('test_storage'))
-    >>> c = db.open()
-    >>> c.root()['p'] = p
-    >>> transaction.commit()
-
-    >>> c2 = db.open()
-    >>> p2 = c2.root()['p']
-    >>> p2
-    [1]
-    >>> p2.__parent__
-    2
-    >>> p2.__name__
-    'test'
-
-    >>> p2._p_changed
-    0
-    >>> p2._p_deactivate()
-    >>> bool(p2._p_changed)
-    False
-    >>> p2.__name__
-    'test'
-
-    >>> db.close()
-    """
-
-
-def test_basic_persistent_w_persistent_proxied():
-    """
-
-    Here, we'll verify that shared references work and
-    that updates to both the proxies and the proxied objects
-    are made correctly.
-
-            ----------------------
-            |                    |
-          parent                other
-            |                 /
-           ob  <--------------
-
-    Here we have an object, parent, that contains ob.  There is another
-    object, other, that has a non-container reference to ob.
-
-    >>> parent = MyOb()
-    >>> parent.ob = ContainedProxy(MyOb())
-    >>> parent.ob.__parent__ = parent
-    >>> parent.ob.__name__ = 'test'
-    >>> other = MyOb()
-    >>> other.ob = parent.ob
+    def setUp(self):
+        self.db = DB(DemoStorage('test_storage'))
 
-    We can change ob through either parent or other
+    def tearDown(self):
+        self.db.close()
 
-    >>> parent.ob.x = 1
-    >>> other.ob.y = 2
+    def test_basic_persistent_w_non_persistent_proxied(self):
+        p = ContainedProxy([1])
+        p.__parent__ = 2
+        p.__name__ = 'test'
+        db = self.db
+        c = db.open()
+        c.root()['p'] = p
+        transaction.commit()
 
-    Now we'll save the data:
+        c2 = db.open()
+        p2 = c2.root()['p']
+        self.assertEqual([1], p2)
+        self.assertEqual(2, p2.__parent__)
+        self.assertEqual('test', p2.__name__)
 
-    >>> db = DB(DemoStorage('test_storage'))
-    >>> c1 = db.open()
-    >>> c1.root()['parent'] = parent
-    >>> c1.root()['other'] = other
-    >>> transaction.commit()
+        self.assertEqual(0, p2._p_changed)
+        p2._p_deactivate()
+        self.assertFalse(bool(p2._p_changed))
 
-    We'll open a second connection and verify that we have the data we
-    expect:
+        self.assertEqual(p2.__name__, 'test')
 
-    >>> c2 = db.open()
-    >>> p2 = c2.root()['parent']
-    >>> p2.ob.__parent__ is p2
-    1
-    >>> p2.ob.x
-    1
-    >>> p2.ob.y
-    2
-    >>> o2 = c2.root()['other']
-    >>> o2.ob is p2.ob
-    1
-    >>> o2.ob is p2.ob
-    1
-    >>> o2.ob.__name__
-    'test'
+    def test_basic_persistent_w_persistent_proxied(self):
+        # Here, we'll verify that shared references work and
+        # that updates to both the proxies and the proxied objects
+        # are made correctly.
+        #
+        #        ----------------------
+        #        |                    |
+        #      parent                other
+        #        |                 /
+        #       ob  <--------------
 
-    Now we'll change things around a bit. We'll move things around
-    a bit. We'll also add an attribute to ob
+        # Here we have an object, parent, that contains ob.  There is another
+        # object, other, that has a non-container reference to ob.
 
-    >>> o2.ob.__name__ = 'test 2'
-    >>> o2.ob.__parent__ = o2
-    >>> o2.ob.z = 3
+        parent = MyOb()
+        parent.ob = ContainedProxy(MyOb())
+        parent.ob.__parent__ = parent
+        parent.ob.__name__ = 'test'
+        other = MyOb()
+        other.ob = parent.ob
 
-    >>> p2.ob.__parent__ is p2
-    0
-    >>> p2.ob.__parent__ is o2
-    1
+        # We can change ob through either parent or other
 
-    And save the changes:
+        parent.ob.x = 1
+        other.ob.y = 2
 
-    >>> transaction.commit()
+        # Now we'll save the data:
 
-    Now we'll reopen the first connection and verify that we can see
-    the changes:
+        db = self.db
+        c1 = db.open()
+        c1.root()['parent'] = parent
+        c1.root()['other'] = other
+        transaction.commit()
 
-    >>> c1.close()
-    >>> c1 = db.open()
-    >>> p2 = c1.root()['parent']
-    >>> p2.ob.__name__
-    'test 2'
-    >>> p2.ob.z
-    3
-    >>> p2.ob.__parent__ is c1.root()['other']
-    1
+        # We'll open a second connection and verify that we have the data we
+        # expect:
 
-    >>> db.close()
-    """
+        c2 = db.open()
+        p2 = c2.root()['parent']
+        self.assertIs(p2.ob.__parent__, p2)
 
-def test_proxy_cache_interaction():
-    """Test to make sure the proxy properly interacts with the object cache
+        self.assertEqual(1, p2.ob.x)
+        self.assertEqual(2, p2.ob.y)
 
-    Persistent objects are their own weak refs.  Thier deallocators
-    need to notify their connection's cache that their object is being
-    deallocated, so that it is removed from the cache.
+        o2 = c2.root()['other']
+        self.assertIs(o2.ob, p2.ob)
+        self.assertIs(o2.ob, p2.ob)
+        self.assertEqual('test', o2.ob.__name__)
 
-    >>> from ZODB.tests.util import DB
-    >>> db = DB()
-    >>> db.setCacheSize(5)
-    >>> conn = db.open()
-    >>> conn.root()['p'] = ContainedProxy(None)
 
-    We need to create some filler objects to push our proxy out of the cache:
+        # Now we'll change things around a bit. We'll move things around
+        # a bit. We'll also add an attribute to ob
 
-    >>> for i in range(10):
-    ...     conn.root()[i] = MyOb()
+        o2.ob.__name__ = 'test 2'
+        o2.ob.__parent__ = o2
+        o2.ob.z = 3
 
-    >>> transaction.commit()
+        self.assertIsNot(p2.ob.__parent__, p2)
+        self.assertIs(p2.ob.__parent__, o2)
 
-    Let's get the oid of our proxy:
+        # And save the changes:
 
-    >>> oid = conn.root()['p']._p_oid
+        transaction.commit()
 
-    Now, we'll access the filler object's:
+        # Now we'll reopen the first connection and verify that we can see
+        # the changes:
 
-    >>> x = [getattr(conn.root()[i], 'x', 0) for i in range(10)]
+        c1.close()
+        c1 = db.open()
+        p2 = c1.root()['parent']
+        self.assertEqual('test 2', p2.ob.__name__)
 
-    We've also accessed the root object. If we garbage-collect the
-    cache:
+        self.assertEqual(3, p2.ob.z)
+        self.assertIs(p2.ob.__parent__, c1.root()['other'])
 
-    >>> _ = conn._cache.incrgc()
+    def test_proxy_cache_interaction(self):
+        # Test to make sure the proxy properly interacts with the object cache
 
-    Then the root object will still be active, because it was accessed
-    recently:
+        # Persistent objects are their own weak refs.  Thier deallocators
+        # need to notify their connection's cache that their object is being
+        # deallocated, so that it is removed from the cache.
 
-    >>> conn.root()._p_changed
-    0
+        db = self.db
+        db.setCacheSize(5)
+        conn = db.open()
+        conn.root()['p'] = ContainedProxy(None)
 
-    And the proxy will be in the cache, because it's refernced from
-    the root object:
+        # We need to create some filler objects to push our proxy out of the cache:
 
-    >>> conn._cache.get(oid) is not None
-    True
+        for i in range(10):
+            conn.root()[i] = MyOb()
 
-    But it's a ghost:
+        transaction.commit()
 
-    >>> bool(conn.root()['p']._p_changed)
-    False
+        # Let's get the oid of our proxy:
 
-    If we deactivate the root object:
+        oid = conn.root()['p']._p_oid
 
-    >>> conn.root()._p_deactivate()
+        # Now, we'll access the filler object's:
+        for i in range(10):
+            getattr(conn.root()[i], 'x', 0)
 
-    Then we'll release the last reference to the proxy and it should
-    no longer be in the cache. To be sure, we'll call gc:
+        # We've also accessed the root object. If we garbage-collect the
+        # cache:
 
-    >>> x = gc.collect()
-    >>> conn._cache.get(oid) is not None
-    False
+        conn._cache.incrgc()
 
-    """
+        # Then the root object will still be active, because it was accessed
+        # recently:
+
+        self.assertEqual(0, conn.root()._p_changed)
+
+        # And the proxy will be in the cache, because it's refernced from
+        # the root object:
+
+        self.assertIsNotNone(conn._cache.get(oid))
+
+        # But it's a ghost:
+
+        self.assertFalse(bool(conn.root()['p']._p_changed))
+
+
+        # If we deactivate the root object:
+
+        conn.root()._p_deactivate()
+
+        # Then we'll release the last reference to the proxy and it should
+        # no longer be in the cache. To be sure, we'll call gc:
+
+        gc.collect()
+        self.assertIsNone(conn._cache.get(oid))
 
 
 def test_suite():
-    if not HAVE_ZODB:
-        return unittest.TestSuite([])
-    return unittest.TestSuite((
-        doctest.DocTestSuite(optionflags=doctest.NORMALIZE_WHITESPACE),
-        ))
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)
 
 
-if __name__ == '__main__': unittest.main()
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/zope/container/tests/test_containertraversable.py b/src/zope/container/tests/test_containertraversable.py
index 7a2a14e..2cc50d4 100644
--- a/src/zope/container/tests/test_containertraversable.py
+++ b/src/zope/container/tests/test_containertraversable.py
@@ -13,6 +13,7 @@
 ##############################################################################
 """Container Traverser tests.
 """
+from __future__ import absolute_import
 import unittest
 from zope.testing.cleanup import CleanUp
 from zope.interface import implementer
@@ -25,24 +26,17 @@ import six
 @implementer(IContainer)
 class Container(object):
 
-    def __init__(self, attrs={}, objs={}):
-        for attr,value in six.iteritems(attrs):
+    def __init__(self, attrs=None, objs=None):
+        for attr, value in six.iteritems(attrs or {}):
             setattr(self, attr, value)
 
         self.__objs = {}
-        for name,value in six.iteritems(objs):
+        for name, value in six.iteritems(objs or {}):
             self.__objs[name] = value
 
-
-    def __getitem__(self, name):
-        return self.__objs[name]
-
     def get(self, name, default=None):
         return self.__objs.get(name, default)
 
-    def __contains__(self, name):
-        return name in self.__objs
-
 
 class Test(CleanUp, unittest.TestCase):
     def testAttr(self):
@@ -50,25 +44,28 @@ class Test(CleanUp, unittest.TestCase):
         foo = Container()
         bar = Container()
         baz = Container()
-        c   = Container({'foo': foo}, {'bar': bar, 'foo': baz})
+        c = Container({'foo': foo}, {'bar': bar, 'foo': baz})
 
         T = ContainerTraversable(c)
         self.assertTrue(T.traverse('foo', []) is baz)
         self.assertTrue(T.traverse('bar', []) is bar)
+        self.assertRaises(TraversalError, T.traverse, 'morebar', [])
 
-        self.assertRaises(TraversalError , T.traverse, 'morebar', [])
-    def test_unicode_attr(self):
+    def test_unicode_obj(self):
         # test traversal with unicode
         voila = Container()
-        c   = Container({}, {u'voil\xe0': voila})
-        self.assertTrue(ContainerTraversable(c).traverse(u'voil\xe0', [])
-                            is voila)
+        c = Container({}, {u'voil\xe0': voila})
+        self.assertIs(ContainerTraversable(c).traverse(u'voil\xe0', []),
+                      voila)
 
+    def test_unicode_attr(self):
+        c = Container()
+        with self.assertRaises(TraversalError):
+            ContainerTraversable(c).traverse(u'voil\xe0', [])
 
-def test_suite():
-    loader = unittest.TestLoader()
-    return loader.loadTestsFromTestCase(Test)
 
+def test_suite():
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)
 
 if __name__ == '__main__':
-    unittest.TextTestRunner().run(test_suite())
+    unittest.main()
diff --git a/src/zope/container/tests/test_containertraverser.py b/src/zope/container/tests/test_containertraverser.py
index 81098ed..20214d3 100644
--- a/src/zope/container/tests/test_containertraverser.py
+++ b/src/zope/container/tests/test_containertraverser.py
@@ -13,6 +13,7 @@
 ##############################################################################
 """Container Traverser Tests
 """
+
 import unittest
 from zope.interface import Interface, implementer
 from zope import component
@@ -21,6 +22,7 @@ from zope.publisher.browser import TestRequest
 from zope.publisher.interfaces.browser import IDefaultBrowserLayer
 
 from zope.container.traversal import ContainerTraverser
+from zope.container.traversal import ItemTraverser
 from zope.container.interfaces import IReadContainer
 from zope.container import testing
 
@@ -29,11 +31,17 @@ class TestContainer(object):
 
     def __init__(self, **kw):
         for name, value in kw.items():
-            setattr(self, name , value)
+            setattr(self, name, value)
 
     def get(self, name, default=None):
         return getattr(self, name, default)
 
+    def __getitem__(self, name):
+        v = object()
+        o = self.get(name, v)
+        if o is v:
+            raise KeyError(name)
+        return o
 
 class View(object):
     def __init__(self, context, request):
@@ -96,13 +104,17 @@ class TraverserTest(testing.ContainerPlacelessSetup, unittest.TestCase):
             'myDefaultView', (Interface, IDefaultBrowserLayer),
             IDefaultViewName)
         self.assertEqual((self.subcontainer, ('@@myDefaultView',)),
-                          self.traverser.browserDefault(self.request))
+                         self.traverser.browserDefault(self.request))
+
 
+class TestItemTraverser(TraverserTest):
+
+    def _getTraverser(self, context, request):
+        return ItemTraverser(context, request)
 
 def test_suite():
-    return unittest.TestSuite((
-        unittest.makeSuite(TraverserTest),
-        ))
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)
+
 
 if __name__ == '__main__':
     unittest.main(defaultTest='test_suite')
diff --git a/src/zope/container/tests/test_directory.py b/src/zope/container/tests/test_directory.py
index 25e27b0..477c4f6 100644
--- a/src/zope/container/tests/test_directory.py
+++ b/src/zope/container/tests/test_directory.py
@@ -15,32 +15,46 @@
 """
 
 import doctest
-from unittest import TestCase, TestSuite, main, makeSuite
+import unittest
 
 from zope.container import testing
-import zope.container.directory
+from zope.container import directory
 
 
 class Directory(object):
-    pass
+    a = None
 
-class Test(TestCase):
+class TestCloner(unittest.TestCase):
 
     def test_Cloner(self):
         d = Directory()
         d.a = 1
-        clone = zope.container.directory.Cloner(d)('foo')
-        self.assertTrue(clone != d)
+        clone = directory.Cloner(d)('foo')
+        self.assertIsNot(clone, d)
         self.assertEqual(clone.__class__, d.__class__)
 
+
+class TestNoop(unittest.TestCase):
+
+    def test_noop(self):
+        self.assertIs(self, directory.noop(self))
+
+
+class TestRootDirectoryFactory(unittest.TestCase):
+
+    def test_returns_folder(self):
+        from zope.container.folder import Folder
+        factory = directory.RootDirectoryFactory(None)
+        self.assertIsInstance(factory(None), Folder)
+
 def test_suite():
     flags = doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE
-    return TestSuite((
-        makeSuite(Test),
+    return unittest.TestSuite((
+        unittest.defaultTestLoader.loadTestsFromName(__name__),
         doctest.DocFileSuite("directory.rst",
                              setUp=testing.setUp, tearDown=testing.tearDown,
                              optionflags=flags),
         ))
 
-if __name__=='__main__':
-    main(defaultTest='test_suite')
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
diff --git a/src/zope/container/tests/test_find.py b/src/zope/container/tests/test_find.py
index 9a417ed..971bbce 100644
--- a/src/zope/container/tests/test_find.py
+++ b/src/zope/container/tests/test_find.py
@@ -13,7 +13,8 @@
 ##############################################################################
 """Find functionality tests
 """
-from unittest import TestCase, main, makeSuite
+import unittest
+
 from zope.container.interfaces import IReadContainer
 from zope.container.interfaces import IObjectFindFilter
 from zope.container.find import FindAdapter, SimpleIdFindFilter
@@ -27,43 +28,18 @@ class FakeContainer(object):
         self._id = id
         self._objects = objects
 
-    def keys(self):
-        return [object._id for object in self._objects]
-
-    def values(self):
-        return self._objects
-
     def items(self):
         return [(object._id, object) for object in self._objects]
 
-    def __getitem__(self, id):
-        for object in self._objects:
-            if object._id == id:
-                return object
-        raise KeyError("Could not find %s" % id)
-
-    def get(self, id, default=None):
-        for object in self._objects:
-            if object._id == id:
-                return object
-
-        return default
-
-    def __contains__(self, id):
-        for object in self._objects:
-            if object.id == id:
-                return True
-        return False
-
     def __len__(self):
         return len(self._objects)
-    
+
 class FakeInterfaceFoo(Interface):
     """Test interface Foo"""
-    
+
 class FakeInterfaceBar(Interface):
     """Test interface Bar"""
-    
+
 class FakeInterfaceSpam(Interface):
     """Test interface Spam"""
 
@@ -74,12 +50,12 @@ class TestObjectFindFilter(object):
         self._count = count
 
     def matches(self, object):
-        if IReadContainer.providedBy(object):
-            return len(object) == self._count
-        else:
-            return False
+        if not IReadContainer.providedBy(object):
+            raise AssertionError("Expecting container")
+        return len(object) == self._count
 
-class Test(TestCase):
+
+class Test(unittest.TestCase):
     def test_idFind(self):
         alpha = FakeContainer('alpha', [])
         delta = FakeContainer('delta', [])
@@ -148,7 +124,7 @@ class Test(TestCase):
         result = find.find(id_filters=[SimpleIdFindFilter(['alpha'])],
                            object_filters=[TestObjectFindFilter(1)])
         self.assertEqual([], result)
-        
+
     def test_interfaceFind(self):
         alpha = FakeContainer('alpha', [])
         directlyProvides(alpha, FakeInterfaceBar)
@@ -165,8 +141,12 @@ class Test(TestCase):
             SimpleInterfacesFindFilter(FakeInterfaceFoo, FakeInterfaceSpam)])
         self.assertEqual([beta, delta], result)
 
+    def test_find_non_container_return_default(self):
+        data = {'a': 42}
+        self.assertEqual(FindAdapter(data).find(), [42])
+
 def test_suite():
-    return makeSuite(Test)
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)
 
-if __name__=='__main__':
-    main(defaultTest='test_suite')
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
diff --git a/src/zope/container/tests/test_icontainer.py b/src/zope/container/tests/test_icontainer.py
index 32fea97..ac7a711 100644
--- a/src/zope/container/tests/test_icontainer.py
+++ b/src/zope/container/tests/test_icontainer.py
@@ -24,6 +24,7 @@ def DefaultTestData():
     return [('3', '0'), ('2', '1'), ('4', '2'), ('6', '3'), ('0', '4'),
             ('5', '5'), ('1', '6'), ('8', '7'), ('7', '8'), ('9', '9')]
 
+
 class BaseTestIContainer(testing.ContainerPlacelessSetup):
     """Base test cases for containers.
 
@@ -34,6 +35,8 @@ class BaseTestIContainer(testing.ContainerPlacelessSetup):
     the test container.  The list must be at least ten items long.
     'NoSuchKey' may not be used as a key value in the returned list.
     """
+    __container = None
+    __data = None
 
     def __setUp(self):
         self.__container = container = self.makeTestObject()
@@ -56,8 +59,8 @@ class BaseTestIContainer(testing.ContainerPlacelessSetup):
 
         container, data = self.__setUp()
         keys = container.keys()
-        keys = list(keys); keys.sort() # convert to sorted list
-        ikeys = [ k for k, v in data ]; ikeys.sort() # sort input keys
+        keys = sorted(keys) # convert to sorted list
+        ikeys = sorted([k for k, _v in data]) # sort input keys
         self.assertEqual(keys, ikeys)
 
     def test_get(self):
@@ -84,11 +87,8 @@ class BaseTestIContainer(testing.ContainerPlacelessSetup):
 
         container, data = self.__setUp()
         values = list(container.values())
-        for k, v in data:
-            try:
-                values.remove(v)
-            except ValueError:
-                self.fail('Value not in list')
+        for _k, v in data:
+            values.remove(v)
 
         self.assertEqual(values, [])
 
@@ -100,6 +100,13 @@ class BaseTestIContainer(testing.ContainerPlacelessSetup):
         container, data = self.__setUp()
         self.assertEqual(len(container), len(data))
 
+    def test_iter(self):
+        container = self.makeTestObject()
+        self.assertEqual(list(container), [])
+
+        container, data = self.__setUp()
+        self.assertEqual(len(list(container)), len(data))
+
     def test_items(self):
         # See interface IReadContainer
         container = self.makeTestObject()
@@ -108,20 +115,20 @@ class BaseTestIContainer(testing.ContainerPlacelessSetup):
 
         container, data = self.__setUp()
         items = container.items()
-        items = list(items); items.sort() # convert to sorted list
-        data.sort()                       # sort input data
+        items = sorted(items) # convert to sorted list
+        data.sort() # sort input data
         self.assertEqual(items, data)
 
     def test___contains__(self):
         # See interface IReadContainer
         container = self.makeTestObject()
         data = self.makeTestData()
-        self.assertEqual(not not (data[6][0] in container), False)
+        self.assertNotIn(data[6][0], container)
 
         container, data = self.__setUp()
-        self.assertEqual(not not (data[6][0] in container), True)
+        self.assertIn(data[6][0], container)
         for i in (1, 8, 7, 3, 4):
-            self.assertEqual(not not (data[i][0] in container), 1)
+            self.assertIn(data[i][0], container)
 
     def test_delObject(self):
         # See interface IWriteContainer
@@ -141,6 +148,42 @@ class BaseTestIContainer(testing.ContainerPlacelessSetup):
         for i in (0, 2, 9, 6, 5):
             self.assertEqual(container[data[i][0]], data[i][1])
 
+    def test_bytes_keys_converted_to_unicode(self):
+        # https://github.com/zopefoundation/zope.container/issues/17
+        container = self.makeTestObject()
+        container[b'abc'] = 1
+        self.assertIn(u'abc', container)
+        del container[u'abc']
+        self.assertNotIn(u'abc', container)
+
+    def test_exception_in_subscriber_leaves_item_in_place(self):
+        # Now register an event subscriber to object added events that
+        # throws an error.
+        # https://github.com/zopefoundation/zope.container/issues/18
+
+        import zope.component
+        from zope.lifecycleevent.interfaces import IObjectAddedEvent
+
+        class MyException(Exception):
+            pass
+
+        @zope.component.adapter(IObjectAddedEvent)
+        def raiseException(event):
+            raise MyException()
+
+        zope.component.provideHandler(raiseException)
+
+        # Now we are adding an object to the container.
+
+        container = self.makeTestObject()
+        with self.assertRaises(MyException):
+            container['foo'] = 'FOO'
+
+        # The key 'foo' should still be present
+        self.assertIn('foo', container.keys())
+        self.assertEqual(list(iter(container)), ['foo'])
+        self.assertIn('foo', container)
+
     ############################################################
     # Tests from Folder
 
@@ -197,11 +240,11 @@ class BaseTestIContainer(testing.ContainerPlacelessSetup):
         folder[name2] = foo2
 
         self.assertEqual(len(folder.keys()), 2)
-        self.assertEqual(not not name2 in folder.keys(), True)
+        self.assertIn(name2, folder.keys())
         self.assertEqual(len(folder.values()), 2)
-        self.assertEqual(not not foo2 in folder.values(), True)
+        self.assertIn(foo2, folder.values())
         self.assertEqual(len(folder.items()), 2)
-        self.assertEqual(not not (name2, foo2) in folder.items(), True)
+        self.assertIn((name2, foo2), folder.items())
         self.assertEqual(len(folder), 2)
 
         del folder[name]
@@ -220,7 +263,7 @@ class BaseTestIContainer(testing.ContainerPlacelessSetup):
     def testManyItems(self):
         folder = self.makeTestObject()
         data = self.makeTestData()
-        objects = [ data[i][1] for i in range(4) ]
+        objects = [data[i][1] for i in range(4)]
         name0 = data[0][0]
         name1 = data[1][0]
         name2 = data[2][0]
@@ -313,5 +356,5 @@ class TestSampleContainer(BaseTestIContainer, TestCase):
 def test_suite():
     return makeSuite(TestSampleContainer)
 
-if __name__=='__main__':
+if __name__ == '__main__':
     main(defaultTest='test_suite')
diff --git a/src/zope/container/tests/test_ordered.py b/src/zope/container/tests/test_ordered.py
index 6de9445..0f04718 100644
--- a/src/zope/container/tests/test_ordered.py
+++ b/src/zope/container/tests/test_ordered.py
@@ -18,141 +18,90 @@ from doctest import DocTestSuite
 
 from zope.component.eventtesting import getEvents, clearEvents
 from zope.container import testing
+from zope.container.tests.test_icontainer import TestSampleContainer
 
+class TestOrderedContainer(TestSampleContainer):
 
-def test_order_events():
-    """
-    Prepare the setup::
+    def test_order_events(self):
+        # Prepare the setup::
+        from zope.container.contained import ContainerModifiedEvent
 
-      >>> from zope.container.sample import SampleContainer
-      >>> root = SampleContainer()
+        # Prepare some objects::
 
-    Prepare some objects::
+        from zope.container.ordered import OrderedContainer
+        oc = OrderedContainer()
+        oc['foo'] = 'bar'
+        oc['baz'] = 'quux'
+        oc['zork'] = 'grue'
+        self.assertEqual(oc.keys(),
+                         ['foo', 'baz', 'zork'])
 
-        >>> from zope.container.ordered import OrderedContainer
-        >>> oc = OrderedContainer()
-        >>> oc['foo'] = 'bar'
-        >>> oc['baz'] = 'quux'
-        >>> oc['zork'] = 'grue'
-        >>> oc.keys()
-        ['foo', 'baz', 'zork']
+        # Now change the order::
 
-    Now change the order::
+        clearEvents()
+        oc.updateOrder(['baz', 'foo', 'zork'])
+        self.assertEqual(oc.keys(),
+                         ['baz', 'foo', 'zork'])
 
-        >>> clearEvents()
-        >>> oc.updateOrder(['baz', 'foo', 'zork'])
-        >>> oc.keys()
-        ['baz', 'foo', 'zork']
+        # Check what events have been sent::
 
-    Check what events have been sent::
+        events = getEvents()
+        self.assertEqual(1, len(events))
+        self.assertIsInstance(events[0], ContainerModifiedEvent)
 
-        >>> events = getEvents()
-        >>> [event.__class__.__name__ for event in events]
-        ['ContainerModifiedEvent']
+        # This is in fact a specialized modification event::
 
-    This is in fact a specialized modification event::
+        from zope.lifecycleevent.interfaces import IObjectModifiedEvent
+        self.assertTrue(IObjectModifiedEvent.providedBy(events[0]))
 
-        >>> from zope.lifecycleevent.interfaces import IObjectModifiedEvent
-        >>> IObjectModifiedEvent.providedBy(events[0])
-        True
 
-    """
+    def test_order_all_items_available_at_object_added_event(self):
+        # Now register an event subscriber to object added events.
+        import zope.component
+        from zope.lifecycleevent.interfaces import IObjectAddedEvent
 
-def test_all_items_available_at_object_added_event():
-    """
-    Prepare the setup::
+        keys = []
+        @zope.component.adapter(IObjectAddedEvent)
+        def printContainerKeys(event):
+            keys.extend(event.newParent.keys())
 
-      >>> from zope.container.sample import SampleContainer
-      >>> root = SampleContainer()
 
-    Now register an event subscriber to object added events.
+        zope.component.provideHandler(printContainerKeys)
 
-        >>> import zope.component
-        >>> from zope.container import interfaces
-        >>> from zope.lifecycleevent.interfaces import IObjectAddedEvent
+        # Now we are adding an object to the container.
 
-        >>> @zope.component.adapter(IObjectAddedEvent)
-        ... def printContainerKeys(event):
-        ...     print(event.newParent.keys())
+        from zope.container.ordered import OrderedContainer
+        oc = OrderedContainer()
+        oc['foo'] = 'FOO'
 
-        >>> zope.component.provideHandler(printContainerKeys)
+        self.assertEqual(keys, ['foo'])
 
-    Now we are adding an object to the container.
+    def test_order_adding_none(self):
+        # This is a regression test: adding None to an OrderedContainer
+        # used to corrupt its internal data structure (_order and _data
+        # would get out of sync, causing KeyErrors when you tried to iterate).
 
-        >>> from zope.container.ordered import OrderedContainer
-        >>> oc = OrderedContainer()
-        >>> oc['foo'] = 'FOO'
-        ['foo']
+        from zope.container.ordered import OrderedContainer
+        oc = OrderedContainer()
+        oc['foo'] = None
+        self.assertEqual(oc.keys(), ['foo'])
+        self.assertEqual(oc.values(), [None])
+        self.assertEqual(oc.items(),
+                         [('foo', None)])
+        # None got proxied, so 'is None is not true
+        self.assertIsNotNone(oc['foo'])
+        self.assertEqual(None, oc['foo'])
 
-    """
-
-def test_exception_causes_order_fix():
-    """
-    Prepare the setup::
-
-      >>> from zope.container.sample import SampleContainer
-      >>> root = SampleContainer()
-
-    Now register an event subscriber to object added events that
-    throws an error.
-
-        >>> import zope.component
-        >>> from zope.container import interfaces
-        >>> from zope.lifecycleevent.interfaces import IObjectAddedEvent
-
-        >>> @zope.component.adapter(IObjectAddedEvent)
-        ... def raiseException(event):
-        ...     raise Exception()
-
-        >>> zope.component.provideHandler(raiseException)
-
-    Now we are adding an object to the container.
-
-        >>> from zope.container.ordered import OrderedContainer
-        >>> oc = OrderedContainer()
-        >>> oc['foo'] = 'FOO'
-        Traceback (most recent call last):
-        ...
-        Exception
-
-    The key 'foo' should not be around:
-
-        >>> 'foo' in oc.keys()
-        False
-
-    """
-
-def test_adding_none():
-    """Test for OrderedContainer
-
-    This is a regression test: adding None to an OrderedContainer
-    used to corrupt its internal data structure (_order and _data
-    wouldl get out of sync, causing KeyErrors when you tried to iterate).
-
-        >>> from zope.container.ordered import OrderedContainer
-        >>> oc = OrderedContainer()
-        >>> oc['foo'] = None
-        >>> oc.keys()
-        ['foo']
-        >>> oc.values()
-        [None]
-        >>> oc.items()
-        [('foo', None)]
-        >>> print(oc['foo'])
-        None
-
-    """
 
 def test_suite():
-    suite = unittest.TestSuite()
+    suite = unittest.TestSuite([
+        unittest.defaultTestLoader.loadTestsFromName(__name__),
+    ])
     suite.addTest(DocTestSuite("zope.container.ordered",
                                setUp=testing.setUp,
                                tearDown=testing.tearDown,
                                checker=testing.checker))
-    suite.addTest(DocTestSuite(
-            setUp=testing.ContainerPlacefulSetup().setUp,
-            tearDown=testing.ContainerPlacefulSetup().tearDown,
-            checker=testing.checker))
+
     return suite
 
 if __name__ == '__main__':
diff --git a/src/zope/container/tests/test_size.py b/src/zope/container/tests/test_size.py
index 1c89c40..8ac8913 100644
--- a/src/zope/container/tests/test_size.py
+++ b/src/zope/container/tests/test_size.py
@@ -60,8 +60,7 @@ class Test(unittest.TestCase):
         self.assertEqual(sized.sizeForDisplay().mapping['items'], '2')
 
 def test_suite():
-    loader = unittest.TestLoader()
-    return loader.loadTestsFromTestCase(Test)
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)
 
-if __name__=='__main__':
-    unittest.TextTestRunner().run(test_suite())
+if __name__ == '__main__':
+    unittest.main()

pip install -e .[test]
parse_log_pytest
pytest
pytest
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
BTrees==4.11.3
certifi==2021.5.30
cffi==1.15.1
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
multipart==1.1.0
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
persistent==4.9.3
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pycparser==2.21
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
python-gettext==4.1
pytz==2025.2
six==1.17.0
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
transaction==3.1.0
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work
zope.browser==2.4
zope.component==5.1.0
zope.configuration==4.4.1
-e git+https://github.com/zopefoundation/zope.container.git@14b41f52058a21164df92ab1d4f86de6dd90960b#egg=zope.container
zope.contenttype==4.6
zope.deprecation==4.4.0
zope.dottedname==5.0
zope.event==4.6
zope.exceptions==4.6
zope.filerepresentation==5.0.0
zope.hookable==5.4
zope.i18n==4.9.0
zope.i18nmessageid==5.1.1
zope.interface==5.5.2
zope.lifecycleevent==4.4
zope.location==4.3
zope.proxy==4.6.1
zope.publisher==6.1.0
zope.schema==6.2.1
zope.security==5.8
zope.size==4.4
zope.testing==5.0.1
zope.testrunner==5.6
zope.traversing==4.4.1

name: zope.container
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - btrees==4.11.3
      - cffi==1.15.1
      - multipart==1.1.0
      - persistent==4.9.3
      - pycparser==2.21
      - python-gettext==4.1
      - pytz==2025.2
      - six==1.17.0
      - transaction==3.1.0
      - zope-browser==2.4
      - zope-component==5.1.0
      - zope-configuration==4.4.1
      - zope-contenttype==4.6
      - zope-deprecation==4.4.0
      - zope-dottedname==5.0
      - zope-event==4.6
      - zope-exceptions==4.6
      - zope-filerepresentation==5.0.0
      - zope-hookable==5.4
      - zope-i18n==4.9.0
      - zope-i18nmessageid==5.1.1
      - zope-interface==5.5.2
      - zope-lifecycleevent==4.4
      - zope-location==4.3
      - zope-proxy==4.6.1
      - zope-publisher==6.1.0
      - zope-schema==6.2.1
      - zope-security==5.8
      - zope-size==4.4
      - zope-testing==5.0.1
      - zope-testrunner==5.6
      - zope-traversing==4.4.1
prefix: /opt/conda/envs/zope.container

src/zope/container/tests/test_contained.py::TestContainedProxy::test_get_set_ProxiedObject
src/zope/container/tests/directory.rst::directory.rst src/zope/container/tests/test_btree.py::TestBTreeContainer::testBadKeyTypes src/zope/container/tests/test_btree.py::TestBTreeContainer::testEmpty src/zope/container/tests/test_btree.py::TestBTreeContainer::testIContainerVerify src/zope/container/tests/test_btree.py::TestBTreeContainer::testManyItems src/zope/container/tests/test_btree.py::TestBTreeContainer::testOneItem src/zope/container/tests/test_btree.py::TestBTreeContainer::test___contains__ src/zope/container/tests/test_btree.py::TestBTreeContainer::test_bytes_keys_converted_to_unicode src/zope/container/tests/test_btree.py::TestBTreeContainer::test_delObject src/zope/container/tests/test_btree.py::TestBTreeContainer::test_exception_in_subscriber_leaves_item_in_place src/zope/container/tests/test_btree.py::TestBTreeContainer::test_get src/zope/container/tests/test_btree.py::TestBTreeContainer::test_items src/zope/container/tests/test_btree.py::TestBTreeContainer::test_iter src/zope/container/tests/test_btree.py::TestBTreeContainer::test_keys src/zope/container/tests/test_btree.py::TestBTreeContainer::test_len src/zope/container/tests/test_btree.py::TestBTreeContainer::test_values src/zope/container/tests/test_btree.py::TestBTreeSpecials::testBTreeContainerInterface src/zope/container/tests/test_btree.py::TestBTreeSpecials::testCorrectLengthWhenAddingExistingItem src/zope/container/tests/test_btree.py::TestBTreeSpecials::testEmptyItemsWithArg src/zope/container/tests/test_btree.py::TestBTreeSpecials::testEmptyKeysWithArg src/zope/container/tests/test_btree.py::TestBTreeSpecials::testEmptyValuesWithArg src/zope/container/tests/test_btree.py::TestBTreeSpecials::testNonemptyItemsWithArg src/zope/container/tests/test_btree.py::TestBTreeSpecials::testNonemptyKeysWithArg src/zope/container/tests/test_btree.py::TestBTreeSpecials::testNonemptyValueWithArg src/zope/container/tests/test_btree.py::TestBTreeSpecials::testStoredLength src/zope/container/tests/test_btree.py::TestBTreeEvents::testDeletion src/zope/container/tests/test_btree.py::test_suite src/zope/container/tests/test_btree.py::TestSampleContainer::testBadKeyTypes src/zope/container/tests/test_btree.py::TestSampleContainer::testEmpty src/zope/container/tests/test_btree.py::TestSampleContainer::testIContainerVerify src/zope/container/tests/test_btree.py::TestSampleContainer::testManyItems src/zope/container/tests/test_btree.py::TestSampleContainer::testOneItem src/zope/container/tests/test_btree.py::TestSampleContainer::test___contains__ src/zope/container/tests/test_btree.py::TestSampleContainer::test_bytes_keys_converted_to_unicode src/zope/container/tests/test_btree.py::TestSampleContainer::test_delObject src/zope/container/tests/test_btree.py::TestSampleContainer::test_exception_in_subscriber_leaves_item_in_place src/zope/container/tests/test_btree.py::TestSampleContainer::test_get src/zope/container/tests/test_btree.py::TestSampleContainer::test_items src/zope/container/tests/test_btree.py::TestSampleContainer::test_iter src/zope/container/tests/test_btree.py::TestSampleContainer::test_keys src/zope/container/tests/test_btree.py::TestSampleContainer::test_len src/zope/container/tests/test_btree.py::TestSampleContainer::test_values src/zope/container/tests/test_constraints.py::TestUnaddableError::test_str src/zope/container/tests/test_constraints.py::TestCheckObject::test_non_container src/zope/container/tests/test_constraints.py::TestCheckFactory::test_no_validate_on_parent src/zope/container/tests/test_constraints.py::TestTypesBased::test_raw_types src/zope/container/tests/test_constraints.py::TestTypesBased::test_raw_types_property src/zope/container/tests/test_constraints.py::test_suite src/zope/container/tests/test_contained.py::TestContainedProxy::test_ContainedProxy_instances_have_no_instance_dictionaries src/zope/container/tests/test_contained.py::TestContainedProxy::test_basic_proxy_attribute_management_and_picklability src/zope/container/tests/test_contained.py::TestContainedProxy::test_declarations_on_ContainedProxy src/zope/container/tests/test_contained.py::TestNameChooser::test_checkName src/zope/container/tests/test_contained.py::TestNameChooser::test_chooseName src/zope/container/tests/test_contained.py::TestFunctions::test_contained src/zope/container/tests/test_contained.py::TestFunctions::test_uncontained_no_attr src/zope/container/tests/test_contained.py::TestFunctions::test_uncontained_no_attr_fixing_up src/zope/container/tests/test_contained.py::TestPlacefulSetup::test_cover src/zope/container/tests/test_contained.py::test_suite src/zope/container/tests/test_contained_zodb.py::test_suite src/zope/container/tests/test_containertraversable.py::Test::testAttr src/zope/container/tests/test_containertraversable.py::Test::test_unicode_attr src/zope/container/tests/test_containertraversable.py::Test::test_unicode_obj src/zope/container/tests/test_containertraversable.py::test_suite src/zope/container/tests/test_containertraverser.py::TraverserTest::test_browserDefault src/zope/container/tests/test_containertraverser.py::TraverserTest::test_browserDefault_without_registration_should_raise src/zope/container/tests/test_containertraverser.py::TraverserTest::test_itemTraversal src/zope/container/tests/test_containertraverser.py::TraverserTest::test_viewTraversal src/zope/container/tests/test_containertraverser.py::TestItemTraverser::test_browserDefault src/zope/container/tests/test_containertraverser.py::TestItemTraverser::test_browserDefault_without_registration_should_raise src/zope/container/tests/test_containertraverser.py::TestItemTraverser::test_itemTraversal src/zope/container/tests/test_containertraverser.py::TestItemTraverser::test_viewTraversal src/zope/container/tests/test_containertraverser.py::test_suite src/zope/container/tests/test_directory.py::TestCloner::test_Cloner src/zope/container/tests/test_directory.py::TestNoop::test_noop src/zope/container/tests/test_directory.py::TestRootDirectoryFactory::test_returns_folder src/zope/container/tests/test_directory.py::test_suite src/zope/container/tests/test_find.py::Test::test_combinedFind src/zope/container/tests/test_find.py::Test::test_find_non_container_return_default src/zope/container/tests/test_find.py::Test::test_idFind src/zope/container/tests/test_find.py::Test::test_interfaceFind src/zope/container/tests/test_find.py::Test::test_objectFind src/zope/container/tests/test_find.py::test_suite src/zope/container/tests/test_icontainer.py::TestSampleContainer::testBadKeyTypes src/zope/container/tests/test_icontainer.py::TestSampleContainer::testEmpty src/zope/container/tests/test_icontainer.py::TestSampleContainer::testIContainerVerify src/zope/container/tests/test_icontainer.py::TestSampleContainer::testManyItems src/zope/container/tests/test_icontainer.py::TestSampleContainer::testOneItem src/zope/container/tests/test_icontainer.py::TestSampleContainer::test___contains__ src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_bytes_keys_converted_to_unicode src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_delObject src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_exception_in_subscriber_leaves_item_in_place src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_get src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_items src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_iter src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_keys src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_len src/zope/container/tests/test_icontainer.py::TestSampleContainer::test_values src/zope/container/tests/test_icontainer.py::test_suite src/zope/container/tests/test_ordered.py::TestSampleContainer::testBadKeyTypes src/zope/container/tests/test_ordered.py::TestSampleContainer::testEmpty src/zope/container/tests/test_ordered.py::TestSampleContainer::testIContainerVerify src/zope/container/tests/test_ordered.py::TestSampleContainer::testManyItems src/zope/container/tests/test_ordered.py::TestSampleContainer::testOneItem src/zope/container/tests/test_ordered.py::TestSampleContainer::test___contains__ src/zope/container/tests/test_ordered.py::TestSampleContainer::test_bytes_keys_converted_to_unicode src/zope/container/tests/test_ordered.py::TestSampleContainer::test_delObject src/zope/container/tests/test_ordered.py::TestSampleContainer::test_exception_in_subscriber_leaves_item_in_place src/zope/container/tests/test_ordered.py::TestSampleContainer::test_get src/zope/container/tests/test_ordered.py::TestSampleContainer::test_items src/zope/container/tests/test_ordered.py::TestSampleContainer::test_iter src/zope/container/tests/test_ordered.py::TestSampleContainer::test_keys src/zope/container/tests/test_ordered.py::TestSampleContainer::test_len src/zope/container/tests/test_ordered.py::TestSampleContainer::test_values src/zope/container/tests/test_ordered.py::TestOrderedContainer::testBadKeyTypes src/zope/container/tests/test_ordered.py::TestOrderedContainer::testEmpty src/zope/container/tests/test_ordered.py::TestOrderedContainer::testIContainerVerify src/zope/container/tests/test_ordered.py::TestOrderedContainer::testManyItems src/zope/container/tests/test_ordered.py::TestOrderedContainer::testOneItem src/zope/container/tests/test_ordered.py::TestOrderedContainer::test___contains__ src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_bytes_keys_converted_to_unicode src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_delObject src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_exception_in_subscriber_leaves_item_in_place src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_get src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_items src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_iter src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_keys src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_len src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_order_adding_none src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_order_all_items_available_at_object_added_event src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_order_events src/zope/container/tests/test_ordered.py::TestOrderedContainer::test_values src/zope/container/tests/test_ordered.py::test_suite src/zope/container/tests/test_size.py::Test::testEmptyContainer src/zope/container/tests/test_size.py::Test::testImplementsISized src/zope/container/tests/test_size.py::Test::testOneItem src/zope/container/tests/test_size.py::Test::testSeveralItems src/zope/container/tests/test_size.py::test_suite
src/zope/container/constraints.py .coveragerc CHANGES.rst src/zope/container/contained.py src/zope/container/ordered.py
src/zope/container/constraints.py .coveragerc CHANGES.rst src/zope/container/contained.py src/zope/container/ordered.py