Initial import to Tizen 08/1608/1 1.0 1.0_branch accepted/trunk/20120904.170055 submit/trunk/20120831.221928
authorJimmy Huang <jimmy.huang@linux.intel.com>
Fri, 31 Aug 2012 22:19:17 +0000 (15:19 -0700)
committerJimmy Huang <jimmy.huang@linux.intel.com>
Fri, 31 Aug 2012 22:19:17 +0000 (15:19 -0700)
Signed-off-by: Jimmy Huang <jimmy.huang@linux.intel.com>
71 files changed:
CHANGES.txt [new file with mode: 0644]
COPYRIGHT.txt [new file with mode: 0644]
LICENSE.txt [new file with mode: 0644]
PKG-INFO [new file with mode: 0644]
README.txt [new file with mode: 0644]
bootstrap.py [new file with mode: 0644]
build_ext_2.py [new file with mode: 0644]
build_ext_3.py [new file with mode: 0644]
buildout.cfg [new file with mode: 0644]
packaging/python-zope.interface.changes [new file with mode: 0644]
packaging/python-zope.interface.spec [new file with mode: 0644]
setup.cfg [new file with mode: 0644]
setup.py [new file with mode: 0644]
src/zope.interface.egg-info/PKG-INFO [new file with mode: 0644]
src/zope.interface.egg-info/SOURCES.txt [new file with mode: 0644]
src/zope.interface.egg-info/dependency_links.txt [new file with mode: 0644]
src/zope.interface.egg-info/namespace_packages.txt [new file with mode: 0644]
src/zope.interface.egg-info/not-zip-safe [new file with mode: 0644]
src/zope.interface.egg-info/requires.txt [new file with mode: 0644]
src/zope.interface.egg-info/top_level.txt [new file with mode: 0644]
src/zope/__init__.py [new file with mode: 0644]
src/zope/interface/README.ru.txt [new file with mode: 0644]
src/zope/interface/README.txt [new file with mode: 0644]
src/zope/interface/__init__.py [new file with mode: 0644]
src/zope/interface/_flatten.py [new file with mode: 0644]
src/zope/interface/_zope_interface_coptimizations.c [new file with mode: 0644]
src/zope/interface/adapter.py [new file with mode: 0644]
src/zope/interface/adapter.ru.txt [new file with mode: 0644]
src/zope/interface/adapter.txt [new file with mode: 0644]
src/zope/interface/advice.py [new file with mode: 0644]
src/zope/interface/common/__init__.py [new file with mode: 0644]
src/zope/interface/common/idatetime.py [new file with mode: 0644]
src/zope/interface/common/interfaces.py [new file with mode: 0644]
src/zope/interface/common/mapping.py [new file with mode: 0644]
src/zope/interface/common/sequence.py [new file with mode: 0644]
src/zope/interface/common/tests/__init__.py [new file with mode: 0644]
src/zope/interface/common/tests/basemapping.py [new file with mode: 0644]
src/zope/interface/common/tests/test_idatetime.py [new file with mode: 0644]
src/zope/interface/common/tests/test_import_interfaces.py [new file with mode: 0644]
src/zope/interface/declarations.py [new file with mode: 0644]
src/zope/interface/document.py [new file with mode: 0644]
src/zope/interface/exceptions.py [new file with mode: 0644]
src/zope/interface/human.ru.txt [new file with mode: 0644]
src/zope/interface/human.txt [new file with mode: 0644]
src/zope/interface/index.txt [new file with mode: 0644]
src/zope/interface/interface.py [new file with mode: 0644]
src/zope/interface/interfaces.py [new file with mode: 0644]
src/zope/interface/registry.py [new file with mode: 0644]
src/zope/interface/ro.py [new file with mode: 0644]
src/zope/interface/tests/__init__.py [new file with mode: 0644]
src/zope/interface/tests/dummy.py [new file with mode: 0644]
src/zope/interface/tests/foodforthought.txt [new file with mode: 0644]
src/zope/interface/tests/ifoo.py [new file with mode: 0644]
src/zope/interface/tests/ifoo_other.py [new file with mode: 0644]
src/zope/interface/tests/m1.py [new file with mode: 0644]
src/zope/interface/tests/m2.py [new file with mode: 0644]
src/zope/interface/tests/odd.py [new file with mode: 0644]
src/zope/interface/tests/test_adapter.py [new file with mode: 0644]
src/zope/interface/tests/test_advice.py [new file with mode: 0644]
src/zope/interface/tests/test_declarations.py [new file with mode: 0644]
src/zope/interface/tests/test_document.py [new file with mode: 0644]
src/zope/interface/tests/test_element.py [new file with mode: 0644]
src/zope/interface/tests/test_interface.py [new file with mode: 0644]
src/zope/interface/tests/test_odd_declarations.py [new file with mode: 0644]
src/zope/interface/tests/test_registry.py [new file with mode: 0644]
src/zope/interface/tests/test_sorting.py [new file with mode: 0644]
src/zope/interface/tests/test_verify.py [new file with mode: 0644]
src/zope/interface/tests/unitfixtures.py [new file with mode: 0644]
src/zope/interface/verify.py [new file with mode: 0644]
src/zope/interface/verify.txt [new file with mode: 0644]
tox.ini [new file with mode: 0644]

diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644 (file)
index 0000000..1c31ba0
--- /dev/null
@@ -0,0 +1,304 @@
+``zope.interface Changelog``
+============================
+
+3.8.0 (2011-09-22)
+------------------
+
+- New module ``zope.interface.registry``.  This is code moved from
+  ``zope.component.registry`` which implements a basic nonperistent component
+  registry as ``zope.interface.registry.Components``.  This class was moved
+  from ``zope.component`` to make porting systems (such as Pyramid) that rely
+  only on a basic component registry to Python 3 possible without needing to
+  port the entirety of the ``zope.component`` package.  Backwards
+  compatibility import shims have been left behind in ``zope.component``, so
+  this change will not break any existing code.
+
+- New ``tests_require`` dependency: ``zope.event`` to test events sent by
+  Components implementation.  The ``zope.interface`` package does not have a
+  hard dependency on ``zope.event``, but if ``zope.event`` is importable, it
+  will send component registration events when methods of an instance of
+  ``zope.interface.registry.Components`` are called.
+
+- New interfaces added to support ``zope.interface.registry.Components``
+  addition: ``ComponentLookupError``, ``Invalid``, ``IObjectEvent``,
+  ``ObjectEvent``, ``IComponentLookup``, ``IRegistration``,
+  ``IUtilityRegistration``, ``IAdapterRegistration``,
+  ``ISubscriptionAdapterRegistration``, ``IHandlerRegistration``,
+  ``IRegistrationEvent``, ``RegistrationEvent``, ``IRegistered``,
+  ``Registered``, ``IUnregistered``, ``Unregistered``,
+  ``IComponentRegistry``, and ``IComponents``.
+
+- No longer Python 2.4 compatible (tested under 2.5, 2.6, 2.7, and 3.2).
+
+3.7.0 (2011-08-13)
+------------------
+
+- Move changes from 3.6.2 - 3.6.5 to a new 3.7.x release line.
+
+3.6.7 (2011-08-20)
+------------------
+
+- Fix sporadic failures on x86-64 platforms in tests of rich comparisons
+  of interfaces.
+
+3.6.6 (2011-08-13)
+------------------
+
+- LP #570942:  Now correctly compare interfaces  from different modules but
+  with the same names.
+  
+  N.B.: This is a less intrusive / destabilizing fix than the one applied in
+  3.6.3:  we only fix the underlying cmp-alike function, rather than adding
+  the other "rich comparison" functions.
+
+- Revert to software as released with 3.6.1 for "stable" 3.6 release branch.
+
+3.6.5 (2011-08-11)
+------------------
+
+- LP #811792:  work around buggy behavior in some subclasses of
+  ``zope.interface.interface.InterfaceClass``, which invoke ``__hash__``
+  before initializing ``__module__`` and ``__name__``.  The workaround
+  returns a fixed constant hash in such cases, and issues a ``UserWarning``.
+
+- LP #804832:  Under PyPy, ``zope.interface`` should not build its C
+  extension.  Also, prevent attempting to build it under Jython.
+
+- Add a tox.ini for easier xplatform testing.
+
+- Fix testing deprecation warnings issued when tested under Py3K.
+
+3.6.4 (2011-07-04)
+------------------
+
+- LP 804951:  InterfaceClass instances were unhashable under Python 3.x.
+
+3.6.3 (2011-05-26)
+------------------
+
+- LP #570942:  Now correctly compare interfaces  from different modules but
+  with the same names.
+
+3.6.2 (2011-05-17)
+------------------
+
+- Moved detailed documentation out-of-line from PyPI page, linking instead to
+  http://docs.zope.org/zope.interface .
+
+- Fixes for small issues when running tests under Python 3.2 using
+  ``zope.testrunner``.
+
+- LP # 675064:  Specify return value type for C optimizations module init
+  under Python 3:  undeclared value caused warnings, and segfaults on some
+  64 bit architectures.
+
+- setup.py now raises RuntimeError if you don't have Distutils installed when
+  running under Python 3.
+
+3.6.1 (2010-05-03)
+------------------
+
+- A non-ASCII character in the changelog made 3.6.0 uninstallable on
+  Python 3 systems with another default encoding than UTF-8.
+
+- Fixed compiler warnings under GCC 4.3.3.
+
+3.6.0 (2010-04-29)
+------------------
+
+- LP #185974:  Clear the cache used by ``Specificaton.get`` inside
+  ``Specification.changed``.  Thanks to Jacob Holm for the patch.
+
+- Added support for Python 3.1. Contributors:
+
+    Lennart Regebro
+    Martin v Loewis
+    Thomas Lotze
+    Wolfgang Schnerring
+
+  The 3.1 support is completely backwards compatible. However, the implements
+  syntax used under Python 2.X does not work under 3.X, since it depends on
+  how metaclasses are implemented and this has changed. Instead it now supports
+  a decorator syntax (also under Python 2.X)::
+
+    class Foo:
+        implements(IFoo)
+        ...
+
+  can now also be written::
+
+    @implementor(IFoo):
+    class Foo:
+        ...
+
+  There are 2to3 fixers available to do this change automatically in the
+  zope.fixers package.
+
+- Python 2.3 is no longer supported.
+
+
+3.5.4 (2009-12-23)
+------------------
+
+- Use the standard Python doctest module instead of zope.testing.doctest, which
+  has been deprecated.
+
+
+3.5.3 (2009-12-08)
+------------------
+
+- Fix an edge case: make providedBy() work when a class has '__provides__' in
+  its __slots__ (see http://thread.gmane.org/gmane.comp.web.zope.devel/22490)
+
+
+3.5.2 (2009-07-01)
+------------------
+
+- BaseAdapterRegistry.unregister, unsubscribe: Remove empty portions of
+  the data structures when something is removed.  This avoids leaving
+  references to global objects (interfaces) that may be slated for
+  removal from the calling application.
+
+
+3.5.1 (2009-03-18)
+------------------
+
+- verifyObject: use getattr instead of hasattr to test for object attributes
+  in order to let exceptions other than AttributeError raised by properties
+  propagate to the caller
+
+- Add Sphinx-based documentation building to the package buildout
+  configuration. Use the ``bin/docs`` command after buildout.
+
+- Improve package description a bit. Unify changelog entries formatting.
+
+- Change package's mailing list address to zope-dev at zope.org as
+  zope3-dev at zope.org is now retired.
+
+
+3.5.0 (2008-10-26)
+------------------
+
+- Fixed declaration of _zope_interface_coptimizations, it's not a top level
+  package.
+
+- Add a DocTestSuite for odd.py module, so their tests are run.
+
+- Allow to bootstrap on Jython.
+
+- Fix https://bugs.launchpad.net/zope3/3.3/+bug/98388: ISpecification
+  was missing a declaration for __iro__.
+
+- Added optional code optimizations support, which allows the building
+  of C code optimizations to fail (Jython).
+
+- Replaced `_flatten` with a non-recursive implementation, effectively making
+  it 3x faster.
+
+
+3.4.1 (2007-10-02)
+------------------
+
+- Fixed a setup bug that prevented installation from source on systems
+  without setuptools.
+
+
+3.4.0 (2007-07-19)
+------------------
+
+- Final release for 3.4.0.
+
+
+3.4.0b3 (2007-05-22)
+--------------------
+
+
+- Objects with picky custom comparison methods couldn't be added to
+  component registries.  Now, when checking whether an object is
+  already registered, identity comparison is used.
+
+
+3.3.0.1 (2007-01-03)
+--------------------
+
+- Made a reference to OverflowWarning, which disappeared in Python
+  2.5, conditional.
+
+
+3.3.0 (2007/01/03)
+------------------
+
+New Features
+++++++++++++
+
+- The adapter-lookup algorithim was refactored to make it
+  much simpler and faster.  
+
+  Also, more of the adapter-lookup logic is implemented in C, making
+  debugging of application code easier, since there is less
+  infrastructre code to step through.
+
+- We now treat objects without interface declarations as if they
+  declared that they provide zope.interface.Interface.
+
+- There are a number of richer new adapter-registration interfaces
+  that provide greater control and introspection.
+
+- Added a new interface decorator to zope.interface that allows the
+  setting of tagged values on an interface at definition time (see
+  zope.interface.taggedValue).
+
+Bug Fixes
++++++++++
+
+- A bug in multi-adapter lookup sometimes caused incorrect adapters to
+  be returned.
+
+
+3.2.0.2 (2006-04-15)
+--------------------
+
+- Fix packaging bug:  'package_dir' must be a *relative* path.
+
+
+3.2.0.1 (2006-04-14)
+--------------------
+
+- Packaging change:  suppress inclusion of 'setup.cfg' in 'sdist' builds.
+
+
+3.2.0 (2006-01-05)
+------------------
+
+- Corresponds to the verison of the zope.interface package shipped as part of
+  the Zope 3.2.0 release.
+
+
+3.1.0 (2005-10-03)
+------------------
+
+- Corresponds to the verison of the zope.interface package shipped as part of
+  the Zope 3.1.0 release.
+
+- Made attribute resolution order consistent with component lookup order,
+  i.e. new-style class MRO semantics.
+
+- Deprecated 'isImplementedBy' and 'isImplementedByInstancesOf' APIs in
+  favor of 'implementedBy' and 'providedBy'.
+
+
+3.0.1 (2005-07-27)
+------------------
+
+- Corresponds to the verison of the zope.interface package shipped as part of
+  the Zope X3.0.1 release.
+
+- Fixed a bug reported by James Knight, which caused adapter registries
+  to fail occasionally to reflect declaration changes.
+
+
+3.0.0 (2004-11-07)
+------------------
+
+- Corresponds to the verison of the zope.interface package shipped as part of
+  the Zope X3.0.0 release.
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
new file mode 100644 (file)
index 0000000..79859e0
--- /dev/null
@@ -0,0 +1 @@
+Zope Foundation and Contributors
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644 (file)
index 0000000..e1f9ad7
--- /dev/null
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644 (file)
index 0000000..b193c28
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,342 @@
+Metadata-Version: 1.0
+Name: zope.interface
+Version: 3.8.0
+Summary: Interfaces for Python
+Home-page: http://pypi.python.org/pypi/zope.interface
+Author: Zope Foundation and Contributors
+Author-email: zope-dev@zope.org
+License: ZPL 2.1
+Description: ``zope.interface`` README
+        =========================
+        
+        This package is intended to be independently reusable in any Python
+        project. It is maintained by the `Zope Toolkit project
+        <http://docs.zope.org/zopetoolkit/>`_.
+        
+        This package provides an implementation of "object interfaces" for Python.
+        Interfaces are a mechanism for labeling objects as conforming to a given
+        API or contract. So, this package can be considered as implementation of
+        the `Design By Contract`_ methodology support in Python.
+        
+        .. _Design By Contract: http://en.wikipedia.org/wiki/Design_by_contract
+        
+        For detailed documentation, please see http://docs.zope.org/zope.interface
+        
+        ``zope.interface Changelog``
+        ============================
+        
+        3.8.0 (2011-09-22)
+        ------------------
+        
+        - New module ``zope.interface.registry``.  This is code moved from
+          ``zope.component.registry`` which implements a basic nonperistent component
+          registry as ``zope.interface.registry.Components``.  This class was moved
+          from ``zope.component`` to make porting systems (such as Pyramid) that rely
+          only on a basic component registry to Python 3 possible without needing to
+          port the entirety of the ``zope.component`` package.  Backwards
+          compatibility import shims have been left behind in ``zope.component``, so
+          this change will not break any existing code.
+        
+        - New ``tests_require`` dependency: ``zope.event`` to test events sent by
+          Components implementation.  The ``zope.interface`` package does not have a
+          hard dependency on ``zope.event``, but if ``zope.event`` is importable, it
+          will send component registration events when methods of an instance of
+          ``zope.interface.registry.Components`` are called.
+        
+        - New interfaces added to support ``zope.interface.registry.Components``
+          addition: ``ComponentLookupError``, ``Invalid``, ``IObjectEvent``,
+          ``ObjectEvent``, ``IComponentLookup``, ``IRegistration``,
+          ``IUtilityRegistration``, ``IAdapterRegistration``,
+          ``ISubscriptionAdapterRegistration``, ``IHandlerRegistration``,
+          ``IRegistrationEvent``, ``RegistrationEvent``, ``IRegistered``,
+          ``Registered``, ``IUnregistered``, ``Unregistered``,
+          ``IComponentRegistry``, and ``IComponents``.
+        
+        - No longer Python 2.4 compatible (tested under 2.5, 2.6, 2.7, and 3.2).
+        
+        3.7.0 (2011-08-13)
+        ------------------
+        
+        - Move changes from 3.6.2 - 3.6.5 to a new 3.7.x release line.
+        
+        3.6.7 (2011-08-20)
+        ------------------
+        
+        - Fix sporadic failures on x86-64 platforms in tests of rich comparisons
+          of interfaces.
+        
+        3.6.6 (2011-08-13)
+        ------------------
+        
+        - LP #570942:  Now correctly compare interfaces  from different modules but
+          with the same names.
+          
+          N.B.: This is a less intrusive / destabilizing fix than the one applied in
+          3.6.3:  we only fix the underlying cmp-alike function, rather than adding
+          the other "rich comparison" functions.
+        
+        - Revert to software as released with 3.6.1 for "stable" 3.6 release branch.
+        
+        3.6.5 (2011-08-11)
+        ------------------
+        
+        - LP #811792:  work around buggy behavior in some subclasses of
+          ``zope.interface.interface.InterfaceClass``, which invoke ``__hash__``
+          before initializing ``__module__`` and ``__name__``.  The workaround
+          returns a fixed constant hash in such cases, and issues a ``UserWarning``.
+        
+        - LP #804832:  Under PyPy, ``zope.interface`` should not build its C
+          extension.  Also, prevent attempting to build it under Jython.
+        
+        - Add a tox.ini for easier xplatform testing.
+        
+        - Fix testing deprecation warnings issued when tested under Py3K.
+        
+        3.6.4 (2011-07-04)
+        ------------------
+        
+        - LP 804951:  InterfaceClass instances were unhashable under Python 3.x.
+        
+        3.6.3 (2011-05-26)
+        ------------------
+        
+        - LP #570942:  Now correctly compare interfaces  from different modules but
+          with the same names.
+        
+        3.6.2 (2011-05-17)
+        ------------------
+        
+        - Moved detailed documentation out-of-line from PyPI page, linking instead to
+          http://docs.zope.org/zope.interface .
+        
+        - Fixes for small issues when running tests under Python 3.2 using
+          ``zope.testrunner``.
+        
+        - LP # 675064:  Specify return value type for C optimizations module init
+          under Python 3:  undeclared value caused warnings, and segfaults on some
+          64 bit architectures.
+        
+        - setup.py now raises RuntimeError if you don't have Distutils installed when
+          running under Python 3.
+        
+        3.6.1 (2010-05-03)
+        ------------------
+        
+        - A non-ASCII character in the changelog made 3.6.0 uninstallable on
+          Python 3 systems with another default encoding than UTF-8.
+        
+        - Fixed compiler warnings under GCC 4.3.3.
+        
+        3.6.0 (2010-04-29)
+        ------------------
+        
+        - LP #185974:  Clear the cache used by ``Specificaton.get`` inside
+          ``Specification.changed``.  Thanks to Jacob Holm for the patch.
+        
+        - Added support for Python 3.1. Contributors:
+        
+            Lennart Regebro
+            Martin v Loewis
+            Thomas Lotze
+            Wolfgang Schnerring
+        
+          The 3.1 support is completely backwards compatible. However, the implements
+          syntax used under Python 2.X does not work under 3.X, since it depends on
+          how metaclasses are implemented and this has changed. Instead it now supports
+          a decorator syntax (also under Python 2.X)::
+        
+            class Foo:
+                implements(IFoo)
+                ...
+        
+          can now also be written::
+        
+            @implementor(IFoo):
+            class Foo:
+                ...
+        
+          There are 2to3 fixers available to do this change automatically in the
+          zope.fixers package.
+        
+        - Python 2.3 is no longer supported.
+        
+        
+        3.5.4 (2009-12-23)
+        ------------------
+        
+        - Use the standard Python doctest module instead of zope.testing.doctest, which
+          has been deprecated.
+        
+        
+        3.5.3 (2009-12-08)
+        ------------------
+        
+        - Fix an edge case: make providedBy() work when a class has '__provides__' in
+          its __slots__ (see http://thread.gmane.org/gmane.comp.web.zope.devel/22490)
+        
+        
+        3.5.2 (2009-07-01)
+        ------------------
+        
+        - BaseAdapterRegistry.unregister, unsubscribe: Remove empty portions of
+          the data structures when something is removed.  This avoids leaving
+          references to global objects (interfaces) that may be slated for
+          removal from the calling application.
+        
+        
+        3.5.1 (2009-03-18)
+        ------------------
+        
+        - verifyObject: use getattr instead of hasattr to test for object attributes
+          in order to let exceptions other than AttributeError raised by properties
+          propagate to the caller
+        
+        - Add Sphinx-based documentation building to the package buildout
+          configuration. Use the ``bin/docs`` command after buildout.
+        
+        - Improve package description a bit. Unify changelog entries formatting.
+        
+        - Change package's mailing list address to zope-dev at zope.org as
+          zope3-dev at zope.org is now retired.
+        
+        
+        3.5.0 (2008-10-26)
+        ------------------
+        
+        - Fixed declaration of _zope_interface_coptimizations, it's not a top level
+          package.
+        
+        - Add a DocTestSuite for odd.py module, so their tests are run.
+        
+        - Allow to bootstrap on Jython.
+        
+        - Fix https://bugs.launchpad.net/zope3/3.3/+bug/98388: ISpecification
+          was missing a declaration for __iro__.
+        
+        - Added optional code optimizations support, which allows the building
+          of C code optimizations to fail (Jython).
+        
+        - Replaced `_flatten` with a non-recursive implementation, effectively making
+          it 3x faster.
+        
+        
+        3.4.1 (2007-10-02)
+        ------------------
+        
+        - Fixed a setup bug that prevented installation from source on systems
+          without setuptools.
+        
+        
+        3.4.0 (2007-07-19)
+        ------------------
+        
+        - Final release for 3.4.0.
+        
+        
+        3.4.0b3 (2007-05-22)
+        --------------------
+        
+        
+        - Objects with picky custom comparison methods couldn't be added to
+          component registries.  Now, when checking whether an object is
+          already registered, identity comparison is used.
+        
+        
+        3.3.0.1 (2007-01-03)
+        --------------------
+        
+        - Made a reference to OverflowWarning, which disappeared in Python
+          2.5, conditional.
+        
+        
+        3.3.0 (2007/01/03)
+        ------------------
+        
+        New Features
+        ++++++++++++
+        
+        - The adapter-lookup algorithim was refactored to make it
+          much simpler and faster.  
+        
+          Also, more of the adapter-lookup logic is implemented in C, making
+          debugging of application code easier, since there is less
+          infrastructre code to step through.
+        
+        - We now treat objects without interface declarations as if they
+          declared that they provide zope.interface.Interface.
+        
+        - There are a number of richer new adapter-registration interfaces
+          that provide greater control and introspection.
+        
+        - Added a new interface decorator to zope.interface that allows the
+          setting of tagged values on an interface at definition time (see
+          zope.interface.taggedValue).
+        
+        Bug Fixes
+        +++++++++
+        
+        - A bug in multi-adapter lookup sometimes caused incorrect adapters to
+          be returned.
+        
+        
+        3.2.0.2 (2006-04-15)
+        --------------------
+        
+        - Fix packaging bug:  'package_dir' must be a *relative* path.
+        
+        
+        3.2.0.1 (2006-04-14)
+        --------------------
+        
+        - Packaging change:  suppress inclusion of 'setup.cfg' in 'sdist' builds.
+        
+        
+        3.2.0 (2006-01-05)
+        ------------------
+        
+        - Corresponds to the verison of the zope.interface package shipped as part of
+          the Zope 3.2.0 release.
+        
+        
+        3.1.0 (2005-10-03)
+        ------------------
+        
+        - Corresponds to the verison of the zope.interface package shipped as part of
+          the Zope 3.1.0 release.
+        
+        - Made attribute resolution order consistent with component lookup order,
+          i.e. new-style class MRO semantics.
+        
+        - Deprecated 'isImplementedBy' and 'isImplementedByInstancesOf' APIs in
+          favor of 'implementedBy' and 'providedBy'.
+        
+        
+        3.0.1 (2005-07-27)
+        ------------------
+        
+        - Corresponds to the verison of the zope.interface package shipped as part of
+          the Zope X3.0.1 release.
+        
+        - Fixed a bug reported by James Knight, which caused adapter registries
+          to fail occasionally to reflect declaration changes.
+        
+        
+        3.0.0 (2004-11-07)
+        ------------------
+        
+        - Corresponds to the verison of the zope.interface package shipped as part of
+          the Zope X3.0.0 release.
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Zope Public License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2.4
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..e00c09d
--- /dev/null
@@ -0,0 +1,15 @@
+``zope.interface`` README
+=========================
+
+This package is intended to be independently reusable in any Python
+project. It is maintained by the `Zope Toolkit project
+<http://docs.zope.org/zopetoolkit/>`_.
+
+This package provides an implementation of "object interfaces" for Python.
+Interfaces are a mechanism for labeling objects as conforming to a given
+API or contract. So, this package can be considered as implementation of
+the `Design By Contract`_ methodology support in Python.
+
+.. _Design By Contract: http://en.wikipedia.org/wiki/Design_by_contract
+
+For detailed documentation, please see http://docs.zope.org/zope.interface
diff --git a/bootstrap.py b/bootstrap.py
new file mode 100644 (file)
index 0000000..8e4027c
--- /dev/null
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+is_jython = sys.platform.startswith('java')
+
+if is_jython:
+    import subprocess
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+
+if is_jython:
+    assert subprocess.Popen([sys.executable] + ['-c', cmd, '-mqNxd', tmpeggs,
+    'zc.buildout'],
+    env = dict(os.environ,
+          PYTHONPATH=
+          ws.find(pkg_resources.Requirement.parse('setuptools')).location
+          ),
+    ).wait() == 0
+
+else:
+    assert os.spawnle(
+        os.P_WAIT, sys.executable, sys.executable,
+        '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+        dict(os.environ,
+            PYTHONPATH=
+            ws.find(pkg_resources.Requirement.parse('setuptools')).location
+            ),
+        ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
diff --git a/build_ext_2.py b/build_ext_2.py
new file mode 100644 (file)
index 0000000..dc19804
--- /dev/null
@@ -0,0 +1,38 @@
+import sys
+from distutils.errors import (CCompilerError, DistutilsExecError, 
+                              DistutilsPlatformError)
+try:
+    from setuptools.command.build_ext import build_ext
+except ImportError:
+    from distutils.command.build_ext import build_ext
+    
+
+class optional_build_ext(build_ext):
+    """This class subclasses build_ext and allows
+       the building of C extensions to fail.
+    """
+    def run(self):
+        try:
+            build_ext.run(self)
+        
+        except DistutilsPlatformError, e:
+            self._unavailable(e)
+
+    def build_extension(self, ext):
+        try:
+            build_ext.build_extension(self, ext)
+        
+        except (CCompilerError, DistutilsExecError), e:
+            self._unavailable(e)
+
+    def _unavailable(self, e):
+        print >> sys.stderr, '*' * 80
+        print >> sys.stderr, """WARNING:
+
+        An optional code optimization (C extension) could not be compiled.
+
+        Optimizations for this package will not be available!"""
+        print >> sys.stderr
+        print >> sys.stderr, e
+        print >> sys.stderr, '*' * 80
+        
\ No newline at end of file
diff --git a/build_ext_3.py b/build_ext_3.py
new file mode 100644 (file)
index 0000000..a6ef8c6
--- /dev/null
@@ -0,0 +1,40 @@
+import os
+import sys
+from distutils.errors import (CCompilerError, DistutilsExecError, 
+                              DistutilsPlatformError)
+try:
+    from setuptools.command.build_ext import build_ext
+    from pkg_resources import (normalize_path, working_set, 
+                               add_activation_listener, require)
+except ImportError:
+    raise RuntimeError("zope.interface requires Distribute under Python 3. "
+                       "See http://packages.python.org/distribute")
+
+class optional_build_ext(build_ext):
+    """This class subclasses build_ext and allows
+       the building of C extensions to fail.
+    """
+    def run(self):
+        try:
+            build_ext.run(self)
+        
+        except DistutilsPlatformError as e:
+            self._unavailable(e)
+
+    def build_extension(self, ext):
+        try:
+            build_ext.build_extension(self, ext)
+        
+        except (CCompilerError, DistutilsExecError) as e:
+            self._unavailable(e)
+
+    def _unavailable(self, e):
+        print('*' * 80, file=sys.stderr)
+        print("""WARNING:
+
+        An optional code optimization (C extension) could not be compiled.
+
+        Optimizations for this package will not be available!""", file=sys.stderr)
+        print(file=sys.stderr)
+        print(e, file=sys.stderr)
+        print('*' * 80, file=sys.stderr)
diff --git a/buildout.cfg b/buildout.cfg
new file mode 100644 (file)
index 0000000..942c7c4
--- /dev/null
@@ -0,0 +1,21 @@
+[buildout]
+develop = .
+parts = test python docs
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = zope.interface
+       zope.event
+
+[python]
+recipe = zc.recipe.egg
+eggs = zope.interface
+       zope.event
+interpreter = python
+
+[docs]
+recipe = z3c.recipe.sphinxdoc
+eggs = zope.interface [docs]
+build-dir = ${buildout:directory}/docs
+default.css =
+layout.html =
diff --git a/packaging/python-zope.interface.changes b/packaging/python-zope.interface.changes
new file mode 100644 (file)
index 0000000..aa4676a
--- /dev/null
@@ -0,0 +1,2 @@
+* Fri Aug 31 22:18:46 UTC 2012 - jimmy.huang@intel.com
+- Intial import from upstream.
diff --git a/packaging/python-zope.interface.spec b/packaging/python-zope.interface.spec
new file mode 100644 (file)
index 0000000..f9732ec
--- /dev/null
@@ -0,0 +1,28 @@
+Name:       python-zope.interface
+Version:    3.8.0
+Release:    1
+Group:      System/Libraries
+Url:        http://pypi.python.org/pypi/zope.interface
+Summary:    Interfaces for Python
+License:    ZPL 2.1
+Group:      Development/Languages/Python
+Source:     http://pypi.python.org/packages/source/z/zope.interface/zope.interface-%{version}.tar.gz
+BuildRequires:  pkgconfig(python)
+
+%description
+This package is intended to be independently reusable in any Python
+project. It is maintained by the Zope Toolkit project.
+
+%prep
+%setup -q -n zope.interface-%{version}
+
+%build
+python setup.py build
+
+%install
+python setup.py install --prefix=%{_prefix} --root=%{buildroot}
+
+%files
+%defattr(-,root,root,-)
+%doc COPYRIGHT.txt CHANGES.txt LICENSE.txt README.txt
+%{python_sitelib}/*
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..861a9f5
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..4fd4e59
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,133 @@
+##############################################################################
+#
+# Copyright (c) 2004-2007 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.
+#
+##############################################################################
+# This package is developed by the Zope Toolkit project, documented here:
+# http://docs.zope.org/zopetoolkit
+# When developing and releasing this package, please follow the documented
+# Zope Toolkit policies as described by this documentation.
+##############################################################################
+"""Setup for zope.interface package
+"""
+
+import os
+import platform
+import sys
+
+try:
+    from setuptools import setup, Extension, Feature
+except ImportError:
+    # do we need to support plain distutils for building when even
+    # the package itself requires setuptools for installing?
+    from distutils.core import setup, Extension
+
+    if sys.version_info[:2] >= (2, 4):
+        extra = dict(
+            package_data={
+                'zope.interface': ['*.txt'],
+                'zope.interface.tests': ['*.txt'],
+                }
+            )
+    else:
+        extra = {}
+
+else:
+    codeoptimization_c = os.path.join('src', 'zope', 'interface',
+                                      '_zope_interface_coptimizations.c')
+    codeoptimization = Feature(
+            "Optional code optimizations",
+            standard = True,
+            ext_modules = [Extension(
+                           "zope.interface._zope_interface_coptimizations",
+                           [os.path.normcase(codeoptimization_c)]
+                          )])
+    py_impl = getattr(platform, 'python_implementation', lambda: None)
+    is_pypy = py_impl() == 'PyPy'
+    is_jython = 'java' in sys.platform
+
+    # Jython cannot build the C optimizations, while on PyPy they are
+    # anti-optimizations (the C extension compatibility layer is known-slow,
+    # and defeats JIT opportunities).
+    if is_pypy or is_jython:
+        features = {}
+    else:
+        features = {'codeoptimization': codeoptimization}
+    extra = dict(
+        namespace_packages=["zope"],
+        include_package_data = True,
+        zip_safe = False,
+        tests_require = ['zope.event'],
+        install_requires = ['setuptools'],
+        extras_require={'docs': ['z3c.recipe.sphinxdoc'],
+                        'test': ['zope.event']},
+        features = features
+        )
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description=(
+        read('README.txt')
+        + '\n' +
+        read('CHANGES.txt')
+        )
+
+try: # Zope setuptools versions
+    from build_ext_3 import optional_build_ext
+    # This is Python 3. Setuptools is now required, and so is zope.fixers.
+    extra['install_requires'] = ['setuptools']
+    extra['setup_requires'] = ['zope.fixers']
+    extra['use_2to3'] = True
+    extra['convert_2to3_doctests'] = [
+        'src/zope/interface/README.ru.txt',
+        'src/zope/interface/README.txt',
+        'src/zope/interface/adapter.ru.txt',
+        'src/zope/interface/adapter.txt',
+        'src/zope/interface/human.ru.txt',
+        'src/zope/interface/human.txt',
+        'src/zope/interface/index.txt',
+        'src/zope/interface/verify.txt',
+        ]
+    extra['use_2to3_fixers'] = ['zope.fixers']
+
+except (ImportError, SyntaxError):
+    from build_ext_2 import optional_build_ext
+    
+setup(name='zope.interface',
+      version='3.8.0',
+      url='http://pypi.python.org/pypi/zope.interface',
+      license='ZPL 2.1',
+      description='Interfaces for Python',
+      author='Zope Foundation and Contributors',
+      author_email='zope-dev@zope.org',
+      long_description=long_description,
+      classifiers=[
+        "Development Status :: 5 - Production/Stable",
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: Zope Public License",
+        "Operating System :: OS Independent",
+        "Programming Language :: Python :: 2.4",
+        "Programming Language :: Python :: 2.5",
+        "Programming Language :: Python :: 2.6",
+        "Programming Language :: Python :: 2.7",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.1",
+        "Programming Language :: Python :: 3.2",
+        "Topic :: Software Development :: Libraries :: Python Modules",
+      ],
+
+      packages = ['zope', 'zope.interface', 'zope.interface.tests'],
+      package_dir = {'': 'src'},
+      cmdclass = {'build_ext': optional_build_ext,
+                  },
+      test_suite = 'zope.interface.tests',
+      **extra)
diff --git a/src/zope.interface.egg-info/PKG-INFO b/src/zope.interface.egg-info/PKG-INFO
new file mode 100644 (file)
index 0000000..b193c28
--- /dev/null
@@ -0,0 +1,342 @@
+Metadata-Version: 1.0
+Name: zope.interface
+Version: 3.8.0
+Summary: Interfaces for Python
+Home-page: http://pypi.python.org/pypi/zope.interface
+Author: Zope Foundation and Contributors
+Author-email: zope-dev@zope.org
+License: ZPL 2.1
+Description: ``zope.interface`` README
+        =========================
+        
+        This package is intended to be independently reusable in any Python
+        project. It is maintained by the `Zope Toolkit project
+        <http://docs.zope.org/zopetoolkit/>`_.
+        
+        This package provides an implementation of "object interfaces" for Python.
+        Interfaces are a mechanism for labeling objects as conforming to a given
+        API or contract. So, this package can be considered as implementation of
+        the `Design By Contract`_ methodology support in Python.
+        
+        .. _Design By Contract: http://en.wikipedia.org/wiki/Design_by_contract
+        
+        For detailed documentation, please see http://docs.zope.org/zope.interface
+        
+        ``zope.interface Changelog``
+        ============================
+        
+        3.8.0 (2011-09-22)
+        ------------------
+        
+        - New module ``zope.interface.registry``.  This is code moved from
+          ``zope.component.registry`` which implements a basic nonperistent component
+          registry as ``zope.interface.registry.Components``.  This class was moved
+          from ``zope.component`` to make porting systems (such as Pyramid) that rely
+          only on a basic component registry to Python 3 possible without needing to
+          port the entirety of the ``zope.component`` package.  Backwards
+          compatibility import shims have been left behind in ``zope.component``, so
+          this change will not break any existing code.
+        
+        - New ``tests_require`` dependency: ``zope.event`` to test events sent by
+          Components implementation.  The ``zope.interface`` package does not have a
+          hard dependency on ``zope.event``, but if ``zope.event`` is importable, it
+          will send component registration events when methods of an instance of
+          ``zope.interface.registry.Components`` are called.
+        
+        - New interfaces added to support ``zope.interface.registry.Components``
+          addition: ``ComponentLookupError``, ``Invalid``, ``IObjectEvent``,
+          ``ObjectEvent``, ``IComponentLookup``, ``IRegistration``,
+          ``IUtilityRegistration``, ``IAdapterRegistration``,
+          ``ISubscriptionAdapterRegistration``, ``IHandlerRegistration``,
+          ``IRegistrationEvent``, ``RegistrationEvent``, ``IRegistered``,
+          ``Registered``, ``IUnregistered``, ``Unregistered``,
+          ``IComponentRegistry``, and ``IComponents``.
+        
+        - No longer Python 2.4 compatible (tested under 2.5, 2.6, 2.7, and 3.2).
+        
+        3.7.0 (2011-08-13)
+        ------------------
+        
+        - Move changes from 3.6.2 - 3.6.5 to a new 3.7.x release line.
+        
+        3.6.7 (2011-08-20)
+        ------------------
+        
+        - Fix sporadic failures on x86-64 platforms in tests of rich comparisons
+          of interfaces.
+        
+        3.6.6 (2011-08-13)
+        ------------------
+        
+        - LP #570942:  Now correctly compare interfaces  from different modules but
+          with the same names.
+          
+          N.B.: This is a less intrusive / destabilizing fix than the one applied in
+          3.6.3:  we only fix the underlying cmp-alike function, rather than adding
+          the other "rich comparison" functions.
+        
+        - Revert to software as released with 3.6.1 for "stable" 3.6 release branch.
+        
+        3.6.5 (2011-08-11)
+        ------------------
+        
+        - LP #811792:  work around buggy behavior in some subclasses of
+          ``zope.interface.interface.InterfaceClass``, which invoke ``__hash__``
+          before initializing ``__module__`` and ``__name__``.  The workaround
+          returns a fixed constant hash in such cases, and issues a ``UserWarning``.
+        
+        - LP #804832:  Under PyPy, ``zope.interface`` should not build its C
+          extension.  Also, prevent attempting to build it under Jython.
+        
+        - Add a tox.ini for easier xplatform testing.
+        
+        - Fix testing deprecation warnings issued when tested under Py3K.
+        
+        3.6.4 (2011-07-04)
+        ------------------
+        
+        - LP 804951:  InterfaceClass instances were unhashable under Python 3.x.
+        
+        3.6.3 (2011-05-26)
+        ------------------
+        
+        - LP #570942:  Now correctly compare interfaces  from different modules but
+          with the same names.
+        
+        3.6.2 (2011-05-17)
+        ------------------
+        
+        - Moved detailed documentation out-of-line from PyPI page, linking instead to
+          http://docs.zope.org/zope.interface .
+        
+        - Fixes for small issues when running tests under Python 3.2 using
+          ``zope.testrunner``.
+        
+        - LP # 675064:  Specify return value type for C optimizations module init
+          under Python 3:  undeclared value caused warnings, and segfaults on some
+          64 bit architectures.
+        
+        - setup.py now raises RuntimeError if you don't have Distutils installed when
+          running under Python 3.
+        
+        3.6.1 (2010-05-03)
+        ------------------
+        
+        - A non-ASCII character in the changelog made 3.6.0 uninstallable on
+          Python 3 systems with another default encoding than UTF-8.
+        
+        - Fixed compiler warnings under GCC 4.3.3.
+        
+        3.6.0 (2010-04-29)
+        ------------------
+        
+        - LP #185974:  Clear the cache used by ``Specificaton.get`` inside
+          ``Specification.changed``.  Thanks to Jacob Holm for the patch.
+        
+        - Added support for Python 3.1. Contributors:
+        
+            Lennart Regebro
+            Martin v Loewis
+            Thomas Lotze
+            Wolfgang Schnerring
+        
+          The 3.1 support is completely backwards compatible. However, the implements
+          syntax used under Python 2.X does not work under 3.X, since it depends on
+          how metaclasses are implemented and this has changed. Instead it now supports
+          a decorator syntax (also under Python 2.X)::
+        
+            class Foo:
+                implements(IFoo)
+                ...
+        
+          can now also be written::
+        
+            @implementor(IFoo):
+            class Foo:
+                ...
+        
+          There are 2to3 fixers available to do this change automatically in the
+          zope.fixers package.
+        
+        - Python 2.3 is no longer supported.
+        
+        
+        3.5.4 (2009-12-23)
+        ------------------
+        
+        - Use the standard Python doctest module instead of zope.testing.doctest, which
+          has been deprecated.
+        
+        
+        3.5.3 (2009-12-08)
+        ------------------
+        
+        - Fix an edge case: make providedBy() work when a class has '__provides__' in
+          its __slots__ (see http://thread.gmane.org/gmane.comp.web.zope.devel/22490)
+        
+        
+        3.5.2 (2009-07-01)
+        ------------------
+        
+        - BaseAdapterRegistry.unregister, unsubscribe: Remove empty portions of
+          the data structures when something is removed.  This avoids leaving
+          references to global objects (interfaces) that may be slated for
+          removal from the calling application.
+        
+        
+        3.5.1 (2009-03-18)
+        ------------------
+        
+        - verifyObject: use getattr instead of hasattr to test for object attributes
+          in order to let exceptions other than AttributeError raised by properties
+          propagate to the caller
+        
+        - Add Sphinx-based documentation building to the package buildout
+          configuration. Use the ``bin/docs`` command after buildout.
+        
+        - Improve package description a bit. Unify changelog entries formatting.
+        
+        - Change package's mailing list address to zope-dev at zope.org as
+          zope3-dev at zope.org is now retired.
+        
+        
+        3.5.0 (2008-10-26)
+        ------------------
+        
+        - Fixed declaration of _zope_interface_coptimizations, it's not a top level
+          package.
+        
+        - Add a DocTestSuite for odd.py module, so their tests are run.
+        
+        - Allow to bootstrap on Jython.
+        
+        - Fix https://bugs.launchpad.net/zope3/3.3/+bug/98388: ISpecification
+          was missing a declaration for __iro__.
+        
+        - Added optional code optimizations support, which allows the building
+          of C code optimizations to fail (Jython).
+        
+        - Replaced `_flatten` with a non-recursive implementation, effectively making
+          it 3x faster.
+        
+        
+        3.4.1 (2007-10-02)
+        ------------------
+        
+        - Fixed a setup bug that prevented installation from source on systems
+          without setuptools.
+        
+        
+        3.4.0 (2007-07-19)
+        ------------------
+        
+        - Final release for 3.4.0.
+        
+        
+        3.4.0b3 (2007-05-22)
+        --------------------
+        
+        
+        - Objects with picky custom comparison methods couldn't be added to
+          component registries.  Now, when checking whether an object is
+          already registered, identity comparison is used.
+        
+        
+        3.3.0.1 (2007-01-03)
+        --------------------
+        
+        - Made a reference to OverflowWarning, which disappeared in Python
+          2.5, conditional.
+        
+        
+        3.3.0 (2007/01/03)
+        ------------------
+        
+        New Features
+        ++++++++++++
+        
+        - The adapter-lookup algorithim was refactored to make it
+          much simpler and faster.  
+        
+          Also, more of the adapter-lookup logic is implemented in C, making
+          debugging of application code easier, since there is less
+          infrastructre code to step through.
+        
+        - We now treat objects without interface declarations as if they
+          declared that they provide zope.interface.Interface.
+        
+        - There are a number of richer new adapter-registration interfaces
+          that provide greater control and introspection.
+        
+        - Added a new interface decorator to zope.interface that allows the
+          setting of tagged values on an interface at definition time (see
+          zope.interface.taggedValue).
+        
+        Bug Fixes
+        +++++++++
+        
+        - A bug in multi-adapter lookup sometimes caused incorrect adapters to
+          be returned.
+        
+        
+        3.2.0.2 (2006-04-15)
+        --------------------
+        
+        - Fix packaging bug:  'package_dir' must be a *relative* path.
+        
+        
+        3.2.0.1 (2006-04-14)
+        --------------------
+        
+        - Packaging change:  suppress inclusion of 'setup.cfg' in 'sdist' builds.
+        
+        
+        3.2.0 (2006-01-05)
+        ------------------
+        
+        - Corresponds to the verison of the zope.interface package shipped as part of
+          the Zope 3.2.0 release.
+        
+        
+        3.1.0 (2005-10-03)
+        ------------------
+        
+        - Corresponds to the verison of the zope.interface package shipped as part of
+          the Zope 3.1.0 release.
+        
+        - Made attribute resolution order consistent with component lookup order,
+          i.e. new-style class MRO semantics.
+        
+        - Deprecated 'isImplementedBy' and 'isImplementedByInstancesOf' APIs in
+          favor of 'implementedBy' and 'providedBy'.
+        
+        
+        3.0.1 (2005-07-27)
+        ------------------
+        
+        - Corresponds to the verison of the zope.interface package shipped as part of
+          the Zope X3.0.1 release.
+        
+        - Fixed a bug reported by James Knight, which caused adapter registries
+          to fail occasionally to reflect declaration changes.
+        
+        
+        3.0.0 (2004-11-07)
+        ------------------
+        
+        - Corresponds to the verison of the zope.interface package shipped as part of
+          the Zope X3.0.0 release.
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Zope Public License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2.4
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/src/zope.interface.egg-info/SOURCES.txt b/src/zope.interface.egg-info/SOURCES.txt
new file mode 100644 (file)
index 0000000..702e2dc
--- /dev/null
@@ -0,0 +1,68 @@
+.bzrignore
+CHANGES.txt
+COPYRIGHT.txt
+LICENSE.txt
+README.txt
+bootstrap.py
+build_ext_2.py
+build_ext_3.py
+buildout.cfg
+setup.py
+tox.ini
+src/zope/__init__.py
+src/zope.interface.egg-info/PKG-INFO
+src/zope.interface.egg-info/SOURCES.txt
+src/zope.interface.egg-info/dependency_links.txt
+src/zope.interface.egg-info/namespace_packages.txt
+src/zope.interface.egg-info/not-zip-safe
+src/zope.interface.egg-info/requires.txt
+src/zope.interface.egg-info/top_level.txt
+src/zope/interface/README.ru.txt
+src/zope/interface/README.txt
+src/zope/interface/__init__.py
+src/zope/interface/_flatten.py
+src/zope/interface/_zope_interface_coptimizations.c
+src/zope/interface/adapter.py
+src/zope/interface/adapter.ru.txt
+src/zope/interface/adapter.txt
+src/zope/interface/advice.py
+src/zope/interface/declarations.py
+src/zope/interface/document.py
+src/zope/interface/exceptions.py
+src/zope/interface/human.ru.txt
+src/zope/interface/human.txt
+src/zope/interface/index.txt
+src/zope/interface/interface.py
+src/zope/interface/interfaces.py
+src/zope/interface/registry.py
+src/zope/interface/ro.py
+src/zope/interface/verify.py
+src/zope/interface/verify.txt
+src/zope/interface/common/__init__.py
+src/zope/interface/common/idatetime.py
+src/zope/interface/common/interfaces.py
+src/zope/interface/common/mapping.py
+src/zope/interface/common/sequence.py
+src/zope/interface/common/tests/__init__.py
+src/zope/interface/common/tests/basemapping.py
+src/zope/interface/common/tests/test_idatetime.py
+src/zope/interface/common/tests/test_import_interfaces.py
+src/zope/interface/tests/__init__.py
+src/zope/interface/tests/dummy.py
+src/zope/interface/tests/foodforthought.txt
+src/zope/interface/tests/ifoo.py
+src/zope/interface/tests/ifoo_other.py
+src/zope/interface/tests/m1.py
+src/zope/interface/tests/m2.py
+src/zope/interface/tests/odd.py
+src/zope/interface/tests/test_adapter.py
+src/zope/interface/tests/test_advice.py
+src/zope/interface/tests/test_declarations.py
+src/zope/interface/tests/test_document.py
+src/zope/interface/tests/test_element.py
+src/zope/interface/tests/test_interface.py
+src/zope/interface/tests/test_odd_declarations.py
+src/zope/interface/tests/test_registry.py
+src/zope/interface/tests/test_sorting.py
+src/zope/interface/tests/test_verify.py
+src/zope/interface/tests/unitfixtures.py
\ No newline at end of file
diff --git a/src/zope.interface.egg-info/dependency_links.txt b/src/zope.interface.egg-info/dependency_links.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/src/zope.interface.egg-info/namespace_packages.txt b/src/zope.interface.egg-info/namespace_packages.txt
new file mode 100644 (file)
index 0000000..66179d4
--- /dev/null
@@ -0,0 +1 @@
+zope
diff --git a/src/zope.interface.egg-info/not-zip-safe b/src/zope.interface.egg-info/not-zip-safe
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/src/zope.interface.egg-info/requires.txt b/src/zope.interface.egg-info/requires.txt
new file mode 100644 (file)
index 0000000..e9d940f
--- /dev/null
@@ -0,0 +1,7 @@
+setuptools
+
+[test]
+zope.event
+
+[docs]
+z3c.recipe.sphinxdoc
\ No newline at end of file
diff --git a/src/zope.interface.egg-info/top_level.txt b/src/zope.interface.egg-info/top_level.txt
new file mode 100644 (file)
index 0000000..66179d4
--- /dev/null
@@ -0,0 +1 @@
+zope
diff --git a/src/zope/__init__.py b/src/zope/__init__.py
new file mode 100644 (file)
index 0000000..2e2033b
--- /dev/null
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)
diff --git a/src/zope/interface/README.ru.txt b/src/zope/interface/README.ru.txt
new file mode 100644 (file)
index 0000000..7c0dd63
--- /dev/null
@@ -0,0 +1,803 @@
+==========
+Интерфейсы
+==========
+
+.. contents::
+
+Интерфейсы - это объекты специфицирующие (документирующие) внешнее поведение
+объектов которые их "предоставляют". Интерфейсы определяют поведение через
+следующие составляющие:
+
+- Неформальную документацию в строках документации
+
+- Определения атрибутов
+
+- Инварианты - условия, которые должны соблюдаться для объектов предоставляющих
+  интерфейс
+
+Определения атрибутов описывают конкретные атрибуты. Они определяют
+имя атрибута и предоставляют документацию и ограничения для значений
+атрибута. Определения атрибутов могут быть заданы несколькими путями
+как мы увидим ниже.
+
+Определение интерфейсов
+=======================
+
+Интерфейсы определяются с использованием ключевого слова class::
+
+  >>> import zope.interface
+  >>> class IFoo(zope.interface.Interface):
+  ...    """Foo blah blah"""
+  ...
+  ...    x = zope.interface.Attribute("""X blah blah""")
+  ...
+  ...    def bar(q, r=None):
+  ...        """bar blah blah"""
+
+В примере выше мы создали интерфейс `IFoo`. Мы наследуем его от
+класса `zope.interface.Interface`, который является родительским интерфейсом
+для всех интерфейсов, как `object` - это родительский класс для всех новых
+классов [#create]_. Данный интерфейс не является классом, а является
+Интерфейсом, экземпляром `InterfaceClass`::
+
+  >>> type(IFoo)
+  <class 'zope.interface.interface.InterfaceClass'>
+
+Мы можем запросить у интерфейса его документацию::
+
+  >>> IFoo.__doc__
+  'Foo blah blah'
+
+и его имя::
+
+  >>> IFoo.__name__
+  'IFoo'
+
+и даже модуль в котором он определен::
+
+  >>> IFoo.__module__
+  '__main__'
+
+Наш интерфейс определяет два атрибута:
+
+`x`
+  Это простейшая форма определения атрибутов. Определяются имя
+  и строка документации. Формально здесь не определяется ничего более.
+
+`bar`
+  Это метод. Методы определяются как обычные функции. Метод - это просто
+  атрибут который должен быть вызываемым с указанием сигнатуры,
+  предоставляемой определением функции.
+
+  Надо отметить, что аргумент `self` не указывается для `bar`. Интерфейс
+  документирует как объект *используется*. Когда методы экземпляров классов
+  вызываются мы не передаем аргумент `self`, таким образом аргумент `self`
+  не включается и в сигнатуру интерфейса. Аргумент `self` в методах
+  экземпляров классов на самом деле деталь реализации экземпляров классов
+  в Python. Другие объекты кроме экземпляров классов могут предоставлять
+  интерфейсы и их методы могут не быть методами экземпляров классов. Для
+  примера модули могут предоставлять интерфейсы и их методы обычно просто
+  функции. Даже экземпляры могут иметь методы не являющиеся методами
+  экземпляров класса.
+
+Мы можем получить доступ к атрибутам определенным интерфейсом используя
+синтаксис доступа к элементам массива::
+
+  >>> x = IFoo['x']
+  >>> type(x)
+  <class 'zope.interface.interface.Attribute'>
+  >>> x.__name__
+  'x'
+  >>> x.__doc__
+  'X blah blah'
+
+  >>> IFoo.get('x').__name__
+  'x'
+
+  >>> IFoo.get('y')
+
+Можно использовать `in` для определения содержит ли интерфейс
+определенное имя::
+
+  >>> 'x' in IFoo
+  True
+
+Мы можем использовать итератор для интерфейсов что бы получить все имена
+которые интерфейсы определяют::
+
+  >>> names = list(IFoo)
+  >>> names.sort()
+  >>> names
+  ['bar', 'x']
+
+Надо помнить, что интерфейсы не являются классами. Мы не можем получить
+доступ к определениям атрибутов через доступ к атрибутам интерфейсов::
+
+  >>> IFoo.x
+  Traceback (most recent call last):
+    File "<stdin>", line 1, in ?
+  AttributeError: 'InterfaceClass' object has no attribute 'x'
+
+Методы также предоставляют доступ к сигнатуре метода::
+
+  >>> bar = IFoo['bar']
+  >>> bar.getSignatureString()
+  '(q, r=None)'
+
+Объявление интерфейсов
+======================
+
+Определив интерфейс мы можем теперь *объявить*, что объекты предоставляют их.
+Перед описанием деталей определим некоторые термины:
+
+*предоставлять*
+  Мы говорим, что объекты *предоставляют* интерфейсы. Если объект
+  предоставляет интерфейс, тогда интерфейс специфицирует поведение объекта.
+  Другими словами, интерфейсы специфицируют поведение объектов которые
+  предоставляют их.
+
+*реализовать*
+  Мы обычно говорим что классы *реализуют* интерфейсы. Если класс
+  реализует интерфейс, тогда экземпляры этого класса предоставляют
+  данный интерфейс. Объекты предоставляют интерфейсы которые их классы
+  реализуют [#factory]_. (Объекты также могут предоставлять интерфейсы напрямую
+  плюс к тем которые реализуют их классы.)
+
+  Важно помнить, что классы обычно не предоставляют интерфейсы которые
+  они реализуют.
+
+  Мы можем обобщить это до фабрик. Для любого вызываемого объекта мы можем
+  объявить что он производит объекты которые предоставляют какие-либо
+  интерфейсы сказав, что фабрика реализует данные интерфейсы.
+
+Теперь после того как мы определили эти термины мы можем поговорить об
+API для объявления интерфейсов.
+
+Объявление реализуемых интерфейсов
+----------------------------------
+
+Наиболее часто используемый путь для объявления интерфейсов - это использование
+функции implements в определении класса::
+
+  >>> class Foo:
+  ...     zope.interface.implements(IFoo)
+  ...
+  ...     def __init__(self, x=None):
+  ...         self.x = x
+  ...
+  ...     def bar(self, q, r=None):
+  ...         return q, r, self.x
+  ...
+  ...     def __repr__(self):
+  ...         return "Foo(%s)" % self.x
+
+В этом примере мы объявили, что `Foo` реализует `IFoo`. Это значит, что
+экземпляры `Foo` предоставляют `IFoo`. После данного объявления есть
+несколько путей для анализа объявлений. Во-первых мы можем спросить
+что интерфейс реализован классом::
+
+  >>> IFoo.implementedBy(Foo)
+  True
+
+Также мы можем спросить если интерфейс предоставляется объектами класса::
+
+  >>> foo = Foo()
+  >>> IFoo.providedBy(foo)
+  True
+
+Конечно `Foo` не предоставляет `IFoo`, он реализует его::
+
+  >>> IFoo.providedBy(Foo)
+  False
+
+Мы можем также узнать какие интерфейсы реализуются объектами::
+
+  >>> list(zope.interface.implementedBy(Foo))
+  [<InterfaceClass __main__.IFoo>]
+
+Это ошибка спрашивать про интерфейсы реализуемые не вызываемым объектом::
+
+  >>> IFoo.implementedBy(foo)
+  Traceback (most recent call last):
+  ...
+  TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+  >>> list(zope.interface.implementedBy(foo))
+  Traceback (most recent call last):
+  ...
+  TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+Также можно узнать какие интерфейсы предоставляются объектами::
+
+  >>> list(zope.interface.providedBy(foo))
+  [<InterfaceClass __main__.IFoo>]
+  >>> list(zope.interface.providedBy(Foo))
+  []
+
+Мы можем объявить интерфейсы реализуемые другими фабриками (кроме классов).
+Это можно сделать используя декоратор `implementer` (в стиле Python 2.4).
+Для версий Python ниже 2.4 это будет выглядеть следующим образом::
+
+  >>> def yfoo(y):
+  ...     foo = Foo()
+  ...     foo.y = y
+  ...     return foo
+  >>> yfoo = zope.interface.implementer(IFoo)(yfoo)
+
+  >>> list(zope.interface.implementedBy(yfoo))
+  [<InterfaceClass __main__.IFoo>]
+
+Надо заметить, что декоратор implementer может модифицировать свои аргументы.
+Вызывающая сторона не должна предполагать, что всегда будет создаваться
+новый объект.
+
+XXX: Double check and update these version numbers, and translate to russian:
+
+In zope.interface 3.5.1 and lower, the implementor decorator can not
+be used for classes, but in 3.5.2 and higher it can:
+
+  >>> Foo = zope.interface.implementer(IFoo)(Foo)
+  >>> list(zope.interface.providedBy(Foo()))
+  [<InterfaceClass __main__.IFoo>]
+  
+Note that class decorators using the @implementor(IFoo) syntax are only 
+supported in Python 2.6 and later.
+
+
+Объявление предоставляемых интерфейсов
+--------------------------------------
+
+Мы можем объявлять интерфейсы напрямую предоставляемые объектами. Предположим
+что мы хотим документировать что делает метод `__init__` класса `Foo`. Это
+*точно* не часть `IFoo`. Обычно мы не должны напрямую вызывать метод `__init__`
+для экземпляров Foo. Скорее метод `__init__` является частью метода `__call__`
+класса `Foo`::
+
+  >>> class IFooFactory(zope.interface.Interface):
+  ...     """Create foos"""
+  ...
+  ...     def __call__(x=None):
+  ...         """Create a foo
+  ...
+  ...         The argument provides the initial value for x ...
+  ...         """
+
+У нас есть класс предоставляющий данный интерфейс, таким образом мы можем
+объявить интерфейс класса::
+
+  >>> zope.interface.directlyProvides(Foo, IFooFactory)
+
+Теперь мы видим, что Foo уже предоставляет интерфейсы::
+
+  >>> list(zope.interface.providedBy(Foo))
+  [<InterfaceClass __main__.IFooFactory>]
+  >>> IFooFactory.providedBy(Foo)
+  True
+
+Объявление интерфейсов класса достаточно частая операция и для нее есть
+специальная функция объявления `classProvides`, которая позволяет объявлять
+интерфейсы при определении класса::
+
+  >>> class Foo2:
+  ...     zope.interface.implements(IFoo)
+  ...     zope.interface.classProvides(IFooFactory)
+  ...
+  ...     def __init__(self, x=None):
+  ...         self.x = x
+  ...
+  ...     def bar(self, q, r=None):
+  ...         return q, r, self.x
+  ...
+  ...     def __repr__(self):
+  ...         return "Foo(%s)" % self.x
+
+  >>> list(zope.interface.providedBy(Foo2))
+  [<InterfaceClass __main__.IFooFactory>]
+  >>> IFooFactory.providedBy(Foo2)
+  True
+
+Похожая функция `moduleProvides` поддерживает объявление интерфейсов при
+определении модуля. Для примера смотрите использование вызова
+`moduleProvides` в `zope.interface.__init__`, который объявляет, что
+пакет `zope.interface` предоставляет `IInterfaceDeclaration`.
+
+Иногда мы хотим объявить интерфейсы экземпляров, даже если эти экземпляры
+уже берут интерфейсы от своих классов. Предположим, что мы создаем новый
+интерфейс `ISpecial`::
+
+  >>> class ISpecial(zope.interface.Interface):
+  ...     reason = zope.interface.Attribute("Reason why we're special")
+  ...     def brag():
+  ...         "Brag about being special"
+
+Мы можем сделать созданный экземпляр foo специальным предоставив атрибуты
+`reason` и `brag`::
+
+  >>> foo.reason = 'I just am'
+  >>> def brag():
+  ...      return "I'm special!"
+  >>> foo.brag = brag
+  >>> foo.reason
+  'I just am'
+  >>> foo.brag()
+  "I'm special!"
+
+и объявив интерфейс::
+
+  >>> zope.interface.directlyProvides(foo, ISpecial)
+
+таким образом новый интерфейс включается в список предоставляемых интерфейсов::
+
+  >>> ISpecial.providedBy(foo)
+  True
+  >>> list(zope.interface.providedBy(foo))
+  [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+Мы также можем определить, что интерфейсы напрямую предоставляются
+объектами::
+
+  >>> list(zope.interface.directlyProvidedBy(foo))
+  [<InterfaceClass __main__.ISpecial>]
+
+  >>> newfoo = Foo()
+  >>> list(zope.interface.directlyProvidedBy(newfoo))
+  []
+
+Наследуемые объявления
+----------------------
+
+Обычно объявления наследуются::
+
+  >>> class SpecialFoo(Foo):
+  ...     zope.interface.implements(ISpecial)
+  ...     reason = 'I just am'
+  ...     def brag(self):
+  ...         return "I'm special because %s" % self.reason
+
+  >>> list(zope.interface.implementedBy(SpecialFoo))
+  [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+  >>> list(zope.interface.providedBy(SpecialFoo()))
+  [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+Иногда мы не хотим наследовать объявления. В этом случае мы можем
+использовать `implementsOnly` вместо `implements`::
+
+  >>> class Special(Foo):
+  ...     zope.interface.implementsOnly(ISpecial)
+  ...     reason = 'I just am'
+  ...     def brag(self):
+  ...         return "I'm special because %s" % self.reason
+
+  >>> list(zope.interface.implementedBy(Special))
+  [<InterfaceClass __main__.ISpecial>]
+
+  >>> list(zope.interface.providedBy(Special()))
+  [<InterfaceClass __main__.ISpecial>]
+
+Внешние объявления
+------------------
+
+Обычно мы создаем объявления реализации как часть объявления класса. Иногда
+мы можем захотеть создать объявления вне объявления класса. Для примера,
+мы можем хотеть объявить интерфейсы для классов которые писали не мы.
+Для этого может использоваться функция `classImplements`::
+
+  >>> class C:
+  ...     pass
+
+  >>> zope.interface.classImplements(C, IFoo)
+  >>> list(zope.interface.implementedBy(C))
+  [<InterfaceClass __main__.IFoo>]
+
+Мы можем использовать `classImplementsOnly` для исключения наследуемых
+интерфейсов::
+
+  >>> class C(Foo):
+  ...     pass
+
+  >>> zope.interface.classImplementsOnly(C, ISpecial)
+  >>> list(zope.interface.implementedBy(C))
+  [<InterfaceClass __main__.ISpecial>]
+
+Объекты объявлений
+------------------
+
+Когда мы объявляем интерфейсы мы создаем объект *объявления*. Когда мы
+запрашиваем объявления возвращается объект объявления::
+
+  >>> type(zope.interface.implementedBy(Special))
+  <class 'zope.interface.declarations.Implements'>
+
+Объекты объявления и объекты интерфейсов во многом похожи друг на друга.
+На самом деле они даже имеют общий базовый класс. Важно понять, что они могут
+использоваться там где в объявлениях ожидаются интерфейсы. Вот простой
+пример::
+
+  >>> class Special2(Foo):
+  ...     zope.interface.implementsOnly(
+  ...          zope.interface.implementedBy(Foo),
+  ...          ISpecial,
+  ...          )
+  ...     reason = 'I just am'
+  ...     def brag(self):
+  ...         return "I'm special because %s" % self.reason
+
+Объявление здесь практически такое же как
+``zope.interface.implements(ISpecial)``, отличие только в порядке
+интерфейсов в итоговом объявления::
+
+  >>> list(zope.interface.implementedBy(Special2))
+  [<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.ISpecial>]
+
+Наследование интерфейсов
+========================
+
+Интерфейсы могут расширять другие интерфейсы. Они делают это просто
+показывая эти интерфейсы как базовые::
+
+  >>> class IBlat(zope.interface.Interface):
+  ...     """Blat blah blah"""
+  ...
+  ...     y = zope.interface.Attribute("y blah blah")
+  ...     def eek():
+  ...         """eek blah blah"""
+
+  >>> IBlat.__bases__
+  (<InterfaceClass zope.interface.Interface>,)
+
+  >>> class IBaz(IFoo, IBlat):
+  ...     """Baz blah"""
+  ...     def eek(a=1):
+  ...         """eek in baz blah"""
+  ...
+
+  >>> IBaz.__bases__
+  (<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.IBlat>)
+
+  >>> names = list(IBaz)
+  >>> names.sort()
+  >>> names
+  ['bar', 'eek', 'x', 'y']
+
+Заметим, что `IBaz` переопределяет eek::
+
+  >>> IBlat['eek'].__doc__
+  'eek blah blah'
+  >>> IBaz['eek'].__doc__
+  'eek in baz blah'
+
+Мы были осторожны переопределяя eek совместимым путем. Когда интерфейс
+расширяется, расширенный интерфейс должен быть совместимым [#compat]_ с
+расширяемыми интерфейсами.
+
+Мы можем запросить расширяет ли один из интерфейсов другой::
+
+  >>> IBaz.extends(IFoo)
+  True
+  >>> IBlat.extends(IFoo)
+  False
+
+Заметим, что интерфейсы не расширяют сами себя::
+
+  >>> IBaz.extends(IBaz)
+  False
+
+Иногда мы можем хотеть что бы они расширяли сами себя, но вместо этого
+мы можем использовать `isOrExtends`::
+
+  >>> IBaz.isOrExtends(IBaz)
+  True
+  >>> IBaz.isOrExtends(IFoo)
+  True
+  >>> IFoo.isOrExtends(IBaz)
+  False
+
+Когда мы применяем итерацию к интерфейсу мы получаем все имена которые он
+определяет включая имена определенные для базовых интерфейсов. Иногда
+мы хотим получить *только* имена определенные интерфейсом напрямую.
+Для этого мы используем метод `names`::
+
+  >>> list(IBaz.names())
+  ['eek']
+
+Наследование в случае определения атрибутов
+--------------------------------------------
+
+Интерфейс может переопределять определения атрибутов из базовых интерфейсов.
+Если два базовых интерфейса определяют один и тот же атрибут атрибут
+наследуется от более специфичного интерфейса. Для примера::
+
+  >>> class IBase(zope.interface.Interface):
+  ...
+  ...     def foo():
+  ...         "base foo doc"
+
+  >>> class IBase1(IBase):
+  ...     pass
+
+  >>> class IBase2(IBase):
+  ...
+  ...     def foo():
+  ...         "base2 foo doc"
+
+  >>> class ISub(IBase1, IBase2):
+  ...     pass
+
+Определение ISub для foo будет из IBase2 т.к. IBase2 более специфичен для
+IBase::
+
+  >>> ISub['foo'].__doc__
+  'base2 foo doc'
+
+Заметим, что это отличается от поиска в глубину.
+
+Иногда полезно узнать, что интерфейс определяет атрибут напрямую. Мы можем
+использовать метод direct для получения напрямую определенных атрибутов::
+
+  >>> IBase.direct('foo').__doc__
+  'base foo doc'
+
+  >>> ISub.direct('foo')
+
+Спецификации
+------------
+
+Интерфейсы и объявления - это специальные случаи спецификаций. Описание
+выше для наследования интерфейсов можно применить и к объявлениям и
+к спецификациям. Объявления фактически расширяют интерфейсы которые они
+объявляют::
+
+  >>> class Baz(object):
+  ...     zope.interface.implements(IBaz)
+
+  >>> baz_implements = zope.interface.implementedBy(Baz)
+  >>> baz_implements.__bases__
+  (<InterfaceClass __main__.IBaz>, <implementedBy ...object>)
+
+  >>> baz_implements.extends(IFoo)
+  True
+
+  >>> baz_implements.isOrExtends(IFoo)
+  True
+  >>> baz_implements.isOrExtends(baz_implements)
+  True
+
+Спецификации (интерфейсы и объявления) предоставляют атрибут `__sro__`
+который описывает спецификацию и всех ее предков::
+
+  >>> baz_implements.__sro__
+  (<implementedBy __main__.Baz>,
+   <InterfaceClass __main__.IBaz>,
+   <InterfaceClass __main__.IFoo>,
+   <InterfaceClass __main__.IBlat>,
+   <InterfaceClass zope.interface.Interface>,
+   <implementedBy ...object>)
+
+Помеченные значения
+===================
+
+Интерфейсы и описания атрибутов поддерживают механизм расширения
+заимствованный из UML и называемый "помеченные значения" который позволяет
+сохранять дополнительные данные::
+
+  >>> IFoo.setTaggedValue('date-modified', '2004-04-01')
+  >>> IFoo.setTaggedValue('author', 'Jim Fulton')
+  >>> IFoo.getTaggedValue('date-modified')
+  '2004-04-01'
+  >>> IFoo.queryTaggedValue('date-modified')
+  '2004-04-01'
+  >>> IFoo.queryTaggedValue('datemodified')
+  >>> tags = list(IFoo.getTaggedValueTags())
+  >>> tags.sort()
+  >>> tags
+  ['author', 'date-modified']
+
+Атрибуты функций конвертируются в помеченные значения когда создаются
+определения атрибутов метода::
+
+  >>> class IBazFactory(zope.interface.Interface):
+  ...     def __call__():
+  ...         "create one"
+  ...     __call__.return_type = IBaz
+
+  >>> IBazFactory['__call__'].getTaggedValue('return_type')
+  <InterfaceClass __main__.IBaz>
+
+Помеченные значения также могут быть определены внутри определения
+интерфейса::
+
+  >>> class IWithTaggedValues(zope.interface.Interface):
+  ...     zope.interface.taggedValue('squish', 'squash')
+  >>> IWithTaggedValues.getTaggedValue('squish')
+  'squash'
+
+Инварианты
+==========
+
+Интерфейсы могут описывать условия которые должны быть соблюдены для объектов
+которые их предоставляют. Эти условия описываются используя один или более
+инвариантов. Инварианты - это вызываемые объекты которые будут вызваны
+с объектом предоставляющим интерфейс в качестве параметра. Инвариант
+должен выкинуть исключение `Invalid` если условие не соблюдено. Например::
+
+  >>> class RangeError(zope.interface.Invalid):
+  ...     """A range has invalid limits"""
+  ...     def __repr__(self):
+  ...         return "RangeError(%r)" % self.args
+
+  >>> def range_invariant(ob):
+  ...     if ob.max < ob.min:
+  ...         raise RangeError(ob)
+
+Определив этот инвариант мы можем использовать его в определении интерфейсов::
+
+  >>> class IRange(zope.interface.Interface):
+  ...     min = zope.interface.Attribute("Lower bound")
+  ...     max = zope.interface.Attribute("Upper bound")
+  ...
+  ...     zope.interface.invariant(range_invariant)
+
+Интерфейсы имеют метод для проверки своих инвариантов::
+
+  >>> class Range(object):
+  ...     zope.interface.implements(IRange)
+  ...
+  ...     def __init__(self, min, max):
+  ...         self.min, self.max = min, max
+  ...
+  ...     def __repr__(self):
+  ...         return "Range(%s, %s)" % (self.min, self.max)
+
+  >>> IRange.validateInvariants(Range(1,2))
+  >>> IRange.validateInvariants(Range(1,1))
+  >>> IRange.validateInvariants(Range(2,1))
+  Traceback (most recent call last):
+  ...
+  RangeError: Range(2, 1)
+
+В случае нескольких инвариантов мы можем захотеть остановить проверку после
+первой ошибки. Если мы передадим в `validateInvariants` пустой список тогда
+будет выкинуто единственное исключение `Invalid` со списком исключений
+как аргументом::
+
+  >>> from zope.interface.exceptions import Invalid
+  >>> errors = []
+  >>> try:
+  ...     IRange.validateInvariants(Range(2,1), errors)
+  ... except Invalid, e:
+  ...     str(e)
+  '[RangeError(Range(2, 1))]'
+
+И список будет заполнен индивидуальными исключениями::
+
+  >>> errors
+  [RangeError(Range(2, 1))]
+
+  >>> del errors[:]
+
+Адаптация
+=========
+
+Интерфейсы могут быть вызваны для осуществления адаптации. Эта семантика
+основана на функции adapt из PEP 246. Если объект не может быть адаптирован
+будет выкинут TypeError::
+
+  >>> class I(zope.interface.Interface):
+  ...     pass
+
+  >>> I(0)
+  Traceback (most recent call last):
+  ...
+  TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>)
+
+только если альтернативное значение не передано как второй аргумент::
+
+  >>> I(0, 'bob')
+  'bob'
+
+Если объект уже реализует нужный интерфейс он будет возвращен::
+
+  >>> class C(object):
+  ...     zope.interface.implements(I)
+
+  >>> obj = C()
+  >>> I(obj) is obj
+  True
+
+Если объект реализует __conform__, тогда она будет использована::
+
+  >>> class C(object):
+  ...     zope.interface.implements(I)
+  ...     def __conform__(self, proto):
+  ...          return 0
+
+  >>> I(C())
+  0
+
+Также если присутствуют функции для вызова адаптации (см. __adapt__) они будут
+использованы::
+
+  >>> from zope.interface.interface import adapter_hooks
+  >>> def adapt_0_to_42(iface, obj):
+  ...     if obj == 0:
+  ...         return 42
+
+  >>> adapter_hooks.append(adapt_0_to_42)
+  >>> I(0)
+  42
+
+  >>> adapter_hooks.remove(adapt_0_to_42)
+  >>> I(0)
+  Traceback (most recent call last):
+  ...
+  TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>)
+
+
+__adapt__
+---------
+
+  >>> class I(zope.interface.Interface):
+  ...     pass
+
+Интерфейсы реализуют метод __adapt__ из PEP 246. Этот метод обычно не
+вызывается напрямую. Он вызывается архитектурой адаптации из PEP 246 и методом
+__call__ интерфейсов. Метод адаптации отвечает за адаптацию объекта к
+получателю. Версия по умолчанию возвращает None::
+
+  >>> I.__adapt__(0)
+
+если только переданный объект не предоставляет нужный интерфейс::
+
+  >>> class C(object):
+  ...     zope.interface.implements(I)
+
+  >>> obj = C()
+  >>> I.__adapt__(obj) is obj
+  True
+
+Функции для вызова адаптации могут быть добавлены (или удалены) для
+предоставления адаптации "на заказ". Мы установим глупую функцию которая
+адаптирует 0 к 42. Мы устанавливаем функцию просто добавляя ее к списку
+adapter_hooks::
+
+  >>> from zope.interface.interface import adapter_hooks
+  >>> def adapt_0_to_42(iface, obj):
+  ...     if obj == 0:
+  ...         return 42
+
+  >>> adapter_hooks.append(adapt_0_to_42)
+  >>> I.__adapt__(0)
+  42
+
+Функции должны возвращать либо адаптер, либо None если адаптер не найден.
+Функции могут быть удалены удалением их из списка::
+
+  >>> adapter_hooks.remove(adapt_0_to_42)
+  >>> I.__adapt__(0)
+
+
+.. [#create] Основная причина по которой мы наследуемся от `Interface` - это
+             что бы быть уверенными в том, что ключевое слово class будет
+             создавать интерфейс, а не класс.
+
+             Есть возможность создать интерфейсы вызвав специальный
+             класс интерфейса напрямую. Делая это, возможно (и в редких
+             случаях полезно) создать интерфейсы которые не наследуются
+             от `Interface`. Однако использование этой техники выходит
+            за рамки данного документа.
+
+.. [#factory] Классы - это фабрики. Они могут быть вызваны для создания
+              своих экземпляров. Мы ожидаем что в итоге мы расширим
+              концепцию реализации на другие типы фабрик, таким образом
+              мы сможем объявлять интерфейсы предоставляемые созданными
+              фабриками объектами.
+
+.. [#compat] Цель - заменяемость. Объект который предоставляет расширенный
+             интерфейс должен быть заменяем в качестве объектов которые
+             предоставляют расширяемый интерфейс. В нашем примере объект
+             который предоставляет IBaz должен быть используемым и
+             в случае если ожидается объект который предоставляет IBlat.
+
+             Реализация интерфейса не требует этого. Но возможно в дальнейшем
+             она должна будет делать какие-либо проверки.
diff --git a/src/zope/interface/README.txt b/src/zope/interface/README.txt
new file mode 100644 (file)
index 0000000..e5bc7b3
--- /dev/null
@@ -0,0 +1,829 @@
+==========
+Interfaces
+==========
+
+Interfaces are objects that specify (document) the external behavior
+of objects that "provide" them.  An interface specifies behavior
+through:
+
+- Informal documentation in a doc string
+
+- Attribute definitions
+
+- Invariants, which are conditions that must hold for objects that
+  provide the interface
+
+Attribute definitions specify specific attributes. They define the
+attribute name and provide documentation and constraints of attribute
+values.  Attribute definitions can take a number of forms, as we'll
+see below.
+
+Defining interfaces
+===================
+
+Interfaces are defined using Python class statements::
+
+  >>> import zope.interface
+  >>> class IFoo(zope.interface.Interface):
+  ...    """Foo blah blah"""
+  ...
+  ...    x = zope.interface.Attribute("""X blah blah""")
+  ...
+  ...    def bar(q, r=None):
+  ...        """bar blah blah"""
+
+In the example above, we've created an interface, `IFoo`.  We
+subclassed `zope.interface.Interface`, which is an ancestor interface for
+all interfaces, much as `object` is an ancestor of all new-style
+classes [#create]_.   The interface is not a class, it's an Interface,
+an instance of `InterfaceClass`::
+
+  >>> type(IFoo)
+  <class 'zope.interface.interface.InterfaceClass'>
+
+We can ask for the interface's documentation::
+
+  >>> IFoo.__doc__
+  'Foo blah blah'
+
+and its name::
+
+  >>> IFoo.__name__
+  'IFoo'
+
+and even its module::
+
+  >>> IFoo.__module__
+  '__main__'
+
+The interface defined two attributes:
+
+`x`
+  This is the simplest form of attribute definition.  It has a name
+  and a doc string.  It doesn't formally specify anything else.
+
+`bar`
+  This is a method.  A method is defined via a function definition.  A
+  method is simply an attribute constrained to be a callable with a
+  particular signature, as provided by the function definition.
+
+  Note that `bar` doesn't take a `self` argument.  Interfaces document
+  how an object is *used*.  When calling instance methods, you don't
+  pass a `self` argument, so a `self` argument isn't included in the
+  interface signature.  The `self` argument in instance methods is
+  really an implementation detail of Python instances. Other objects,
+  besides instances can provide interfaces and their methods might not
+  be instance methods. For example, modules can provide interfaces and
+  their methods are usually just functions.  Even instances can have
+  methods that are not instance methods.
+
+You can access the attributes defined by an interface using mapping
+syntax::
+
+  >>> x = IFoo['x']
+  >>> type(x)
+  <class 'zope.interface.interface.Attribute'>
+  >>> x.__name__
+  'x'
+  >>> x.__doc__
+  'X blah blah'
+
+  >>> IFoo.get('x').__name__
+  'x'
+
+  >>> IFoo.get('y')
+
+You can use `in` to determine if an interface defines a name::
+
+  >>> 'x' in IFoo
+  True
+
+You can iterate over interfaces to get the names they define::
+
+  >>> names = list(IFoo)
+  >>> names.sort()
+  >>> names
+  ['bar', 'x']
+
+Remember that interfaces aren't classes. You can't access attribute
+definitions as attributes of interfaces::
+
+  >>> IFoo.x
+  Traceback (most recent call last):
+    File "<stdin>", line 1, in ?
+  AttributeError: 'InterfaceClass' object has no attribute 'x'
+
+Methods provide access to the method signature::
+
+  >>> bar = IFoo['bar']
+  >>> bar.getSignatureString()
+  '(q, r=None)'
+
+TODO
+  Methods really should have a better API.  This is something that
+  needs to be improved.
+
+Declaring interfaces
+====================
+
+Having defined interfaces, we can *declare* that objects provide
+them.  Before we describe the details, lets define some terms:
+
+*provide*
+   We say that objects *provide* interfaces.  If an object provides an
+   interface, then the interface specifies the behavior of the
+   object. In other words, interfaces specify the behavior of the
+   objects that provide them.
+
+*implement*
+   We normally say that classes *implement* interfaces.  If a class
+   implements an interface, then the instances of the class provide
+   the interface.  Objects provide interfaces that their classes
+   implement [#factory]_.  (Objects can provide interfaces directly,
+   in addition to what their classes implement.)
+
+   It is important to note that classes don't usually provide the
+   interfaces that they implement.
+
+   We can generalize this to factories.  For any callable object we
+   can declare that it produces objects that provide some interfaces
+   by saying that the factory implements the interfaces.
+
+Now that we've defined these terms, we can talk about the API for
+declaring interfaces.
+
+Declaring implemented interfaces
+--------------------------------
+
+The most common way to declare interfaces is using the implements
+function in a class statement::
+
+  >>> class Foo:
+  ...     zope.interface.implements(IFoo)
+  ...
+  ...     def __init__(self, x=None):
+  ...         self.x = x
+  ...
+  ...     def bar(self, q, r=None):
+  ...         return q, r, self.x
+  ...
+  ...     def __repr__(self):
+  ...         return "Foo(%s)" % self.x
+
+
+In this example, we declared that `Foo` implements `IFoo`. This means
+that instances of `Foo` provide `IFoo`.  Having made this declaration,
+there are several ways we can introspect the declarations.  First, we
+can ask an interface whether it is implemented by a class::
+
+  >>> IFoo.implementedBy(Foo)
+  True
+
+And we can ask whether an interface is provided by an object::
+
+  >>> foo = Foo()
+  >>> IFoo.providedBy(foo)
+  True
+
+Of course, `Foo` doesn't provide `IFoo`, it implements it::
+
+  >>> IFoo.providedBy(Foo)
+  False
+
+We can also ask what interfaces are implemented by an object::
+
+  >>> list(zope.interface.implementedBy(Foo))
+  [<InterfaceClass __main__.IFoo>]
+
+It's an error to ask for interfaces implemented by a non-callable
+object::
+
+  >>> IFoo.implementedBy(foo)
+  Traceback (most recent call last):
+  ...
+  TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+  >>> list(zope.interface.implementedBy(foo))
+  Traceback (most recent call last):
+  ...
+  TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+Similarly, we can ask what interfaces are provided by an object::
+
+  >>> list(zope.interface.providedBy(foo))
+  [<InterfaceClass __main__.IFoo>]
+  >>> list(zope.interface.providedBy(Foo))
+  []
+
+We can declare interfaces implemented by other factories (besides
+classes).  We do this using a Python-2.4-style decorator named
+`implementer`.  In versions of Python before 2.4, this looks like::
+
+  >>> def yfoo(y):
+  ...     foo = Foo()
+  ...     foo.y = y
+  ...     return foo
+  >>> yfoo = zope.interface.implementer(IFoo)(yfoo)
+
+  >>> list(zope.interface.implementedBy(yfoo))
+  [<InterfaceClass __main__.IFoo>]
+
+Note that the implementer decorator may modify it's argument. Callers
+should not assume that a new object is created.
+
+Using implementer also works on callable objects. This is used by
+zope.formlib, as an example.
+
+  >>> class yfactory:
+  ...     def __call__(self, y):
+  ...         foo = Foo()
+  ...         foo.y = y
+  ...         return foo
+  >>> yfoo = yfactory()
+  >>> yfoo = zope.interface.implementer(IFoo)(yfoo)
+
+  >>> list(zope.interface.implementedBy(yfoo))
+  [<InterfaceClass __main__.IFoo>]
+
+XXX: Double check and update these version numbers:
+
+In zope.interface 3.5.2 and lower, the implementor decorator can not
+be used for classes, but in 3.6.0 and higher it can:
+
+  >>> Foo = zope.interface.implementer(IFoo)(Foo)
+  >>> list(zope.interface.providedBy(Foo()))
+  [<InterfaceClass __main__.IFoo>]
+  
+Note that class decorators using the @implementor(IFoo) syntax are only 
+supported in Python 2.6 and later.
+
+
+Declaring provided interfaces
+-----------------------------
+
+We can declare interfaces directly provided by objects.  Suppose that
+we want to document what the `__init__` method of the `Foo` class
+does.  It's not *really* part of `IFoo`.  You wouldn't normally call
+the `__init__` method on Foo instances.  Rather, the `__init__` method
+is part of the `Foo`'s `__call__` method::
+
+  >>> class IFooFactory(zope.interface.Interface):
+  ...     """Create foos"""
+  ...
+  ...     def __call__(x=None):
+  ...         """Create a foo
+  ...
+  ...         The argument provides the initial value for x ...
+  ...         """
+
+It's the class that provides this interface, so we declare the
+interface on the class::
+
+  >>> zope.interface.directlyProvides(Foo, IFooFactory)
+
+And then, we'll see that Foo provides some interfaces::
+
+  >>> list(zope.interface.providedBy(Foo))
+  [<InterfaceClass __main__.IFooFactory>]
+  >>> IFooFactory.providedBy(Foo)
+  True
+
+Declaring class interfaces is common enough that there's a special
+declaration function for it, `classProvides`, that allows the
+declaration from within a class statement::
+
+  >>> class Foo2:
+  ...     zope.interface.implements(IFoo)
+  ...     zope.interface.classProvides(IFooFactory)
+  ...
+  ...     def __init__(self, x=None):
+  ...         self.x = x
+  ...
+  ...     def bar(self, q, r=None):
+  ...         return q, r, self.x
+  ...
+  ...     def __repr__(self):
+  ...         return "Foo(%s)" % self.x
+
+  >>> list(zope.interface.providedBy(Foo2))
+  [<InterfaceClass __main__.IFooFactory>]
+  >>> IFooFactory.providedBy(Foo2)
+  True
+
+There's a similar function, `moduleProvides`, that supports interface
+declarations from within module definitions.  For example, see the use
+of `moduleProvides` call in `zope.interface.__init__`, which declares that
+the package `zope.interface` provides `IInterfaceDeclaration`.
+
+Sometimes, we want to declare interfaces on instances, even though
+those instances get interfaces from their classes.  Suppose we create
+a new interface, `ISpecial`::
+
+  >>> class ISpecial(zope.interface.Interface):
+  ...     reason = zope.interface.Attribute("Reason why we're special")
+  ...     def brag():
+  ...         "Brag about being special"
+
+We can make an existing foo instance special by providing `reason`
+and `brag` attributes::
+
+  >>> foo.reason = 'I just am'
+  >>> def brag():
+  ...      return "I'm special!"
+  >>> foo.brag = brag
+  >>> foo.reason
+  'I just am'
+  >>> foo.brag()
+  "I'm special!"
+
+and by declaring the interface::
+
+  >>> zope.interface.directlyProvides(foo, ISpecial)
+
+then the new interface is included in the provided interfaces::
+
+  >>> ISpecial.providedBy(foo)
+  True
+  >>> list(zope.interface.providedBy(foo))
+  [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+We can find out what interfaces are directly provided by an object::
+
+  >>> list(zope.interface.directlyProvidedBy(foo))
+  [<InterfaceClass __main__.ISpecial>]
+
+  >>> newfoo = Foo()
+  >>> list(zope.interface.directlyProvidedBy(newfoo))
+  []
+
+Inherited declarations
+----------------------
+
+Normally, declarations are inherited::
+
+  >>> class SpecialFoo(Foo):
+  ...     zope.interface.implements(ISpecial)
+  ...     reason = 'I just am'
+  ...     def brag(self):
+  ...         return "I'm special because %s" % self.reason
+
+  >>> list(zope.interface.implementedBy(SpecialFoo))
+  [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+  >>> list(zope.interface.providedBy(SpecialFoo()))
+  [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+Sometimes, you don't want to inherit declarations.  In that case, you
+can use `implementsOnly`, instead of `implements`::
+
+  >>> class Special(Foo):
+  ...     zope.interface.implementsOnly(ISpecial)
+  ...     reason = 'I just am'
+  ...     def brag(self):
+  ...         return "I'm special because %s" % self.reason
+
+  >>> list(zope.interface.implementedBy(Special))
+  [<InterfaceClass __main__.ISpecial>]
+
+  >>> list(zope.interface.providedBy(Special()))
+  [<InterfaceClass __main__.ISpecial>]
+
+External declarations
+---------------------
+
+Normally, we make implementation declarations as part of a class
+definition. Sometimes, we may want to make declarations from outside
+the class definition. For example, we might want to declare interfaces
+for classes that we didn't write.  The function `classImplements` can
+be used for this purpose::
+
+  >>> class C:
+  ...     pass
+
+  >>> zope.interface.classImplements(C, IFoo)
+  >>> list(zope.interface.implementedBy(C))
+  [<InterfaceClass __main__.IFoo>]
+
+We can use `classImplementsOnly` to exclude inherited interfaces::
+
+  >>> class C(Foo):
+  ...     pass
+
+  >>> zope.interface.classImplementsOnly(C, ISpecial)
+  >>> list(zope.interface.implementedBy(C))
+  [<InterfaceClass __main__.ISpecial>]
+
+
+
+Declaration Objects
+-------------------
+
+When we declare interfaces, we create *declaration* objects.  When we
+query declarations, declaration objects are returned::
+
+  >>> type(zope.interface.implementedBy(Special))
+  <class 'zope.interface.declarations.Implements'>
+
+Declaration objects and interface objects are similar in many ways. In
+fact, they share a common base class.  The important thing to realize
+about them is that they can be used where interfaces are expected in
+declarations. Here's a silly example::
+
+  >>> class Special2(Foo):
+  ...     zope.interface.implementsOnly(
+  ...          zope.interface.implementedBy(Foo),
+  ...          ISpecial,
+  ...          )
+  ...     reason = 'I just am'
+  ...     def brag(self):
+  ...         return "I'm special because %s" % self.reason
+
+The declaration here is almost the same as
+``zope.interface.implements(ISpecial)``, except that the order of
+interfaces in the resulting declaration is different::
+
+  >>> list(zope.interface.implementedBy(Special2))
+  [<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.ISpecial>]
+
+
+Interface Inheritance
+=====================
+
+Interfaces can extend other interfaces. They do this simply by listing
+the other interfaces as base interfaces::
+
+  >>> class IBlat(zope.interface.Interface):
+  ...     """Blat blah blah"""
+  ...
+  ...     y = zope.interface.Attribute("y blah blah")
+  ...     def eek():
+  ...         """eek blah blah"""
+
+  >>> IBlat.__bases__
+  (<InterfaceClass zope.interface.Interface>,)
+
+  >>> class IBaz(IFoo, IBlat):
+  ...     """Baz blah"""
+  ...     def eek(a=1):
+  ...         """eek in baz blah"""
+  ...
+
+  >>> IBaz.__bases__
+  (<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.IBlat>)
+
+  >>> names = list(IBaz)
+  >>> names.sort()
+  >>> names
+  ['bar', 'eek', 'x', 'y']
+
+Note that `IBaz` overrides eek::
+
+  >>> IBlat['eek'].__doc__
+  'eek blah blah'
+  >>> IBaz['eek'].__doc__
+  'eek in baz blah'
+
+We were careful to override eek in a compatible way.  When extending
+an interface, the extending interface should be compatible [#compat]_
+with the extended interfaces.
+
+We can ask whether one interface extends another::
+
+  >>> IBaz.extends(IFoo)
+  True
+  >>> IBlat.extends(IFoo)
+  False
+
+Note that interfaces don't extend themselves::
+
+  >>> IBaz.extends(IBaz)
+  False
+
+Sometimes we wish they did, but we can, instead use `isOrExtends`::
+
+  >>> IBaz.isOrExtends(IBaz)
+  True
+  >>> IBaz.isOrExtends(IFoo)
+  True
+  >>> IFoo.isOrExtends(IBaz)
+  False
+
+When we iterate over an interface, we get all of the names it defines,
+including names defined by base interfaces. Sometimes, we want *just*
+the names defined by the interface directly. We bane use the `names`
+method for that::
+
+  >>> list(IBaz.names())
+  ['eek']
+
+Inheritance of attribute specifications
+---------------------------------------
+
+An interface may override attribute definitions from base interfaces.
+If two base interfaces define the same attribute, the attribute is
+inherited from the most specific interface. For example, with::
+
+  >>> class IBase(zope.interface.Interface):
+  ...
+  ...     def foo():
+  ...         "base foo doc"
+
+  >>> class IBase1(IBase):
+  ...     pass
+
+  >>> class IBase2(IBase):
+  ...
+  ...     def foo():
+  ...         "base2 foo doc"
+
+  >>> class ISub(IBase1, IBase2):
+  ...     pass
+
+ISub's definition of foo is the one from IBase2, since IBase2 is more
+specific that IBase::
+
+  >>> ISub['foo'].__doc__
+  'base2 foo doc'
+
+Note that this differs from a depth-first search.
+
+Sometimes, it's useful to ask whether an interface defines an
+attribute directly.  You can use the direct method to get a directly
+defined definitions::
+
+  >>> IBase.direct('foo').__doc__
+  'base foo doc'
+
+  >>> ISub.direct('foo')
+
+Specifications
+--------------
+
+Interfaces and declarations are both special cases of specifications.
+What we described above for interface inheritance applies to both
+declarations and specifications.  Declarations actually extend the
+interfaces that they declare::
+
+  >>> class Baz(object):
+  ...     zope.interface.implements(IBaz)
+
+  >>> baz_implements = zope.interface.implementedBy(Baz)
+  >>> baz_implements.__bases__
+  (<InterfaceClass __main__.IBaz>, <implementedBy ...object>)
+
+  >>> baz_implements.extends(IFoo)
+  True
+
+  >>> baz_implements.isOrExtends(IFoo)
+  True
+  >>> baz_implements.isOrExtends(baz_implements)
+  True
+
+Specifications (interfaces and declarations) provide an `__sro__`
+that lists the specification and all of it's ancestors::
+
+  >>> baz_implements.__sro__
+  (<implementedBy __main__.Baz>,
+   <InterfaceClass __main__.IBaz>,
+   <InterfaceClass __main__.IFoo>,
+   <InterfaceClass __main__.IBlat>,
+   <InterfaceClass zope.interface.Interface>,
+   <implementedBy ...object>)
+
+
+Tagged Values
+=============
+
+Interfaces and attribute descriptions support an extension mechanism,
+borrowed from UML, called "tagged values" that lets us store extra
+data::
+
+  >>> IFoo.setTaggedValue('date-modified', '2004-04-01')
+  >>> IFoo.setTaggedValue('author', 'Jim Fulton')
+  >>> IFoo.getTaggedValue('date-modified')
+  '2004-04-01'
+  >>> IFoo.queryTaggedValue('date-modified')
+  '2004-04-01'
+  >>> IFoo.queryTaggedValue('datemodified')
+  >>> tags = list(IFoo.getTaggedValueTags())
+  >>> tags.sort()
+  >>> tags
+  ['author', 'date-modified']
+
+Function attributes are converted to tagged values when method
+attribute definitions are created::
+
+  >>> class IBazFactory(zope.interface.Interface):
+  ...     def __call__():
+  ...         "create one"
+  ...     __call__.return_type = IBaz
+
+  >>> IBazFactory['__call__'].getTaggedValue('return_type')
+  <InterfaceClass __main__.IBaz>
+
+Tagged values can also be defined from within an interface definition::
+
+  >>> class IWithTaggedValues(zope.interface.Interface):
+  ...     zope.interface.taggedValue('squish', 'squash')
+  >>> IWithTaggedValues.getTaggedValue('squish')
+  'squash'
+
+Invariants
+==========
+
+Interfaces can express conditions that must hold for objects that
+provide them. These conditions are expressed using one or more
+invariants.  Invariants are callable objects that will be called with
+an object that provides an interface. An invariant raises an `Invalid`
+exception if the condition doesn't hold.  Here's an example::
+
+  >>> class RangeError(zope.interface.Invalid):
+  ...     """A range has invalid limits"""
+  ...     def __repr__(self):
+  ...         return "RangeError(%r)" % self.args
+
+  >>> def range_invariant(ob):
+  ...     if ob.max < ob.min:
+  ...         raise RangeError(ob)
+
+Given this invariant, we can use it in an interface definition::
+
+  >>> class IRange(zope.interface.Interface):
+  ...     min = zope.interface.Attribute("Lower bound")
+  ...     max = zope.interface.Attribute("Upper bound")
+  ...
+  ...     zope.interface.invariant(range_invariant)
+
+Interfaces have a method for checking their invariants::
+
+  >>> class Range(object):
+  ...     zope.interface.implements(IRange)
+  ...
+  ...     def __init__(self, min, max):
+  ...         self.min, self.max = min, max
+  ...
+  ...     def __repr__(self):
+  ...         return "Range(%s, %s)" % (self.min, self.max)
+
+  >>> IRange.validateInvariants(Range(1,2))
+  >>> IRange.validateInvariants(Range(1,1))
+  >>> IRange.validateInvariants(Range(2,1))
+  Traceback (most recent call last):
+  ...
+  RangeError: Range(2, 1)
+
+If you have multiple invariants, you may not want to stop checking
+after the first error.  If you pass a list to `validateInvariants`,
+then a single `Invalid` exception will be raised with the list of
+exceptions as it's argument::
+
+  >>> from zope.interface.exceptions import Invalid
+  >>> errors = []
+  >>> try:
+  ...     IRange.validateInvariants(Range(2,1), errors)
+  ... except Invalid, e:
+  ...     str(e)
+  '[RangeError(Range(2, 1))]'
+  
+And the list will be filled with the individual exceptions::
+
+  >>> errors
+  [RangeError(Range(2, 1))]
+
+
+  >>> del errors[:]
+
+Adaptation
+==========
+
+Interfaces can be called to perform adaptation.
+
+The semantics are based on those of the PEP 246 adapt function.
+
+If an object cannot be adapted, then a TypeError is raised::
+
+  >>> class I(zope.interface.Interface):
+  ...     pass
+
+  >>> I(0)
+  Traceback (most recent call last):
+  ...
+  TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>)
+
+
+
+unless an alternate value is provided as a second positional argument::
+
+  >>> I(0, 'bob')
+  'bob'
+
+If an object already implements the interface, then it will be returned::
+
+  >>> class C(object):
+  ...     zope.interface.implements(I)
+
+  >>> obj = C()
+  >>> I(obj) is obj
+  True
+
+If an object implements __conform__, then it will be used::
+
+  >>> class C(object):
+  ...     zope.interface.implements(I)
+  ...     def __conform__(self, proto):
+  ...          return 0
+
+  >>> I(C())
+  0
+
+Adapter hooks (see __adapt__) will also be used, if present::
+
+  >>> from zope.interface.interface import adapter_hooks
+  >>> def adapt_0_to_42(iface, obj):
+  ...     if obj == 0:
+  ...         return 42
+
+  >>> adapter_hooks.append(adapt_0_to_42)
+  >>> I(0)
+  42
+
+  >>> adapter_hooks.remove(adapt_0_to_42)
+  >>> I(0)
+  Traceback (most recent call last):
+  ...
+  TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>)
+
+__adapt__
+---------
+
+  >>> class I(zope.interface.Interface):
+  ...     pass
+
+Interfaces implement the PEP 246 __adapt__ method.
+
+This method is normally not called directly. It is called by the PEP
+246 adapt framework and by the interface __call__ operator.
+
+The adapt method is responsible for adapting an object to the
+reciever.
+
+The default version returns None::
+
+  >>> I.__adapt__(0)
+
+unless the object given provides the interface::
+
+  >>> class C(object):
+  ...     zope.interface.implements(I)
+
+  >>> obj = C()
+  >>> I.__adapt__(obj) is obj
+  True
+
+Adapter hooks can be provided (or removed) to provide custom
+adaptation. We'll install a silly hook that adapts 0 to 42.
+We install a hook by simply adding it to the adapter_hooks
+list::
+
+  >>> from zope.interface.interface import adapter_hooks
+  >>> def adapt_0_to_42(iface, obj):
+  ...     if obj == 0:
+  ...         return 42
+
+  >>> adapter_hooks.append(adapt_0_to_42)
+  >>> I.__adapt__(0)
+  42
+
+Hooks must either return an adapter, or None if no adapter can
+be found.
+
+Hooks can be uninstalled by removing them from the list::
+
+  >>> adapter_hooks.remove(adapt_0_to_42)
+  >>> I.__adapt__(0)
+
+
+.. [#create] The main reason we subclass `Interface` is to cause the
+             Python class statement to create an interface, rather
+             than a class.
+
+             It's possible to create interfaces by calling a special
+             interface class directly.  Doing this, it's possible
+             (and, on rare occasions, useful) to create interfaces
+             that don't descend from `Interface`.  Using this
+             technique is beyond the scope of this document.
+
+.. [#factory] Classes are factories.  They can be called to create
+              their instances.  We expect that we will eventually
+              extend the concept of implementation to other kinds of
+              factories, so that we can declare the interfaces
+              provided by the objects created.
+
+.. [#compat] The goal is substitutability.  An object that provides an
+             extending interface should be substitutable for an object
+             that provides the extended interface.  In our example, an
+             object that provides IBaz should be usable whereever an
+             object that provides IBlat is expected.
+
+             The interface implementation doesn't enforce this.
+             but maybe it should do some checks.
diff --git a/src/zope/interface/__init__.py b/src/zope/interface/__init__.py
new file mode 100644 (file)
index 0000000..8b05f6b
--- /dev/null
@@ -0,0 +1,79 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Interfaces
+
+This package implements the Python "scarecrow" proposal.
+
+The package exports two objects, `Interface` and `Attribute` directly. It also
+exports several helper methods. Interface is used to create an interface with
+a class statement, as in:
+
+  class IMyInterface(Interface):
+    '''Interface documentation
+    '''
+
+    def meth(arg1, arg2):
+        '''Documentation for meth
+        '''
+
+    # Note that there is no self argument
+
+To find out what you can do with interfaces, see the interface
+interface, `IInterface` in the `interfaces` module.
+
+The package has several public modules:
+
+  o `declarations` provides utilities to declare interfaces on objects. It
+    also provides a wide range of helpful utilities that aid in managing
+    declared interfaces. Most of its public names are however imported here.
+
+  o `document` has a utility for documenting an interface as structured text.
+
+  o `exceptions` has the interface-defined exceptions
+
+  o `interfaces` contains a list of all public interfaces for this package.
+
+  o `verify` has utilities for verifying implementations of interfaces.
+
+See the module doc strings for more information.
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.interface.interface import Interface, _wire
+
+# Need to actually get the interface elements to implement the right interfaces
+_wire()
+del _wire
+
+from zope.interface.interface import Attribute, invariant, taggedValue
+
+from zope.interface.declarations import providedBy, implementedBy
+from zope.interface.declarations import classImplements, classImplementsOnly
+from zope.interface.declarations import directlyProvidedBy, directlyProvides
+from zope.interface.declarations import alsoProvides, provider
+from zope.interface.declarations import implementer, implementer_only
+from zope.interface.declarations import implements, implementsOnly
+from zope.interface.declarations import classProvides, moduleProvides
+from zope.interface.declarations import noLongerProvides, Declaration
+from zope.interface.exceptions import Invalid
+
+# The following are to make spec pickles cleaner
+from zope.interface.declarations import Provides
+
+
+from zope.interface.interfaces import IInterfaceDeclaration
+
+moduleProvides(IInterfaceDeclaration)
+
+__all__ = ('Interface', 'Attribute') + tuple(IInterfaceDeclaration)
diff --git a/src/zope/interface/_flatten.py b/src/zope/interface/_flatten.py
new file mode 100644 (file)
index 0000000..a80c2de
--- /dev/null
@@ -0,0 +1,35 @@
+##############################################################################
+#
+# Copyright (c) 2002 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.
+#
+##############################################################################
+"""Adapter-style interface registry
+
+See Adapter class.
+"""
+from zope.interface import Declaration
+
+def _flatten(implements, include_None=0):
+
+    try:
+        r = implements.flattened()
+    except AttributeError:
+        if implements is None:
+            r=()
+        else:
+            r = Declaration(implements).flattened()
+
+    if not include_None:
+        return r
+
+    r = list(r)
+    r.append(None)
+    return r
diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c
new file mode 100644 (file)
index 0000000..7b0f816
--- /dev/null
@@ -0,0 +1,1682 @@
+/*###########################################################################
+ #
+ # Copyright (c) 2003 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.
+ #
+ ############################################################################*/
+
+#include "Python.h"
+#include "structmember.h"
+
+#define TYPE(O) ((PyTypeObject*)(O))
+#define OBJECT(O) ((PyObject*)(O))
+#define CLASSIC(O) ((PyClassObject*)(O))
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(a, b) PyObject_HEAD_INIT(a) b,
+#endif
+#ifndef Py_TYPE
+#define Py_TYPE(o) ((o)->ob_type)
+#endif
+
+static PyObject *str__dict__, *str__implemented__, *strextends;
+static PyObject *BuiltinImplementationSpecifications, *str__provides__;
+static PyObject *str__class__, *str__providedBy__;
+static PyObject *empty, *fallback, *str_implied, *str_cls, *str_implements;
+static PyObject *str__conform__, *str_call_conform, *adapter_hooks;
+static PyObject *str_uncached_lookup, *str_uncached_lookupAll;
+static PyObject *str_uncached_subscriptions;
+static PyObject *str_registry, *strro, *str_generation, *strchanged;
+
+static PyTypeObject *Implements;
+
+static int imported_declarations = 0;
+
+static int 
+import_declarations(void)
+{
+  PyObject *declarations, *i;
+
+  declarations = PyImport_ImportModule("zope.interface.declarations");
+  if (declarations == NULL)
+    return -1;
+  
+  BuiltinImplementationSpecifications = PyObject_GetAttrString(
+                    declarations, "BuiltinImplementationSpecifications");
+  if (BuiltinImplementationSpecifications == NULL)
+    return -1;
+
+  empty = PyObject_GetAttrString(declarations, "_empty");
+  if (empty == NULL)
+    return -1;
+
+  fallback = PyObject_GetAttrString(declarations, "implementedByFallback");
+  if (fallback == NULL)
+    return -1;
+
+
+
+  i = PyObject_GetAttrString(declarations, "Implements");
+  if (i == NULL)
+    return -1;
+
+  if (! PyType_Check(i))
+    {
+      PyErr_SetString(PyExc_TypeError, 
+                      "zope.interface.declarations.Implements is not a type");
+      return -1;
+    }
+
+  Implements = (PyTypeObject *)i;
+
+  Py_DECREF(declarations);
+
+  imported_declarations = 1;
+  return 0;
+}
+
+static PyTypeObject SpecType;   /* Forward */
+
+static PyObject *
+implementedByFallback(PyObject *cls)
+{
+  if (imported_declarations == 0 && import_declarations() < 0)
+    return NULL;
+
+  return PyObject_CallFunctionObjArgs(fallback, cls, NULL);
+}
+
+static PyObject *
+implementedBy(PyObject *ignored, PyObject *cls)
+{
+  /* Fast retrieval of implements spec, if possible, to optimize
+     common case.  Use fallback code if we get stuck.
+  */
+
+  PyObject *dict = NULL, *spec;
+
+  if (PyType_Check(cls))
+    {
+      dict = TYPE(cls)->tp_dict;
+      Py_XINCREF(dict);
+    }
+
+  if (dict == NULL)
+    dict = PyObject_GetAttr(cls, str__dict__);
+
+  if (dict == NULL)
+    {
+      /* Probably a security proxied class, use more expensive fallback code */
+      PyErr_Clear();
+      return implementedByFallback(cls);
+    }
+
+  spec = PyObject_GetItem(dict, str__implemented__);
+  Py_DECREF(dict);
+  if (spec)
+    {
+      if (imported_declarations == 0 && import_declarations() < 0)
+        return NULL;
+
+      if (PyObject_TypeCheck(spec, Implements))
+        return spec;
+
+      /* Old-style declaration, use more expensive fallback code */
+      Py_DECREF(spec);
+      return implementedByFallback(cls);
+    }
+
+  PyErr_Clear();
+
+  /* Maybe we have a builtin */
+  if (imported_declarations == 0 && import_declarations() < 0)
+    return NULL;
+  
+  spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls);
+  if (spec != NULL)
+    {
+      Py_INCREF(spec);
+      return spec;
+    }
+
+  /* We're stuck, use fallback */
+  return implementedByFallback(cls);
+}
+
+static PyObject *
+getObjectSpecification(PyObject *ignored, PyObject *ob)
+{
+  PyObject *cls, *result;
+
+  result = PyObject_GetAttr(ob, str__provides__);
+  if (result != NULL && PyObject_TypeCheck(result, &SpecType))
+    return result;
+
+  PyErr_Clear();
+
+  /* We do a getattr here so as not to be defeated by proxies */
+  cls = PyObject_GetAttr(ob, str__class__);
+  if (cls == NULL)
+    {
+      PyErr_Clear();
+      if (imported_declarations == 0 && import_declarations() < 0)
+        return NULL;
+      Py_INCREF(empty);
+      return empty;
+    }
+
+  result = implementedBy(NULL, cls);
+  Py_DECREF(cls);
+
+  return result;
+}
+
+static PyObject *
+providedBy(PyObject *ignored, PyObject *ob)
+{
+  PyObject *result, *cls, *cp;
+  
+  result = PyObject_GetAttr(ob, str__providedBy__);
+  if (result == NULL)
+    {
+      PyErr_Clear();
+      return getObjectSpecification(NULL, ob);
+    } 
+
+
+  /* We want to make sure we have a spec. We can't do a type check
+     because we may have a proxy, so we'll just try to get the
+     only attribute.
+  */
+  if (PyObject_TypeCheck(result, &SpecType)
+      || 
+      PyObject_HasAttr(result, strextends)
+      )
+    return result;
+    
+  /*
+    The object's class doesn't understand descriptors.
+    Sigh. We need to get an object descriptor, but we have to be
+    careful.  We want to use the instance's __provides__,l if
+    there is one, but only if it didn't come from the class.
+  */
+  Py_DECREF(result);
+
+  cls = PyObject_GetAttr(ob, str__class__);
+  if (cls == NULL)
+    return NULL;
+
+  result = PyObject_GetAttr(ob, str__provides__);
+  if (result == NULL)
+    {      
+      /* No __provides__, so just fall back to implementedBy */
+      PyErr_Clear();
+      result = implementedBy(NULL, cls);
+      Py_DECREF(cls);
+      return result;
+    } 
+
+  cp = PyObject_GetAttr(cls, str__provides__);
+  if (cp == NULL)
+    {
+      /* The the class has no provides, assume we're done: */
+      PyErr_Clear();
+      Py_DECREF(cls);
+      return result;
+    }
+
+  if (cp == result)
+    {
+      /*
+        Oops, we got the provides from the class. This means
+        the object doesn't have it's own. We should use implementedBy
+      */
+      Py_DECREF(result);
+      result = implementedBy(NULL, cls);
+    }
+
+  Py_DECREF(cls);
+  Py_DECREF(cp);
+
+  return result;
+}
+
+/* 
+   Get an attribute from an inst dict. Return a borrowed reference.
+  
+   This has a number of advantages:
+
+   - It avoids layers of Python api
+
+   - It doesn't waste time looking for descriptors
+
+   - It fails wo raising an exception, although that shouldn't really
+     matter.
+
+*/
+static PyObject *
+inst_attr(PyObject *self, PyObject *name)
+{
+  PyObject **dictp, *v;
+
+  dictp = _PyObject_GetDictPtr(self);
+  if (dictp && *dictp && (v = PyDict_GetItem(*dictp, name)))
+    return v;
+  PyErr_SetObject(PyExc_AttributeError, name);
+  return NULL;
+}
+
+
+static PyObject *
+Spec_extends(PyObject *self, PyObject *other)
+{  
+  PyObject *implied;
+
+  implied = inst_attr(self, str_implied);
+  if (implied == NULL)
+    return NULL;
+
+#ifdef Py_True
+  if (PyDict_GetItem(implied, other) != NULL)
+    {
+      Py_INCREF(Py_True);
+      return Py_True;
+    }
+  Py_INCREF(Py_False);
+  return Py_False;
+#else
+  return PyInt_FromLong(PyDict_GetItem(implied, other) != NULL);
+#endif
+}
+
+static char Spec_extends__doc__[] = 
+"Test whether a specification is or extends another"
+;
+
+static char Spec_providedBy__doc__[] = 
+"Test whether an interface is implemented by the specification"
+;
+
+static PyObject *
+Spec_call(PyObject *self, PyObject *args, PyObject *kw)
+{
+  PyObject *spec;
+
+  if (! PyArg_ParseTuple(args, "O", &spec))
+    return NULL;
+  return Spec_extends(self, spec);
+}
+
+static PyObject *
+Spec_providedBy(PyObject *self, PyObject *ob)
+{
+  PyObject *decl, *item;
+
+  decl = providedBy(NULL, ob);
+  if (decl == NULL)
+    return NULL;
+
+  if (PyObject_TypeCheck(decl, &SpecType))
+    item = Spec_extends(decl, self);
+  else
+    /* decl is probably a security proxy.  We have to go the long way
+       around. 
+    */
+    item = PyObject_CallFunctionObjArgs(decl, self, NULL);
+
+  Py_DECREF(decl);
+  return item;
+}
+
+
+static char Spec_implementedBy__doc__[] = 
+"Test whether the specification is implemented by a class or factory.\n"
+"Raise TypeError if argument is neither a class nor a callable."
+;
+
+static PyObject *
+Spec_implementedBy(PyObject *self, PyObject *cls)
+{
+  PyObject *decl, *item;
+
+  decl = implementedBy(NULL, cls);
+  if (decl == NULL)
+    return NULL;
+  
+  if (PyObject_TypeCheck(decl, &SpecType))
+    item = Spec_extends(decl, self);
+  else
+    item = PyObject_CallFunctionObjArgs(decl, self, NULL);
+
+  Py_DECREF(decl);
+  return item;
+}
+
+static struct PyMethodDef Spec_methods[] = {
+       {"providedBy",  
+         (PyCFunction)Spec_providedBy,         METH_O,
+        Spec_providedBy__doc__},
+       {"implementedBy", 
+         (PyCFunction)Spec_implementedBy,      METH_O,
+        Spec_implementedBy__doc__},
+       {"isOrExtends", (PyCFunction)Spec_extends,      METH_O,
+        Spec_extends__doc__},
+
+       {NULL,          NULL}           /* sentinel */
+};
+
+static PyTypeObject SpecType = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       /* tp_name           */ "_interface_coptimizations."
+                                "SpecificationBase",
+       /* tp_basicsize      */ 0,
+       /* tp_itemsize       */ 0,
+       /* tp_dealloc        */ (destructor)0,
+       /* tp_print          */ (printfunc)0,
+       /* tp_getattr        */ (getattrfunc)0,
+       /* tp_setattr        */ (setattrfunc)0,
+       /* tp_compare        */ 0,
+       /* tp_repr           */ (reprfunc)0,
+       /* tp_as_number      */ 0,
+       /* tp_as_sequence    */ 0,
+       /* tp_as_mapping     */ 0,
+       /* tp_hash           */ (hashfunc)0,
+       /* tp_call           */ (ternaryfunc)Spec_call,
+       /* tp_str            */ (reprfunc)0,
+        /* tp_getattro       */ (getattrofunc)0,
+        /* tp_setattro       */ (setattrofunc)0,
+        /* tp_as_buffer      */ 0,
+        /* tp_flags          */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+        "Base type for Specification objects",
+        /* tp_traverse       */ (traverseproc)0,
+        /* tp_clear          */ (inquiry)0,
+        /* tp_richcompare    */ (richcmpfunc)0,
+        /* tp_weaklistoffset */ (long)0,
+        /* tp_iter           */ (getiterfunc)0,
+        /* tp_iternext       */ (iternextfunc)0,
+        /* tp_methods        */ Spec_methods,
+};
+
+static PyObject *
+OSD_descr_get(PyObject *self, PyObject *inst, PyObject *cls)
+{
+  PyObject *provides;
+
+  if (inst == NULL)
+    return getObjectSpecification(NULL, cls);
+
+  provides = PyObject_GetAttr(inst, str__provides__);
+  if (provides != NULL)
+    return provides;
+  PyErr_Clear();
+  return implementedBy(NULL, cls);
+}
+
+static PyTypeObject OSDType = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       /* tp_name           */ "_interface_coptimizations."
+                                "ObjectSpecificationDescriptor",
+       /* tp_basicsize      */ 0,
+       /* tp_itemsize       */ 0,
+       /* tp_dealloc        */ (destructor)0,
+       /* tp_print          */ (printfunc)0,
+       /* tp_getattr        */ (getattrfunc)0,
+       /* tp_setattr        */ (setattrfunc)0,
+       /* tp_compare        */ 0,
+       /* tp_repr           */ (reprfunc)0,
+       /* tp_as_number      */ 0,
+       /* tp_as_sequence    */ 0,
+       /* tp_as_mapping     */ 0,
+       /* tp_hash           */ (hashfunc)0,
+       /* tp_call           */ (ternaryfunc)0,
+       /* tp_str            */ (reprfunc)0,
+        /* tp_getattro       */ (getattrofunc)0,
+        /* tp_setattro       */ (setattrofunc)0,
+        /* tp_as_buffer      */ 0,
+        /* tp_flags          */ Py_TPFLAGS_DEFAULT
+                               | Py_TPFLAGS_BASETYPE ,
+       "Object Specification Descriptor",
+        /* tp_traverse       */ (traverseproc)0,
+        /* tp_clear          */ (inquiry)0,
+        /* tp_richcompare    */ (richcmpfunc)0,
+        /* tp_weaklistoffset */ (long)0,
+        /* tp_iter           */ (getiterfunc)0,
+        /* tp_iternext       */ (iternextfunc)0,
+        /* tp_methods        */ 0,
+        /* tp_members        */ 0,
+        /* tp_getset         */ 0,
+        /* tp_base           */ 0,
+        /* tp_dict           */ 0, /* internal use */
+        /* tp_descr_get      */ (descrgetfunc)OSD_descr_get,
+};
+
+static PyObject *
+CPB_descr_get(PyObject *self, PyObject *inst, PyObject *cls)
+{
+  PyObject *mycls, *implements;
+
+  mycls = inst_attr(self, str_cls);
+  if (mycls == NULL)
+    return NULL;
+
+  if (cls == mycls)
+    {
+      if (inst == NULL)
+        {
+          Py_INCREF(self);
+          return OBJECT(self);
+        }
+
+      implements = inst_attr(self, str_implements);
+      Py_XINCREF(implements);
+      return implements;
+    }
+  
+  PyErr_SetObject(PyExc_AttributeError, str__provides__);
+  return NULL;
+}
+
+static PyTypeObject CPBType = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       /* tp_name           */ "_interface_coptimizations."
+                                "ClassProvidesBase",
+       /* tp_basicsize      */ 0,
+       /* tp_itemsize       */ 0,
+       /* tp_dealloc        */ (destructor)0,
+       /* tp_print          */ (printfunc)0,
+       /* tp_getattr        */ (getattrfunc)0,
+       /* tp_setattr        */ (setattrfunc)0,
+       /* tp_compare        */ 0,
+       /* tp_repr           */ (reprfunc)0,
+       /* tp_as_number      */ 0,
+       /* tp_as_sequence    */ 0,
+       /* tp_as_mapping     */ 0,
+       /* tp_hash           */ (hashfunc)0,
+       /* tp_call           */ (ternaryfunc)0,
+       /* tp_str            */ (reprfunc)0,
+        /* tp_getattro       */ (getattrofunc)0,
+        /* tp_setattro       */ (setattrofunc)0,
+        /* tp_as_buffer      */ 0,
+        /* tp_flags          */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+        "C Base class for ClassProvides",
+        /* tp_traverse       */ (traverseproc)0,
+        /* tp_clear          */ (inquiry)0,
+        /* tp_richcompare    */ (richcmpfunc)0,
+        /* tp_weaklistoffset */ (long)0,
+        /* tp_iter           */ (getiterfunc)0,
+        /* tp_iternext       */ (iternextfunc)0,
+        /* tp_methods        */ 0,
+        /* tp_members        */ 0,
+        /* tp_getset         */ 0,
+        /* tp_base           */ &SpecType,
+        /* tp_dict           */ 0, /* internal use */
+        /* tp_descr_get      */ (descrgetfunc)CPB_descr_get,
+};
+
+/* ==================================================================== */
+/* ========== Begin: __call__ and __adapt__ =========================== */
+
+/*
+    def __adapt__(self, obj):
+        """Adapt an object to the reciever
+        """
+        if self.providedBy(obj):
+            return obj
+
+        for hook in adapter_hooks:
+            adapter = hook(self, obj)
+            if adapter is not None:
+                return adapter
+
+  
+*/
+static PyObject *
+__adapt__(PyObject *self, PyObject *obj)
+{
+  PyObject *decl, *args, *adapter;
+  int implements, i, l;
+
+  decl = providedBy(NULL, obj);
+  if (decl == NULL)
+    return NULL;
+
+  if (PyObject_TypeCheck(decl, &SpecType))
+    {
+      PyObject *implied;
+
+      implied = inst_attr(decl, str_implied);
+      if (implied == NULL)
+        {
+          Py_DECREF(decl);
+          return NULL;
+        }
+
+      implements = PyDict_GetItem(implied, self) != NULL;
+      Py_DECREF(decl);
+    }
+  else
+    {
+      /* decl is probably a security proxy.  We have to go the long way
+         around. 
+      */
+      PyObject *r;
+      r = PyObject_CallFunctionObjArgs(decl, self, NULL);
+      Py_DECREF(decl);
+      if (r == NULL)
+        return NULL;
+      implements = PyObject_IsTrue(r);
+      Py_DECREF(r);
+    }
+
+  if (implements)
+    {
+      Py_INCREF(obj);
+      return obj;
+    }
+
+  l = PyList_GET_SIZE(adapter_hooks);
+  args = PyTuple_New(2);
+  if (args == NULL)
+    return NULL;
+  Py_INCREF(self);
+  PyTuple_SET_ITEM(args, 0, self);
+  Py_INCREF(obj);
+  PyTuple_SET_ITEM(args, 1, obj);
+  for (i = 0; i < l; i++)
+    {
+      adapter = PyObject_CallObject(PyList_GET_ITEM(adapter_hooks, i), args);
+      if (adapter == NULL || adapter != Py_None)
+        {
+          Py_DECREF(args);
+          return adapter;
+        }
+      Py_DECREF(adapter);
+    }
+
+  Py_DECREF(args);
+
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static struct PyMethodDef ib_methods[] = {
+  {"__adapt__",        (PyCFunction)__adapt__, METH_O,
+   "Adapt an object to the reciever"},
+  {NULL,               NULL}           /* sentinel */
+};
+
+/* 
+        def __call__(self, obj, alternate=_marker):
+            conform = getattr(obj, '__conform__', None)
+            if conform is not None:
+                adapter = self._call_conform(conform)
+                if adapter is not None:
+                    return adapter
+
+            adapter = self.__adapt__(obj)
+
+            if adapter is not None:
+                return adapter
+            elif alternate is not _marker:
+                return alternate
+            else:
+                raise TypeError("Could not adapt", obj, self)
+*/
+static PyObject *
+ib_call(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+  PyObject *conform, *obj, *alternate=NULL, *adapter;
+  
+  static char *kwlist[] = {"obj", "alternate", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist,
+                                   &obj, &alternate))
+    return NULL;
+
+  conform = PyObject_GetAttr(obj, str__conform__);
+  if (conform != NULL)
+    {
+      adapter = PyObject_CallMethodObjArgs(self, str_call_conform,
+                                           conform, NULL);
+      Py_DECREF(conform);
+      if (adapter == NULL || adapter != Py_None)
+        return adapter;
+      Py_DECREF(adapter);
+    }
+  else
+    PyErr_Clear();
+  adapter = __adapt__(self, obj);
+  if (adapter == NULL || adapter != Py_None)
+    return adapter;
+  Py_DECREF(adapter);
+
+  if (alternate != NULL)
+    {
+      Py_INCREF(alternate);
+      return alternate;
+    }
+
+  adapter = Py_BuildValue("sOO", "Could not adapt", obj, self);
+  if (adapter != NULL)
+    {
+      PyErr_SetObject(PyExc_TypeError, adapter);
+      Py_DECREF(adapter);
+    }
+  return NULL;
+}
+
+static PyTypeObject InterfaceBase = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       /* tp_name           */ "_zope_interface_coptimizations."
+                                "InterfaceBase",
+       /* tp_basicsize      */ 0,
+       /* tp_itemsize       */ 0,
+       /* tp_dealloc        */ (destructor)0,
+       /* tp_print          */ (printfunc)0,
+       /* tp_getattr        */ (getattrfunc)0,
+       /* tp_setattr        */ (setattrfunc)0,
+       /* tp_compare        */ 0,
+       /* tp_repr           */ (reprfunc)0,
+       /* tp_as_number      */ 0,
+       /* tp_as_sequence    */ 0,
+       /* tp_as_mapping     */ 0,
+       /* tp_hash           */ (hashfunc)0,
+       /* tp_call           */ (ternaryfunc)ib_call,
+       /* tp_str            */ (reprfunc)0,
+        /* tp_getattro       */ (getattrofunc)0,
+        /* tp_setattro       */ (setattrofunc)0,
+        /* tp_as_buffer      */ 0,
+        /* tp_flags          */ Py_TPFLAGS_DEFAULT
+                               | Py_TPFLAGS_BASETYPE ,
+       /* tp_doc */ "Interface base type providing __call__ and __adapt__",
+        /* tp_traverse       */ (traverseproc)0,
+        /* tp_clear          */ (inquiry)0,
+        /* tp_richcompare    */ (richcmpfunc)0,
+        /* tp_weaklistoffset */ (long)0,
+        /* tp_iter           */ (getiterfunc)0,
+        /* tp_iternext       */ (iternextfunc)0,
+        /* tp_methods        */ ib_methods,
+};
+
+/* =================== End: __call__ and __adapt__ ==================== */
+/* ==================================================================== */
+
+/* ==================================================================== */
+/* ========================== Begin: Lookup Bases ===================== */
+
+typedef struct {
+  PyObject_HEAD
+  PyObject *_cache;
+  PyObject *_mcache;
+  PyObject *_scache;
+} lookup;
+
+typedef struct {
+  PyObject_HEAD
+  PyObject *_cache;
+  PyObject *_mcache;
+  PyObject *_scache;
+  PyObject *_verify_ro;
+  PyObject *_verify_generations;
+} verify;
+
+static int
+lookup_traverse(lookup *self, visitproc visit, void *arg)
+{
+  int vret;
+
+  if (self->_cache) {
+    vret = visit(self->_cache, arg);
+    if (vret != 0)
+      return vret;
+  }
+
+  if (self->_mcache) {
+    vret = visit(self->_mcache, arg);
+    if (vret != 0)
+      return vret;
+  }
+
+  if (self->_scache) {
+    vret = visit(self->_scache, arg);
+    if (vret != 0)
+      return vret;
+  }
+  
+  return 0;
+}
+
+static int
+lookup_clear(lookup *self)
+{
+  Py_CLEAR(self->_cache);
+  Py_CLEAR(self->_mcache);
+  Py_CLEAR(self->_scache);
+  return 0;
+}
+
+static void
+lookup_dealloc(lookup *self)
+{
+  lookup_clear(self);
+  Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+/*
+    def changed(self, ignored=None):
+        self._cache.clear()
+        self._mcache.clear()
+        self._scache.clear()
+*/
+static PyObject *
+lookup_changed(lookup *self, PyObject *ignored)
+{
+  lookup_clear(self);
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+#define ASSURE_DICT(N) if (N == NULL) { N = PyDict_New(); \
+                                        if (N == NULL) return NULL; \
+                                       }
+
+/*  
+    def _getcache(self, provided, name):
+        cache = self._cache.get(provided)
+        if cache is None:
+            cache = {}
+            self._cache[provided] = cache
+        if name:
+            c = cache.get(name)
+            if c is None:
+                c = {}
+                cache[name] = c
+            cache = c
+        return cache
+*/
+static PyObject *
+_subcache(PyObject *cache, PyObject *key)
+{
+  PyObject *subcache;
+
+  subcache = PyDict_GetItem(cache, key);
+  if (subcache == NULL)
+    {
+      int status;
+      subcache = PyDict_New();
+      if (subcache == NULL)
+        return NULL;
+      status = PyDict_SetItem(cache, key, subcache);
+      Py_DECREF(subcache);
+      if (status < 0)
+        return NULL;
+    }
+
+  return subcache;
+}
+static PyObject *
+_getcache(lookup *self, PyObject *provided, PyObject *name)
+{
+  PyObject *cache;
+
+  ASSURE_DICT(self->_cache);
+  cache = _subcache(self->_cache, provided);
+  if (cache == NULL)
+    return NULL;
+
+  if (name != NULL && PyObject_IsTrue(name))
+    cache = _subcache(cache, name);
+
+  return cache;
+}
+
+
+/*  
+    def lookup(self, required, provided, name=u'', default=None):
+        cache = self._getcache(provided, name)
+        if len(required) == 1:
+            result = cache.get(required[0], _not_in_mapping)
+        else:
+            result = cache.get(tuple(required), _not_in_mapping)
+
+        if result is _not_in_mapping:
+            result = self._uncached_lookup(required, provided, name)
+            if len(required) == 1:
+                cache[required[0]] = result
+            else:
+                cache[tuple(required)] = result
+
+        if result is None:
+            return default
+
+        return result
+*/
+static PyObject *
+tuplefy(PyObject *v)
+{
+  if (! PyTuple_Check(v))
+    {
+      v = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), v, NULL);
+      if (v == NULL)
+        return NULL;
+    }
+  else
+    Py_INCREF(v);
+  
+  return v;
+}
+static PyObject *
+_lookup(lookup *self, 
+        PyObject *required, PyObject *provided, PyObject *name, 
+        PyObject *default_)
+{
+  PyObject *result, *key, *cache;
+
+  cache = _getcache(self, provided, name);
+  if (cache == NULL)
+    return NULL;
+
+  required = tuplefy(required);
+  if (required == NULL)
+    return NULL;
+
+  if (PyTuple_GET_SIZE(required) == 1)
+    key = PyTuple_GET_ITEM(required, 0);
+  else
+    key = required;
+
+  result = PyDict_GetItem(cache, key);
+  if (result == NULL)
+    {
+      int status;
+
+      result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookup,
+                                          required, provided, name, NULL);
+      if (result == NULL)
+        {
+          Py_DECREF(required);
+          return NULL;
+        }
+      status = PyDict_SetItem(cache, key, result);
+      Py_DECREF(required);
+      if (status < 0)
+        {
+          Py_DECREF(result);
+          return NULL;
+        }
+    }
+  else
+    {
+      Py_INCREF(result);
+      Py_DECREF(required);
+    }
+
+  if (result == Py_None && default_ != NULL)
+    {
+      Py_DECREF(Py_None);
+      Py_INCREF(default_);
+      return default_;
+    }
+
+  return result;
+}
+static PyObject *
+lookup_lookup(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+  PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &required, &provided, &name, &default_))
+    return NULL; 
+
+  return _lookup(self, required, provided, name, default_);
+}
+
+
+/*  
+    def lookup1(self, required, provided, name=u'', default=None):
+        cache = self._getcache(provided, name)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            return self.lookup((required, ), provided, name, default)
+
+        if result is None:
+            return default
+
+        return result
+*/
+static PyObject *
+_lookup1(lookup *self, 
+        PyObject *required, PyObject *provided, PyObject *name, 
+        PyObject *default_)
+{
+  PyObject *result, *cache;
+
+  cache = _getcache(self, provided, name);
+  if (cache == NULL)
+    return NULL;
+
+  result = PyDict_GetItem(cache, required);
+  if (result == NULL)
+    {
+      PyObject *tup;
+
+      tup = PyTuple_New(1);
+      if (tup == NULL)
+        return NULL;
+      Py_INCREF(required);
+      PyTuple_SET_ITEM(tup, 0, required);
+      result = _lookup(self, tup, provided, name, default_);
+      Py_DECREF(tup);
+    }
+  else
+    Py_INCREF(result);
+
+  return result;
+}
+static PyObject *
+lookup_lookup1(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+  PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &required, &provided, &name, &default_))
+    return NULL; 
+
+  return _lookup1(self, required, provided, name, default_);
+}
+
+/*  
+    def adapter_hook(self, provided, object, name=u'', default=None):
+        required = providedBy(object)
+        cache = self._getcache(provided, name)
+        factory = cache.get(required, _not_in_mapping)
+        if factory is _not_in_mapping:
+            factory = self.lookup((required, ), provided, name)
+
+        if factory is not None:
+            result = factory(object)
+            if result is not None:
+                return result
+
+        return default
+*/
+static PyObject *
+_adapter_hook(lookup *self, 
+              PyObject *provided, PyObject *object,  PyObject *name, 
+              PyObject *default_)
+{
+  PyObject *required, *factory, *result;
+
+  required = providedBy(NULL, object);
+  if (required == NULL)
+    return NULL;
+  
+  factory = _lookup1(self, required, provided, name, Py_None);
+  Py_DECREF(required);
+  if (factory == NULL)
+    return NULL;
+  
+  if (factory != Py_None)
+    {
+      result = PyObject_CallFunctionObjArgs(factory, object, NULL);
+      Py_DECREF(factory);
+      if (result == NULL || result != Py_None)
+        return result;
+    }
+  else
+    result = factory; /* None */
+
+  if (default_ == NULL || default_ == result) /* No default specified, */
+    return result;   /* Return None.  result is owned None */
+
+  Py_DECREF(result);
+  Py_INCREF(default_);
+
+  return default_;
+}
+static PyObject *
+lookup_adapter_hook(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"provided", "object", "name", "default", NULL};
+  PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &provided, &object, &name, &default_))
+    return NULL; 
+
+  return _adapter_hook(self, provided, object, name, default_);
+}
+
+static PyObject *
+lookup_queryAdapter(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"object", "provided", "name", "default", NULL};
+  PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &object, &provided, &name, &default_))
+    return NULL; 
+
+  return _adapter_hook(self, provided, object, name, default_);
+}
+
+/*  
+    def lookupAll(self, required, provided):
+        cache = self._mcache.get(provided)
+        if cache is None:
+            cache = {}
+            self._mcache[provided] = cache
+
+        required = tuple(required)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            result = self._uncached_lookupAll(required, provided)
+            cache[required] = result
+
+        return result
+*/
+static PyObject *
+_lookupAll(lookup *self, PyObject *required, PyObject *provided)
+{
+  PyObject *cache, *result;
+
+  ASSURE_DICT(self->_mcache);
+  cache = _subcache(self->_mcache, provided);
+  if (cache == NULL)
+    return NULL;
+
+  required = tuplefy(required);
+  if (required == NULL)
+    return NULL;
+
+  result = PyDict_GetItem(cache, required);
+  if (result == NULL)
+    {
+      int status;
+
+      result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookupAll,
+                                          required, provided, NULL);
+      if (result == NULL)
+        {
+          Py_DECREF(required);
+          return NULL;
+        }
+      status = PyDict_SetItem(cache, required, result);
+      Py_DECREF(required);
+      if (status < 0)
+        {
+          Py_DECREF(result);
+          return NULL;
+        }
+    }
+  else
+    {
+      Py_INCREF(result);
+      Py_DECREF(required);
+    }
+
+  return result;  
+}
+static PyObject *
+lookup_lookupAll(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", NULL};
+  PyObject *required, *provided;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+                                    &required, &provided))
+    return NULL; 
+
+  return _lookupAll(self, required, provided);
+}
+
+/*  
+    def subscriptions(self, required, provided):
+        cache = self._scache.get(provided)
+        if cache is None:
+            cache = {}
+            self._scache[provided] = cache
+
+        required = tuple(required)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            result = self._uncached_subscriptions(required, provided)
+            cache[required] = result
+
+        return result
+*/
+static PyObject *
+_subscriptions(lookup *self, PyObject *required, PyObject *provided)
+{
+  PyObject *cache, *result;
+
+  ASSURE_DICT(self->_scache);
+  cache = _subcache(self->_scache, provided);
+  if (cache == NULL)
+    return NULL;
+
+  required = tuplefy(required);
+  if (required == NULL)
+    return NULL;
+
+  result = PyDict_GetItem(cache, required);
+  if (result == NULL)
+    {
+      int status;
+
+      result = PyObject_CallMethodObjArgs(
+                                 OBJECT(self), str_uncached_subscriptions,
+                                 required, provided, NULL);
+      if (result == NULL)
+        {
+          Py_DECREF(required);
+          return NULL;
+        }
+      status = PyDict_SetItem(cache, required, result);
+      Py_DECREF(required);
+      if (status < 0)
+        {
+          Py_DECREF(result);
+          return NULL;
+        }
+    }
+  else
+    {
+      Py_INCREF(result);
+      Py_DECREF(required);
+    }
+
+  return result;  
+}
+static PyObject *
+lookup_subscriptions(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", NULL};
+  PyObject *required, *provided;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+                                    &required, &provided))
+    return NULL; 
+
+  return _subscriptions(self, required, provided);
+}
+
+static struct PyMethodDef lookup_methods[] = {
+  {"changed",      (PyCFunction)lookup_changed,       METH_O,        ""},
+  {"lookup",       (PyCFunction)lookup_lookup,        METH_KEYWORDS, ""},
+  {"lookup1",      (PyCFunction)lookup_lookup1,       METH_KEYWORDS, ""},
+  {"queryAdapter",  (PyCFunction)lookup_queryAdapter,  METH_KEYWORDS, ""},
+  {"adapter_hook",  (PyCFunction)lookup_adapter_hook,  METH_KEYWORDS, ""},
+  {"lookupAll",            (PyCFunction)lookup_lookupAll,     METH_KEYWORDS, ""},
+  {"subscriptions", (PyCFunction)lookup_subscriptions, METH_KEYWORDS, ""},
+  {NULL,           NULL}               /* sentinel */
+};
+
+static PyTypeObject LookupBase = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       /* tp_name           */ "_zope_interface_coptimizations."
+                                "LookupBase",
+       /* tp_basicsize      */ sizeof(lookup),
+       /* tp_itemsize       */ 0,
+       /* tp_dealloc        */ (destructor)&lookup_dealloc,
+       /* tp_print          */ (printfunc)0,
+       /* tp_getattr        */ (getattrfunc)0,
+       /* tp_setattr        */ (setattrfunc)0,
+       /* tp_compare        */ 0,
+       /* tp_repr           */ (reprfunc)0,
+       /* tp_as_number      */ 0,
+       /* tp_as_sequence    */ 0,
+       /* tp_as_mapping     */ 0,
+       /* tp_hash           */ (hashfunc)0,
+       /* tp_call           */ (ternaryfunc)0,
+       /* tp_str            */ (reprfunc)0,
+        /* tp_getattro       */ (getattrofunc)0,
+        /* tp_setattro       */ (setattrofunc)0,
+        /* tp_as_buffer      */ 0,
+        /* tp_flags          */ Py_TPFLAGS_DEFAULT
+                               | Py_TPFLAGS_BASETYPE 
+                               | Py_TPFLAGS_HAVE_GC,
+       /* tp_doc            */ "",
+        /* tp_traverse       */ (traverseproc)lookup_traverse,
+        /* tp_clear          */ (inquiry)lookup_clear,
+        /* tp_richcompare    */ (richcmpfunc)0,
+        /* tp_weaklistoffset */ (long)0,
+        /* tp_iter           */ (getiterfunc)0,
+        /* tp_iternext       */ (iternextfunc)0,
+        /* tp_methods        */ lookup_methods,
+};
+
+static int
+verifying_traverse(verify *self, visitproc visit, void *arg)
+{
+  int vret;
+
+  vret = lookup_traverse((lookup *)self, visit, arg);
+  if (vret != 0)
+    return vret;
+
+  if (self->_verify_ro) {
+    vret = visit(self->_verify_ro, arg);
+    if (vret != 0)
+      return vret;
+  }
+  if (self->_verify_generations) {
+    vret = visit(self->_verify_generations, arg);
+    if (vret != 0)
+      return vret;
+  }
+  
+  return 0;
+}
+
+static int
+verifying_clear(verify *self)
+{
+  lookup_clear((lookup *)self);
+  Py_CLEAR(self->_verify_generations);
+  Py_CLEAR(self->_verify_ro);
+  return 0;
+}
+
+
+static void
+verifying_dealloc(verify *self)
+{
+  verifying_clear(self);
+  Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+/*  
+    def changed(self, originally_changed):
+        super(VerifyingBasePy, self).changed(originally_changed)
+        self._verify_ro = self._registry.ro[1:]
+        self._verify_generations = [r._generation for r in self._verify_ro]
+*/
+static PyObject *
+_generations_tuple(PyObject *ro)
+{
+  int i, l;
+  PyObject *generations;
+  
+  l = PyTuple_GET_SIZE(ro);
+  generations = PyTuple_New(l);
+  for (i=0; i < l; i++)
+    {
+      PyObject *generation;
+      
+      generation = PyObject_GetAttr(PyTuple_GET_ITEM(ro, i), str_generation);
+      if (generation == NULL)
+        {
+          Py_DECREF(generations);
+          return NULL;
+        }
+      PyTuple_SET_ITEM(generations, i, generation);
+    }
+
+  return generations;
+}
+static PyObject *
+verifying_changed(verify *self, PyObject *ignored)
+{
+  PyObject *t, *ro;
+
+  verifying_clear(self);
+
+  t = PyObject_GetAttr(OBJECT(self), str_registry);
+  if (t == NULL)
+    return NULL;
+  ro = PyObject_GetAttr(t, strro);
+  Py_DECREF(t);
+  if (ro == NULL)
+    return NULL;
+
+  t = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), ro, NULL);
+  Py_DECREF(ro);
+  if (t == NULL)
+    return NULL;
+
+  ro = PyTuple_GetSlice(t, 1, PyTuple_GET_SIZE(t));
+  Py_DECREF(t);
+  if (ro == NULL)
+    return NULL;
+  
+  self->_verify_generations = _generations_tuple(ro);
+  if (self->_verify_generations == NULL)
+    {
+      Py_DECREF(ro);
+      return NULL;
+    }
+
+  self->_verify_ro = ro;
+
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+/*  
+    def _verify(self):
+        if ([r._generation for r in self._verify_ro]
+            != self._verify_generations):
+            self.changed(None)
+*/
+static int
+_verify(verify *self)
+{
+  PyObject *changed_result;
+
+  if (self->_verify_ro != NULL && self->_verify_generations != NULL)
+    {
+      PyObject *generations;
+      int changed;
+
+      generations = _generations_tuple(self->_verify_ro);
+      if (generations == NULL)
+        return -1;
+
+      changed = PyObject_RichCompareBool(self->_verify_generations, 
+                                        generations, Py_NE);
+      Py_DECREF(generations);
+      if (changed == -1)
+        return -1;
+      
+      if (changed == 0)
+        return 0;
+    }
+
+  changed_result = PyObject_CallMethodObjArgs(OBJECT(self), strchanged, 
+                                              Py_None, NULL);
+  if (changed_result == NULL)
+    return -1;
+
+  Py_DECREF(changed_result);
+  return 0;
+}
+
+static PyObject *
+verifying_lookup(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+  PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &required, &provided, &name, &default_))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _lookup((lookup *)self, required, provided, name, default_);
+}
+
+static PyObject *
+verifying_lookup1(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+  PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &required, &provided, &name, &default_))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _lookup1((lookup *)self, required, provided, name, default_);
+}
+
+static PyObject *
+verifying_adapter_hook(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"provided", "object", "name", "default", NULL};
+  PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &provided, &object, &name, &default_))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _adapter_hook((lookup *)self, provided, object, name, default_);
+}
+
+static PyObject *
+verifying_queryAdapter(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"object", "provided", "name", "default", NULL};
+  PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &object, &provided, &name, &default_))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _adapter_hook((lookup *)self, provided, object, name, default_);
+}
+
+static PyObject *
+verifying_lookupAll(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", NULL};
+  PyObject *required, *provided;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+                                    &required, &provided))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _lookupAll((lookup *)self, required, provided);
+}
+
+static PyObject *
+verifying_subscriptions(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", NULL};
+  PyObject *required, *provided;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+                                    &required, &provided))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _subscriptions((lookup *)self, required, provided);
+}
+
+static struct PyMethodDef verifying_methods[] = {
+  {"changed",     (PyCFunction)verifying_changed,        METH_O,        ""},
+  {"lookup",      (PyCFunction)verifying_lookup,         METH_KEYWORDS, ""},
+  {"lookup1",     (PyCFunction)verifying_lookup1,        METH_KEYWORDS, ""},
+  {"queryAdapter",  (PyCFunction)verifying_queryAdapter,  METH_KEYWORDS, ""},
+  {"adapter_hook",  (PyCFunction)verifying_adapter_hook,  METH_KEYWORDS, ""},
+  {"lookupAll",           (PyCFunction)verifying_lookupAll,      METH_KEYWORDS, ""},
+  {"subscriptions", (PyCFunction)verifying_subscriptions, METH_KEYWORDS, ""},
+  {NULL,           NULL}               /* sentinel */
+};
+
+static PyTypeObject VerifyingBase = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       /* tp_name           */ "_zope_interface_coptimizations."
+                                "VerifyingBase",
+       /* tp_basicsize      */ sizeof(verify),
+       /* tp_itemsize       */ 0,
+       /* tp_dealloc        */ (destructor)&verifying_dealloc,
+       /* tp_print          */ (printfunc)0,
+       /* tp_getattr        */ (getattrfunc)0,
+       /* tp_setattr        */ (setattrfunc)0,
+       /* tp_compare        */ 0,
+       /* tp_repr           */ (reprfunc)0,
+       /* tp_as_number      */ 0,
+       /* tp_as_sequence    */ 0,
+       /* tp_as_mapping     */ 0,
+       /* tp_hash           */ (hashfunc)0,
+       /* tp_call           */ (ternaryfunc)0,
+       /* tp_str            */ (reprfunc)0,
+        /* tp_getattro       */ (getattrofunc)0,
+        /* tp_setattro       */ (setattrofunc)0,
+        /* tp_as_buffer      */ 0,
+        /* tp_flags          */ Py_TPFLAGS_DEFAULT
+                               | Py_TPFLAGS_BASETYPE 
+                               | Py_TPFLAGS_HAVE_GC,
+       /* tp_doc            */ "",
+        /* tp_traverse       */ (traverseproc)verifying_traverse,
+        /* tp_clear          */ (inquiry)verifying_clear,
+        /* tp_richcompare    */ (richcmpfunc)0,
+        /* tp_weaklistoffset */ (long)0,
+        /* tp_iter           */ (getiterfunc)0,
+        /* tp_iternext       */ (iternextfunc)0,
+        /* tp_methods        */ verifying_methods,
+        /* tp_members        */ 0,
+        /* tp_getset         */ 0,
+        /* tp_base           */ &LookupBase,
+};
+
+/* ========================== End: Lookup Bases ======================= */
+/* ==================================================================== */
+
+
+
+static struct PyMethodDef m_methods[] = {
+  {"implementedBy", (PyCFunction)implementedBy, METH_O,
+   "Interfaces implemented by a class or factory.\n"
+   "Raises TypeError if argument is neither a class nor a callable."},
+  {"getObjectSpecification", (PyCFunction)getObjectSpecification, METH_O,
+   "Get an object's interfaces (internal api)"},
+  {"providedBy", (PyCFunction)providedBy, METH_O,
+   "Get an object's interfaces"},
+  
+  {NULL,        (PyCFunction)NULL, 0, NULL}            /* sentinel */
+};
+
+#if  PY_MAJOR_VERSION >= 3
+static char module_doc[] = "C optimizations for zope.interface\n\n";
+
+static struct PyModuleDef _zic_module = {
+       PyModuleDef_HEAD_INIT,
+       "_zope_interface_coptimizations",
+       module_doc,
+       -1,
+       m_methods,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+#endif
+
+static PyObject *
+init(void)
+{
+  PyObject *m;
+
+#if  PY_MAJOR_VERSION < 3
+#define DEFINE_STRING(S) \
+  if(! (str ## S = PyString_FromString(# S))) return NULL
+#else
+#define DEFINE_STRING(S) \
+  if(! (str ## S = PyUnicode_FromString(# S))) return NULL
+#endif
+
+  DEFINE_STRING(__dict__);
+  DEFINE_STRING(__implemented__);
+  DEFINE_STRING(__provides__);
+  DEFINE_STRING(__class__);
+  DEFINE_STRING(__providedBy__);
+  DEFINE_STRING(extends);
+  DEFINE_STRING(_implied);
+  DEFINE_STRING(_implements);
+  DEFINE_STRING(_cls);
+  DEFINE_STRING(__conform__);
+  DEFINE_STRING(_call_conform);
+  DEFINE_STRING(_uncached_lookup);
+  DEFINE_STRING(_uncached_lookupAll);
+  DEFINE_STRING(_uncached_subscriptions);
+  DEFINE_STRING(_registry);
+  DEFINE_STRING(_generation);
+  DEFINE_STRING(ro);
+  DEFINE_STRING(changed);
+#undef DEFINE_STRING
+  adapter_hooks = PyList_New(0);
+  if (adapter_hooks == NULL)
+    return NULL;
+        
+  /* Initialize types: */
+  SpecType.tp_new = PyBaseObject_Type.tp_new;
+  if (PyType_Ready(&SpecType) < 0)
+    return NULL;
+  OSDType.tp_new = PyBaseObject_Type.tp_new;
+  if (PyType_Ready(&OSDType) < 0)
+    return NULL;
+  CPBType.tp_new = PyBaseObject_Type.tp_new;
+  if (PyType_Ready(&CPBType) < 0)
+    return NULL;
+
+  InterfaceBase.tp_new = PyBaseObject_Type.tp_new;
+  if (PyType_Ready(&InterfaceBase) < 0)
+    return NULL;
+
+  LookupBase.tp_new = PyBaseObject_Type.tp_new;
+  if (PyType_Ready(&LookupBase) < 0)
+    return NULL;
+
+  VerifyingBase.tp_new = PyBaseObject_Type.tp_new;
+  if (PyType_Ready(&VerifyingBase) < 0)
+    return NULL;
+
+  #if PY_MAJOR_VERSION < 3
+  /* Create the module and add the functions */
+  m = Py_InitModule3("_zope_interface_coptimizations", m_methods,
+                     "C optimizations for zope.interface\n\n");
+  #else
+  m = PyModule_Create(&_zic_module);
+  #endif
+  if (m == NULL)
+    return NULL;
+
+  /* Add types: */
+  if (PyModule_AddObject(m, "SpecificationBase", OBJECT(&SpecType)) < 0)
+    return NULL;
+  if (PyModule_AddObject(m, "ObjectSpecificationDescriptor", 
+                         (PyObject *)&OSDType) < 0)
+    return NULL;
+  if (PyModule_AddObject(m, "ClassProvidesBase", OBJECT(&CPBType)) < 0)
+    return NULL;
+  if (PyModule_AddObject(m, "InterfaceBase", OBJECT(&InterfaceBase)) < 0)
+    return NULL;
+  if (PyModule_AddObject(m, "LookupBase", OBJECT(&LookupBase)) < 0)
+    return NULL;
+  if (PyModule_AddObject(m, "VerifyingBase", OBJECT(&VerifyingBase)) < 0)
+    return NULL;
+  if (PyModule_AddObject(m, "adapter_hooks", adapter_hooks) < 0)
+    return NULL;
+  return m;
+}
+
+PyMODINIT_FUNC
+#if PY_MAJOR_VERSION < 3
+init_zope_interface_coptimizations(void)
+{
+  init();
+}
+#else
+PyInit__zope_interface_coptimizations(void)
+{
+  return init();
+}
+#endif
diff --git a/src/zope/interface/adapter.py b/src/zope/interface/adapter.py
new file mode 100644 (file)
index 0000000..2ad145b
--- /dev/null
@@ -0,0 +1,692 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Adapter management
+"""
+
+import weakref
+from zope.interface import providedBy, Interface, ro
+
+_marker = object
+class BaseAdapterRegistry(object):
+
+    # List of methods copied from lookup sub-objects:
+    _delegated = ('lookup', 'queryMultiAdapter', 'lookup1', 'queryAdapter',
+                  'adapter_hook', 'lookupAll', 'names',
+                  'subscriptions', 'subscribers')
+
+    # All registries maintain a generation that can be used by verifying
+    # registries
+    _generation = 0
+
+    def __init__(self, bases=()):
+
+        # The comments here could be improved. Possibly this bit needs
+        # explaining in a separate document, as the comments here can
+        # be quite confusing. /regebro
+
+        # {order -> {required -> {provided -> {name -> value}}}}
+        # Here "order" is actually an index in a list, "required" and
+        # "provided" are interfaces, and "required" is really a nested
+        # key.  So, for example:
+        # for order == 0 (that is, self._adapters[0]), we have:
+        #   {provided -> {name -> value}}
+        # but for order == 2 (that is, self._adapters[2]), we have:
+        #   {r1 -> {r2 -> {provided -> {name -> value}}}}
+        #
+        self._adapters = []
+
+        # {order -> {required -> {provided -> {name -> [value]}}}}
+        # where the remarks about adapters above apply
+        self._subscribers = []
+
+        # Set, with a reference count, keeping track of the interfaces
+        # for which we have provided components:
+        self._provided = {}
+
+        # Create ``_v_lookup`` object to perform lookup.  We make this a
+        # separate object to to make it easier to implement just the
+        # lookup functionality in C.  This object keeps track of cache
+        # invalidation data in two kinds of registries.
+
+        #   Invalidating registries have caches that are invalidated
+        #     when they or their base registies change.  An invalidating
+        #     registry can only have invalidating registries as bases.
+        #     See LookupBasePy below for the pertinent logic.
+
+        #   Verifying registies can't rely on getting invalidation messages,
+        #     so have to check the generations of base registries to determine
+        #     if their cache data are current.  See VerifyingBasePy below
+        #     for the pertinent object.
+        self._createLookup()
+
+        # Setting the bases causes the registries described above
+        # to be initialized (self._setBases -> self.changed ->
+        # self._v_lookup.changed).
+
+        self.__bases__ = bases
+
+    def _setBases(self, bases):
+        self.__dict__['__bases__'] = bases
+        self.ro = ro.ro(self)
+        self.changed(self)
+
+    __bases__ = property(lambda self: self.__dict__['__bases__'],
+                         lambda self, bases: self._setBases(bases),
+                         )
+
+    def _createLookup(self):
+        self._v_lookup = self.LookupClass(self)
+        for name in self._delegated:
+            self.__dict__[name] = getattr(self._v_lookup, name)
+
+    def changed(self, originally_changed):
+        self._generation += 1
+        self._v_lookup.changed(originally_changed)
+
+    def register(self, required, provided, name, value):
+        if value is None:
+            self.unregister(required, provided, name, value)
+            return
+
+        required = tuple(map(_convert_None_to_Interface, required))
+        name = _normalize_name(name)
+        order = len(required)
+        byorder = self._adapters
+        while len(byorder) <= order:
+            byorder.append({})
+        components = byorder[order]
+        key = required + (provided,)
+
+        for k in key:
+            d = components.get(k)
+            if d is None:
+                d = {}
+                components[k] = d
+            components = d
+
+        if components.get(name) is value:
+            return
+
+        components[name] = value
+
+        n = self._provided.get(provided, 0) + 1
+        self._provided[provided] = n
+        if n == 1:
+            self._v_lookup.add_extendor(provided)
+
+        self.changed(self)
+
+    def registered(self, required, provided, name=u''):
+        required = tuple(map(_convert_None_to_Interface, required))
+        name = _normalize_name(name)
+        order = len(required)
+        byorder = self._adapters
+        if len(byorder) <= order:
+            return None
+
+        components = byorder[order]
+        key = required + (provided,)
+
+        for k in key:
+            d = components.get(k)
+            if d is None:
+                return None
+            components = d
+
+        return components.get(name)
+
+    def unregister(self, required, provided, name, value=None):
+        required = tuple(map(_convert_None_to_Interface, required))
+        order = len(required)
+        byorder = self._adapters
+        if order >= len(byorder):
+            return False
+        components = byorder[order]
+        key = required + (provided,)
+
+        # Keep track of how we got to `components`:
+        lookups = []
+        # Keep track of how we got to `components`:
+        lookups = []
+        for k in key:
+            d = components.get(k)
+            if d is None:
+                return
+            lookups.append((components, k))
+            components = d
+
+        old = components.get(name)
+        if old is None:
+            return
+        if (value is not None) and (old is not value):
+            return
+
+        del components[name]
+        if not components:
+            # Clean out empty containers, since we don't want our keys
+            # to reference global objects (interfaces) unnecessarily.
+            # This is often a problem when an interface is slated for
+            # removal; a hold-over entry in the registry can make it
+            # difficult to remove such interfaces.
+            for comp, k in reversed(lookups):
+                d = comp[k]
+                if d:
+                    break
+                else:
+                    del comp[k]
+            while byorder and not byorder[-1]:
+                del byorder[-1]
+        n = self._provided[provided] - 1
+        if n == 0:
+            del self._provided[provided]
+            self._v_lookup.remove_extendor(provided)
+        else:
+            self._provided[provided] = n
+
+        self.changed(self)
+
+    def subscribe(self, required, provided, value):
+        required = tuple(map(_convert_None_to_Interface, required))
+        name = u''
+        order = len(required)
+        byorder = self._subscribers
+        while len(byorder) <= order:
+            byorder.append({})
+        components = byorder[order]
+        key = required + (provided,)
+
+        for k in key:
+            d = components.get(k)
+            if d is None:
+                d = {}
+                components[k] = d
+            components = d
+
+        components[name] = components.get(name, ()) + (value, )
+
+        if provided is not None:
+            n = self._provided.get(provided, 0) + 1
+            self._provided[provided] = n
+            if n == 1:
+                self._v_lookup.add_extendor(provided)
+
+        self.changed(self)
+
+    def unsubscribe(self, required, provided, value=None):
+        required = tuple(map(_convert_None_to_Interface, required))
+        order = len(required)
+        byorder = self._subscribers
+        if order >= len(byorder):
+            return
+        components = byorder[order]
+        key = required + (provided,)
+
+        # Keep track of how we got to `components`:
+        lookups = []
+        # Keep track of how we got to `components`:
+        lookups = []
+        for k in key:
+            d = components.get(k)
+            if d is None:
+                return
+            lookups.append((components, k))
+            components = d
+
+        old = components.get(u'')
+        if not old:
+            return
+
+        if value is None:
+            new = ()
+        else:
+            new = tuple([v for v in old if v is not value])
+
+        if new == old:
+            return
+
+        if new:
+            components[u''] = new
+        else:
+            # Instead of setting components[u''] = new, we clean out
+            # empty containers, since we don't want our keys to
+            # reference global objects (interfaces) unnecessarily.  This
+            # is often a problem when an interface is slated for
+            # removal; a hold-over entry in the registry can make it
+            # difficult to remove such interfaces.
+            if u'' in components:
+                del components[u'']
+            for comp, k in reversed(lookups):
+                d = comp[k]
+                if d:
+                    break
+                else:
+                    del comp[k]
+            while byorder and not byorder[-1]:
+                del byorder[-1]
+
+        if provided is not None:
+            n = self._provided[provided] + len(new) - len(old)
+            if n == 0:
+                del self._provided[provided]
+                self._v_lookup.remove_extendor(provided)
+
+        self.changed(self)
+
+    # XXX hack to fake out twisted's use of a private api.  We need to get them
+    # to use the new registed method.
+    def get(self, _):
+        class XXXTwistedFakeOut:
+            selfImplied = {}
+        return XXXTwistedFakeOut
+
+
+_not_in_mapping = object()
+class LookupBasePy(object):
+
+    def __init__(self):
+        self._cache = {}
+        self._mcache = {}
+        self._scache = {}
+
+    def changed(self, ignored=None):
+        self._cache.clear()
+        self._mcache.clear()
+        self._scache.clear()
+
+    def _getcache(self, provided, name):
+        cache = self._cache.get(provided)
+        if cache is None:
+            cache = {}
+            self._cache[provided] = cache
+        if name:
+            c = cache.get(name)
+            if c is None:
+                c = {}
+                cache[name] = c
+            cache = c
+        return cache
+
+    def lookup(self, required, provided, name=u'', default=None):
+        cache = self._getcache(provided, name)
+        if len(required) == 1:
+            result = cache.get(required[0], _not_in_mapping)
+        else:
+            result = cache.get(tuple(required), _not_in_mapping)
+
+        if result is _not_in_mapping:
+            result = self._uncached_lookup(required, provided, name)
+            if len(required) == 1:
+                cache[required[0]] = result
+            else:
+                cache[tuple(required)] = result
+
+        if result is None:
+            return default
+
+        return result
+
+    def lookup1(self, required, provided, name=u'', default=None):
+        cache = self._getcache(provided, name)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            return self.lookup((required, ), provided, name, default)
+
+        if result is None:
+            return default
+
+        return result
+
+    def queryAdapter(self, object, provided, name=u'', default=None):
+        return self.adapter_hook(provided, object, name, default)
+
+    def adapter_hook(self, provided, object, name=u'', default=None):
+        required = providedBy(object)
+        cache = self._getcache(provided, name)
+        factory = cache.get(required, _not_in_mapping)
+        if factory is _not_in_mapping:
+            factory = self.lookup((required, ), provided, name)
+
+        if factory is not None:
+            result = factory(object)
+            if result is not None:
+                return result
+
+        return default
+
+    def lookupAll(self, required, provided):
+        cache = self._mcache.get(provided)
+        if cache is None:
+            cache = {}
+            self._mcache[provided] = cache
+
+        required = tuple(required)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            result = self._uncached_lookupAll(required, provided)
+            cache[required] = result
+
+        return result
+
+
+    def subscriptions(self, required, provided):
+        cache = self._scache.get(provided)
+        if cache is None:
+            cache = {}
+            self._scache[provided] = cache
+
+        required = tuple(required)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            result = self._uncached_subscriptions(required, provided)
+            cache[required] = result
+
+        return result
+
+LookupBase = LookupBasePy
+
+class VerifyingBasePy(LookupBasePy):
+
+    def changed(self, originally_changed):
+        LookupBasePy.changed(self, originally_changed)
+        self._verify_ro = self._registry.ro[1:]
+        self._verify_generations = [r._generation for r in self._verify_ro]
+
+    def _verify(self):
+        if ([r._generation for r in self._verify_ro]
+            != self._verify_generations):
+            self.changed(None)
+
+    def _getcache(self, provided, name):
+        self._verify()
+        return LookupBasePy._getcache(self, provided, name)
+
+    def lookupAll(self, required, provided):
+        self._verify()
+        return LookupBasePy.lookupAll(self, required, provided)
+
+    def subscriptions(self, required, provided):
+        self._verify()
+        return LookupBasePy.subscriptions(self, required, provided)
+
+VerifyingBase = VerifyingBasePy
+
+
+try:
+    import _zope_interface_coptimizations
+except ImportError:
+    pass
+else:
+    from _zope_interface_coptimizations import LookupBase, VerifyingBase
+
+class AdapterLookupBase(object):
+
+    def __init__(self, registry):
+        self._registry = registry
+        self._required = {}
+        self.init_extendors()
+        super(AdapterLookupBase, self).__init__()
+
+    def changed(self, ignored=None):
+        super(AdapterLookupBase, self).changed(None)
+        for r in self._required.keys():
+            r = r()
+            if r is not None:
+                r.unsubscribe(self)
+        self._required.clear()
+
+
+    # Extendors
+    # ---------
+
+    # When given an target interface for an adapter lookup, we need to consider
+    # adapters for interfaces that extend the target interface.  This is
+    # what the extendors dictionary is about.  It tells us all of the
+    # interfaces that extend an interface for which there are adapters
+    # registered.
+
+    # We could separate this by order and name, thus reducing the
+    # number of provided interfaces to search at run time.  The tradeoff,
+    # however, is that we have to store more information.  For example,
+    # is the same interface is provided for multiple names and if the
+    # interface extends many interfaces, we'll have to keep track of
+    # a fair bit of information for each name.  It's better to
+    # be space efficient here and be time efficient in the cache
+    # implementation.
+
+    # TODO: add invalidation when a provided interface changes, in case
+    # the interface's __iro__ has changed.  This is unlikely enough that
+    # we'll take our chances for now.
+
+    def init_extendors(self):
+        self._extendors = {}
+        for p in self._registry._provided:
+            self.add_extendor(p)
+
+    def add_extendor(self, provided):
+        _extendors = self._extendors
+        for i in provided.__iro__:
+            extendors = _extendors.get(i, ())
+            _extendors[i] = (
+                [e for e in extendors if provided.isOrExtends(e)]
+                +
+                [provided]
+                +
+                [e for e in extendors if not provided.isOrExtends(e)]
+                )
+
+    def remove_extendor(self, provided):
+        _extendors = self._extendors
+        for i in provided.__iro__:
+            _extendors[i] = [e for e in _extendors.get(i, ())
+                             if e != provided]
+
+
+    def _subscribe(self, *required):
+        _refs = self._required
+        for r in required:
+            ref = r.weakref()
+            if ref not in _refs:
+                r.subscribe(self)
+                _refs[ref] = 1
+
+    def _uncached_lookup(self, required, provided, name=u''):
+        result = None
+        order = len(required)
+        for registry in self._registry.ro:
+            byorder = registry._adapters
+            if order >= len(byorder):
+                continue
+
+            extendors = registry._v_lookup._extendors.get(provided)
+            if not extendors:
+                continue
+
+            components = byorder[order]
+            result = _lookup(components, required, extendors, name, 0,
+                             order)
+            if result is not None:
+                break
+
+        self._subscribe(*required)
+
+        return result
+
+    def queryMultiAdapter(self, objects, provided, name=u'', default=None):
+        factory = self.lookup(map(providedBy, objects), provided, name)
+        if factory is None:
+            return default
+
+        result = factory(*objects)
+        if result is None:
+            return default
+
+        return result
+
+    def _uncached_lookupAll(self, required, provided):
+        order = len(required)
+        result = {}
+        for registry in reversed(self._registry.ro):
+            byorder = registry._adapters
+            if order >= len(byorder):
+                continue
+            extendors = registry._v_lookup._extendors.get(provided)
+            if not extendors:
+                continue
+            components = byorder[order]
+            _lookupAll(components, required, extendors, result, 0, order)
+
+        self._subscribe(*required)
+
+        return tuple(result.iteritems())
+
+    def names(self, required, provided):
+        return [c[0] for c in self.lookupAll(required, provided)]
+
+    def _uncached_subscriptions(self, required, provided):
+        order = len(required)
+        result = []
+        for registry in reversed(self._registry.ro):
+            byorder = registry._subscribers
+            if order >= len(byorder):
+                continue
+
+            if provided is None:
+                extendors = (provided, )
+            else:
+                extendors = registry._v_lookup._extendors.get(provided)
+                if extendors is None:
+                    continue
+
+            _subscriptions(byorder[order], required, extendors, u'',
+                           result, 0, order)
+
+        self._subscribe(*required)
+
+        return result
+
+    def subscribers(self, objects, provided):
+        subscriptions = self.subscriptions(map(providedBy, objects), provided)
+        if provided is None:
+            result = ()
+            for subscription in subscriptions:
+                subscription(*objects)
+        else:
+            result = []
+            for subscription in subscriptions:
+                subscriber = subscription(*objects)
+                if subscriber is not None:
+                    result.append(subscriber)
+        return result
+
+class AdapterLookup(AdapterLookupBase, LookupBase):
+    pass
+
+class AdapterRegistry(BaseAdapterRegistry):
+
+    LookupClass = AdapterLookup
+
+    def __init__(self, bases=()):
+        # AdapterRegisties are invalidating registries, so
+        # we need to keep track of out invalidating subregistries.
+        self._v_subregistries = weakref.WeakKeyDictionary()
+
+        super(AdapterRegistry, self).__init__(bases)
+
+    def _addSubregistry(self, r):
+        self._v_subregistries[r] = 1
+
+    def _removeSubregistry(self, r):
+        if r in self._v_subregistries:
+            del self._v_subregistries[r]
+
+    def _setBases(self, bases):
+        old = self.__dict__.get('__bases__', ())
+        for r in old:
+            if r not in bases:
+                r._removeSubregistry(self)
+        for r in bases:
+            if r not in old:
+                r._addSubregistry(self)
+
+        super(AdapterRegistry, self)._setBases(bases)
+
+    def changed(self, originally_changed):
+        super(AdapterRegistry, self).changed(originally_changed)
+
+        for sub in self._v_subregistries.keys():
+            sub.changed(originally_changed)
+
+
+class VerifyingAdapterLookup(AdapterLookupBase, VerifyingBase):
+    pass
+
+class VerifyingAdapterRegistry(BaseAdapterRegistry):
+
+    LookupClass = VerifyingAdapterLookup
+
+def _convert_None_to_Interface(x):
+    if x is None:
+        return Interface
+    else:
+        return x
+
+def _normalize_name(name):
+    if isinstance(name, basestring):
+        return unicode(name)
+
+    raise TypeError("name must be a regular or unicode string")
+
+def _lookup(components, specs, provided, name, i, l):
+    if i < l:
+        for spec in specs[i].__sro__:
+            comps = components.get(spec)
+            if comps:
+                r = _lookup(comps, specs, provided, name, i+1, l)
+                if r is not None:
+                    return r
+    else:
+        for iface in provided:
+            comps = components.get(iface)
+            if comps:
+                r = comps.get(name)
+                if r is not None:
+                    return r
+
+    return None
+
+def _lookupAll(components, specs, provided, result, i, l):
+    if i < l:
+        for spec in reversed(specs[i].__sro__):
+            comps = components.get(spec)
+            if comps:
+                _lookupAll(comps, specs, provided, result, i+1, l)
+    else:
+        for iface in reversed(provided):
+            comps = components.get(iface)
+            if comps:
+                result.update(comps)
+
+def _subscriptions(components, specs, provided, name, result, i, l):
+    if i < l:
+        for spec in reversed(specs[i].__sro__):
+            comps = components.get(spec)
+            if comps:
+                _subscriptions(comps, specs, provided, name, result, i+1, l)
+    else:
+        for iface in reversed(provided):
+            comps = components.get(iface)
+            if comps:
+                comps = comps.get(name)
+                if comps:
+                    result.extend(comps)
diff --git a/src/zope/interface/adapter.ru.txt b/src/zope/interface/adapter.ru.txt
new file mode 100644 (file)
index 0000000..30c2782
--- /dev/null
@@ -0,0 +1,540 @@
+================
+Реестр адаптеров
+================
+
+.. contents::
+
+Реестры адаптеров предоставляют возможность для регистрации объектов которые
+зависят от одной, или нескольких спецификаций интерфейсов и предоставляют
+(возможно не напрямую) какой-либо интерфейс. В дополнение, регистрации имеют
+имена. (Можно думать об именах как о спецификаторах предоставляемого
+интерфейса.)
+
+Термин "спецификация интерфейса" ссылается и на интерфейсы и на определения
+интерфейсов, такие как определения интерфейсов реализованных некоторым классом.
+
+Одиночные адаптеры
+==================
+
+Давайте рассмотрим простой пример использующий единственную требуемую
+спецификацию::
+
+  >>> from zope.interface.adapter import AdapterRegistry
+  >>> import zope.interface
+
+  >>> class IR1(zope.interface.Interface):
+  ...     pass
+  >>> class IP1(zope.interface.Interface):
+  ...     pass
+  >>> class IP2(IP1):
+  ...     pass
+
+  >>> registry = AdapterRegistry()
+
+Мы зарегистрируем объект который зависит от IR1 и "предоставляет" IP2::
+
+  >>> registry.register([IR1], IP2, '', 12)
+
+После регистрации мы можем запросить объект снова::
+
+  >>> registry.lookup([IR1], IP2, '')
+  12
+
+Заметьте, что мы используем целое в этом примере. В реальных приложениях вы
+можете использовать объекты которые на самом деле зависят или предоставляют
+интерфейсы. Реестр не заботиться о том, что регистрируется и таким образом мы
+можем использовать целые, или строки что бы упростить наши примеры. Здесь есть
+одно исключение. Регистрация значения None удаляет регистрацию для любого
+зарегистрированного прежде значения.
+
+Если объект зависит от спецификации он может быть запрошен с помощью
+спецификации которая расширяет спецификацию от которой он зависит::
+
+  >>> class IR2(IR1):
+  ...     pass
+  >>> registry.lookup([IR2], IP2, '')
+  12
+
+Мы можем использовать класс реализующий спецификацию для запроса объекта::
+
+  >>> class C2:
+  ...     zope.interface.implements(IR2)
+
+  >>> registry.lookup([zope.interface.implementedBy(C2)], IP2, '')
+  12
+
+и объект может быть запрошен для интерфейсов которые предоставляемый объектом
+интерфейс расширяет::
+
+  >>> registry.lookup([IR1], IP1, '')
+  12
+  >>> registry.lookup([IR2], IP1, '')
+  12
+
+Но если вы требуете спецификацию которая не расширяет спецификацию от которой
+зависит объект, вы не получите ничего::
+
+  >>> registry.lookup([zope.interface.Interface], IP1, '')
+
+Между прочим, вы можете передать значение по умолчанию при запросе::
+
+  >>> registry.lookup([zope.interface.Interface], IP1, '', 42)
+  42
+
+Если вы пробуете получить интерфейс который объект не предоставляет вы также
+не получите ничего::
+
+  >>> class IP3(IP2):
+  ...     pass
+  >>> registry.lookup([IR1], IP3, '')
+
+Вы также не получите ничего если вы используете неверное имя::
+
+  >>> registry.lookup([IR1], IP1, 'bob')
+  >>> registry.register([IR1], IP2, 'bob', "Bob's 12")
+  >>> registry.lookup([IR1], IP1, 'bob')
+  "Bob's 12"
+
+Вы можете не использовать имя при запросе::
+
+  >>> registry.lookup([IR1], IP1)
+  12
+
+Если мы регистрируем объект который предоставляет IP1::
+
+  >>> registry.register([IR1], IP1, '', 11)
+
+тогда этот объект будет иметь преимущество перед O(12)::
+
+  >>> registry.lookup([IR1], IP1, '')
+  11
+
+Также, если мы регистрируем объект для IR2 тогда он будет иметь преимущество
+когда используется IR2::
+
+  >>> registry.register([IR2], IP1, '', 21)
+  >>> registry.lookup([IR2], IP1, '')
+  21
+
+Поиск того, что (если вообще что-то) зарегистрировано
+-----------------------------------------------------
+
+Мы можем спросить есть-ли адаптер зарегистрированный для набора интерфейсов.
+Это отличается от обычного запроса так как здесь мы ищем точное совпадение::
+
+  >>> print registry.registered([IR1], IP1)
+  11
+
+  >>> print registry.registered([IR1], IP2)
+  12
+
+  >>> print registry.registered([IR1], IP2, 'bob')
+  Bob's 12
+  
+
+  >>> print registry.registered([IR2], IP1)
+  21
+
+  >>> print registry.registered([IR2], IP2)
+  None
+
+В последнем примере, None был возвращен потому, что для данного интерфейса
+ничего не было зарегистрировано.
+
+lookup1
+-------
+
+Запрос одиночного адаптера - это наиболее частая операция и для нее есть
+специализированная версия запроса которая получает на вход единственный
+требуемый интерфейс::
+
+  >>> registry.lookup1(IR2, IP1, '')
+  21
+  >>> registry.lookup1(IR2, IP1)
+  21
+
+Адаптация на практике
+---------------------
+
+Реестр адаптеров предназначен для поддержки адаптации когда один объект
+реализующий интерфейс адаптируется к другому объекту который поддерживает
+другой интерфейс. Реестр адаптеров также поддерживает вычисление адаптеров. В
+этом случае мы должны регистрировать фабрики для адаптеров::
+
+   >>> class IR(zope.interface.Interface):
+   ...     pass
+
+   >>> class X:
+   ...     zope.interface.implements(IR)
+           
+   >>> class Y:
+   ...     zope.interface.implements(IP1)
+   ...     def __init__(self, context):
+   ...         self.context = context
+
+  >>> registry.register([IR], IP1, '', Y)
+
+В этом случае мы регистрируем класс как фабрику. Теперь мы можем вызвать
+`queryAdapter` для получения адаптированного объекта::
+
+  >>> x = X()
+  >>> y = registry.queryAdapter(x, IP1)
+  >>> y.__class__.__name__
+  'Y'
+  >>> y.context is x
+  True
+
+Мы также можем регистрировать и запрашивать по имени::
+
+  >>> class Y2(Y):
+  ...     pass
+
+  >>> registry.register([IR], IP1, 'bob', Y2)
+  >>> y = registry.queryAdapter(x, IP1, 'bob')
+  >>> y.__class__.__name__
+  'Y2'
+  >>> y.context is x
+  True
+
+Когда фабрика для адаптера возвращает `None` - это рассматривается как если бы
+адаптер не был найден. Это позволяет нам избежать адаптации (по желанию) и дает
+возможность фабрике адаптера определить возможна ли адаптация основываясь на
+состоянии объекта который адаптируется::
+
+  >>> def factory(context):
+  ...     if context.name == 'object':
+  ...         return 'adapter'
+  ...     return None
+
+  >>> class Object(object):
+  ...     zope.interface.implements(IR)
+  ...     name = 'object'
+
+  >>> registry.register([IR], IP1, 'conditional', factory) 
+  >>> obj = Object()
+  >>> registry.queryAdapter(obj, IP1, 'conditional')
+  'adapter'
+  >>> obj.name = 'no object'
+  >>> registry.queryAdapter(obj, IP1, 'conditional') is None
+  True
+  >>> registry.queryAdapter(obj, IP1, 'conditional', 'default')
+  'default'
+
+Альтернативный метод для предоставления такой же функциональности как и
+`queryAdapter()` - это `adapter_hook()`::
+
+  >>> y = registry.adapter_hook(IP1, x)
+  >>> y.__class__.__name__
+  'Y'
+  >>> y.context is x
+  True
+  >>> y = registry.adapter_hook(IP1, x, 'bob')
+  >>> y.__class__.__name__
+  'Y2'
+  >>> y.context is x
+  True
+
+`adapter_hook()` просто меняет порядок аргументов для объекта и интерфейса. Это
+используется для встраивания в механизм вызовов интерфейсов.
+
+Адаптеры по умолчанию
+---------------------
+
+Иногда вы можете захотеть предоставить адаптер который не будет ничего
+адаптировать. Для этого нужно передать None как требуемый интерфейс::
+
+  >>> registry.register([None], IP1, '', 1)
+
+после этого вы можете использовать этот адаптер для интерфейсов для которых у
+вас нет конкретного адаптера::
+
+  >>> class IQ(zope.interface.Interface):
+  ...     pass
+  >>> registry.lookup([IQ], IP1, '')
+  1
+
+Конечно, конкретные адаптеры все еще используются когда необходимо::
+
+  >>> registry.lookup([IR2], IP1, '')
+  21
+
+Адаптеры классов
+----------------
+
+Вы можете регистрировать адаптеры для определений классов, что будет похоже на
+регистрацию их для классов::
+
+  >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', 'C21')
+  >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '')
+  'C21'
+
+Адаптеры для словарей
+---------------------
+
+В какой-то момент было невозможно регистрировать адаптеры основанные на
+словарях из-за ошибки. Давайте удостоверимся что это теперь работает::
+
+  >>> adapter = {}
+  >>> registry.register((), IQ, '', adapter)
+  >>> registry.lookup((), IQ, '') is adapter
+  True
+
+Удаление регистрации
+--------------------
+
+Вы можете удалить регистрацию регистрируя None вместо объекта::
+
+  >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', None)
+  >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '')
+  21
+
+Конечно это значит, что None не может быть зарегистрирован. Это исключение к
+утверждению выше о том, что реестр не заботиться о том, что регистрируется.
+
+Мульти-адаптеры
+===============
+
+Вы можете адаптировать несколько спецификаций::
+
+  >>> registry.register([IR1, IQ], IP2, '', '1q2')
+  >>> registry.lookup([IR1, IQ], IP2, '')
+  '1q2'
+  >>> registry.lookup([IR2, IQ], IP1, '')
+  '1q2'
+
+  >>> class IS(zope.interface.Interface):
+  ...     pass
+  >>> registry.lookup([IR2, IS], IP1, '')
+
+  >>> class IQ2(IQ):
+  ...     pass
+
+  >>> registry.lookup([IR2, IQ2], IP1, '')
+  '1q2'
+
+  >>> registry.register([IR1, IQ2], IP2, '', '1q22')
+  >>> registry.lookup([IR2, IQ2], IP1, '')
+  '1q22'
+
+Мульти-адаптация
+----------------
+
+Вы можете адаптировать несколько объектов::
+
+  >>> class Q:
+  ...     zope.interface.implements(IQ)
+
+Как и с одиночными адаптерами, мы регистрируем фабрику которая возвращает
+класс::
+
+  >>> class IM(zope.interface.Interface):
+  ...     pass
+  >>> class M:
+  ...     zope.interface.implements(IM)
+  ...     def __init__(self, x, q):
+  ...         self.x, self.q = x, q
+  >>> registry.register([IR, IQ], IM, '', M)
+
+И затем мы можем вызвать `queryMultiAdapter` для вычисления адаптера::
+
+  >>> q = Q()
+  >>> m = registry.queryMultiAdapter((x, q), IM)
+  >>> m.__class__.__name__
+  'M'
+  >>> m.x is x and m.q is q
+  True
+
+и, конечно, мы можем использовать имена::
+
+  >>> class M2(M):
+  ...     pass
+  >>> registry.register([IR, IQ], IM, 'bob', M2)
+  >>> m = registry.queryMultiAdapter((x, q), IM, 'bob')
+  >>> m.__class__.__name__
+  'M2'
+  >>> m.x is x and m.q is q
+  True
+
+Адаптеры по умолчанию
+---------------------
+
+Как и для одиночных адаптеров вы можете определить адаптер по умолчанию передав
+None вместо *первой* спецификации::
+
+  >>> registry.register([None, IQ], IP2, '', 'q2')
+  >>> registry.lookup([IS, IQ], IP2, '')
+  'q2'
+
+Нулевые адаптеры
+================
+
+Вы можете также адаптировать без спецификации::
+
+  >>> registry.register([], IP2, '', 2)
+  >>> registry.lookup([], IP2, '')
+  2
+  >>> registry.lookup([], IP1, '')
+  2
+
+Перечисление именованных адаптеров
+----------------------------------
+
+Адаптеры имеют имена. Иногда это полезно для получения всех именованных
+адаптеров для заданного интерфейса::
+
+  >>> adapters = list(registry.lookupAll([IR1], IP1))
+  >>> adapters.sort()
+  >>> assert adapters == [(u'', 11), (u'bob', "Bob's 12")]
+
+Это работает также и для мульти-адаптеров::
+
+  >>> registry.register([IR1, IQ2], IP2, 'bob', '1q2 for bob')
+  >>> adapters = list(registry.lookupAll([IR2, IQ2], IP1))
+  >>> adapters.sort()
+  >>> assert adapters == [(u'', '1q22'), (u'bob', '1q2 for bob')]
+
+И даже для нулевых адаптеров::
+
+  >>> registry.register([], IP2, 'bob', 3)
+  >>> adapters = list(registry.lookupAll([], IP1))
+  >>> adapters.sort()
+  >>> assert adapters == [(u'', 2), (u'bob', 3)]
+
+Подписки
+========
+
+Обычно мы хотим запросить объект который наиболее близко соответствует
+спецификации. Иногда мы хотим получить все объекты которые соответствуют
+какой-либо спецификации. Мы используем подписки для этого. Мы подписываем
+объекты для спецификаций и затем позже находим все подписанные объекты::
+
+  >>> registry.subscribe([IR1], IP2, 'sub12 1')
+  >>> registry.subscriptions([IR1], IP2)
+  ['sub12 1']
+
+Заметьте, что в отличие от обычных адаптеров подписки не имеют имен.
+
+Вы можете иметь несколько подписчиков для одной спецификации::
+
+  >>> registry.subscribe([IR1], IP2, 'sub12 2')
+  >>> registry.subscriptions([IR1], IP2)
+  ['sub12 1', 'sub12 2']
+
+Если подписчики зарегистрированы для одних и тех же требуемых интерфейсов, они
+возвращаются в порядке определения.
+
+Вы можете зарегистрировать подписчики для всех спецификаций используя None::
+
+  >>> registry.subscribe([None], IP1, 'sub_1')
+  >>> registry.subscriptions([IR2], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2']
+
+Заметьте, что новый подписчик возвращается первым. Подписчики определенные
+для менее общих требуемых интерфейсов возвращаются перед подписчиками
+для более общих интерфейсов.
+
+Подписки могут смешиваться между несколькими совместимыми спецификациями::
+
+  >>> registry.subscriptions([IR2], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2']
+  >>> registry.subscribe([IR1], IP1, 'sub11')
+  >>> registry.subscriptions([IR2], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2', 'sub11']
+  >>> registry.subscribe([IR2], IP2, 'sub22')
+  >>> registry.subscriptions([IR2], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2', 'sub11', 'sub22']
+  >>> registry.subscriptions([IR2], IP2)
+  ['sub12 1', 'sub12 2', 'sub22']
+
+Подписки могут существовать для нескольких спецификаций::
+
+  >>> registry.subscribe([IR1, IQ], IP2, 'sub1q2')
+  >>> registry.subscriptions([IR1, IQ], IP2)
+  ['sub1q2']
+
+Как и с одиночными подписчиками и адаптерами без подписок, вы можете определить
+None для первого требуемого интерфейса, что бы задать значение по умолчанию::
+
+  >>> registry.subscribe([None, IQ], IP2, 'sub_q2')
+  >>> registry.subscriptions([IS, IQ], IP2)
+  ['sub_q2']
+  >>> registry.subscriptions([IR1, IQ], IP2)
+  ['sub_q2', 'sub1q2']
+
+Вы можете создать подписки которые независимы от любых спецификаций::
+
+  >>> list(registry.subscriptions([], IP1))
+  []
+
+  >>> registry.subscribe([], IP2, 'sub2')
+  >>> registry.subscriptions([], IP1)
+  ['sub2']
+  >>> registry.subscribe([], IP1, 'sub1')
+  >>> registry.subscriptions([], IP1)
+  ['sub2', 'sub1']
+  >>> registry.subscriptions([], IP2)
+  ['sub2']
+
+Удаление регистрации подписчиков
+--------------------------------
+
+Мы можем удалять регистрацию подписчиков. При удалении регистрации подписчика
+мы можем удалить регистрацию заданного адаптера::
+
+  >>> registry.unsubscribe([IR1], IP1, 'sub11')
+  >>> registry.subscriptions([IR1], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2']
+
+Если мы не задаем никакого значения тогда подписки будут удалены для всех
+подписчиков совпадающих с заданным интерфейсом::
+
+  >>> registry.unsubscribe([IR1], IP2)
+  >>> registry.subscriptions([IR1], IP1)
+  ['sub_1']
+
+Адаптеры подписки
+-----------------
+
+Обычно мы регистрируем фабрики для адаптеров которые затем позволяют нам
+вычислять адаптеры, но с подписками мы получаем несколько адаптеров. Это пример
+подписчика для нескольких объектов::
+
+  >>> registry.subscribe([IR, IQ], IM, M)
+  >>> registry.subscribe([IR, IQ], IM, M2)
+
+  >>> subscribers = registry.subscribers((x, q), IM)
+  >>> len(subscribers)
+  2
+  >>> class_names = [s.__class__.__name__ for s in subscribers]
+  >>> class_names.sort()
+  >>> class_names
+  ['M', 'M2']
+  >>> [(s.x is x and s.q is q) for s in subscribers]
+  [True, True]
+
+подписчики фабрик адаптеров не могут возвращать None::
+
+  >>> def M3(x, y):
+  ...     return None
+
+  >>> registry.subscribe([IR, IQ], IM, M3)
+  >>> subscribers = registry.subscribers((x, q), IM)
+  >>> len(subscribers)
+  2
+
+Обработчики
+-----------
+
+Обработчик - это подписанная фабрика которая не возвращает нормального
+значения. Она возвращает None. Обработчик отличается от адаптеров тем, что он
+делает всю работу когда вызывается фабрика.
+
+Для регистрации обработчика надо просто передать None как предоставляемый
+интерфейс::
+
+  >>> def handler(event):
+  ...     print 'handler', event
+
+  >>> registry.subscribe([IR1], None, handler)
+  >>> registry.subscriptions([IR1], None) == [handler]
+  True
diff --git a/src/zope/interface/adapter.txt b/src/zope/interface/adapter.txt
new file mode 100644 (file)
index 0000000..298a862
--- /dev/null
@@ -0,0 +1,543 @@
+================
+Adapter Registry
+================
+
+Adapter registries provide a way to register objects that depend on
+one or more interface specifications and provide (perhaps indirectly)
+some interface.  In addition, the registrations have names. (You can
+think of the names as qualifiers of the provided interfaces.)
+
+The term "interface specification" refers both to interfaces and to
+interface declarations, such as declarations of interfaces implemented
+by a class.
+
+
+Single Adapters
+===============
+
+Let's look at a simple example, using a single required specification::
+
+  >>> from zope.interface.adapter import AdapterRegistry
+  >>> import zope.interface
+
+  >>> class IR1(zope.interface.Interface):
+  ...     pass
+  >>> class IP1(zope.interface.Interface):
+  ...     pass
+  >>> class IP2(IP1):
+  ...     pass
+
+  >>> registry = AdapterRegistry()
+
+We'll register an object that depends on IR1 and "provides" IP2::
+
+  >>> registry.register([IR1], IP2, '', 12)
+
+Given the registration, we can look it up again::
+
+  >>> registry.lookup([IR1], IP2, '')
+  12
+
+Note that we used an integer in the example.  In real applications,
+one would use some objects that actually depend on or provide
+interfaces. The registry doesn't care about what gets registered, so
+we'll use integers and strings to keep the examples simple. There is
+one exception.  Registering a value of None unregisters any
+previously-registered value.
+
+If an object depends on a specification, it can be looked up with a
+specification that extends the specification that it depends on::
+
+  >>> class IR2(IR1):
+  ...     pass
+  >>> registry.lookup([IR2], IP2, '')
+  12
+
+We can use a class implementation specification to look up the object::
+
+  >>> class C2:
+  ...     zope.interface.implements(IR2)
+
+  >>> registry.lookup([zope.interface.implementedBy(C2)], IP2, '')
+  12
+
+
+and it can be looked up for interfaces that its provided interface
+extends::
+
+  >>> registry.lookup([IR1], IP1, '')
+  12
+  >>> registry.lookup([IR2], IP1, '')
+  12
+
+But if you require a specification that doesn't extend the specification the
+object depends on, you won't get anything::
+
+  >>> registry.lookup([zope.interface.Interface], IP1, '')
+
+By the way, you can pass a default value to lookup::
+
+  >>> registry.lookup([zope.interface.Interface], IP1, '', 42)
+  42
+
+If you try to get an interface the object doesn't provide, you also
+won't get anything::
+
+  >>> class IP3(IP2):
+  ...     pass
+  >>> registry.lookup([IR1], IP3, '')
+
+You also won't get anything if you use the wrong name::
+
+  >>> registry.lookup([IR1], IP1, 'bob')
+  >>> registry.register([IR1], IP2, 'bob', "Bob's 12")
+  >>> registry.lookup([IR1], IP1, 'bob')
+  "Bob's 12"
+
+You can leave the name off when doing a lookup::
+
+  >>> registry.lookup([IR1], IP1)
+  12
+
+If we register an object that provides IP1::
+
+  >>> registry.register([IR1], IP1, '', 11)
+
+then that object will be prefered over O(12)::
+
+  >>> registry.lookup([IR1], IP1, '')
+  11
+
+Also, if we register an object for IR2, then that will be prefered
+when using IR2::
+
+  >>> registry.register([IR2], IP1, '', 21)
+  >>> registry.lookup([IR2], IP1, '')
+  21
+
+Finding out what, if anything, is registered
+--------------------------------------------
+
+We can ask if there is an adapter registered for a collection of
+interfaces. This is different than lookup, because it looks for an
+exact match.
+
+  >>> print registry.registered([IR1], IP1)
+  11
+
+  >>> print registry.registered([IR1], IP2)
+  12
+
+  >>> print registry.registered([IR1], IP2, 'bob')
+  Bob's 12
+  
+
+  >>> print registry.registered([IR2], IP1)
+  21
+
+  >>> print registry.registered([IR2], IP2)
+  None
+
+In the last example, None was returned because nothing was registered
+exactly for the given interfaces.
+
+lookup1
+-------
+
+Lookup of single adapters is common enough that there is a specialized
+version of lookup that takes a single required interface::
+
+  >>> registry.lookup1(IR2, IP1, '')
+  21
+  >>> registry.lookup1(IR2, IP1)
+  21
+
+Actual Adaptation
+-----------------
+
+The adapter registry is intended to support adaptation, where one
+object that implements an interface is adapted to another object that
+supports a different interface.  The adapter registry supports the
+computation of adapters. In this case, we have to register adapter
+factories::
+
+   >>> class IR(zope.interface.Interface):
+   ...     pass
+
+   >>> class X:
+   ...     zope.interface.implements(IR)
+           
+   >>> class Y:
+   ...     zope.interface.implements(IP1)
+   ...     def __init__(self, context):
+   ...         self.context = context
+
+  >>> registry.register([IR], IP1, '', Y)
+
+In this case, we registered a class as the factory. Now we can call
+`queryAdapter` to get the adapted object::
+
+  >>> x = X()
+  >>> y = registry.queryAdapter(x, IP1)
+  >>> y.__class__.__name__
+  'Y'
+  >>> y.context is x
+  True
+
+We can register and lookup by name too::
+
+  >>> class Y2(Y):
+  ...     pass
+
+  >>> registry.register([IR], IP1, 'bob', Y2)
+  >>> y = registry.queryAdapter(x, IP1, 'bob')
+  >>> y.__class__.__name__
+  'Y2'
+  >>> y.context is x
+  True
+
+When the adapter factory produces `None`, then this is treated as if no
+adapter has been found. This allows us to prevent adaptation (when desired)
+and let the adapter factory determine whether adaptation is possible based on
+the state of the object being adapted.
+
+  >>> def factory(context):
+  ...     if context.name == 'object':
+  ...         return 'adapter'
+  ...     return None
+
+  >>> class Object(object):
+  ...     zope.interface.implements(IR)
+  ...     name = 'object'
+
+  >>> registry.register([IR], IP1, 'conditional', factory) 
+  >>> obj = Object()
+  >>> registry.queryAdapter(obj, IP1, 'conditional')
+  'adapter'
+  >>> obj.name = 'no object'
+  >>> registry.queryAdapter(obj, IP1, 'conditional') is None
+  True
+  >>> registry.queryAdapter(obj, IP1, 'conditional', 'default')
+  'default'
+
+An alternate method that provides the same function as `queryAdapter()` is
+`adapter_hook()`::
+
+  >>> y = registry.adapter_hook(IP1, x)
+  >>> y.__class__.__name__
+  'Y'
+  >>> y.context is x
+  True
+  >>> y = registry.adapter_hook(IP1, x, 'bob')
+  >>> y.__class__.__name__
+  'Y2'
+  >>> y.context is x
+  True
+
+The `adapter_hook()` simply switches the order of the object and
+interface arguments.  It is used to hook into the interface call
+mechanism.
+
+
+Default Adapters
+----------------
+  
+Sometimes, you want to provide an adapter that will adapt anything.
+For that, provide None as the required interface::
+
+  >>> registry.register([None], IP1, '', 1)
+  
+then we can use that adapter for interfaces we don't have specific
+adapters for::
+
+  >>> class IQ(zope.interface.Interface):
+  ...     pass
+  >>> registry.lookup([IQ], IP1, '')
+  1
+
+Of course, specific adapters are still used when applicable::
+
+  >>> registry.lookup([IR2], IP1, '')
+  21
+
+Class adapters
+--------------
+
+You can register adapters for class declarations, which is almost the
+same as registering them for a class::
+
+  >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', 'C21')
+  >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '')
+  'C21'
+
+Dict adapters
+-------------
+
+At some point it was impossible to register dictionary-based adapters due a
+bug. Let's make sure this works now:
+
+  >>> adapter = {}
+  >>> registry.register((), IQ, '', adapter)
+  >>> registry.lookup((), IQ, '') is adapter
+  True
+
+Unregistering
+-------------
+
+You can unregister by registering None, rather than an object::
+
+  >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', None)
+  >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '')
+  21
+
+Of course, this means that None can't be registered. This is an
+exception to the statement, made earlier, that the registry doesn't
+care what gets registered.
+
+Multi-adapters
+==============
+
+You can adapt multiple specifications::
+
+  >>> registry.register([IR1, IQ], IP2, '', '1q2')
+  >>> registry.lookup([IR1, IQ], IP2, '')
+  '1q2'
+  >>> registry.lookup([IR2, IQ], IP1, '')
+  '1q2'
+
+  >>> class IS(zope.interface.Interface):
+  ...     pass
+  >>> registry.lookup([IR2, IS], IP1, '')
+
+  >>> class IQ2(IQ):
+  ...     pass
+
+  >>> registry.lookup([IR2, IQ2], IP1, '')
+  '1q2'
+
+  >>> registry.register([IR1, IQ2], IP2, '', '1q22')
+  >>> registry.lookup([IR2, IQ2], IP1, '')
+  '1q22'
+
+Multi-adaptation
+----------------
+
+You can adapt multiple objects::
+
+  >>> class Q:
+  ...     zope.interface.implements(IQ)
+
+As with single adapters, we register a factory, which is often a class::
+
+  >>> class IM(zope.interface.Interface):
+  ...     pass
+  >>> class M:
+  ...     zope.interface.implements(IM)
+  ...     def __init__(self, x, q):
+  ...         self.x, self.q = x, q
+  >>> registry.register([IR, IQ], IM, '', M)
+
+And then we can call `queryMultiAdapter` to compute an adapter::
+
+  >>> q = Q()
+  >>> m = registry.queryMultiAdapter((x, q), IM)
+  >>> m.__class__.__name__
+  'M'
+  >>> m.x is x and m.q is q
+  True
+
+and, of course, we can use names::
+
+  >>> class M2(M):
+  ...     pass
+  >>> registry.register([IR, IQ], IM, 'bob', M2)
+  >>> m = registry.queryMultiAdapter((x, q), IM, 'bob')
+  >>> m.__class__.__name__
+  'M2'
+  >>> m.x is x and m.q is q
+  True
+  
+Default Adapters
+----------------
+
+As with single adapters, you can define default adapters by specifying
+None for the *first* specification::
+
+  >>> registry.register([None, IQ], IP2, '', 'q2')
+  >>> registry.lookup([IS, IQ], IP2, '')
+  'q2'
+
+Null Adapters
+=============
+
+You can also adapt no specification::
+
+  >>> registry.register([], IP2, '', 2)
+  >>> registry.lookup([], IP2, '')
+  2
+  >>> registry.lookup([], IP1, '')
+  2
+
+Listing named adapters
+----------------------
+
+Adapters are named. Sometimes, it's useful to get all of the named
+adapters for given interfaces::
+
+  >>> adapters = list(registry.lookupAll([IR1], IP1))
+  >>> adapters.sort()
+  >>> assert adapters == [(u'', 11), (u'bob', "Bob's 12")]
+
+This works for multi-adapters too::
+
+  >>> registry.register([IR1, IQ2], IP2, 'bob', '1q2 for bob')
+  >>> adapters = list(registry.lookupAll([IR2, IQ2], IP1))
+  >>> adapters.sort()
+  >>> assert adapters == [(u'', '1q22'), (u'bob', '1q2 for bob')]
+
+And even null adapters::
+
+  >>> registry.register([], IP2, 'bob', 3)
+  >>> adapters = list(registry.lookupAll([], IP1))
+  >>> adapters.sort()
+  >>> assert adapters == [(u'', 2), (u'bob', 3)]
+
+Subscriptions
+=============
+
+Normally, we want to look up an object that most-closely matches a
+specification.  Sometimes, we want to get all of the objects that
+match some specification.  We use subscriptions for this.  We
+subscribe objects against specifications and then later find all of
+the subscribed objects::
+
+  >>> registry.subscribe([IR1], IP2, 'sub12 1')
+  >>> registry.subscriptions([IR1], IP2)
+  ['sub12 1']
+
+Note that, unlike regular adapters, subscriptions are unnamed.
+
+You can have multiple subscribers for the same specification::
+
+  >>> registry.subscribe([IR1], IP2, 'sub12 2')
+  >>> registry.subscriptions([IR1], IP2)
+  ['sub12 1', 'sub12 2']
+
+If subscribers are registered for the same required interfaces, they
+are returned in the order of definition.
+
+You can register subscribers for all specifications using None::
+
+  >>> registry.subscribe([None], IP1, 'sub_1')
+  >>> registry.subscriptions([IR2], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2']
+
+Note that the new subscriber is returned first.  Subscribers defined
+for less general required interfaces are returned before subscribers
+for more general interfaces.
+
+Subscriptions may be combined over multiple compatible specifications::
+
+  >>> registry.subscriptions([IR2], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2']
+  >>> registry.subscribe([IR1], IP1, 'sub11')
+  >>> registry.subscriptions([IR2], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2', 'sub11']
+  >>> registry.subscribe([IR2], IP2, 'sub22')
+  >>> registry.subscriptions([IR2], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2', 'sub11', 'sub22']
+  >>> registry.subscriptions([IR2], IP2)
+  ['sub12 1', 'sub12 2', 'sub22']
+
+Subscriptions can be on multiple specifications::
+
+  >>> registry.subscribe([IR1, IQ], IP2, 'sub1q2')
+  >>> registry.subscriptions([IR1, IQ], IP2)
+  ['sub1q2']
+  
+As with single subscriptions and non-subscription adapters, you can
+specify None for the first required interface, to specify a default::
+
+  >>> registry.subscribe([None, IQ], IP2, 'sub_q2')
+  >>> registry.subscriptions([IS, IQ], IP2)
+  ['sub_q2']
+  >>> registry.subscriptions([IR1, IQ], IP2)
+  ['sub_q2', 'sub1q2']
+
+You can have subscriptions that are indepenent of any specifications::
+  
+  >>> list(registry.subscriptions([], IP1))
+  []
+
+  >>> registry.subscribe([], IP2, 'sub2')
+  >>> registry.subscriptions([], IP1)
+  ['sub2']
+  >>> registry.subscribe([], IP1, 'sub1')
+  >>> registry.subscriptions([], IP1)
+  ['sub2', 'sub1']
+  >>> registry.subscriptions([], IP2)
+  ['sub2']
+
+Unregistering subscribers
+-------------------------
+
+We can unregister subscribers.  When unregistering a subscriber, we
+can unregister a specific subscriber::
+
+  >>> registry.unsubscribe([IR1], IP1, 'sub11')
+  >>> registry.subscriptions([IR1], IP1)
+  ['sub_1', 'sub12 1', 'sub12 2']
+
+If we don't specify a value, then all subscribers matching the given
+interfaces will be unsubscribed:
+
+  >>> registry.unsubscribe([IR1], IP2)
+  >>> registry.subscriptions([IR1], IP1)
+  ['sub_1']
+
+
+Subscription adapters
+---------------------
+
+We normally register adapter factories, which then allow us to compute
+adapters, but with subscriptions, we get multiple adapters.  Here's an
+example of multiple-object subscribers::
+
+  >>> registry.subscribe([IR, IQ], IM, M)
+  >>> registry.subscribe([IR, IQ], IM, M2)
+
+  >>> subscribers = registry.subscribers((x, q), IM)
+  >>> len(subscribers)
+  2
+  >>> class_names = [s.__class__.__name__ for s in subscribers]
+  >>> class_names.sort()
+  >>> class_names
+  ['M', 'M2']
+  >>> [(s.x is x and s.q is q) for s in subscribers]
+  [True, True]
+
+adapter factory subcribers can't return None values::
+
+  >>> def M3(x, y):
+  ...     return None
+
+  >>> registry.subscribe([IR, IQ], IM, M3)
+  >>> subscribers = registry.subscribers((x, q), IM)
+  >>> len(subscribers)
+  2
+
+Handlers
+--------
+
+A handler is a subscriber factory that doesn't produce any normal
+output.  It returns None.  A handler is unlike adapters in that it does
+all of its work when the factory is called.
+
+To register a handler, simply provide None as the provided interface::
+
+  >>> def handler(event):
+  ...     print 'handler', event
+
+  >>> registry.subscribe([IR1], None, handler)
+  >>> registry.subscriptions([IR1], None) == [handler]
+  True
diff --git a/src/zope/interface/advice.py b/src/zope/interface/advice.py
new file mode 100644 (file)
index 0000000..d23818e
--- /dev/null
@@ -0,0 +1,201 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Class advice.
+
+This module was adapted from 'protocols.advice', part of the Python
+Enterprise Application Kit (PEAK).  Please notify the PEAK authors
+(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or
+Zope-specific changes are required, so that the PEAK version of this module
+can be kept in sync.
+
+PEAK is a Python application framework that interoperates with (but does
+not require) Zope 3 and Twisted.  It provides tools for manipulating UML
+models, object-relational persistence, aspect-oriented programming, and more.
+Visit the PEAK home page at http://peak.telecommunity.com for more information.
+"""
+
+from types import FunctionType
+try:
+    from types import ClassType
+    __python3 = False
+except ImportError:
+    __python3 = True
+    
+import sys
+
+def getFrameInfo(frame):
+    """Return (kind,module,locals,globals) for a frame
+
+    'kind' is one of "exec", "module", "class", "function call", or "unknown".
+    """
+
+    f_locals = frame.f_locals
+    f_globals = frame.f_globals
+
+    sameNamespace = f_locals is f_globals
+    hasModule = '__module__' in f_locals
+    hasName = '__name__' in f_globals
+
+    sameName = hasModule and hasName
+    sameName = sameName and f_globals['__name__']==f_locals['__module__']
+
+    module = hasName and sys.modules.get(f_globals['__name__']) or None
+
+    namespaceIsModule = module and module.__dict__ is f_globals
+
+    if not namespaceIsModule:
+        # some kind of funky exec
+        kind = "exec"
+    elif sameNamespace and not hasModule:
+        kind = "module"
+    elif sameName and not sameNamespace:
+        kind = "class"
+    elif not sameNamespace:
+        kind = "function call"
+    else:
+        # How can you have f_locals is f_globals, and have '__module__' set?
+        # This is probably module-level code, but with a '__module__' variable.
+        kind = "unknown"
+    return kind, module, f_locals, f_globals
+
+
+def addClassAdvisor(callback, depth=2):
+    """Set up 'callback' to be passed the containing class upon creation
+
+    This function is designed to be called by an "advising" function executed
+    in a class suite.  The "advising" function supplies a callback that it
+    wishes to have executed when the containing class is created.  The
+    callback will be given one argument: the newly created containing class.
+    The return value of the callback will be used in place of the class, so
+    the callback should return the input if it does not wish to replace the
+    class.
+
+    The optional 'depth' argument to this function determines the number of
+    frames between this function and the targeted class suite.  'depth'
+    defaults to 2, since this skips this function's frame and one calling
+    function frame.  If you use this function from a function called directly
+    in the class suite, the default will be correct, otherwise you will need
+    to determine the correct depth yourself.
+
+    This function works by installing a special class factory function in
+    place of the '__metaclass__' of the containing class.  Therefore, only
+    callbacks *after* the last '__metaclass__' assignment in the containing
+    class will be executed.  Be sure that classes using "advising" functions
+    declare any '__metaclass__' *first*, to ensure all callbacks are run."""
+
+    frame = sys._getframe(depth)
+    kind, module, caller_locals, caller_globals = getFrameInfo(frame)
+
+    # This causes a problem when zope interfaces are used from doctest.
+    # In these cases, kind == "exec".
+    #
+    #if kind != "class":
+    #    raise SyntaxError(
+    #        "Advice must be in the body of a class statement"
+    #    )
+
+    previousMetaclass = caller_locals.get('__metaclass__')
+    if __python3:
+        defaultMetaclass  = caller_globals.get('__metaclass__', type)
+    else:
+        defaultMetaclass  = caller_globals.get('__metaclass__', ClassType)
+
+
+    def advise(name, bases, cdict):
+
+        if '__metaclass__' in cdict:
+            del cdict['__metaclass__']
+
+        if previousMetaclass is None:
+            if bases:
+                # find best metaclass or use global __metaclass__ if no bases
+                meta = determineMetaclass(bases)
+            else:
+                meta = defaultMetaclass
+
+        elif isClassAdvisor(previousMetaclass):
+            # special case: we can't compute the "true" metaclass here,
+            # so we need to invoke the previous metaclass and let it
+            # figure it out for us (and apply its own advice in the process)
+            meta = previousMetaclass
+
+        else:
+            meta = determineMetaclass(bases, previousMetaclass)
+
+        newClass = meta(name,bases,cdict)
+
+        # this lets the callback replace the class completely, if it wants to
+        return callback(newClass)
+
+    # introspection data only, not used by inner function
+    advise.previousMetaclass = previousMetaclass
+    advise.callback = callback
+
+    # install the advisor
+    caller_locals['__metaclass__'] = advise
+
+
+def isClassAdvisor(ob):
+    """True if 'ob' is a class advisor function"""
+    return isinstance(ob,FunctionType) and hasattr(ob,'previousMetaclass')
+
+
+def determineMetaclass(bases, explicit_mc=None):
+    """Determine metaclass from 1+ bases and optional explicit __metaclass__"""
+
+    meta = [getattr(b,'__class__',type(b)) for b in bases]
+
+    if explicit_mc is not None:
+        # The explicit metaclass needs to be verified for compatibility
+        # as well, and allowed to resolve the incompatible bases, if any
+        meta.append(explicit_mc)
+
+    if len(meta)==1:
+        # easy case
+        return meta[0]
+
+    candidates = minimalBases(meta) # minimal set of metaclasses
+
+    if not candidates:
+        # they're all "classic" classes
+        assert(not __python3) # This should not happen under Python 3
+        return ClassType
+
+    elif len(candidates)>1:
+        # We could auto-combine, but for now we won't...
+        raise TypeError("Incompatible metatypes",bases)
+
+    # Just one, return it
+    return candidates[0]
+
+
+def minimalBases(classes):
+    """Reduce a list of base classes to its ordered minimum equivalent"""
+
+    if not __python3:
+        classes = [c for c in classes if c is not ClassType]
+    candidates = []
+
+    for m in classes:
+        for n in classes:
+            if issubclass(n,m) and m is not n:
+                break
+        else:
+            # m has no subclasses in 'classes'
+            if m in candidates:
+                candidates.remove(m)    # ensure that we're later in the list
+            candidates.append(m)
+
+    return candidates
+
diff --git a/src/zope/interface/common/__init__.py b/src/zope/interface/common/__init__.py
new file mode 100644 (file)
index 0000000..b711d36
--- /dev/null
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
diff --git a/src/zope/interface/common/idatetime.py b/src/zope/interface/common/idatetime.py
new file mode 100644 (file)
index 0000000..e8700af
--- /dev/null
@@ -0,0 +1,575 @@
+##############################################################################
+# Copyright (c) 2002 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.
+##############################################################################
+"""Datetime interfaces.
+
+This module is called idatetime because if it were called datetime the import
+of the real datetime would fail.
+"""
+
+from zope.interface import Interface, Attribute
+from zope.interface import classImplements
+
+from datetime import timedelta, date, datetime, time, tzinfo
+
+
+class ITimeDeltaClass(Interface):
+    """This is the timedelta class interface."""
+
+    min = Attribute("The most negative timedelta object")
+
+    max = Attribute("The most positive timedelta object")
+
+    resolution = Attribute(
+        "The smallest difference between non-equal timedelta objects")
+
+
+class ITimeDelta(ITimeDeltaClass):
+    """Represent the difference between two datetime objects.
+
+    Supported operators:
+
+    - add, subtract timedelta
+    - unary plus, minus, abs
+    - compare to timedelta
+    - multiply, divide by int/long
+
+    In addition, datetime supports subtraction of two datetime objects
+    returning a timedelta, and addition or subtraction of a datetime
+    and a timedelta giving a datetime.
+
+    Representation: (days, seconds, microseconds).
+    """
+
+    days = Attribute("Days between -999999999 and 999999999 inclusive")
+
+    seconds = Attribute("Seconds between 0 and 86399 inclusive")
+
+    microseconds = Attribute("Microseconds between 0 and 999999 inclusive")
+
+
+class IDateClass(Interface):
+    """This is the date class interface."""
+
+    min = Attribute("The earliest representable date")
+
+    max = Attribute("The latest representable date")
+
+    resolution = Attribute(
+        "The smallest difference between non-equal date objects")
+
+    def today():
+        """Return the current local time.
+
+        This is equivalent to date.fromtimestamp(time.time())"""
+
+    def fromtimestamp(timestamp):
+        """Return the local date from a POSIX timestamp (like time.time())
+
+        This may raise ValueError, if the timestamp is out of the range of
+        values supported by the platform C localtime() function. It's common
+        for this to be restricted to years from 1970 through 2038. Note that
+        on non-POSIX systems that include leap seconds in their notion of a
+        timestamp, leap seconds are ignored by fromtimestamp().
+        """
+
+    def fromordinal(ordinal):
+        """Return the date corresponding to the proleptic Gregorian ordinal.
+
+         January 1 of year 1 has ordinal 1. ValueError is raised unless
+         1 <= ordinal <= date.max.toordinal().
+         For any date d, date.fromordinal(d.toordinal()) == d.
+         """
+
+
+class IDate(IDateClass):
+    """Represents a date (year, month and day) in an idealized calendar.
+
+    Operators:
+
+    __repr__, __str__
+    __cmp__, __hash__
+    __add__, __radd__, __sub__ (add/radd only with timedelta arg)
+    """
+
+    year = Attribute("Between MINYEAR and MAXYEAR inclusive.")
+
+    month = Attribute("Between 1 and 12 inclusive")
+
+    day = Attribute(
+        "Between 1 and the number of days in the given month of the given year.")
+
+    def replace(year, month, day):
+        """Return a date with the same value.
+
+        Except for those members given new values by whichever keyword
+        arguments are specified. For example, if d == date(2002, 12, 31), then
+        d.replace(day=26) == date(2000, 12, 26). 
+        """
+
+    def timetuple():
+        """Return a 9-element tuple of the form returned by time.localtime().
+
+        The hours, minutes and seconds are 0, and the DST flag is -1.
+        d.timetuple() is equivalent to
+        (d.year, d.month, d.day, 0, 0, 0, d.weekday(), d.toordinal() -
+        date(d.year, 1, 1).toordinal() + 1, -1)
+        """
+
+    def toordinal():
+        """Return the proleptic Gregorian ordinal of the date
+
+        January 1 of year 1 has ordinal 1. For any date object d,
+        date.fromordinal(d.toordinal()) == d.
+        """
+
+    def weekday():
+        """Return the day of the week as an integer.
+
+        Monday is 0 and Sunday is 6. For example,
+        date(2002, 12, 4).weekday() == 2, a Wednesday.
+
+        See also isoweekday().
+        """
+
+    def isoweekday():
+        """Return the day of the week as an integer.
+
+        Monday is 1 and Sunday is 7. For example,
+        date(2002, 12, 4).isoweekday() == 3, a Wednesday.
+
+        See also weekday(), isocalendar().
+        """
+
+    def isocalendar():
+        """Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
+
+        The ISO calendar is a widely used variant of the Gregorian calendar.
+        See http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm for a good
+        explanation.
+
+        The ISO year consists of 52 or 53 full weeks, and where a week starts
+        on a Monday and ends on a Sunday. The first week of an ISO year is the
+        first (Gregorian) calendar week of a year containing a Thursday. This
+        is called week number 1, and the ISO year of that Thursday is the same
+        as its Gregorian year.
+
+        For example, 2004 begins on a Thursday, so the first week of ISO year
+        2004 begins on Monday, 29 Dec 2003 and ends on Sunday, 4 Jan 2004, so
+        that date(2003, 12, 29).isocalendar() == (2004, 1, 1) and
+        date(2004, 1, 4).isocalendar() == (2004, 1, 7).
+        """
+
+    def isoformat():
+        """Return a string representing the date in ISO 8601 format.
+
+        This is 'YYYY-MM-DD'.
+        For example, date(2002, 12, 4).isoformat() == '2002-12-04'.
+        """
+
+    def __str__():
+        """For a date d, str(d) is equivalent to d.isoformat()."""
+
+    def ctime():
+        """Return a string representing the date.
+
+        For example date(2002, 12, 4).ctime() == 'Wed Dec 4 00:00:00 2002'.
+        d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple()))
+        on platforms where the native C ctime() function
+        (which time.ctime() invokes, but which date.ctime() does not invoke)
+        conforms to the C standard.
+        """
+
+    def strftime(format):
+        """Return a string representing the date.
+
+        Controlled by an explicit format string. Format codes referring to
+        hours, minutes or seconds will see 0 values.
+        """
+
+
+class IDateTimeClass(Interface):
+    """This is the datetime class interface."""
+
+    min = Attribute("The earliest representable datetime")
+
+    max = Attribute("The latest representable datetime")
+
+    resolution = Attribute(
+        "The smallest possible difference between non-equal datetime objects")
+
+    def today():
+        """Return the current local datetime, with tzinfo None.
+
+        This is equivalent to datetime.fromtimestamp(time.time()).
+        See also now(), fromtimestamp().
+        """
+
+    def now(tz=None):
+        """Return the current local date and time.
+
+        If optional argument tz is None or not specified, this is like today(),
+        but, if possible, supplies more precision than can be gotten from going
+        through a time.time() timestamp (for example, this may be possible on
+        platforms supplying the C gettimeofday() function).
+
+        Else tz must be an instance of a class tzinfo subclass, and the current
+        date and time are converted to tz's time zone. In this case the result
+        is equivalent to tz.fromutc(datetime.utcnow().replace(tzinfo=tz)).
+
+        See also today(), utcnow().
+        """
+
+    def utcnow():
+        """Return the current UTC date and time, with tzinfo None.
+
+        This is like now(), but returns the current UTC date and time, as a
+        naive datetime object. 
+
+        See also now().
+        """
+
+    def fromtimestamp(timestamp, tz=None):
+        """Return the local date and time corresponding to the POSIX timestamp.
+
+        Same as is returned by time.time(). If optional argument tz is None or
+        not specified, the timestamp is converted to the platform's local date
+        and time, and the returned datetime object is naive.
+
+        Else tz must be an instance of a class tzinfo subclass, and the
+        timestamp is converted to tz's time zone. In this case the result is
+        equivalent to
+        tz.fromutc(datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz)).
+
+        fromtimestamp() may raise ValueError, if the timestamp is out of the
+        range of values supported by the platform C localtime() or gmtime()
+        functions. It's common for this to be restricted to years in 1970
+        through 2038. Note that on non-POSIX systems that include leap seconds
+        in their notion of a timestamp, leap seconds are ignored by
+        fromtimestamp(), and then it's possible to have two timestamps
+        differing by a second that yield identical datetime objects.
+
+        See also utcfromtimestamp().
+        """
+
+    def utcfromtimestamp(timestamp):
+        """Return the UTC datetime from the POSIX timestamp with tzinfo None.
+
+        This may raise ValueError, if the timestamp is out of the range of
+        values supported by the platform C gmtime() function. It's common for
+        this to be restricted to years in 1970 through 2038.
+
+        See also fromtimestamp().
+        """
+
+    def fromordinal(ordinal):
+        """Return the datetime from the proleptic Gregorian ordinal.
+
+        January 1 of year 1 has ordinal 1. ValueError is raised unless
+        1 <= ordinal <= datetime.max.toordinal().
+        The hour, minute, second and microsecond of the result are all 0, and
+        tzinfo is None.
+        """
+
+    def combine(date, time):
+        """Return a new datetime object.
+
+        Its date members are equal to the given date object's, and whose time
+        and tzinfo members are equal to the given time object's. For any
+        datetime object d, d == datetime.combine(d.date(), d.timetz()).
+        If date is a datetime object, its time and tzinfo members are ignored.
+        """
+
+
+class IDateTime(IDate, IDateTimeClass):
+    """Object contains all the information from a date object and a time object.
+    """
+
+    year = Attribute("Year between MINYEAR and MAXYEAR inclusive")
+
+    month = Attribute("Month between 1 and 12 inclusive")
+
+    day = Attribute(
+        "Day between 1 and the number of days in the given month of the year")
+
+    hour = Attribute("Hour in range(24)")
+
+    minute = Attribute("Minute in range(60)")
+
+    second = Attribute("Second in range(60)")
+
+    microsecond = Attribute("Microsecond in range(1000000)")
+
+    tzinfo = Attribute(
+        """The object passed as the tzinfo argument to the datetime constructor
+        or None if none was passed""")
+
+    def date():
+         """Return date object with same year, month and day."""
+
+    def time():
+        """Return time object with same hour, minute, second, microsecond.
+
+        tzinfo is None. See also method timetz().
+        """
+
+    def timetz():
+        """Return time object with same hour, minute, second, microsecond,
+        and tzinfo.
+
+        See also method time().
+        """
+
+    def replace(year, month, day, hour, minute, second, microsecond, tzinfo):
+        """Return a datetime with the same members, except for those members
+        given new values by whichever keyword arguments are specified.
+
+        Note that tzinfo=None can be specified to create a naive datetime from
+        an aware datetime with no conversion of date and time members.
+        """
+
+    def astimezone(tz):
+        """Return a datetime object with new tzinfo member tz, adjusting the
+        date and time members so the result is the same UTC time as self, but
+        in tz's local time.
+
+        tz must be an instance of a tzinfo subclass, and its utcoffset() and
+        dst() methods must not return None. self must be aware (self.tzinfo
+        must not be None, and self.utcoffset() must not return None).
+
+        If self.tzinfo is tz, self.astimezone(tz) is equal to self: no
+        adjustment of date or time members is performed. Else the result is
+        local time in time zone tz, representing the same UTC time as self:
+            after astz = dt.astimezone(tz), astz - astz.utcoffset()
+        will usually have the same date and time members as dt - dt.utcoffset().
+        The discussion of class tzinfo explains the cases at Daylight Saving
+        Time transition boundaries where this cannot be achieved (an issue only
+        if tz models both standard and daylight time).
+
+        If you merely want to attach a time zone object tz to a datetime dt
+        without adjustment of date and time members, use dt.replace(tzinfo=tz).
+        If you merely want to remove the time zone object from an aware
+        datetime dt without conversion of date and time members, use 
+        dt.replace(tzinfo=None).
+
+        Note that the default tzinfo.fromutc() method can be overridden in a
+        tzinfo subclass to effect the result returned by astimezone().
+        """
+
+    def utcoffset():
+        """Return the timezone offset in minutes east of UTC (negative west of
+        UTC)."""
+
+    def dst():
+        """Return 0 if DST is not in effect, or the DST offset (in minutes
+        eastward) if DST is in effect.
+        """
+
+    def tzname():
+        """Return the timezone name."""
+
+    def timetuple():
+        """Return a 9-element tuple of the form returned by time.localtime()."""
+
+    def utctimetuple():
+        """Return UTC time tuple compatilble with time.gmtimr()."""
+
+    def toordinal():
+        """Return the proleptic Gregorian ordinal of the date.
+
+        The same as self.date().toordinal().
+        """
+
+    def weekday():
+        """Return the day of the week as an integer.
+
+        Monday is 0 and Sunday is 6. The same as self.date().weekday().
+        See also isoweekday().
+        """
+
+    def isoweekday():
+        """Return the day of the week as an integer.
+
+        Monday is 1 and Sunday is 7. The same as self.date().isoweekday.
+        See also weekday(), isocalendar().
+        """
+
+    def isocalendar():
+        """Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
+
+        The same as self.date().isocalendar().
+        """
+
+    def isoformat(sep='T'):
+        """Return a string representing the date and time in ISO 8601 format.
+
+        YYYY-MM-DDTHH:MM:SS.mmmmmm or YYYY-MM-DDTHH:MM:SS if microsecond is 0
+
+        If utcoffset() does not return None, a 6-character string is appended,
+        giving the UTC offset in (signed) hours and minutes:
+
+        YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or YYYY-MM-DDTHH:MM:SS+HH:MM
+        if microsecond is 0.
+
+        The optional argument sep (default 'T') is a one-character separator,
+        placed between the date and time portions of the result.
+        """
+
+    def __str__():
+        """For a datetime instance d, str(d) is equivalent to d.isoformat(' ').
+        """
+
+    def ctime():
+        """Return a string representing the date and time.
+
+        datetime(2002, 12, 4, 20, 30, 40).ctime() == 'Wed Dec 4 20:30:40 2002'.
+        d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple())) on
+        platforms where the native C ctime() function (which time.ctime()
+        invokes, but which datetime.ctime() does not invoke) conforms to the
+        C standard.
+        """
+
+    def strftime(format):
+        """Return a string representing the date and time.
+
+        This is controlled by an explicit format string.
+        """
+
+
+class ITimeClass(Interface):
+    """This is the time class interface."""
+
+    min = Attribute("The earliest representable time")
+
+    max = Attribute("The latest representable time")
+
+    resolution = Attribute(
+        "The smallest possible difference between non-equal time objects")
+
+
+class ITime(ITimeClass):
+    """Represent time with time zone.
+
+    Operators:
+
+    __repr__, __str__
+    __cmp__, __hash__
+    """
+
+    hour = Attribute("Hour in range(24)")
+
+    minute = Attribute("Minute in range(60)")
+
+    second = Attribute("Second in range(60)")
+
+    microsecond = Attribute("Microsecond in range(1000000)")
+
+    tzinfo = Attribute(
+        """The object passed as the tzinfo argument to the time constructor
+        or None if none was passed.""")
+
+    def replace(hour, minute, second, microsecond, tzinfo):
+        """Return a time with the same value.
+
+        Except for those members given new values by whichever keyword
+        arguments are specified. Note that tzinfo=None can be specified
+        to create a naive time from an aware time, without conversion of the
+        time members.
+        """
+
+    def isoformat():
+        """Return a string representing the time in ISO 8601 format.
+
+        That is HH:MM:SS.mmmmmm or, if self.microsecond is 0, HH:MM:SS
+        If utcoffset() does not return None, a 6-character string is appended,
+        giving the UTC offset in (signed) hours and minutes:
+        HH:MM:SS.mmmmmm+HH:MM or, if self.microsecond is 0, HH:MM:SS+HH:MM
+        """
+
+    def __str__():
+        """For a time t, str(t) is equivalent to t.isoformat()."""
+
+    def strftime(format):
+        """Return a string representing the time.
+
+        This is controlled by an explicit format string.
+        """
+
+    def utcoffset():
+        """Return the timezone offset in minutes east of UTC (negative west of
+        UTC).
+
+        If tzinfo is None, returns None, else returns
+        self.tzinfo.utcoffset(None), and raises an exception if the latter
+        doesn't return None or a timedelta object representing a whole number
+        of minutes with magnitude less than one day.
+        """
+
+    def dst():
+        """Return 0 if DST is not in effect, or the DST offset (in minutes
+        eastward) if DST is in effect.
+
+        If tzinfo is None, returns None, else returns self.tzinfo.dst(None),
+        and raises an exception if the latter doesn't return None, or a
+        timedelta object representing a whole number of minutes with
+        magnitude less than one day.
+        """
+
+    def tzname():
+        """Return the timezone name.
+
+        If tzinfo is None, returns None, else returns self.tzinfo.tzname(None),
+        or raises an exception if the latter doesn't return None or a string
+        object.
+        """
+
+
+class ITZInfo(Interface):
+    """Time zone info class.
+    """
+
+    def utcoffset(dt):
+        """Return offset of local time from UTC, in minutes east of UTC.
+
+        If local time is west of UTC, this should be negative.
+        Note that this is intended to be the total offset from UTC;
+        for example, if a tzinfo object represents both time zone and DST
+        adjustments, utcoffset() should return their sum. If the UTC offset
+        isn't known, return None. Else the value returned must be a timedelta
+        object specifying a whole number of minutes in the range -1439 to 1439
+        inclusive (1440 = 24*60; the magnitude of the offset must be less
+        than one day).
+        """
+
+    def dst(dt):
+        """Return the daylight saving time (DST) adjustment, in minutes east
+        of UTC, or None if DST information isn't known.
+        """
+
+    def tzname(dt):
+        """Return the time zone name corresponding to the datetime object as
+        a string.
+        """
+
+    def fromutc(dt):
+        """Return an equivalent datetime in self's local time."""
+
+
+classImplements(timedelta, ITimeDelta)
+classImplements(date, IDate)
+classImplements(datetime, IDateTime)
+classImplements(time, ITime)
+classImplements(tzinfo, ITZInfo)
+
+## directlyProvides(timedelta, ITimeDeltaClass)
+## directlyProvides(date, IDateClass)
+## directlyProvides(datetime, IDateTimeClass)
+## directlyProvides(time, ITimeClass)
diff --git a/src/zope/interface/common/interfaces.py b/src/zope/interface/common/interfaces.py
new file mode 100644 (file)
index 0000000..47e9de7
--- /dev/null
@@ -0,0 +1,102 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Interfaces for standard python exceptions
+"""
+from zope.interface import Interface
+from zope.interface import classImplements
+
+class IException(Interface): pass
+class IStandardError(IException): pass
+class IWarning(IException): pass
+class ISyntaxError(IStandardError): pass
+class ILookupError(IStandardError): pass
+class IValueError(IStandardError): pass
+class IRuntimeError(IStandardError): pass
+class IArithmeticError(IStandardError): pass
+class IAssertionError(IStandardError): pass
+class IAttributeError(IStandardError): pass
+class IDeprecationWarning(IWarning): pass
+class IEOFError(IStandardError): pass
+class IEnvironmentError(IStandardError): pass
+class IFloatingPointError(IArithmeticError): pass
+class IIOError(IEnvironmentError): pass
+class IImportError(IStandardError): pass
+class IIndentationError(ISyntaxError): pass
+class IIndexError(ILookupError): pass
+class IKeyError(ILookupError): pass
+class IKeyboardInterrupt(IStandardError): pass
+class IMemoryError(IStandardError): pass
+class INameError(IStandardError): pass
+class INotImplementedError(IRuntimeError): pass
+class IOSError(IEnvironmentError): pass
+class IOverflowError(IArithmeticError): pass
+class IOverflowWarning(IWarning): pass
+class IReferenceError(IStandardError): pass
+class IRuntimeWarning(IWarning): pass
+class IStopIteration(IException): pass
+class ISyntaxWarning(IWarning): pass
+class ISystemError(IStandardError): pass
+class ISystemExit(IException): pass
+class ITabError(IIndentationError): pass
+class ITypeError(IStandardError): pass
+class IUnboundLocalError(INameError): pass
+class IUnicodeError(IValueError): pass
+class IUserWarning(IWarning): pass
+class IZeroDivisionError(IArithmeticError): pass
+
+classImplements(ArithmeticError, IArithmeticError)
+classImplements(AssertionError, IAssertionError)
+classImplements(AttributeError, IAttributeError)
+classImplements(DeprecationWarning, IDeprecationWarning)
+classImplements(EnvironmentError, IEnvironmentError)
+classImplements(EOFError, IEOFError)
+classImplements(Exception, IException)
+classImplements(FloatingPointError, IFloatingPointError)
+classImplements(ImportError, IImportError)
+classImplements(IndentationError, IIndentationError)
+classImplements(IndexError, IIndexError)
+classImplements(IOError, IIOError)
+classImplements(KeyboardInterrupt, IKeyboardInterrupt)
+classImplements(KeyError, IKeyError)
+classImplements(LookupError, ILookupError)
+classImplements(MemoryError, IMemoryError)
+classImplements(NameError, INameError)
+classImplements(NotImplementedError, INotImplementedError)
+classImplements(OSError, IOSError)
+classImplements(OverflowError, IOverflowError)
+try:
+    classImplements(OverflowWarning, IOverflowWarning)
+except NameError:
+    pass # OverflowWarning was removed in Python 2.5
+classImplements(ReferenceError, IReferenceError)
+classImplements(RuntimeError, IRuntimeError)
+classImplements(RuntimeWarning, IRuntimeWarning)
+try:
+    classImplements(StandardError, IStandardError)
+except NameError:
+    pass # StandardError does not exist in Python 3
+classImplements(StopIteration, IStopIteration)
+classImplements(SyntaxError, ISyntaxError)
+classImplements(SyntaxWarning, ISyntaxWarning)
+classImplements(SystemError, ISystemError)
+classImplements(SystemExit, ISystemExit)
+classImplements(TabError, ITabError)
+classImplements(TypeError, ITypeError)
+classImplements(UnboundLocalError, IUnboundLocalError)
+classImplements(UnicodeError, IUnicodeError)
+classImplements(UserWarning, IUserWarning)
+classImplements(ValueError, IValueError)
+classImplements(Warning, IWarning)
+classImplements(ZeroDivisionError, IZeroDivisionError)
+
diff --git a/src/zope/interface/common/mapping.py b/src/zope/interface/common/mapping.py
new file mode 100644 (file)
index 0000000..139715f
--- /dev/null
@@ -0,0 +1,125 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Mapping Interfaces
+"""
+from zope.interface import Interface
+
+class IItemMapping(Interface):
+    """Simplest readable mapping object
+    """
+
+    def __getitem__(key):
+        """Get a value for a key
+
+        A KeyError is raised if there is no value for the key.
+        """
+
+
+class IReadMapping(IItemMapping):
+    """Basic mapping interface
+    """
+
+    def get(key, default=None):
+        """Get a value for a key
+
+        The default is returned if there is no value for the key.
+        """
+
+    def __contains__(key):
+        """Tell if a key exists in the mapping."""
+
+
+class IWriteMapping(Interface):
+    """Mapping methods for changing data"""
+    
+    def __delitem__(key):
+        """Delete a value from the mapping using the key."""
+
+    def __setitem__(key, value):
+        """Set a new item in the mapping."""
+        
+
+class IEnumerableMapping(IReadMapping):
+    """Mapping objects whose items can be enumerated.
+    """
+
+    def keys():
+        """Return the keys of the mapping object.
+        """
+
+    def __iter__():
+        """Return an iterator for the keys of the mapping object.
+        """
+
+    def values():
+        """Return the values of the mapping object.
+        """
+
+    def items():
+        """Return the items of the mapping object.
+        """
+
+    def __len__():
+        """Return the number of items.
+        """
+
+class IMapping(IWriteMapping, IEnumerableMapping):
+    ''' Simple mapping interface '''
+
+class IIterableMapping(IEnumerableMapping):
+
+    def iterkeys():
+        "iterate over keys; equivalent to __iter__"
+
+    def itervalues():
+        "iterate over values"
+
+    def iteritems():
+        "iterate over items"
+
+class IClonableMapping(Interface):
+    
+    def copy():
+        "return copy of dict"
+
+class IExtendedReadMapping(IIterableMapping):
+    
+    def has_key(key):
+        """Tell if a key exists in the mapping; equivalent to __contains__"""
+
+class IExtendedWriteMapping(IWriteMapping):
+    
+    def clear():
+        "delete all items"
+    
+    def update(d):
+        " Update D from E: for k in E.keys(): D[k] = E[k]"
+    
+    def setdefault(key, default=None):
+        "D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"
+    
+    def pop(k, *args):
+        """remove specified key and return the corresponding value
+        *args may contain a single default value, or may not be supplied.
+        If key is not found, default is returned if given, otherwise 
+        KeyError is raised"""
+    
+    def popitem():
+        """remove and return some (key, value) pair as a
+        2-tuple; but raise KeyError if mapping is empty"""
+
+class IFullMapping(
+    IExtendedReadMapping, IExtendedWriteMapping, IClonableMapping, IMapping):
+    ''' Full mapping interface ''' # IMapping included so tests for IMapping
+    # succeed with IFullMapping
diff --git a/src/zope/interface/common/sequence.py b/src/zope/interface/common/sequence.py
new file mode 100644 (file)
index 0000000..223a94e
--- /dev/null
@@ -0,0 +1,160 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Sequence Interfaces
+"""
+__docformat__ = 'restructuredtext'
+from zope import interface
+
+class IMinimalSequence(interface.Interface):
+    """Most basic sequence interface.
+
+    All sequences are iterable.  This requires at least one of the
+    following:
+
+    - a `__getitem__()` method that takes a single argument; interger
+      values starting at 0 must be supported, and `IndexError` should
+      be raised for the first index for which there is no value, or
+
+    - an `__iter__()` method that returns an iterator as defined in
+      the Python documentation (http://docs.python.org/lib/typeiter.html).
+
+    """
+
+    def __getitem__(index):
+        """`x.__getitem__(index)` <==> `x[index]`
+
+        Declaring this interface does not specify whether `__getitem__`
+        supports slice objects."""
+
+class IFiniteSequence(IMinimalSequence):
+
+    def __len__():
+        """`x.__len__()` <==> `len(x)`"""
+
+class IReadSequence(IFiniteSequence):
+    """read interface shared by tuple and list"""
+
+    def __contains__(item):
+        """`x.__contains__(item)` <==> `item in x`"""
+
+    def __lt__(other):
+        """`x.__lt__(other)` <==> `x < other`"""
+
+    def __le__(other):
+        """`x.__le__(other)` <==> `x <= other`"""
+
+    def __eq__(other):
+        """`x.__eq__(other)` <==> `x == other`"""
+
+    def __ne__(other):
+        """`x.__ne__(other)` <==> `x != other`"""
+
+    def __gt__(other):
+        """`x.__gt__(other)` <==> `x > other`"""
+
+    def __ge__(other):
+        """`x.__ge__(other)` <==> `x >= other`"""
+
+    def __add__(other):
+        """`x.__add__(other)` <==> `x + other`"""
+
+    def __mul__(n):
+        """`x.__mul__(n)` <==> `x * n`"""
+
+    def __rmul__(n):
+        """`x.__rmul__(n)` <==> `n * x`"""
+
+    def __getslice__(i, j):
+        """`x.__getslice__(i, j)` <==> `x[i:j]`
+
+        Use of negative indices is not supported.
+
+        Deprecated since Python 2.0 but still a part of `UserList`.
+        """
+
+class IExtendedReadSequence(IReadSequence):
+    """Full read interface for lists"""
+
+    def count(item):
+        """Return number of occurrences of value"""
+
+    def index(item, *args):
+        """Return first index of value
+
+        `L.index(value, [start, [stop]])` -> integer"""
+
+class IUniqueMemberWriteSequence(interface.Interface):
+    """The write contract for a sequence that may enforce unique members"""
+
+    def __setitem__(index, item):
+        """`x.__setitem__(index, item)` <==> `x[index] = item`
+
+        Declaring this interface does not specify whether `__setitem__`
+        supports slice objects.
+        """
+
+    def __delitem__(index):
+        """`x.__delitem__(index)` <==> `del x[index]`
+
+        Declaring this interface does not specify whether `__delitem__`
+        supports slice objects.
+        """
+
+    def __setslice__(i, j, other):
+        """`x.__setslice__(i, j, other)` <==> `x[i:j]=other`
+
+        Use of negative indices is not supported.
+
+        Deprecated since Python 2.0 but still a part of `UserList`.
+        """
+
+    def __delslice__(i, j):
+        """`x.__delslice__(i, j)` <==> `del x[i:j]`
+
+        Use of negative indices is not supported.
+
+        Deprecated since Python 2.0 but still a part of `UserList`.
+        """
+    def __iadd__(y):
+        """`x.__iadd__(y)` <==> `x += y`"""
+
+    def append(item):
+        """Append item to end"""
+
+    def insert(index, item):
+        """Insert item before index"""
+
+    def pop(index=-1):
+        """Remove and return item at index (default last)"""
+
+    def remove(item):
+        """Remove first occurrence of value"""
+
+    def reverse():
+        """Reverse *IN PLACE*"""
+
+    def sort(cmpfunc=None):
+        """Stable sort *IN PLACE*; `cmpfunc(x, y)` -> -1, 0, 1"""
+
+    def extend(iterable):
+        """Extend list by appending elements from the iterable"""
+
+class IWriteSequence(IUniqueMemberWriteSequence):
+    """Full write contract for sequences"""
+
+    def __imul__(n):
+        """`x.__imul__(n)` <==> `x *= n`"""
+
+class ISequence(IReadSequence, IWriteSequence):
+    """Full sequence contract"""
diff --git a/src/zope/interface/common/tests/__init__.py b/src/zope/interface/common/tests/__init__.py
new file mode 100644 (file)
index 0000000..b711d36
--- /dev/null
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
diff --git a/src/zope/interface/common/tests/basemapping.py b/src/zope/interface/common/tests/basemapping.py
new file mode 100644 (file)
index 0000000..66f0ee4
--- /dev/null
@@ -0,0 +1,107 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Base Mapping tests
+"""
+from operator import __getitem__
+
+def testIReadMapping(self, inst, state, absent):
+    for key in state:
+        self.assertEqual(inst[key], state[key])
+        self.assertEqual(inst.get(key, None), state[key])
+        self.failUnless(key in inst)
+
+    for key in absent:
+        self.assertEqual(inst.get(key, None), None)
+        self.assertEqual(inst.get(key), None)
+        self.assertEqual(inst.get(key, self), self)
+        self.assertRaises(KeyError, __getitem__, inst, key)
+
+
+def test_keys(self, inst, state):
+    # Return the keys of the mapping object
+    inst_keys = list(inst.keys()); inst_keys.sort()
+    state_keys = list(state.keys()) ; state_keys.sort()
+    self.assertEqual(inst_keys, state_keys)
+
+def test_iter(self, inst, state):
+    # Return the keys of the mapping object
+    inst_keys = list(inst); inst_keys.sort()
+    state_keys = list(state.keys()) ; state_keys.sort()
+    self.assertEqual(inst_keys, state_keys)
+
+def test_values(self, inst, state):
+    # Return the values of the mapping object
+    inst_values = list(inst.values()); inst_values.sort()
+    state_values = list(state.values()) ; state_values.sort()
+    self.assertEqual(inst_values, state_values)
+
+def test_items(self, inst, state):
+    # Return the items of the mapping object
+    inst_items = list(inst.items()); inst_items.sort()
+    state_items = list(state.items()) ; state_items.sort()
+    self.assertEqual(inst_items, state_items)
+
+def test___len__(self, inst, state):
+    # Return the number of items
+    self.assertEqual(len(inst), len(state))
+
+def testIEnumerableMapping(self, inst, state):
+    test_keys(self, inst, state)
+    test_items(self, inst, state)
+    test_values(self, inst, state)
+    test___len__(self, inst, state)
+
+
+class BaseTestIReadMapping(object):
+    def testIReadMapping(self):
+        inst = self._IReadMapping__sample()
+        state = self._IReadMapping__stateDict()
+        absent = self._IReadMapping__absentKeys()
+        testIReadMapping(self, inst, state, absent)
+
+
+class BaseTestIEnumerableMapping(BaseTestIReadMapping):
+    # Mapping objects whose items can be enumerated
+    def test_keys(self):
+        # Return the keys of the mapping object
+        inst = self._IEnumerableMapping__sample()
+        state = self._IEnumerableMapping__stateDict()
+        test_keys(self, inst, state)
+
+    def test_values(self):
+        # Return the values of the mapping object
+        inst = self._IEnumerableMapping__sample()
+        state = self._IEnumerableMapping__stateDict()
+        test_values(self, inst, state)
+
+    def test_items(self):
+        # Return the items of the mapping object
+        inst = self._IEnumerableMapping__sample()
+        state = self._IEnumerableMapping__stateDict()
+        test_items(self, inst, state)
+
+    def test___len__(self):
+        # Return the number of items
+        inst = self._IEnumerableMapping__sample()
+        state = self._IEnumerableMapping__stateDict()
+        test___len__(self, inst, state)
+
+    def _IReadMapping__stateDict(self):
+        return self._IEnumerableMapping__stateDict()
+
+    def _IReadMapping__sample(self):
+        return self._IEnumerableMapping__sample()
+
+    def _IReadMapping__absentKeys(self):
+        return self._IEnumerableMapping__absentKeys()
diff --git a/src/zope/interface/common/tests/test_idatetime.py b/src/zope/interface/common/tests/test_idatetime.py
new file mode 100644 (file)
index 0000000..60f377e
--- /dev/null
@@ -0,0 +1,47 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Test for datetime interfaces
+"""
+
+import unittest
+
+from zope.interface.verify import verifyObject, verifyClass
+from zope.interface.common.idatetime import ITimeDelta, ITimeDeltaClass
+from zope.interface.common.idatetime import IDate, IDateClass
+from zope.interface.common.idatetime import IDateTime, IDateTimeClass
+from zope.interface.common.idatetime import ITime, ITimeClass, ITZInfo
+from datetime import timedelta, date, datetime, time, tzinfo
+
+class TestDateTimeInterfaces(unittest.TestCase):
+
+    def test_interfaces(self):
+        verifyObject(ITimeDelta, timedelta(minutes=20))
+        verifyObject(IDate, date(2000, 1, 2))
+        verifyObject(IDateTime, datetime(2000, 1, 2, 10, 20))
+        verifyObject(ITime, time(20, 30, 15, 1234))
+        verifyObject(ITZInfo, tzinfo())
+        verifyClass(ITimeDeltaClass, timedelta)
+        verifyClass(IDateClass, date)
+        verifyClass(IDateTimeClass, datetime)
+        verifyClass(ITimeClass, time)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestDateTimeInterfaces))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/zope/interface/common/tests/test_import_interfaces.py b/src/zope/interface/common/tests/test_import_interfaces.py
new file mode 100644 (file)
index 0000000..1473a53
--- /dev/null
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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 doctest
+import unittest
+
+def test_interface_import():
+    """
+    >>> import zope.interface.common.interfaces
+    """
+
+def test_suite():
+    return unittest.TestSuite((
+        doctest.DocTestSuite(),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+
diff --git a/src/zope/interface/declarations.py b/src/zope/interface/declarations.py
new file mode 100644 (file)
index 0000000..3ee27c4
--- /dev/null
@@ -0,0 +1,1395 @@
+##############################################################################
+# Copyright (c) 2003 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.
+##############################################################################
+"""Implementation of interface declarations
+
+There are three flavors of declarations:
+
+  - Declarations are used to simply name declared interfaces.
+
+  - ImplementsDeclarations are used to express the interfaces that a
+    class implements (that instances of the class provides).
+
+    Implements specifications support inheriting interfaces.
+
+  - ProvidesDeclarations are used to express interfaces directly
+    provided by objects.
+
+"""
+__docformat__ = 'restructuredtext'
+
+import sys
+import weakref
+from zope.interface.interface import InterfaceClass, Specification
+from zope.interface.interface import SpecificationBase
+from types import ModuleType, MethodType, FunctionType
+from zope.interface.advice import addClassAdvisor
+
+# Registry of class-implementation specifications
+BuiltinImplementationSpecifications = {}
+
+class Declaration(Specification):
+    """Interface declarations"""
+
+    def __init__(self, *interfaces):
+        Specification.__init__(self, _normalizeargs(interfaces))
+
+    def changed(self, originally_changed):
+        Specification.changed(self, originally_changed)
+        try:
+            del self._v_attrs
+        except AttributeError:
+            pass
+
+    def __contains__(self, interface):
+        """Test whether an interface is in the specification
+
+        for example:
+
+          >>> from zope.interface import Interface
+          >>> class I1(Interface): pass
+          ...
+          >>> class I2(I1): pass
+          ...
+          >>> class I3(Interface): pass
+          ...
+          >>> class I4(I3): pass
+          ...
+          >>> spec = Declaration(I2, I3)
+          >>> spec = Declaration(I4, spec)
+          >>> int(I1 in spec)
+          0
+          >>> int(I2 in spec)
+          1
+          >>> int(I3 in spec)
+          1
+          >>> int(I4 in spec)
+          1
+        """
+        return self.extends(interface) and interface in self.interfaces()
+
+    def __iter__(self):
+        """Return an iterator for the interfaces in the specification
+
+        for example:
+
+          >>> from zope.interface import Interface
+          >>> class I1(Interface): pass
+          ...
+          >>> class I2(I1): pass
+          ...
+          >>> class I3(Interface): pass
+          ...
+          >>> class I4(I3): pass
+          ...
+          >>> spec = Declaration(I2, I3)
+          >>> spec = Declaration(I4, spec)
+          >>> i = iter(spec)
+          >>> [x.getName() for x in i]
+          ['I4', 'I2', 'I3']
+          >>> list(i)
+          []
+        """
+        return self.interfaces()
+
+    def flattened(self):
+        """Return an iterator of all included and extended interfaces
+
+        for example:
+
+          >>> from zope.interface import Interface
+          >>> class I1(Interface): pass
+          ...
+          >>> class I2(I1): pass
+          ...
+          >>> class I3(Interface): pass
+          ...
+          >>> class I4(I3): pass
+          ...
+          >>> spec = Declaration(I2, I3)
+          >>> spec = Declaration(I4, spec)
+          >>> i = spec.flattened()
+          >>> [x.getName() for x in i]
+          ['I4', 'I2', 'I1', 'I3', 'Interface']
+          >>> list(i)
+          []
+
+        """
+        return iter(self.__iro__)
+
+    def __sub__(self, other):
+        """Remove interfaces from a specification
+
+        Examples:
+
+          >>> from zope.interface import Interface
+          >>> class I1(Interface): pass
+          ...
+          >>> class I2(I1): pass
+          ...
+          >>> class I3(Interface): pass
+          ...
+          >>> class I4(I3): pass
+          ...
+          >>> spec = Declaration()
+          >>> [iface.getName() for iface in spec]
+          []
+          >>> spec -= I1
+          >>> [iface.getName() for iface in spec]
+          []
+          >>> spec -= Declaration(I1, I2)
+          >>> [iface.getName() for iface in spec]
+          []
+          >>> spec = Declaration(I2, I4)
+          >>> [iface.getName() for iface in spec]
+          ['I2', 'I4']
+          >>> [iface.getName() for iface in spec - I4]
+          ['I2']
+          >>> [iface.getName() for iface in spec - I1]
+          ['I4']
+          >>> [iface.getName() for iface
+          ...  in spec - Declaration(I3, I4)]
+          ['I2']
+
+        """
+
+        return Declaration(
+            *[i for i in self.interfaces()
+                if not [j for j in other.interfaces()
+                        if i.extends(j, 0)]
+                ]
+                )
+
+    def __add__(self, other):
+        """Add two specifications or a specification and an interface
+
+        Examples:
+
+          >>> from zope.interface import Interface
+          >>> class I1(Interface): pass
+          ...
+          >>> class I2(I1): pass
+          ...
+          >>> class I3(Interface): pass
+          ...
+          >>> class I4(I3): pass
+          ...
+          >>> spec = Declaration()
+          >>> [iface.getName() for iface in spec]
+          []
+          >>> [iface.getName() for iface in spec+I1]
+          ['I1']
+          >>> [iface.getName() for iface in I1+spec]
+          ['I1']
+          >>> spec2 = spec
+          >>> spec += I1
+          >>> [iface.getName() for iface in spec]
+          ['I1']
+          >>> [iface.getName() for iface in spec2]
+          []
+          >>> spec2 += Declaration(I3, I4)
+          >>> [iface.getName() for iface in spec2]
+          ['I3', 'I4']
+          >>> [iface.getName() for iface in spec+spec2]
+          ['I1', 'I3', 'I4']
+          >>> [iface.getName() for iface in spec2+spec]
+          ['I3', 'I4', 'I1']
+
+        """
+
+        seen = {}
+        result = []
+        for i in self.interfaces():
+            if i not in seen:
+                seen[i] = 1
+                result.append(i)
+        for i in other.interfaces():
+            if i not in seen:
+                seen[i] = 1
+                result.append(i)
+
+        return Declaration(*result)
+
+    __radd__ = __add__
+
+
+##############################################################################
+#
+# Implementation specifications
+#
+# These specify interfaces implemented by instances of classes
+
+class Implements(Declaration):
+
+    # class whose specification should be used as additional base
+    inherit = None
+
+    # interfaces actually declared for a class
+    declared = ()
+
+    __name__ = '?'
+
+    def __repr__(self):
+        return '<implementedBy %s>' % (self.__name__)
+
+    def __reduce__(self):
+        return implementedBy, (self.inherit, )
+
+def implementedByFallback(cls):
+    """Return the interfaces implemented for a class' instances
+
+      The value returned is an IDeclaration.
+
+      for example:
+
+        >>> from zope.interface import Interface
+        >>> class I1(Interface): pass
+        ...
+        >>> class I2(I1): pass
+        ...
+        >>> class I3(Interface): pass
+        ...
+        >>> class I4(I3): pass
+        ...
+        >>> class C1(object):
+        ...   implements(I2)
+        >>> class C2(C1):
+        ...   implements(I3)
+        >>> [i.getName() for i in implementedBy(C2)]
+        ['I3', 'I2']
+
+      Really, any object should be able to receive a successful answer, even
+      an instance:
+
+        >>> class Callable(object):
+        ...     def __call__(self):
+        ...         return self
+
+        >>> implementedBy(Callable())
+        <implementedBy zope.interface.declarations.?>
+
+      Note that the name of the spec ends with a '?', because the `Callable`
+      instance does not have a `__name__` attribute.
+      """
+    # This also manages storage of implementation specifications
+
+    try:
+        spec = cls.__dict__.get('__implemented__')
+    except AttributeError:
+
+        # we can't get the class dict. This is probably due to a
+        # security proxy.  If this is the case, then probably no
+        # descriptor was installed for the class.
+
+        # We don't want to depend directly on zope.security in
+        # zope.interface, but we'll try to make reasonable
+        # accommodations in an indirect way.
+
+        # We'll check to see if there's an implements:
+
+        spec = getattr(cls, '__implemented__', None)
+        if spec is None:
+            # There's no spec stred in the class. Maybe its a builtin:
+            spec = BuiltinImplementationSpecifications.get(cls)
+            if spec is not None:
+                return spec
+            return _empty
+
+        if spec.__class__ == Implements:
+            # we defaulted to _empty or there was a spec. Good enough.
+            # Return it.
+            return spec
+
+        # TODO: need old style __implements__ compatibility?
+        # Hm, there's an __implemented__, but it's not a spec. Must be
+        # an old-style declaration. Just compute a spec for it
+        return Declaration(*_normalizeargs((spec, )))
+
+    if isinstance(spec, Implements):
+        return spec
+
+    if spec is None:
+        spec = BuiltinImplementationSpecifications.get(cls)
+        if spec is not None:
+            return spec
+
+    # TODO: need old style __implements__ compatibility?
+    if spec is not None:
+        # old-style __implemented__ = foo declaration
+        spec = (spec, ) # tuplefy, as it might be just an int
+        spec = Implements(*_normalizeargs(spec))
+        spec.inherit = None    # old-style implies no inherit
+        del cls.__implemented__ # get rid of the old-style declaration
+    else:
+        try:
+            bases = cls.__bases__
+        except AttributeError:
+            if not callable(cls):
+                raise TypeError("ImplementedBy called for non-factory", cls)
+            bases = ()
+
+        spec = Implements(*[implementedBy(c) for c in bases])
+        spec.inherit = cls
+
+    spec.__name__ = (getattr(cls, '__module__', '?') or '?') + \
+                    '.' + (getattr(cls, '__name__', '?') or '?')
+
+    try:
+        cls.__implemented__ = spec
+        if not hasattr(cls, '__providedBy__'):
+            cls.__providedBy__ = objectSpecificationDescriptor
+
+        if (isinstance(cls, DescriptorAwareMetaClasses)
+            and
+            '__provides__' not in cls.__dict__):
+            # Make sure we get a __provides__ descriptor
+            cls.__provides__ = ClassProvides(
+                cls,
+                getattr(cls, '__class__', type(cls)),
+                )
+
+    except TypeError:
+        if not isinstance(cls, type):
+            raise TypeError("ImplementedBy called for non-type", cls)
+        BuiltinImplementationSpecifications[cls] = spec
+
+    return spec
+
+implementedBy = implementedByFallback
+
+def classImplementsOnly(cls, *interfaces):
+    """Declare the only interfaces implemented by instances of a class
+
+      The arguments after the class are one or more interfaces or interface
+      specifications (``IDeclaration`` objects).
+
+      The interfaces given (including the interfaces in the specifications)
+      replace any previous declarations.
+
+      Consider the following example:
+
+        >>> from zope.interface import Interface
+        >>> class I1(Interface): pass
+        ...
+        >>> class I2(Interface): pass
+        ...
+        >>> class I3(Interface): pass
+        ...
+        >>> class I4(Interface): pass
+        ...
+        >>> class A(object):
+        ...   implements(I3)
+        >>> class B(object):
+        ...   implements(I4)
+        >>> class C(A, B):
+        ...   pass
+        >>> classImplementsOnly(C, I1, I2)
+        >>> [i.getName() for i in implementedBy(C)]
+        ['I1', 'I2']
+
+      Instances of ``C`` provide only ``I1``, ``I2``, and regardless of
+      whatever interfaces instances of ``A`` and ``B`` implement.
+      """
+    spec = implementedBy(cls)
+    spec.declared = ()
+    spec.inherit = None
+    classImplements(cls, *interfaces)
+
+def classImplements(cls, *interfaces):
+    """Declare additional interfaces implemented for instances of a class
+
+      The arguments after the class are one or more interfaces or
+      interface specifications (``IDeclaration`` objects).
+
+      The interfaces given (including the interfaces in the specifications)
+      are added to any interfaces previously declared.
+
+      Consider the following example:
+
+        >>> from zope.interface import Interface
+        >>> class I1(Interface): pass
+        ...
+        >>> class I2(Interface): pass
+        ...
+        >>> class I3(Interface): pass
+        ...
+        >>> class I4(Interface): pass
+        ...
+        >>> class I5(Interface): pass
+        ...
+        >>> class A(object):
+        ...   implements(I3)
+        >>> class B(object):
+        ...   implements(I4)
+        >>> class C(A, B):
+        ...   pass
+        >>> classImplements(C, I1, I2)
+        >>> [i.getName() for i in implementedBy(C)]
+        ['I1', 'I2', 'I3', 'I4']
+        >>> classImplements(C, I5)
+        >>> [i.getName() for i in implementedBy(C)]
+        ['I1', 'I2', 'I5', 'I3', 'I4']
+
+      Instances of ``C`` provide ``I1``, ``I2``, ``I5``, and whatever
+      interfaces instances of ``A`` and ``B`` provide.
+      """
+
+    spec = implementedBy(cls)
+    spec.declared += tuple(_normalizeargs(interfaces))
+
+    # compute the bases
+    bases = []
+    seen = {}
+    for b in spec.declared:
+        if b not in seen:
+            seen[b] = 1
+            bases.append(b)
+
+    if spec.inherit is not None:
+
+        for c in spec.inherit.__bases__:
+            b = implementedBy(c)
+            if b not in seen:
+                seen[b] = 1
+                bases.append(b)            
+
+    spec.__bases__ = tuple(bases)
+
+def _implements_advice(cls):
+    interfaces, classImplements = cls.__dict__['__implements_advice_data__']
+    del cls.__implements_advice_data__
+    classImplements(cls, *interfaces)
+    return cls
+
+
+class implementer:
+
+    def __init__(self, *interfaces):
+        self.interfaces = interfaces
+
+    def __call__(self, ob):
+        if isinstance(ob, DescriptorAwareMetaClasses):
+            classImplements(ob, *self.interfaces)
+            return ob            
+        
+        spec = Implements(*self.interfaces)
+        try:
+            ob.__implemented__ = spec
+        except AttributeError:
+            raise TypeError("Can't declare implements", ob)
+        return ob
+
+class implementer_only:
+
+    def __init__(self, *interfaces):
+        self.interfaces = interfaces
+
+    def __call__(self, ob):
+        if isinstance(ob, (FunctionType, MethodType)):
+            # XXX Does this decorator make sense for anything but classes?
+            # I don't think so. There can be no inheritance of interfaces
+            # on a method pr function....
+            raise ValueError('The implementor_only decorator is not '
+                             'supported for methods or functions.')
+        else:
+            # Assume it's a class:
+            classImplementsOnly(ob, *self.interfaces)
+            return ob            
+        
+def _implements(name, interfaces, classImplements):
+    frame = sys._getframe(2)
+    locals = frame.f_locals
+
+    # Try to make sure we were called from a class def. In 2.2.0 we can't
+    # check for __module__ since it doesn't seem to be added to the locals
+    # until later on.
+    if (locals is frame.f_globals) or (
+        ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)):
+        raise TypeError(name+" can be used only from a class definition.")
+
+    if '__implements_advice_data__' in locals:
+        raise TypeError(name+" can be used only once in a class definition.")
+
+    locals['__implements_advice_data__'] = interfaces, classImplements
+    addClassAdvisor(_implements_advice, depth=3)
+
+def implements(*interfaces):
+    """Declare interfaces implemented by instances of a class
+
+      This function is called in a class definition.
+
+      The arguments are one or more interfaces or interface
+      specifications (IDeclaration objects).
+
+      The interfaces given (including the interfaces in the
+      specifications) are added to any interfaces previously
+      declared.
+
+      Previous declarations include declarations for base classes
+      unless implementsOnly was used.
+
+      This function is provided for convenience. It provides a more
+      convenient way to call classImplements. For example::
+
+        implements(I1)
+
+      is equivalent to calling::
+
+        classImplements(C, I1)
+
+      after the class has been created.
+
+      Consider the following example::
+
+
+        >>> from zope.interface import Interface
+        >>> class IA1(Interface): pass
+        ...
+        >>> class IA2(Interface): pass
+        ...
+        >>> class IB(Interface): pass
+        ...
+        >>> class IC(Interface): pass
+        ...
+        >>> class A(object):
+        ...     implements(IA1, IA2)
+        >>> class B(object):
+        ...     implements(IB)
+
+        >>> class C(A, B):
+        ...    implements(IC)
+
+        >>> ob = C()
+        >>> int(IA1 in providedBy(ob))
+        1
+        >>> int(IA2 in providedBy(ob))
+        1
+        >>> int(IB in providedBy(ob))
+        1
+        >>> int(IC in providedBy(ob))
+        1
+
+      Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces
+      instances of ``A`` and ``B`` implement.
+
+      """
+    _implements("implements", interfaces, classImplements)
+
+def implementsOnly(*interfaces):
+    """Declare the only interfaces implemented by instances of a class
+
+      This function is called in a class definition.
+
+      The arguments are one or more interfaces or interface
+      specifications (IDeclaration objects).
+
+      Previous declarations including declarations for base classes
+      are overridden.
+
+      This function is provided for convenience. It provides a more
+      convenient way to call classImplementsOnly. For example::
+
+        implementsOnly(I1)
+
+      is equivalent to calling::
+
+        classImplementsOnly(I1)
+
+      after the class has been created.
+
+      Consider the following example::
+
+        >>> from zope.interface import Interface
+        >>> class IA1(Interface): pass
+        ...
+        >>> class IA2(Interface): pass
+        ...
+        >>> class IB(Interface): pass
+        ...
+        >>> class IC(Interface): pass
+        ...
+        >>> class A(object):
+        ...     implements(IA1, IA2)
+        >>> class B(object):
+        ...     implements(IB)
+
+        >>> class C(A, B):
+        ...    implementsOnly(IC)
+
+        >>> ob = C()
+        >>> int(IA1 in providedBy(ob))
+        0
+        >>> int(IA2 in providedBy(ob))
+        0
+        >>> int(IB in providedBy(ob))
+        0
+        >>> int(IC in providedBy(ob))
+        1
+
+
+      Instances of ``C`` implement ``IC``, regardless of what
+      instances of ``A`` and ``B`` implement.
+
+      """
+    _implements("implementsOnly", interfaces, classImplementsOnly)
+
+##############################################################################
+#
+# Instance declarations
+
+class Provides(Declaration):  # Really named ProvidesClass
+    """Implement __provides__, the instance-specific specification
+
+    When an object is pickled, we pickle the interfaces that it implements.
+    """
+
+    def __init__(self, cls, *interfaces):
+        self.__args = (cls, ) + interfaces
+        self._cls = cls
+        Declaration.__init__(self, *(interfaces + (implementedBy(cls), )))
+
+    def __reduce__(self):
+        return Provides, self.__args
+
+    __module__ = 'zope.interface'
+
+    def __get__(self, inst, cls):
+        """Make sure that a class __provides__ doesn't leak to an instance
+
+        For example:
+
+          >>> from zope.interface import Interface
+          >>> class IFooFactory(Interface): pass
+          ...
+
+          >>> class C(object):
+          ...   pass
+
+          >>> C.__provides__ = ProvidesClass(C, IFooFactory)
+          >>> [i.getName() for i in C.__provides__]
+          ['IFooFactory']
+          >>> getattr(C(), '__provides__', 0)
+          0
+
+        """
+        if inst is None and cls is self._cls:
+            # We were accessed through a class, so we are the class'
+            # provides spec. Just return this object, but only if we are
+            # being called on the same class that we were defined for:
+            return self
+
+        raise AttributeError('__provides__')
+
+ProvidesClass = Provides
+
+# Registry of instance declarations
+# This is a memory optimization to allow objects to share specifications.
+InstanceDeclarations = weakref.WeakValueDictionary()
+
+def Provides(*interfaces):
+    """Cache instance declarations
+
+      Instance declarations are shared among instances that have the same
+      declaration. The declarations are cached in a weak value dictionary.
+
+      (Note that, in the examples below, we are going to make assertions about
+       the size of the weakvalue dictionary.  For the assertions to be
+       meaningful, we need to force garbage collection to make sure garbage
+       objects are, indeed, removed from the system. Depending on how Python
+       is run, we may need to make multiple calls to be sure.  We provide a
+       collect function to help with this:
+
+       >>> import gc
+       >>> def collect():
+       ...     for i in range(4):
+       ...         gc.collect()
+
+      )
+
+      >>> collect()
+      >>> before = len(InstanceDeclarations)
+
+      >>> class C(object):
+      ...    pass
+
+      >>> from zope.interface import Interface
+      >>> class I(Interface):
+      ...    pass
+
+      >>> c1 = C()
+      >>> c2 = C()
+
+      >>> len(InstanceDeclarations) == before
+      1
+
+      >>> directlyProvides(c1, I)
+      >>> len(InstanceDeclarations) == before + 1
+      1
+
+      >>> directlyProvides(c2, I)
+      >>> len(InstanceDeclarations) == before + 1
+      1
+
+      >>> del c1
+      >>> collect()
+      >>> len(InstanceDeclarations) == before + 1
+      1
+
+      >>> del c2
+      >>> collect()
+      >>> len(InstanceDeclarations) == before
+      1
+      """
+
+    spec = InstanceDeclarations.get(interfaces)
+    if spec is None:
+        spec = ProvidesClass(*interfaces)
+        InstanceDeclarations[interfaces] = spec
+
+    return spec
+Provides.__safe_for_unpickling__ = True
+
+try:
+    from types import ClassType
+    DescriptorAwareMetaClasses = ClassType, type
+except ImportError: # Python 3
+    DescriptorAwareMetaClasses = (type,)
+    
+def directlyProvides(object, *interfaces):
+    """Declare interfaces declared directly for an object
+
+      The arguments after the object are one or more interfaces or interface
+      specifications (``IDeclaration`` objects).
+
+      The interfaces given (including the interfaces in the specifications)
+      replace interfaces previously declared for the object.
+
+      Consider the following example:
+
+        >>> from zope.interface import Interface
+        >>> class I1(Interface): pass
+        ...
+        >>> class I2(Interface): pass
+        ...
+        >>> class IA1(Interface): pass
+        ...
+        >>> class IA2(Interface): pass
+        ...
+        >>> class IB(Interface): pass
+        ...
+        >>> class IC(Interface): pass
+        ...
+        >>> class A(object):
+        ...     implements(IA1, IA2)
+        >>> class B(object):
+        ...     implements(IB)
+
+        >>> class C(A, B):
+        ...    implements(IC)
+
+        >>> ob = C()
+        >>> directlyProvides(ob, I1, I2)
+        >>> int(I1 in providedBy(ob))
+        1
+        >>> int(I2 in providedBy(ob))
+        1
+        >>> int(IA1 in providedBy(ob))
+        1
+        >>> int(IA2 in providedBy(ob))
+        1
+        >>> int(IB in providedBy(ob))
+        1
+        >>> int(IC in providedBy(ob))
+        1
+
+      The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+      instances have been declared for instances of ``C``.
+
+      To remove directly provided interfaces, use ``directlyProvidedBy`` and
+      subtract the unwanted interfaces. For example:
+
+        >>> directlyProvides(ob, directlyProvidedBy(ob)-I2)
+        >>> int(I1 in providedBy(ob))
+        1
+        >>> int(I2 in providedBy(ob))
+        0
+
+      removes I2 from the interfaces directly provided by ``ob``. The object,
+      ``ob`` no longer directly provides ``I2``, although it might still
+      provide ``I2`` if it's class implements ``I2``.
+
+      To add directly provided interfaces, use ``directlyProvidedBy`` and
+      include additional interfaces.  For example:
+
+        >>> int(I2 in providedBy(ob))
+        0
+        >>> directlyProvides(ob, directlyProvidedBy(ob), I2)
+
+      adds ``I2`` to the interfaces directly provided by ob::
+
+        >>> int(I2 in providedBy(ob))
+        1
+
+      """
+
+    # We need to avoid setting this attribute on meta classes that
+    # don't support descriptors.
+    # We can do away with this check when we get rid of the old EC
+    cls = getattr(object, '__class__', None)
+    if cls is not None and getattr(cls,  '__class__', None) is cls:
+        # It's a meta class (well, at least it it could be an extension class)
+        if not isinstance(object, DescriptorAwareMetaClasses):
+            raise TypeError("Attempt to make an interface declaration on a "
+                            "non-descriptor-aware class")
+
+    interfaces = _normalizeargs(interfaces)
+    if cls is None:
+        cls = type(object)
+
+    issub = False
+    for damc in DescriptorAwareMetaClasses:
+        if issubclass(cls, damc):
+            issub = True
+            break
+    if issub:
+        # we have a class or type.  We'll use a special descriptor
+        # that provides some extra caching
+        object.__provides__ = ClassProvides(object, cls, *interfaces)
+    else:
+        object.__provides__ = Provides(cls, *interfaces)
+
+
+def alsoProvides(object, *interfaces):
+    """Declare interfaces declared directly for an object
+
+    The arguments after the object are one or more interfaces or interface
+    specifications (``IDeclaration`` objects).
+
+    The interfaces given (including the interfaces in the specifications) are
+    added to the interfaces previously declared for the object.
+
+    Consider the following example:
+
+      >>> from zope.interface import Interface
+      >>> class I1(Interface): pass
+      ...
+      >>> class I2(Interface): pass
+      ...
+      >>> class IA1(Interface): pass
+      ...
+      >>> class IA2(Interface): pass
+      ...
+      >>> class IB(Interface): pass
+      ...
+      >>> class IC(Interface): pass
+      ...
+      >>> class A(object):
+      ...     implements(IA1, IA2)
+      >>> class B(object):
+      ...     implements(IB)
+
+      >>> class C(A, B):
+      ...    implements(IC)
+
+      >>> ob = C()
+      >>> directlyProvides(ob, I1)
+      >>> int(I1 in providedBy(ob))
+      1
+      >>> int(I2 in providedBy(ob))
+      0
+      >>> int(IA1 in providedBy(ob))
+      1
+      >>> int(IA2 in providedBy(ob))
+      1
+      >>> int(IB in providedBy(ob))
+      1
+      >>> int(IC in providedBy(ob))
+      1
+
+      >>> alsoProvides(ob, I2)
+      >>> int(I1 in providedBy(ob))
+      1
+      >>> int(I2 in providedBy(ob))
+      1
+      >>> int(IA1 in providedBy(ob))
+      1
+      >>> int(IA2 in providedBy(ob))
+      1
+      >>> int(IB in providedBy(ob))
+      1
+      >>> int(IC in providedBy(ob))
+      1
+
+    The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+    instances have been declared for instances of ``C``. Notice that the
+    alsoProvides just extends the provided interfaces.
+    """
+    directlyProvides(object, directlyProvidedBy(object), *interfaces)
+
+def noLongerProvides(object, interface):
+    """
+    This removes a directly provided interface from an object.
+    Consider the following two interfaces:
+
+      >>> from zope.interface import Interface
+      >>> class I1(Interface): pass
+      ...
+      >>> class I2(Interface): pass
+      ...
+
+    ``I1`` is provided through the class, ``I2`` is directly provided
+    by the object:
+    
+      >>> class C(object):
+      ...    implements(I1)
+      >>> c = C()
+      >>> alsoProvides(c, I2)
+      >>> I2.providedBy(c)
+      True
+
+    Remove I2 from c again:
+      
+      >>> noLongerProvides(c, I2)
+      >>> I2.providedBy(c)
+      False
+
+    Removing an interface that is provided through the class is not possible:
+
+      >>> noLongerProvides(c, I1)
+      Traceback (most recent call last):
+      ...
+      ValueError: Can only remove directly provided interfaces.
+
+    """
+    directlyProvides(object, directlyProvidedBy(object)-interface)
+    if interface.providedBy(object):
+        raise ValueError("Can only remove directly provided interfaces.")
+
+class ClassProvidesBasePy(object):
+
+    def __get__(self, inst, cls):
+        if cls is self._cls:
+            # We only work if called on the class we were defined for
+
+            if inst is None:
+                # We were accessed through a class, so we are the class'
+                # provides spec. Just return this object as is:
+                return self
+
+            return self._implements
+
+        raise AttributeError('__provides__')
+
+ClassProvidesBase = ClassProvidesBasePy
+
+# Try to get C base:
+try:
+    import _zope_interface_coptimizations
+except ImportError:
+    pass
+else:
+    from _zope_interface_coptimizations import ClassProvidesBase
+
+
+class ClassProvides(Declaration, ClassProvidesBase):
+    """Special descriptor for class __provides__
+
+    The descriptor caches the implementedBy info, so that
+    we can get declarations for objects without instance-specific
+    interfaces a bit quicker.
+
+    For example:
+
+      >>> from zope.interface import Interface
+      >>> class IFooFactory(Interface):
+      ...     pass
+      >>> class IFoo(Interface):
+      ...     pass
+      >>> class C(object):
+      ...     implements(IFoo)
+      ...     classProvides(IFooFactory)
+      >>> [i.getName() for i in C.__provides__]
+      ['IFooFactory']
+
+      >>> [i.getName() for i in C().__provides__]
+      ['IFoo']
+    """
+
+    def __init__(self, cls, metacls, *interfaces):
+        self._cls = cls
+        self._implements = implementedBy(cls)
+        self.__args = (cls, metacls, ) + interfaces
+        Declaration.__init__(self, *(interfaces + (implementedBy(metacls), )))
+
+    def __reduce__(self):
+        return self.__class__, self.__args
+
+    # Copy base-class method for speed
+    __get__ = ClassProvidesBase.__get__
+
+def directlyProvidedBy(object):
+    """Return the interfaces directly provided by the given object
+
+    The value returned is an ``IDeclaration``.
+    """
+    provides = getattr(object, "__provides__", None)
+    if (provides is None # no spec
+        or
+        # We might have gotten the implements spec, as an
+        # optimization. If so, it's like having only one base, that we
+        # lop off to exclude class-supplied declarations:
+        isinstance(provides, Implements)
+        ):
+        return _empty
+
+    # Strip off the class part of the spec:
+    return Declaration(provides.__bases__[:-1])
+
+def classProvides(*interfaces):
+    """Declare interfaces provided directly by a class
+
+      This function is called in a class definition.
+
+      The arguments are one or more interfaces or interface specifications
+      (``IDeclaration`` objects).
+
+      The given interfaces (including the interfaces in the specifications)
+      are used to create the class's direct-object interface specification.
+      An error will be raised if the module class has an direct interface
+      specification. In other words, it is an error to call this function more
+      than once in a class definition.
+
+      Note that the given interfaces have nothing to do with the interfaces
+      implemented by instances of the class.
+
+      This function is provided for convenience. It provides a more convenient
+      way to call directlyProvides for a class. For example::
+
+        classProvides(I1)
+
+      is equivalent to calling::
+
+        directlyProvides(theclass, I1)
+
+      after the class has been created.
+
+      For example:
+
+        >>> from zope.interface import Interface
+        >>> class IFoo(Interface): pass
+        ...
+        >>> class IFooFactory(Interface): pass
+        ...
+        >>> class C(object):
+        ...   implements(IFoo)
+        ...   classProvides(IFooFactory)
+        >>> [i.getName() for i in C.__providedBy__]
+        ['IFooFactory']
+        >>> [i.getName() for i in C().__providedBy__]
+        ['IFoo']
+
+      if equivalent to:
+
+        >>> from zope.interface import Interface
+        >>> class IFoo(Interface): pass
+        ...
+        >>> class IFooFactory(Interface): pass
+        ...
+        >>> class C(object):
+        ...   implements(IFoo)
+        >>> directlyProvides(C, IFooFactory)
+        >>> [i.getName() for i in C.__providedBy__]
+        ['IFooFactory']
+        >>> [i.getName() for i in C().__providedBy__]
+        ['IFoo']
+
+      """
+    frame = sys._getframe(1)
+    locals = frame.f_locals
+
+    # Try to make sure we were called from a class def
+    if (locals is frame.f_globals) or ('__module__' not in locals):
+        raise TypeError("classProvides can be used only from a class definition.")
+
+    if '__provides__' in locals:
+        raise TypeError(
+            "classProvides can only be used once in a class definition.")
+
+    locals["__provides__"] = _normalizeargs(interfaces)
+
+    addClassAdvisor(_classProvides_advice, depth=2)
+
+def _classProvides_advice(cls):
+    interfaces = cls.__dict__['__provides__']
+    del cls.__provides__
+    directlyProvides(cls, *interfaces)
+    return cls
+
+class provider:
+    """Class decorator version of classProvides"""
+
+    def __init__(self, *interfaces):
+        self.interfaces = interfaces
+
+    def __call__(self, ob):
+        directlyProvides(ob, *self.interfaces)
+        return ob            
+
+def moduleProvides(*interfaces):
+    """Declare interfaces provided by a module
+
+    This function is used in a module definition.
+
+    The arguments are one or more interfaces or interface specifications
+    (``IDeclaration`` objects).
+
+    The given interfaces (including the interfaces in the specifications) are
+    used to create the module's direct-object interface specification.  An
+    error will be raised if the module already has an interface specification.
+    In other words, it is an error to call this function more than once in a
+    module definition.
+
+    This function is provided for convenience. It provides a more convenient
+    way to call directlyProvides. For example::
+
+      moduleImplements(I1)
+
+    is equivalent to::
+
+      directlyProvides(sys.modules[__name__], I1)
+    """
+    frame = sys._getframe(1)
+    locals = frame.f_locals
+
+    # Try to make sure we were called from a class def
+    if (locals is not frame.f_globals) or ('__name__' not in locals):
+        raise TypeError(
+            "moduleProvides can only be used from a module definition.")
+
+    if '__provides__' in locals:
+        raise TypeError(
+            "moduleProvides can only be used once in a module definition.")
+
+    locals["__provides__"] = Provides(ModuleType,
+                                      *_normalizeargs(interfaces))
+
+##############################################################################
+#
+# Declaration querying support
+
+def ObjectSpecification(direct, cls):
+    """Provide object specifications
+
+    These combine information for the object and for it's classes.
+
+    For example:
+
+      >>> from zope.interface import Interface
+      >>> class I1(Interface): pass
+      ...
+      >>> class I2(Interface): pass
+      ...
+      >>> class I3(Interface): pass
+      ...
+      >>> class I31(I3): pass
+      ...
+      >>> class I4(Interface): pass
+      ...
+      >>> class I5(Interface): pass
+      ...
+      >>> class A(object):
+      ...     implements(I1)
+      >>> class B(object): __implemented__ = I2
+      ...
+      >>> class C(A, B):
+      ...     implements(I31)
+      >>> c = C()
+      >>> directlyProvides(c, I4)
+      >>> [i.getName() for i in providedBy(c)]
+      ['I4', 'I31', 'I1', 'I2']
+      >>> [i.getName() for i in providedBy(c).flattened()]
+      ['I4', 'I31', 'I3', 'I1', 'I2', 'Interface']
+      >>> int(I1 in providedBy(c))
+      1
+      >>> int(I3 in providedBy(c))
+      0
+      >>> int(providedBy(c).extends(I3))
+      1
+      >>> int(providedBy(c).extends(I31))
+      1
+      >>> int(providedBy(c).extends(I5))
+      0
+      >>> class COnly(A, B):
+      ...     implementsOnly(I31)
+      >>> class D(COnly):
+      ...     implements(I5)
+      >>> c = D()
+      >>> directlyProvides(c, I4)
+      >>> [i.getName() for i in providedBy(c)]
+      ['I4', 'I5', 'I31']
+      >>> [i.getName() for i in providedBy(c).flattened()]
+      ['I4', 'I5', 'I31', 'I3', 'Interface']
+      >>> int(I1 in providedBy(c))
+      0
+      >>> int(I3 in providedBy(c))
+      0
+      >>> int(providedBy(c).extends(I3))
+      1
+      >>> int(providedBy(c).extends(I1))
+      0
+      >>> int(providedBy(c).extends(I31))
+      1
+      >>> int(providedBy(c).extends(I5))
+      1
+    """
+
+    return Provides(cls, direct)
+
+def getObjectSpecification(ob):
+
+    provides = getattr(ob, '__provides__', None)
+    if provides is not None:
+        if isinstance(provides, SpecificationBase):
+            return provides
+
+    try:
+        cls = ob.__class__
+    except AttributeError:
+        # We can't get the class, so just consider provides
+        return _empty
+
+    return implementedBy(cls)
+
+def providedBy(ob):
+
+    # Here we have either a special object, an old-style declaration
+    # or a descriptor
+
+    # Try to get __providedBy__
+    try:
+        r = ob.__providedBy__
+    except AttributeError:
+        # Not set yet. Fall back to lower-level thing that computes it
+        return getObjectSpecification(ob)
+
+    try:
+        # We might have gotten a descriptor from an instance of a
+        # class (like an ExtensionClass) that doesn't support
+        # descriptors.  We'll make sure we got one by trying to get
+        # the only attribute, which all specs have.
+        r.extends
+
+    except AttributeError:
+
+        # The object's class doesn't understand descriptors.
+        # Sigh. We need to get an object descriptor, but we have to be
+        # careful.  We want to use the instance's __provides__, if
+        # there is one, but only if it didn't come from the class.
+
+        try:
+            r = ob.__provides__
+        except AttributeError:
+            # No __provides__, so just fall back to implementedBy
+            return implementedBy(ob.__class__)
+
+        # We need to make sure we got the __provides__ from the
+        # instance. We'll do this by making sure we don't get the same
+        # thing from the class:
+
+        try:
+            cp = ob.__class__.__provides__
+        except AttributeError:
+            # The ob doesn't have a class or the class has no
+            # provides, assume we're done:
+            return r
+
+        if r is cp:
+            # Oops, we got the provides from the class. This means
+            # the object doesn't have it's own. We should use implementedBy
+            return implementedBy(ob.__class__)
+
+    return r
+
+class ObjectSpecificationDescriptorPy(object):
+    """Implement the `__providedBy__` attribute
+
+    The `__providedBy__` attribute computes the interfaces peovided by
+    an object.
+    """
+
+    def __get__(self, inst, cls):
+        """Get an object specification for an object
+
+        For example:
+
+          >>> from zope.interface import Interface
+          >>> class IFoo(Interface): pass
+          ...
+          >>> class IFooFactory(Interface): pass
+          ...
+          >>> class C(object):
+          ...   implements(IFoo)
+          ...   classProvides(IFooFactory)
+          >>> [i.getName() for i in C.__providedBy__]
+          ['IFooFactory']
+          >>> [i.getName() for i in C().__providedBy__]
+          ['IFoo']
+
+        """
+
+        # Get an ObjectSpecification bound to either an instance or a class,
+        # depending on how we were accessed.
+
+        if inst is None:
+            return getObjectSpecification(cls)
+
+        provides = getattr(inst, '__provides__', None)
+        if provides is not None:
+            return provides
+
+        return implementedBy(cls)
+
+ObjectSpecificationDescriptor = ObjectSpecificationDescriptorPy
+
+##############################################################################
+
+def _normalizeargs(sequence, output = None):
+    """Normalize declaration arguments
+
+    Normalization arguments might contain Declarions, tuples, or single
+    interfaces.
+
+    Anything but individial interfaces or implements specs will be expanded.
+    """
+    if output is None:
+        output = []
+
+    cls = sequence.__class__
+    if InterfaceClass in cls.__mro__ or Implements in cls.__mro__:
+        output.append(sequence)
+    else:
+        for v in sequence:
+            _normalizeargs(v, output)
+
+    return output
+
+_empty = Declaration()
+
+try:
+    import _zope_interface_coptimizations
+except ImportError:
+    pass
+else:
+    from _zope_interface_coptimizations import implementedBy, providedBy
+    from _zope_interface_coptimizations import getObjectSpecification
+    from _zope_interface_coptimizations import ObjectSpecificationDescriptor
+
+objectSpecificationDescriptor = ObjectSpecificationDescriptor()
diff --git a/src/zope/interface/document.py b/src/zope/interface/document.py
new file mode 100644 (file)
index 0000000..ba93bed
--- /dev/null
@@ -0,0 +1,105 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+""" Pretty-Print an Interface object as structured text (Yum)
+
+This module provides a function, asStructuredText, for rendering an
+interface as structured text.
+"""
+import zope.interface
+
+def asStructuredText(I, munge=0):
+    """ Output structured text format.  Note, this will whack any existing
+    'structured' format of the text.  """
+
+    r = [I.getName()]
+    outp = r.append
+    level = 1
+
+    if I.getDoc():
+        outp(_justify_and_indent(_trim_doc_string(I.getDoc()), level))
+
+    bases = [base
+             for base in I.__bases__
+             if base is not zope.interface.Interface
+             ]
+    if bases:
+        outp(_justify_and_indent("This interface extends:", level, munge))
+        level += 1
+        for b in bases:
+            item = "o %s" % b.getName()
+            outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+        level -= 1
+
+    namesAndDescriptions = I.namesAndDescriptions()
+    namesAndDescriptions.sort()
+
+    outp(_justify_and_indent("Attributes:", level, munge))
+    level += 1
+    for name, desc in namesAndDescriptions:
+        if not hasattr(desc, 'getSignatureString'):   # ugh...
+            item = "%s -- %s" % (desc.getName(),
+                                 desc.getDoc() or 'no documentation')
+            outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+    level -= 1
+
+    outp(_justify_and_indent("Methods:", level, munge))
+    level += 1
+    for name, desc in namesAndDescriptions:
+        if hasattr(desc, 'getSignatureString'):   # ugh...
+            item = "%s%s -- %s" % (desc.getName(),
+                                   desc.getSignatureString(),
+                                   desc.getDoc() or 'no documentation')
+            outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+
+    return "\n\n".join(r) + "\n\n"
+
+
+def _trim_doc_string(text):
+    """ Trims a doc string to make it format
+    correctly with structured text. """
+
+    lines = text.replace('\r\n', '\n').split('\n')
+    nlines = [lines.pop(0)]
+    if lines:
+        min_indent = min([len(line) - len(line.lstrip())
+                          for line in lines])
+        for line in lines:
+            nlines.append(line[min_indent:])
+
+    return '\n'.join(nlines)
+
+
+def _justify_and_indent(text, level, munge=0, width=72):
+    """ indent and justify text, rejustify (munge) if specified """
+
+    indent = " " * level
+
+    if munge:
+        lines = []
+        line = indent
+        text = text.split()
+
+        for word in text:
+            line = ' '.join([line, word])
+            if len(line) > width:
+                lines.append(line)
+                line = indent
+        else:
+            lines.append(line)
+
+        return '\n'.join(lines)
+
+    else:
+        return indent + \
+            text.strip().replace("\r\n", "\n") .replace("\n", "\n" + indent)
diff --git a/src/zope/interface/exceptions.py b/src/zope/interface/exceptions.py
new file mode 100644 (file)
index 0000000..e9a4788
--- /dev/null
@@ -0,0 +1,67 @@
+##############################################################################
+#
+# Copyright (c) 2002 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.
+#
+##############################################################################
+"""Interface-specific exceptions
+"""
+
+class Invalid(Exception):
+    """A specification is violated
+    """
+
+class DoesNotImplement(Invalid):
+    """ This object does not implement """
+    def __init__(self, interface):
+        self.interface = interface
+
+    def __str__(self):
+        return """An object does not implement interface %(interface)s
+
+        """ % self.__dict__
+
+class BrokenImplementation(Invalid):
+    """An attribute is not completely implemented.
+    """
+
+    def __init__(self, interface, name):
+        self.interface=interface
+        self.name=name
+
+    def __str__(self):
+        return """An object has failed to implement interface %(interface)s
+
+        The %(name)s attribute was not provided.
+        """ % self.__dict__
+
+class BrokenMethodImplementation(Invalid):
+    """An method is not completely implemented.
+    """
+
+    def __init__(self, method, mess):
+        self.method=method
+        self.mess=mess
+
+    def __str__(self):
+        return """The implementation of %(method)s violates its contract
+        because %(mess)s.
+        """ % self.__dict__
+
+class InvalidInterface(Exception):
+    """The interface has invalid contents
+    """
+
+class BadImplements(TypeError):
+    """An implementation assertion is invalid
+
+    because it doesn't contain an interface or a sequence of valid
+    implementation assertions.
+    """
diff --git a/src/zope/interface/human.ru.txt b/src/zope/interface/human.ru.txt
new file mode 100644 (file)
index 0000000..a149072
--- /dev/null
@@ -0,0 +1,156 @@
+===============================
+Использование реестра адаптеров
+===============================
+
+Данный документ содержит небольшую демонстрацию пакета ``zope.interface`` и его
+реестра адаптеров. Документ рассчитывался как конкретный, но более узкий пример
+того как использовать интерфейсы и адаптеры вне Zope 3.
+
+Сначала нам необходимо импортировать пакет для работы с интерфейсами::
+
+  >>> import zope.interface
+
+Теперь мы разработаем интерфейс для нашего объекта - простого файла. Наш файл
+будет содержать всего один атрибут - body, в котором фактически будет сохранено
+содержимое файла::
+
+  >>> class IFile(zope.interface.Interface):
+  ...
+  ...     body = zope.interface.Attribute(u'Содержимое файла.')
+  ...
+
+Для статистики нам часто необходимо знать размер файла. Но было бы несколько
+топорно реализовывать определение размера прямо для объекта файла, т.к. размер
+больше относится к мета-данным. Таким образом мы создаем еще один интерфейс для
+представления размера какого-либо объекта::
+
+  >>> class ISize(zope.interface.Interface):
+  ...
+  ...     def getSize():
+  ...         'Return the size of an object.'
+  ...
+
+Теперь мы должны создать класс реализующий наш файл. Необходимо что бы наш
+объект хранил информацию о том, что он реализует интерфейс `IFile`. Мы также
+создаем атрибут с содержимым файла по умолчанию (для упрощения нашего
+примера)::
+
+  >>> class File(object):
+  ...
+  ...      zope.interface.implements(IFile)
+  ...      body = 'foo bar'
+  ...
+
+Дальше мы создаем адаптер, который будет предоставлять интерфейс `ISize`
+получая любой объект предоставляющий интерфейс `IFile`. По соглашению мы
+используем атрибут `__used_for__` для указания интерфейса который как мы
+ожидаем предоставляет адаптируемый объект, `IFile` в нашем случае. На самом
+деле этот атрибут используется только для документирования. В случае если
+адаптер используется для нескольких интерфейсов можно указать их все в виде
+кортежа.
+
+Опять же по соглашению конструктор адаптера получает один аргумент - context
+(контекст). В нашем случае контекст - это экземпляр `IFile` (объект,
+предоставляющий `IFile`) который используется для получения из него размера.
+Так же по соглашению контекст сохраняется а адаптере в атрибуте с именем
+`context`. Twisted комьюнити ссылается на контекст как на объект `original`.
+Таким образом можно также дать аргументу любое подходящее имя, например
+`file`::
+
+  >>> class FileSize(object):
+  ...
+  ...      zope.interface.implements(ISize)
+  ...      __used_for__ = IFile
+  ...
+  ...      def __init__(self, context):
+  ...          self.context = context
+  ...
+  ...      def getSize(self):
+  ...          return len(self.context.body)
+  ...
+
+Теперь когда мы написали наш адаптер мы должны зарегистрировать его в реестре
+адаптеров, что бы его можно было запросить когда он понадобится. Здесь нет
+какого-либо глобального реестра адаптеров, таким образом мы должны
+самостоятельно создать для нашего примера реестр::
+
+  >>> from zope.interface.adapter import AdapterRegistry
+  >>> registry = AdapterRegistry()
+
+Реестр содержит отображение того, что адаптер реализует на основе другого
+интерфейса который предоставляет объект. Поэтому дальше мы регистрируем адаптер
+который адаптирует интерфейс `IFile` к интерфейсу `ISize`. Первый аргумент к
+методу `register()` реестра - это список адаптируемых интерфейсов. В нашем
+случае мы имеем только один адаптируемый интерфейс - `IFile`. Список
+интерфейсов имеет смысл для использования концепции мульти-адаптеров, которые
+требуют нескольких оригинальных объектов для адаптации к новому интерфейсу. В
+этой ситуации конструктор адаптера будет требовать новый аргумент для каждого
+оригинального интерфейса.
+
+Второй аргумент метода `register()` - это интерфейс который предоставляет
+адаптер, в нашем случае `ISize`. Третий аргумент - имя адаптера. Сейчас нам не
+важно имя адаптера и мы передаем его как пустую строку. Обычно имена полезны
+если используются адаптеры для одинакового набора интерфейсов, но в различных
+ситуациях. Последний аргумент - это класс адаптера::
+
+  >>> registry.register([IFile], ISize, '', FileSize)
+
+Теперь мы можем использовать реестр для запроса адаптера::
+
+  >>> registry.lookup1(IFile, ISize, '')
+  <class '__main__.FileSize'>
+
+Попробуем более практичный пример. Создадим экземпляр `File` и создадим адаптер
+использующий запрос реестра. Затем мы увидим возвращает ли адаптер корректный
+размер при вызове `getSize()`::
+
+  >>> file = File()
+  >>> size = registry.lookup1(IFile, ISize, '')(file)
+  >>> size.getSize()
+  7
+
+На самом деле это не очень практично, т.к. нам нужно самим передавать все
+аргументы методу запроса. Существует некоторый синтаксический леденец который
+позволяет нам получить экземпляр адаптера просто вызвав `ISize(file)`. Что бы
+использовать эту функциональность нам понадобится добавить наш реестр к списку
+adapter_hooks, который находится в модуле с адаптерами. Этот список хранит
+коллекцию вызываемых объектов которые вызываются автоматически когда вызывается
+IFoo(obj); их предназначение - найти адаптеры которые реализуют интерфейс для
+определенного экземпляра контекста.
+
+Необходимо реализовать свою собственную функцию для поиска адаптера; данный
+пример описывает одну из простейших функций для использования с реестром, но
+также можно реализовать поисковые функции которые, например, используют
+кэширование, или адаптеры сохраняемые в базе. Функция поиска должна принимать
+желаемый на выходе интерфейс (в нашем случае `ISize`) как первый аргумент и
+контекст для адаптации (`file`) как второй. Функция должна вернуть адаптер,
+т.е. экземпляр `FileSize`::
+
+  >>> def hook(provided, object):
+  ...     adapter = registry.lookup1(zope.interface.providedBy(object),
+  ...                                provided, '')
+  ...     return adapter(object)
+  ...
+
+Теперь мы просто добавляем нашу функцию к списку `adapter_hooks`::
+
+  >>> from zope.interface.interface import adapter_hooks
+  >>> adapter_hooks.append(hook)
+
+Как только функция зарегистрирована мы можем использовать желаемый синтаксис::
+
+  >>> size = ISize(file)
+  >>> size.getSize()
+  7
+
+После нам нужно прибраться за собой, что бы другие получили чистый список
+`adaper_hooks` после нас::
+
+  >>> adapter_hooks.remove(hook)
+
+Это все. Здесь намеренно отложена дискуссия об именованных и мульти-адаптерах,
+т.к. данный текст рассчитан как практическое и простое введение в интерфейсы и
+адаптеры Zope 3. Для более подробной информации имеет смысл прочитать
+`adapter.txt` из пакета `zope.interface`, что бы получить более формальное,
+справочное и полное трактование пакета. Внимание: многие жаловались, что
+`adapter.txt` приводит их мозг к расплавленному состоянию!
diff --git a/src/zope/interface/human.txt b/src/zope/interface/human.txt
new file mode 100644 (file)
index 0000000..749b87d
--- /dev/null
@@ -0,0 +1,152 @@
+==========================
+Using the Adapter Registry
+==========================
+
+This is a small demonstration of the ``zope.interface`` package including its
+adapter registry. It is intended to provide a concrete but narrow example on
+how to use interfaces and adapters outside of Zope 3.
+
+First we have to import the interface package::
+
+  >>> import zope.interface
+
+We now develop an interface for our object, which is a simple file in this
+case. For now we simply support one attribute, the body, which contains the
+actual file contents::
+
+  >>> class IFile(zope.interface.Interface):
+  ...
+  ...     body = zope.interface.Attribute('Contents of the file.')
+  ...
+
+For statistical reasons we often want to know the size of a file. However, it
+would be clumsy to implement the size directly in the file object, since the
+size really represents meta-data. Thus we create another interface that
+provides the size of something::
+
+  >>> class ISize(zope.interface.Interface):
+  ...
+  ...     def getSize():
+  ...         'Return the size of an object.'
+  ...
+
+Now we need to implement the file. It is essential that the object states
+that it implements the `IFile` interface. We also provide a default body
+value (just to make things simpler for this example)::
+
+  >>> class File(object):
+  ...
+  ...      zope.interface.implements(IFile)
+  ...      body = 'foo bar'
+  ...
+
+Next we implement an adapter that can provide the `ISize` interface given any
+object providing `IFile`. By convention we use `__used_for__` to specify the
+interface that we expect the adapted object to provide, in our case
+`IFile`. However, this attribute is not used for anything. If you have
+multiple interfaces for which an adapter is used, just specify the interfaces
+via a tuple.
+
+Again by convention, the constructor of an adapter takes one argument, the
+context. The context in this case is an instance of `File` (providing `IFile`)
+that is used to extract the size from. Also by convention the context is
+stored in an attribute named `context` on the adapter. The twisted community
+refers to the context as the `original` object. However, you may feel free to
+use a specific argument name, such as `file`::
+
+  >>> class FileSize(object):
+  ...
+  ...      zope.interface.implements(ISize)
+  ...      __used_for__ = IFile
+  ...
+  ...      def __init__(self, context):
+  ...          self.context = context
+  ...
+  ...      def getSize(self):
+  ...          return len(self.context.body)
+  ...
+
+Now that we have written our adapter, we have to register it with an adapter
+registry, so that it can be looked up when needed. There is no such thing as a
+global registry; thus we have to instantiate one for our example manually::
+
+  >>> from zope.interface.adapter import AdapterRegistry
+  >>> registry = AdapterRegistry()
+
+
+The registry keeps a map of what adapters implement based on another
+interface, the object already provides. Therefore, we next have to register an
+adapter that adapts from `IFile` to `ISize`. The first argument to
+the registry's `register()` method is a list of original interfaces.In our
+cause we have only one original interface, `IFile`. A list makes sense, since
+the interface package has the concept of multi-adapters, which are adapters
+that require multiple objects to adapt to a new interface. In these
+situations, your adapter constructor will require an argument for each
+specified interface.
+
+The second argument is the interface the adapter provides, in our case
+`ISize`. The third argument is the name of the adapter. Since we do not care
+about names, we simply leave it as an empty string. Names are commonly useful,
+if you have adapters for the same set of interfaces, but they are useful in
+different situations. The last argument is simply the adapter class::
+
+  >>> registry.register([IFile], ISize, '', FileSize)
+
+You can now use the the registry to lookup the adapter::
+
+  >>> registry.lookup1(IFile, ISize, '')
+  <class '__main__.FileSize'>
+
+Let's get a little bit more practical. Let's create a `File` instance and
+create the adapter using a registry lookup. Then we see whether the adapter
+returns the correct size by calling `getSize()`::
+
+  >>> file = File()
+  >>> size = registry.lookup1(IFile, ISize, '')(file)
+  >>> size.getSize()
+  7
+
+However, this is not very practical, since I have to manually pass in the
+arguments to the lookup method. There is some syntactic candy that will allow
+us to get an adapter instance by simply calling `ISize(file)`. To make use of
+this functionality, we need to add our registry to the adapter_hooks list,
+which is a member of the adapters module. This list stores a collection of
+callables that are automatically invoked when IFoo(obj) is called; their
+purpose is to locate adapters that implement an interface for a certain
+context instance.
+
+You are required to implement your own adapter hook; this example covers one
+of the simplest hooks that use the registry, but you could implement one that
+used an adapter cache or persistent adapters, for instance. The helper hook is
+required to expect as first argument the desired output interface (for us
+`ISize`) and as the second argument the context of the adapter (here
+`file`). The function returns an adapter, i.e. a `FileSize` instance::
+
+  >>> def hook(provided, object):
+  ...     adapter = registry.lookup1(zope.interface.providedBy(object),
+  ...                                provided, '')
+  ...     return adapter(object)
+  ...
+
+We now just add the hook to an `adapter_hooks` list::
+
+  >>> from zope.interface.interface import adapter_hooks
+  >>> adapter_hooks.append(hook)
+
+Once the hook is registered, you can use the desired syntax::
+
+  >>> size = ISize(file)
+  >>> size.getSize()
+  7
+
+Now we have to cleanup after ourselves, so that others after us have a clean
+`adapter_hooks` list::
+
+  >>> adapter_hooks.remove(hook)
+
+That's it. I have intentionally left out a discussion of named adapters and
+multi-adapters, since this text is intended as a practical and simple
+introduction to Zope 3 interfaces and adapters. You might want to read the
+`adapter.txt` in the `zope.interface` package for a more formal, referencial
+and complete treatment of the package. Warning: People have reported that
+`adapter.txt` makes their brain feel soft!
diff --git a/src/zope/interface/index.txt b/src/zope/interface/index.txt
new file mode 100644 (file)
index 0000000..3c499b5
--- /dev/null
@@ -0,0 +1,29 @@
+Welcome to zope.interface's documentation!
+==========================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   README
+   adapter
+   human
+   verify
+
+По-русски
+=========
+
+.. toctree::
+   :maxdepth: 2
+
+   README.ru
+   adapter.ru
+   human.ru
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/src/zope/interface/interface.py b/src/zope/interface/interface.py
new file mode 100644 (file)
index 0000000..af76f12
--- /dev/null
@@ -0,0 +1,838 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Interface object implementation
+"""
+from __future__ import generators
+
+import sys
+from types import FunctionType
+import warnings
+import weakref
+
+from zope.interface.exceptions import Invalid
+from zope.interface.ro import ro
+
+
+CO_VARARGS = 4
+CO_VARKEYWORDS = 8
+TAGGED_DATA = '__interface_tagged_values__'
+
+_decorator_non_return = object()
+
+def invariant(call):
+    f_locals = sys._getframe(1).f_locals
+    tags = f_locals.setdefault(TAGGED_DATA, {})
+    invariants = tags.setdefault('invariants', [])
+    invariants.append(call)
+    return _decorator_non_return
+
+
+def taggedValue(key, value):
+    """Attaches a tagged value to an interface at definition time."""
+    f_locals = sys._getframe(1).f_locals
+    tagged_values = f_locals.setdefault(TAGGED_DATA, {})
+    tagged_values[key] = value
+    return _decorator_non_return
+
+
+class Element(object):
+
+    # We can't say this yet because we don't have enough
+    # infrastructure in place.
+    #
+    #implements(IElement)
+
+    def __init__(self, __name__, __doc__=''):
+        """Create an 'attribute' description
+        """
+        if not __doc__ and __name__.find(' ') >= 0:
+            __doc__ = __name__
+            __name__ = None
+
+        self.__name__=__name__
+        self.__doc__=__doc__
+        self.__tagged_values = {}
+
+    def getName(self):
+        """ Returns the name of the object. """
+        return self.__name__
+
+    def getDoc(self):
+        """ Returns the documentation for the object. """
+        return self.__doc__
+
+    def getTaggedValue(self, tag):
+        """ Returns the value associated with 'tag'. """
+        return self.__tagged_values[tag]
+
+    def queryTaggedValue(self, tag, default=None):
+        """ Returns the value associated with 'tag'. """
+        return self.__tagged_values.get(tag, default)
+
+    def getTaggedValueTags(self):
+        """ Returns a list of all tags. """
+        return self.__tagged_values.keys()
+
+    def setTaggedValue(self, tag, value):
+        """ Associates 'value' with 'key'. """
+        self.__tagged_values[tag] = value
+
+class SpecificationBasePy(object):
+
+    def providedBy(self, ob):
+        """Is the interface implemented by an object
+
+          >>> from zope.interface import *
+          >>> class I1(Interface):
+          ...     pass
+          >>> class C(object):
+          ...     implements(I1)
+          >>> c = C()
+          >>> class X(object):
+          ...     pass
+          >>> x = X()
+          >>> I1.providedBy(x)
+          False
+          >>> I1.providedBy(C)
+          False
+          >>> I1.providedBy(c)
+          True
+          >>> directlyProvides(x, I1)
+          >>> I1.providedBy(x)
+          True
+          >>> directlyProvides(C, I1)
+          >>> I1.providedBy(C)
+          True
+
+        """
+        spec = providedBy(ob)
+        return self in spec._implied
+
+    def implementedBy(self, cls):
+        """Test whether the specification is implemented by a class or factory.
+        Raise TypeError if argument is neither a class nor a callable."""
+        spec = implementedBy(cls)
+        return self in spec._implied
+
+    def isOrExtends(self, interface):
+        """Is the interface the same as or extend the given interface
+
+        Examples::
+
+          >>> from zope.interface import Interface
+          >>> from zope.interface.declarations import Declaration
+          >>> class I1(Interface): pass
+          ...
+          >>> class I2(I1): pass
+          ...
+          >>> class I3(Interface): pass
+          ...
+          >>> class I4(I3): pass
+          ...
+          >>> spec = Declaration()
+          >>> int(spec.extends(Interface))
+          1
+          >>> spec = Declaration(I2)
+          >>> int(spec.extends(Interface))
+          1
+          >>> int(spec.extends(I1))
+          1
+          >>> int(spec.extends(I2))
+          1
+          >>> int(spec.extends(I3))
+          0
+          >>> int(spec.extends(I4))
+          0
+
+        """
+        return interface in self._implied
+
+    __call__ = isOrExtends
+
+SpecificationBase = SpecificationBasePy
+try:
+    from _zope_interface_coptimizations import SpecificationBase
+except ImportError:
+    pass
+
+_marker = object()
+class InterfaceBasePy(object):
+    """Base class that wants to be replaced with a C base :)
+    """
+
+    def __call__(self, obj, alternate=_marker):
+        """Adapt an object to the interface
+        """
+        conform = getattr(obj, '__conform__', None)
+        if conform is not None:
+            adapter = self._call_conform(conform)
+            if adapter is not None:
+                return adapter
+
+        adapter = self.__adapt__(obj)
+
+        if adapter is not None:
+            return adapter
+        elif alternate is not _marker:
+            return alternate
+        else:
+            raise TypeError("Could not adapt", obj, self)
+
+    def __adapt__(self, obj):
+        """Adapt an object to the reciever
+        """
+        if self.providedBy(obj):
+            return obj
+
+        for hook in adapter_hooks:
+            adapter = hook(self, obj)
+            if adapter is not None:
+                return adapter
+
+    
+InterfaceBase = InterfaceBasePy
+try:
+    from _zope_interface_coptimizations import InterfaceBase
+except ImportError:
+    pass
+
+
+adapter_hooks = []
+try:
+    from _zope_interface_coptimizations import adapter_hooks
+except ImportError:
+    pass
+
+
+class Specification(SpecificationBase):
+    """Specifications
+
+    An interface specification is used to track interface declarations
+    and component registrations.
+
+    This class is a base class for both interfaces themselves and for
+    interface specifications (declarations).
+
+    Specifications are mutable.  If you reassign their cases, their
+    relations with other specifications are adjusted accordingly.
+
+    For example:
+
+    >>> from zope.interface import Interface
+    >>> class I1(Interface):
+    ...     pass
+    >>> class I2(I1):
+    ...     pass
+    >>> class I3(I2):
+    ...     pass
+
+    >>> [i.__name__ for i in I1.__bases__]
+    ['Interface']
+
+    >>> [i.__name__ for i in I2.__bases__]
+    ['I1']
+
+    >>> I3.extends(I1)
+    1
+
+    >>> I2.__bases__ = (Interface, )
+
+    >>> [i.__name__ for i in I2.__bases__]
+    ['Interface']
+
+    >>> I3.extends(I1)
+    0
+
+    """
+
+    # Copy some base class methods for speed
+    isOrExtends = SpecificationBase.isOrExtends
+    providedBy = SpecificationBase.providedBy
+
+    def __init__(self, bases=()):
+        self._implied = {}
+        self.dependents = weakref.WeakKeyDictionary()
+        self.__bases__ = tuple(bases)
+
+    def subscribe(self, dependent):
+        self.dependents[dependent] = self.dependents.get(dependent, 0) + 1
+
+    def unsubscribe(self, dependent):
+        n = self.dependents.get(dependent, 0) - 1
+        if not n:
+            del self.dependents[dependent]
+        elif n > 0:
+            self.dependents[dependent] = n
+        else:
+            raise KeyError(dependent)
+
+    def __setBases(self, bases):
+        # Register ourselves as a dependent of our old bases
+        for b in self.__bases__:
+            b.unsubscribe(self)
+
+        # Register ourselves as a dependent of our bases
+        self.__dict__['__bases__'] = bases
+        for b in bases:
+            b.subscribe(self)
+
+        self.changed(self)
+
+    __bases__ = property(
+
+        lambda self: self.__dict__.get('__bases__', ()),
+        __setBases,
+        )
+
+    def changed(self, originally_changed):
+        """We, or something we depend on, have changed
+        """
+        try:
+            del self._v_attrs
+        except AttributeError:
+            pass
+
+        implied = self._implied
+        implied.clear()
+
+        ancestors = ro(self)
+
+        try:
+            if Interface not in ancestors:
+                ancestors.append(Interface)
+        except NameError:
+            pass # defining Interface itself
+
+        self.__sro__ = tuple(ancestors)
+        self.__iro__ = tuple([ancestor for ancestor in ancestors
+                              if isinstance(ancestor, InterfaceClass)
+                              ])
+
+        for ancestor in ancestors:
+            # We directly imply our ancestors:
+            implied[ancestor] = ()
+
+        # Now, advise our dependents of change:
+        for dependent in self.dependents.keys():
+            dependent.changed(originally_changed)
+
+
+    def interfaces(self):
+        """Return an iterator for the interfaces in the specification
+
+        for example::
+
+          >>> from zope.interface import Interface
+          >>> class I1(Interface): pass
+          ...
+          >>> class I2(I1): pass
+          ...
+          >>> class I3(Interface): pass
+          ...
+          >>> class I4(I3): pass
+          ...
+          >>> spec = Specification((I2, I3))
+          >>> spec = Specification((I4, spec))
+          >>> i = spec.interfaces()
+          >>> [x.getName() for x in i]
+          ['I4', 'I2', 'I3']
+          >>> list(i)
+          []
+        """
+        seen = {}
+        for base in self.__bases__:
+            for interface in base.interfaces():
+                if interface not in seen:
+                    seen[interface] = 1
+                    yield interface
+
+
+    def extends(self, interface, strict=True):
+        """Does the specification extend the given interface?
+
+        Test whether an interface in the specification extends the
+        given interface
+
+        Examples::
+
+          >>> from zope.interface import Interface
+          >>> from zope.interface.declarations import Declaration
+          >>> class I1(Interface): pass
+          ...
+          >>> class I2(I1): pass
+          ...
+          >>> class I3(Interface): pass
+          ...
+          >>> class I4(I3): pass
+          ...
+          >>> spec = Declaration()
+          >>> int(spec.extends(Interface))
+          1
+          >>> spec = Declaration(I2)
+          >>> int(spec.extends(Interface))
+          1
+          >>> int(spec.extends(I1))
+          1
+          >>> int(spec.extends(I2))
+          1
+          >>> int(spec.extends(I3))
+          0
+          >>> int(spec.extends(I4))
+          0
+          >>> I2.extends(I2)
+          0
+          >>> I2.extends(I2, False)
+          1
+          >>> I2.extends(I2, strict=False)
+          1
+
+        """
+        return ((interface in self._implied)
+                and
+                ((not strict) or (self != interface))
+                )
+
+    def weakref(self, callback=None):
+        return weakref.ref(self, callback)
+
+    def get(self, name, default=None):
+        """Query for an attribute description
+        """
+        try:
+            attrs = self._v_attrs
+        except AttributeError:
+            attrs = self._v_attrs = {}
+        attr = attrs.get(name)
+        if attr is None:
+            for iface in self.__iro__:
+                attr = iface.direct(name)
+                if attr is not None:
+                    attrs[name] = attr
+                    break
+
+        if attr is None:
+            return default
+        else:
+            return attr
+
+class InterfaceClass(Element, InterfaceBase, Specification):
+    """Prototype (scarecrow) Interfaces Implementation."""
+
+    # We can't say this yet because we don't have enough
+    # infrastructure in place.
+    #
+    #implements(IInterface)
+
+    def __init__(self, name, bases=(), attrs=None, __doc__=None,
+                 __module__=None):
+
+        if attrs is None:
+            attrs = {}
+
+        if __module__ is None:
+            __module__ = attrs.get('__module__')
+            if isinstance(__module__, str):
+                del attrs['__module__']
+            else:
+                try:
+                    # Figure out what module defined the interface.
+                    # This is how cPython figures out the module of
+                    # a class, but of course it does it in C. :-/
+                    __module__ = sys._getframe(1).f_globals['__name__']
+                except (AttributeError, KeyError):
+                    pass
+
+        self.__module__ = __module__
+
+        d = attrs.get('__doc__')
+        if d is not None:
+            if not isinstance(d, Attribute):
+                if __doc__ is None:
+                    __doc__ = d
+                del attrs['__doc__']
+
+        if __doc__ is None:
+            __doc__ = ''
+
+        Element.__init__(self, name, __doc__)
+
+        tagged_data = attrs.pop(TAGGED_DATA, None)
+        if tagged_data is not None:
+            for key, val in tagged_data.items():
+                self.setTaggedValue(key, val)
+
+        for base in bases:
+            if not isinstance(base, InterfaceClass):
+                raise TypeError('Expected base interfaces')
+
+        Specification.__init__(self, bases)
+
+        # Make sure that all recorded attributes (and methods) are of type
+        # `Attribute` and `Method`
+        for name, attr in attrs.items():
+            if name == '__locals__':
+                # This happens under Python 3 sometimes, not sure why. /regebro
+                continue
+            if isinstance(attr, Attribute):
+                attr.interface = self
+                if not attr.__name__:
+                    attr.__name__ = name
+            elif isinstance(attr, FunctionType):
+                attrs[name] = fromFunction(attr, self, name=name)
+            elif attr is _decorator_non_return:
+                del attrs[name]
+            else:
+                raise InvalidInterface("Concrete attribute, " + name)
+
+        self.__attrs = attrs
+
+        self.__identifier__ = "%s.%s" % (self.__module__, self.__name__)
+
+    def interfaces(self):
+        """Return an iterator for the interfaces in the specification
+
+        for example::
+
+          >>> from zope.interface import Interface
+          >>> class I1(Interface): pass
+          ...
+          >>>
+          >>> i = I1.interfaces()
+          >>> [x.getName() for x in i]
+          ['I1']
+          >>> list(i)
+          []
+        """
+        yield self
+
+    def getBases(self):
+        return self.__bases__
+
+    def isEqualOrExtendedBy(self, other):
+        """Same interface or extends?"""
+        return self == other or other.extends(self)
+
+    def names(self, all=False):
+        """Return the attribute names defined by the interface."""
+        if not all:
+            return self.__attrs.keys()
+
+        r = self.__attrs.copy()
+
+        for base in self.__bases__:
+            r.update(dict.fromkeys(base.names(all)))
+
+        return r.keys()
+
+    def __iter__(self):
+        return iter(self.names(all=True))
+
+    def namesAndDescriptions(self, all=False):
+        """Return attribute names and descriptions defined by interface."""
+        if not all:
+            return self.__attrs.items()
+
+        r = {}
+        for base in self.__bases__[::-1]:
+            r.update(dict(base.namesAndDescriptions(all)))
+
+        r.update(self.__attrs)
+
+        return r.items()
+
+    def getDescriptionFor(self, name):
+        """Return the attribute description for the given name."""
+        r = self.get(name)
+        if r is not None:
+            return r
+
+        raise KeyError(name)
+
+    __getitem__ = getDescriptionFor
+
+    def __contains__(self, name):
+        return self.get(name) is not None
+
+    def direct(self, name):
+        return self.__attrs.get(name)
+
+    def queryDescriptionFor(self, name, default=None):
+        return self.get(name, default)
+
+    def deferred(self):
+        """Return a defered class corresponding to the interface."""
+        if hasattr(self, "_deferred"): return self._deferred
+
+        klass={}
+        exec "class %s: pass" % self.__name__ in klass
+        klass=klass[self.__name__]
+
+        self.__d(klass)
+
+        self._deferred=klass
+
+        return klass
+
+    def validateInvariants(self, obj, errors=None):
+        """validate object to defined invariants."""
+        for call in self.queryTaggedValue('invariants', []):
+            try:
+                call(obj)
+            except Invalid, e:
+                if errors is None:
+                    raise
+                else:
+                    errors.append(e)
+        for base in self.__bases__:
+            try:
+                base.validateInvariants(obj, errors)
+            except Invalid:
+                if errors is None:
+                    raise
+        if errors:
+            raise Invalid(errors)
+
+    def _getInterface(self, ob, name):
+        """Retrieve a named interface."""
+        return None
+
+    def __d(self, klass):
+        for k, v in self.__attrs.items():
+            if isinstance(v, Method) and not (k in klass.__dict__):
+                setattr(klass, k, v)
+
+        for b in self.__bases__:
+            b.__d(klass)
+
+    def __repr__(self):
+        try:
+            return self._v_repr
+        except AttributeError:
+            name = self.__name__
+            m = self.__module__
+            if m:
+                name = '%s.%s' % (m, name)
+            r = "<%s %s>" % (self.__class__.__name__, name)
+            self._v_repr = r
+            return r
+
+    def _call_conform(self, conform):
+        try:
+            return conform(self)
+        except TypeError:
+            # We got a TypeError. It might be an error raised by
+            # the __conform__ implementation, or *we* may have
+            # made the TypeError by calling an unbound method
+            # (object is a class).  In the later case, we behave
+            # as though there is no __conform__ method. We can
+            # detect this case by checking whether there is more
+            # than one traceback object in the traceback chain:
+            if sys.exc_info()[2].tb_next is not None:
+                # There is more than one entry in the chain, so
+                # reraise the error:
+                raise
+            # This clever trick is from Phillip Eby
+
+        return None
+
+    def __reduce__(self):
+        return self.__name__
+
+    def __cmp(self, o1, o2):
+        # Yes, I did mean to name this __cmp, rather than __cmp__.
+        # It is a private method used by __lt__ and __gt__.
+        # I don't want to override __eq__ because I want the default
+        # __eq__, which is really fast.
+        """Make interfaces sortable
+
+        TODO: It would ne nice if:
+
+           More specific interfaces should sort before less specific ones.
+           Otherwise, sort on name and module.
+
+           But this is too complicated, and we're going to punt on it
+           for now.
+
+        For now, sort on interface and module name.
+
+        None is treated as a pseudo interface that implies the loosest
+        contact possible, no contract. For that reason, all interfaces
+        sort before None.
+
+        """
+        if o1 is None:
+            return 1
+        if o2 is None:
+            return -1
+
+        n1 = (getattr(o1, '__name__', ''), getattr(o1,  '__module__', ''))
+        n2 = (getattr(o2, '__name__', ''), getattr(o2,  '__module__', ''))
+
+        # This spelling works under Python3, which doesn't have cmp().
+        return (n1 > n2) - (n1 < n2)
+
+    def __hash__(self):
+        d = self.__dict__
+        if '__module__' not in d or '__name__' not in d:
+            warnings.warn('Hashing uninitialized InterfaceClass instance')
+            return 1
+        return hash((self.__name__, self.__module__))
+
+    def __eq__(self, other):
+        c = self.__cmp(self, other)
+        return c == 0
+
+    def __ne__(self, other):
+        c = self.__cmp(self, other)
+        return c != 0
+
+    def __lt__(self, other):
+        c = self.__cmp(self, other)
+        return c < 0
+
+    def __le__(self, other):
+        c = self.__cmp(self, other)
+        return c <= 0
+
+    def __gt__(self, other):
+        c = self.__cmp(self, other)
+        return c > 0
+
+    def __ge__(self, other):
+        c = self.__cmp(self, other)
+        return c >= 0
+
+
+Interface = InterfaceClass("Interface", __module__ = 'zope.interface')
+
+class Attribute(Element):
+    """Attribute descriptions
+    """
+
+    # We can't say this yet because we don't have enough
+    # infrastructure in place.
+    #
+    # implements(IAttribute)
+
+    interface = None
+
+
+class Method(Attribute):
+    """Method interfaces
+
+    The idea here is that you have objects that describe methods.
+    This provides an opportunity for rich meta-data.
+    """
+
+    # We can't say this yet because we don't have enough
+    # infrastructure in place.
+    #
+    # implements(IMethod)
+
+    def __call__(self, *args, **kw):
+        raise BrokenImplementation(self.interface, self.__name__)
+
+    def getSignatureInfo(self):
+        return {'positional': self.positional,
+                'required': self.required,
+                'optional': self.optional,
+                'varargs': self.varargs,
+                'kwargs': self.kwargs,
+                }
+
+    def getSignatureString(self):
+        sig = []
+        for v in self.positional:
+            sig.append(v)
+            if v in self.optional.keys():
+                sig[-1] += "=" + `self.optional[v]`
+        if self.varargs:
+            sig.append("*" + self.varargs)
+        if self.kwargs:
+            sig.append("**" + self.kwargs)
+
+        return "(%s)" % ", ".join(sig)
+
+
+def fromFunction(func, interface=None, imlevel=0, name=None):
+    name = name or func.__name__
+    method = Method(name, func.__doc__)
+    defaults = func.func_defaults or ()
+    code = func.func_code
+    # Number of positional arguments
+    na = code.co_argcount-imlevel
+    names = code.co_varnames[imlevel:]
+    opt = {}
+    # Number of required arguments
+    nr = na-len(defaults)
+    if nr < 0:
+        defaults=defaults[-nr:]
+        nr = 0
+
+    # Determine the optional arguments.
+    opt.update(dict(zip(names[nr:], defaults)))
+
+    method.positional = names[:na]
+    method.required = names[:nr]
+    method.optional = opt
+
+    argno = na
+
+    # Determine the function's variable argument's name (i.e. *args)
+    if code.co_flags & CO_VARARGS:
+        method.varargs = names[argno]
+        argno = argno + 1
+    else:
+        method.varargs = None
+
+    # Determine the function's keyword argument's name (i.e. **kw)
+    if code.co_flags & CO_VARKEYWORDS:
+        method.kwargs = names[argno]
+    else:
+        method.kwargs = None
+
+    method.interface = interface
+
+    for key, value in func.__dict__.items():
+        method.setTaggedValue(key, value)
+
+    return method
+
+
+def fromMethod(meth, interface=None, name=None):
+    func = meth.im_func
+    return fromFunction(func, interface, imlevel=1, name=name)
+
+
+# Now we can create the interesting interfaces and wire them up:
+def _wire():
+    from zope.interface.declarations import classImplements
+
+    from zope.interface.interfaces import IAttribute
+    classImplements(Attribute, IAttribute)
+
+    from zope.interface.interfaces import IMethod
+    classImplements(Method, IMethod)
+
+    from zope.interface.interfaces import IInterface
+    classImplements(InterfaceClass, IInterface)
+
+    from zope.interface.interfaces import ISpecification
+    classImplements(Specification, ISpecification)
+
+# We import this here to deal with module dependencies.
+from zope.interface.declarations import implementedBy
+from zope.interface.declarations import providedBy
+from zope.interface.exceptions import InvalidInterface
+from zope.interface.exceptions import BrokenImplementation
diff --git a/src/zope/interface/interfaces.py b/src/zope/interface/interfaces.py
new file mode 100644 (file)
index 0000000..dbc7ffa
--- /dev/null
@@ -0,0 +1,1284 @@
+##############################################################################
+#
+# Copyright (c) 2002 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.
+#
+##############################################################################
+"""Interface Package Interfaces
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.interface.interface import Attribute
+from zope.interface.interface import Interface
+from zope.interface.declarations import implements
+from zope.interface.declarations import implementer # required by py3k fixers
+
+class IElement(Interface):
+    """Objects that have basic documentation and tagged values.
+    """
+
+    __name__ = Attribute('__name__', 'The object name')
+    __doc__  = Attribute('__doc__', 'The object doc string')
+
+    def getTaggedValue(tag):
+        """Returns the value associated with `tag`.
+
+        Raise a `KeyError` of the tag isn't set.
+        """
+
+    def queryTaggedValue(tag, default=None):
+        """Returns the value associated with `tag`.
+
+        Return the default value of the tag isn't set.
+        """
+
+    def getTaggedValueTags():
+        """Returns a list of all tags."""
+
+    def setTaggedValue(tag, value):
+        """Associates `value` with `key`."""
+
+
+class IAttribute(IElement):
+    """Attribute descriptors"""
+
+    interface = Attribute('interface',
+                          'Stores the interface instance in which the '
+                          'attribute is located.')
+
+
+class IMethod(IAttribute):
+    """Method attributes"""
+
+    def getSignatureInfo():
+        """Returns the signature information.
+
+        This method returns a dictionary with the following keys:
+
+        o `positional` - All positional arguments.
+
+        o `required` - A list of all required arguments.
+
+        o `optional` - A list of all optional arguments.
+
+        o `varargs` - The name of the varargs argument.
+
+        o `kwargs` - The name of the kwargs argument.
+        """
+
+    def getSignatureString():
+        """Return a signature string suitable for inclusion in documentation.
+
+        This method returns the function signature string. For example, if you
+        have `func(a, b, c=1, d='f')`, then the signature string is `(a, b,
+        c=1, d='f')`.
+        """
+
+class ISpecification(Interface):
+    """Object Behavioral specifications"""
+
+    def extends(other, strict=True):
+        """Test whether a specification extends another
+
+        The specification extends other if it has other as a base
+        interface or if one of it's bases extends other.
+
+        If strict is false, then the specification extends itself.
+        """
+
+    def isOrExtends(other):
+        """Test whether the specification is or extends another
+        """
+
+    def weakref(callback=None):
+        """Return a weakref to the specification
+
+        This method is, regrettably, needed to allow weakrefs to be
+        computed to security-proxied specifications.  While the
+        zope.interface package does not require zope.security or
+        zope.proxy, it has to be able to coexist with it.
+
+        """
+
+    __bases__ = Attribute("""Base specifications
+
+    A tuple if specifications from which this specification is
+    directly derived.
+
+    """)
+
+    __sro__ = Attribute("""Specification-resolution order
+
+    A tuple of the specification and all of it's ancestor
+    specifications from most specific to least specific.
+
+    (This is similar to the method-resolution order for new-style classes.)
+    """)
+
+    __iro__ = Attribute("""Interface-resolution order
+
+    A tuple of the of the specification's ancestor interfaces from
+    most specific to least specific.  The specification itself is
+    included if it is an interface.
+
+    (This is similar to the method-resolution order for new-style classes.)
+    """)
+
+    def get(name, default=None):
+        """Look up the description for a name
+
+        If the named attribute is not defined, the default is
+        returned.
+        """
+
+
+class IInterface(ISpecification, IElement):
+    """Interface objects
+
+    Interface objects describe the behavior of an object by containing
+    useful information about the object.  This information includes:
+
+      o Prose documentation about the object.  In Python terms, this
+        is called the "doc string" of the interface.  In this element,
+        you describe how the object works in prose language and any
+        other useful information about the object.
+
+      o Descriptions of attributes.  Attribute descriptions include
+        the name of the attribute and prose documentation describing
+        the attributes usage.
+
+      o Descriptions of methods.  Method descriptions can include:
+
+        - Prose "doc string" documentation about the method and its
+          usage.
+
+        - A description of the methods arguments; how many arguments
+          are expected, optional arguments and their default values,
+          the position or arguments in the signature, whether the
+          method accepts arbitrary arguments and whether the method
+          accepts arbitrary keyword arguments.
+
+      o Optional tagged data.  Interface objects (and their attributes and
+        methods) can have optional, application specific tagged data
+        associated with them.  Examples uses for this are examples,
+        security assertions, pre/post conditions, and other possible
+        information you may want to associate with an Interface or its
+        attributes.
+
+    Not all of this information is mandatory.  For example, you may
+    only want the methods of your interface to have prose
+    documentation and not describe the arguments of the method in
+    exact detail.  Interface objects are flexible and let you give or
+    take any of these components.
+
+    Interfaces are created with the Python class statement using
+    either Interface.Interface or another interface, as in::
+
+      from zope.interface import Interface
+
+      class IMyInterface(Interface):
+        '''Interface documentation'''
+
+        def meth(arg1, arg2):
+            '''Documentation for meth'''
+
+        # Note that there is no self argument
+
+     class IMySubInterface(IMyInterface):
+        '''Interface documentation'''
+
+        def meth2():
+            '''Documentation for meth2'''
+
+    You use interfaces in two ways:
+
+    o You assert that your object implement the interfaces.
+
+      There are several ways that you can assert that an object
+      implements an interface:
+
+      1. Call zope.interface.implements in your class definition.
+
+      2. Call zope.interfaces.directlyProvides on your object.
+
+      3. Call 'zope.interface.classImplements' to assert that instances
+         of a class implement an interface.
+
+         For example::
+
+           from zope.interface import classImplements
+
+           classImplements(some_class, some_interface)
+
+         This approach is useful when it is not an option to modify
+         the class source.  Note that this doesn't affect what the
+         class itself implements, but only what its instances
+         implement.
+
+    o You query interface meta-data. See the IInterface methods and
+      attributes for details.
+
+    """
+
+    def providedBy(object):
+        """Test whether the interface is implemented by the object
+
+        Return true of the object asserts that it implements the
+        interface, including asserting that it implements an extended
+        interface.
+        """
+
+    def implementedBy(class_):
+        """Test whether the interface is implemented by instances of the class
+
+        Return true of the class asserts that its instances implement the
+        interface, including asserting that they implement an extended
+        interface.
+        """
+
+    def names(all=False):
+        """Get the interface attribute names
+
+        Return a sequence of the names of the attributes, including
+        methods, included in the interface definition.
+
+        Normally, only directly defined attributes are included. If
+        a true positional or keyword argument is given, then
+        attributes defined by base classes will be included.
+        """
+
+    def namesAndDescriptions(all=False):
+        """Get the interface attribute names and descriptions
+
+        Return a sequence of the names and descriptions of the
+        attributes, including methods, as name-value pairs, included
+        in the interface definition.
+
+        Normally, only directly defined attributes are included. If
+        a true positional or keyword argument is given, then
+        attributes defined by base classes will be included.
+        """
+
+    def __getitem__(name):
+        """Get the description for a name
+
+        If the named attribute is not defined, a KeyError is raised.
+        """
+
+    def direct(name):
+        """Get the description for the name if it was defined by the interface
+
+        If the interface doesn't define the name, returns None.
+        """
+
+    def validateInvariants(obj, errors=None):
+        """Validate invariants
+
+        Validate object to defined invariants.  If errors is None,
+        raises first Invalid error; if errors is a list, appends all errors
+        to list, then raises Invalid with the errors as the first element
+        of the "args" tuple."""
+
+    def __contains__(name):
+        """Test whether the name is defined by the interface"""
+
+    def __iter__():
+        """Return an iterator over the names defined by the interface
+
+        The names iterated include all of the names defined by the
+        interface directly and indirectly by base interfaces.
+        """
+
+    __module__ = Attribute("""The name of the module defining the interface""")
+
+class IDeclaration(ISpecification):
+    """Interface declaration
+
+    Declarations are used to express the interfaces implemented by
+    classes or provided by objects.
+    """
+
+    def __contains__(interface):
+        """Test whether an interface is in the specification
+
+        Return true if the given interface is one of the interfaces in
+        the specification and false otherwise.
+        """
+
+    def __iter__():
+        """Return an iterator for the interfaces in the specification
+        """
+
+    def flattened():
+        """Return an iterator of all included and extended interfaces
+
+        An iterator is returned for all interfaces either included in
+        or extended by interfaces included in the specifications
+        without duplicates. The interfaces are in "interface
+        resolution order". The interface resolution order is such that
+        base interfaces are listed after interfaces that extend them
+        and, otherwise, interfaces are included in the order that they
+        were defined in the specification.
+        """
+
+    def __sub__(interfaces):
+        """Create an interface specification with some interfaces excluded
+
+        The argument can be an interface or an interface
+        specifications.  The interface or interfaces given in a
+        specification are subtracted from the interface specification.
+
+        Removing an interface that is not in the specification does
+        not raise an error. Doing so has no effect.
+
+        Removing an interface also removes sub-interfaces of the interface.
+
+        """
+
+    def __add__(interfaces):
+        """Create an interface specification with some interfaces added
+
+        The argument can be an interface or an interface
+        specifications.  The interface or interfaces given in a
+        specification are added to the interface specification.
+
+        Adding an interface that is already in the specification does
+        not raise an error. Doing so has no effect.
+        """
+
+    def __nonzero__():
+        """Return a true value of the interface specification is non-empty
+        """
+
+class IInterfaceDeclaration(Interface):
+    """Declare and check the interfaces of objects
+
+    The functions defined in this interface are used to declare the
+    interfaces that objects provide and to query the interfaces that have
+    been declared.
+
+    Interfaces can be declared for objects in two ways:
+
+    - Interfaces are declared for instances of the object's class
+
+    - Interfaces are declared for the object directly.
+
+    The interfaces declared for an object are, therefore, the union of
+    interfaces declared for the object directly and the interfaces
+    declared for instances of the object's class.
+
+    Note that we say that a class implements the interfaces provided
+    by it's instances.  An instance can also provide interfaces
+    directly.  The interfaces provided by an object are the union of
+    the interfaces provided directly and the interfaces implemented by
+    the class.
+    """
+
+    def providedBy(ob):
+        """Return the interfaces provided by an object
+
+        This is the union of the interfaces directly provided by an
+        object and interfaces implemented by it's class.
+
+        The value returned is an IDeclaration.
+        """
+
+    def implementedBy(class_):
+        """Return the interfaces implemented for a class' instances
+
+        The value returned is an IDeclaration.
+        """
+
+    def classImplements(class_, *interfaces):
+        """Declare additional interfaces implemented for instances of a class
+
+        The arguments after the class are one or more interfaces or
+        interface specifications (IDeclaration objects).
+
+        The interfaces given (including the interfaces in the
+        specifications) are added to any interfaces previously
+        declared.
+
+        Consider the following example::
+
+          class C(A, B):
+             ...
+
+          classImplements(C, I1, I2)
+
+
+        Instances of ``C`` provide ``I1``, ``I2``, and whatever interfaces
+        instances of ``A`` and ``B`` provide.
+        """
+
+    def implementer(*interfaces):
+        """Create a decorator for declaring interfaces implemented by a facory
+
+        A callable is returned that makes an implements declaration on
+        objects passed to it.
+        """
+
+    def classImplementsOnly(class_, *interfaces):
+        """Declare the only interfaces implemented by instances of a class
+
+        The arguments after the class are one or more interfaces or
+        interface specifications (IDeclaration objects).
+
+        The interfaces given (including the interfaces in the
+        specifications) replace any previous declarations.
+
+        Consider the following example::
+
+          class C(A, B):
+             ...
+
+          classImplements(C, IA, IB. IC)
+          classImplementsOnly(C. I1, I2)
+
+        Instances of ``C`` provide only ``I1``, ``I2``, and regardless of
+        whatever interfaces instances of ``A`` and ``B`` implement.
+        """
+        
+    def implementer_only(*interfaces):
+        """Create a decorator for declaring the only interfaces implemented 
+        
+        A callable is returned that makes an implements declaration on
+        objects passed to it.
+        """
+
+    def directlyProvidedBy(object):
+        """Return the interfaces directly provided by the given object
+
+        The value returned is an IDeclaration.
+        """
+
+    def directlyProvides(object, *interfaces):
+        """Declare interfaces declared directly for an object
+
+        The arguments after the object are one or more interfaces or
+        interface specifications (IDeclaration objects).
+
+        The interfaces given (including the interfaces in the
+        specifications) replace interfaces previously
+        declared for the object.
+
+        Consider the following example::
+
+          class C(A, B):
+             ...
+
+          ob = C()
+          directlyProvides(ob, I1, I2)
+
+        The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+        instances have been declared for instances of ``C``.
+
+        To remove directly provided interfaces, use ``directlyProvidedBy`` and
+        subtract the unwanted interfaces. For example::
+
+          directlyProvides(ob, directlyProvidedBy(ob)-I2)
+
+        removes I2 from the interfaces directly provided by
+        ``ob``. The object, ``ob`` no longer directly provides ``I2``,
+        although it might still provide ``I2`` if it's class
+        implements ``I2``.
+
+        To add directly provided interfaces, use ``directlyProvidedBy`` and
+        include additional interfaces.  For example::
+
+          directlyProvides(ob, directlyProvidedBy(ob), I2)
+
+        adds I2 to the interfaces directly provided by ob.
+        """
+
+    def alsoProvides(object, *interfaces):
+        """Declare additional interfaces directly for an object::
+
+          alsoProvides(ob, I1)
+
+        is equivalent to::
+
+          directlyProvides(ob, directlyProvidedBy(ob), I1)
+        """
+
+    def noLongerProvides(object, interface):
+        """Remove an interface from the list of an object's directly
+        provided interfaces::
+
+          noLongerProvides(ob, I1)
+
+        is equivalent to::
+
+          directlyProvides(ob, directlyProvidedBy(ob)-I1)
+
+        with the exception that if ``I1`` is an interface that is
+        provided by ``ob`` through the class's implementation,
+        ValueError is raised.
+        """
+
+    def implements(*interfaces):
+        """Declare interfaces implemented by instances of a class
+
+        This function is called in a class definition.
+
+        The arguments are one or more interfaces or interface
+        specifications (IDeclaration objects).
+
+        The interfaces given (including the interfaces in the
+        specifications) are added to any interfaces previously
+        declared.
+
+        Previous declarations include declarations for base classes
+        unless implementsOnly was used.
+
+        This function is provided for convenience. It provides a more
+        convenient way to call classImplements. For example::
+
+          implements(I1)
+
+        is equivalent to calling::
+
+          classImplements(C, I1)
+
+        after the class has been created.
+
+        Consider the following example::
+
+          class C(A, B):
+            implements(I1, I2)
+
+
+        Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces
+        instances of ``A`` and ``B`` implement.
+        """
+
+    def implementsOnly(*interfaces):
+        """Declare the only interfaces implemented by instances of a class
+
+        This function is called in a class definition.
+
+        The arguments are one or more interfaces or interface
+        specifications (IDeclaration objects).
+
+        Previous declarations including declarations for base classes
+        are overridden.
+
+        This function is provided for convenience. It provides a more
+        convenient way to call classImplementsOnly. For example::
+
+          implementsOnly(I1)
+
+        is equivalent to calling::
+
+          classImplementsOnly(I1)
+
+        after the class has been created.
+
+        Consider the following example::
+
+          class C(A, B):
+            implementsOnly(I1, I2)
+
+
+        Instances of ``C`` implement ``I1``, ``I2``, regardless of what
+        instances of ``A`` and ``B`` implement.
+        """
+
+    def classProvides(*interfaces):
+        """Declare interfaces provided directly by a class
+
+        This function is called in a class definition.
+
+        The arguments are one or more interfaces or interface
+        specifications (IDeclaration objects).
+
+        The given interfaces (including the interfaces in the
+        specifications) are used to create the class's direct-object
+        interface specification.  An error will be raised if the module
+        class has an direct interface specification.  In other words, it is
+        an error to call this function more than once in a class
+        definition.
+
+        Note that the given interfaces have nothing to do with the
+        interfaces implemented by instances of the class.
+
+        This function is provided for convenience. It provides a more
+        convenient way to call directlyProvides for a class. For example::
+
+          classProvides(I1)
+
+        is equivalent to calling::
+
+          directlyProvides(theclass, I1)
+
+        after the class has been created.
+        """
+    def provider(*interfaces):
+        """A class decorator version of classProvides"""
+
+    def moduleProvides(*interfaces):
+        """Declare interfaces provided by a module
+
+        This function is used in a module definition.
+
+        The arguments are one or more interfaces or interface
+        specifications (IDeclaration objects).
+
+        The given interfaces (including the interfaces in the
+        specifications) are used to create the module's direct-object
+        interface specification.  An error will be raised if the module
+        already has an interface specification.  In other words, it is
+        an error to call this function more than once in a module
+        definition.
+
+        This function is provided for convenience. It provides a more
+        convenient way to call directlyProvides for a module. For example::
+
+          moduleImplements(I1)
+
+        is equivalent to::
+
+          directlyProvides(sys.modules[__name__], I1)
+        """
+
+    def Declaration(*interfaces):
+        """Create an interface specification
+
+        The arguments are one or more interfaces or interface
+        specifications (IDeclaration objects).
+
+        A new interface specification (IDeclaration) with
+        the given interfaces is returned.
+        """
+
+class IAdapterRegistry(Interface):
+    """Provide an interface-based registry for adapters
+
+    This registry registers objects that are in some sense "from" a
+    sequence of specification to an interface and a name.
+
+    No specific semantics are assumed for the registered objects,
+    however, the most common application will be to register factories
+    that adapt objects providing required specifications to a provided
+    interface.
+    """
+
+    def register(required, provided, name, value):
+        """Register a value
+
+        A value is registered for a *sequence* of required specifications, a
+        provided interface, and a name.
+        """
+
+    def registered(required, provided, name=u''):
+        """Return the component registered for the given interfaces and name
+
+        Unlike the lookup method, this methods won't retrieve
+        components registered for more specific required interfaces or
+        less specific provided interfaces.
+
+        If no component was registered exactly for the given
+        interfaces and name, then None is returned.
+
+        """
+
+    def lookup(required, provided, name='', default=None):
+        """Lookup a value
+
+        A value is looked up based on a *sequence* of required
+        specifications, a provided interface, and a name.
+        """
+
+    def queryMultiAdapter(objects, provided, name=u'', default=None):
+        """Adapt a sequence of objects to a named, provided, interface
+        """
+
+    def lookup1(required, provided, name=u'', default=None):
+        """Lookup a value using a single required interface
+
+        A value is looked up based on a single required
+        specifications, a provided interface, and a name.
+        """
+
+    def queryAdapter(object, provided, name=u'', default=None):
+        """Adapt an object using a registered adapter factory.
+        """
+
+    def adapter_hook(provided, object, name=u'', default=None):
+        """Adapt an object using a registered adapter factory.
+        """
+
+    def lookupAll(required, provided):
+        """Find all adapters from the required to the provided interfaces
+
+        An iterable object is returned that provides name-value two-tuples.
+        """
+
+    def names(required, provided):
+        """Return the names for which there are registered objects
+        """
+
+    def subscribe(required, provided, subscriber, name=u''):
+        """Register a subscriber
+
+        A subscriber is registered for a *sequence* of required
+        specifications, a provided interface, and a name.
+
+        Multiple subscribers may be registered for the same (or
+        equivalent) interfaces.
+        """
+
+    def subscriptions(required, provided, name=u''):
+        """Get a sequence of subscribers
+
+        Subscribers for a *sequence* of required interfaces, and a provided
+        interface are returned.
+        """
+
+    def subscribers(objects, provided, name=u''):
+        """Get a sequence of subscription adapters
+        """
+
+# begin formerly in zope.component
+
+class ComponentLookupError(LookupError):
+    """A component could not be found."""
+
+class Invalid(Exception):
+    """A component doesn't satisfy a promise."""
+
+class IObjectEvent(Interface):
+    """An event related to an object.
+
+    The object that generated this event is not necessarily the object
+    refered to by location.
+    """
+
+    object = Attribute("The subject of the event.")
+
+
+class ObjectEvent(object):
+    implements(IObjectEvent)
+
+    def __init__(self, object):
+        self.object = object
+
+class IComponentLookup(Interface):
+    """Component Manager for a Site
+
+    This object manages the components registered at a particular site. The
+    definition of a site is intentionally vague.
+    """
+
+    adapters = Attribute(
+        "Adapter Registry to manage all registered adapters.")
+
+    utilities = Attribute(
+        "Adapter Registry to manage all registered utilities.")
+
+    def queryAdapter(object, interface, name=u'', default=None):
+        """Look for a named adapter to an interface for an object
+
+        If a matching adapter cannot be found, returns the default.
+        """
+
+    def getAdapter(object, interface, name=u''):
+        """Look for a named adapter to an interface for an object
+
+        If a matching adapter cannot be found, a ComponentLookupError
+        is raised.
+        """
+
+    def queryMultiAdapter(objects, interface, name=u'', default=None):
+        """Look for a multi-adapter to an interface for multiple objects
+
+        If a matching adapter cannot be found, returns the default.
+        """
+
+    def getMultiAdapter(objects, interface, name=u''):
+        """Look for a multi-adapter to an interface for multiple objects
+
+        If a matching adapter cannot be found, a ComponentLookupError
+        is raised.
+        """
+
+    def getAdapters(objects, provided):
+        """Look for all matching adapters to a provided interface for objects
+
+        Return an iterable of name-adapter pairs for adapters that
+        provide the given interface.
+        """
+
+    def subscribers(objects, provided):
+        """Get subscribers
+
+        Subscribers are returned that provide the provided interface
+        and that depend on and are comuted from the sequence of
+        required objects.
+        """
+
+    def handle(*objects):
+        """Call handlers for the given objects
+
+        Handlers registered for the given objects are called.
+        """
+
+    def queryUtility(interface, name='', default=None):
+        """Look up a utility that provides an interface.
+
+        If one is not found, returns default.
+        """
+
+    def getUtilitiesFor(interface):
+        """Look up the registered utilities that provide an interface.
+
+        Returns an iterable of name-utility pairs.
+        """
+
+    def getAllUtilitiesRegisteredFor(interface):
+        """Return all registered utilities for an interface
+
+        This includes overridden utilities.
+
+        An iterable of utility instances is returned.  No names are
+        returned.
+        """
+
+class IRegistration(Interface):
+    """A registration-information object
+    """
+
+    registry = Attribute("The registry having the registration")
+
+    name = Attribute("The registration name")
+
+    info = Attribute("""Information about the registration
+
+    This is information deemed useful to people browsing the
+    configuration of a system. It could, for example, include
+    commentary or information about the source of the configuration.
+    """)
+
+class IUtilityRegistration(IRegistration):
+    """Information about the registration of a utility
+    """
+
+    factory = Attribute("The factory used to create the utility. Optional.")
+    component = Attribute("The object registered")
+    provided = Attribute("The interface provided by the component")
+
+class _IBaseAdapterRegistration(IRegistration):
+    """Information about the registration of an adapter
+    """
+
+    factory = Attribute("The factory used to create adapters")
+
+    required = Attribute("""The adapted interfaces
+
+    This is a sequence of interfaces adapters by the registered
+    factory.  The factory will be caled with a sequence of objects, as
+    positional arguments, that provide these interfaces.
+    """)
+
+    provided = Attribute("""The interface provided by the adapters.
+
+    This interface is implemented by the factory
+    """)
+
+class IAdapterRegistration(_IBaseAdapterRegistration):
+    """Information about the registration of an adapter
+    """
+
+class ISubscriptionAdapterRegistration(_IBaseAdapterRegistration):
+    """Information about the registration of a subscription adapter
+    """
+
+class IHandlerRegistration(IRegistration):
+
+    handler = Attribute("An object called used to handle an event")
+
+    required = Attribute("""The handled interfaces
+
+    This is a sequence of interfaces handled by the registered
+    handler.  The handler will be caled with a sequence of objects, as
+    positional arguments, that provide these interfaces.
+    """)
+
+class IRegistrationEvent(IObjectEvent):
+    """An event that involves a registration"""
+
+class RegistrationEvent(ObjectEvent):
+    """There has been a change in a registration
+    """
+    implements(IRegistrationEvent)
+
+    def __repr__(self):
+        return "%s event:\n%r" % (self.__class__.__name__, self.object)
+
+class IRegistered(IRegistrationEvent):
+    """A component or factory was registered
+    """
+
+class Registered(RegistrationEvent):
+    implements(IRegistered)
+
+class IUnregistered(IRegistrationEvent):
+    """A component or factory was unregistered
+    """
+
+class Unregistered(RegistrationEvent):
+    """A component or factory was unregistered
+    """
+    implements(IUnregistered)
+
+class IComponentRegistry(Interface):
+    """Register components
+    """
+
+    def registerUtility(component=None, provided=None, name=u'',
+                        info=u'', factory=None):
+        """Register a utility
+
+        factory
+           Factory for the component to be registerd.
+
+        component
+           The registered component
+
+        provided
+           This is the interface provided by the utility.  If the
+           component provides a single interface, then this
+           argument is optional and the component-implemented
+           interface will be used.
+
+        name
+           The utility name.
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+
+        Only one of component and factory can be used.
+        A Registered event is generated with an IUtilityRegistration.
+        """
+
+    def unregisterUtility(component=None, provided=None, name=u'',
+                          factory=None):
+        """Unregister a utility
+
+        A boolean is returned indicating whether the registry was
+        changed.  If the given component is None and there is no
+        component registered, or if the given component is not
+        None and is not registered, then the function returns
+        False, otherwise it returns True.
+
+        factory
+           Factory for the component to be unregisterd.
+
+        component
+           The registered component The given component can be
+           None, in which case any component registered to provide
+           the given provided interface with the given name is
+           unregistered.
+
+        provided
+           This is the interface provided by the utility.  If the
+           component is not None and provides a single interface,
+           then this argument is optional and the
+           component-implemented interface will be used.
+
+        name
+           The utility name.
+
+        Only one of component and factory can be used.
+        An UnRegistered event is generated with an IUtilityRegistration.
+        """
+
+    def registeredUtilities():
+        """Return an iterable of IUtilityRegistration instances.
+
+        These registrations describe the current utility registrations
+        in the object.
+        """
+
+    def registerAdapter(factory, required=None, provided=None, name=u'',
+                       info=u''):
+        """Register an adapter factory
+
+        Parameters:
+
+        factory
+            The object used to compute the adapter
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute is usually attribute is
+            normally set in class definitions using adapts
+            function, or for callables using the adapter
+            decorator.  If the factory doesn't have a
+            __component_adapts__ adapts attribute, then this
+            argument is required.
+
+        provided
+            This is the interface provided by the adapter and
+            implemented by the factory.  If the factory
+            implements a single interface, then this argument is
+            optional and the factory-implemented interface will be
+            used.
+
+        name
+            The adapter name.
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+
+        A Registered event is generated with an IAdapterRegistration.
+        """
+
+    def unregisterAdapter(factory=None, required=None,
+                          provided=None, name=u''):
+        """Register an adapter factory
+
+        A boolean is returned indicating whether the registry was
+        changed.  If the given component is None and there is no
+        component registered, or if the given component is not
+        None and is not registered, then the function returns
+        False, otherwise it returns True.
+
+        Parameters:
+
+        factory
+            This is the object used to compute the adapter. The
+            factory can be None, in which case any factory
+            registered to implement the given provided interface
+            for the given required specifications with the given
+            name is unregistered.
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If the factory is not None and the required
+            arguments is omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute attribute is normally
+            set in class definitions using adapts function, or for
+            callables using the adapter decorator.  If the factory
+            is None or doesn't have a __component_adapts__ adapts
+            attribute, then this argument is required.
+
+        provided
+            This is the interface provided by the adapter and
+            implemented by the factory.  If the factory is not
+            None and implements a single interface, then this
+            argument is optional and the factory-implemented
+            interface will be used.
+
+        name
+            The adapter name.
+
+        An Unregistered event is generated with an IAdapterRegistration.
+        """
+
+    def registeredAdapters():
+        """Return an iterable of IAdapterRegistration instances.
+
+        These registrations describe the current adapter registrations
+        in the object.
+        """
+
+    def registerSubscriptionAdapter(factory, required=None, provides=None,
+                                    name=u'', info=''):
+        """Register a subscriber factory
+
+        Parameters:
+
+        factory
+            The object used to compute the adapter
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute is usually attribute is
+            normally set in class definitions using adapts
+            function, or for callables using the adapter
+            decorator.  If the factory doesn't have a
+            __component_adapts__ adapts attribute, then this
+            argument is required.
+
+        provided
+            This is the interface provided by the adapter and
+            implemented by the factory.  If the factory implements
+            a single interface, then this argument is optional and
+            the factory-implemented interface will be used.
+
+        name
+            The adapter name.
+
+            Currently, only the empty string is accepted.  Other
+            strings will be accepted in the future when support for
+            named subscribers is added.
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+
+        A Registered event is generated with an
+        ISubscriptionAdapterRegistration.
+        """
+
+    def unregisterSubscriptionAdapter(factory=None, required=None,
+                                      provides=None, name=u''):
+        """Unregister a subscriber factory.
+
+        A boolean is returned indicating whether the registry was
+        changed.  If the given component is None and there is no
+        component registered, or if the given component is not
+        None and is not registered, then the function returns
+        False, otherwise it returns True.
+
+        Parameters:
+
+        factory
+            This is the object used to compute the adapter. The
+            factory can be None, in which case any factories
+            registered to implement the given provided interface
+            for the given required specifications with the given
+            name are unregistered.
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If the factory is not None and the required
+            arguments is omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute attribute is normally
+            set in class definitions using adapts function, or for
+            callables using the adapter decorator.  If the factory
+            is None or doesn't have a __component_adapts__ adapts
+            attribute, then this argument is required.
+
+        provided
+            This is the interface provided by the adapter and
+            implemented by the factory.  If the factory is not
+            None implements a single interface, then this argument
+            is optional and the factory-implemented interface will
+            be used.
+
+        name
+            The adapter name.
+
+            Currently, only the empty string is accepted.  Other
+            strings will be accepted in the future when support for
+            named subscribers is added.
+
+        An Unregistered event is generated with an
+        ISubscriptionAdapterRegistration.
+        """
+
+    def registeredSubscriptionAdapters():
+        """Return an iterable of ISubscriptionAdapterRegistration instances.
+
+        These registrations describe the current subscription adapter
+        registrations in the object.
+        """
+
+    def registerHandler(handler, required=None, name=u'', info=''):
+        """Register a handler.
+
+        A handler is a subscriber that doesn't compute an adapter
+        but performs some function when called.
+
+        Parameters:
+
+        handler
+            The object used to handle some event represented by
+            the objects passed to it.
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute is usually attribute is
+            normally set in class definitions using adapts
+            function, or for callables using the adapter
+            decorator.  If the factory doesn't have a
+            __component_adapts__ adapts attribute, then this
+            argument is required.
+
+        name
+            The handler name.
+
+            Currently, only the empty string is accepted.  Other
+            strings will be accepted in the future when support for
+            named handlers is added.
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+
+
+        A Registered event is generated with an IHandlerRegistration.
+        """
+
+    def unregisterHandler(handler=None, required=None, name=u''):
+        """Unregister a handler.
+
+        A handler is a subscriber that doesn't compute an adapter
+        but performs some function when called.
+
+        A boolean is returned indicating whether the registry was
+        changed.
+
+        Parameters:
+
+        handler
+            This is the object used to handle some event
+            represented by the objects passed to it. The handler
+            can be None, in which case any handlers registered for
+            the given required specifications with the given are
+            unregistered.
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute is usually attribute is
+            normally set in class definitions using adapts
+            function, or for callables using the adapter
+            decorator.  If the factory doesn't have a
+            __component_adapts__ adapts attribute, then this
+            argument is required.
+
+        name
+            The handler name.
+
+            Currently, only the empty string is accepted.  Other
+            strings will be accepted in the future when support for
+            named handlers is added.
+
+        An Unregistered event is generated with an IHandlerRegistration.
+        """
+
+    def registeredHandlers():
+        """Return an iterable of IHandlerRegistration instances.
+
+        These registrations describe the current handler registrations
+        in the object.
+        """
+
+
+class IComponents(IComponentLookup, IComponentRegistry):
+    """Component registration and access
+    """
+
+
+# end formerly in zope.component
diff --git a/src/zope/interface/registry.py b/src/zope/interface/registry.py
new file mode 100644 (file)
index 0000000..6310686
--- /dev/null
@@ -0,0 +1,545 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Basic components support
+"""
+import sys
+import types
+
+try:
+    from zope.event import notify
+except ImportError:
+    def notify(*arg, **kw): pass
+
+from zope.interface.interfaces import ISpecification
+from zope.interface.interfaces import ComponentLookupError
+from zope.interface.interfaces import IAdapterRegistration
+from zope.interface.interfaces import IComponents
+from zope.interface.interfaces import IHandlerRegistration
+from zope.interface.interfaces import ISubscriptionAdapterRegistration
+from zope.interface.interfaces import IUtilityRegistration
+from zope.interface.interfaces import Registered
+from zope.interface.interfaces import Unregistered
+
+from zope.interface.interface import Interface
+from zope.interface.declarations import implementedBy
+from zope.interface.declarations import implements
+from zope.interface.declarations import implementsOnly
+from zope.interface.declarations import providedBy
+from zope.interface.declarations import implementer # required by py3k fixers
+from zope.interface.declarations import implementer_only # req by py3k fixers
+from zope.interface.adapter import AdapterRegistry
+
+if sys.version_info[0] == 3:
+    def _u(s):
+        return s
+    class_types = type
+    string_types = (str,)
+else:
+    def _u(s):
+        return unicode(s, 'unicode_escape')
+    class_types = (type, types.ClassType)
+    string_types = (basestring,)
+
+class Components(object):
+
+    implements(IComponents)
+
+    def __init__(self, name='', bases=()):
+        assert isinstance(name, string_types)
+        self.__name__ = name
+        self._init_registries()
+        self._init_registrations()
+        self.__bases__ = tuple(bases)
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__, self.__name__)
+
+    def _init_registries(self):
+        self.adapters = AdapterRegistry()
+        self.utilities = AdapterRegistry()
+
+    def _init_registrations(self):
+        self._utility_registrations = {}
+        self._adapter_registrations = {}
+        self._subscription_registrations = []
+        self._handler_registrations = []
+
+    def _getBases(self):
+        # Subclasses might override
+        return self.__dict__.get('__bases__', ())
+
+    def _setBases(self, bases):
+        # Subclasses might override
+        self.adapters.__bases__ = tuple([
+            base.adapters for base in bases])
+        self.utilities.__bases__ = tuple([
+            base.utilities for base in bases])
+        self.__dict__['__bases__'] = tuple(bases)
+
+    __bases__ = property(
+        lambda self: self._getBases(),
+        lambda self, bases: self._setBases(bases),
+        )
+
+    def registerUtility(self, component=None, provided=None, name=_u(''), 
+                        info=_u(''), event=True, factory=None):
+        if factory:
+            if component:
+                raise TypeError("Can't specify factory and component.")
+            component = factory()
+
+        if provided is None:
+            provided = _getUtilityProvided(component)
+
+        reg = self._utility_registrations.get((provided, name))
+        if reg is not None:
+            if reg[:2] == (component, info):
+                # already registered
+                return
+            self.unregisterUtility(reg[0], provided, name)
+
+        subscribed = False
+        for ((p, _), data) in iter(self._utility_registrations.items()):
+            if p == provided and data[0] == component:
+                subscribed = True
+                break
+
+        self._utility_registrations[(provided, name)] = component, info, factory
+        self.utilities.register((), provided, name, component)
+
+        if not subscribed:
+            self.utilities.subscribe((), provided, component)
+
+        if event:
+            notify(Registered(
+                UtilityRegistration(self, provided, name, component, info,
+                                    factory)
+                ))
+
+    def unregisterUtility(self, component=None, provided=None, name=_u(''),
+                          factory=None):
+        if factory:
+            if component:
+                raise TypeError("Can't specify factory and component.")
+            component = factory()
+
+        if provided is None:
+            if component is None:
+                raise TypeError("Must specify one of component, factory and "
+                                "provided")
+            provided = _getUtilityProvided(component)
+
+        old = self._utility_registrations.get((provided, name))
+        if (old is None) or ((component is not None) and
+                             (component != old[0])):
+            return False
+
+        if component is None:
+            component = old[0]
+
+        # Note that component is now the old thing registered
+
+        del self._utility_registrations[(provided, name)]
+        self.utilities.unregister((), provided, name)
+
+        subscribed = False
+        for ((p, _), data) in iter(self._utility_registrations.items()):
+            if p == provided and data[0] == component:
+                subscribed = True
+                break
+
+        if not subscribed:
+            self.utilities.unsubscribe((), provided, component)
+
+        notify(Unregistered(
+            UtilityRegistration(self, provided, name, component, *old[1:])
+            ))
+
+        return True
+
+    def registeredUtilities(self):
+        for ((provided, name), data
+             ) in iter(self._utility_registrations.items()):
+            yield UtilityRegistration(self, provided, name, *data)
+
+    def queryUtility(self, provided, name=_u(''), default=None):
+        return self.utilities.lookup((), provided, name, default)
+
+    def getUtility(self, provided, name=_u('')):
+        utility = self.utilities.lookup((), provided, name)
+        if utility is None:
+            raise ComponentLookupError(provided, name)
+        return utility
+
+    def getUtilitiesFor(self, interface):
+        for name, utility in self.utilities.lookupAll((), interface):
+            yield name, utility
+
+    def getAllUtilitiesRegisteredFor(self, interface):
+        return self.utilities.subscriptions((), interface)
+
+    def registerAdapter(self, factory, required=None, provided=None, 
+                        name=_u(''), info=_u(''), event=True):
+        if provided is None:
+            provided = _getAdapterProvided(factory)
+        required = _getAdapterRequired(factory, required)
+        self._adapter_registrations[(required, provided, name)
+                                    ] = factory, info
+        self.adapters.register(required, provided, name, factory)
+
+        if event:
+            notify(Registered(
+                AdapterRegistration(self, required, provided, name,
+                                    factory, info)
+                ))
+
+
+    def unregisterAdapter(self, factory=None,
+                          required=None, provided=None, name=_u(''),
+                          ):
+        if provided is None:
+            if factory is None:
+                raise TypeError("Must specify one of factory and provided")
+            provided = _getAdapterProvided(factory)
+
+        if (required is None) and (factory is None):
+            raise TypeError("Must specify one of factory and required")
+
+        required = _getAdapterRequired(factory, required)
+        old = self._adapter_registrations.get((required, provided, name))
+        if (old is None) or ((factory is not None) and
+                             (factory != old[0])):
+            return False
+
+        del self._adapter_registrations[(required, provided, name)]
+        self.adapters.unregister(required, provided, name)
+
+        notify(Unregistered(
+            AdapterRegistration(self, required, provided, name,
+                                *old)
+            ))
+
+        return True
+
+    def registeredAdapters(self):
+        for ((required, provided, name), (component, info)
+             ) in iter(self._adapter_registrations.items()):
+            yield AdapterRegistration(self, required, provided, name,
+                                      component, info)
+
+    def queryAdapter(self, object, interface, name=_u(''), default=None):
+        return self.adapters.queryAdapter(object, interface, name, default)
+
+    def getAdapter(self, object, interface, name=_u('')):
+        adapter = self.adapters.queryAdapter(object, interface, name)
+        if adapter is None:
+            raise ComponentLookupError(object, interface, name)
+        return adapter
+
+    def queryMultiAdapter(self, objects, interface, name=_u(''), 
+                          default=None):
+        return self.adapters.queryMultiAdapter(
+            objects, interface, name, default)
+
+    def getMultiAdapter(self, objects, interface, name=_u('')):
+        adapter = self.adapters.queryMultiAdapter(objects, interface, name)
+        if adapter is None:
+            raise ComponentLookupError(objects, interface, name)
+        return adapter
+
+    def getAdapters(self, objects, provided):
+        for name, factory in self.adapters.lookupAll(
+            list(map(providedBy, objects)),
+            provided):
+            adapter = factory(*objects)
+            if adapter is not None:
+                yield name, adapter
+
+    def registerSubscriptionAdapter(self,
+                                    factory, required=None, provided=None,
+                                    name=_u(''), info=_u(''),
+                                    event=True):
+        if name:
+            raise TypeError("Named subscribers are not yet supported")
+        if provided is None:
+            provided = _getAdapterProvided(factory)
+        required = _getAdapterRequired(factory, required)
+        self._subscription_registrations.append(
+            (required, provided, name, factory, info)
+            )
+        self.adapters.subscribe(required, provided, factory)
+
+        if event:
+            notify(Registered(
+                SubscriptionRegistration(self, required, provided, name,
+                                         factory, info)
+                ))
+
+    def registeredSubscriptionAdapters(self):
+        for data in self._subscription_registrations:
+            yield SubscriptionRegistration(self, *data)
+
+    def unregisterSubscriptionAdapter(self, factory=None,
+                          required=None, provided=None, name=_u(''),
+                          ):
+        if name:
+            raise TypeError("Named subscribers are not yet supported")
+        if provided is None:
+            if factory is None:
+                raise TypeError("Must specify one of factory and provided")
+            provided = _getAdapterProvided(factory)
+
+        if (required is None) and (factory is None):
+            raise TypeError("Must specify one of factory and required")
+
+        required = _getAdapterRequired(factory, required)
+
+        if factory is None:
+            new = [(r, p, n, f, i)
+                   for (r, p, n, f, i)
+                   in self._subscription_registrations
+                   if not (r == required and p == provided)
+                   ]
+        else:
+            new = [(r, p, n, f, i)
+                   for (r, p, n, f, i)
+                   in self._subscription_registrations
+                   if not (r == required and p == provided and f == factory)
+                   ]
+
+        if len(new) == len(self._subscription_registrations):
+            return False
+
+
+        self._subscription_registrations[:] = new
+        self.adapters.unsubscribe(required, provided, factory)
+
+        notify(Unregistered(
+            SubscriptionRegistration(self, required, provided, name,
+                                     factory, '')
+            ))
+
+        return True
+
+    def subscribers(self, objects, provided):
+        return self.adapters.subscribers(objects, provided)
+
+    def registerHandler(self,
+                        factory, required=None,
+                        name=_u(''), info=_u(''),
+                        event=True):
+        if name:
+            raise TypeError("Named handlers are not yet supported")
+        required = _getAdapterRequired(factory, required)
+        self._handler_registrations.append(
+            (required, name, factory, info)
+            )
+        self.adapters.subscribe(required, None, factory)
+
+        if event:
+            notify(Registered(
+                HandlerRegistration(self, required, name, factory, info)
+                ))
+
+    def registeredHandlers(self):
+        for data in self._handler_registrations:
+            yield HandlerRegistration(self, *data)
+
+    def unregisterHandler(self, factory=None, required=None, name=_u('')):
+        if name:
+            raise TypeError("Named subscribers are not yet supported")
+
+        if (required is None) and (factory is None):
+            raise TypeError("Must specify one of factory and required")
+
+        required = _getAdapterRequired(factory, required)
+
+        if factory is None:
+            new = [(r, n, f, i)
+                   for (r, n, f, i)
+                   in self._handler_registrations
+                   if r != required
+                   ]
+        else:
+            new = [(r, n, f, i)
+                   for (r, n, f, i)
+                   in self._handler_registrations
+                   if not (r == required and f == factory)
+                   ]
+
+        if len(new) == len(self._handler_registrations):
+            return False
+
+        self._handler_registrations[:] = new
+        self.adapters.unsubscribe(required, None, factory)
+
+        notify(Unregistered(
+            HandlerRegistration(self, required, name, factory, '')
+            ))
+
+        return True
+
+    def handle(self, *objects):
+        self.adapters.subscribers(objects, None)
+
+
+def _getUtilityProvided(component):
+    provided = list(providedBy(component))
+    if len(provided) == 1:
+        return provided[0]
+    raise TypeError(
+        "The utility doesn't provide a single interface "
+        "and no provided interface was specified.")
+
+def _getAdapterProvided(factory):
+    provided = list(implementedBy(factory))
+    if len(provided) == 1:
+        return provided[0]
+    raise TypeError(
+        "The adapter factory doesn't implement a single interface "
+        "and no provided interface was specified.")
+
+def _getAdapterRequired(factory, required):
+    if required is None:
+        try:
+            required = factory.__component_adapts__
+        except AttributeError:
+            raise TypeError(
+                "The adapter factory doesn't have a __component_adapts__ "
+                "attribute and no required specifications were specified"
+                )
+    elif ISpecification.providedBy(required):
+        raise TypeError("the required argument should be a list of "
+                        "interfaces, not a single interface")
+
+    result = []
+    for r in required:
+        if r is None:
+            r = Interface
+        elif not ISpecification.providedBy(r):
+            if isinstance(r, class_types):
+                r = implementedBy(r)
+            else:
+                raise TypeError("Required specification must be a "
+                                "specification or class."
+                                )
+        result.append(r)
+    return tuple(result)
+
+
+class UtilityRegistration(object):
+
+    implements(IUtilityRegistration)
+
+    def __init__(self, registry, provided, name, component, doc, factory=None):
+        (self.registry, self.provided, self.name, self.component, self.info,
+         self.factory
+         ) = registry, provided, name, component, doc, factory
+
+    def __repr__(self):
+        return '%s(%r, %s, %r, %s, %r, %r)' % (
+                self.__class__.__name__,
+                self.registry,
+                getattr(self.provided, '__name__', None), self.name,
+                getattr(self.component, '__name__', repr(self.component)),
+                self.factory, self.info,
+                )
+
+    def __hash__(self):
+        return id(self)
+
+    def __eq__(self, other):
+        return repr(self) == repr(other)
+
+    def __ne__(self, other):
+        return repr(self) != repr(other)
+
+    def __lt__(self, other):
+        return repr(self) < repr(other)
+
+    def __le__(self, other):
+        return repr(self) <= repr(other)
+
+    def __gt__(self, other):
+        return repr(self) > repr(other)
+
+    def __ge__(self, other):
+        return repr(self) >= repr(other)
+
+class AdapterRegistration(object):
+
+    implements(IAdapterRegistration)
+
+    def __init__(self, registry, required, provided, name, component, doc):
+        (self.registry, self.required, self.provided, self.name,
+         self.factory, self.info
+         ) = registry, required, provided, name, component, doc
+
+    def __repr__(self):
+        return '%s(%r, %s, %s, %r, %s, %r)' % (
+            self.__class__.__name__,
+            self.registry,
+            '[' + ", ".join([r.__name__ for r in self.required]) + ']',
+            getattr(self.provided, '__name__', None), self.name,
+            getattr(self.factory, '__name__', repr(self.factory)), self.info,
+            )
+
+    def __hash__(self):
+        return id(self)
+
+    def __eq__(self, other):
+        return repr(self) == repr(other)
+
+    def __ne__(self, other):
+        return repr(self) != repr(other)
+
+    def __lt__(self, other):
+        return repr(self) < repr(other)
+
+    def __le__(self, other):
+        return repr(self) <= repr(other)
+
+    def __gt__(self, other):
+        return repr(self) > repr(other)
+
+    def __ge__(self, other):
+        return repr(self) >= repr(other)
+
+class SubscriptionRegistration(AdapterRegistration):
+
+    implementsOnly(ISubscriptionAdapterRegistration)
+
+class HandlerRegistration(AdapterRegistration):
+
+    implementsOnly(IHandlerRegistration)
+
+    def __init__(self, registry, required, name, handler, doc):
+        (self.registry, self.required, self.name, self.handler, self.info
+         ) = registry, required, name, handler, doc
+
+    @property
+    def factory(self):
+        return self.handler
+
+    provided = None
+
+    def __repr__(self):
+        return '%s(%r, %s, %r, %s, %r)' % (
+            self.__class__.__name__,
+            self.registry,
+            '[' + ", ".join([r.__name__ for r in self.required]) + ']',
+            self.name,
+            getattr(self.factory, '__name__', repr(self.factory)), self.info,
+            )
+
diff --git a/src/zope/interface/ro.py b/src/zope/interface/ro.py
new file mode 100644 (file)
index 0000000..47a7ea2
--- /dev/null
@@ -0,0 +1,69 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Compute a resolution order for an object and its bases
+"""
+__docformat__ = 'restructuredtext'
+
+
+def ro(object):
+    """Compute a "resolution order" for an object
+    """
+    return mergeOrderings([_flatten(object)])
+
+def mergeOrderings(orderings, seen=None):
+    """Merge multiple orderings so that within-ordering order is preserved
+
+    Orderings are constrained in such a way that if an object appears
+    in two or more orderings, then the suffix that begins with the
+    object must be in both orderings.
+
+    For example:
+
+    >>> _mergeOrderings([
+    ... ['x', 'y', 'z'],
+    ... ['q', 'z'],
+    ... [1, 3, 5],
+    ... ['z']
+    ... ])
+    ['x', 'y', 'q', 1, 3, 5, 'z']
+
+    """
+
+    if seen is None:
+        seen = {}
+    result = []
+    orderings.reverse()
+    for ordering in orderings:
+        ordering = list(ordering)
+        ordering.reverse()
+        for o in ordering:
+            if o not in seen:
+                seen[o] = 1
+                result.append(o)
+
+    result.reverse()
+    return result
+
+def _flatten(ob):
+    result = [ob]
+    i = 0
+    for ob in iter(result):
+        i += 1
+        # The recursive calls can be avoided by inserting the base classes
+        # into the dynamically growing list directly after the currently
+        # considered object;  the iterator makes sure this will keep working
+        # in the future, since it cannot rely on the length of the list
+        # by definition.
+        result[i:i] = ob.__bases__
+    return result
diff --git a/src/zope/interface/tests/__init__.py b/src/zope/interface/tests/__init__.py
new file mode 100644 (file)
index 0000000..1cf24e6
--- /dev/null
@@ -0,0 +1,13 @@
+import os
+import unittest
+
+def additional_tests():
+    suites = unittest.TestSuite()
+    for file in os.listdir(os.path.dirname(__file__)):
+        if file.endswith('.py') and file!='__init__.py':
+            name = os.path.splitext(file)[0]
+            module = __import__('.'.join((__name__, name)), globals(), 
+                                locals(), [name])
+            if hasattr(module, 'test_suite'):
+                suites.addTests(module.test_suite())
+    return suites
diff --git a/src/zope/interface/tests/dummy.py b/src/zope/interface/tests/dummy.py
new file mode 100644 (file)
index 0000000..f5564da
--- /dev/null
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Dummy Module
+"""
+from zope.interface import moduleProvides
+from zope.interface.tests.ifoo import IFoo
+
+moduleProvides(IFoo)
+
+def bar(baz):
+    pass
diff --git a/src/zope/interface/tests/foodforthought.txt b/src/zope/interface/tests/foodforthought.txt
new file mode 100644 (file)
index 0000000..45d961b
--- /dev/null
@@ -0,0 +1,61 @@
+================================
+Food-based subscription examples
+================================
+
+
+This file gives more subscription examples using a cooking-based example::
+
+    >>> from zope.interface.adapter import AdapterRegistry
+    >>> registry = AdapterRegistry()
+
+    >>> import zope.interface
+    >>> class IAnimal(zope.interface.Interface):
+    ...     pass
+    >>> class IPoultry(IAnimal):
+    ...     pass
+    >>> class IChicken(IPoultry):
+    ...     pass
+    >>> class ISeafood(IAnimal):
+    ...     pass
+
+Adapting to some other interface for which there is no
+subscription adapter returns an empty sequence::
+
+    >>> class IRecipe(zope.interface.Interface):
+    ...     pass
+    >>> class ISausages(IRecipe):
+    ...     pass
+    >>> class INoodles(IRecipe):
+    ...     pass
+    >>> class IKFC(IRecipe):
+    ...     pass
+
+    >>> list(registry.subscriptions([IPoultry], IRecipe))
+    []
+
+unless we define a subscription::
+
+    >>> registry.subscribe([IAnimal], ISausages, 'sausages')
+    >>> list(registry.subscriptions([IPoultry], ISausages))
+    ['sausages']
+
+And define another subscription adapter::
+
+    >>> registry.subscribe([IPoultry], INoodles, 'noodles')
+    >>> meals = list(registry.subscriptions([IPoultry], IRecipe))
+    >>> meals.sort()
+    >>> meals
+    ['noodles', 'sausages']
+
+    >>> registry.subscribe([IChicken], IKFC, 'kfc')
+    >>> meals = list(registry.subscriptions([IChicken], IRecipe))
+    >>> meals.sort()
+    >>> meals
+    ['kfc', 'noodles', 'sausages']
+
+And the answer for poultry hasn't changed::
+
+    >>> meals = list(registry.subscriptions([IPoultry], IRecipe))
+    >>> meals.sort()
+    >>> meals
+    ['noodles', 'sausages']
diff --git a/src/zope/interface/tests/ifoo.py b/src/zope/interface/tests/ifoo.py
new file mode 100644 (file)
index 0000000..29a7877
--- /dev/null
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""IFoo test module
+"""
+from zope.interface import Interface
+
+class IFoo(Interface):
+    """
+        Dummy interface for unit tests.
+    """
+
+    def bar(baz):
+        """
+            Just a note.
+        """
diff --git a/src/zope/interface/tests/ifoo_other.py b/src/zope/interface/tests/ifoo_other.py
new file mode 100644 (file)
index 0000000..29a7877
--- /dev/null
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""IFoo test module
+"""
+from zope.interface import Interface
+
+class IFoo(Interface):
+    """
+        Dummy interface for unit tests.
+    """
+
+    def bar(baz):
+        """
+            Just a note.
+        """
diff --git a/src/zope/interface/tests/m1.py b/src/zope/interface/tests/m1.py
new file mode 100644 (file)
index 0000000..d311fb4
--- /dev/null
@@ -0,0 +1,21 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Test module that declares an interface
+"""
+from zope.interface import Interface, moduleProvides
+
+class I1(Interface): pass
+class I2(Interface): pass
+
+moduleProvides(I1, I2)
diff --git a/src/zope/interface/tests/m2.py b/src/zope/interface/tests/m2.py
new file mode 100644 (file)
index 0000000..511cd9c
--- /dev/null
@@ -0,0 +1,15 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Test module that doesn't declare an interface
+"""
diff --git a/src/zope/interface/tests/odd.py b/src/zope/interface/tests/odd.py
new file mode 100644 (file)
index 0000000..04ffa31
--- /dev/null
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Odd meta class that doesn't subclass type.
+
+This is used for testing support for ExtensionClass in new interfaces.
+
+  >>> class A(object):
+  ...     __metaclass__ = MetaClass
+  ...     a = 1
+  ...
+  >>> A.__name__
+  'A'
+  >>> A.__bases__ == (object,)
+  True
+  >>> class B(object):
+  ...     __metaclass__ = MetaClass
+  ...     b = 1
+  ...
+  >>> class C(A, B): pass
+  ...
+  >>> C.__name__
+  'C'
+  >>> int(C.__bases__ == (A, B))
+  1
+  >>> a = A()
+  >>> aa = A()
+  >>> a.a
+  1
+  >>> aa.a
+  1
+  >>> aa.a = 2
+  >>> a.a
+  1
+  >>> aa.a
+  2
+  >>> c = C()
+  >>> c.a
+  1
+  >>> c.b
+  1
+  >>> c.b = 2
+  >>> c.b
+  2
+  >>> C.c = 1
+  >>> c.c
+  1
+  >>> import sys
+  >>> if sys.version[0] == '2': # This test only makes sense under Python 2.x
+  ...     from types import ClassType
+  ...     assert not isinstance(C, (type, ClassType))
+  
+  >>> int(C.__class__.__class__ is C.__class__)
+  1
+"""
+
+# class OddClass is an odd meta class
+
+class MetaMetaClass(type):
+
+    def __getattribute__(self, name):
+        if name == '__class__':
+            return self
+        return type.__getattribute__(self, name)
+    
+
+class MetaClass(object):
+    """Odd classes
+    """
+    __metaclass__ = MetaMetaClass
+
+    def __init__(self, name, bases, dict):
+        self.__name__ = name
+        self.__bases__ = bases
+        self.__dict__.update(dict)
+
+    def __call__(self):
+        return OddInstance(self)
+
+    def __getattr__(self, name):
+        for b in self.__bases__:
+            v = getattr(b, name, self)
+            if v is not self:
+                return v
+        raise AttributeError(name)
+
+    def __repr__(self):
+        return "<odd class %s at %s>" % (self.__name__, hex(id(self)))
+
+class OddInstance(object):
+
+    def __init__(self, cls):
+        self.__dict__['__class__'] = cls
+
+    def __getattribute__(self, name):
+        dict = object.__getattribute__(self, '__dict__')
+        if name == '__dict__':
+            return dict
+        v = dict.get(name, self)
+        if v is not self:
+            return v
+        return getattr(dict['__class__'], name)
+
+    def __setattr__(self, name, v):
+        self.__dict__[name] = v
+
+    def __delattr__(self, name):
+        del self.__dict__[name]
+
+    def __repr__(self):
+        return "<odd %s instance at %s>" % (
+            self.__class__.__name__, hex(id(self)))
+        
+
+
+# DocTest:
+if __name__ == "__main__":
+    import doctest, __main__
+    doctest.testmod(__main__, isprivate=lambda *a: False)
diff --git a/src/zope/interface/tests/test_adapter.py b/src/zope/interface/tests/test_adapter.py
new file mode 100644 (file)
index 0000000..30a8598
--- /dev/null
@@ -0,0 +1,412 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Adapter registry tests
+"""
+import doctest
+import unittest
+import zope.interface
+from zope.interface.adapter import AdapterRegistry
+
+
+class IF0(zope.interface.Interface):
+    pass
+class IF1(IF0):
+    pass
+
+class IB0(zope.interface.Interface):
+    pass
+class IB1(IB0):
+    pass
+
+class IR0(zope.interface.Interface):
+    pass
+class IR1(IR0):
+    pass
+
+def test_multi_adapter_get_best_match():
+    """
+    >>> registry = AdapterRegistry()
+
+    >>> class IB2(IB0):
+    ...     pass
+    >>> class IB3(IB2, IB1):
+    ...     pass
+    >>> class IB4(IB1, IB2):
+    ...     pass
+
+    >>> registry.register([None, IB1], IR0, '', 'A1')
+    >>> registry.register([None, IB0], IR0, '', 'A0')
+    >>> registry.register([None, IB2], IR0, '', 'A2')
+
+    >>> registry.lookup((IF1, IB1), IR0, '')
+    'A1'
+    >>> registry.lookup((IF1, IB2), IR0, '')
+    'A2'
+    >>> registry.lookup((IF1, IB0), IR0, '')
+    'A0'
+    >>> registry.lookup((IF1, IB3), IR0, '')
+    'A2'
+    >>> registry.lookup((IF1, IB4), IR0, '')
+    'A1'
+    """
+
+def test_multi_adapter_lookupAll_get_best_matches():
+    """
+    >>> registry = AdapterRegistry()
+
+    >>> class IB2(IB0):
+    ...     pass
+    >>> class IB3(IB2, IB1):
+    ...     pass
+    >>> class IB4(IB1, IB2):
+    ...     pass
+
+    >>> registry.register([None, IB1], IR0, '', 'A1')
+    >>> registry.register([None, IB0], IR0, '', 'A0')
+    >>> registry.register([None, IB2], IR0, '', 'A2')
+
+    >>> tuple(registry.lookupAll((IF1, IB1), IR0))[0][1]
+    'A1'
+    >>> tuple(registry.lookupAll((IF1, IB2), IR0))[0][1]
+    'A2'
+    >>> tuple(registry.lookupAll((IF1, IB0), IR0))[0][1]
+    'A0'
+    >>> tuple(registry.lookupAll((IF1, IB3), IR0))[0][1]
+    'A2'
+    >>> tuple(registry.lookupAll((IF1, IB4), IR0))[0][1]
+    'A1'
+    """
+
+
+def test_multi_adapter_w_default():
+    """
+    >>> registry = AdapterRegistry()
+    
+    >>> registry.register([None, None], IB1, 'bob', 'A0')
+
+    >>> registry.lookup((IF1, IR1), IB0, 'bob')
+    'A0'
+    
+    >>> registry.register([None, IR0], IB1, 'bob', 'A1')
+
+    >>> registry.lookup((IF1, IR1), IB0, 'bob')
+    'A1'
+    
+    >>> registry.lookup((IF1, IR1), IB0, 'bruce')
+
+    >>> registry.register([None, IR1], IB1, 'bob', 'A2')
+    >>> registry.lookup((IF1, IR1), IB0, 'bob')
+    'A2'
+    """
+
+def test_multi_adapter_w_inherited_and_multiple_registrations():
+    """
+    >>> registry = AdapterRegistry()
+
+    >>> class IX(zope.interface.Interface):
+    ...    pass
+
+    >>> registry.register([IF0, IR0], IB1, 'bob', 'A1')
+    >>> registry.register([IF1, IX], IB1, 'bob', 'AX')
+
+    >>> registry.lookup((IF1, IR1), IB0, 'bob')
+    'A1'
+    """
+
+def test_named_adapter_with_default():
+    """Query a named simple adapter
+
+    >>> registry = AdapterRegistry()
+
+    If we ask for a named adapter, we won't get a result unless there
+    is a named adapter, even if the object implements the interface:
+
+    >>> registry.lookup([IF1], IF0, 'bob')
+
+    >>> registry.register([None], IB1, 'bob', 'A1')
+    >>> registry.lookup([IF1], IB0, 'bob')
+    'A1'
+
+    >>> registry.lookup([IF1], IB0, 'bruce')
+
+    >>> registry.register([None], IB0, 'bob', 'A2')
+    >>> registry.lookup([IF1], IB0, 'bob')
+    'A2'
+    """
+
+def test_multi_adapter_gets_closest_provided():
+    """
+    >>> registry = AdapterRegistry()
+    >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+    >>> registry.register((IF1, IR0), IB1, 'bob', 'A2')
+    >>> registry.lookup((IF1, IR1), IB0, 'bob')
+    'A1'
+
+    >>> registry = AdapterRegistry()
+    >>> registry.register([IF1, IR0], IB1, 'bob', 'A2')
+    >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+    >>> registry.lookup([IF1, IR0], IB0, 'bob')
+    'A1'
+
+    >>> registry = AdapterRegistry()
+    >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+    >>> registry.register([IF1, IR1], IB1, 'bob', 'A2')
+    >>> registry.lookup([IF1, IR1], IB0, 'bob')
+    'A2'
+
+    >>> registry = AdapterRegistry()
+    >>> registry.register([IF1, IR1], IB1, 'bob', 2)
+    >>> registry.register([IF1, IR0], IB0, 'bob', 1)
+    >>> registry.lookup([IF1, IR1], IB0, 'bob')
+    2
+    """
+
+def test_multi_adapter_check_non_default_dont_hide_default():
+    """
+    >>> registry = AdapterRegistry()
+
+    >>> class IX(zope.interface.Interface):
+    ...     pass
+
+
+    >>> registry.register([None, IR0], IB0, 'bob', 1)
+    >>> registry.register([IF1,   IX], IB0, 'bob', 2)
+    >>> registry.lookup([IF1, IR1], IB0, 'bob')
+    1
+    """
+
+def test_adapter_hook_with_factory_producing_None():
+    """
+    >>> registry = AdapterRegistry()
+    >>> default = object()
+    
+    >>> class Object1(object):
+    ...     zope.interface.implements(IF0)
+    >>> class Object2(object):
+    ...     zope.interface.implements(IF0)
+
+    >>> def factory(context):
+    ...     if isinstance(context, Object1):
+    ...         return 'adapter'
+    ...     return None
+
+    >>> registry.register([IF0], IB0, '', factory)
+
+    >>> registry.adapter_hook(IB0, Object1())
+    'adapter'
+    >>> registry.adapter_hook(IB0, Object2()) is None
+    True
+    >>> registry.adapter_hook(IB0, Object2(), default=default) is default
+    True
+    """
+
+def test_adapter_registry_update_upon_interface_bases_change():
+    """
+    Let's first create a adapter registry and a simple adaptation hook:
+
+    >>> globalRegistry = AdapterRegistry()
+
+    >>> def _hook(iface, ob, lookup=globalRegistry.lookup1):
+    ...     factory = lookup(zope.interface.providedBy(ob), iface)
+    ...     if factory is None:
+    ...         return None
+    ...     else:
+    ...         return factory(ob)
+
+    >>> zope.interface.interface.adapter_hooks.append(_hook)
+
+    Now we create some interfaces and an implementation:
+
+    >>> class IX(zope.interface.Interface):
+    ...   pass
+
+    >>> class IY(zope.interface.Interface):
+    ...   pass
+
+    >>> class X(object):
+    ...  pass
+
+    >>> class Y(object):
+    ...  zope.interface.implements(IY)
+    ...  def __init__(self, original):
+    ...   self.original=original
+
+    and register an adapter:
+
+    >>> globalRegistry.register((IX,), IY, '', Y)
+
+    at first, we still expect the adapter lookup from `X` to `IY` to fail:
+
+    >>> IY(X()) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+    Traceback (most recent call last):
+    ...
+    TypeError: ('Could not adapt',
+                <zope.interface.tests.test_adapter.X object at ...>,
+                <InterfaceClass zope.interface.tests.test_adapter.IY>)
+
+    But after we declare an interface on the class `X`, it should pass:
+
+    >>> zope.interface.classImplementsOnly(X, IX)
+
+    >>> IY(X()) #doctest: +ELLIPSIS
+    <zope.interface.tests.test_adapter.Y object at ...>
+
+    >>> hook = zope.interface.interface.adapter_hooks.pop()
+    """
+
+
+def test_changing_declarations():
+    """
+
+    If we change declarations for a class, those adapter lookup should
+    eflect the changes:
+
+    >>> class I1(zope.interface.Interface):
+    ...     pass
+    >>> class I2(zope.interface.Interface):
+    ...     pass
+
+    >>> registry = AdapterRegistry()
+    >>> registry.register([I1], I2, '', 42)
+
+    >>> class C:
+    ...     pass
+
+    >>> registry.lookup([zope.interface.implementedBy(C)], I2, '')
+
+    >>> zope.interface.classImplements(C, I1)
+
+    >>> registry.lookup([zope.interface.implementedBy(C)], I2, '')
+    42
+    """
+
+def test_correct_multi_adapter_lookup():
+    """
+    >>> registry = AdapterRegistry()
+    >>> registry.register([IF0, IB1], IR0, '', 'A01')
+    >>> registry.register([IF1, IB0], IR0, '', 'A10')
+    >>> registry.lookup((IF1, IB1), IR0, '')
+    'A10'
+    """
+
+def test_duplicate_bases():
+    """
+There was a bug that caused problems if a spec had multiple bases:
+
+    >>> class I(zope.interface.Interface):
+    ...     pass
+    >>> class I2(I, I):
+    ...     pass
+    >>> registry = AdapterRegistry()
+    >>> registry.register([I2], IR0, 'x', 'X')
+    >>> registry.lookup((I2, ), IR0, 'x')
+    'X'
+    >>> registry.register([I2], IR0, 'y', 'Y')
+    >>> registry.lookup((I2, ), IR0, 'x')
+    'X'
+    >>> registry.lookup((I2, ), IR0, 'y')
+    'Y'
+"""
+
+def test_register_objects_with_cmp():
+    """
+    The registry should never use == as that will tend to fail when
+    objects are picky about what they are compared with:
+
+    >>> class Picky:
+    ...     def __cmp__(self, other):
+    ...         raise TypeError("I\'m too picky for comparison!")
+    >>> class I(zope.interface.Interface):
+    ...     pass
+    >>> class I2(I, I):
+    ...     pass
+
+    >>> registry = AdapterRegistry()
+    >>> picky = Picky()
+    >>> registry.register([I2], IR0, '', picky)
+    >>> registry.unregister([I2], IR0, '', picky)
+
+    >>> registry.subscribe([I2], IR0, picky)
+    >>> registry.unsubscribe([I2], IR0, picky)
+
+    """
+
+def test_unregister_cleans_up_empties():
+    """
+    >>> class I(zope.interface.Interface):
+    ...     pass
+    >>> class IP(zope.interface.Interface):
+    ...     pass
+    >>> class C(object):
+    ...     pass
+
+    >>> registry = AdapterRegistry()
+
+    >>> registry.register([], IP, '', C)
+    >>> registry.register([I], IP, '', C)
+    >>> registry.register([I], IP, 'name', C)
+    >>> registry.register([I, I], IP, '', C)
+    >>> len(registry._adapters)
+    3
+    >>> map(len, registry._adapters)
+    [1, 1, 1]
+
+    >>> registry.unregister([], IP, '', C)
+    >>> registry.unregister([I], IP, '', C)
+    >>> registry.unregister([I], IP, 'name', C)
+    >>> registry.unregister([I, I], IP, '', C)
+    >>> registry._adapters
+    []
+
+    """
+
+def test_unsubscribe_cleans_up_empties():
+    """
+    >>> class I1(zope.interface.Interface):
+    ...     pass
+    >>> class I2(zope.interface.Interface):
+    ...     pass
+    >>> class IP(zope.interface.Interface):
+    ...     pass
+
+    >>> registry = AdapterRegistry()
+    >>> def handler(event):
+    ...     pass
+
+    >>> registry.subscribe([I1], I1, handler)
+    >>> registry.subscribe([I2], I1, handler)
+    >>> len(registry._subscribers)
+    2
+    >>> map(len, registry._subscribers)
+    [0, 2]
+
+    >>> registry.unsubscribe([I1], I1, handler)
+    >>> registry.unsubscribe([I2], I1, handler)
+    >>> registry._subscribers
+    []
+
+    """
+
+
+def test_suite():
+    return unittest.TestSuite((
+        doctest.DocFileSuite('../adapter.txt', '../adapter.ru.txt',
+                                 '../human.txt', '../human.ru.txt',
+                                 'foodforthought.txt',
+                                 globs={'__name__': '__main__'}),
+        doctest.DocTestSuite(),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
diff --git a/src/zope/interface/tests/test_advice.py b/src/zope/interface/tests/test_advice.py
new file mode 100644 (file)
index 0000000..f21252e
--- /dev/null
@@ -0,0 +1,185 @@
+
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Tests for advice
+
+This module was adapted from 'protocols.tests.advice', part of the Python
+Enterprise Application Kit (PEAK).  Please notify the PEAK authors
+(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or
+Zope-specific changes are required, so that the PEAK version of this module
+can be kept in sync.
+
+PEAK is a Python application framework that interoperates with (but does
+not require) Zope 3 and Twisted.  It provides tools for manipulating UML
+models, object-relational persistence, aspect-oriented programming, and more.
+Visit the PEAK home page at http://peak.telecommunity.com for more information.
+"""
+
+import unittest
+from unittest import TestCase, makeSuite, TestSuite
+from zope.interface.advice import addClassAdvisor, determineMetaclass
+from zope.interface.advice import getFrameInfo
+import sys
+
+def ping(log, value):
+
+    def pong(klass):
+        log.append((value,klass))
+        return [klass]
+
+    addClassAdvisor(pong)
+
+try:
+    from types import ClassType
+    
+    class ClassicClass:
+        __metaclass__ = ClassType
+        classLevelFrameInfo = getFrameInfo(sys._getframe())
+except ImportError:
+    pass
+
+class NewStyleClass:
+    __metaclass__ = type
+    classLevelFrameInfo = getFrameInfo(sys._getframe())
+
+moduleLevelFrameInfo = getFrameInfo(sys._getframe())
+
+class FrameInfoTest(TestCase):
+
+    classLevelFrameInfo = getFrameInfo(sys._getframe())
+
+    def checkModuleInfo(self):
+        kind, module, f_locals, f_globals = moduleLevelFrameInfo
+        self.assertEquals(kind, "module")
+        for d in module.__dict__, f_locals, f_globals:
+            self.assert_(d is globals())
+
+    def checkClassicClassInfo(self):
+        kind, module, f_locals, f_globals = ClassicClass.classLevelFrameInfo
+        self.assertEquals(kind, "class")
+
+        self.assert_(f_locals is ClassicClass.__dict__)  # ???
+        for d in module.__dict__, f_globals:
+            self.assert_(d is globals())
+
+    def checkNewStyleClassInfo(self):
+        kind, module, f_locals, f_globals = NewStyleClass.classLevelFrameInfo
+        self.assertEquals(kind, "class")
+
+        for d in module.__dict__, f_globals:
+            self.assert_(d is globals())
+
+    def checkCallInfo(self):
+        kind, module, f_locals, f_globals = getFrameInfo(sys._getframe())
+        self.assertEquals(kind, "function call")
+        self.assert_(f_locals is locals()) # ???
+        for d in module.__dict__, f_globals:
+            self.assert_(d is globals())
+
+
+class AdviceTests(TestCase):
+
+    def checkOrder(self):
+        log = []
+        class Foo(object):
+            ping(log, 1)
+            ping(log, 2)
+            ping(log, 3)
+
+        # Strip the list nesting
+        for i in 1,2,3:
+            self.assert_(isinstance(Foo, list))
+            Foo, = Foo
+
+        self.assertEquals(log, [(1, Foo), (2, [Foo]), (3, [[Foo]])])
+
+    def TODOcheckOutside(self):
+        # Disabled because the check does not work with doctest tests.
+        try:
+            ping([], 1)
+        except SyntaxError:
+            pass
+        else:
+            raise AssertionError(
+                "Should have detected advice outside class body"
+            )
+
+    def checkDoubleType(self):
+        if sys.hexversion >= 0x02030000:
+            return  # you can't duplicate bases in 2.3
+        class aType(type,type):
+            ping([],1)
+        aType, = aType
+        self.assert_(aType.__class__ is type)
+
+    def checkSingleExplicitMeta(self):
+
+        class M(type):
+            pass
+
+        class C(M):
+            __metaclass__ = M
+            ping([],1)
+
+        C, = C
+        self.assert_(C.__class__ is M)
+
+
+    def checkMixedMetas(self):
+
+        class M1(type): pass
+        class M2(type): pass
+
+        class B1: __metaclass__ = M1
+        class B2: __metaclass__ = M2
+
+        try:
+            class C(B1,B2):
+                ping([],1)
+        except TypeError:
+            pass
+        else:
+            raise AssertionError("Should have gotten incompatibility error")
+
+        class M3(M1,M2): pass
+
+        class C(B1,B2):
+            __metaclass__ = M3
+            ping([],1)
+
+        self.assert_(isinstance(C,list))
+        C, = C
+        self.assert_(isinstance(C,M3))
+
+    def checkMetaOfClass(self):
+
+        class metameta(type):
+            pass
+
+        class meta(type):
+            __metaclass__ = metameta
+
+        self.assertEquals(determineMetaclass((meta, type)), metameta)
+
+TestClasses = (AdviceTests, FrameInfoTest)
+
+def test_suite():
+    if sys.version[0] == '2':
+        return TestSuite([makeSuite(t,'check') for t in TestClasses])
+    else:
+        # Advise metaclasses doesn't work in Python 3
+        return TestSuite([])
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
diff --git a/src/zope/interface/tests/test_declarations.py b/src/zope/interface/tests/test_declarations.py
new file mode 100644 (file)
index 0000000..e6f2e14
--- /dev/null
@@ -0,0 +1,434 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Test the new API for making and checking interface declarations
+"""
+import doctest
+import unittest
+
+from zope.interface import Interface, implements
+from zope.interface import directlyProvides, providedBy
+from zope.interface import classImplements, implementedBy, implementsOnly
+
+class I1(Interface): pass
+class I2(Interface): pass
+class I3(Interface): pass
+class I4(Interface): pass
+class I5(Interface): pass
+
+class A(object):
+    implements(I1)
+class B(object):
+    implements(I2)
+class C(A, B):
+    implements(I3)
+
+class COnly(A, B):
+    implementsOnly(I3)
+
+class COnly_old(A, B):
+    __implemented__ = I3
+
+class D(COnly):
+    implements(I5)
+
+def test_ObjectSpecification_Simple():
+    """
+    >>> c = C()
+    >>> directlyProvides(c, I4)
+    >>> [i.__name__ for i in providedBy(c)]
+    ['I4', 'I3', 'I1', 'I2']
+    """
+
+def test_ObjectSpecification_Simple_w_only():
+    """
+    >>> c = COnly()
+    >>> directlyProvides(c, I4)
+    >>> [i.__name__ for i in providedBy(c)]
+    ['I4', 'I3']
+    """
+
+def test_ObjectSpecification_Simple_old_style():
+    """
+    >>> c = COnly_old()
+    >>> directlyProvides(c, I4)
+    >>> [i.__name__ for i in providedBy(c)]
+    ['I4', 'I3']
+    """
+
+
+class Test(unittest.TestCase):
+
+    # Note that most of the tests are in the doc strings of the
+    # declarations module.
+
+    def failUnless(self, expr): # silence deprecation warnings under py3
+        return self.assertTrue(expr)
+
+    def failIf(self, expr): # silence deprecation warnings under py3
+        return self.assertFalse(expr)
+
+    def test_backward_compat(self):
+
+        class C1(object): __implemented__ = I1
+        class C2(C1): __implemented__ = I2, I5
+        class C3(C2): __implemented__ = I3, C2.__implemented__
+
+        self.failUnless(C3.__implemented__.__class__ is tuple)
+
+        self.assertEqual(
+            [i.getName() for i in providedBy(C3())],
+            ['I3', 'I2', 'I5'],
+            )
+
+        class C4(C3):
+            implements(I4)
+
+        self.assertEqual(
+            [i.getName() for i in providedBy(C4())],
+            ['I4', 'I3', 'I2', 'I5'],
+            )
+
+        self.assertEqual(
+            [i.getName() for i in C4.__implemented__],
+            ['I4', 'I3', 'I2', 'I5'],
+            )
+
+        # Note that C3.__implemented__ should now be a sequence of interfaces
+        self.assertEqual(
+            [i.getName() for i in C3.__implemented__],
+            ['I3', 'I2', 'I5'],
+            )
+        self.failIf(C3.__implemented__.__class__ is tuple)
+
+    def test_module(self):
+        from zope.interface.tests import m1, m2
+        #import zope.interface.tests.m2
+        directlyProvides(m2,
+                         m1.I1,
+                         m1.I2,
+                         )
+        self.assertEqual(list(providedBy(m1)),
+                         list(providedBy(m2)),
+                         )
+
+    def test_builtins(self):
+        # Setup
+
+        intspec = implementedBy(int)
+        olddeclared = intspec.declared
+
+        classImplements(int, I1)
+        class myint(int):
+            implements(I2)
+
+        x = 42
+        self.assertEqual([i.getName() for i in providedBy(x)],
+                         ['I1'])
+
+        x = myint(42)
+        directlyProvides(x, I3)
+        self.assertEqual([i.getName() for i in providedBy(x)],
+                         ['I3', 'I2', 'I1'])
+
+        # cleanup
+        intspec.declared = olddeclared
+        classImplements(int)
+
+        x = 42
+        self.assertEqual([i.getName() for i in providedBy(x)],
+                         [])
+
+
+def test_signature_w_no_class_interfaces():
+    """
+    >>> from zope.interface import *
+    >>> class C(object):
+    ...     pass
+    >>> c = C()
+    >>> list(providedBy(c))
+    []
+
+    >>> class I(Interface):
+    ...    pass
+    >>> directlyProvides(c, I)
+    >>> list(providedBy(c))  == list(directlyProvidedBy(c))
+    1
+    """
+
+def test_classImplement_on_deeply_nested_classes():
+    """This test is in response to a bug found, which is why it's a bit
+    contrived
+
+    >>> from zope.interface import *
+    >>> class B1(object):
+    ...     pass
+    >>> class B2(B1):
+    ...     pass
+    >>> class B3(B2):
+    ...     pass
+    >>> class D(object):
+    ...     implements()
+    >>> class S(B3, D):
+    ...     implements()
+
+    This failed due to a bug in the code for finding __providedBy__
+    descriptors for old-style classes.
+
+    """
+
+def test_pickle_provides_specs():
+    """
+    >>> from pickle import dumps, loads
+    >>> a = A()
+    >>> I2.providedBy(a)
+    0
+    >>> directlyProvides(a, I2)
+    >>> I2.providedBy(a)
+    1
+    >>> a2 = loads(dumps(a))
+    >>> I2.providedBy(a2)
+    1
+
+    """
+
+def test_that_we_dont_inherit_class_provides():
+    """
+    >>> from zope.interface import classProvides
+    >>> class X(object):
+    ...     classProvides(I1)
+    >>> class Y(X):
+    ...     pass
+    >>> [i.__name__ for i in X.__provides__]
+    ['I1']
+    >>> Y.__provides__
+    Traceback (most recent call last):
+    ...
+    AttributeError: __provides__
+
+    """
+
+def test_that_we_dont_inherit_provides_optimizations():
+    """
+
+    When we make a declaration for a class, we install a __provides__
+    descriptors that provides a default for instances that don't have
+    instance-specific declarations:
+
+    >>> class A(object):
+    ...     implements(I1)
+
+    >>> class B(object):
+    ...     implements(I2)
+
+    >>> [i.__name__ for i in A().__provides__]
+    ['I1']
+    >>> [i.__name__ for i in B().__provides__]
+    ['I2']
+
+    But it's important that we don't use this for subclasses without
+    declarations.  This would cause incorrect results:
+
+    >>> class X(A, B):
+    ...     pass
+
+    >>> X().__provides__
+    Traceback (most recent call last):
+    ...
+    AttributeError: __provides__
+
+    However, if we "induce" a declaration, by calling implementedBy
+    (even indirectly through providedBy):
+
+    >>> [i.__name__ for i in providedBy(X())]
+    ['I1', 'I2']
+
+
+    then the optimization will work:
+
+    >>> [i.__name__ for i in X().__provides__]
+    ['I1', 'I2']
+
+    """
+
+def test_classProvides_before_implements():
+    """Special descriptor for class __provides__
+
+    The descriptor caches the implementedBy info, so that
+    we can get declarations for objects without instance-specific
+    interfaces a bit quicker.
+
+        For example::
+
+          >>> from zope.interface import Interface, classProvides
+          >>> class IFooFactory(Interface):
+          ...     pass
+          >>> class IFoo(Interface):
+          ...     pass
+          >>> class C(object):
+          ...     classProvides(IFooFactory)
+          ...     implements(IFoo)
+          >>> [i.getName() for i in C.__provides__]
+          ['IFooFactory']
+
+          >>> [i.getName() for i in C().__provides__]
+          ['IFoo']
+    """
+
+def test_getting_spec_for_proxied_builtin_class():
+    """
+
+    In general, we should be able to get a spec
+    for a proxied class if someone has declared or
+    asked for a spec before.
+
+    We don't want to depend on proxies in this (zope.interface)
+    package, but we do want to work with proxies.  Proxies have the
+    effect that a class's __dict__ cannot be gotten. Further, for
+    built-in classes, we can't save, and thus, cannot get, any class
+    attributes.  We'll emulate this by treating a plain object as a class:
+
+      >>> cls = object()
+
+    We'll create an implements specification:
+
+      >>> import zope.interface.declarations
+      >>> impl = zope.interface.declarations.Implements(I1, I2)
+
+    Now, we'll emulate a declaration for a built-in type by putting
+    it in BuiltinImplementationSpecifications:
+
+      >>> zope.interface.declarations.BuiltinImplementationSpecifications[
+      ...   cls] = impl
+
+    Now, we should be able to get it back:
+
+      >>> implementedBy(cls) is impl
+      True
+
+    Of course, we don't want to leave it there. :)
+
+      >>> del zope.interface.declarations.BuiltinImplementationSpecifications[
+      ...   cls]
+
+    """
+
+def test_declaration_get():
+    """
+    We can get definitions from a declaration:
+
+        >>> import zope.interface
+        >>> class I1(zope.interface.Interface):
+        ...    a11 = zope.interface.Attribute('a11')
+        ...    a12 = zope.interface.Attribute('a12')
+        >>> class I2(zope.interface.Interface):
+        ...    a21 = zope.interface.Attribute('a21')
+        ...    a22 = zope.interface.Attribute('a22')
+        ...    a12 = zope.interface.Attribute('a212')
+        >>> class I11(I1):
+        ...    a11 = zope.interface.Attribute('a111')
+
+        >>> decl = zope.interface.Declaration(I11, I2)
+        >>> decl.get('a11') is I11.get('a11')
+        True
+        >>> decl.get('a12') is I1.get('a12')
+        True
+        >>> decl.get('a21') is I2.get('a21')
+        True
+        >>> decl.get('a22') is I2.get('a22')
+        True
+        >>> decl.get('a')
+        >>> decl.get('a', 42)
+        42
+
+    We get None even with no interfaces:
+
+        >>> decl = zope.interface.Declaration()
+        >>> decl.get('a11')
+        >>> decl.get('a11', 42)
+        42
+
+    We get new data if e change interface bases:
+
+        >>> decl.__bases__ = I11, I2
+        >>> decl.get('a11') is I11.get('a11')
+        True
+    """
+
+def test_classImplements_after_classImplementsOnly_issue_402():
+    """http://www.zope.org/Collectors/Zope3-dev/402
+
+>>> from zope.interface import *
+>>> class I1(Interface):
+...     pass
+>>> class I2(Interface):
+...     pass
+>>> class C:
+...     implements(I1)
+>>> class C2:
+...     implementsOnly(I2)
+>>> class I3(Interface):
+...     pass
+
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'Interface']
+
+>>> classImplements(C2, I3)
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'I3', 'Interface']
+
+>>> class I4(Interface):
+...     pass
+>>> classImplements(C2, I4)
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'I3', 'I4', 'Interface']
+
+
+"""
+
+def test_picklability_of_implements_specifications():
+    """
+
+    Sometimes, we need to pickle implements specs.  We should be able
+    to do so as long as the class is picklable.
+
+    >>> import pickle
+    >>> pickle.loads(pickle.dumps(implementedBy(C))) is implementedBy(C)
+    True
+
+
+    """
+
+def test_provided_by_with_slots():
+    """
+
+    This is an edge case: if the __slots__ of a class contain '__provides__',
+    using providedBy() on that class should still work (this occurs, for
+    example, when providing an adapter for a concrete class.)
+
+    >>> import zope.interface
+    >>> class Slotted(object):
+    ...     __slots__ = ('__provides__')
+    >>> class IFoo(zope.interface.Interface):
+    ...     pass
+    >>> IFoo.providedBy(Slotted)
+    False
+
+    """
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(Test),
+        doctest.DocTestSuite("zope.interface.declarations"),
+        doctest.DocTestSuite(),
+    ))
diff --git a/src/zope/interface/tests/test_document.py b/src/zope/interface/tests/test_document.py
new file mode 100644 (file)
index 0000000..a2653b3
--- /dev/null
@@ -0,0 +1,69 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Documentation tests.
+"""
+from unittest import TestCase, main, makeSuite
+
+from zope.interface import Interface, Attribute
+
+class Test(TestCase):
+
+    def testBlech(self):
+        from zope.interface.document import asStructuredText
+
+        self.assertEqual(asStructuredText(I2), '''\
+I2
+
+ I2 doc
+
+ This interface extends:
+
+  o _I1
+
+ Attributes:
+
+  a1 -- no documentation
+
+  a2 -- a2 doc
+
+ Methods:
+
+  f21() -- f21 doc
+
+  f22() -- no documentation
+
+  f23() -- f23 doc
+
+''')
+
+
+def test_suite():
+    return makeSuite(Test)
+
+class _I1(Interface):
+    def f11(): pass
+    def f12(): pass
+
+class I2(_I1):
+    "I2 doc"
+
+    a1 = Attribute('a1')
+    a2 = Attribute('a2', 'a2 doc')
+
+    def f21(): "f21 doc"
+    def f22(): pass
+    def f23(): "f23 doc"
+
+if __name__=='__main__':
+    main(defaultTest='test_suite')
diff --git a/src/zope/interface/tests/test_element.py b/src/zope/interface/tests/test_element.py
new file mode 100644 (file)
index 0000000..66724a6
--- /dev/null
@@ -0,0 +1,41 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Test Element meta-class.
+"""
+
+import unittest
+from zope.interface.interface import Element
+
+class TestElement(unittest.TestCase):
+
+    def test_taggedValues(self):
+        """Test that we can update tagged values of more than one element
+        """
+        
+        e1 = Element("foo")
+        e2 = Element("bar")
+        e1.setTaggedValue("x", 1)
+        e2.setTaggedValue("x", 2)
+        self.assertEqual(e1.getTaggedValue("x"), 1)
+        self.assertEqual(e2.getTaggedValue("x"), 2)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestElement))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
diff --git a/src/zope/interface/tests/test_interface.py b/src/zope/interface/tests/test_interface.py
new file mode 100644 (file)
index 0000000..78398a1
--- /dev/null
@@ -0,0 +1,507 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Test Interface implementation
+"""
+from __future__ import with_statement
+
+import doctest
+import unittest
+import sys
+
+class InterfaceTests(unittest.TestCase):
+
+    def failUnless(self, expr): # silence deprecation warnings under py3
+        return self.assertTrue(expr)
+
+    def failIf(self, expr): # silence deprecation warnings under py3
+        return self.assertFalse(expr)
+
+    def _makeDerivedInterface(self):
+        from zope.interface import Interface
+        from zope.interface import Attribute
+        class _I1(Interface):
+
+            a1 = Attribute("This is an attribute")
+
+            def f11():
+                pass
+            def f12():
+                pass
+            f12.optional = 1
+
+        class _I1_(_I1):
+            pass
+
+        class _I1__(_I1_):
+            pass
+
+        class _I2(_I1__):
+            def f21():
+                pass
+            def f22():
+                pass
+            f23 = f22
+
+        return _I2
+
+    def testInterfaceSetOnAttributes(self):
+        from zope.interface.tests.unitfixtures import FooInterface
+        self.assertEqual(FooInterface['foobar'].interface,
+                         FooInterface)
+        self.assertEqual(FooInterface['aMethod'].interface,
+                         FooInterface)
+
+    def testClassImplements(self):
+        from zope.interface.tests.unitfixtures import A
+        from zope.interface.tests.unitfixtures import B
+        from zope.interface.tests.unitfixtures import C
+        from zope.interface.tests.unitfixtures import D
+        from zope.interface.tests.unitfixtures import E
+        from zope.interface.tests.unitfixtures import I1
+        from zope.interface.tests.unitfixtures import I2
+        from zope.interface.tests.unitfixtures import IC
+        self.failUnless(IC.implementedBy(C))
+
+        self.failUnless(I1.implementedBy(A))
+        self.failUnless(I1.implementedBy(B))
+        self.failUnless(not I1.implementedBy(C))
+        self.failUnless(I1.implementedBy(D))
+        self.failUnless(I1.implementedBy(E))
+
+        self.failUnless(not I2.implementedBy(A))
+        self.failUnless(I2.implementedBy(B))
+        self.failUnless(not I2.implementedBy(C))
+
+        # No longer after interfacegeddon
+        # self.failUnless(not I2.implementedBy(D))
+
+        self.failUnless(not I2.implementedBy(E))
+
+    def testUtil(self):
+        from zope.interface import implementedBy
+        from zope.interface import providedBy
+        from zope.interface.tests.unitfixtures import A
+        from zope.interface.tests.unitfixtures import B
+        from zope.interface.tests.unitfixtures import C
+        from zope.interface.tests.unitfixtures import I1
+        from zope.interface.tests.unitfixtures import I2
+        from zope.interface.tests.unitfixtures import IC
+        self.failUnless(IC in implementedBy(C))
+        self.failUnless(I1 in implementedBy(A))
+        self.failUnless(not I1 in implementedBy(C))
+        self.failUnless(I2 in implementedBy(B))
+        self.failUnless(not I2 in implementedBy(C))
+
+        self.failUnless(IC in providedBy(C()))
+        self.failUnless(I1 in providedBy(A()))
+        self.failUnless(not I1 in providedBy(C()))
+        self.failUnless(I2 in providedBy(B()))
+        self.failUnless(not I2 in providedBy(C()))
+
+
+    def testObjectImplements(self):
+        from zope.interface.tests.unitfixtures import A
+        from zope.interface.tests.unitfixtures import B
+        from zope.interface.tests.unitfixtures import C
+        from zope.interface.tests.unitfixtures import D
+        from zope.interface.tests.unitfixtures import E
+        from zope.interface.tests.unitfixtures import I1
+        from zope.interface.tests.unitfixtures import I2
+        from zope.interface.tests.unitfixtures import IC
+        self.failUnless(IC.providedBy(C()))
+
+        self.failUnless(I1.providedBy(A()))
+        self.failUnless(I1.providedBy(B()))
+        self.failUnless(not I1.providedBy(C()))
+        self.failUnless(I1.providedBy(D()))
+        self.failUnless(I1.providedBy(E()))
+
+        self.failUnless(not I2.providedBy(A()))
+        self.failUnless(I2.providedBy(B()))
+        self.failUnless(not I2.providedBy(C()))
+
+        # Not after interface geddon
+        # self.failUnless(not I2.providedBy(D()))
+
+        self.failUnless(not I2.providedBy(E()))
+
+    def testDeferredClass(self):
+        from zope.interface.tests.unitfixtures import A
+        from zope.interface.exceptions import BrokenImplementation
+        a = A()
+        self.assertRaises(BrokenImplementation, a.ma)
+
+
+    def testInterfaceExtendsInterface(self):
+        from zope.interface.tests.unitfixtures import BazInterface
+        from zope.interface.tests.unitfixtures import BarInterface
+        from zope.interface.tests.unitfixtures import BobInterface
+        from zope.interface.tests.unitfixtures import FunInterface
+        self.failUnless(BazInterface.extends(BobInterface))
+        self.failUnless(BazInterface.extends(BarInterface))
+        self.failUnless(BazInterface.extends(FunInterface))
+        self.failUnless(not BobInterface.extends(FunInterface))
+        self.failUnless(not BobInterface.extends(BarInterface))
+        self.failUnless(BarInterface.extends(FunInterface))
+        self.failUnless(not BarInterface.extends(BazInterface))
+
+    def testVerifyImplementation(self):
+        from zope.interface.verify import verifyClass
+        from zope.interface import Interface
+        from zope.interface.tests.unitfixtures import Foo
+        from zope.interface.tests.unitfixtures import FooInterface
+        from zope.interface.tests.unitfixtures import I1
+        self.failUnless(verifyClass(FooInterface, Foo))
+        self.failUnless(Interface.providedBy(I1))
+
+    def test_names(self):
+        iface = self._makeDerivedInterface()
+        names = list(iface.names())
+        names.sort()
+        self.assertEqual(names, ['f21', 'f22', 'f23'])
+        all = list(iface.names(all=True))
+        all.sort()
+        self.assertEqual(all, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+    def test_namesAndDescriptions(self):
+        iface = self._makeDerivedInterface()
+        names = [nd[0] for nd in iface.namesAndDescriptions()]
+        names.sort()
+        self.assertEqual(names, ['f21', 'f22', 'f23'])
+        names = [nd[0] for nd in iface.namesAndDescriptions(1)]
+        names.sort()
+        self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+        for name, d in iface.namesAndDescriptions(1):
+            self.assertEqual(name, d.__name__)
+
+    def test_getDescriptionFor(self):
+        iface = self._makeDerivedInterface()
+        self.assertEqual(iface.getDescriptionFor('f11').__name__, 'f11')
+        self.assertEqual(iface.getDescriptionFor('f22').__name__, 'f22')
+        self.assertEqual(iface.queryDescriptionFor('f33', self), self)
+        self.assertRaises(KeyError, iface.getDescriptionFor, 'f33')
+
+    def test___getitem__(self):
+        iface = self._makeDerivedInterface()
+        self.assertEqual(iface['f11'].__name__, 'f11')
+        self.assertEqual(iface['f22'].__name__, 'f22')
+        self.assertEqual(iface.get('f33', self), self)
+        self.assertRaises(KeyError, iface.__getitem__, 'f33')
+
+    def test___contains__(self):
+        iface = self._makeDerivedInterface()
+        self.failUnless('f11' in iface)
+        self.failIf('f33' in iface)
+
+    def test___iter__(self):
+        iface = self._makeDerivedInterface()
+        names = list(iter(iface))
+        names.sort()
+        self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+    def testAttr(self):
+        iface = self._makeDerivedInterface()
+        description = iface.getDescriptionFor('a1')
+        self.assertEqual(description.__name__, 'a1')
+        self.assertEqual(description.__doc__, 'This is an attribute')
+
+    def testFunctionAttributes(self):
+        # Make sure function attributes become tagged values.
+        from zope.interface import Interface
+        class ITest(Interface):
+            def method():
+                pass
+            method.optional = 1
+
+        method = ITest['method']
+        self.assertEqual(method.getTaggedValue('optional'), 1)
+
+    def testInvariant(self):
+        from zope.interface.exceptions import Invalid
+        from zope.interface import directlyProvides
+        from zope.interface.tests.unitfixtures import BarGreaterThanFoo
+        from zope.interface.tests.unitfixtures import ifFooThenBar
+        from zope.interface.tests.unitfixtures import IInvariant
+        from zope.interface.tests.unitfixtures import InvariantC
+        from zope.interface.tests.unitfixtures import ISubInvariant
+        # set up
+        o = InvariantC()
+        directlyProvides(o, IInvariant)
+        # a helper
+        def errorsEqual(self, o, error_len, error_msgs, iface=None):
+            if iface is None:
+                iface = IInvariant
+            self.assertRaises(Invalid, iface.validateInvariants, o)
+            e = []
+            try:
+                iface.validateInvariants(o, e)
+            except Invalid, error:
+                self.assertEqual(error.args[0], e)
+            else:
+                self._assert(0) # validateInvariants should always raise
+                # Invalid
+            self.assertEqual(len(e), error_len)
+            msgs = [error.args[0] for error in e]
+            msgs.sort()
+            for msg in msgs:
+                self.assertEqual(msg, error_msgs.pop(0))
+        # the tests
+        self.assertEqual(IInvariant.getTaggedValue('invariants'),
+                          [ifFooThenBar])
+        self.assertEqual(IInvariant.validateInvariants(o), None)
+        o.bar = 27
+        self.assertEqual(IInvariant.validateInvariants(o), None)
+        o.foo = 42
+        self.assertEqual(IInvariant.validateInvariants(o), None)
+        del o.bar
+        errorsEqual(self, o, 1, ['If Foo, then Bar!'])
+        # nested interfaces with invariants:
+        self.assertEqual(ISubInvariant.getTaggedValue('invariants'),
+                          [BarGreaterThanFoo])
+        o = InvariantC()
+        directlyProvides(o, ISubInvariant)
+        o.foo = 42
+        # even though the interface has changed, we should still only have one
+        # error.
+        errorsEqual(self, o, 1, ['If Foo, then Bar!'], ISubInvariant)
+        # however, if we set foo to 0 (Boolean False) and bar to a negative
+        # number then we'll get the new error
+        o.foo = 2
+        o.bar = 1
+        errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'],
+                    ISubInvariant)
+        # and if we set foo to a positive number and boo to 0, we'll
+        # get both errors!
+        o.foo = 1
+        o.bar = 0
+        errorsEqual(self, o, 2, ['If Foo, then Bar!',
+                                 'Please, Boo MUST be greater than Foo!'],
+                    ISubInvariant)
+        # for a happy ending, we'll make the invariants happy
+        o.foo = 1
+        o.bar = 2
+        self.assertEqual(IInvariant.validateInvariants(o), None) # woohoo
+        # now we'll do two invariants on the same interface,
+        # just to make sure that a small
+        # multi-invariant interface is at least minimally tested.
+        o = InvariantC()
+        directlyProvides(o, IInvariant)
+        o.foo = 42
+        old_invariants = IInvariant.getTaggedValue('invariants')
+        invariants = old_invariants[:]
+        invariants.append(BarGreaterThanFoo) # if you really need to mutate,
+        # then this would be the way to do it.  Probably a bad idea, though. :-)
+        IInvariant.setTaggedValue('invariants', invariants)
+        #
+        # even though the interface has changed, we should still only have one
+        # error.
+        errorsEqual(self, o, 1, ['If Foo, then Bar!'])
+        # however, if we set foo to 0 (Boolean False) and bar to a negative
+        # number then we'll get the new error
+        o.foo = 2
+        o.bar = 1
+        errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'])
+        # and if we set foo to a positive number and boo to 0, we'll
+        # get both errors!
+        o.foo = 1
+        o.bar = 0
+        errorsEqual(self, o, 2, ['If Foo, then Bar!',
+                                 'Please, Boo MUST be greater than Foo!'])
+        # for another happy ending, we'll make the invariants happy again
+        o.foo = 1
+        o.bar = 2
+        self.assertEqual(IInvariant.validateInvariants(o), None) # bliss
+        # clean up
+        IInvariant.setTaggedValue('invariants', old_invariants)
+
+    def test___doc___element(self):
+        from zope.interface import Interface
+        from zope.interface import Attribute
+        class I(Interface):
+            "xxx"
+
+        self.assertEqual(I.__doc__, "xxx")
+        self.assertEqual(list(I), [])
+
+        class I(Interface):
+            "xxx"
+
+            __doc__ = Attribute('the doc')
+
+        self.assertEqual(I.__doc__, "")
+        self.assertEqual(list(I), ['__doc__'])
+
+    def testIssue228(self):
+        from zope.interface import Interface
+        # Test for http://collector.zope.org/Zope3-dev/228
+        if sys.version[0] == '3':
+            # No old style classes in Python 3, so the test becomes moot.
+            return
+        class I(Interface):
+            "xxx"
+        class Bad:
+            __providedBy__ = None
+        # Old style classes don't have a '__class__' attribute
+        self.failUnlessRaises(AttributeError, I.providedBy, Bad)
+
+    def test_comparison_with_None(self):
+        from zope.interface import Interface
+
+        class IEmpty(Interface):
+            pass
+
+        self.failUnless(IEmpty < None)
+        self.failUnless(IEmpty <= None)
+        self.failIf(IEmpty == None)
+        self.failUnless(IEmpty != None)
+        self.failIf(IEmpty >= None)
+        self.failIf(IEmpty > None)
+
+        self.failIf(None < IEmpty)
+        self.failIf(None <= IEmpty)
+        self.failIf(None == IEmpty)
+        self.failUnless(None != IEmpty)
+        self.failUnless(None >= IEmpty)
+        self.failUnless(None > IEmpty)
+
+    def test_comparison_with_same_instance(self):
+        from zope.interface import Interface
+
+        class IEmpty(Interface):
+            pass
+
+        self.failIf(IEmpty < IEmpty)
+        self.failUnless(IEmpty <= IEmpty)
+        self.failUnless(IEmpty == IEmpty)
+        self.failIf(IEmpty != IEmpty)
+        self.failUnless(IEmpty >= IEmpty)
+        self.failIf(IEmpty > IEmpty)
+
+    def test_comparison_with_same_named_instance_in_other_module(self):
+        from zope.interface.tests.ifoo import IFoo as IFoo1
+        from zope.interface.tests.ifoo_other import IFoo as IFoo2
+
+        self.failUnless(IFoo1 < IFoo2)
+        self.failUnless(IFoo1 <= IFoo2)
+        self.failIf(IFoo1 == IFoo2)
+        self.failUnless(IFoo1 != IFoo2)
+        self.failIf(IFoo1 >= IFoo2)
+        self.failIf(IFoo1 > IFoo2)
+
+    def test_hash_normal(self):
+        from zope.interface.tests.ifoo import IFoo
+        self.assertEqual(hash(IFoo),
+                         hash((('IFoo', 'zope.interface.tests.ifoo'))))
+
+    def test_hash_missing_required_attrs(self):
+        import warnings
+        try:
+            from warnings import catch_warnings
+        except ImportError:  # Python 2.5
+            return
+        from zope.interface.interface import InterfaceClass
+        class Derived(InterfaceClass):
+            def __init__(self):
+                pass # Don't call base class.
+        derived = Derived()
+        with catch_warnings(record=True) as warned:
+            warnings.simplefilter('always') # see LP #825249 
+            self.assertEqual(hash(derived), 1)
+            self.assertEqual(len(warned), 1)
+            self.failUnless(warned[0].category is UserWarning)
+            self.assertEqual(str(warned[0].message),
+                             'Hashing uninitialized InterfaceClass instance')
+
+
+if sys.version_info >= (2, 4):
+
+    def test_invariant_as_decorator():
+        """Invaiants can be deined in line
+
+          >>> from zope.interface.exceptions import Invalid
+          >>> from zope.interface import Interface
+          >>> from zope.interface import Attribute
+          >>> from zope.interface import implements
+          >>> from zope.interface import invariant
+          >>> class IRange(Interface):
+          ...     min = Attribute("Lower bound")
+          ...     max = Attribute("Upper bound")
+          ...
+          ...     @invariant
+          ...     def range_invariant(ob):
+          ...         if ob.max < ob.min:
+          ...             raise Invalid('max < min')
+
+
+          >>> class Range(object):
+          ...     implements(IRange)
+          ...
+          ...     def __init__(self, min, max):
+          ...         self.min, self.max = min, max
+
+          >>> from zope.interface.exceptions import Invalid
+          >>> IRange.validateInvariants(Range(1,2))
+          >>> IRange.validateInvariants(Range(1,1))
+          >>> try:
+          ...     IRange.validateInvariants(Range(2,1))
+          ... except Invalid, e:
+          ...     str(e)
+          'max < min'
+
+
+        """
+
+
+def test_description_cache_management():
+    """ See https://bugs.launchpad.net/zope.interface/+bug/185974
+
+There was a bug where the cache used by Specification.get() was not
+cleared when the bases were changed.
+
+    >>> from zope.interface import Interface
+    >>> from zope.interface import Attribute
+    >>> class I1(Interface):
+    ...     a = Attribute('a')
+
+    >>> class I2(I1):
+    ...     pass
+
+    >>> class I3(I2):
+    ...     pass
+
+    >>> I3.get('a') is I1.get('a')
+    True
+    >>> I2.__bases__ = (Interface,)
+    >>> I3.get('a') is None
+    True
+    """
+
+
+def test_suite():
+    suite = unittest.makeSuite(InterfaceTests)
+    suite.addTest(doctest.DocTestSuite("zope.interface.interface"))
+    if sys.version_info >= (2, 4):
+        suite.addTest(doctest.DocTestSuite())
+    suite.addTest(doctest.DocFileSuite(
+        '../README.txt',
+        globs={'__name__': '__main__'},
+        optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+        ))
+    suite.addTest(doctest.DocFileSuite(
+        '../README.ru.txt',
+        globs={'__name__': '__main__'},
+        optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+        ))
+    return suite
diff --git a/src/zope/interface/tests/test_odd_declarations.py b/src/zope/interface/tests/test_odd_declarations.py
new file mode 100644 (file)
index 0000000..cbafa22
--- /dev/null
@@ -0,0 +1,222 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Test interface declarations against ExtensionClass-like classes.
+
+These tests are to make sure we do something sane in the presence of
+classic ExtensionClass classes and instances.
+"""
+import doctest
+import unittest
+
+from zope.interface.tests import odd
+from zope.interface import Interface, implements, classProvides
+from zope.interface import directlyProvides, providedBy, directlyProvidedBy
+from zope.interface import classImplements, classImplementsOnly, implementedBy
+
+class I1(Interface): pass
+class I2(Interface): pass
+class I3(Interface): pass
+class I31(I3): pass
+class I4(Interface): pass
+class I5(Interface): pass
+
+class Odd(object): __metaclass__ = odd.MetaClass
+
+class B(Odd): __implemented__ = I2
+
+
+# TODO: We are going to need more magic to make classProvides work with odd
+#       classes. This will work in the next iteration. For now, we'll use
+#       a different mechanism.
+
+# from zope.interface import classProvides
+
+class A(Odd):
+    pass
+classImplements(A, I1)
+
+class C(A, B):
+    pass
+classImplements(C, I31)
+
+
+class Test(unittest.TestCase):
+
+    def failUnless(self, expr): # silence deprecation warnings under py3
+        return self.assertTrue(expr)
+
+    def failIf(self, expr): # silence deprecation warnings under py3
+        return self.assertFalse(expr)
+
+    def test_ObjectSpecification(self):
+        c = C()
+        directlyProvides(c, I4)
+        self.assertEqual([i.getName() for i in providedBy(c)],
+                         ['I4', 'I31', 'I1', 'I2']
+                         )
+        self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+                         ['I4', 'I31', 'I3', 'I1', 'I2', 'Interface']
+                         )
+        self.failUnless(I1 in providedBy(c))
+        self.failIf(I3 in providedBy(c))
+        self.failUnless(providedBy(c).extends(I3))
+        self.failUnless(providedBy(c).extends(I31))
+        self.failIf(providedBy(c).extends(I5))
+
+        class COnly(A, B):
+            pass
+        classImplementsOnly(COnly, I31)
+
+        class D(COnly):
+            pass
+        classImplements(D, I5)
+
+        classImplements(D, I5)
+
+        c = D()
+        directlyProvides(c, I4)
+        self.assertEqual([i.getName() for i in providedBy(c)],
+                         ['I4', 'I5', 'I31'])
+        self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+                         ['I4', 'I5', 'I31', 'I3', 'Interface'])
+        self.failIf(I1 in providedBy(c))
+        self.failIf(I3 in providedBy(c))
+        self.failUnless(providedBy(c).extends(I3))
+        self.failIf(providedBy(c).extends(I1))
+        self.failUnless(providedBy(c).extends(I31))
+        self.failUnless(providedBy(c).extends(I5))
+
+        class COnly(A, B): __implemented__ = I31
+        class D(COnly):
+            pass
+        classImplements(D, I5)
+
+        classImplements(D, I5)
+        c = D()
+        directlyProvides(c, I4)
+        self.assertEqual([i.getName() for i in providedBy(c)],
+                         ['I4', 'I5', 'I31'])
+        self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+                         ['I4', 'I5', 'I31', 'I3', 'Interface'])
+        self.failIf(I1 in providedBy(c))
+        self.failIf(I3 in providedBy(c))
+        self.failUnless(providedBy(c).extends(I3))
+        self.failIf(providedBy(c).extends(I1))
+        self.failUnless(providedBy(c).extends(I31))
+        self.failUnless(providedBy(c).extends(I5))
+
+    def test_classImplements(self):
+        class A(Odd):
+            implements(I3)
+
+        class B(Odd):
+            implements(I4)
+
+        class C(A, B):
+            pass
+        classImplements(C, I1, I2)
+        self.assertEqual([i.getName() for i in implementedBy(C)],
+                         ['I1', 'I2', 'I3', 'I4'])
+        classImplements(C, I5)
+        self.assertEqual([i.getName() for i in implementedBy(C)],
+                         ['I1', 'I2', 'I5', 'I3', 'I4'])
+
+    def test_classImplementsOnly(self):
+        class A(Odd):
+            implements(I3)
+
+        class B(Odd):
+            implements(I4)
+
+        class C(A, B):
+            pass
+        classImplementsOnly(C, I1, I2)
+        self.assertEqual([i.__name__ for i in implementedBy(C)],
+                         ['I1', 'I2'])
+
+
+    def test_directlyProvides(self):
+        class IA1(Interface): pass
+        class IA2(Interface): pass
+        class IB(Interface): pass
+        class IC(Interface): pass
+        class A(Odd):
+            pass
+        classImplements(A, IA1, IA2)
+
+        class B(Odd):
+            pass
+        classImplements(B, IB)
+
+        class C(A, B):
+            pass
+        classImplements(C, IC)
+
+
+        ob = C()
+        directlyProvides(ob, I1, I2)
+        self.failUnless(I1 in providedBy(ob))
+        self.failUnless(I2 in providedBy(ob))
+        self.failUnless(IA1 in providedBy(ob))
+        self.failUnless(IA2 in providedBy(ob))
+        self.failUnless(IB in providedBy(ob))
+        self.failUnless(IC in providedBy(ob))
+
+        directlyProvides(ob, directlyProvidedBy(ob)-I2)
+        self.failUnless(I1 in providedBy(ob))
+        self.failIf(I2 in providedBy(ob))
+        self.failIf(I2 in providedBy(ob))
+        directlyProvides(ob, directlyProvidedBy(ob), I2)
+        self.failUnless(I2 in providedBy(ob))
+
+    def test_directlyProvides_fails_for_odd_class(self):
+        self.assertRaises(TypeError, directlyProvides, C, I5)
+
+    # see above
+    def TODO_test_classProvides_fails_for_odd_class(self):
+        try:
+            class A(Odd):
+                classProvides(I1)
+        except TypeError:
+            pass # Sucess
+        self.failUnless(False,
+                     "Shouldn't be able to use directlyProvides on odd class."
+                     )
+
+    def test_implementedBy(self):
+        class I2(I1): pass
+
+        class C1(Odd):
+            pass
+        classImplements(C1, I2)
+
+        class C2(C1):
+            pass
+        classImplements(C2, I3)
+
+        self.assertEqual([i.getName() for i in implementedBy(C2)],
+                         ['I3', 'I2'])
+
+
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    suite.addTest(doctest.DocTestSuite(odd))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/zope/interface/tests/test_registry.py b/src/zope/interface/tests/test_registry.py
new file mode 100644 (file)
index 0000000..a151001
--- /dev/null
@@ -0,0 +1,950 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002, 2009 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.
+#
+##############################################################################
+"""Component Registry Tests"""
+
+import types
+import unittest
+
+from zope import interface
+from zope.interface import implementedBy
+from zope.interface.interfaces import ComponentLookupError
+from zope.interface.registry import Components
+
+import sys
+
+# fixtures
+
+if sys.version_info[0] == 3:
+    _class_types = type
+else:
+    _class_types = (type, types.ClassType)
+
+class adapter:
+
+    def __init__(self, *interfaces):
+        self.interfaces = interfaces
+
+    def __call__(self, ob):
+        if isinstance(ob, _class_types):
+            ob.__component_adapts__ = _adapts_descr(self.interfaces)
+        else:
+            ob.__component_adapts__ = self.interfaces
+
+        return ob
+
+
+def adapts(*interfaces):
+    frame = sys._getframe(1)
+    locals = frame.f_locals
+
+    # Try to make sure we were called from a class def. In 2.2.0 we can't
+    # check for __module__ since it doesn't seem to be added to the locals
+    # until later on.
+    if (locals is frame.f_globals) or (
+        ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)):
+        raise TypeError("adapts can be used only from a class definition.")
+
+    if '__component_adapts__' in locals:
+        raise TypeError("adapts can be used only once in a class definition.")
+
+    locals['__component_adapts__'] = _adapts_descr(interfaces)
+
+class _adapts_descr(object):
+    def __init__(self, interfaces):
+        self.interfaces = interfaces
+
+    def __get__(self, inst, cls):
+        if inst is None:
+            return self.interfaces
+        raise AttributeError('__component_adapts__')
+
+class I1(interface.Interface):
+    pass
+class I2(interface.Interface):
+    pass
+class I2e(I2):
+    pass
+class I3(interface.Interface):
+    pass
+class IC(interface.Interface):
+    pass
+
+class ITestType(interface.interfaces.IInterface):
+    pass
+
+class U:
+
+    def __init__(self, name):
+        self.__name__ = name
+
+    def __repr__(self):
+        return "%s(%s)" % (self.__class__.__name__, self.__name__)
+
+class U1(U):
+    interface.implements(I1)
+
+class U12(U):
+    interface.implements(I1, I2)
+
+class IA1(interface.Interface):
+    pass
+
+class IA2(interface.Interface):
+    pass
+
+class IA3(interface.Interface):
+    pass
+
+class A:
+
+    def __init__(self, *context):
+        self.context = context
+
+    def __repr__(self):
+        return "%s%r" % (self.__class__.__name__, self.context)
+
+class A12_1(A):
+    adapts(I1, I2)
+    interface.implements(IA1)
+
+class A12_(A):
+    adapts(I1, I2)
+
+class A_2(A):
+    interface.implements(IA2)
+
+class A_3(A):
+    interface.implements(IA3)
+
+class A1_12(U):
+    adapts(I1)
+    interface.implements(IA1, IA2)
+
+class A1_2(U):
+    adapts(I1)
+    interface.implements(IA2)
+
+class A1_23(U):
+    adapts(I1)
+    interface.implements(IA1, IA3)
+
+def noop(*args):
+    pass
+
+
+# tests
+
+class TestAdapter(unittest.TestCase):
+
+    def setUp(self):
+        self.components = Components('comps')
+
+    def test_register_and_unregister_adapter(self):
+        self.components.registerAdapter(A12_1)
+
+        multi_adapter = self.components.getMultiAdapter(
+            (U1(1), U12(2)), IA1)
+        self.assertEqual(multi_adapter.__class__, A12_1)
+        self.assertEqual(repr(multi_adapter), 'A12_1(U1(1), U12(2))')
+
+        self.assertTrue(self.components.unregisterAdapter(A12_1))
+        self.assertRaises(
+            ComponentLookupError,
+            self.components.getMultiAdapter,
+            (U1(1), U12(2)),
+            IA1
+            )
+
+    def test_register_and_unregister_adapter_with_two_interfaces(self):
+        self.assertRaises(TypeError, self.components.registerAdapter,
+                          A1_12)
+        self.components.registerAdapter(A1_12,
+                                        provided=IA2)
+
+        multi_adapter = self.components.getMultiAdapter((U1(1),), IA2)
+        self.assertEqual(multi_adapter.__class__, A1_12)
+        self.assertEqual(repr(multi_adapter), 'A1_12(U1(1))')
+
+        self.assertRaises(TypeError, self.components.unregisterAdapter, A1_12)
+        self.assertTrue(self.components.unregisterAdapter(A1_12, provided=IA2))
+        self.assertRaises(ComponentLookupError,
+                          self.components.getMultiAdapter, (U1(1),), IA2)
+
+    def test_register_and_unregister_adapter_with_no_interfaces(self):
+        self.assertRaises(TypeError, self.components.registerAdapter, A12_)
+
+        self.components.registerAdapter(A12_, provided=IA2)
+        multi_adapter = self.components.getMultiAdapter((U1(1), U12(2)), IA2)
+        self.assertEqual(multi_adapter.__class__, A12_)
+        self.assertEqual(repr(multi_adapter), 'A12_(U1(1), U12(2))')
+
+        self.assertRaises(TypeError, self.components.unregisterAdapter, A12_)
+        self.assertTrue(self.components.unregisterAdapter(A12_, provided=IA2))
+        self.assertRaises(ComponentLookupError,
+                          self.components.getMultiAdapter, (U1(1), U12(2)), IA2)
+
+    def test_reg_and_unreg_adp_with_no___component_adapts___attribute(self):
+        self.assertRaises(TypeError, self.components.registerAdapter, A_2)
+        self.components.registerAdapter(A_2, required=[I3])
+        self.assertTrue(self.components.unregisterAdapter(A_2, required=[I3]))
+
+    def test_register_and_unregister_class_specific(self):
+        self.components.registerAdapter(A_3, required=[U],
+                                        info=u'Really class specific')
+        self.assertTrue(self.components.unregisterAdapter(required=[U],
+                                                          provided=IA3))
+      
+    def test_registered_adapters_and_sorting(self):
+        self.components.registerAdapter(A12_1)
+        self.components.registerAdapter(A1_12, provided=IA2)
+        self.components.registerAdapter(A12_, provided=IA2)
+        self.components.registerAdapter(A_2, required=[I3])
+        self.components.registerAdapter(A_3, required=[U],
+                                        info=u'Really class specific')
+
+        sorted_adapters = sorted(self.components.registeredAdapters())
+        sorted_adapters_name = map(lambda x: getattr(x, 'name'),
+                                   sorted_adapters)
+        sorted_adapters_provided = map(lambda x: getattr(x, 'provided'),
+                                       sorted_adapters) 
+        sorted_adapters_required = map(lambda x: getattr(x, 'required'),
+                                       sorted_adapters)
+        sorted_adapters_info = map(lambda x: getattr(x, 'info'),
+                                   sorted_adapters)
+
+        self.assertEqual(len(sorted_adapters), 5)
+        self.assertEqual(sorted_adapters_name, [u'', u'', u'', u'', u''])
+        self.assertEqual(sorted_adapters_provided, [IA1,
+                                                    IA2,
+                                                    IA2,
+                                                    IA2,
+                                                    IA3])
+
+        self.assertEqual(sorted_adapters_required, [(I1, I2),
+                                                    (I1, I2),
+                                                    (I1,),
+                                                    (I3,),
+                                                    (implementedBy(U),)])
+        self.assertEqual(sorted_adapters_info,
+                         [u'', u'', u'', u'', u'Really class specific'])
+
+    def test_get_none_existing_adapter(self):
+        self.assertRaises(ComponentLookupError,
+                          self.components.getMultiAdapter, (U(1),), IA1)
+
+    def test_query_none_existing_adapter(self):
+        self.assertTrue(self.components.queryMultiAdapter((U(1),), IA1) is None)
+        self.assertEqual(self.components.queryMultiAdapter((U(1),), IA1,
+                                                           default=42), 42)
+
+    def test_unregister_none_existing_adapter(self):
+        self.assertFalse(self.components.unregisterAdapter(A_2, required=[I3]))
+        self.assertFalse(self.components.unregisterAdapter(A12_1, required=[U]))
+
+    def test_unregister_adapter(self):
+        self.components.registerAdapter(A12_1)
+        self.components.registerAdapter(A1_12, provided=IA2)
+        self.components.registerAdapter(A12_, provided=IA2)
+        self.components.registerAdapter(A_2, required=[I3])
+        self.components.registerAdapter(A_3, required=[U],
+                                        info=u'Really class specific')
+
+        self.assertTrue(self.components.unregisterAdapter(A12_1))
+        self.assertTrue(self.components.unregisterAdapter(
+            required=[U], provided=IA3))
+
+        sorted_adapters = sorted(self.components.registeredAdapters())
+        sorted_adapters_name = map(lambda x: getattr(x, 'name'),
+                                   sorted_adapters)
+        sorted_adapters_provided = map(lambda x: getattr(x, 'provided'),
+                                       sorted_adapters) 
+        sorted_adapters_required = map(lambda x: getattr(x, 'required'),
+                                       sorted_adapters)
+        sorted_adapters_info = map(lambda x: getattr(x, 'info'),
+                                   sorted_adapters)
+
+        self.assertEqual(len(sorted_adapters), 3)
+        self.assertEqual(sorted_adapters_name, [u'', u'', u''])
+        self.assertEqual(sorted_adapters_provided, [IA2,
+                                                    IA2,
+                                                    IA2])
+        self.assertEqual(sorted_adapters_required, [(I1, I2),
+                                                    (I1,),
+                                                    (I3,)])
+        self.assertEqual(sorted_adapters_info, [u'', u'', u''])
+
+    def test_register_named_adapter(self):
+        self.components.registerAdapter(A1_12, provided=IA2, name=u'test')
+        self.assertTrue(
+            self.components.queryMultiAdapter((U1(1),), IA2) is None)
+        self.assertEqual(
+            repr(self.components.queryMultiAdapter((U1(1),),IA2,name=u'test')),
+            'A1_12(U1(1))')
+
+        self.assertTrue(self.components.queryAdapter(U1(1), IA2) is None)
+        self.assertEqual(
+            repr(self.components.queryAdapter(U1(1), IA2, name=u'test')),
+            'A1_12(U1(1))')
+        self.assertEqual(
+            repr(self.components.getAdapter(U1(1), IA2, name=u'test')),
+            'A1_12(U1(1))')
+
+    def test_get_adapters(self):
+        self.components.registerAdapter(A1_12, provided=IA1, name=u'test 1')
+        self.components.registerAdapter(A1_23, provided=IA2, name=u'test 2')
+        self.components.registerAdapter(A1_12, provided=IA2)
+        self.components.registerAdapter(A1_12, provided=IA2)
+
+        adapters = list(self.components.getAdapters((U1(1),), IA2))
+        self.assertEqual(len(adapters), 2)
+        self.assertEqual(adapters[0][0], u'test 2')
+        self.assertEqual(adapters[1][0], u'')
+        self.assertEqual(repr(adapters[0][1]), 'A1_23(U1(1))')
+        self.assertEqual(repr(adapters[1][1]), 'A1_12(U1(1))')
+
+    def test_register_no_factory(self):
+        self.components.registerAdapter(A1_12, provided=IA2)
+        self.components.registerAdapter(noop, 
+                                        required=[IA1], provided=IA2, 
+                                        name=u'test noop')
+
+        self.assertTrue(
+            self.components.queryAdapter(U1(9), IA2, name=u'test noop') is None)
+        adapters = list(self.components.getAdapters((U1(1),), IA2))
+        self.assertEqual(len(adapters), 1)
+        self.assertEqual(adapters[0][0], u'')
+        self.assertEqual(repr(adapters[0][1]), 'A1_12(U1(1))')
+
+        self.assertTrue(self.components.unregisterAdapter(A1_12, provided=IA2))
+
+        sorted_adapters = sorted(self.components.registeredAdapters())
+        sorted_adapters_name = map(lambda x: getattr(x, 'name'),
+                                   sorted_adapters)
+        sorted_adapters_provided = map(lambda x: getattr(x, 'provided'),
+                                       sorted_adapters) 
+        sorted_adapters_required = map(lambda x: getattr(x, 'required'),
+                                       sorted_adapters)
+        sorted_adapters_info = map(lambda x: getattr(x, 'info'),
+                                   sorted_adapters)
+
+        self.assertEqual(len(sorted_adapters), 1)
+        self.assertEqual(sorted_adapters_name, [u'test noop'])
+        self.assertEqual(sorted_adapters_provided, [IA2])
+        self.assertEqual(sorted_adapters_required, [(IA1,)])
+        self.assertEqual(sorted_adapters_info, [u''])
+
+
+class TestExtending(unittest.TestCase):
+
+    def test_extendning(self):
+        c1 = Components('1')
+        self.assertEqual(c1.__bases__, ())
+
+        c2 = Components('2', (c1, ))
+        self.assertTrue(c2.__bases__ == (c1, ))
+
+        test_object1 = U1(1)
+        test_object2 = U1(2)
+        test_object3 = U12(1)
+        test_object4 = U12(3)
+
+        self.assertEqual(len(list(c1.registeredUtilities())), 0)
+        self.assertEqual(len(list(c2.registeredUtilities())), 0)
+
+        c1.registerUtility(test_object1)
+        self.assertEqual(len(list(c1.registeredUtilities())), 1)
+        self.assertEqual(len(list(c2.registeredUtilities())), 0)
+        self.assertEqual(c1.queryUtility(I1), test_object1)
+        self.assertEqual(c2.queryUtility(I1), test_object1)
+
+        c1.registerUtility(test_object2)
+        self.assertEqual(len(list(c1.registeredUtilities())), 1)
+        self.assertEqual(len(list(c2.registeredUtilities())), 0)
+        self.assertEqual(c1.queryUtility(I1), test_object2)
+        self.assertEqual(c2.queryUtility(I1), test_object2)
+
+
+        c3 = Components('3', (c1, ))
+        c4 = Components('4', (c2, c3))
+        self.assertEqual(c4.queryUtility(I1), test_object2)
+    
+        c1.registerUtility(test_object3, I2)
+        self.assertEqual(c4.queryUtility(I2), test_object3)
+
+        c3.registerUtility(test_object4, I2)
+        self.assertEqual(c4.queryUtility(I2), test_object4)
+
+        @adapter(I1)
+        def handle1(x):
+            self.assertEqual(x, test_object1)
+
+        def handle(*objects):
+            self.assertEqual(objects, (test_object1,))
+
+        @adapter(I1)
+        def handle3(x):
+            self.assertEqual(x, test_object1)
+
+        @adapter(I1)
+        def handle4(x):
+            self.assertEqual(x, test_object1)
+
+        c1.registerHandler(handle1, info=u'First handler')
+        c2.registerHandler(handle, required=[U])
+        c3.registerHandler(handle3)
+        c4.registerHandler(handle4)
+
+        c4.handle(test_object1)
+
+class TestHandler(unittest.TestCase):
+
+    def setUp(self):
+        self.components = Components('comps')
+
+    def test_register_handler(self):
+        test_object1 = U1(1)
+        test_object2 = U12(2)
+
+        @adapter(I1)
+        def handle1(x):
+            self.assertEqual(x, test_object1)
+
+        self.components.registerHandler(handle1, info=u'First handler')
+        self.components.handle(test_object1)
+
+        @adapter(I1, I2)
+        def handle12(x, y):
+            self.assertEqual(x, test_object1)
+            self.assertEqual(y, test_object2)
+
+        self.components.registerHandler(handle12)
+        self.components.handle(test_object1, test_object2)
+
+    def test_register_noncompliant_handler(self):
+        handle_calls = []
+        def handle(*objects):
+            handle_calls.append(objects)
+
+        self.assertRaises(TypeError, self.components.registerHandler, handle)
+        self.components.registerHandler(
+            handle, required=[I1], info=u'a comment')
+        self.components.registerHandler(
+            handle, required=[U], info=u'handle a class')
+
+        test_object = U1(1)
+        self.components.handle(test_object)
+        self.assertEqual(len(handle_calls), 2)
+        map(self.assertEqual, handle_calls, [(test_object,), (test_object,)])
+
+    def test_list_handlers(self):
+        test_object1 = U1(1)
+        test_object2 = U12(2)
+
+        @adapter(I1)
+        def handle1(x):
+            self.assertEqual(x, test_object1)
+
+        @adapter(I1, I2)
+        def handle12(x, y):
+            self.assertEqual(x, test_object1)
+            self.assertEqual(y, test_object2)
+
+        handle_calls = []
+        def handle(*objects):
+            handle_calls.append(objects)
+
+        self.components.registerHandler(handle1, info=u'First handler')
+        self.components.registerHandler(handle12)
+        self.components.registerHandler(
+            handle, required=[I1], info=u'a comment')
+        self.components.registerHandler(
+            handle, required=[U], info=u'handle a class')
+
+        handlers = list(self.components.registeredHandlers())
+        handlers_required = map(lambda x: getattr(x, 'required'), handlers)
+        handlers_handler = map(lambda x: getattr(x, 'handler'), handlers)
+        handlers_info = map(lambda x: getattr(x, 'info'), handlers)
+
+        self.assertEqual(len(handlers), 4)
+        self.assertEqual(handlers_required,
+                         [(I1,), (I1, I2), (I1,), (implementedBy(U),)])
+        self.assertEqual(handlers_handler,
+                         [handle1, handle12, handle, handle])
+        self.assertEqual(
+            handlers_info,
+            [u'First handler', u'', u'a comment', u'handle a class'])
+
+    def test_unregister_handler(self):
+        test_object1 = U1(1)
+        test_object2 = U12(2)
+
+        @adapter(I1)
+        def handle1(x):
+            self.assertEqual(x, test_object1)
+
+        @adapter(I1, I2)
+        def handle12(x, y):
+            self.assertEqual(x, test_object1)
+            self.assertEqual(y, test_object2)
+
+        handle_calls = []
+        def handle(*objects):
+            handle_calls.append(objects)
+
+        self.components.registerHandler(handle1, info=u'First handler')
+        self.components.registerHandler(handle12)
+        self.components.registerHandler(
+            handle, required=[I1], info=u'a comment')
+        self.components.registerHandler(
+            handle, required=[U], info=u'handle a class')
+
+        self.assertEqual(len(list(self.components.registeredHandlers())), 4)
+        self.assertTrue(self.components.unregisterHandler(handle12))
+        self.assertEqual(len(list(self.components.registeredHandlers())), 3)
+        self.assertFalse(self.components.unregisterHandler(handle12))
+        self.assertEqual(len(list(self.components.registeredHandlers())), 3)
+        self.assertRaises(TypeError, self.components.unregisterHandler)
+        self.assertEqual(len(list(self.components.registeredHandlers())), 3)
+        self.assertTrue(
+            self.components.unregisterHandler(handle, required=[I1]))
+        self.assertEqual(len(list(self.components.registeredHandlers())), 2)
+        self.assertTrue(self.components.unregisterHandler(handle, required=[U]))
+        self.assertEqual(len(list(self.components.registeredHandlers())), 1)
+
+    def test_multi_handler_unregistration(self):
+        """
+        There was a bug where multiple handlers for the same required
+        specification would all be removed when one of them was
+        unregistered.
+
+        """
+        from zope import interface
+
+        calls = []
+
+        class I(interface.Interface):
+            pass
+
+        def factory1(event):
+            calls.append(2)
+
+        def factory2(event):
+            calls.append(3)
+
+        class Event(object):
+            interface.implements(I)
+
+        self.components.registerHandler(factory1, [I,])
+        self.components.registerHandler(factory2, [I,])
+        self.components.handle(Event())
+        self.assertEqual(sum(calls), 5)
+        self.assertTrue(self.components.unregisterHandler(factory1, [I,]))
+        calls = []
+        self.components.handle(Event())
+        self.assertEqual(sum(calls), 3)
+
+class TestSubscriber(unittest.TestCase):
+
+    def setUp(self):
+        self.components = Components('comps')
+
+    def test_register_subscriber(self):
+        self.components.registerSubscriptionAdapter(A1_2)
+        self.components.registerSubscriptionAdapter(A1_12, provided=IA2)
+        self.components.registerSubscriptionAdapter(
+            A, [I1], IA2, info='a sample comment')
+        subscribers = self.components.subscribers((U1(1),), IA2)
+        self.assertEqual(len(subscribers), 3)
+        self.assertEqual(repr(subscribers[0]), 'A1_2(U1(1))')
+        self.assertEqual(repr(subscribers[1]), 'A1_12(U1(1))')
+        self.assertEqual(repr(subscribers[2]), 'A(U1(1),)') 
+
+    def test_register_noncompliant_subscriber(self):
+        self.assertRaises(TypeError,
+                          self.components.registerSubscriptionAdapter, A1_12)
+        self.assertRaises(TypeError,
+                          self.components.registerSubscriptionAdapter, A)
+        self.assertRaises(
+            TypeError,
+            self.components.registerSubscriptionAdapter, A, required=[IA1])
+
+    def test_register_named_subscriber(self):
+        self.components.registerSubscriptionAdapter(
+            A, [I1], IA2, u'', u'a sample comment')
+        self.assertRaises(TypeError,
+                          self.components.registerSubscriptionAdapter, 
+                          A, [I1], IA2, u'oops', u'a sample comment')
+        subscribers = self.components.subscribers((U1(1),), IA2)
+        self.assertEqual(len(subscribers), 1)
+        self.assertEqual(repr(subscribers[0]), 'A(U1(1),)')
+
+    def test_register_no_factory(self):
+        self.components.registerSubscriptionAdapter(noop, [I1], IA2)
+        subscribers = self.components.subscribers((U1(1),), IA2)
+        self.assertEqual(len(subscribers), 0)
+
+    def test_sorting_registered_subscription_adapters(self):
+        self.components.registerSubscriptionAdapter(A1_2)
+        self.components.registerSubscriptionAdapter(A1_12, provided=IA2)
+        self.components.registerSubscriptionAdapter(
+            A, [I1], IA2, info=u'a sample comment')
+        self.components.registerSubscriptionAdapter(
+            A, [I1], IA2, u'', u'a sample comment')
+        self.components.registerSubscriptionAdapter(noop, [I1], IA2)
+
+        sorted_subscribers = sorted(
+            self.components.registeredSubscriptionAdapters())
+        sorted_subscribers_name = map(lambda x: getattr(x, 'name'),
+                                      sorted_subscribers)
+        sorted_subscribers_provided = map(lambda x: getattr(x, 'provided'),
+                                          sorted_subscribers) 
+        sorted_subscribers_required = map(lambda x: getattr(x, 'required'),
+                                          sorted_subscribers)
+        sorted_subscribers_factory = map(lambda x: getattr(x, 'factory'),
+                                         sorted_subscribers)
+        sorted_subscribers_info = map(lambda x: getattr(x, 'info'),
+                                      sorted_subscribers)
+
+        self.assertEqual(len(sorted_subscribers), 5)
+        self.assertEqual(sorted_subscribers_name, [u'', u'', u'', u'', u''])
+        self.assertEqual(sorted_subscribers_provided,
+                         [IA2, IA2, IA2, IA2, IA2])
+        self.assertEqual(sorted_subscribers_required,
+                         [(I1,), (I1,), (I1,),(I1,), (I1,)])
+        self.assertEqual(sorted_subscribers_factory,
+                         [A, A, A1_12, A1_2, noop])
+        self.assertEqual(
+            sorted_subscribers_info,
+            [u'a sample comment', u'a sample comment', u'', u'', u''])
+
+    def test_unregister(self):
+        self.components.registerSubscriptionAdapter(A1_2)
+        self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 1)
+        self.assertTrue(self.components.unregisterSubscriptionAdapter(A1_2))
+        self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 0)
+
+    def test_unregister_multiple(self):
+        self.components.registerSubscriptionAdapter(A1_2)
+        self.components.registerSubscriptionAdapter(A1_12, provided=IA2)
+        self.components.registerSubscriptionAdapter(
+            A, [I1], IA2, info=u'a sample comment')
+        self.components.registerSubscriptionAdapter(
+            A, [I1], IA2, u'', u'a sample comment')
+        self.components.registerSubscriptionAdapter(noop, [I1], IA2)
+        self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 4)
+        self.assertEqual(
+            len(list(self.components.registeredSubscriptionAdapters())), 5)
+
+        self.assertTrue(
+            self.components.unregisterSubscriptionAdapter(A, [I1], IA2))
+        self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 2)
+        self.assertEqual(
+            len(list(self.components.registeredSubscriptionAdapters())), 3)
+
+    def test_unregister_no_factory(self):
+        self.components.registerSubscriptionAdapter(A1_2)
+        self.components.registerSubscriptionAdapter(A1_12, provided=IA2)
+        self.components.registerSubscriptionAdapter(noop, [I1], IA2)
+        self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 2)
+        self.assertEqual(
+            len(list(self.components.registeredSubscriptionAdapters())), 3)
+
+        self.assertRaises(
+            TypeError,
+            self.components.unregisterSubscriptionAdapter, required=[I1])
+        self.assertRaises(
+            TypeError,
+            self.components.unregisterSubscriptionAdapter, provided=IA2)
+        self.assertTrue(
+            self.components.unregisterSubscriptionAdapter(
+                required=[I1], provided=IA2))
+        self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 0)
+        self.assertEqual(
+            len(list(self.components.registeredSubscriptionAdapters())), 0)
+
+    def test_unregister_noncompliant_subscriber(self):
+        self.assertRaises(
+            TypeError,
+            self.components.unregisterSubscriptionAdapter, A1_12)
+        self.assertRaises(
+            TypeError,
+            self.components.unregisterSubscriptionAdapter, A)
+        self.assertRaises(
+            TypeError,
+            self.components.unregisterSubscriptionAdapter, A, required=[IA1])
+
+    def test_unregister_nonexistent_subscriber(self):
+        self.assertFalse(
+            self.components.unregisterSubscriptionAdapter(required=[I1],
+                                                          provided=IA2))
+
+class TestUtility(unittest.TestCase):
+
+    def setUp(self):
+        self.components = Components('comps')
+
+    def test_register_utility(self):
+        test_object = U1(1)
+        self.components.registerUtility(test_object)
+        self.assertEqual(self.components.getUtility(I1), test_object)
+
+    def test_register_utility_with_factory(self):
+        test_object = U1(1)
+        def factory():
+           return test_object
+        self.components.registerUtility(factory=factory)
+        self.assertEqual(self.components.getUtility(I1), test_object)
+        self.assertTrue(self.components.unregisterUtility(factory=factory))
+
+    def test_register_utility_with_component_and_factory(self):
+        def factory():
+            return U1(1)
+        self.assertRaises(
+            TypeError,
+            self.components.registerUtility, U1(1), factory=factory)
+
+    def test_unregister_utility_with_and_without_component_and_factory(self):
+        def factory():
+            return U1(1)
+        self.assertRaises(
+            TypeError,
+            self.components.unregisterUtility, U1(1), factory=factory)
+        self.assertRaises(TypeError, self.components.unregisterUtility)
+
+    def test_register_utility_with_no_interfaces(self):
+        self.assertRaises(TypeError, self.components.registerUtility, A)
+
+    def test_register_utility_with_two_interfaces(self):
+        self.assertRaises(TypeError, self.components.registerUtility, U12(1))
+
+    def test_register_utility_with_arguments(self):
+        test_object1 = U12(1)
+        test_object2 = U12(2)
+        self.components.registerUtility(test_object1, I2)
+        self.components.registerUtility(test_object2, I2, 'name')
+        self.assertEqual(self.components.getUtility(I2), test_object1)
+        self.assertEqual(self.components.getUtility(I2, 'name'), test_object2)
+
+    def test_get_none_existing_utility(self):
+        from zope.interface.interfaces import ComponentLookupError
+        self.assertRaises(ComponentLookupError, self.components.getUtility, I3)
+
+    def test_query_none_existing_utility(self):
+        self.assertTrue(self.components.queryUtility(I3) is None)
+        self.assertEqual(self.components.queryUtility(I3, default=42), 42)
+
+    def test_registered_utilities_and_sorting(self):
+        test_object1 = U1(1)
+        test_object2 = U12(2)
+        test_object3 = U12(3)
+        self.components.registerUtility(test_object1)
+        self.components.registerUtility(test_object3, I2, u'name')
+        self.components.registerUtility(test_object2, I2)
+
+        sorted_utilities = sorted(self.components.registeredUtilities())
+        sorted_utilities_name = map(lambda x: getattr(x, 'name'),
+                                    sorted_utilities)
+        sorted_utilities_component = map(lambda x: getattr(x, 'component'),
+                                         sorted_utilities)
+        sorted_utilities_provided = map(lambda x: getattr(x, 'provided'),
+                                        sorted_utilities)
+
+        self.assertEqual(len(sorted_utilities), 3)
+        self.assertEqual(sorted_utilities_name, [u'', u'', u'name'])
+        self.assertEqual(
+            sorted_utilities_component,
+            [test_object1, test_object2, test_object3])
+        self.assertEqual(sorted_utilities_provided, [I1, I2, I2])
+
+    def test_duplicate_utility(self):
+        test_object1 = U1(1)
+        test_object2 = U12(2)
+        test_object3 = U12(3)
+        test_object4 = U1(4)
+        self.components.registerUtility(test_object1)
+        self.components.registerUtility(test_object2, I2)
+        self.components.registerUtility(test_object3, I2, u'name')
+        self.assertEqual(self.components.getUtility(I1), test_object1)
+
+        self.components.registerUtility(test_object4, info=u'use 4 now')
+        self.assertEqual(self.components.getUtility(I1), test_object4)
+
+    def test_unregister_utility(self):
+        test_object = U1(1)
+        self.components.registerUtility(test_object)
+        self.assertEqual(self.components.getUtility(I1), test_object)
+        self.assertTrue(self.components.unregisterUtility(provided=I1))
+        self.assertFalse(self.components.unregisterUtility(provided=I1))
+
+    def test_unregister_utility_extended(self):
+        test_object = U1(1)
+        self.components.registerUtility(test_object)
+        self.assertFalse(self.components.unregisterUtility(U1(1)))
+        self.assertEqual(self.components.queryUtility(I1), test_object)
+        self.assertTrue(self.components.unregisterUtility(test_object))
+        self.assertTrue(self.components.queryUtility(I1) is None)
+
+    def test_get_utilities_for(self):
+        test_object1 = U1(1)
+        test_object2 = U12(2)
+        test_object3 = U12(3)
+        self.components.registerUtility(test_object1)
+        self.components.registerUtility(test_object2, I2)
+        self.components.registerUtility(test_object3, I2, u'name')
+
+        sorted_utilities = sorted(self.components.getUtilitiesFor(I2))
+        self.assertEqual(len(sorted_utilities), 2)
+        self.assertEqual(sorted_utilities[0], (u'', test_object2))
+        self.assertEqual(sorted_utilities[1], (u'name', test_object3))
+
+    def test_get_all_utilities_registered_for(self):
+        test_object1 = U1(1)
+        test_object2 = U12(2)
+        test_object3 = U12(3)
+        test_object4 = U('ext')
+        self.components.registerUtility(test_object1)
+        self.components.registerUtility(test_object2, I2)
+        self.components.registerUtility(test_object3, I2, u'name')
+        self.components.registerUtility(test_object4, I2e)
+
+        sorted_utilities = sorted(self.components.getUtilitiesFor(I2))
+        self.assertEqual(len(sorted_utilities), 2)
+        self.assertEqual(sorted_utilities[0], (u'', test_object2))
+        self.assertEqual(sorted_utilities[1], (u'name', test_object3))
+
+        all_utilities = self.components.getAllUtilitiesRegisteredFor(I2)
+        self.assertEqual(len(all_utilities), 3)
+        self.assertTrue(test_object2 in all_utilities)
+        self.assertTrue(test_object3 in all_utilities)
+        self.assertTrue(test_object4 in all_utilities)
+
+        self.assertTrue(self.components.unregisterUtility(test_object4, I2e))
+        self.assertEqual(self.components.getAllUtilitiesRegisteredFor(I2e), [])
+
+    def test_utility_events(self):
+        from zope.event import subscribers
+        old_subscribers = subscribers[:]
+        subscribers[:] = []
+
+        test_object = U1(1)
+        def log_event(event):
+            self.assertEqual(event.object.component, test_object)
+        subscribers.append(log_event)
+        self.components.registerUtility(test_object)
+
+        subscribers[:] = old_subscribers
+
+    def test_dont_leak_utility_registrations_in__subscribers(self):
+        """
+        We've observed utilities getting left in _subscribers when they
+        get unregistered.
+
+        """
+        class C:
+            def __init__(self, name):
+                self.name = name
+            def __repr__(self):
+                return "C(%s)" % self.name
+
+        c1 = C(1)
+        c2 = C(2)
+
+        self.components.registerUtility(c1, I1)
+        self.components.registerUtility(c1, I1)
+        utilities = list(self.components.getAllUtilitiesRegisteredFor(I1))
+        self.assertEqual(len(utilities), 1)
+        self.assertEqual(utilities[0], c1)
+
+        self.assertTrue(self.components.unregisterUtility(provided=I1))
+        utilities = list(self.components.getAllUtilitiesRegisteredFor(I1))
+        self.assertEqual(len(utilities), 0)
+
+        self.components.registerUtility(c1, I1)
+        self.components.registerUtility(c2, I1)
+
+        utilities = list(self.components.getAllUtilitiesRegisteredFor(I1))
+        self.assertEqual(len(utilities), 1)
+        self.assertEqual(utilities[0], c2)
+
+
+class TestExtending(unittest.TestCase):
+
+    def test_extendning(self):
+        c1 = Components('1')
+        self.assertEqual(c1.__bases__, ())
+
+        c2 = Components('2', (c1, ))
+        self.assertTrue(c2.__bases__ == (c1, ))
+
+        test_object1 = U1(1)
+        test_object2 = U1(2)
+        test_object3 = U12(1)
+        test_object4 = U12(3)
+
+        self.assertEqual(len(list(c1.registeredUtilities())), 0)
+        self.assertEqual(len(list(c2.registeredUtilities())), 0)
+
+        c1.registerUtility(test_object1)
+        self.assertEqual(len(list(c1.registeredUtilities())), 1)
+        self.assertEqual(len(list(c2.registeredUtilities())), 0)
+        self.assertEqual(c1.queryUtility(I1), test_object1)
+        self.assertEqual(c2.queryUtility(I1), test_object1)
+
+        c1.registerUtility(test_object2)
+        self.assertEqual(len(list(c1.registeredUtilities())), 1)
+        self.assertEqual(len(list(c2.registeredUtilities())), 0)
+        self.assertEqual(c1.queryUtility(I1), test_object2)
+        self.assertEqual(c2.queryUtility(I1), test_object2)
+
+
+        c3 = Components('3', (c1, ))
+        c4 = Components('4', (c2, c3))
+        self.assertEqual(c4.queryUtility(I1), test_object2)
+    
+        c1.registerUtility(test_object3, I2)
+        self.assertEqual(c4.queryUtility(I2), test_object3)
+
+        c3.registerUtility(test_object4, I2)
+        self.assertEqual(c4.queryUtility(I2), test_object4)
+
+        @adapter(I1)
+        def handle1(x):
+            self.assertEqual(x, test_object1)
+
+        def handle(*objects):
+            self.assertEqual(objects, (test_object1,))
+
+        @adapter(I1)
+        def handle3(x):
+            self.assertEqual(x, test_object1)
+
+        @adapter(I1)
+        def handle4(x):
+            self.assertEqual(x, test_object1)
+
+        c1.registerHandler(handle1, info=u'First handler')
+        c2.registerHandler(handle, required=[U])
+        c3.registerHandler(handle3)
+        c4.registerHandler(handle4)
+
+        c4.handle(test_object1)
+
+def test_suite():
+    return unittest.TestSuite((
+            unittest.makeSuite(TestUtility),
+            unittest.makeSuite(TestAdapter),
+            unittest.makeSuite(TestSubscriber),
+            unittest.makeSuite(TestHandler),
+            unittest.makeSuite(TestExtending)
+        ))
diff --git a/src/zope/interface/tests/test_sorting.py b/src/zope/interface/tests/test_sorting.py
new file mode 100644 (file)
index 0000000..af60f88
--- /dev/null
@@ -0,0 +1,55 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Test interface sorting
+"""
+
+from unittest import TestCase, TestSuite, main, makeSuite
+
+from zope.interface import Interface
+
+class I1(Interface): pass
+class I2(I1): pass
+class I3(I1): pass
+class I4(Interface): pass
+class I5(I4): pass
+class I6(I2): pass
+
+
+class Test(TestCase):
+
+    def test(self):
+        l = [I1, I3, I5, I6, I4, I2]
+        l.sort()
+        self.assertEqual(l, [I1, I2, I3, I4, I5, I6])
+
+    def test_w_None(self):
+        l = [I1, None, I3, I5, I6, I4, I2]
+        l.sort()
+        self.assertEqual(l, [I1, I2, I3, I4, I5, I6, None])
+    
+    def test_w_equal_names(self):
+        # interfaces with equal names but different modules should sort by
+        # module name
+        from zope.interface.tests.m1 import I1 as m1_I1
+        l = [I1, m1_I1]
+        l.sort()
+        self.assertEqual(l, [m1_I1, I1])
+
+def test_suite():
+    return TestSuite((
+        makeSuite(Test),
+        ))
+
+if __name__=='__main__':
+    main(defaultTest='test_suite')
diff --git a/src/zope/interface/tests/test_verify.py b/src/zope/interface/tests/test_verify.py
new file mode 100644 (file)
index 0000000..1e2282f
--- /dev/null
@@ -0,0 +1,200 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Interface Verify tests
+"""
+import doctest
+import unittest
+
+from zope.interface import Interface, implements, classImplements, Attribute
+from zope.interface.verify import verifyClass, verifyObject
+from zope.interface.exceptions import DoesNotImplement, BrokenImplementation
+from zope.interface.exceptions import BrokenMethodImplementation
+
+class Test(unittest.TestCase):
+
+    def testNotImplemented(self):
+
+        class C(object): pass
+
+        class I(Interface): pass
+
+        self.assertRaises(DoesNotImplement, verifyClass, I, C)
+
+        classImplements(C, I)
+
+        verifyClass(I, C)
+
+    def testMissingAttr(self):
+
+        class I(Interface):
+            def f(): pass
+
+        class C(object):
+            implements(I)
+
+        self.assertRaises(BrokenImplementation, verifyClass, I, C)
+
+        C.f=lambda self: None
+
+        verifyClass(I, C)
+
+    def testMissingAttr_with_Extended_Interface(self):
+
+        class II(Interface):
+            def f():
+                pass
+
+        class I(II):
+            pass
+
+        class C(object):
+            implements(I)
+
+        self.assertRaises(BrokenImplementation, verifyClass, I, C)
+
+        C.f=lambda self: None
+
+        verifyClass(I, C)
+
+    def testWrongArgs(self):
+
+        class I(Interface):
+            def f(a): pass
+
+        class C(object):
+            def f(self, b): pass
+
+            implements(I)
+
+        # We no longer require names to match.
+        #self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+        C.f=lambda self, a: None
+
+        verifyClass(I, C)
+
+        C.f=lambda self, **kw: None
+
+        self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+        C.f=lambda self, a, *args: None
+
+        verifyClass(I, C)
+
+        C.f=lambda self, a, *args, **kw: None
+
+        verifyClass(I, C)
+
+        C.f=lambda self, *args: None
+
+        verifyClass(I, C)
+
+    def testExtraArgs(self):
+
+        class I(Interface):
+            def f(a): pass
+
+        class C(object):
+            def f(self, a, b): pass
+
+            implements(I)
+
+        self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+        C.f=lambda self, a: None
+
+        verifyClass(I, C)
+
+        C.f=lambda self, a, b=None: None
+
+        verifyClass(I, C)
+
+    def testNoVar(self):
+
+        class I(Interface):
+            def f(a, *args): pass
+
+        class C(object):
+            def f(self, a): pass
+
+            implements(I)
+
+        self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+        C.f=lambda self, a, *foo: None
+
+        verifyClass(I, C)
+
+    def testNoKW(self):
+
+        class I(Interface):
+            def f(a, **args): pass
+
+        class C(object):
+            def f(self, a): pass
+
+            implements(I)
+
+        self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+        C.f=lambda self, a, **foo: None
+
+        verifyClass(I, C)
+
+    def testModule(self):
+
+        from zope.interface.tests.ifoo import IFoo
+        from zope.interface.tests import dummy
+
+        verifyObject(IFoo, dummy)
+
+    def testMethodForAttr(self):
+        
+        class IFoo(Interface):
+             foo = Attribute("The foo Attribute")
+
+
+        class Foo:
+             implements(IFoo)
+
+             def foo(self):
+                 pass
+
+        verifyClass(IFoo, Foo)
+
+    def testNonMethodForMethod(self):
+
+        class IBar(Interface):
+             def foo():
+                 pass
+
+        class Bar:
+            implements(IBar)
+
+            foo = 1
+
+        self.assertRaises(BrokenMethodImplementation, verifyClass, IBar, Bar)
+        
+
+def test_suite():
+    loader=unittest.TestLoader()
+    return unittest.TestSuite((
+        doctest.DocFileSuite(
+            '../verify.txt',
+            optionflags=doctest.NORMALIZE_WHITESPACE),
+        loader.loadTestsFromTestCase(Test),
+        ))
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run(test_suite())
diff --git a/src/zope/interface/tests/unitfixtures.py b/src/zope/interface/tests/unitfixtures.py
new file mode 100644 (file)
index 0000000..c47eaf0
--- /dev/null
@@ -0,0 +1,140 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Unit Test Fixtures
+"""
+from zope.interface import Interface, invariant
+from zope.interface.interface import Attribute
+from zope.interface.exceptions import Invalid
+
+class mytest(Interface):
+    pass
+
+class C(object):
+    def m1(self, a, b):
+        "return 1"
+        return 1
+
+    def m2(self, a, b):
+        "return 2"
+        return 2
+
+# testInstancesOfClassImplements
+
+#  YAGNI IC=Interface.impliedInterface(C)
+class IC(Interface):
+    def m1(a, b):
+        "return 1"
+
+    def m2(a, b):
+        "return 2"
+
+
+
+C.__implemented__=IC
+
+class I1(Interface):
+    def ma():
+        "blah"
+
+class I2(I1): pass
+
+class I3(Interface): pass
+
+class I4(Interface): pass
+
+class A(I1.deferred()):
+    __implemented__=I1
+
+class B(object):
+    __implemented__=I2, I3
+
+class D(A, B): pass
+
+class E(A, B):
+    __implemented__ = A.__implemented__, C.__implemented__
+
+
+class FooInterface(Interface):
+    """ This is an Abstract Base Class """
+
+    foobar = Attribute("fuzzed over beyond all recognition")
+
+    def aMethod(foo, bar, bingo):
+        """ This is aMethod """
+
+    def anotherMethod(foo=6, bar="where you get sloshed", bingo=(1,3,)):
+        """ This is anotherMethod """
+
+    def wammy(zip, *argues):
+        """ yadda yadda """
+
+    def useless(**keywords):
+        """ useless code is fun! """
+
+class Foo(object):
+    """ A concrete class """
+
+    __implemented__ = FooInterface,
+
+    foobar = "yeah"
+
+    def aMethod(self, foo, bar, bingo):
+        """ This is aMethod """
+        return "barf!"
+
+    def anotherMethod(self, foo=6, bar="where you get sloshed", bingo=(1,3,)):
+        """ This is anotherMethod """
+        return "barf!"
+
+    def wammy(self, zip, *argues):
+        """ yadda yadda """
+        return "barf!"
+
+    def useless(self, **keywords):
+        """ useless code is fun! """
+        return "barf!"
+
+foo_instance = Foo()
+
+class Blah(object):
+    pass
+
+new = Interface.__class__
+FunInterface = new('FunInterface')
+BarInterface = new('BarInterface', [FunInterface])
+BobInterface = new('BobInterface')
+BazInterface = new('BazInterface', [BobInterface, BarInterface])
+
+# fixtures for invariant tests
+def ifFooThenBar(obj):
+    if getattr(obj, 'foo', None) and not getattr(obj, 'bar', None):
+        raise Invalid('If Foo, then Bar!')
+class IInvariant(Interface):
+    foo = Attribute('foo')
+    bar = Attribute('bar; must eval to Boolean True if foo does')
+    invariant(ifFooThenBar)
+def BarGreaterThanFoo(obj):
+    foo = getattr(obj, 'foo', None)
+    bar = getattr(obj, 'bar', None)
+    if foo is not None and isinstance(foo, type(bar)):
+        # type checking should be handled elsewhere (like, say, 
+        # schema); these invariants should be intra-interface 
+        # constraints.  This is a hacky way to do it, maybe, but you
+        # get the idea
+        if not bar > foo:
+            raise Invalid('Please, Boo MUST be greater than Foo!')
+class ISubInvariant(IInvariant):
+    invariant(BarGreaterThanFoo)
+class InvariantC(object):
+    pass
diff --git a/src/zope/interface/verify.py b/src/zope/interface/verify.py
new file mode 100644 (file)
index 0000000..da60b6e
--- /dev/null
@@ -0,0 +1,115 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Verify interface implementations
+"""
+from zope.interface.exceptions import BrokenImplementation, DoesNotImplement
+from zope.interface.exceptions import BrokenMethodImplementation
+from types import FunctionType, MethodType
+from zope.interface.interface import fromMethod, fromFunction, Method
+import sys
+
+# This will be monkey-patched when running under Zope 2, so leave this
+# here:
+MethodTypes = (MethodType, )
+
+
+def _verify(iface, candidate, tentative=0, vtype=None):
+    """Verify that 'candidate' might correctly implements 'iface'.
+
+    This involves:
+
+      o Making sure the candidate defines all the necessary methods
+
+      o Making sure the methods have the correct signature
+
+      o Making sure the candidate asserts that it implements the interface
+
+    Note that this isn't the same as verifying that the class does
+    implement the interface.
+
+    If optional tentative is true, suppress the "is implemented by" test.
+    """
+
+    if vtype == 'c':
+        tester = iface.implementedBy
+    else:
+        tester = iface.providedBy
+
+    if not tentative and not tester(candidate):
+        raise DoesNotImplement(iface)
+
+    # Here the `desc` is either an `Attribute` or `Method` instance
+    for name, desc in iface.namesAndDescriptions(1):
+        try:
+            attr = getattr(candidate, name)
+        except AttributeError:
+            if (not isinstance(desc, Method)) and vtype == 'c':
+                # We can't verify non-methods on classes, since the
+                # class may provide attrs in it's __init__.
+                continue
+
+            raise BrokenImplementation(iface, name)
+
+        if not isinstance(desc, Method):
+            # If it's not a method, there's nothing else we can test
+            continue
+
+        if isinstance(attr, FunctionType):
+            if sys.version[0] == '3' and isinstance(candidate, type):
+                # This is an "unbound method" in Python 3.
+                meth = fromFunction(attr, iface, name=name, imlevel=1)
+            else:
+                # Nope, just a normal function
+                meth = fromFunction(attr, iface, name=name)
+        elif (isinstance(attr, MethodTypes)
+              and type(attr.im_func) is FunctionType):
+            meth = fromMethod(attr, iface, name)
+        else:
+            if not callable(attr):
+                raise BrokenMethodImplementation(name, "Not a method")
+            # sigh, it's callable, but we don't know how to intrspect it, so
+            # we have to give it a pass.
+            continue
+
+        # Make sure that the required and implemented method signatures are
+        # the same.
+        desc = desc.getSignatureInfo()
+        meth = meth.getSignatureInfo()
+
+        mess = _incompat(desc, meth)
+        if mess:
+            raise BrokenMethodImplementation(name, mess)
+
+    return True
+
+def verifyClass(iface, candidate, tentative=0):
+    return _verify(iface, candidate, tentative, vtype='c')
+
+def verifyObject(iface, candidate, tentative=0):
+    return _verify(iface, candidate, tentative, vtype='o')
+
+def _incompat(required, implemented):
+    #if (required['positional'] !=
+    #    implemented['positional'][:len(required['positional'])]
+    #    and implemented['kwargs'] is None):
+    #    return 'imlementation has different argument names'
+    if len(implemented['required']) > len(required['required']):
+        return 'implementation requires too many arguments'
+    if ((len(implemented['positional']) < len(required['positional']))
+        and not implemented['varargs']):
+        return "implementation doesn't allow enough arguments"
+    if required['kwargs'] and not implemented['kwargs']:
+        return "implementation doesn't support keyword arguments"
+    if required['varargs'] and not implemented['varargs']:
+        return "implementation doesn't support variable arguments"
diff --git a/src/zope/interface/verify.txt b/src/zope/interface/verify.txt
new file mode 100644 (file)
index 0000000..7eec6d2
--- /dev/null
@@ -0,0 +1,127 @@
+===================================
+Verifying interface implementations
+===================================
+
+The ``zope.interface.verify`` module provides functions that test whether a
+given interface is implemented by a class or provided by an object, resp.
+
+
+Verifying classes
+=================
+
+This is covered by unit tests defined in ``zope.interface.tests.test_verify``.
+
+
+Verifying objects
+=================
+
+An object provides an interface if
+
+- either its class declares that it implements the interfaces, or the object
+  declares that it directly provides the interface
+
+- the object defines all the methods required by the interface
+
+- all the methods have the correct signature
+
+- the object defines all non-method attributes required by the interface
+
+This doctest currently covers only the latter item.
+
+Testing for attributes
+----------------------
+
+Attributes of the object, be they defined by its class or added by its
+``__init__`` method, will be recognized:
+
+>>> from zope.interface import Interface, Attribute, implements
+>>> from zope.interface.exceptions import BrokenImplementation
+>>> class IFoo(Interface):
+...     x = Attribute("The X attribute")
+...     y = Attribute("The Y attribute")
+
+>>> class Foo(object):
+...     implements(IFoo)
+...     x = 1
+...     def __init__(self):
+...         self.y = 2
+
+>>> from zope.interface.verify import verifyObject
+>>> verifyObject(IFoo, Foo())
+True
+
+If either attribute is missing, verification will fail:
+
+>>> class Foo(object):
+...     implements(IFoo)
+...     x = 1
+
+>>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+...     verifyObject(IFoo, Foo())
+... except BrokenImplementation, e:
+...     print str(e)
+An object has failed to implement interface <InterfaceClass ...IFoo>
+<BLANKLINE>
+        The y attribute was not provided.
+<BLANKLINE>
+
+>>> class Foo(object):
+...     implements(IFoo)
+...     def __init__(self):
+...         self.y = 2
+
+>>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+...     verifyObject(IFoo, Foo())
+... except BrokenImplementation, e:
+...     print str(e)
+An object has failed to implement interface <InterfaceClass ...IFoo>
+<BLANKLINE>
+        The x attribute was not provided.
+<BLANKLINE>
+
+If an attribute is implemented as a property that raises an AttributeError
+when trying to get its value, the attribute is considered missing:
+
+>>> class IFoo(Interface):
+...     x = Attribute('The X attribute')
+
+>>> class Foo(object):
+...     implements(IFoo)
+...     @property
+...     def x(self):
+...         raise AttributeError
+
+>>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+...     verifyObject(IFoo, Foo())
+... except BrokenImplementation, e:
+...     print str(e)
+An object has failed to implement interface <InterfaceClass ...IFoo>
+<BLANKLINE>
+        The x attribute was not provided.
+<BLANKLINE>
+
+Any other exception raised by a property will propagate to the caller of
+``verifyObject``:
+
+>>> class Foo(object):
+...     implements(IFoo)
+...     @property
+...     def x(self):
+...         raise Exception
+
+>>> verifyObject(IFoo, Foo())
+Traceback (most recent call last):
+Exception
+
+Of course, broken properties that are not required by the interface don't do
+any harm:
+
+>>> class Foo(object):
+...     implements(IFoo)
+...     x = 1
+...     @property
+...     def y(self):
+...         raise Exception
+
+>>> verifyObject(IFoo, Foo())
+True
diff --git a/tox.ini b/tox.ini
new file mode 100644 (file)
index 0000000..6466e45
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,17 @@
+[tox]
+envlist = 
+    py25,py26,py27,py32,jython,pypy
+
+[testenv]
+commands = 
+    python setup.py test -q
+deps = zope.event
+
+[testenv:jython]
+commands = 
+   jython setup.py test -q
+
+[testenv:py32]
+deps = zope.event
+       zope.fixers
+