aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/zope.interface/py2
diff options
context:
space:
mode:
authorshmel1k <shmel1k@ydb.tech>2023-11-26 18:16:14 +0300
committershmel1k <shmel1k@ydb.tech>2023-11-26 18:43:30 +0300
commitb8cf9e88f4c5c64d9406af533d8948deb050d695 (patch)
tree218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/zope.interface/py2
parent523f645a83a0ec97a0332dbc3863bb354c92a328 (diff)
downloadydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz
add kikimr_configure
Diffstat (limited to 'contrib/python/zope.interface/py2')
-rw-r--r--contrib/python/zope.interface/py2/.dist-info/METADATA1094
-rw-r--r--contrib/python/zope.interface/py2/.dist-info/top_level.txt1
-rw-r--r--contrib/python/zope.interface/py2/COPYRIGHT.txt1
-rw-r--r--contrib/python/zope.interface/py2/LICENSE.txt44
-rw-r--r--contrib/python/zope.interface/py2/README.rst31
-rw-r--r--contrib/python/zope.interface/py2/ya.make61
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/__init__.py96
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/_compat.py170
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/_flatten.py35
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/_zope_interface_coptimizations.c2122
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/adapter.py1018
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/advice.py213
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/__init__.py272
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/builtins.py125
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/collections.py284
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/idatetime.py606
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/interfaces.py212
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/io.py53
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/mapping.py184
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/numbers.py84
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/common/sequence.py215
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/declarations.py1313
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/document.py124
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/exceptions.py275
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/interface.py1153
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/interfaces.py1593
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/registry.py726
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/ro.py666
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/verify.py218
29 files changed, 12989 insertions, 0 deletions
diff --git a/contrib/python/zope.interface/py2/.dist-info/METADATA b/contrib/python/zope.interface/py2/.dist-info/METADATA
new file mode 100644
index 0000000000..7f8e6998e3
--- /dev/null
+++ b/contrib/python/zope.interface/py2/.dist-info/METADATA
@@ -0,0 +1,1094 @@
+Metadata-Version: 2.1
+Name: zope.interface
+Version: 5.5.2
+Summary: Interfaces for Python
+Home-page: https://github.com/zopefoundation/zope.interface
+Author: Zope Foundation and Contributors
+Author-email: zope-dev@zope.org
+License: ZPL 2.1
+Keywords: interface,components,plugins
+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
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Framework :: Zope :: 3
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+License-File: LICENSE.txt
+Requires-Dist: setuptools
+Provides-Extra: docs
+Requires-Dist: Sphinx ; extra == 'docs'
+Requires-Dist: repoze.sphinx.autointerface ; extra == 'docs'
+Provides-Extra: test
+Requires-Dist: coverage (>=5.0.3) ; extra == 'test'
+Requires-Dist: zope.event ; extra == 'test'
+Requires-Dist: zope.testing ; extra == 'test'
+Provides-Extra: testing
+Requires-Dist: coverage (>=5.0.3) ; extra == 'testing'
+Requires-Dist: zope.event ; extra == 'testing'
+Requires-Dist: zope.testing ; extra == 'testing'
+
+====================
+ ``zope.interface``
+====================
+
+.. image:: https://img.shields.io/pypi/v/zope.interface.svg
+ :target: https://pypi.python.org/pypi/zope.interface/
+ :alt: Latest Version
+
+.. image:: https://img.shields.io/pypi/pyversions/zope.interface.svg
+ :target: https://pypi.org/project/zope.interface/
+ :alt: Supported Python versions
+
+.. image:: https://github.com/zopefoundation/zope.interface/actions/workflows/tests.yml/badge.svg
+ :target: https://github.com/zopefoundation/zope.interface/actions/workflows/tests.yml
+
+.. image:: https://readthedocs.org/projects/zopeinterface/badge/?version=latest
+ :target: https://zopeinterface.readthedocs.io/en/latest/
+ :alt: Documentation Status
+
+This package is intended to be independently reusable in any Python
+project. It is maintained by the `Zope Toolkit project
+<https://zopetoolkit.readthedocs.io/>`_.
+
+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 https://zopeinterface.readthedocs.io/en/latest/
+
+=========
+ Changes
+=========
+
+5.5.2 (2022-11-17)
+==================
+
+- Add support for building arm64 wheels on macOS.
+
+
+5.5.1 (2022-11-03)
+==================
+
+- Add support for final Python 3.11 release.
+
+
+5.5.0 (2022-10-10)
+==================
+
+- Add support for Python 3.10 and 3.11 (as of 3.11.0rc2).
+
+- Add missing Trove classifier showing support for Python 3.9.
+
+- Add some more entries to ``zope.interface.interfaces.__all__``.
+
+- Disable unsafe math optimizations in C code. See `pull request 262
+ <https://github.com/zopefoundation/zope.interface/pull/262>`_.
+
+
+5.4.0 (2021-04-15)
+==================
+
+- Make the C implementation of the ``__providedBy__`` descriptor stop
+ ignoring all errors raised when accessing the instance's
+ ``__provides__``. Now it behaves like the Python version and only
+ catches ``AttributeError``. The previous behaviour could lead to
+ crashing the interpreter in cases of recursion and errors. See
+ `issue 239 <https://github.com/zopefoundation/zope.interface/issues>`_.
+
+- Update the ``repr()`` and ``str()`` of various objects to be shorter
+ and more informative. In many cases, the ``repr()`` is now something
+ that can be evaluated to produce an equal object. For example, what
+ was previously printed as ``<implementedBy builtins.list>`` is now
+ shown as ``classImplements(list, IMutableSequence, IIterable)``. See
+ `issue 236 <https://github.com/zopefoundation/zope.interface/issues/236>`_.
+
+- Make ``Declaration.__add__`` (as in ``implementedBy(Cls) +
+ ISomething``) try harder to preserve a consistent resolution order
+ when the two arguments share overlapping pieces of the interface
+ inheritance hierarchy. Previously, the right hand side was always
+ put at the end of the resolution order, which could easily produce
+ invalid orders. See `issue 193
+ <https://github.com/zopefoundation/zope.interface/issues/193>`_.
+
+5.3.0 (2020-03-21)
+==================
+
+- No changes from 5.3.0a1
+
+
+5.3.0a1 (2021-03-18)
+====================
+
+- Improve the repr of ``zope.interface.Provides`` to remove ambiguity
+ about what is being provided. This is especially helpful diagnosing
+ IRO issues.
+
+- Allow subclasses of ``BaseAdapterRegistry`` (including
+ ``AdapterRegistry`` and ``VerifyingAdapterRegistry``) to have
+ control over the data structures. This allows persistent
+ implementations such as those based on ZODB to choose more scalable
+ options (e.g., BTrees instead of dicts). See `issue 224
+ <https://github.com/zopefoundation/zope.interface/issues/224>`_.
+
+- Fix a reference counting issue in ``BaseAdapterRegistry`` that could
+ lead to references to interfaces being kept around even when all
+ utilities/adapters/subscribers providing that interface have been
+ removed. This is mostly an issue for persistent implementations.
+ Note that this only corrects the issue moving forward, it does not
+ solve any already corrupted reference counts. See `issue 227
+ <https://github.com/zopefoundation/zope.interface/issues/227>`_.
+
+- Add the method ``BaseAdapterRegistry.rebuild()``. This can be used
+ to fix the reference counting issue mentioned above, as well as to
+ update the data structures when custom data types have changed.
+
+- Add the interface method ``IAdapterRegistry.subscribed()`` and
+ implementation ``BaseAdapterRegistry.subscribed()`` for querying
+ directly registered subscribers. See `issue 230
+ <https://github.com/zopefoundation/zope.interface/issues/230>`_.
+
+- Add the maintenance method
+ ``Components.rebuildUtilityRegistryFromLocalCache()``. Most users
+ will not need this, but it can be useful if the ``Components.utilities``
+ registry is suspected to be out of sync with the ``Components``
+ object itself (this might happen to persistent ``Components``
+ implementations in the face of bugs).
+
+- Fix the ``Provides`` and ``ClassProvides`` descriptors to stop
+ allowing redundant interfaces (those already implemented by the
+ underlying class or meta class) to produce an inconsistent
+ resolution order. This is similar to the change in ``@implementer``
+ in 5.1.0, and resolves inconsistent resolution orders with
+ ``zope.proxy`` and ``zope.location``. See `issue 207
+ <https://github.com/zopefoundation/zope.interface/issues/207>`_.
+
+5.2.0 (2020-11-05)
+==================
+
+- Add documentation section ``Persistency and Equality``
+ (`#218 <https://github.com/zopefoundation/zope.interface/issues/218>`_).
+
+- Create arm64 wheels.
+
+- Add support for Python 3.9.
+
+
+5.1.2 (2020-10-01)
+==================
+
+- Make sure to call each invariant only once when validating invariants.
+ Previously, invariants could be called multiple times because when an
+ invariant is defined in an interface, it's found by in all interfaces
+ inheriting from that interface. See `pull request 215
+ <https://github.com/zopefoundation/zope.interface/pull/215/>`_.
+
+5.1.1 (2020-09-30)
+==================
+
+- Fix the method definitions of ``IAdapterRegistry.subscribe``,
+ ``subscriptions`` and ``subscribers``. Previously, they all were
+ defined to accept a ``name`` keyword argument, but subscribers have
+ no names and the implementation of that interface did not accept
+ that argument. See `issue 208
+ <https://github.com/zopefoundation/zope.interface/issues/208>`_.
+
+- Fix a potential reference leak in the C optimizations. Previously,
+ applications that dynamically created unique ``Specification``
+ objects (e.g., used ``@implementer`` on dynamic classes) could
+ notice a growth of small objects over time leading to increased
+ garbage collection times. See `issue 216
+ <https://github.com/zopefoundation/zope.interface/issues/216>`_.
+
+ .. caution::
+
+ This leak could prevent interfaces used as the bases of
+ other interfaces from being garbage collected. Those interfaces
+ will now be collected.
+
+ One way in which this would manifest was that ``weakref.ref``
+ objects (and things built upon them, like
+ ``Weak[Key|Value]Dictionary``) would continue to have access to
+ the original object even if there were no other visible
+ references to Python and the original object *should* have been
+ collected. This could be especially problematic for the
+ ``WeakKeyDictionary`` when combined with dynamic or local
+ (created in the scope of a function) interfaces, since interfaces
+ are hashed based just on their name and module name. See the
+ linked issue for an example of a resulting ``KeyError``.
+
+ Note that such potential errors are not new, they are just once
+ again a possibility.
+
+5.1.0 (2020-04-08)
+==================
+
+- Make ``@implementer(*iface)`` and ``classImplements(cls, *iface)``
+ ignore redundant interfaces. If the class already implements an
+ interface through inheritance, it is no longer redeclared
+ specifically for *cls*. This solves many instances of inconsistent
+ resolution orders, while still allowing the interface to be declared
+ for readability and maintenance purposes. See `issue 199
+ <https://github.com/zopefoundation/zope.interface/issues/199>`_.
+
+- Remove all bare ``except:`` statements. Previously, when accessing
+ special attributes such as ``__provides__``, ``__providedBy__``,
+ ``__class__`` and ``__conform__``, this package wrapped such access
+ in a bare ``except:`` statement, meaning that many errors could pass
+ silently; typically this would result in a fallback path being taken
+ and sometimes (like with ``providedBy()``) the result would be
+ non-sensical. This is especially true when those attributes are
+ implemented with descriptors. Now, only ``AttributeError`` is
+ caught. This makes errors more obvious.
+
+ Obviously, this means that some exceptions will be propagated
+ differently than before. In particular, ``RuntimeError`` raised by
+ Acquisition in the case of circular containment will now be
+ propagated. Previously, when adapting such a broken object, a
+ ``TypeError`` would be the common result, but now it will be a more
+ informative ``RuntimeError``.
+
+ In addition, ZODB errors like ``POSKeyError`` could now be
+ propagated where previously they would ignored by this package.
+
+ See `issue 200 <https://github.com/zopefoundation/zope.interface/issues/200>`_.
+
+- Require that the second argument (*bases*) to ``InterfaceClass`` is
+ a tuple. This only matters when directly using ``InterfaceClass`` to
+ create new interfaces dynamically. Previously, an individual
+ interface was allowed, but did not work correctly. Now it is
+ consistent with ``type`` and requires a tuple.
+
+- Let interfaces define custom ``__adapt__`` methods. This implements
+ the other side of the :pep:`246` adaptation protocol: objects being
+ adapted could already implement ``__conform__`` if they know about
+ the interface, and now interfaces can implement ``__adapt__`` if
+ they know about particular objects. There is no performance penalty
+ for interfaces that do not supply custom ``__adapt__`` methods.
+
+ This includes the ability to add new methods, or override existing
+ interface methods using the new ``@interfacemethod`` decorator.
+
+ See `issue 3 <https://github.com/zopefoundation/zope.interface/issues/3>`_.
+
+- Make the internal singleton object returned by APIs like
+ ``implementedBy`` and ``directlyProvidedBy`` for objects that
+ implement or provide no interfaces more immutable. Previously an
+ internal cache could be mutated. See `issue 204
+ <https://github.com/zopefoundation/zope.interface/issues/204>`_.
+
+5.0.2 (2020-03-30)
+==================
+
+- Ensure that objects that implement no interfaces (such as direct
+ subclasses of ``object``) still include ``Interface`` itself in
+ their ``__iro___`` and ``__sro___``. This fixes adapter registry
+ lookups for such objects when the adapter is registered for
+ ``Interface``. See `issue 197
+ <https://github.com/zopefoundation/zope.interface/issues/197>`_.
+
+
+5.0.1 (2020-03-21)
+==================
+
+- Ensure the resolution order for ``InterfaceClass`` is consistent.
+ See `issue 192 <https://github.com/zopefoundation/zope.interface/issues/192>`_.
+
+- Ensure the resolution order for ``collections.OrderedDict`` is
+ consistent on CPython 2. (It was already consistent on Python 3 and PyPy).
+
+- Fix the handling of the ``ZOPE_INTERFACE_STRICT_IRO`` environment
+ variable. Previously, ``ZOPE_INTERFACE_STRICT_RO`` was read, in
+ contrast with the documentation. See `issue 194
+ <https://github.com/zopefoundation/zope.interface/issues/194>`_.
+
+
+5.0.0 (2020-03-19)
+==================
+
+- Make an internal singleton object returned by APIs like
+ ``implementedBy`` and ``directlyProvidedBy`` immutable. Previously,
+ it was fully mutable and allowed changing its ``__bases___``. That
+ could potentially lead to wrong results in pathological corner
+ cases. See `issue 158
+ <https://github.com/zopefoundation/zope.interface/issues/158>`_.
+
+- Support the ``PURE_PYTHON`` environment variable at runtime instead
+ of just at wheel build time. A value of 0 forces the C extensions to
+ be used (even on PyPy) failing if they aren't present. Any other
+ value forces the Python implementation to be used, ignoring the C
+ extensions. See `PR 151 <https://github.com/zopefoundation/zope.interface/pull/151>`_.
+
+- Cache the result of ``__hash__`` method in ``InterfaceClass`` as a
+ speed optimization. The method is called very often (i.e several
+ hundred thousand times during Plone 5.2 startup). Because the hash value never
+ changes it can be cached. This improves test performance from 0.614s
+ down to 0.575s (1.07x faster). In a real world Plone case a reindex
+ index came down from 402s to 320s (1.26x faster). See `PR 156
+ <https://github.com/zopefoundation/zope.interface/pull/156>`_.
+
+- Change the C classes ``SpecificationBase`` and its subclass
+ ``ClassProvidesBase`` to store implementation attributes in their structures
+ instead of their instance dictionaries. This eliminates the use of
+ an undocumented private C API function, and helps make some
+ instances require less memory. See `PR 154 <https://github.com/zopefoundation/zope.interface/pull/154>`_.
+
+- Reduce memory usage in other ways based on observations of usage
+ patterns in Zope (3) and Plone code bases.
+
+ - Specifications with no dependents are common (more than 50%) so
+ avoid allocating a ``WeakKeyDictionary`` unless we need it.
+ - Likewise, tagged values are relatively rare, so don't allocate a
+ dictionary to hold them until they are used.
+ - Use ``__slots___`` or the C equivalent ``tp_members`` in more
+ common places. Note that this removes the ability to set arbitrary
+ instance variables on certain objects.
+ See `PR 155 <https://github.com/zopefoundation/zope.interface/pull/155>`_.
+
+ The changes in this release resulted in a 7% memory reduction after
+ loading about 6,000 modules that define about 2,200 interfaces.
+
+ .. caution::
+
+ Details of many private attributes have changed, and external use
+ of those private attributes may break. In particular, the
+ lifetime and default value of ``_v_attrs`` has changed.
+
+- Remove support for hashing uninitialized interfaces. This could only
+ be done by subclassing ``InterfaceClass``. This has generated a
+ warning since it was first added in 2011 (3.6.5). Please call the
+ ``InterfaceClass`` constructor or otherwise set the appropriate
+ fields in your subclass before attempting to hash or sort it. See
+ `issue 157 <https://github.com/zopefoundation/zope.interface/issues/157>`_.
+
+- Remove unneeded override of the ``__hash__`` method from
+ ``zope.interface.declarations.Implements``. Watching a reindex index
+ process in ZCatalog with on a Py-Spy after 10k samples the time for
+ ``.adapter._lookup`` was reduced from 27.5s to 18.8s (~1.5x faster).
+ Overall reindex index time shrunk from 369s to 293s (1.26x faster).
+ See `PR 161
+ <https://github.com/zopefoundation/zope.interface/pull/161>`_.
+
+- Make the Python implementation closer to the C implementation by
+ ignoring all exceptions, not just ``AttributeError``, during (parts
+ of) interface adaptation. See `issue 163
+ <https://github.com/zopefoundation/zope.interface/issues/163>`_.
+
+- Micro-optimization in ``.adapter._lookup`` , ``.adapter._lookupAll``
+ and ``.adapter._subscriptions``: By loading ``components.get`` into
+ a local variable before entering the loop a bytcode "LOAD_FAST 0
+ (components)" in the loop can be eliminated. In Plone, while running
+ all tests, average speedup of the "owntime" of ``_lookup`` is ~5x.
+ See `PR 167
+ <https://github.com/zopefoundation/zope.interface/pull/167>`_.
+
+- Add ``__all__`` declarations to all modules. This helps tools that
+ do auto-completion and documentation and results in less cluttered
+ results. Wildcard ("*") are not recommended and may be affected. See
+ `issue 153
+ <https://github.com/zopefoundation/zope.interface/issues/153>`_.
+
+- Fix ``verifyClass`` and ``verifyObject`` for builtin types like
+ ``dict`` that have methods taking an optional, unnamed argument with
+ no default value like ``dict.pop``. On PyPy3, the verification is
+ strict, but on PyPy2 (as on all versions of CPython) those methods
+ cannot be verified and are ignored. See `issue 118
+ <https://github.com/zopefoundation/zope.interface/issues/118>`_.
+
+- Update the common interfaces ``IEnumerableMapping``,
+ ``IExtendedReadMapping``, ``IExtendedWriteMapping``,
+ ``IReadSequence`` and ``IUniqueMemberWriteSequence`` to no longer
+ require methods that were removed from Python 3 on Python 3, such as
+ ``__setslice___``. Now, ``dict``, ``list`` and ``tuple`` properly
+ verify as ``IFullMapping``, ``ISequence`` and ``IReadSequence,``
+ respectively on all versions of Python.
+
+- Add human-readable ``__str___`` and ``__repr___`` to ``Attribute``
+ and ``Method``. These contain the name of the defining interface
+ and the attribute. For methods, it also includes the signature.
+
+- Change the error strings raised by ``verifyObject`` and
+ ``verifyClass``. They now include more human-readable information
+ and exclude extraneous lines and spaces. See `issue 170
+ <https://github.com/zopefoundation/zope.interface/issues/170>`_.
+
+ .. caution:: This will break consumers (such as doctests) that
+ depended on the exact error messages.
+
+- Make ``verifyObject`` and ``verifyClass`` report all errors, if the
+ candidate object has multiple detectable violations. Previously they
+ reported only the first error. See `issue
+ <https://github.com/zopefoundation/zope.interface/issues/171>`_.
+
+ Like the above, this will break consumers depending on the exact
+ output of error messages if more than one error is present.
+
+- Add ``zope.interface.common.collections``,
+ ``zope.interface.common.numbers``, and ``zope.interface.common.io``.
+ These modules define interfaces based on the ABCs defined in the
+ standard library ``collections.abc``, ``numbers`` and ``io``
+ modules, respectively. Importing these modules will make the
+ standard library concrete classes that are registered with those
+ ABCs declare the appropriate interface. See `issue 138
+ <https://github.com/zopefoundation/zope.interface/issues/138>`_.
+
+- Add ``zope.interface.common.builtins``. This module defines
+ interfaces of common builtin types, such as ``ITextString`` and
+ ``IByteString``, ``IDict``, etc. These interfaces extend the
+ appropriate interfaces from ``collections`` and ``numbers``, and the
+ standard library classes implement them after importing this module.
+ This is intended as a replacement for third-party packages like
+ `dolmen.builtins <https://pypi.org/project/dolmen.builtins/>`_.
+ See `issue 138 <https://github.com/zopefoundation/zope.interface/issues/138>`_.
+
+- Make ``providedBy()`` and ``implementedBy()`` respect ``super``
+ objects. For instance, if class ``Derived`` implements ``IDerived``
+ and extends ``Base`` which in turn implements ``IBase``, then
+ ``providedBy(super(Derived, derived))`` will return ``[IBase]``.
+ Previously it would have returned ``[IDerived]`` (in general, it
+ would previously have returned whatever would have been returned
+ without ``super``).
+
+ Along with this change, adapter registries will unpack ``super``
+ objects into their ``__self___`` before passing it to the factory.
+ Together, this means that ``component.getAdapter(super(Derived,
+ self), ITarget)`` is now meaningful.
+
+ See `issue 11 <https://github.com/zopefoundation/zope.interface/issues/11>`_.
+
+- Fix a potential interpreter crash in the low-level adapter
+ registry lookup functions. See issue 11.
+
+- Adopt Python's standard `C3 resolution order
+ <https://www.python.org/download/releases/2.3/mro/>`_ to compute the
+ ``__iro__`` and ``__sro__`` of interfaces, with tweaks to support
+ additional cases that are common in interfaces but disallowed for
+ Python classes. Previously, an ad-hoc ordering that made no
+ particular guarantees was used.
+
+ This has many beneficial properties, including the fact that base
+ interface and base classes tend to appear near the end of the
+ resolution order instead of the beginning. The resolution order in
+ general should be more predictable and consistent.
+
+ .. caution::
+ In some cases, especially with complex interface inheritance
+ trees or when manually providing or implementing interfaces, the
+ resulting IRO may be quite different. This may affect adapter
+ lookup.
+
+ The C3 order enforces some constraints in order to be able to
+ guarantee a sensible ordering. Older versions of zope.interface did
+ not impose similar constraints, so it was possible to create
+ interfaces and declarations that are inconsistent with the C3
+ constraints. In that event, zope.interface will still produce a
+ resolution order equal to the old order, but it won't be guaranteed
+ to be fully C3 compliant. In the future, strict enforcement of C3
+ order may be the default.
+
+ A set of environment variables and module constants allows
+ controlling several aspects of this new behaviour. It is possible to
+ request warnings about inconsistent resolution orders encountered,
+ and even to forbid them. Differences between the C3 resolution order
+ and the previous order can be logged, and, in extreme cases, the
+ previous order can still be used (this ability will be removed in
+ the future). For details, see the documentation for
+ ``zope.interface.ro``.
+
+- Make inherited tagged values in interfaces respect the resolution
+ order (``__iro__``), as method and attribute lookup does. Previously
+ tagged values could give inconsistent results. See `issue 190
+ <https://github.com/zopefoundation/zope.interface/issues/190>`_.
+
+- Add ``getDirectTaggedValue`` (and related methods) to interfaces to
+ allow accessing tagged values irrespective of inheritance. See
+ `issue 190
+ <https://github.com/zopefoundation/zope.interface/issues/190>`_.
+
+- Ensure that ``Interface`` is always the last item in the ``__iro__``
+ and ``__sro__``. This is usually the case, but if classes that do
+ not implement any interfaces are part of a class inheritance
+ hierarchy, ``Interface`` could be assigned too high a priority.
+ See `issue 8 <https://github.com/zopefoundation/zope.interface/issues/8>`_.
+
+- Implement sorting, equality, and hashing in C for ``Interface``
+ objects. In micro benchmarks, this makes those operations 40% to 80%
+ faster. This translates to a 20% speed up in querying adapters.
+
+ Note that this changes certain implementation details. In
+ particular, ``InterfaceClass`` now has a non-default metaclass, and
+ it is enforced that ``__module__`` in instances of
+ ``InterfaceClass`` is read-only.
+
+ See `PR 183 <https://github.com/zopefoundation/zope.interface/pull/183>`_.
+
+
+4.7.2 (2020-03-10)
+==================
+
+- Remove deprecated use of setuptools features. See `issue 30
+ <https://github.com/zopefoundation/zope.interface/issues/30>`_.
+
+
+4.7.1 (2019-11-11)
+==================
+
+- Use Python 3 syntax in the documentation. See `issue 119
+ <https://github.com/zopefoundation/zope.interface/issues/119>`_.
+
+
+4.7.0 (2019-11-11)
+==================
+
+- Drop support for Python 3.4.
+
+- Change ``queryTaggedValue``, ``getTaggedValue``,
+ ``getTaggedValueTags`` in interfaces. They now include inherited
+ values by following ``__bases__``. See `PR 144
+ <https://github.com/zopefoundation/zope.interface/pull/144>`_.
+
+ .. caution:: This may be a breaking change.
+
+- Add support for Python 3.8.
+
+
+4.6.0 (2018-10-23)
+==================
+
+- Add support for Python 3.7
+
+- Fix ``verifyObject`` for class objects with staticmethods on
+ Python 3. See `issue 126
+ <https://github.com/zopefoundation/zope.interface/issues/126>`_.
+
+
+4.5.0 (2018-04-19)
+==================
+
+- Drop support for 3.3, avoid accidental dependence breakage via setup.py.
+ See `PR 110 <https://github.com/zopefoundation/zope.interface/pull/110>`_.
+- Allow registering and unregistering instance methods as listeners.
+ See `issue 12 <https://github.com/zopefoundation/zope.interface/issues/12>`_
+ and `PR 102 <https://github.com/zopefoundation/zope.interface/pull/102>`_.
+- Synchronize and simplify zope/__init__.py. See `issue 114
+ <https://github.com/zopefoundation/zope.interface/issues/114>`_
+
+
+4.4.3 (2017-09-22)
+==================
+
+- Avoid exceptions when the ``__annotations__`` attribute is added to
+ interface definitions with Python 3.x type hints. See `issue 98
+ <https://github.com/zopefoundation/zope.interface/issues/98>`_.
+- Fix the possibility of a rare crash in the C extension when
+ deallocating items. See `issue 100
+ <https://github.com/zopefoundation/zope.interface/issues/100>`_.
+
+
+4.4.2 (2017-06-14)
+==================
+
+- Fix a regression storing
+ ``zope.component.persistentregistry.PersistentRegistry`` instances.
+ See `issue 85 <https://github.com/zopefoundation/zope.interface/issues/85>`_.
+
+- Fix a regression that could lead to the utility registration cache
+ of ``Components`` getting out of sync. See `issue 93
+ <https://github.com/zopefoundation/zope.interface/issues/93>`_.
+
+4.4.1 (2017-05-13)
+==================
+
+- Simplify the caching of utility-registration data. In addition to
+ simplification, avoids spurious test failures when checking for
+ leaks in tests with persistent registries. See `pull 84
+ <https://github.com/zopefoundation/zope.interface/pull/84>`_.
+
+- Raise ``ValueError`` when non-text names are passed to adapter registry
+ methods: prevents corruption of lookup caches.
+
+4.4.0 (2017-04-21)
+==================
+
+- Avoid a warning from the C compiler.
+ (https://github.com/zopefoundation/zope.interface/issues/71)
+
+- Add support for Python 3.6.
+
+4.3.3 (2016-12-13)
+==================
+
+- Correct typos and ReST formatting errors in documentation.
+
+- Add API documentation for the adapter registry.
+
+- Ensure that the ``LICENSE.txt`` file is included in built wheels.
+
+- Fix C optimizations broken on Py3k. See the Python bug at:
+ http://bugs.python.org/issue15657
+ (https://github.com/zopefoundation/zope.interface/issues/60)
+
+
+4.3.2 (2016-09-05)
+==================
+
+- Fix equality testing of ``implementedBy`` objects and proxies.
+ (https://github.com/zopefoundation/zope.interface/issues/55)
+
+
+4.3.1 (2016-08-31)
+==================
+
+- Support Components subclasses that are not hashable.
+ (https://github.com/zopefoundation/zope.interface/issues/53)
+
+
+4.3.0 (2016-08-31)
+==================
+
+- Add the ability to sort the objects returned by ``implementedBy``.
+ This is compatible with the way interface classes sort so they can
+ be used together in ordered containers like BTrees.
+ (https://github.com/zopefoundation/zope.interface/issues/42)
+
+- Make ``setuptools`` a hard dependency of ``setup.py``.
+ (https://github.com/zopefoundation/zope.interface/issues/13)
+
+- Change a linear algorithm (O(n)) in ``Components.registerUtility`` and
+ ``Components.unregisterUtility`` into a dictionary lookup (O(1)) for
+ hashable components. This substantially improves the time taken to
+ manipulate utilities in large registries at the cost of some
+ additional memory usage. (https://github.com/zopefoundation/zope.interface/issues/46)
+
+
+4.2.0 (2016-06-10)
+==================
+
+- Add support for Python 3.5
+
+- Drop support for Python 2.6 and 3.2.
+
+
+4.1.3 (2015-10-05)
+==================
+
+- Fix installation without a C compiler on Python 3.5
+ (https://github.com/zopefoundation/zope.interface/issues/24).
+
+
+4.1.2 (2014-12-27)
+==================
+
+- Add support for PyPy3.
+
+- Remove unittest assertions deprecated in Python3.x.
+
+- Add ``zope.interface.document.asReStructuredText``, which formats the
+ generated text for an interface using ReST double-backtick markers.
+
+
+4.1.1 (2014-03-19)
+==================
+
+- Add support for Python 3.4.
+
+
+4.1.0 (2014-02-05)
+==================
+
+- Update ``boostrap.py`` to version 2.2.
+
+- Add ``@named(name)`` declaration, that specifies the component name, so it
+ does not have to be passed in during registration.
+
+
+4.0.5 (2013-02-28)
+==================
+
+- Fix a bug where a decorated method caused false positive failures on
+ ``verifyClass()``.
+
+
+4.0.4 (2013-02-21)
+==================
+
+- Fix a bug that was revealed by porting zope.traversing. During a loop, the
+ loop body modified a weakref dict causing a ``RuntimeError`` error.
+
+4.0.3 (2012-12-31)
+==================
+
+- Fleshed out PyPI Trove classifiers.
+
+4.0.2 (2012-11-21)
+==================
+
+- Add support for Python 3.3.
+
+- Restored ability to install the package in the absence of ``setuptools``.
+
+- LP #1055223: Fix test which depended on dictionary order and failed randomly
+ in Python 3.3.
+
+4.0.1 (2012-05-22)
+==================
+
+- Drop explicit ``DeprecationWarnings`` for "class advice" APIS (these
+ APIs are still deprecated under Python 2.x, and still raise an exception
+ under Python 3.x, but no longer cause a warning to be emitted under
+ Python 2.x).
+
+4.0.0 (2012-05-16)
+==================
+
+- Automated build of Sphinx HTML docs and running doctest snippets via tox.
+
+- Deprecate the "class advice" APIs from ``zope.interface.declarations``:
+ ``implements``, ``implementsOnly``, and ``classProvides``. In their place,
+ prefer the equivalent class decorators: ``@implementer``,
+ ``@implementer_only``, and ``@provider``. Code which uses the deprecated
+ APIs will not work as expected under Py3k.
+
+- Remove use of '2to3' and associated fixers when installing under Py3k.
+ The code is now in a "compatible subset" which supports Python 2.6, 2.7,
+ and 3.2, including PyPy 1.8 (the version compatible with the 2.7 language
+ spec).
+
+- Drop explicit support for Python 2.4 / 2.5 / 3.1.
+
+- Add support for PyPy.
+
+- Add support for continuous integration using ``tox`` and ``jenkins``.
+
+- Add 'setup.py dev' alias (runs ``setup.py develop`` plus installs
+ ``nose`` and ``coverage``).
+
+- Add 'setup.py docs' alias (installs ``Sphinx`` and dependencies).
+
+- Replace all unittest coverage previously accomplished via doctests with
+ unittests. The doctests have been moved into a ``docs`` section, managed
+ as a Sphinx collection.
+
+- LP #910987: Ensure that the semantics of the ``lookup`` method of
+ ``zope.interface.adapter.LookupBase`` are the same in both the C and
+ Python implementations.
+
+- LP #900906: Avoid exceptions due to tne new ``__qualname__`` attribute
+ added in Python 3.3 (see PEP 3155 for rationale). Thanks to Antoine
+ Pitrou for the patch.
+
+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.
+
+- Fix 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.
+
+- Add 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::
+
+ @implementer(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)
+==================
+
+- Fix 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__.
+
+- Add optional code optimizations support, which allows the building
+ of C code optimizations to fail (Jython).
+
+- Replace `_flatten` with a non-recursive implementation, effectively making
+ it 3x faster.
+
+
+3.4.1 (2007-10-02)
+==================
+
+- Fix 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)
+====================
+
+
+- When checking whether an object is already registered, use identity
+ comparison, to allow adding registering with picky custom comparison methods.
+
+
+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
+------------
+
+- Refactor the adapter-lookup algorithim to make it much simpler and faster.
+
+ Also, implement more of the adapter-lookup logic in C, making
+ debugging of application code easier, since there is less
+ infrastructre code to step through.
+
+- Treat objects without interface declarations as if they
+ declared that they provide ``zope.interface.Interface``.
+
+- Add a number of richer new adapter-registration interfaces
+ that provide greater control and introspection.
+
+- Add 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 version of the zope.interface package shipped as part of
+ the Zope 3.2.0 release.
+
+
+3.1.0 (2005-10-03)
+==================
+
+- Corresponds to the version 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.
+
+- Deprecate 'isImplementedBy' and 'isImplementedByInstancesOf' APIs in
+ favor of 'implementedBy' and 'providedBy'.
+
+
+3.0.1 (2005-07-27)
+==================
+
+- Corresponds to the version of the zope.interface package shipped as part of
+ the Zope X3.0.1 release.
+
+- Fix 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 version of the zope.interface package shipped as part of
+ the Zope X3.0.0 release.
diff --git a/contrib/python/zope.interface/py2/.dist-info/top_level.txt b/contrib/python/zope.interface/py2/.dist-info/top_level.txt
new file mode 100644
index 0000000000..66179d4985
--- /dev/null
+++ b/contrib/python/zope.interface/py2/.dist-info/top_level.txt
@@ -0,0 +1 @@
+zope
diff --git a/contrib/python/zope.interface/py2/COPYRIGHT.txt b/contrib/python/zope.interface/py2/COPYRIGHT.txt
new file mode 100644
index 0000000000..79859e0601
--- /dev/null
+++ b/contrib/python/zope.interface/py2/COPYRIGHT.txt
@@ -0,0 +1 @@
+Zope Foundation and Contributors \ No newline at end of file
diff --git a/contrib/python/zope.interface/py2/LICENSE.txt b/contrib/python/zope.interface/py2/LICENSE.txt
new file mode 100644
index 0000000000..e1f9ad7b3b
--- /dev/null
+++ b/contrib/python/zope.interface/py2/LICENSE.txt
@@ -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/contrib/python/zope.interface/py2/README.rst b/contrib/python/zope.interface/py2/README.rst
new file mode 100644
index 0000000000..e8a18e905d
--- /dev/null
+++ b/contrib/python/zope.interface/py2/README.rst
@@ -0,0 +1,31 @@
+====================
+ ``zope.interface``
+====================
+
+.. image:: https://img.shields.io/pypi/v/zope.interface.svg
+ :target: https://pypi.python.org/pypi/zope.interface/
+ :alt: Latest Version
+
+.. image:: https://img.shields.io/pypi/pyversions/zope.interface.svg
+ :target: https://pypi.org/project/zope.interface/
+ :alt: Supported Python versions
+
+.. image:: https://github.com/zopefoundation/zope.interface/actions/workflows/tests.yml/badge.svg
+ :target: https://github.com/zopefoundation/zope.interface/actions/workflows/tests.yml
+
+.. image:: https://readthedocs.org/projects/zopeinterface/badge/?version=latest
+ :target: https://zopeinterface.readthedocs.io/en/latest/
+ :alt: Documentation Status
+
+This package is intended to be independently reusable in any Python
+project. It is maintained by the `Zope Toolkit project
+<https://zopetoolkit.readthedocs.io/>`_.
+
+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 https://zopeinterface.readthedocs.io/en/latest/
diff --git a/contrib/python/zope.interface/py2/ya.make b/contrib/python/zope.interface/py2/ya.make
new file mode 100644
index 0000000000..70358bd290
--- /dev/null
+++ b/contrib/python/zope.interface/py2/ya.make
@@ -0,0 +1,61 @@
+# Generated by devtools/yamaker (pypi).
+
+PY2_LIBRARY()
+
+VERSION(5.5.2)
+
+LICENSE(ZPL-2.1)
+
+PEERDIR(
+ contrib/python/setuptools
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_LINT()
+
+SRCS(
+ zope/interface/_zope_interface_coptimizations.c
+)
+
+PY_REGISTER(
+ zope.interface._zope_interface_coptimizations
+)
+
+PY_SRCS(
+ TOP_LEVEL
+ zope/interface/__init__.py
+ zope/interface/_compat.py
+ zope/interface/_flatten.py
+ zope/interface/adapter.py
+ zope/interface/advice.py
+ zope/interface/common/__init__.py
+ zope/interface/common/builtins.py
+ zope/interface/common/collections.py
+ zope/interface/common/idatetime.py
+ zope/interface/common/interfaces.py
+ zope/interface/common/io.py
+ zope/interface/common/mapping.py
+ zope/interface/common/numbers.py
+ zope/interface/common/sequence.py
+ zope/interface/declarations.py
+ zope/interface/document.py
+ zope/interface/exceptions.py
+ zope/interface/interface.py
+ zope/interface/interfaces.py
+ zope/interface/registry.py
+ zope/interface/ro.py
+ zope/interface/verify.py
+)
+
+RESOURCE_FILES(
+ PREFIX contrib/python/zope.interface/py2/
+ .dist-info/METADATA
+ .dist-info/top_level.txt
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ tests
+)
diff --git a/contrib/python/zope.interface/py2/zope/interface/__init__.py b/contrib/python/zope.interface/py2/zope/interface/__init__.py
new file mode 100644
index 0000000000..3372103e61
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/__init__.py
@@ -0,0 +1,96 @@
+##############################################################################
+#
+# 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'
+# pylint:disable=wrong-import-position,unused-import
+from zope.interface.interface import Interface
+from zope.interface.interface import _wire
+
+# Need to actually get the interface elements to implement the right interfaces
+_wire()
+del _wire
+
+from zope.interface.declarations import Declaration
+from zope.interface.declarations import alsoProvides
+from zope.interface.declarations import classImplements
+from zope.interface.declarations import classImplementsFirst
+from zope.interface.declarations import classImplementsOnly
+from zope.interface.declarations import classProvides
+from zope.interface.declarations import directlyProvidedBy
+from zope.interface.declarations import directlyProvides
+from zope.interface.declarations import implementedBy
+from zope.interface.declarations import implementer
+from zope.interface.declarations import implementer_only
+from zope.interface.declarations import implements
+from zope.interface.declarations import implementsOnly
+from zope.interface.declarations import moduleProvides
+from zope.interface.declarations import named
+from zope.interface.declarations import noLongerProvides
+from zope.interface.declarations import providedBy
+from zope.interface.declarations import provider
+
+from zope.interface.exceptions import Invalid
+
+from zope.interface.interface import Attribute
+from zope.interface.interface import interfacemethod
+from zope.interface.interface import invariant
+from zope.interface.interface import taggedValue
+
+# 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)
+
+assert all(k in globals() for k in __all__)
diff --git a/contrib/python/zope.interface/py2/zope/interface/_compat.py b/contrib/python/zope.interface/py2/zope/interface/_compat.py
new file mode 100644
index 0000000000..3587463c43
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/_compat.py
@@ -0,0 +1,170 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""
+Support functions for dealing with differences in platforms, including Python
+versions and implementations.
+
+This file should have no imports from the rest of zope.interface because it is
+used during early bootstrapping.
+"""
+import os
+import sys
+import types
+
+if sys.version_info[0] < 3:
+
+ def _normalize_name(name):
+ if isinstance(name, basestring):
+ return unicode(name)
+ raise TypeError("name must be a regular or unicode string")
+
+ CLASS_TYPES = (type, types.ClassType)
+ STRING_TYPES = (basestring,)
+
+ _BUILTINS = '__builtin__'
+
+ PYTHON3 = False
+ PYTHON2 = True
+
+else:
+
+ def _normalize_name(name):
+ if isinstance(name, bytes):
+ name = str(name, 'ascii')
+ if isinstance(name, str):
+ return name
+ raise TypeError("name must be a string or ASCII-only bytes")
+
+ CLASS_TYPES = (type,)
+ STRING_TYPES = (str,)
+
+ _BUILTINS = 'builtins'
+
+ PYTHON3 = True
+ PYTHON2 = False
+
+PYPY = hasattr(sys, 'pypy_version_info')
+PYPY2 = PYTHON2 and PYPY
+
+def _skip_under_py3k(test_method):
+ import unittest
+ return unittest.skipIf(sys.version_info[0] >= 3, "Only on Python 2")(test_method)
+
+
+def _skip_under_py2(test_method):
+ import unittest
+ return unittest.skipIf(sys.version_info[0] < 3, "Only on Python 3")(test_method)
+
+
+def _c_optimizations_required():
+ """
+ Return a true value if the C optimizations are required.
+
+ This uses the ``PURE_PYTHON`` variable as documented in `_use_c_impl`.
+ """
+ pure_env = os.environ.get('PURE_PYTHON')
+ require_c = pure_env == "0"
+ return require_c
+
+
+def _c_optimizations_available():
+ """
+ Return the C optimization module, if available, otherwise
+ a false value.
+
+ If the optimizations are required but not available, this
+ raises the ImportError.
+
+ This does not say whether they should be used or not.
+ """
+ catch = () if _c_optimizations_required() else (ImportError,)
+ try:
+ from zope.interface import _zope_interface_coptimizations as c_opt
+ return c_opt
+ except catch: # pragma: no cover (only Jython doesn't build extensions)
+ return False
+
+
+def _c_optimizations_ignored():
+ """
+ The opposite of `_c_optimizations_required`.
+ """
+ pure_env = os.environ.get('PURE_PYTHON')
+ return pure_env is not None and pure_env != "0"
+
+
+def _should_attempt_c_optimizations():
+ """
+ Return a true value if we should attempt to use the C optimizations.
+
+ This takes into account whether we're on PyPy and the value of the
+ ``PURE_PYTHON`` environment variable, as defined in `_use_c_impl`.
+ """
+ is_pypy = hasattr(sys, 'pypy_version_info')
+
+ if _c_optimizations_required():
+ return True
+ if is_pypy:
+ return False
+ return not _c_optimizations_ignored()
+
+
+def _use_c_impl(py_impl, name=None, globs=None):
+ """
+ Decorator. Given an object implemented in Python, with a name like
+ ``Foo``, import the corresponding C implementation from
+ ``zope.interface._zope_interface_coptimizations`` with the name
+ ``Foo`` and use it instead.
+
+ If the ``PURE_PYTHON`` environment variable is set to any value
+ other than ``"0"``, or we're on PyPy, ignore the C implementation
+ and return the Python version. If the C implementation cannot be
+ imported, return the Python version. If ``PURE_PYTHON`` is set to
+ 0, *require* the C implementation (let the ImportError propagate);
+ note that PyPy can import the C implementation in this case (and all
+ tests pass).
+
+ In all cases, the Python version is kept available. in the module
+ globals with the name ``FooPy`` and the name ``FooFallback`` (both
+ conventions have been used; the C implementation of some functions
+ looks for the ``Fallback`` version, as do some of the Sphinx
+ documents).
+
+ Example::
+
+ @_use_c_impl
+ class Foo(object):
+ ...
+ """
+ name = name or py_impl.__name__
+ globs = globs or sys._getframe(1).f_globals
+
+ def find_impl():
+ if not _should_attempt_c_optimizations():
+ return py_impl
+
+ c_opt = _c_optimizations_available()
+ if not c_opt: # pragma: no cover (only Jython doesn't build extensions)
+ return py_impl
+
+ __traceback_info__ = c_opt
+ return getattr(c_opt, name)
+
+ c_impl = find_impl()
+ # Always make available by the FooPy name and FooFallback
+ # name (for testing and documentation)
+ globs[name + 'Py'] = py_impl
+ globs[name + 'Fallback'] = py_impl
+
+ return c_impl
diff --git a/contrib/python/zope.interface/py2/zope/interface/_flatten.py b/contrib/python/zope.interface/py2/zope/interface/_flatten.py
new file mode 100644
index 0000000000..a80c2de49a
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/_flatten.py
@@ -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/contrib/python/zope.interface/py2/zope/interface/_zope_interface_coptimizations.c b/contrib/python/zope.interface/py2/zope/interface/_zope_interface_coptimizations.c
new file mode 100644
index 0000000000..af52a0aa73
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/_zope_interface_coptimizations.c
@@ -0,0 +1,2122 @@
+/*###########################################################################
+ #
+ # 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"
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+#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
+
+#if PY_MAJOR_VERSION >= 3
+#define PY3K
+#define PyNative_FromString PyUnicode_FromString
+#else
+#define PyNative_FromString PyString_FromString
+#endif
+
+static PyObject *str__dict__, *str__implemented__, *strextends;
+static PyObject *BuiltinImplementationSpecifications, *str__provides__;
+static PyObject *str__class__, *str__providedBy__;
+static PyObject *empty, *fallback;
+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 PyObject *str__self__;
+static PyObject *str__module__;
+static PyObject *str__name__;
+static PyObject *str__adapt__;
+static PyObject *str_CALL_CUSTOM_ADAPT;
+
+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 SpecificationBaseType; /* 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 (PyObject_TypeCheck(cls, &PySuper_Type))
+ {
+ // Let merging be handled by Python.
+ return implementedByFallback(cls);
+ }
+
+ 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)
+ {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ {
+ /* Propagate non AttributeError exceptions. */
+ return NULL;
+ }
+ PyErr_Clear();
+ }
+ else
+ {
+ int is_instance = -1;
+ is_instance = PyObject_IsInstance(result, (PyObject*)&SpecificationBaseType);
+ if (is_instance < 0)
+ {
+ /* Propagate all errors */
+ return NULL;
+ }
+ if (is_instance)
+ {
+ return result;
+ }
+ }
+
+ /* We do a getattr here so as not to be defeated by proxies */
+ cls = PyObject_GetAttr(ob, str__class__);
+ if (cls == NULL)
+ {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ {
+ /* Propagate non-AttributeErrors */
+ return 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;
+ int is_instance = -1;
+ result = NULL;
+
+ is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type);
+ if (is_instance < 0)
+ {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ {
+ /* Propagate non-AttributeErrors */
+ return NULL;
+ }
+ PyErr_Clear();
+ }
+ if (is_instance)
+ {
+ return implementedBy(NULL, ob);
+ }
+
+ result = PyObject_GetAttr(ob, str__providedBy__);
+
+ if (result == NULL)
+ {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ {
+ return 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, &SpecificationBaseType)
+ ||
+ 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;
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject* weakreflist;
+ /*
+ In the past, these fields were stored in the __dict__
+ and were technically allowed to contain any Python object, though
+ other type checks would fail or fall back to generic code paths if
+ they didn't have the expected type. We preserve that behaviour and don't
+ make any assumptions about contents.
+ */
+ PyObject* _implied;
+ /*
+ The remainder aren't used in C code but must be stored here
+ to prevent instance layout conflicts.
+ */
+ PyObject* _dependents;
+ PyObject* _bases;
+ PyObject* _v_attrs;
+ PyObject* __iro__;
+ PyObject* __sro__;
+} Spec;
+
+/*
+ We know what the fields are *supposed* to define, but
+ they could have anything, so we need to traverse them.
+*/
+static int
+Spec_traverse(Spec* self, visitproc visit, void* arg)
+{
+ Py_VISIT(self->_implied);
+ Py_VISIT(self->_dependents);
+ Py_VISIT(self->_bases);
+ Py_VISIT(self->_v_attrs);
+ Py_VISIT(self->__iro__);
+ Py_VISIT(self->__sro__);
+ return 0;
+}
+
+static int
+Spec_clear(Spec* self)
+{
+ Py_CLEAR(self->_implied);
+ Py_CLEAR(self->_dependents);
+ Py_CLEAR(self->_bases);
+ Py_CLEAR(self->_v_attrs);
+ Py_CLEAR(self->__iro__);
+ Py_CLEAR(self->__sro__);
+ return 0;
+}
+
+static void
+Spec_dealloc(Spec* self)
+{
+ /* PyType_GenericAlloc that you get when you don't
+ specify a tp_alloc always tracks the object. */
+ PyObject_GC_UnTrack((PyObject *)self);
+ if (self->weakreflist != NULL) {
+ PyObject_ClearWeakRefs(OBJECT(self));
+ }
+ Spec_clear(self);
+ Py_TYPE(self)->tp_free(OBJECT(self));
+}
+
+static PyObject *
+Spec_extends(Spec *self, PyObject *other)
+{
+ PyObject *implied;
+
+ implied = self->_implied;
+ if (implied == NULL) {
+ return NULL;
+ }
+
+ if (PyDict_GetItem(implied, other) != NULL)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+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(Spec *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, &SpecificationBaseType))
+ item = Spec_extends((Spec*)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, &SpecificationBaseType))
+ item = Spec_extends((Spec*)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 PyMemberDef Spec_members[] = {
+ {"_implied", T_OBJECT_EX, offsetof(Spec, _implied), 0, ""},
+ {"_dependents", T_OBJECT_EX, offsetof(Spec, _dependents), 0, ""},
+ {"_bases", T_OBJECT_EX, offsetof(Spec, _bases), 0, ""},
+ {"_v_attrs", T_OBJECT_EX, offsetof(Spec, _v_attrs), 0, ""},
+ {"__iro__", T_OBJECT_EX, offsetof(Spec, __iro__), 0, ""},
+ {"__sro__", T_OBJECT_EX, offsetof(Spec, __sro__), 0, ""},
+ {NULL},
+};
+
+
+static PyTypeObject SpecificationBaseType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ /* tp_name */ "_interface_coptimizations."
+ "SpecificationBase",
+ /* tp_basicsize */ sizeof(Spec),
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor)Spec_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)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 | Py_TPFLAGS_HAVE_GC,
+ "Base type for Specification objects",
+ /* tp_traverse */ (traverseproc)Spec_traverse,
+ /* tp_clear */ (inquiry)Spec_clear,
+ /* tp_richcompare */ (richcmpfunc)0,
+ /* tp_weaklistoffset */ offsetof(Spec, weakreflist),
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ Spec_methods,
+ /* tp_members */ Spec_members,
+};
+
+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__);
+ /* Return __provides__ if we got it, or return NULL and propagate non-AttributeError. */
+ if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError))
+ 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,
+};
+
+typedef struct {
+ Spec spec;
+ /* These members are handled generically, as for Spec members. */
+ PyObject* _cls;
+ PyObject* _implements;
+} CPB;
+
+static PyObject *
+CPB_descr_get(CPB *self, PyObject *inst, PyObject *cls)
+{
+ PyObject *implements;
+
+ if (self->_cls == NULL)
+ return NULL;
+
+ if (cls == self->_cls)
+ {
+ if (inst == NULL)
+ {
+ Py_INCREF(self);
+ return OBJECT(self);
+ }
+
+ implements = self->_implements;
+ Py_XINCREF(implements);
+ return implements;
+ }
+
+ PyErr_SetObject(PyExc_AttributeError, str__provides__);
+ return NULL;
+}
+
+static int
+CPB_traverse(CPB* self, visitproc visit, void* arg)
+{
+ Py_VISIT(self->_cls);
+ Py_VISIT(self->_implements);
+ return Spec_traverse((Spec*)self, visit, arg);
+}
+
+static int
+CPB_clear(CPB* self)
+{
+ Py_CLEAR(self->_cls);
+ Py_CLEAR(self->_implements);
+ Spec_clear((Spec*)self);
+ return 0;
+}
+
+static void
+CPB_dealloc(CPB* self)
+{
+ PyObject_GC_UnTrack((PyObject *)self);
+ CPB_clear(self);
+ Spec_dealloc((Spec*)self);
+}
+
+static PyMemberDef CPB_members[] = {
+ {"_cls", T_OBJECT_EX, offsetof(CPB, _cls), 0, "Defining class."},
+ {"_implements", T_OBJECT_EX, offsetof(CPB, _implements), 0, "Result of implementedBy."},
+ {NULL}
+};
+
+static PyTypeObject CPBType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ /* tp_name */ "_interface_coptimizations."
+ "ClassProvidesBase",
+ /* tp_basicsize */ sizeof(CPB),
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor)CPB_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,
+ "C Base class for ClassProvides",
+ /* tp_traverse */ (traverseproc)CPB_traverse,
+ /* tp_clear */ (inquiry)CPB_clear,
+ /* tp_richcompare */ (richcmpfunc)0,
+ /* tp_weaklistoffset */ (long)0,
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ 0,
+ /* tp_members */ CPB_members,
+ /* tp_getset */ 0,
+ /* tp_base */ &SpecificationBaseType,
+ /* tp_dict */ 0, /* internal use */
+ /* tp_descr_get */ (descrgetfunc)CPB_descr_get,
+ /* tp_descr_set */ 0,
+ /* tp_dictoffset */ 0,
+ /* tp_init */ 0,
+ /* tp_alloc */ 0,
+ /* tp_new */ 0,
+};
+
+/* ==================================================================== */
+/* ========== Begin: __call__ and __adapt__ =========================== */
+
+/*
+ def __adapt__(self, obj):
+ """Adapt an object to the receiver
+ """
+ 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, &SpecificationBaseType))
+ {
+ PyObject *implied;
+
+ implied = ((Spec*)decl)->_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;
+}
+
+#ifndef PY3K
+typedef long Py_hash_t;
+#endif
+
+typedef struct {
+ Spec spec;
+ PyObject* __name__;
+ PyObject* __module__;
+ Py_hash_t _v_cached_hash;
+} IB;
+
+static struct PyMethodDef ib_methods[] = {
+ {"__adapt__", (PyCFunction)__adapt__, METH_O,
+ "Adapt an object to the receiver"},
+ {NULL, NULL} /* sentinel */
+};
+
+/*
+ def __call__(self, obj, alternate=_marker):
+ try:
+ conform = obj.__conform__
+ except AttributeError: # pylint:disable=bare-except
+ 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
+ if alternate is not _marker:
+ return alternate
+ raise TypeError("Could not adapt", obj, self)
+
+*/
+static PyObject *
+IB_call(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *conform, *obj, *alternate, *adapter;
+ static char *kwlist[] = {"obj", "alternate", NULL};
+ conform = obj = alternate = adapter = NULL;
+
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist,
+ &obj, &alternate))
+ return NULL;
+
+ conform = PyObject_GetAttr(obj, str__conform__);
+ if (conform == NULL)
+ {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ {
+ /* Propagate non-AttributeErrors */
+ return NULL;
+ }
+ PyErr_Clear();
+
+ Py_INCREF(Py_None);
+ conform = Py_None;
+ }
+
+ if (conform != Py_None)
+ {
+ adapter = PyObject_CallMethodObjArgs(self, str_call_conform,
+ conform, NULL);
+ Py_DECREF(conform);
+ if (adapter == NULL || adapter != Py_None)
+ return adapter;
+ Py_DECREF(adapter);
+ }
+ else
+ {
+ Py_DECREF(conform);
+ }
+
+ /* We differ from the Python code here. For speed, instead of always calling
+ self.__adapt__(), we check to see if the type has defined it. Checking in
+ the dict for __adapt__ isn't sufficient because there's no cheap way to
+ tell if it's the __adapt__ that InterfaceBase itself defines (our type
+ will *never* be InterfaceBase, we're always subclassed by
+ InterfaceClass). Instead, we cooperate with InterfaceClass in Python to
+ set a flag in a new subclass when this is necessary. */
+ if (PyDict_GetItem(self->ob_type->tp_dict, str_CALL_CUSTOM_ADAPT))
+ {
+ /* Doesn't matter what the value is. Simply being present is enough. */
+ adapter = PyObject_CallMethodObjArgs(self, str__adapt__, obj, NULL);
+ }
+ else
+ {
+ 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 int
+IB_traverse(IB* self, visitproc visit, void* arg)
+{
+ Py_VISIT(self->__name__);
+ Py_VISIT(self->__module__);
+ return Spec_traverse((Spec*)self, visit, arg);
+}
+
+static int
+IB_clear(IB* self)
+{
+ Py_CLEAR(self->__name__);
+ Py_CLEAR(self->__module__);
+ return Spec_clear((Spec*)self);
+}
+
+static void
+IB_dealloc(IB* self)
+{
+ PyObject_GC_UnTrack((PyObject *)self);
+ IB_clear(self);
+ Spec_dealloc((Spec*)self);
+}
+
+static PyMemberDef IB_members[] = {
+ {"__name__", T_OBJECT_EX, offsetof(IB, __name__), 0, ""},
+ // The redundancy between __module__ and __ibmodule__ is because
+ // __module__ is often shadowed by subclasses.
+ {"__module__", T_OBJECT_EX, offsetof(IB, __module__), READONLY, ""},
+ {"__ibmodule__", T_OBJECT_EX, offsetof(IB, __module__), 0, ""},
+ {NULL}
+};
+
+static Py_hash_t
+IB_hash(IB* self)
+{
+ PyObject* tuple;
+ if (!self->__module__) {
+ PyErr_SetString(PyExc_AttributeError, "__module__");
+ return -1;
+ }
+ if (!self->__name__) {
+ PyErr_SetString(PyExc_AttributeError, "__name__");
+ return -1;
+ }
+
+ if (self->_v_cached_hash) {
+ return self->_v_cached_hash;
+ }
+
+ tuple = PyTuple_Pack(2, self->__name__, self->__module__);
+ if (!tuple) {
+ return -1;
+ }
+ self->_v_cached_hash = PyObject_Hash(tuple);
+ Py_CLEAR(tuple);
+ return self->_v_cached_hash;
+}
+
+static PyTypeObject InterfaceBaseType;
+
+static PyObject*
+IB_richcompare(IB* self, PyObject* other, int op)
+{
+ PyObject* othername;
+ PyObject* othermod;
+ PyObject* oresult;
+ IB* otherib;
+ int result;
+
+ otherib = NULL;
+ oresult = othername = othermod = NULL;
+
+ if (OBJECT(self) == other) {
+ switch(op) {
+ case Py_EQ:
+ case Py_LE:
+ case Py_GE:
+ Py_RETURN_TRUE;
+ break;
+ case Py_NE:
+ Py_RETURN_FALSE;
+ }
+ }
+
+ if (other == Py_None) {
+ switch(op) {
+ case Py_LT:
+ case Py_LE:
+ case Py_NE:
+ Py_RETURN_TRUE;
+ default:
+ Py_RETURN_FALSE;
+ }
+ }
+
+ if (PyObject_TypeCheck(other, &InterfaceBaseType)) {
+ // This branch borrows references. No need to clean
+ // up if otherib is not null.
+ otherib = (IB*)other;
+ othername = otherib->__name__;
+ othermod = otherib->__module__;
+ }
+ else {
+ othername = PyObject_GetAttrString(other, "__name__");
+ if (othername) {
+ othermod = PyObject_GetAttrString(other, "__module__");
+ }
+ if (!othername || !othermod) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ oresult = Py_NotImplemented;
+ }
+ goto cleanup;
+ }
+ }
+#if 0
+// This is the simple, straightforward version of what Python does.
+ PyObject* pt1 = PyTuple_Pack(2, self->__name__, self->__module__);
+ PyObject* pt2 = PyTuple_Pack(2, othername, othermod);
+ oresult = PyObject_RichCompare(pt1, pt2, op);
+#endif
+
+ // tuple comparison is decided by the first non-equal element.
+ result = PyObject_RichCompareBool(self->__name__, othername, Py_EQ);
+ if (result == 0) {
+ result = PyObject_RichCompareBool(self->__name__, othername, op);
+ }
+ else if (result == 1) {
+ result = PyObject_RichCompareBool(self->__module__, othermod, op);
+ }
+ // If either comparison failed, we have an error set.
+ // Leave oresult NULL so we raise it.
+ if (result == -1) {
+ goto cleanup;
+ }
+
+ oresult = result ? Py_True : Py_False;
+
+
+cleanup:
+ Py_XINCREF(oresult);
+
+ if (!otherib) {
+ Py_XDECREF(othername);
+ Py_XDECREF(othermod);
+ }
+ return oresult;
+
+}
+
+static int
+IB_init(IB* self, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {"__name__", "__module__", NULL};
+ PyObject* module = NULL;
+ PyObject* name = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:InterfaceBase.__init__", kwlist,
+ &name, &module)) {
+ return -1;
+ }
+ IB_clear(self);
+ self->__module__ = module ? module : Py_None;
+ Py_INCREF(self->__module__);
+ self->__name__ = name ? name : Py_None;
+ Py_INCREF(self->__name__);
+ return 0;
+}
+
+
+static PyTypeObject InterfaceBaseType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ /* tp_name */ "_zope_interface_coptimizations."
+ "InterfaceBase",
+ /* tp_basicsize */ sizeof(IB),
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor)IB_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)IB_hash,
+ /* 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 | Py_TPFLAGS_HAVE_GC,
+ /* tp_doc */ "Interface base type providing __call__ and __adapt__",
+ /* tp_traverse */ (traverseproc)IB_traverse,
+ /* tp_clear */ (inquiry)IB_clear,
+ /* tp_richcompare */ (richcmpfunc)IB_richcompare,
+ /* tp_weaklistoffset */ (long)0,
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ ib_methods,
+ /* tp_members */ IB_members,
+ /* tp_getset */ 0,
+ /* tp_base */ &SpecificationBaseType,
+ /* tp_dict */ 0,
+ /* tp_descr_get */ 0,
+ /* tp_descr_set */ 0,
+ /* tp_dictoffset */ 0,
+ /* tp_init */ (initproc)IB_init,
+};
+
+/* =================== 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)
+{
+ PyObject_GC_UnTrack((PyObject *)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 *
+_lookup(lookup *self,
+ PyObject *required, PyObject *provided, PyObject *name,
+ PyObject *default_)
+{
+ PyObject *result, *key, *cache;
+ result = key = cache = NULL;
+#ifdef PY3K
+ if ( name && !PyUnicode_Check(name) )
+#else
+ if ( name && !PyString_Check(name) && !PyUnicode_Check(name) )
+#endif
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "name is not a string or unicode");
+ return NULL;
+ }
+
+ /* If `required` is a lazy sequence, it could have arbitrary side-effects,
+ such as clearing our caches. So we must not retrieve the cache until
+ after resolving it. */
+ required = PySequence_Tuple(required);
+ if (required == NULL)
+ return NULL;
+
+
+ cache = _getcache(self, provided, name);
+ if (cache == 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:LookupBase.lookup", 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;
+
+#ifdef PY3K
+ if ( name && !PyUnicode_Check(name) )
+#else
+ if ( name && !PyString_Check(name) && !PyUnicode_Check(name) )
+#endif
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "name is not a string or unicode");
+ return NULL;
+ }
+
+ 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
+ {
+ if (result == Py_None && default_ != NULL)
+ {
+ result = default_;
+ }
+ 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:LookupBase.lookup1", 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:
+ if isinstance(object, super):
+ object = object.__self__
+ 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;
+
+#ifdef PY3K
+ if ( name && !PyUnicode_Check(name) )
+#else
+ if ( name && !PyString_Check(name) && !PyUnicode_Check(name) )
+#endif
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "name is not a string or unicode");
+ return NULL;
+ }
+
+ 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)
+ {
+ if (PyObject_TypeCheck(object, &PySuper_Type)) {
+ PyObject* self = PyObject_GetAttr(object, str__self__);
+ if (self == NULL)
+ {
+ Py_DECREF(factory);
+ return NULL;
+ }
+ // Borrow the reference to self
+ Py_DECREF(self);
+ object = self;
+ }
+ 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:LookupBase.adapter_hook", 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:LookupBase.queryAdapter", 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;
+
+ /* resolve before getting cache. See note in _lookup. */
+ required = PySequence_Tuple(required);
+ if (required == NULL)
+ return NULL;
+
+ ASSURE_DICT(self->_mcache);
+ cache = _subcache(self->_mcache, provided);
+ if (cache == 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:LookupBase.lookupAll", 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;
+
+ /* resolve before getting cache. See note in _lookup. */
+ required = PySequence_Tuple(required);
+ if (required == NULL)
+ return NULL;
+
+ ASSURE_DICT(self->_scache);
+ cache = _subcache(self->_scache, provided);
+ if (cache == 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 | METH_VARARGS, ""},
+ {"lookup1", (PyCFunction)lookup_lookup1, METH_KEYWORDS | METH_VARARGS, ""},
+ {"queryAdapter", (PyCFunction)lookup_queryAdapter, METH_KEYWORDS | METH_VARARGS, ""},
+ {"adapter_hook", (PyCFunction)lookup_adapter_hook, METH_KEYWORDS | METH_VARARGS, ""},
+ {"lookupAll", (PyCFunction)lookup_lookupAll, METH_KEYWORDS | METH_VARARGS, ""},
+ {"subscriptions", (PyCFunction)lookup_subscriptions, METH_KEYWORDS | METH_VARARGS, ""},
+ {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)
+{
+ PyObject_GC_UnTrack((PyObject *)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 | METH_VARARGS, ""},
+ {"lookup1", (PyCFunction)verifying_lookup1, METH_KEYWORDS | METH_VARARGS, ""},
+ {"queryAdapter", (PyCFunction)verifying_queryAdapter, METH_KEYWORDS | METH_VARARGS, ""},
+ {"adapter_hook", (PyCFunction)verifying_adapter_hook, METH_KEYWORDS | METH_VARARGS, ""},
+ {"lookupAll", (PyCFunction)verifying_lookupAll, METH_KEYWORDS | METH_VARARGS, ""},
+ {"subscriptions", (PyCFunction)verifying_subscriptions, METH_KEYWORDS | METH_VARARGS, ""},
+ {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(__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);
+ DEFINE_STRING(__self__);
+ DEFINE_STRING(__name__);
+ DEFINE_STRING(__module__);
+ DEFINE_STRING(__adapt__);
+ DEFINE_STRING(_CALL_CUSTOM_ADAPT);
+#undef DEFINE_STRING
+ adapter_hooks = PyList_New(0);
+ if (adapter_hooks == NULL)
+ return NULL;
+
+ /* Initialize types: */
+ SpecificationBaseType.tp_new = PyBaseObject_Type.tp_new;
+ if (PyType_Ready(&SpecificationBaseType) < 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;
+
+ InterfaceBaseType.tp_new = PyBaseObject_Type.tp_new;
+ if (PyType_Ready(&InterfaceBaseType) < 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(&SpecificationBaseType)) < 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(&InterfaceBaseType)) < 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
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
diff --git a/contrib/python/zope.interface/py2/zope/interface/adapter.py b/contrib/python/zope.interface/py2/zope/interface/adapter.py
new file mode 100644
index 0000000000..9a542db3c7
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/adapter.py
@@ -0,0 +1,1018 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Adapter management
+"""
+import itertools
+import weakref
+
+from zope.interface import implementer
+from zope.interface import providedBy
+from zope.interface import Interface
+from zope.interface import ro
+from zope.interface.interfaces import IAdapterRegistry
+
+from zope.interface._compat import _normalize_name
+from zope.interface._compat import STRING_TYPES
+from zope.interface._compat import _use_c_impl
+
+__all__ = [
+ 'AdapterRegistry',
+ 'VerifyingAdapterRegistry',
+]
+
+# In the CPython implementation,
+# ``tuple`` and ``list`` cooperate so that ``tuple([some list])``
+# directly allocates and iterates at the C level without using a
+# Python iterator. That's not the case for
+# ``tuple(generator_expression)`` or ``tuple(map(func, it))``.
+##
+# 3.8
+# ``tuple([t for t in range(10)])`` -> 610ns
+# ``tuple(t for t in range(10))`` -> 696ns
+# ``tuple(map(lambda t: t, range(10)))`` -> 881ns
+##
+# 2.7
+# ``tuple([t fon t in range(10)])`` -> 625ns
+# ``tuple(t for t in range(10))`` -> 665ns
+# ``tuple(map(lambda t: t, range(10)))`` -> 958ns
+#
+# All three have substantial variance.
+##
+# On PyPy, this is also the best option.
+##
+# PyPy 2.7.18-7.3.3
+# ``tuple([t fon t in range(10)])`` -> 128ns
+# ``tuple(t for t in range(10))`` -> 175ns
+# ``tuple(map(lambda t: t, range(10)))`` -> 153ns
+##
+# PyPy 3.7.9 7.3.3-beta
+# ``tuple([t fon t in range(10)])`` -> 82ns
+# ``tuple(t for t in range(10))`` -> 177ns
+# ``tuple(map(lambda t: t, range(10)))`` -> 168ns
+#
+
+class BaseAdapterRegistry(object):
+ """
+ A basic implementation of the data storage and algorithms required
+ for a :class:`zope.interface.interfaces.IAdapterRegistry`.
+
+ Subclasses can set the following attributes to control how the data
+ is stored; in particular, these hooks can be helpful for ZODB
+ persistence. They can be class attributes that are the named (or similar) type, or
+ they can be methods that act as a constructor for an object that behaves
+ like the types defined here; this object will not assume that they are type
+ objects, but subclasses are free to do so:
+
+ _sequenceType = list
+ This is the type used for our two mutable top-level "byorder" sequences.
+ Must support mutation operations like ``append()`` and ``del seq[index]``.
+ These are usually small (< 10). Although at least one of them is
+ accessed when performing lookups or queries on this object, the other
+ is untouched. In many common scenarios, both are only required when
+ mutating registrations and subscriptions (like what
+ :meth:`zope.interface.interfaces.IComponents.registerUtility` does).
+ This use pattern makes it an ideal candidate to be a
+ :class:`~persistent.list.PersistentList`.
+ _leafSequenceType = tuple
+ This is the type used for the leaf sequences of subscribers.
+ It could be set to a ``PersistentList`` to avoid many unnecessary data
+ loads when subscribers aren't being used. Mutation operations are directed
+ through :meth:`_addValueToLeaf` and :meth:`_removeValueFromLeaf`; if you use
+ a mutable type, you'll need to override those.
+ _mappingType = dict
+ This is the mutable mapping type used for the keyed mappings.
+ A :class:`~persistent.mapping.PersistentMapping`
+ could be used to help reduce the number of data loads when the registry is large
+ and parts of it are rarely used. Further reductions in data loads can come from
+ using a :class:`~BTrees.OOBTree.OOBTree`, but care is required
+ to be sure that all required/provided
+ values are fully ordered (e.g., no required or provided values that are classes
+ can be used).
+ _providedType = dict
+ This is the mutable mapping type used for the ``_provided`` mapping.
+ This is separate from the generic mapping type because the values
+ are always integers, so one might choose to use a more optimized data
+ structure such as a :class:`~BTrees.OIBTree.OIBTree`.
+ The same caveats regarding key types
+ apply as for ``_mappingType``.
+
+ It is possible to also set these on an instance, but because of the need to
+ potentially also override :meth:`_addValueToLeaf` and :meth:`_removeValueFromLeaf`,
+ this may be less useful in a persistent scenario; using a subclass is recommended.
+
+ .. versionchanged:: 5.3.0
+ Add support for customizing the way internal data
+ structures are created.
+ .. versionchanged:: 5.3.0
+ Add methods :meth:`rebuild`, :meth:`allRegistrations`
+ and :meth:`allSubscriptions`.
+ """
+
+ # 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 = self._sequenceType()
+
+ # {order -> {required -> {provided -> {name -> [value]}}}}
+ # where the remarks about adapters above apply
+ self._subscribers = self._sequenceType()
+
+ # Set, with a reference count, keeping track of the interfaces
+ # for which we have provided components:
+ self._provided = self._providedType()
+
+ # 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 LookupBaseFallback 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):
+ """
+ If subclasses need to track when ``__bases__`` changes, they
+ can override this method.
+
+ Subclasses must still call this method.
+ """
+ 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)
+
+ # Hooks for subclasses to define the types of objects used in
+ # our data structures.
+ # These have to be documented in the docstring, instead of local
+ # comments, because Sphinx autodoc ignores the comment and just writes
+ # "alias of list"
+ _sequenceType = list
+ _leafSequenceType = tuple
+ _mappingType = dict
+ _providedType = dict
+
+ def _addValueToLeaf(self, existing_leaf_sequence, new_item):
+ """
+ Add the value *new_item* to the *existing_leaf_sequence*, which may
+ be ``None``.
+
+ Subclasses that redefine `_leafSequenceType` should override this method.
+
+ :param existing_leaf_sequence:
+ If *existing_leaf_sequence* is not *None*, it will be an instance
+ of `_leafSequenceType`. (Unless the object has been unpickled
+ from an old pickle and the class definition has changed, in which case
+ it may be an instance of a previous definition, commonly a `tuple`.)
+
+ :return:
+ This method returns the new value to be stored. It may mutate the
+ sequence in place if it was not ``None`` and the type is mutable, but
+ it must also return it.
+
+ .. versionadded:: 5.3.0
+ """
+ if existing_leaf_sequence is None:
+ return (new_item,)
+ return existing_leaf_sequence + (new_item,)
+
+ def _removeValueFromLeaf(self, existing_leaf_sequence, to_remove):
+ """
+ Remove the item *to_remove* from the (non-``None``, non-empty)
+ *existing_leaf_sequence* and return the mutated sequence.
+
+ If there is more than one item that is equal to *to_remove*
+ they must all be removed.
+
+ Subclasses that redefine `_leafSequenceType` should override
+ this method. Note that they can call this method to help
+ in their implementation; this implementation will always
+ return a new tuple constructed by iterating across
+ the *existing_leaf_sequence* and omitting items equal to *to_remove*.
+
+ :param existing_leaf_sequence:
+ As for `_addValueToLeaf`, probably an instance of
+ `_leafSequenceType` but possibly an older type; never `None`.
+ :return:
+ A version of *existing_leaf_sequence* with all items equal to
+ *to_remove* removed. Must not return `None`. However,
+ returning an empty
+ object, even of another type such as the empty tuple, ``()`` is
+ explicitly allowed; such an object will never be stored.
+
+ .. versionadded:: 5.3.0
+ """
+ return tuple([v for v in existing_leaf_sequence if v != to_remove])
+
+ def changed(self, originally_changed):
+ self._generation += 1
+ self._v_lookup.changed(originally_changed)
+
+ def register(self, required, provided, name, value):
+ if not isinstance(name, STRING_TYPES):
+ raise ValueError('name is not a string')
+ if value is None:
+ self.unregister(required, provided, name, value)
+ return
+
+ required = tuple([_convert_None_to_Interface(r) for r in required])
+ name = _normalize_name(name)
+ order = len(required)
+ byorder = self._adapters
+ while len(byorder) <= order:
+ byorder.append(self._mappingType())
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ d = self._mappingType()
+ 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 _find_leaf(self, byorder, required, provided, name):
+ # Find the leaf value, if any, in the *byorder* list
+ # for the interface sequence *required* and the interface
+ # *provided*, given the already normalized *name*.
+ #
+ # If no such leaf value exists, returns ``None``
+ required = tuple([_convert_None_to_Interface(r) for r in required])
+ order = len(required)
+ 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 registered(self, required, provided, name=u''):
+ return self._find_leaf(
+ self._adapters,
+ required,
+ provided,
+ _normalize_name(name)
+ )
+
+ @classmethod
+ def _allKeys(cls, components, i, parent_k=()):
+ if i == 0:
+ for k, v in components.items():
+ yield parent_k + (k,), v
+ else:
+ for k, v in components.items():
+ new_parent_k = parent_k + (k,)
+ for x, y in cls._allKeys(v, i - 1, new_parent_k):
+ yield x, y
+
+ def _all_entries(self, byorder):
+ # Recurse through the mapping levels of the `byorder` sequence,
+ # reconstructing a flattened sequence of ``(required, provided, name, value)``
+ # tuples that can be used to reconstruct the sequence with the appropriate
+ # registration methods.
+ #
+ # Locally reference the `byorder` data; it might be replaced while
+ # this method is running (see ``rebuild``).
+ for i, components in enumerate(byorder):
+ # We will have *i* levels of dictionaries to go before
+ # we get to the leaf.
+ for key, value in self._allKeys(components, i + 1):
+ assert len(key) == i + 2
+ required = key[:i]
+ provided = key[-2]
+ name = key[-1]
+ yield (required, provided, name, value)
+
+ def allRegistrations(self):
+ """
+ Yields tuples ``(required, provided, name, value)`` for all
+ the registrations that this object holds.
+
+ These tuples could be passed as the arguments to the
+ :meth:`register` method on another adapter registry to
+ duplicate the registrations this object holds.
+
+ .. versionadded:: 5.3.0
+ """
+ for t in self._all_entries(self._adapters):
+ yield t
+
+ def unregister(self, required, provided, name, value=None):
+ required = tuple([_convert_None_to_Interface(r) for r in 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 = []
+ 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([_convert_None_to_Interface(r) for r in required])
+ name = u''
+ order = len(required)
+ byorder = self._subscribers
+ while len(byorder) <= order:
+ byorder.append(self._mappingType())
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ d = self._mappingType()
+ components[k] = d
+ components = d
+
+ components[name] = self._addValueToLeaf(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 subscribed(self, required, provided, subscriber):
+ subscribers = self._find_leaf(
+ self._subscribers,
+ required,
+ provided,
+ u''
+ ) or ()
+ return subscriber if subscriber in subscribers else None
+
+ def allSubscriptions(self):
+ """
+ Yields tuples ``(required, provided, value)`` for all the
+ subscribers that this object holds.
+
+ These tuples could be passed as the arguments to the
+ :meth:`subscribe` method on another adapter registry to
+ duplicate the registrations this object holds.
+
+ .. versionadded:: 5.3.0
+ """
+ for required, provided, _name, value in self._all_entries(self._subscribers):
+ for v in value:
+ yield (required, provided, v)
+
+ def unsubscribe(self, required, provided, value=None):
+ required = tuple([_convert_None_to_Interface(r) for r in 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 = []
+ 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:
+ # this is belt-and-suspenders against the failure of cleanup below
+ return # pragma: no cover
+ len_old = len(old)
+ if value is None:
+ # Removing everything; note that the type of ``new`` won't
+ # necessarily match the ``_leafSequenceType``, but that's
+ # OK because we're about to delete the entire entry
+ # anyway.
+ new = ()
+ else:
+ new = self._removeValueFromLeaf(old, value)
+ # ``new`` may be the same object as ``old``, just mutated in place,
+ # so we cannot compare it to ``old`` to check for changes. Remove
+ # our reference to it now to avoid trying to do so below.
+ del old
+
+ if len(new) == len_old:
+ # No changes, so nothing could have been removed.
+ 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.
+ 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)
+ else:
+ self._provided[provided] = n
+
+ self.changed(self)
+
+ def rebuild(self):
+ """
+ Rebuild (and replace) all the internal data structures of this
+ object.
+
+ This is useful, especially for persistent implementations, if
+ you suspect an issue with reference counts keeping interfaces
+ alive even though they are no longer used.
+
+ It is also useful if you or a subclass change the data types
+ (``_mappingType`` and friends) that are to be used.
+
+ This method replaces all internal data structures with new objects;
+ it specifically does not re-use any storage.
+
+ .. versionadded:: 5.3.0
+ """
+
+ # Grab the iterators, we're about to discard their data.
+ registrations = self.allRegistrations()
+ subscriptions = self.allSubscriptions()
+
+ def buffer(it):
+ # The generator doesn't actually start running until we
+ # ask for its next(), by which time the attributes will change
+ # unless we do so before calling __init__.
+ try:
+ first = next(it)
+ except StopIteration:
+ return iter(())
+
+ return itertools.chain((first,), it)
+
+ registrations = buffer(registrations)
+ subscriptions = buffer(subscriptions)
+
+
+ # Replace the base data structures as well as _v_lookup.
+ self.__init__(self.__bases__)
+ # Re-register everything previously registered and subscribed.
+ #
+ # XXX: This is going to call ``self.changed()`` a lot, all of
+ # which is unnecessary (because ``self.__init__`` just
+ # re-created those dependent objects and also called
+ # ``self.changed()``). Is this a bottleneck that needs fixed?
+ # (We could do ``self.changed = lambda _: None`` before
+ # beginning and remove it after to disable the presumably expensive
+ # part of passing that notification to the change of objects.)
+ for args in registrations:
+ self.register(*args)
+ for args in subscriptions:
+ self.subscribe(*args)
+
+ # XXX hack to fake out twisted's use of a private api. We need to get them
+ # to use the new registered method.
+ def get(self, _): # pragma: no cover
+ class XXXTwistedFakeOut:
+ selfImplied = {}
+ return XXXTwistedFakeOut
+
+
+_not_in_mapping = object()
+
+@_use_c_impl
+class LookupBase(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):
+ if not isinstance(name, STRING_TYPES):
+ raise ValueError('name is not a string')
+ cache = self._getcache(provided, name)
+ required = tuple(required)
+ 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):
+ if not isinstance(name, STRING_TYPES):
+ raise ValueError('name is not a string')
+ 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):
+ if not isinstance(name, STRING_TYPES):
+ raise ValueError('name is not a string')
+ 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:
+ if isinstance(object, super):
+ object = object.__self__
+ 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
+
+
+@_use_c_impl
+class VerifyingBase(LookupBaseFallback):
+ # Mixin for lookups against registries which "chain" upwards, and
+ # whose lookups invalidate their own caches whenever a parent registry
+ # bumps its own '_generation' counter. E.g., used by
+ # zope.component.persistentregistry
+
+ def changed(self, originally_changed):
+ LookupBaseFallback.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 LookupBaseFallback._getcache(self, provided, name)
+
+ def lookupAll(self, required, provided):
+ self._verify()
+ return LookupBaseFallback.lookupAll(self, required, provided)
+
+ def subscriptions(self, required, provided):
+ self._verify()
+ return LookupBaseFallback.subscriptions(self, required, provided)
+
+
+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,
+ # if 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''):
+ required = tuple(required)
+ 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([providedBy(o) for o in objects], provided, name)
+ if factory is None:
+ return default
+
+ result = factory(*[o.__self__ if isinstance(o, super) else o for o in objects])
+ if result is None:
+ return default
+
+ return result
+
+ def _uncached_lookupAll(self, required, provided):
+ required = tuple(required)
+ 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.items())
+
+ def names(self, required, provided):
+ return [c[0] for c in self.lookupAll(required, provided)]
+
+ def _uncached_subscriptions(self, required, provided):
+ required = tuple(required)
+ 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([providedBy(o) for o in 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
+
+@implementer(IAdapterRegistry)
+class AdapterRegistry(BaseAdapterRegistry):
+ """
+ A full implementation of ``IAdapterRegistry`` that adds support for
+ sub-registries.
+ """
+
+ LookupClass = AdapterLookup
+
+ def __init__(self, bases=()):
+ # AdapterRegisties are invalidating registries, so
+ # we need to keep track of our 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
+
+@implementer(IAdapterRegistry)
+class VerifyingAdapterRegistry(BaseAdapterRegistry):
+ """
+ The most commonly-used adapter registry.
+ """
+
+ LookupClass = VerifyingAdapterLookup
+
+def _convert_None_to_Interface(x):
+ if x is None:
+ return Interface
+ else:
+ return x
+
+def _lookup(components, specs, provided, name, i, l):
+ # this function is called very often.
+ # The components.get in loops is executed 100 of 1000s times.
+ # by loading get into a local variable the bytecode
+ # "LOAD_FAST 0 (components)" in the loop can be eliminated.
+ components_get = components.get
+ 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):
+ components_get = components.get # see _lookup above
+ 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):
+ components_get = components.get # see _lookup above
+ 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/contrib/python/zope.interface/py2/zope/interface/advice.py b/contrib/python/zope.interface/py2/zope/interface/advice.py
new file mode 100644
index 0000000000..86d0f11aa4
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/advice.py
@@ -0,0 +1,213 @@
+##############################################################################
+#
+# 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
+except ImportError:
+ __python3 = True
+else:
+ __python3 = False
+
+__all__ = [
+ 'addClassAdvisor',
+ 'determineMetaclass',
+ 'getFrameInfo',
+ 'isClassAdvisor',
+ 'minimalBases',
+]
+
+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: # pragma: no cover
+ # 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."""
+ # This entire approach is invalid under Py3K. Don't even try to fix
+ # the coverage for this block there. :(
+ if __python3: # pragma: no cover
+ raise TypeError('Class advice impossible in Python3')
+
+ 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: # pragma: no cover
+ 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: # pragma: no cover
+ # 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: # pragma: no cover
+ 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/contrib/python/zope.interface/py2/zope/interface/common/__init__.py b/contrib/python/zope.interface/py2/zope/interface/common/__init__.py
new file mode 100644
index 0000000000..137e93867e
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/__init__.py
@@ -0,0 +1,272 @@
+##############################################################################
+# Copyright (c) 2020 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+##############################################################################
+
+import itertools
+from types import FunctionType
+
+from zope.interface import classImplements
+from zope.interface import Interface
+from zope.interface.interface import fromFunction
+from zope.interface.interface import InterfaceClass
+from zope.interface.interface import _decorator_non_return
+
+__all__ = [
+ # Nothing public here.
+]
+
+
+# pylint:disable=inherit-non-class,
+# pylint:disable=no-self-argument,no-method-argument
+# pylint:disable=unexpected-special-method-signature
+
+class optional(object):
+ # Apply this decorator to a method definition to make it
+ # optional (remove it from the list of required names), overriding
+ # the definition inherited from the ABC.
+ def __init__(self, method):
+ self.__doc__ = method.__doc__
+
+
+class ABCInterfaceClass(InterfaceClass):
+ """
+ An interface that is automatically derived from a
+ :class:`abc.ABCMeta` type.
+
+ Internal use only.
+
+ The body of the interface definition *must* define
+ a property ``abc`` that is the ABC to base the interface on.
+
+ If ``abc`` is *not* in the interface definition, a regular
+ interface will be defined instead (but ``extra_classes`` is still
+ respected).
+
+ Use the ``@optional`` decorator on method definitions if
+ the ABC defines methods that are not actually required in all cases
+ because the Python language has multiple ways to implement a protocol.
+ For example, the ``iter()`` protocol can be implemented with
+ ``__iter__`` or the pair ``__len__`` and ``__getitem__``.
+
+ When created, any existing classes that are registered to conform
+ to the ABC are declared to implement this interface. This is *not*
+ automatically updated as the ABC registry changes. If the body of the
+ interface definition defines ``extra_classes``, it should be a
+ tuple giving additional classes to declare implement the interface.
+
+ Note that this is not fully symmetric. For example, it is usually
+ the case that a subclass relationship carries the interface
+ declarations over::
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface):
+ ... pass
+ ...
+ >>> from zope.interface import implementer
+ >>> @implementer(I1)
+ ... class Root(object):
+ ... pass
+ ...
+ >>> class Child(Root):
+ ... pass
+ ...
+ >>> child = Child()
+ >>> isinstance(child, Root)
+ True
+ >>> from zope.interface import providedBy
+ >>> list(providedBy(child))
+ [<InterfaceClass __main__.I1>]
+
+ However, that's not the case with ABCs and ABC interfaces. Just
+ because ``isinstance(A(), AnABC)`` and ``isinstance(B(), AnABC)``
+ are both true, that doesn't mean there's any class hierarchy
+ relationship between ``A`` and ``B``, or between either of them
+ and ``AnABC``. Thus, if ``AnABC`` implemented ``IAnABC``, it would
+ not follow that either ``A`` or ``B`` implements ``IAnABC`` (nor
+ their instances provide it)::
+
+ >>> class SizedClass(object):
+ ... def __len__(self): return 1
+ ...
+ >>> from collections.abc import Sized
+ >>> isinstance(SizedClass(), Sized)
+ True
+ >>> from zope.interface import classImplements
+ >>> classImplements(Sized, I1)
+ None
+ >>> list(providedBy(SizedClass()))
+ []
+
+ Thus, to avoid conflicting assumptions, ABCs should not be
+ declared to implement their parallel ABC interface. Only concrete
+ classes specifically registered with the ABC should be declared to
+ do so.
+
+ .. versionadded:: 5.0.0
+ """
+
+ # If we could figure out invalidation, and used some special
+ # Specification/Declaration instances, and override the method ``providedBy`` here,
+ # perhaps we could more closely integrate with ABC virtual inheritance?
+
+ def __init__(self, name, bases, attrs):
+ # go ahead and give us a name to ease debugging.
+ self.__name__ = name
+ extra_classes = attrs.pop('extra_classes', ())
+ ignored_classes = attrs.pop('ignored_classes', ())
+
+ if 'abc' not in attrs:
+ # Something like ``IList(ISequence)``: We're extending
+ # abc interfaces but not an ABC interface ourself.
+ InterfaceClass.__init__(self, name, bases, attrs)
+ ABCInterfaceClass.__register_classes(self, extra_classes, ignored_classes)
+ self.__class__ = InterfaceClass
+ return
+
+ based_on = attrs.pop('abc')
+ self.__abc = based_on
+ self.__extra_classes = tuple(extra_classes)
+ self.__ignored_classes = tuple(ignored_classes)
+
+ assert name[1:] == based_on.__name__, (name, based_on)
+ methods = {
+ # Passing the name is important in case of aliases,
+ # e.g., ``__ror__ = __or__``.
+ k: self.__method_from_function(v, k)
+ for k, v in vars(based_on).items()
+ if isinstance(v, FunctionType) and not self.__is_private_name(k)
+ and not self.__is_reverse_protocol_name(k)
+ }
+
+ methods['__doc__'] = self.__create_class_doc(attrs)
+ # Anything specified in the body takes precedence.
+ methods.update(attrs)
+ InterfaceClass.__init__(self, name, bases, methods)
+ self.__register_classes()
+
+ @staticmethod
+ def __optional_methods_to_docs(attrs):
+ optionals = {k: v for k, v in attrs.items() if isinstance(v, optional)}
+ for k in optionals:
+ attrs[k] = _decorator_non_return
+
+ if not optionals:
+ return ''
+
+ docs = "\n\nThe following methods are optional:\n - " + "\n-".join(
+ "%s\n%s" % (k, v.__doc__) for k, v in optionals.items()
+ )
+ return docs
+
+ def __create_class_doc(self, attrs):
+ based_on = self.__abc
+ def ref(c):
+ mod = c.__module__
+ name = c.__name__
+ if mod == str.__module__:
+ return "`%s`" % name
+ if mod == '_io':
+ mod = 'io'
+ return "`%s.%s`" % (mod, name)
+ implementations_doc = "\n - ".join(
+ ref(c)
+ for c in sorted(self.getRegisteredConformers(), key=ref)
+ )
+ if implementations_doc:
+ implementations_doc = "\n\nKnown implementations are:\n\n - " + implementations_doc
+
+ based_on_doc = (based_on.__doc__ or '')
+ based_on_doc = based_on_doc.splitlines()
+ based_on_doc = based_on_doc[0] if based_on_doc else ''
+
+ doc = """Interface for the ABC `%s.%s`.\n\n%s%s%s""" % (
+ based_on.__module__, based_on.__name__,
+ attrs.get('__doc__', based_on_doc),
+ self.__optional_methods_to_docs(attrs),
+ implementations_doc
+ )
+ return doc
+
+
+ @staticmethod
+ def __is_private_name(name):
+ if name.startswith('__') and name.endswith('__'):
+ return False
+ return name.startswith('_')
+
+ @staticmethod
+ def __is_reverse_protocol_name(name):
+ # The reverse names, like __rand__,
+ # aren't really part of the protocol. The interpreter has
+ # very complex behaviour around invoking those. PyPy
+ # doesn't always even expose them as attributes.
+ return name.startswith('__r') and name.endswith('__')
+
+ def __method_from_function(self, function, name):
+ method = fromFunction(function, self, name=name)
+ # Eliminate the leading *self*, which is implied in
+ # an interface, but explicit in an ABC.
+ method.positional = method.positional[1:]
+ return method
+
+ def __register_classes(self, conformers=None, ignored_classes=None):
+ # Make the concrete classes already present in our ABC's registry
+ # declare that they implement this interface.
+ conformers = conformers if conformers is not None else self.getRegisteredConformers()
+ ignored = ignored_classes if ignored_classes is not None else self.__ignored_classes
+ for cls in conformers:
+ if cls in ignored:
+ continue
+ classImplements(cls, self)
+
+ def getABC(self):
+ """
+ Return the ABC this interface represents.
+ """
+ return self.__abc
+
+ def getRegisteredConformers(self):
+ """
+ Return an iterable of the classes that are known to conform to
+ the ABC this interface parallels.
+ """
+ based_on = self.__abc
+
+ # The registry only contains things that aren't already
+ # known to be subclasses of the ABC. But the ABC is in charge
+ # of checking that, so its quite possible that registrations
+ # are in fact ignored, winding up just in the _abc_cache.
+ try:
+ registered = list(based_on._abc_registry) + list(based_on._abc_cache)
+ except AttributeError:
+ # Rewritten in C in CPython 3.7.
+ # These expose the underlying weakref.
+ from abc import _get_dump
+ data = _get_dump(based_on)
+ registry = data[0]
+ cache = data[1]
+ registered = [x() for x in itertools.chain(registry, cache)]
+ registered = [x for x in registered if x is not None]
+
+ return set(itertools.chain(registered, self.__extra_classes))
+
+
+def _create_ABCInterface():
+ # It's a two-step process to create the root ABCInterface, because
+ # without specifying a corresponding ABC, using the normal constructor
+ # gets us a plain InterfaceClass object, and there is no ABC to associate with the
+ # root.
+ abc_name_bases_attrs = ('ABCInterface', (Interface,), {})
+ instance = ABCInterfaceClass.__new__(ABCInterfaceClass, *abc_name_bases_attrs)
+ InterfaceClass.__init__(instance, *abc_name_bases_attrs)
+ return instance
+
+ABCInterface = _create_ABCInterface()
diff --git a/contrib/python/zope.interface/py2/zope/interface/common/builtins.py b/contrib/python/zope.interface/py2/zope/interface/common/builtins.py
new file mode 100644
index 0000000000..a07c0a36e7
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/builtins.py
@@ -0,0 +1,125 @@
+##############################################################################
+# Copyright (c) 2020 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 definitions for builtin types.
+
+After this module is imported, the standard library types will declare
+that they implement the appropriate interface.
+
+.. versionadded:: 5.0.0
+"""
+from __future__ import absolute_import
+
+from zope.interface import classImplements
+
+from zope.interface.common import collections
+from zope.interface.common import numbers
+from zope.interface.common import io
+
+__all__ = [
+ 'IList',
+ 'ITuple',
+ 'ITextString',
+ 'IByteString',
+ 'INativeString',
+ 'IBool',
+ 'IDict',
+ 'IFile',
+]
+
+# pylint:disable=no-self-argument
+class IList(collections.IMutableSequence):
+ """
+ Interface for :class:`list`
+ """
+ extra_classes = (list,)
+
+ def sort(key=None, reverse=False):
+ """
+ Sort the list in place and return None.
+
+ *key* and *reverse* must be passed by name only.
+ """
+
+
+class ITuple(collections.ISequence):
+ """
+ Interface for :class:`tuple`
+ """
+ extra_classes = (tuple,)
+
+
+class ITextString(collections.ISequence):
+ """
+ Interface for text (unicode) strings.
+
+ On Python 2, this is :class:`unicode`. On Python 3,
+ this is :class:`str`
+ """
+ extra_classes = (type(u'unicode'),)
+
+
+class IByteString(collections.IByteString):
+ """
+ Interface for immutable byte strings.
+
+ On all Python versions this is :class:`bytes`.
+
+ Unlike :class:`zope.interface.common.collections.IByteString`
+ (the parent of this interface) this does *not* include
+ :class:`bytearray`.
+ """
+ extra_classes = (bytes,)
+
+
+class INativeString(IByteString if str is bytes else ITextString):
+ """
+ Interface for native strings.
+
+ On all Python versions, this is :class:`str`. On Python 2,
+ this extends :class:`IByteString`, while on Python 3 it extends
+ :class:`ITextString`.
+ """
+# We're not extending ABCInterface so extra_classes won't work
+classImplements(str, INativeString)
+
+
+class IBool(numbers.IIntegral):
+ """
+ Interface for :class:`bool`
+ """
+ extra_classes = (bool,)
+
+
+class IDict(collections.IMutableMapping):
+ """
+ Interface for :class:`dict`
+ """
+ extra_classes = (dict,)
+
+
+class IFile(io.IIOBase):
+ """
+ Interface for :class:`file`.
+
+ It is recommended to use the interfaces from :mod:`zope.interface.common.io`
+ instead of this interface.
+
+ On Python 3, there is no single implementation of this interface;
+ depending on the arguments, the :func:`open` builtin can return
+ many different classes that implement different interfaces from
+ :mod:`zope.interface.common.io`.
+ """
+ try:
+ extra_classes = (file,)
+ except NameError:
+ extra_classes = ()
diff --git a/contrib/python/zope.interface/py2/zope/interface/common/collections.py b/contrib/python/zope.interface/py2/zope/interface/common/collections.py
new file mode 100644
index 0000000000..00e2b8c287
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/collections.py
@@ -0,0 +1,284 @@
+##############################################################################
+# Copyright (c) 2020 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 definitions paralleling the abstract base classes defined in
+:mod:`collections.abc`.
+
+After this module is imported, the standard library types will declare
+that they implement the appropriate interface. While most standard
+library types will properly implement that interface (that
+is, ``verifyObject(ISequence, list()))`` will pass, for example), a few might not:
+
+ - `memoryview` doesn't feature all the defined methods of
+ ``ISequence`` such as ``count``; it is still declared to provide
+ ``ISequence`` though.
+
+ - `collections.deque.pop` doesn't accept the ``index`` argument of
+ `collections.abc.MutableSequence.pop`
+
+ - `range.index` does not accept the ``start`` and ``stop`` arguments.
+
+.. versionadded:: 5.0.0
+"""
+from __future__ import absolute_import
+
+import sys
+
+from abc import ABCMeta
+# The collections imports are here, and not in
+# zope.interface._compat to avoid importing collections
+# unless requested. It's a big import.
+try:
+ from collections import abc
+except ImportError:
+ import collections as abc
+from collections import OrderedDict
+try:
+ # On Python 3, all of these extend the appropriate collection ABC,
+ # but on Python 2, UserDict does not (though it is registered as a
+ # MutableMapping). (Importantly, UserDict on Python 2 is *not*
+ # registered, because it's not iterable.) Extending the ABC is not
+ # taken into account for interface declarations, though, so we
+ # need to be explicit about it.
+ from collections import UserList
+ from collections import UserDict
+ from collections import UserString
+except ImportError:
+ # Python 2
+ from UserList import UserList
+ from UserDict import IterableUserDict as UserDict
+ from UserString import UserString
+
+from zope.interface._compat import PYTHON2 as PY2
+from zope.interface._compat import PYTHON3 as PY3
+from zope.interface.common import ABCInterface
+from zope.interface.common import optional
+
+# pylint:disable=inherit-non-class,
+# pylint:disable=no-self-argument,no-method-argument
+# pylint:disable=unexpected-special-method-signature
+# pylint:disable=no-value-for-parameter
+
+PY35 = sys.version_info[:2] >= (3, 5)
+PY36 = sys.version_info[:2] >= (3, 6)
+
+def _new_in_ver(name, ver,
+ bases_if_missing=(ABCMeta,),
+ register_if_missing=()):
+ if ver:
+ return getattr(abc, name)
+
+ # TODO: It's a shame to have to repeat the bases when
+ # the ABC is missing. Can we DRY that?
+ missing = ABCMeta(name, bases_if_missing, {
+ '__doc__': "The ABC %s is not defined in this version of Python." % (
+ name
+ ),
+ })
+
+ for c in register_if_missing:
+ missing.register(c)
+
+ return missing
+
+__all__ = [
+ 'IAsyncGenerator',
+ 'IAsyncIterable',
+ 'IAsyncIterator',
+ 'IAwaitable',
+ 'ICollection',
+ 'IContainer',
+ 'ICoroutine',
+ 'IGenerator',
+ 'IHashable',
+ 'IItemsView',
+ 'IIterable',
+ 'IIterator',
+ 'IKeysView',
+ 'IMapping',
+ 'IMappingView',
+ 'IMutableMapping',
+ 'IMutableSequence',
+ 'IMutableSet',
+ 'IReversible',
+ 'ISequence',
+ 'ISet',
+ 'ISized',
+ 'IValuesView',
+]
+
+class IContainer(ABCInterface):
+ abc = abc.Container
+
+ @optional
+ def __contains__(other):
+ """
+ Optional method. If not provided, the interpreter will use
+ ``__iter__`` or the old ``__getitem__`` protocol
+ to implement ``in``.
+ """
+
+class IHashable(ABCInterface):
+ abc = abc.Hashable
+
+class IIterable(ABCInterface):
+ abc = abc.Iterable
+
+ @optional
+ def __iter__():
+ """
+ Optional method. If not provided, the interpreter will
+ implement `iter` using the old ``__getitem__`` protocol.
+ """
+
+class IIterator(IIterable):
+ abc = abc.Iterator
+
+class IReversible(IIterable):
+ abc = _new_in_ver('Reversible', PY36, (IIterable.getABC(),))
+
+ @optional
+ def __reversed__():
+ """
+ Optional method. If this isn't present, the interpreter
+ will use ``__len__`` and ``__getitem__`` to implement the
+ `reversed` builtin.
+ """
+
+class IGenerator(IIterator):
+ # New in 3.5
+ abc = _new_in_ver('Generator', PY35, (IIterator.getABC(),))
+
+
+class ISized(ABCInterface):
+ abc = abc.Sized
+
+
+# ICallable is not defined because there's no standard signature.
+
+class ICollection(ISized,
+ IIterable,
+ IContainer):
+ abc = _new_in_ver('Collection', PY36,
+ (ISized.getABC(), IIterable.getABC(), IContainer.getABC()))
+
+
+class ISequence(IReversible,
+ ICollection):
+ abc = abc.Sequence
+ extra_classes = (UserString,)
+ # On Python 2, basestring is registered as an ISequence, and
+ # its subclass str is an IByteString. If we also register str as
+ # an ISequence, that tends to lead to inconsistent resolution order.
+ ignored_classes = (basestring,) if str is bytes else () # pylint:disable=undefined-variable
+
+ @optional
+ def __reversed__():
+ """
+ Optional method. If this isn't present, the interpreter
+ will use ``__len__`` and ``__getitem__`` to implement the
+ `reversed` builtin.
+ """
+
+ @optional
+ def __iter__():
+ """
+ Optional method. If not provided, the interpreter will
+ implement `iter` using the old ``__getitem__`` protocol.
+ """
+
+class IMutableSequence(ISequence):
+ abc = abc.MutableSequence
+ extra_classes = (UserList,)
+
+
+class IByteString(ISequence):
+ """
+ This unifies `bytes` and `bytearray`.
+ """
+ abc = _new_in_ver('ByteString', PY3,
+ (ISequence.getABC(),),
+ (bytes, bytearray))
+
+
+class ISet(ICollection):
+ abc = abc.Set
+
+
+class IMutableSet(ISet):
+ abc = abc.MutableSet
+
+
+class IMapping(ICollection):
+ abc = abc.Mapping
+ extra_classes = (dict,)
+ # OrderedDict is a subclass of dict. On CPython 2,
+ # it winds up registered as a IMutableMapping, which
+ # produces an inconsistent IRO if we also try to register it
+ # here.
+ ignored_classes = (OrderedDict,)
+ if PY2:
+ @optional
+ def __eq__(other):
+ """
+ The interpreter will supply one.
+ """
+
+ __ne__ = __eq__
+
+
+class IMutableMapping(IMapping):
+ abc = abc.MutableMapping
+ extra_classes = (dict, UserDict,)
+ ignored_classes = (OrderedDict,)
+
+class IMappingView(ISized):
+ abc = abc.MappingView
+
+
+class IItemsView(IMappingView, ISet):
+ abc = abc.ItemsView
+
+
+class IKeysView(IMappingView, ISet):
+ abc = abc.KeysView
+
+
+class IValuesView(IMappingView, ICollection):
+ abc = abc.ValuesView
+
+ @optional
+ def __contains__(other):
+ """
+ Optional method. If not provided, the interpreter will use
+ ``__iter__`` or the old ``__len__`` and ``__getitem__`` protocol
+ to implement ``in``.
+ """
+
+class IAwaitable(ABCInterface):
+ abc = _new_in_ver('Awaitable', PY35)
+
+
+class ICoroutine(IAwaitable):
+ abc = _new_in_ver('Coroutine', PY35)
+
+
+class IAsyncIterable(ABCInterface):
+ abc = _new_in_ver('AsyncIterable', PY35)
+
+
+class IAsyncIterator(IAsyncIterable):
+ abc = _new_in_ver('AsyncIterator', PY35)
+
+
+class IAsyncGenerator(IAsyncIterator):
+ abc = _new_in_ver('AsyncGenerator', PY36)
diff --git a/contrib/python/zope.interface/py2/zope/interface/common/idatetime.py b/contrib/python/zope.interface/py2/zope/interface/common/idatetime.py
new file mode 100644
index 0000000000..82f0059c85
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/idatetime.py
@@ -0,0 +1,606 @@
+##############################################################################
+# 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 datetime import timedelta, date, datetime, time, tzinfo
+
+from zope.interface import Interface, Attribute
+from zope.interface import classImplements
+
+
+class ITimeDeltaClass(Interface):
+ """This is the timedelta class interface.
+
+ This is symbolic; this module does **not** make
+ `datetime.timedelta` provide this 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.
+
+ Implemented by `datetime.timedelta`.
+
+ 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.
+
+ This is symbolic; this module does **not** make
+ `datetime.date` provide this 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.
+
+ Implemented by `datetime.date`.
+
+ 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.
+
+ .. seealso:: `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.
+
+ .. seealso:: `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.
+
+ This is symbolic; this module does **not** make
+ `datetime.datetime` provide this 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())``.
+
+ .. seealso:: `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)).
+
+ .. seealso:: `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.
+
+ .. seealso:: `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.
+
+ .. seealso:: `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.
+
+ .. seealso:: `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.
+
+ Implemented by `datetime.datetime`.
+ """
+
+ 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.
+
+ .. seealso:: Method :meth:`timetz`.
+ """
+
+ def timetz():
+ """Return time object with same hour, minute, second, microsecond,
+ and tzinfo.
+
+ .. seealso:: Method :meth:`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 `datetime.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.gmtime`."""
+
+ 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.
+
+ .. seealso:: `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.
+
+ This is symbolic; this module does **not** make
+ `datetime.time` provide this 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.
+
+ Implemented by `datetime.time`.
+
+ 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/contrib/python/zope.interface/py2/zope/interface/common/interfaces.py b/contrib/python/zope.interface/py2/zope/interface/common/interfaces.py
new file mode 100644
index 0000000000..4308e0ac32
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/interfaces.py
@@ -0,0 +1,212 @@
+##############################################################################
+#
+# 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):
+ "Interface for `Exception`"
+classImplements(Exception, IException)
+
+
+class IStandardError(IException):
+ "Interface for `StandardError` (Python 2 only.)"
+try:
+ classImplements(StandardError, IStandardError)
+except NameError: #pragma NO COVER
+ pass # StandardError does not exist in Python 3
+
+
+class IWarning(IException):
+ "Interface for `Warning`"
+classImplements(Warning, IWarning)
+
+
+class ISyntaxError(IStandardError):
+ "Interface for `SyntaxError`"
+classImplements(SyntaxError, ISyntaxError)
+
+
+class ILookupError(IStandardError):
+ "Interface for `LookupError`"
+classImplements(LookupError, ILookupError)
+
+
+class IValueError(IStandardError):
+ "Interface for `ValueError`"
+classImplements(ValueError, IValueError)
+
+
+class IRuntimeError(IStandardError):
+ "Interface for `RuntimeError`"
+classImplements(RuntimeError, IRuntimeError)
+
+
+class IArithmeticError(IStandardError):
+ "Interface for `ArithmeticError`"
+classImplements(ArithmeticError, IArithmeticError)
+
+
+class IAssertionError(IStandardError):
+ "Interface for `AssertionError`"
+classImplements(AssertionError, IAssertionError)
+
+
+class IAttributeError(IStandardError):
+ "Interface for `AttributeError`"
+classImplements(AttributeError, IAttributeError)
+
+
+class IDeprecationWarning(IWarning):
+ "Interface for `DeprecationWarning`"
+classImplements(DeprecationWarning, IDeprecationWarning)
+
+
+class IEOFError(IStandardError):
+ "Interface for `EOFError`"
+classImplements(EOFError, IEOFError)
+
+
+class IEnvironmentError(IStandardError):
+ "Interface for `EnvironmentError`"
+classImplements(EnvironmentError, IEnvironmentError)
+
+
+class IFloatingPointError(IArithmeticError):
+ "Interface for `FloatingPointError`"
+classImplements(FloatingPointError, IFloatingPointError)
+
+
+class IIOError(IEnvironmentError):
+ "Interface for `IOError`"
+classImplements(IOError, IIOError)
+
+
+class IImportError(IStandardError):
+ "Interface for `ImportError`"
+classImplements(ImportError, IImportError)
+
+
+class IIndentationError(ISyntaxError):
+ "Interface for `IndentationError`"
+classImplements(IndentationError, IIndentationError)
+
+
+class IIndexError(ILookupError):
+ "Interface for `IndexError`"
+classImplements(IndexError, IIndexError)
+
+
+class IKeyError(ILookupError):
+ "Interface for `KeyError`"
+classImplements(KeyError, IKeyError)
+
+
+class IKeyboardInterrupt(IStandardError):
+ "Interface for `KeyboardInterrupt`"
+classImplements(KeyboardInterrupt, IKeyboardInterrupt)
+
+
+class IMemoryError(IStandardError):
+ "Interface for `MemoryError`"
+classImplements(MemoryError, IMemoryError)
+
+
+class INameError(IStandardError):
+ "Interface for `NameError`"
+classImplements(NameError, INameError)
+
+
+class INotImplementedError(IRuntimeError):
+ "Interface for `NotImplementedError`"
+classImplements(NotImplementedError, INotImplementedError)
+
+
+class IOSError(IEnvironmentError):
+ "Interface for `OSError`"
+classImplements(OSError, IOSError)
+
+
+class IOverflowError(IArithmeticError):
+ "Interface for `ArithmeticError`"
+classImplements(OverflowError, IOverflowError)
+
+
+class IOverflowWarning(IWarning):
+ """Deprecated, no standard class implements this.
+
+ This was the interface for ``OverflowWarning`` prior to Python 2.5,
+ but that class was removed for all versions after that.
+ """
+
+
+class IReferenceError(IStandardError):
+ "Interface for `ReferenceError`"
+classImplements(ReferenceError, IReferenceError)
+
+
+class IRuntimeWarning(IWarning):
+ "Interface for `RuntimeWarning`"
+classImplements(RuntimeWarning, IRuntimeWarning)
+
+
+class IStopIteration(IException):
+ "Interface for `StopIteration`"
+classImplements(StopIteration, IStopIteration)
+
+
+class ISyntaxWarning(IWarning):
+ "Interface for `SyntaxWarning`"
+classImplements(SyntaxWarning, ISyntaxWarning)
+
+
+class ISystemError(IStandardError):
+ "Interface for `SystemError`"
+classImplements(SystemError, ISystemError)
+
+
+class ISystemExit(IException):
+ "Interface for `SystemExit`"
+classImplements(SystemExit, ISystemExit)
+
+
+class ITabError(IIndentationError):
+ "Interface for `TabError`"
+classImplements(TabError, ITabError)
+
+
+class ITypeError(IStandardError):
+ "Interface for `TypeError`"
+classImplements(TypeError, ITypeError)
+
+
+class IUnboundLocalError(INameError):
+ "Interface for `UnboundLocalError`"
+classImplements(UnboundLocalError, IUnboundLocalError)
+
+
+class IUnicodeError(IValueError):
+ "Interface for `UnicodeError`"
+classImplements(UnicodeError, IUnicodeError)
+
+
+class IUserWarning(IWarning):
+ "Interface for `UserWarning`"
+classImplements(UserWarning, IUserWarning)
+
+
+class IZeroDivisionError(IArithmeticError):
+ "Interface for `ZeroDivisionError`"
+classImplements(ZeroDivisionError, IZeroDivisionError)
diff --git a/contrib/python/zope.interface/py2/zope/interface/common/io.py b/contrib/python/zope.interface/py2/zope/interface/common/io.py
new file mode 100644
index 0000000000..540d53ac94
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/io.py
@@ -0,0 +1,53 @@
+##############################################################################
+# Copyright (c) 2020 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 definitions paralleling the abstract base classes defined in
+:mod:`io`.
+
+After this module is imported, the standard library types will declare
+that they implement the appropriate interface.
+
+.. versionadded:: 5.0.0
+"""
+from __future__ import absolute_import
+
+import io as abc
+
+from zope.interface.common import ABCInterface
+
+# pylint:disable=inherit-non-class,
+# pylint:disable=no-member
+
+class IIOBase(ABCInterface):
+ abc = abc.IOBase
+
+
+class IRawIOBase(IIOBase):
+ abc = abc.RawIOBase
+
+
+class IBufferedIOBase(IIOBase):
+ abc = abc.BufferedIOBase
+ try:
+ import cStringIO
+ except ImportError:
+ # Python 3
+ extra_classes = ()
+ else:
+ import StringIO
+ extra_classes = (StringIO.StringIO, cStringIO.InputType, cStringIO.OutputType)
+ del cStringIO
+ del StringIO
+
+
+class ITextIOBase(IIOBase):
+ abc = abc.TextIOBase
diff --git a/contrib/python/zope.interface/py2/zope/interface/common/mapping.py b/contrib/python/zope.interface/py2/zope/interface/common/mapping.py
new file mode 100644
index 0000000000..de56cf8493
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/mapping.py
@@ -0,0 +1,184 @@
+##############################################################################
+#
+# 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.
+
+Importing this module does *not* mark any standard classes as
+implementing any of these interfaces.
+
+While this module is not deprecated, new code should generally use
+:mod:`zope.interface.common.collections`, specifically
+:class:`~zope.interface.common.collections.IMapping` and
+:class:`~zope.interface.common.collections.IMutableMapping`. This
+module is occasionally useful for its extremely fine grained breakdown
+of interfaces.
+
+The standard library :class:`dict` and :class:`collections.UserDict`
+implement ``IMutableMapping``, but *do not* implement any of the
+interfaces in this module.
+"""
+from zope.interface import Interface
+from zope.interface._compat import PYTHON2 as PY2
+from zope.interface.common import collections
+
+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(collections.IContainer, IItemMapping):
+ """
+ Basic mapping interface.
+
+ .. versionchanged:: 5.0.0
+ Extend ``IContainer``
+ """
+
+ 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."""
+ # Optional in IContainer, required by this interface.
+
+
+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(collections.ISized, IReadMapping):
+ """
+ Mapping objects whose items can be enumerated.
+
+ .. versionchanged:: 5.0.0
+ Extend ``ISized``
+ """
+
+ 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.
+ """
+
+class IMapping(IWriteMapping, IEnumerableMapping):
+ ''' Simple mapping interface '''
+
+class IIterableMapping(IEnumerableMapping):
+ """A mapping that has distinct methods for iterating
+ without copying.
+
+ On Python 2, a `dict` has these methods, but on Python 3
+ the methods defined in `IEnumerableMapping` already iterate
+ without copying.
+ """
+
+ if PY2:
+ def iterkeys():
+ "iterate over keys; equivalent to ``__iter__``"
+
+ def itervalues():
+ "iterate over values"
+
+ def iteritems():
+ "iterate over items"
+
+class IClonableMapping(Interface):
+ """Something that can produce a copy of itself.
+
+ This is available in `dict`.
+ """
+
+ def copy():
+ "return copy of dict"
+
+class IExtendedReadMapping(IIterableMapping):
+ """
+ Something with a particular method equivalent to ``__contains__``.
+
+ On Python 2, `dict` provides this method, but it was removed
+ in Python 3.
+ """
+
+ if PY2:
+ def has_key(key):
+ """Tell if a key exists in the mapping; equivalent to ``__contains__``"""
+
+class IExtendedWriteMapping(IWriteMapping):
+ """Additional mutation methods.
+
+ These are all provided by `dict`.
+ """
+
+ 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, default=None):
+ """
+ pop(k[,default]) -> value
+
+ Remove specified key and return the corresponding value.
+
+ If key is not found, *default* is returned if given, otherwise
+ `KeyError` is raised. Note that *default* must not be passed by
+ name.
+ """
+
+ def popitem():
+ """remove and return some (key, value) pair as a
+ 2-tuple; but raise KeyError if mapping is empty"""
+
+class IFullMapping(
+ collections.IMutableMapping,
+ IExtendedReadMapping, IExtendedWriteMapping, IClonableMapping, IMapping,):
+ """
+ Full mapping interface.
+
+ Most uses of this interface should instead use
+ :class:`~zope.interface.commons.collections.IMutableMapping` (one of the
+ bases of this interface). The required methods are the same.
+
+ .. versionchanged:: 5.0.0
+ Extend ``IMutableMapping``
+ """
diff --git a/contrib/python/zope.interface/py2/zope/interface/common/numbers.py b/contrib/python/zope.interface/py2/zope/interface/common/numbers.py
new file mode 100644
index 0000000000..3bf9206b5e
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/numbers.py
@@ -0,0 +1,84 @@
+##############################################################################
+# Copyright (c) 2020 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 definitions paralleling the abstract base classes defined in
+:mod:`numbers`.
+
+After this module is imported, the standard library types will declare
+that they implement the appropriate interface.
+
+.. versionadded:: 5.0.0
+"""
+from __future__ import absolute_import
+
+import numbers as abc
+
+from zope.interface.common import ABCInterface
+from zope.interface.common import optional
+
+from zope.interface._compat import PYTHON2 as PY2
+
+# pylint:disable=inherit-non-class,
+# pylint:disable=no-self-argument,no-method-argument
+# pylint:disable=unexpected-special-method-signature
+# pylint:disable=no-value-for-parameter
+
+
+class INumber(ABCInterface):
+ abc = abc.Number
+
+
+class IComplex(INumber):
+ abc = abc.Complex
+
+ @optional
+ def __complex__():
+ """
+ Rarely implemented, even in builtin types.
+ """
+
+ if PY2:
+ @optional
+ def __eq__(other):
+ """
+ The interpreter may supply one through complicated rules.
+ """
+
+ __ne__ = __eq__
+
+class IReal(IComplex):
+ abc = abc.Real
+
+ @optional
+ def __complex__():
+ """
+ Rarely implemented, even in builtin types.
+ """
+
+ __floor__ = __ceil__ = __complex__
+
+ if PY2:
+ @optional
+ def __le__(other):
+ """
+ The interpreter may supply one through complicated rules.
+ """
+
+ __lt__ = __le__
+
+
+class IRational(IReal):
+ abc = abc.Rational
+
+
+class IIntegral(IRational):
+ abc = abc.Integral
diff --git a/contrib/python/zope.interface/py2/zope/interface/common/sequence.py b/contrib/python/zope.interface/py2/zope/interface/common/sequence.py
new file mode 100644
index 0000000000..da4bc84a09
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/common/sequence.py
@@ -0,0 +1,215 @@
+##############################################################################
+#
+# 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
+
+Importing this module does *not* mark any standard classes as
+implementing any of these interfaces.
+
+While this module is not deprecated, new code should generally use
+:mod:`zope.interface.common.collections`, specifically
+:class:`~zope.interface.common.collections.ISequence` and
+:class:`~zope.interface.common.collections.IMutableSequence`. This
+module is occasionally useful for its fine-grained breakdown of interfaces.
+
+The standard library :class:`list`, :class:`tuple` and
+:class:`collections.UserList`, among others, implement ``ISequence``
+or ``IMutableSequence`` but *do not* implement any of the interfaces
+in this module.
+"""
+
+__docformat__ = 'restructuredtext'
+from zope.interface import Interface
+from zope.interface.common import collections
+from zope.interface._compat import PYTHON2 as PY2
+
+class IMinimalSequence(collections.IIterable):
+ """Most basic sequence interface.
+
+ All sequences are iterable. This requires at least one of the
+ following:
+
+ - a `__getitem__()` method that takes a single argument; integer
+ 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(collections.ISized, IMinimalSequence):
+ """
+ A sequence of bound size.
+
+ .. versionchanged:: 5.0.0
+ Extend ``ISized``
+ """
+
+class IReadSequence(collections.IContainer, IFiniteSequence):
+ """
+ read interface shared by tuple and list
+
+ This interface is similar to
+ :class:`~zope.interface.common.collections.ISequence`, but
+ requires that all instances be totally ordered. Most users
+ should prefer ``ISequence``.
+
+ .. versionchanged:: 5.0.0
+ Extend ``IContainer``
+ """
+
+ def __contains__(item):
+ """``x.__contains__(item) <==> item in x``"""
+ # Optional in IContainer, required here.
+
+ 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``"""
+
+ if PY2:
+ 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):
+ """index(value, [start, [stop]]) -> int
+
+ Return first index of *value*
+ """
+
+class IUniqueMemberWriteSequence(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.
+ """
+
+ if PY2:
+ 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.
+
+ New code should prefer
+ :class:`~zope.interface.common.collections.IMutableSequence`.
+
+ Compared to that interface, which is implemented by :class:`list`
+ (:class:`~zope.interface.common.builtins.IList`), among others,
+ this interface is missing the following methods:
+
+ - clear
+
+ - count
+
+ - index
+
+ This interface adds the following methods:
+
+ - sort
+ """
diff --git a/contrib/python/zope.interface/py2/zope/interface/declarations.py b/contrib/python/zope.interface/py2/zope/interface/declarations.py
new file mode 100644
index 0000000000..59bd650fdc
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/declarations.py
@@ -0,0 +1,1313 @@
+##############################################################################
+# 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
+from types import FunctionType
+from types import MethodType
+from types import ModuleType
+import weakref
+
+from zope.interface.advice import addClassAdvisor
+from zope.interface.interface import Interface
+from zope.interface.interface import InterfaceClass
+from zope.interface.interface import SpecificationBase
+from zope.interface.interface import Specification
+from zope.interface.interface import NameAndModuleComparisonMixin
+from zope.interface._compat import CLASS_TYPES as DescriptorAwareMetaClasses
+from zope.interface._compat import PYTHON3
+from zope.interface._compat import _use_c_impl
+
+__all__ = [
+ # None. The public APIs of this module are
+ # re-exported from zope.interface directly.
+]
+
+# pylint:disable=too-many-lines
+
+# Registry of class-implementation specifications
+BuiltinImplementationSpecifications = {}
+
+_ADVICE_ERROR = ('Class advice impossible in Python3. '
+ 'Use the @%s class decorator instead.')
+
+_ADVICE_WARNING = ('The %s API is deprecated, and will not work in Python3 '
+ 'Use the @%s class decorator instead.')
+
+def _next_super_class(ob):
+ # When ``ob`` is an instance of ``super``, return
+ # the next class in the MRO that we should actually be
+ # looking at. Watch out for diamond inheritance!
+ self_class = ob.__self_class__
+ class_that_invoked_super = ob.__thisclass__
+ complete_mro = self_class.__mro__
+ next_class = complete_mro[complete_mro.index(class_that_invoked_super) + 1]
+ return next_class
+
+class named(object):
+
+ def __init__(self, name):
+ self.name = name
+
+ def __call__(self, ob):
+ ob.__component_name__ = self.name
+ return ob
+
+
+class Declaration(Specification):
+ """Interface declarations"""
+
+ __slots__ = ()
+
+ def __init__(self, *bases):
+ Specification.__init__(self, _normalizeargs(bases))
+
+ def __contains__(self, interface):
+ """Test whether an interface is in the specification
+ """
+
+ return self.extends(interface) and interface in self.interfaces()
+
+ def __iter__(self):
+ """Return an iterator for the interfaces in the specification
+ """
+ return self.interfaces()
+
+ def flattened(self):
+ """Return an iterator of all included and extended interfaces
+ """
+ return iter(self.__iro__)
+
+ def __sub__(self, other):
+ """Remove interfaces from a specification
+ """
+ return Declaration(*[
+ i for i in self.interfaces()
+ if not [
+ j
+ for j in other.interfaces()
+ if i.extends(j, 0) # non-strict extends
+ ]
+ ])
+
+ def __add__(self, other):
+ """
+ Add two specifications or a specification and an interface
+ and produce a new declaration.
+
+ .. versionchanged:: 5.4.0
+ Now tries to preserve a consistent resolution order. Interfaces
+ being added to this object are added to the front of the resulting resolution
+ order if they already extend an interface in this object. Previously,
+ they were always added to the end of the order, which easily resulted in
+ invalid orders.
+ """
+ before = []
+ result = list(self.interfaces())
+ seen = set(result)
+ for i in other.interfaces():
+ if i in seen:
+ continue
+ seen.add(i)
+ if any(i.extends(x) for x in result):
+ # It already extends us, e.g., is a subclass,
+ # so it needs to go at the front of the RO.
+ before.append(i)
+ else:
+ result.append(i)
+ return Declaration(*(before + result))
+
+ # XXX: Is __radd__ needed? No tests break if it's removed.
+ # If it is needed, does it need to handle the C3 ordering differently?
+ # I (JAM) don't *think* it does.
+ __radd__ = __add__
+
+ @staticmethod
+ def _add_interfaces_to_cls(interfaces, cls):
+ # Strip redundant interfaces already provided
+ # by the cls so we don't produce invalid
+ # resolution orders.
+ implemented_by_cls = implementedBy(cls)
+ interfaces = tuple([
+ iface
+ for iface in interfaces
+ if not implemented_by_cls.isOrExtends(iface)
+ ])
+ return interfaces + (implemented_by_cls,)
+
+ @staticmethod
+ def _argument_names_for_repr(interfaces):
+ # These don't actually have to be interfaces, they could be other
+ # Specification objects like Implements. Also, the first
+ # one is typically/nominally the cls.
+ ordered_names = []
+ names = set()
+ for iface in interfaces:
+ duplicate_transform = repr
+ if isinstance(iface, InterfaceClass):
+ # Special case to get 'foo.bar.IFace'
+ # instead of '<InterfaceClass foo.bar.IFace>'
+ this_name = iface.__name__
+ duplicate_transform = str
+ elif isinstance(iface, type):
+ # Likewise for types. (Ignoring legacy old-style
+ # classes.)
+ this_name = iface.__name__
+ duplicate_transform = _implements_name
+ elif (isinstance(iface, Implements)
+ and not iface.declared
+ and iface.inherit in interfaces):
+ # If nothing is declared, there's no need to even print this;
+ # it would just show as ``classImplements(Class)``, and the
+ # ``Class`` has typically already.
+ continue
+ else:
+ this_name = repr(iface)
+
+ already_seen = this_name in names
+ names.add(this_name)
+ if already_seen:
+ this_name = duplicate_transform(iface)
+
+ ordered_names.append(this_name)
+ return ', '.join(ordered_names)
+
+
+class _ImmutableDeclaration(Declaration):
+ # A Declaration that is immutable. Used as a singleton to
+ # return empty answers for things like ``implementedBy``.
+ # We have to define the actual singleton after normalizeargs
+ # is defined, and that in turn is defined after InterfaceClass and
+ # Implements.
+
+ __slots__ = ()
+
+ __instance = None
+
+ def __new__(cls):
+ if _ImmutableDeclaration.__instance is None:
+ _ImmutableDeclaration.__instance = object.__new__(cls)
+ return _ImmutableDeclaration.__instance
+
+ def __reduce__(self):
+ return "_empty"
+
+ @property
+ def __bases__(self):
+ return ()
+
+ @__bases__.setter
+ def __bases__(self, new_bases):
+ # We expect the superclass constructor to set ``self.__bases__ = ()``.
+ # Rather than attempt to special case that in the constructor and allow
+ # setting __bases__ only at that time, it's easier to just allow setting
+ # the empty tuple at any time. That makes ``x.__bases__ = x.__bases__`` a nice
+ # no-op too. (Skipping the superclass constructor altogether is a recipe
+ # for maintenance headaches.)
+ if new_bases != ():
+ raise TypeError("Cannot set non-empty bases on shared empty Declaration.")
+
+ # As the immutable empty declaration, we cannot be changed.
+ # This means there's no logical reason for us to have dependents
+ # or subscriptions: we'll never notify them. So there's no need for
+ # us to keep track of any of that.
+ @property
+ def dependents(self):
+ return {}
+
+ changed = subscribe = unsubscribe = lambda self, _ignored: None
+
+ def interfaces(self):
+ # An empty iterator
+ return iter(())
+
+ def extends(self, interface, strict=True):
+ return interface is self._ROOT
+
+ def get(self, name, default=None):
+ return default
+
+ def weakref(self, callback=None):
+ # We're a singleton, we never go away. So there's no need to return
+ # distinct weakref objects here; their callbacks will never
+ # be called. Instead, we only need to return a callable that
+ # returns ourself. The easiest one is to return _ImmutableDeclaration
+ # itself; testing on Python 3.8 shows that's faster than a function that
+ # returns _empty. (Remember, one goal is to avoid allocating any
+ # object, and that includes a method.)
+ return _ImmutableDeclaration
+
+ @property
+ def _v_attrs(self):
+ # _v_attrs is not a public, documented property, but some client
+ # code uses it anyway as a convenient place to cache things. To keep
+ # the empty declaration truly immutable, we must ignore that. That includes
+ # ignoring assignments as well.
+ return {}
+
+ @_v_attrs.setter
+ def _v_attrs(self, new_attrs):
+ pass
+
+
+##############################################################################
+#
+# Implementation specifications
+#
+# These specify interfaces implemented by instances of classes
+
+class Implements(NameAndModuleComparisonMixin,
+ Declaration):
+ # Inherit from NameAndModuleComparisonMixin to be
+ # mutually comparable with InterfaceClass objects.
+ # (The two must be mutually comparable to be able to work in e.g., BTrees.)
+ # Instances of this class generally don't have a __module__ other than
+ # `zope.interface.declarations`, whereas they *do* have a __name__ that is the
+ # fully qualified name of the object they are representing.
+
+ # Note, though, that equality and hashing are still identity based. This
+ # accounts for things like nested objects that have the same name (typically
+ # only in tests) and is consistent with pickling. As far as comparisons to InterfaceClass
+ # goes, we'll never have equal name and module to those, so we're still consistent there.
+ # Instances of this class are essentially intended to be unique and are
+ # heavily cached (note how our __reduce__ handles this) so having identity
+ # based hash and eq should also work.
+
+ # We want equality and hashing to be based on identity. However, we can't actually
+ # implement __eq__/__ne__ to do this because sometimes we get wrapped in a proxy.
+ # We need to let the proxy types implement these methods so they can handle unwrapping
+ # and then rely on: (1) the interpreter automatically changing `implements == proxy` into
+ # `proxy == implements` (which will call proxy.__eq__ to do the unwrapping) and then
+ # (2) the default equality and hashing semantics being identity based.
+
+ # class whose specification should be used as additional base
+ inherit = None
+
+ # interfaces actually declared for a class
+ declared = ()
+
+ # Weak cache of {class: <implements>} for super objects.
+ # Created on demand. These are rare, as of 5.0 anyway. Using a class
+ # level default doesn't take space in instances. Using _v_attrs would be
+ # another place to store this without taking space unless needed.
+ _super_cache = None
+
+ __name__ = '?'
+
+ @classmethod
+ def named(cls, name, *bases):
+ # Implementation method: Produce an Implements interface with
+ # a fully fleshed out __name__ before calling the constructor, which
+ # sets bases to the given interfaces and which may pass this object to
+ # other objects (e.g., to adjust dependents). If they're sorting or comparing
+ # by name, this needs to be set.
+ inst = cls.__new__(cls)
+ inst.__name__ = name
+ inst.__init__(*bases)
+ return inst
+
+ def changed(self, originally_changed):
+ try:
+ del self._super_cache
+ except AttributeError:
+ pass
+ return super(Implements, self).changed(originally_changed)
+
+ def __repr__(self):
+ if self.inherit:
+ name = getattr(self.inherit, '__name__', None) or _implements_name(self.inherit)
+ else:
+ name = self.__name__
+ declared_names = self._argument_names_for_repr(self.declared)
+ if declared_names:
+ declared_names = ', ' + declared_names
+ return 'classImplements(%s%s)' % (name, declared_names)
+
+ def __reduce__(self):
+ return implementedBy, (self.inherit, )
+
+
+def _implements_name(ob):
+ # Return the __name__ attribute to be used by its __implemented__
+ # property.
+ # This must be stable for the "same" object across processes
+ # because it is used for sorting. It needn't be unique, though, in cases
+ # like nested classes named Foo created by different functions, because
+ # equality and hashing is still based on identity.
+ # It might be nice to use __qualname__ on Python 3, but that would produce
+ # different values between Py2 and Py3.
+ return (getattr(ob, '__module__', '?') or '?') + \
+ '.' + (getattr(ob, '__name__', '?') or '?')
+
+
+def _implementedBy_super(sup):
+ # TODO: This is now simple enough we could probably implement
+ # in C if needed.
+
+ # If the class MRO is strictly linear, we could just
+ # follow the normal algorithm for the next class in the
+ # search order (e.g., just return
+ # ``implemented_by_next``). But when diamond inheritance
+ # or mixins + interface declarations are present, we have
+ # to consider the whole MRO and compute a new Implements
+ # that excludes the classes being skipped over but
+ # includes everything else.
+ implemented_by_self = implementedBy(sup.__self_class__)
+ cache = implemented_by_self._super_cache # pylint:disable=protected-access
+ if cache is None:
+ cache = implemented_by_self._super_cache = weakref.WeakKeyDictionary()
+
+ key = sup.__thisclass__
+ try:
+ return cache[key]
+ except KeyError:
+ pass
+
+ next_cls = _next_super_class(sup)
+ # For ``implementedBy(cls)``:
+ # .__bases__ is .declared + [implementedBy(b) for b in cls.__bases__]
+ # .inherit is cls
+
+ implemented_by_next = implementedBy(next_cls)
+ mro = sup.__self_class__.__mro__
+ ix_next_cls = mro.index(next_cls)
+ classes_to_keep = mro[ix_next_cls:]
+ new_bases = [implementedBy(c) for c in classes_to_keep]
+
+ new = Implements.named(
+ implemented_by_self.__name__ + ':' + implemented_by_next.__name__,
+ *new_bases
+ )
+ new.inherit = implemented_by_next.inherit
+ new.declared = implemented_by_next.declared
+ # I don't *think* that new needs to subscribe to ``implemented_by_self``;
+ # it auto-subscribed to its bases, and that should be good enough.
+ cache[key] = new
+
+ return new
+
+
+@_use_c_impl
+def implementedBy(cls): # pylint:disable=too-many-return-statements,too-many-branches
+ """Return the interfaces implemented for a class' instances
+
+ The value returned is an `~zope.interface.interfaces.IDeclaration`.
+ """
+ try:
+ if isinstance(cls, super):
+ # Yes, this needs to be inside the try: block. Some objects
+ # like security proxies even break isinstance.
+ return _implementedBy_super(cls)
+
+ 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?
+ spec_name = _implements_name(cls)
+ if spec is not None:
+ # old-style __implemented__ = foo declaration
+ spec = (spec, ) # tuplefy, as it might be just an int
+ spec = Implements.named(spec_name, *_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.named(spec_name, *[implementedBy(c) for c in bases])
+ spec.inherit = cls
+
+ 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
+
+
+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 (`~zope.interface.interfaces.IDeclaration` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ replace any previous declarations, *including* inherited definitions. If you
+ wish to preserve inherited declarations, you can pass ``implementedBy(cls)``
+ in *interfaces*. This can be used to alter the interface resolution order.
+ """
+ spec = implementedBy(cls)
+ # Clear out everything inherited. It's important to
+ # also clear the bases right now so that we don't improperly discard
+ # interfaces that are already implemented by *old* bases that we're
+ # about to get rid of.
+ spec.declared = ()
+ spec.inherit = None
+ spec.__bases__ = ()
+ _classImplements_ordered(spec, 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 (`~zope.interface.interfaces.IDeclaration` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ are added to any interfaces previously declared. An effort is made to
+ keep a consistent C3 resolution order, but this cannot be guaranteed.
+
+ .. versionchanged:: 5.0.0
+ Each individual interface in *interfaces* may be added to either the
+ beginning or end of the list of interfaces declared for *cls*,
+ based on inheritance, in order to try to maintain a consistent
+ resolution order. Previously, all interfaces were added to the end.
+ .. versionchanged:: 5.1.0
+ If *cls* is already declared to implement an interface (or derived interface)
+ in *interfaces* through inheritance, the interface is ignored. Previously, it
+ would redundantly be made direct base of *cls*, which often produced inconsistent
+ interface resolution orders. Now, the order will be consistent, but may change.
+ Also, if the ``__bases__`` of the *cls* are later changed, the *cls* will no
+ longer be considered to implement such an interface (changing the ``__bases__`` of *cls*
+ has never been supported).
+ """
+ spec = implementedBy(cls)
+ interfaces = tuple(_normalizeargs(interfaces))
+
+ before = []
+ after = []
+
+ # Take steps to try to avoid producing an invalid resolution
+ # order, while still allowing for BWC (in the past, we always
+ # appended)
+ for iface in interfaces:
+ for b in spec.declared:
+ if iface.extends(b):
+ before.append(iface)
+ break
+ else:
+ after.append(iface)
+ _classImplements_ordered(spec, tuple(before), tuple(after))
+
+
+def classImplementsFirst(cls, iface):
+ """
+ Declare that instances of *cls* additionally provide *iface*.
+
+ The second argument is an interface or interface specification.
+ It is added as the highest priority (first in the IRO) interface;
+ no attempt is made to keep a consistent resolution order.
+
+ .. versionadded:: 5.0.0
+ """
+ spec = implementedBy(cls)
+ _classImplements_ordered(spec, (iface,), ())
+
+
+def _classImplements_ordered(spec, before=(), after=()):
+ # Elide everything already inherited.
+ # Except, if it is the root, and we don't already declare anything else
+ # that would imply it, allow the root through. (TODO: When we disallow non-strict
+ # IRO, this part of the check can be removed because it's not possible to re-declare
+ # like that.)
+ before = [
+ x
+ for x in before
+ if not spec.isOrExtends(x) or (x is Interface and not spec.declared)
+ ]
+ after = [
+ x
+ for x in after
+ if not spec.isOrExtends(x) or (x is Interface and not spec.declared)
+ ]
+
+ # eliminate duplicates
+ new_declared = []
+ seen = set()
+ for l in before, spec.declared, after:
+ for b in l:
+ if b not in seen:
+ new_declared.append(b)
+ seen.add(b)
+
+ spec.declared = tuple(new_declared)
+
+ # compute the bases
+ bases = new_declared # guaranteed no dupes
+
+ if spec.inherit is not None:
+ for c in spec.inherit.__bases__:
+ b = implementedBy(c)
+ if b not in seen:
+ seen.add(b)
+ bases.append(b)
+
+ spec.__bases__ = tuple(bases)
+
+
+def _implements_advice(cls):
+ interfaces, do_classImplements = cls.__dict__['__implements_advice_data__']
+ del cls.__implements_advice_data__
+ do_classImplements(cls, *interfaces)
+ return cls
+
+
+class implementer(object):
+ """
+ Declare the interfaces implemented by instances of a class.
+
+ This function is called as a class decorator.
+
+ The arguments are one or more interfaces or interface
+ specifications (`~zope.interface.interfaces.IDeclaration`
+ objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) are added to any interfaces previously declared,
+ unless the interface is already implemented.
+
+ 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::
+
+ @implementer(I1)
+ class C(object):
+ pass
+
+ is equivalent to calling::
+
+ classImplements(C, I1)
+
+ after the class has been created.
+
+ .. seealso:: `classImplements`
+ The change history provided there applies to this function too.
+ """
+ __slots__ = ('interfaces',)
+
+ def __init__(self, *interfaces):
+ self.interfaces = interfaces
+
+ def __call__(self, ob):
+ if isinstance(ob, DescriptorAwareMetaClasses):
+ # This is the common branch for new-style (object) and
+ # on Python 2 old-style classes.
+ classImplements(ob, *self.interfaces)
+ return ob
+
+ spec_name = _implements_name(ob)
+ spec = Implements.named(spec_name, *self.interfaces)
+ try:
+ ob.__implemented__ = spec
+ except AttributeError:
+ raise TypeError("Can't declare implements", ob)
+ return ob
+
+class implementer_only(object):
+ """Declare the only interfaces implemented by instances of a class
+
+ This function is called as a class decorator.
+
+ The arguments are one or more interfaces or interface
+ specifications (`~zope.interface.interfaces.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::
+
+ @implementer_only(I1)
+ class C(object): pass
+
+ is equivalent to calling::
+
+ classImplementsOnly(I1)
+
+ after the class has been created.
+ """
+
+ 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 or function....
+ raise ValueError('The implementer_only decorator is not '
+ 'supported for methods or functions.')
+
+ # Assume it's a class:
+ classImplementsOnly(ob, *self.interfaces)
+ return ob
+
+def _implements(name, interfaces, do_classImplements):
+ # This entire approach is invalid under Py3K. Don't even try to fix
+ # the coverage for this block there. :(
+ frame = sys._getframe(2) # pylint:disable=protected-access
+ locals = frame.f_locals # pylint:disable=redefined-builtin
+
+ # 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:
+ 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, do_classImplements
+ addClassAdvisor(_implements_advice, depth=3)
+
+def implements(*interfaces):
+ """
+ Declare interfaces implemented by instances of a class.
+
+ .. deprecated:: 5.0
+ This only works for Python 2. The `implementer` decorator
+ is preferred for all versions.
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (`~zope.interface.interfaces.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.
+ """
+ # This entire approach is invalid under Py3K. Don't even try to fix
+ # the coverage for this block there. :(
+ if PYTHON3:
+ raise TypeError(_ADVICE_ERROR % 'implementer')
+ _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 (`~zope.interface.interfaces.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.
+ """
+ # This entire approach is invalid under Py3K. Don't even try to fix
+ # the coverage for this block there. :(
+ if PYTHON3:
+ raise TypeError(_ADVICE_ERROR % 'implementer_only')
+ _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, *self._add_interfaces_to_cls(interfaces, cls))
+
+ # Added to by ``moduleProvides``, et al
+ _v_module_names = ()
+
+ def __repr__(self):
+ # The typical way to create instances of this
+ # object is via calling ``directlyProvides(...)`` or ``alsoProvides()``,
+ # but that's not the only way. Proxies, for example,
+ # directly use the ``Provides(...)`` function (which is the
+ # more generic method, and what we pickle as). We're after the most
+ # readable, useful repr in the common case, so we use the most
+ # common name.
+ #
+ # We also cooperate with ``moduleProvides`` to attempt to do the
+ # right thing for that API. See it for details.
+ function_name = 'directlyProvides'
+ if self._cls is ModuleType and self._v_module_names:
+ # See notes in ``moduleProvides``/``directlyProvides``
+ providing_on_module = True
+ interfaces = self.__args[1:]
+ else:
+ providing_on_module = False
+ interfaces = (self._cls,) + self.__bases__
+ ordered_names = self._argument_names_for_repr(interfaces)
+ if providing_on_module:
+ mod_names = self._v_module_names
+ if len(mod_names) == 1:
+ mod_names = "sys.modules[%r]" % mod_names[0]
+ ordered_names = (
+ '%s, ' % (mod_names,)
+ ) + ordered_names
+ return "%s(%s)" % (
+ function_name,
+ ordered_names,
+ )
+
+ def __reduce__(self):
+ # This reduces to the Provides *function*, not
+ # this class.
+ return Provides, self.__args
+
+ __module__ = 'zope.interface'
+
+ def __get__(self, inst, cls):
+ """Make sure that a class __provides__ doesn't leak to an instance
+ """
+ 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): # pylint:disable=function-redefined
+ """Cache instance declarations
+
+ Instance declarations are shared among instances that have the same
+ declaration. The declarations are cached in a weak value dictionary.
+ """
+ spec = InstanceDeclarations.get(interfaces)
+ if spec is None:
+ spec = ProvidesClass(*interfaces)
+ InstanceDeclarations[interfaces] = spec
+
+ return spec
+
+Provides.__safe_for_unpickling__ = True
+
+
+def directlyProvides(object, *interfaces): # pylint:disable=redefined-builtin
+ """Declare interfaces declared directly for an object
+
+ The arguments after the object are one or more interfaces or interface
+ specifications (`~zope.interface.interfaces.IDeclaration` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ replace interfaces previously declared for the object.
+ """
+ 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)
+ # Note that we can't get here from Py3k tests: there is no normal
+ # class which isn't descriptor aware.
+ 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:
+ provides = object.__provides__ = Provides(cls, *interfaces)
+ # See notes in ``moduleProvides``.
+ if issubclass(cls, ModuleType) and hasattr(object, '__name__'):
+ provides._v_module_names += (object.__name__,)
+
+
+
+def alsoProvides(object, *interfaces): # pylint:disable=redefined-builtin
+ """Declare interfaces declared directly for an object
+
+ The arguments after the object are one or more interfaces or interface
+ specifications (`~zope.interface.interfaces.IDeclaration` objects).
+
+ The interfaces given (including the interfaces in the specifications) are
+ added to the interfaces previously declared for the object.
+ """
+ directlyProvides(object, directlyProvidedBy(object), *interfaces)
+
+
+def noLongerProvides(object, interface): # pylint:disable=redefined-builtin
+ """ Removes a directly provided interface from an object.
+ """
+ directlyProvides(object, directlyProvidedBy(object) - interface)
+ if interface.providedBy(object):
+ raise ValueError("Can only remove directly provided interfaces.")
+
+
+@_use_c_impl
+class ClassProvidesBase(SpecificationBase):
+
+ __slots__ = (
+ '_cls',
+ '_implements',
+ )
+
+ def __get__(self, inst, cls):
+ # member slots are set by subclass
+ # pylint:disable=no-member
+ 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__')
+
+
+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.
+ """
+
+ __slots__ = (
+ '__args',
+ )
+
+ def __init__(self, cls, metacls, *interfaces):
+ self._cls = cls
+ self._implements = implementedBy(cls)
+ self.__args = (cls, metacls, ) + interfaces
+ Declaration.__init__(self, *self._add_interfaces_to_cls(interfaces, metacls))
+
+ def __repr__(self):
+ # There are two common ways to get instances of this object:
+ # The most interesting way is calling ``@provider(..)`` as a decorator
+ # of a class; this is the same as calling ``directlyProvides(cls, ...)``.
+ #
+ # The other way is by default: anything that invokes ``implementedBy(x)``
+ # will wind up putting an instance in ``type(x).__provides__``; this includes
+ # the ``@implementer(...)`` decorator. Those instances won't have any
+ # interfaces.
+ #
+ # Thus, as our repr, we go with the ``directlyProvides()`` syntax.
+ interfaces = (self._cls, ) + self.__args[2:]
+ ordered_names = self._argument_names_for_repr(interfaces)
+ return "directlyProvides(%s)" % (ordered_names,)
+
+ def __reduce__(self):
+ return self.__class__, self.__args
+
+ # Copy base-class method for speed
+ __get__ = ClassProvidesBase.__get__
+
+
+def directlyProvidedBy(object): # pylint:disable=redefined-builtin
+ """Return the interfaces directly provided by the given object
+
+ The value returned is an `~zope.interface.interfaces.IDeclaration`.
+ """
+ provides = getattr(object, "__provides__", None)
+ if (
+ provides is None # no spec
+ # 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:
+ or 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
+ (`~zope.interface.interfaces.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.
+ """
+ # This entire approach is invalid under Py3K. Don't even try to fix
+ # the coverage for this block there. :(
+
+ if PYTHON3:
+ raise TypeError(_ADVICE_ERROR % 'provider')
+
+ frame = sys._getframe(1) # pylint:disable=protected-access
+ locals = frame.f_locals # pylint:disable=redefined-builtin
+
+ # 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):
+ # This entire approach is invalid under Py3K. Don't even try to fix
+ # the coverage for this block there. :(
+ interfaces = cls.__dict__['__provides__']
+ del cls.__provides__
+ directlyProvides(cls, *interfaces)
+ return cls
+
+
+class provider(object):
+ """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
+ (`~zope.interface.interfaces.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::
+
+ moduleProvides(I1)
+
+ is equivalent to::
+
+ directlyProvides(sys.modules[__name__], I1)
+ """
+ frame = sys._getframe(1) # pylint:disable=protected-access
+ locals = frame.f_locals # pylint:disable=redefined-builtin
+
+ # Try to make sure we were called from a module body
+ 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.")
+
+ # Note: This is cached based on the key ``(ModuleType, *interfaces)``;
+ # One consequence is that any module that provides the same interfaces
+ # gets the same ``__repr__``, meaning that you can't tell what module
+ # such a declaration came from. Adding the module name to ``_v_module_names``
+ # attempts to correct for this; it works in some common situations, but fails
+ # (1) after pickling (the data is lost) and (2) if declarations are
+ # actually shared and (3) if the alternate spelling of ``directlyProvides()``
+ # is used. Problem (3) is fixed by cooperating with ``directlyProvides``
+ # to maintain this information, and problem (2) is worked around by
+ # printing all the names, but (1) is unsolvable without introducing
+ # new classes or changing the stored data...but it doesn't actually matter,
+ # because ``ModuleType`` can't be pickled!
+ p = locals["__provides__"] = Provides(ModuleType,
+ *_normalizeargs(interfaces))
+ p._v_module_names += (locals['__name__'],)
+
+
+##############################################################################
+#
+# Declaration querying support
+
+# XXX: is this a fossil? Nobody calls it, no unit tests exercise it, no
+# doctests import it, and the package __init__ doesn't import it.
+# (Answer: Versions of zope.container prior to 4.4.0 called this,
+# and zope.proxy.decorator up through at least 4.3.5 called this.)
+def ObjectSpecification(direct, cls):
+ """Provide object specifications
+
+ These combine information for the object and for it's classes.
+ """
+ return Provides(cls, direct) # pragma: no cover fossil
+
+@_use_c_impl
+def getObjectSpecification(ob):
+ try:
+ provides = ob.__provides__
+ except AttributeError:
+ 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)
+
+
+@_use_c_impl
+def providedBy(ob):
+ """
+ Return the interfaces provided by *ob*.
+
+ If *ob* is a :class:`super` object, then only interfaces implemented
+ by the remainder of the classes in the method resolution order are
+ considered. Interfaces directly provided by the object underlying *ob*
+ are not.
+ """
+ # Here we have either a special object, an old-style declaration
+ # or a descriptor
+
+ # Try to get __providedBy__
+ try:
+ if isinstance(ob, super): # Some objects raise errors on isinstance()
+ return implementedBy(ob)
+
+ 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
+
+
+@_use_c_impl
+class ObjectSpecificationDescriptor(object):
+ """Implement the ``__providedBy__`` attribute
+
+ The ``__providedBy__`` attribute computes the interfaces provided by
+ an object. If an object has an ``__provides__`` attribute, that is returned.
+ Otherwise, `implementedBy` the *cls* is returned.
+
+ .. versionchanged:: 5.4.0
+ Both the default (C) implementation and the Python implementation
+ now let exceptions raised by accessing ``__provides__`` propagate.
+ Previously, the C version ignored all exceptions.
+ .. versionchanged:: 5.4.0
+ The Python implementation now matches the C implementation and lets
+ a ``__provides__`` of ``None`` override what the class is declared to
+ implement.
+ """
+
+ def __get__(self, inst, cls):
+ """Get an object specification for an object
+ """
+ if inst is None:
+ return getObjectSpecification(cls)
+
+ try:
+ return inst.__provides__
+ except AttributeError:
+ return implementedBy(cls)
+
+
+##############################################################################
+
+def _normalizeargs(sequence, output=None):
+ """Normalize declaration arguments
+
+ Normalization arguments might contain Declarions, tuples, or single
+ interfaces.
+
+ Anything but individual 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 = _ImmutableDeclaration()
+
+objectSpecificationDescriptor = ObjectSpecificationDescriptor()
diff --git a/contrib/python/zope.interface/py2/zope/interface/document.py b/contrib/python/zope.interface/py2/zope/interface/document.py
new file mode 100644
index 0000000000..309bb575ee
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/document.py
@@ -0,0 +1,124 @@
+##############################################################################
+#
+# 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
+
+__all__ = [
+ 'asReStructuredText',
+ 'asStructuredText',
+]
+
+def asStructuredText(I, munge=0, rst=False):
+ """ Output structured text format. Note, this will whack any existing
+ 'structured' format of the text.
+
+ If `rst=True`, then the output will quote all code as inline literals in
+ accordance with 'reStructuredText' markup principles.
+ """
+
+ if rst:
+ inline_literal = lambda s: "``%s``" % (s,)
+ else:
+ inline_literal = lambda s: s
+
+ r = [inline_literal(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" % inline_literal(b.getName())
+ outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+ level -= 1
+
+ namesAndDescriptions = sorted(I.namesAndDescriptions())
+
+ outp(_justify_and_indent("Attributes:", level, munge))
+ level += 1
+ for name, desc in namesAndDescriptions:
+ if not hasattr(desc, 'getSignatureString'): # ugh...
+ item = "%s -- %s" % (inline_literal(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...
+ _call = "%s%s" % (desc.getName(), desc.getSignatureString())
+ item = "%s -- %s" % (inline_literal(_call),
+ desc.getDoc() or 'no documentation')
+ outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+
+ return "\n\n".join(r) + "\n\n"
+
+
+def asReStructuredText(I, munge=0):
+ """ Output reStructuredText format. Note, this will whack any existing
+ 'structured' format of the text."""
+ return asStructuredText(I, munge=munge, rst=True)
+
+
+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/contrib/python/zope.interface/py2/zope/interface/exceptions.py b/contrib/python/zope.interface/py2/zope/interface/exceptions.py
new file mode 100644
index 0000000000..47c351b25f
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/exceptions.py
@@ -0,0 +1,275 @@
+##############################################################################
+#
+# 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
+"""
+
+__all__ = [
+ # Invalid tree
+ 'Invalid',
+ 'DoesNotImplement',
+ 'BrokenImplementation',
+ 'BrokenMethodImplementation',
+ 'MultipleInvalid',
+ # Other
+ 'BadImplements',
+ 'InvalidInterface',
+]
+
+class Invalid(Exception):
+ """A specification is violated
+ """
+
+
+class _TargetInvalid(Invalid):
+ # Internal use. Subclass this when you're describing
+ # a particular target object that's invalid according
+ # to a specific interface.
+ #
+ # For backwards compatibility, the *target* and *interface* are
+ # optional, and the signatures are inconsistent in their ordering.
+ #
+ # We deal with the inconsistency in ordering by defining the index
+ # of the two values in ``self.args``. *target* uses a marker object to
+ # distinguish "not given" from "given, but None", because the latter
+ # can be a value that gets passed to validation. For this reason, it must
+ # always be the last argument (we detect absence by the ``IndexError``).
+
+ _IX_INTERFACE = 0
+ _IX_TARGET = 1
+ # The exception to catch when indexing self.args indicating that
+ # an argument was not given. If all arguments are expected,
+ # a subclass should set this to ().
+ _NOT_GIVEN_CATCH = IndexError
+ _NOT_GIVEN = '<Not Given>'
+
+ def _get_arg_or_default(self, ix, default=None):
+ try:
+ return self.args[ix] # pylint:disable=unsubscriptable-object
+ except self._NOT_GIVEN_CATCH:
+ return default
+
+ @property
+ def interface(self):
+ return self._get_arg_or_default(self._IX_INTERFACE)
+
+ @property
+ def target(self):
+ return self._get_arg_or_default(self._IX_TARGET, self._NOT_GIVEN)
+
+ ###
+ # str
+ #
+ # The ``__str__`` of self is implemented by concatenating (%s), in order,
+ # these properties (none of which should have leading or trailing
+ # whitespace):
+ #
+ # - self._str_subject
+ # Begin the message, including a description of the target.
+ # - self._str_description
+ # Provide a general description of the type of error, including
+ # the interface name if possible and relevant.
+ # - self._str_conjunction
+ # Join the description to the details. Defaults to ": ".
+ # - self._str_details
+ # Provide details about how this particular instance of the error.
+ # - self._str_trailer
+ # End the message. Usually just a period.
+ ###
+
+ @property
+ def _str_subject(self):
+ target = self.target
+ if target is self._NOT_GIVEN:
+ return "An object"
+ return "The object %r" % (target,)
+
+ @property
+ def _str_description(self):
+ return "has failed to implement interface %s" % (
+ self.interface or '<Unknown>'
+ )
+
+ _str_conjunction = ": "
+ _str_details = "<unknown>"
+ _str_trailer = '.'
+
+ def __str__(self):
+ return "%s %s%s%s%s" % (
+ self._str_subject,
+ self._str_description,
+ self._str_conjunction,
+ self._str_details,
+ self._str_trailer
+ )
+
+
+class DoesNotImplement(_TargetInvalid):
+ """
+ DoesNotImplement(interface[, target])
+
+ The *target* (optional) does not implement the *interface*.
+
+ .. versionchanged:: 5.0.0
+ Add the *target* argument and attribute, and change the resulting
+ string value of this object accordingly.
+ """
+
+ _str_details = "Does not declaratively implement the interface"
+
+
+class BrokenImplementation(_TargetInvalid):
+ """
+ BrokenImplementation(interface, name[, target])
+
+ The *target* (optional) is missing the attribute *name*.
+
+ .. versionchanged:: 5.0.0
+ Add the *target* argument and attribute, and change the resulting
+ string value of this object accordingly.
+
+ The *name* can either be a simple string or a ``Attribute`` object.
+ """
+
+ _IX_NAME = _TargetInvalid._IX_INTERFACE + 1
+ _IX_TARGET = _IX_NAME + 1
+
+ @property
+ def name(self):
+ return self.args[1] # pylint:disable=unsubscriptable-object
+
+ @property
+ def _str_details(self):
+ return "The %s attribute was not provided" % (
+ repr(self.name) if isinstance(self.name, str) else self.name
+ )
+
+
+class BrokenMethodImplementation(_TargetInvalid):
+ """
+ BrokenMethodImplementation(method, message[, implementation, interface, target])
+
+ The *target* (optional) has a *method* in *implementation* that violates
+ its contract in a way described by *mess*.
+
+ .. versionchanged:: 5.0.0
+ Add the *interface* and *target* argument and attribute,
+ and change the resulting string value of this object accordingly.
+
+ The *method* can either be a simple string or a ``Method`` object.
+
+ .. versionchanged:: 5.0.0
+ If *implementation* is given, then the *message* will have the
+ string "implementation" replaced with an short but informative
+ representation of *implementation*.
+
+ """
+
+ _IX_IMPL = 2
+ _IX_INTERFACE = _IX_IMPL + 1
+ _IX_TARGET = _IX_INTERFACE + 1
+
+ @property
+ def method(self):
+ return self.args[0] # pylint:disable=unsubscriptable-object
+
+ @property
+ def mess(self):
+ return self.args[1] # pylint:disable=unsubscriptable-object
+
+ @staticmethod
+ def __implementation_str(impl):
+ # It could be a callable or some arbitrary object, we don't
+ # know yet.
+ import inspect # Inspect is a heavy-weight dependency, lots of imports
+ try:
+ sig = inspect.signature
+ formatsig = str
+ except AttributeError:
+ sig = inspect.getargspec
+ f = inspect.formatargspec
+ formatsig = lambda sig: f(*sig) # pylint:disable=deprecated-method
+
+ try:
+ sig = sig(impl)
+ except (ValueError, TypeError):
+ # Unable to introspect. Darn.
+ # This could be a non-callable, or a particular builtin,
+ # or a bound method that doesn't even accept 'self', e.g.,
+ # ``Class.method = lambda: None; Class().method``
+ return repr(impl)
+
+ try:
+ name = impl.__qualname__
+ except AttributeError:
+ name = impl.__name__
+
+ return name + formatsig(sig)
+
+ @property
+ def _str_details(self):
+ impl = self._get_arg_or_default(self._IX_IMPL, self._NOT_GIVEN)
+ message = self.mess
+ if impl is not self._NOT_GIVEN and 'implementation' in message:
+ message = message.replace("implementation", '%r')
+ message = message % (self.__implementation_str(impl),)
+
+ return 'The contract of %s is violated because %s' % (
+ repr(self.method) if isinstance(self.method, str) else self.method,
+ message,
+ )
+
+
+class MultipleInvalid(_TargetInvalid):
+ """
+ The *target* has failed to implement the *interface* in
+ multiple ways.
+
+ The failures are described by *exceptions*, a collection of
+ other `Invalid` instances.
+
+ .. versionadded:: 5.0
+ """
+
+ _NOT_GIVEN_CATCH = ()
+
+ def __init__(self, interface, target, exceptions):
+ super(MultipleInvalid, self).__init__(interface, target, tuple(exceptions))
+
+ @property
+ def exceptions(self):
+ return self.args[2] # pylint:disable=unsubscriptable-object
+
+ @property
+ def _str_details(self):
+ # It would be nice to use tabs here, but that
+ # is hard to represent in doctests.
+ return '\n ' + '\n '.join(
+ x._str_details.strip() if isinstance(x, _TargetInvalid) else str(x)
+ for x in self.exceptions
+ )
+
+ _str_conjunction = ':' # We don't want a trailing space, messes up doctests
+ _str_trailer = ''
+
+
+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/contrib/python/zope.interface/py2/zope/interface/interface.py b/contrib/python/zope.interface/py2/zope/interface/interface.py
new file mode 100644
index 0000000000..74476418b7
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/interface.py
@@ -0,0 +1,1153 @@
+##############################################################################
+#
+# 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
+"""
+# pylint:disable=protected-access
+import sys
+from types import MethodType
+from types import FunctionType
+import weakref
+
+from zope.interface._compat import _use_c_impl
+from zope.interface._compat import PYTHON2 as PY2
+from zope.interface.exceptions import Invalid
+from zope.interface.ro import ro as calculate_ro
+from zope.interface import ro
+
+__all__ = [
+ # Most of the public API from this module is directly exported
+ # from zope.interface. The only remaining public API intended to
+ # be imported from here should be those few things documented as
+ # such.
+ 'InterfaceClass',
+ 'Specification',
+ 'adapter_hooks',
+]
+
+CO_VARARGS = 4
+CO_VARKEYWORDS = 8
+# Put in the attrs dict of an interface by ``taggedValue`` and ``invariants``
+TAGGED_DATA = '__interface_tagged_values__'
+# Put in the attrs dict of an interface by ``interfacemethod``
+INTERFACE_METHODS = '__interface_methods__'
+
+_decorator_non_return = object()
+_marker = 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):
+ """
+ Default implementation of `zope.interface.interfaces.IElement`.
+ """
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ #implements(IElement)
+
+ def __init__(self, __name__, __doc__=''): # pylint:disable=redefined-builtin
+ if not __doc__ and __name__.find(' ') >= 0:
+ __doc__ = __name__
+ __name__ = None
+
+ self.__name__ = __name__
+ self.__doc__ = __doc__
+ # Tagged values are rare, especially on methods or attributes.
+ # Deferring the allocation can save substantial memory.
+ self.__tagged_values = None
+
+ def getName(self):
+ """ Returns the name of the object. """
+ return self.__name__
+
+ def getDoc(self):
+ """ Returns the documentation for the object. """
+ return self.__doc__
+
+ ###
+ # Tagged values.
+ #
+ # Direct tagged values are set only in this instance. Others
+ # may be inherited (for those subclasses that have that concept).
+ ###
+
+ def getTaggedValue(self, tag):
+ """ Returns the value associated with 'tag'. """
+ if not self.__tagged_values:
+ raise KeyError(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) if self.__tagged_values else default
+
+ def getTaggedValueTags(self):
+ """ Returns a collection of all tags. """
+ return self.__tagged_values.keys() if self.__tagged_values else ()
+
+ def setTaggedValue(self, tag, value):
+ """ Associates 'value' with 'key'. """
+ if self.__tagged_values is None:
+ self.__tagged_values = {}
+ self.__tagged_values[tag] = value
+
+ queryDirectTaggedValue = queryTaggedValue
+ getDirectTaggedValue = getTaggedValue
+ getDirectTaggedValueTags = getTaggedValueTags
+
+
+SpecificationBasePy = object # filled by _use_c_impl.
+
+
+@_use_c_impl
+class SpecificationBase(object):
+ # This object is the base of the inheritance hierarchy for ClassProvides:
+ #
+ # ClassProvides < ClassProvidesBase, Declaration
+ # Declaration < Specification < SpecificationBase
+ # ClassProvidesBase < SpecificationBase
+ #
+ # In order to have compatible instance layouts, we need to declare
+ # the storage used by Specification and Declaration here (and
+ # those classes must have ``__slots__ = ()``); fortunately this is
+ # not a waste of space because those are the only two inheritance
+ # trees. These all translate into tp_members in C.
+ __slots__ = (
+ # Things used here.
+ '_implied',
+ # Things used in Specification.
+ '_dependents',
+ '_bases',
+ '_v_attrs',
+ '__iro__',
+ '__sro__',
+ '__weakref__',
+ )
+
+ def providedBy(self, ob):
+ """Is the interface implemented by an object
+ """
+ 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
+ """
+ return interface in self._implied # pylint:disable=no-member
+
+ __call__ = isOrExtends
+
+
+class NameAndModuleComparisonMixin(object):
+ # Internal use. Implement the basic sorting operators (but not (in)equality
+ # or hashing). Subclasses must provide ``__name__`` and ``__module__``
+ # attributes. Subclasses will be mutually comparable; but because equality
+ # and hashing semantics are missing from this class, take care in how
+ # you define those two attributes: If you stick with the default equality
+ # and hashing (identity based) you should make sure that all possible ``__name__``
+ # and ``__module__`` pairs are unique ACROSS ALL SUBCLASSES. (Actually, pretty
+ # much the same thing goes if you define equality and hashing to be based on
+ # those two attributes: they must still be consistent ACROSS ALL SUBCLASSES.)
+
+ # pylint:disable=assigning-non-slot
+ __slots__ = ()
+
+ def _compare(self, other):
+ """
+ Compare *self* to *other* based on ``__name__`` and ``__module__``.
+
+ Return 0 if they are equal, return 1 if *self* is
+ greater than *other*, and return -1 if *self* is less than
+ *other*.
+
+ If *other* does not have ``__name__`` or ``__module__``, then
+ return ``NotImplemented``.
+
+ .. caution::
+ This allows comparison to things well outside the type hierarchy,
+ perhaps not symmetrically.
+
+ For example, ``class Foo(object)`` and ``class Foo(Interface)``
+ in the same file would compare equal, depending on the order of
+ operands. Writing code like this by hand would be unusual, but it could
+ happen with dynamic creation of types and interfaces.
+
+ None is treated as a pseudo interface that implies the loosest
+ contact possible, no contract. For that reason, all interfaces
+ sort before None.
+ """
+ if other is self:
+ return 0
+
+ if other is None:
+ return -1
+
+ n1 = (self.__name__, self.__module__)
+ try:
+ n2 = (other.__name__, other.__module__)
+ except AttributeError:
+ return NotImplemented
+
+ # This spelling works under Python3, which doesn't have cmp().
+ return (n1 > n2) - (n1 < n2)
+
+ def __lt__(self, other):
+ c = self._compare(other)
+ if c is NotImplemented:
+ return c
+ return c < 0
+
+ def __le__(self, other):
+ c = self._compare(other)
+ if c is NotImplemented:
+ return c
+ return c <= 0
+
+ def __gt__(self, other):
+ c = self._compare(other)
+ if c is NotImplemented:
+ return c
+ return c > 0
+
+ def __ge__(self, other):
+ c = self._compare(other)
+ if c is NotImplemented:
+ return c
+ return c >= 0
+
+
+@_use_c_impl
+class InterfaceBase(NameAndModuleComparisonMixin, SpecificationBasePy):
+ """Base class that wants to be replaced with a C base :)
+ """
+
+ __slots__ = (
+ '__name__',
+ '__ibmodule__',
+ '_v_cached_hash',
+ )
+
+ def __init__(self, name=None, module=None):
+ self.__name__ = name
+ self.__ibmodule__ = module
+
+ def _call_conform(self, conform):
+ raise NotImplementedError
+
+ @property
+ def __module_property__(self):
+ # This is for _InterfaceMetaClass
+ return self.__ibmodule__
+
+ def __call__(self, obj, alternate=_marker):
+ """Adapt an object to the interface
+ """
+ try:
+ conform = obj.__conform__
+ except AttributeError:
+ 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
+ if alternate is not _marker:
+ return alternate
+ raise TypeError("Could not adapt", obj, self)
+
+ def __adapt__(self, obj):
+ """Adapt an object to the receiver
+ """
+ if self.providedBy(obj):
+ return obj
+
+ for hook in adapter_hooks:
+ adapter = hook(self, obj)
+ if adapter is not None:
+ return adapter
+
+ return None
+
+ def __hash__(self):
+ # pylint:disable=assigning-non-slot,attribute-defined-outside-init
+ try:
+ return self._v_cached_hash
+ except AttributeError:
+ self._v_cached_hash = hash((self.__name__, self.__module__))
+ return self._v_cached_hash
+
+ def __eq__(self, other):
+ c = self._compare(other)
+ if c is NotImplemented:
+ return c
+ return c == 0
+
+ def __ne__(self, other):
+ if other is self:
+ return False
+
+ c = self._compare(other)
+ if c is NotImplemented:
+ return c
+ return c != 0
+
+adapter_hooks = _use_c_impl([], 'adapter_hooks')
+
+
+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 bases, their
+ relations with other specifications are adjusted accordingly.
+ """
+ __slots__ = ()
+
+ # The root of all Specifications. This will be assigned `Interface`,
+ # once it is defined.
+ _ROOT = None
+
+ # Copy some base class methods for speed
+ isOrExtends = SpecificationBase.isOrExtends
+ providedBy = SpecificationBase.providedBy
+
+ def __init__(self, bases=()):
+ # There are many leaf interfaces with no dependents,
+ # and a few with very many. It's a heavily left-skewed
+ # distribution. In a survey of Plone and Zope related packages
+ # that loaded 2245 InterfaceClass objects and 2235 ClassProvides
+ # instances, there were a total of 7000 Specification objects created.
+ # 4700 had 0 dependents, 1400 had 1, 382 had 2 and so on. Only one
+ # for <type> had 1664. So there's savings to be had deferring
+ # the creation of dependents.
+ self._dependents = None # type: weakref.WeakKeyDictionary
+ self._bases = ()
+ self._implied = {}
+ self._v_attrs = None
+ self.__iro__ = ()
+ self.__sro__ = ()
+
+ self.__bases__ = tuple(bases)
+
+ @property
+ def dependents(self):
+ if self._dependents is None:
+ self._dependents = weakref.WeakKeyDictionary()
+ return self._dependents
+
+ def subscribe(self, dependent):
+ self._dependents[dependent] = self.dependents.get(dependent, 0) + 1
+
+ def unsubscribe(self, dependent):
+ try:
+ n = self._dependents[dependent]
+ except TypeError:
+ raise KeyError(dependent)
+ n -= 1
+ if not n:
+ del self.dependents[dependent]
+ else:
+ assert n > 0
+ self.dependents[dependent] = n
+
+ def __setBases(self, bases):
+ # Remove ourselves as a dependent of our old bases
+ for b in self.__bases__:
+ b.unsubscribe(self)
+
+ # Register ourselves as a dependent of our new bases
+ self._bases = bases
+ for b in bases:
+ b.subscribe(self)
+
+ self.changed(self)
+
+ __bases__ = property(
+ lambda self: self._bases,
+ __setBases,
+ )
+
+ # This method exists for tests to override the way we call
+ # ro.calculate_ro(), usually by adding extra kwargs. We don't
+ # want to have a mutable dictionary as a class member that we pass
+ # ourself because mutability is bad, and passing **kw is slower than
+ # calling the bound function.
+ _do_calculate_ro = calculate_ro
+
+ def _calculate_sro(self):
+ """
+ Calculate and return the resolution order for this object, using its ``__bases__``.
+
+ Ensures that ``Interface`` is always the last (lowest priority) element.
+ """
+ # We'd like to make Interface the lowest priority as a
+ # property of the resolution order algorithm. That almost
+ # works out naturally, but it fails when class inheritance has
+ # some bases that DO implement an interface, and some that DO
+ # NOT. In such a mixed scenario, you wind up with a set of
+ # bases to consider that look like this: [[..., Interface],
+ # [..., object], ...]. Depending on the order of inheritance,
+ # Interface can wind up before or after object, and that can
+ # happen at any point in the tree, meaning Interface can wind
+ # up somewhere in the middle of the order. Since Interface is
+ # treated as something that everything winds up implementing
+ # anyway (a catch-all for things like adapters), having it high up
+ # the order is bad. It's also bad to have it at the end, just before
+ # some concrete class: concrete classes should be HIGHER priority than
+ # interfaces (because there's only one class, but many implementations).
+ #
+ # One technically nice way to fix this would be to have
+ # ``implementedBy(object).__bases__ = (Interface,)``
+ #
+ # But: (1) That fails for old-style classes and (2) that causes
+ # everything to appear to *explicitly* implement Interface, when up
+ # to this point it's been an implicit virtual sort of relationship.
+ #
+ # So we force the issue by mutating the resolution order.
+
+ # Note that we let C3 use pre-computed __sro__ for our bases.
+ # This requires that by the time this method is invoked, our bases
+ # have settled their SROs. Thus, ``changed()`` must first
+ # update itself before telling its descendents of changes.
+ sro = self._do_calculate_ro(base_mros={
+ b: b.__sro__
+ for b in self.__bases__
+ })
+ root = self._ROOT
+ if root is not None and sro and sro[-1] is not root:
+ # In one dataset of 1823 Interface objects, 1117 ClassProvides objects,
+ # sro[-1] was root 4496 times, and only not root 118 times. So it's
+ # probably worth checking.
+
+ # Once we don't have to deal with old-style classes,
+ # we can add a check and only do this if base_count > 1,
+ # if we tweak the bootstrapping for ``<implementedBy object>``
+ sro = [
+ x
+ for x in sro
+ if x is not root
+ ]
+ sro.append(root)
+
+ return sro
+
+ def changed(self, originally_changed):
+ """
+ We, or something we depend on, have changed.
+
+ By the time this is called, the things we depend on,
+ such as our bases, should themselves be stable.
+ """
+ self._v_attrs = None
+
+ implied = self._implied
+ implied.clear()
+
+ ancestors = self._calculate_sro()
+ 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
+ # (being careful not to create the WeakKeyDictionary if not needed):
+ for dependent in tuple(self._dependents.keys() if self._dependents else ()):
+ dependent.changed(originally_changed)
+
+ # Just in case something called get() at some point
+ # during that process and we have a cycle of some sort
+ # make sure we didn't cache incomplete results.
+ self._v_attrs = None
+
+ def interfaces(self):
+ """Return an iterator for the interfaces in the specification.
+ """
+ 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
+ """
+ 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
+ """
+ attrs = self._v_attrs
+ if attrs is None:
+ 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
+
+ return default if attr is None else attr
+
+
+class _InterfaceMetaClass(type):
+ # Handling ``__module__`` on ``InterfaceClass`` is tricky. We need
+ # to be able to read it on a type and get the expected string. We
+ # also need to be able to set it on an instance and get the value
+ # we set. So far so good. But what gets tricky is that we'd like
+ # to store the value in the C structure (``InterfaceBase.__ibmodule__``) for
+ # direct access during equality, sorting, and hashing. "No
+ # problem, you think, I'll just use a property" (well, the C
+ # equivalents, ``PyMemberDef`` or ``PyGetSetDef``).
+ #
+ # Except there is a problem. When a subclass is created, the
+ # metaclass (``type``) always automatically puts the expected
+ # string in the class's dictionary under ``__module__``, thus
+ # overriding the property inherited from the superclass. Writing
+ # ``Subclass.__module__`` still works, but
+ # ``Subclass().__module__`` fails.
+ #
+ # There are multiple ways to work around this:
+ #
+ # (1) Define ``InterfaceBase.__getattribute__`` to watch for
+ # ``__module__`` and return the C storage.
+ #
+ # This works, but slows down *all* attribute access (except,
+ # ironically, to ``__module__``) by about 25% (40ns becomes 50ns)
+ # (when implemented in C). Since that includes methods like
+ # ``providedBy``, that's probably not acceptable.
+ #
+ # All the other methods involve modifying subclasses. This can be
+ # done either on the fly in some cases, as instances are
+ # constructed, or by using a metaclass. These next few can be done on the fly.
+ #
+ # (2) Make ``__module__`` a descriptor in each subclass dictionary.
+ # It can't be a straight up ``@property`` descriptor, though, because accessing
+ # it on the class returns a ``property`` object, not the desired string.
+ #
+ # (3) Implement a data descriptor (``__get__`` and ``__set__``)
+ # that is both a subclass of string, and also does the redirect of
+ # ``__module__`` to ``__ibmodule__`` and does the correct thing
+ # with the ``instance`` argument to ``__get__`` is None (returns
+ # the class's value.) (Why must it be a subclass of string? Because
+ # when it' s in the class's dict, it's defined on an *instance* of the
+ # metaclass; descriptors in an instance's dict aren't honored --- their
+ # ``__get__`` is never invoked --- so it must also *be* the value we want
+ # returned.)
+ #
+ # This works, preserves the ability to read and write
+ # ``__module__``, and eliminates any penalty accessing other
+ # attributes. But it slows down accessing ``__module__`` of
+ # instances by 200% (40ns to 124ns), requires editing class dicts on the fly
+ # (in InterfaceClass.__init__), thus slightly slowing down all interface creation,
+ # and is ugly.
+ #
+ # (4) As in the last step, but make it a non-data descriptor (no ``__set__``).
+ #
+ # If you then *also* store a copy of ``__ibmodule__`` in
+ # ``__module__`` in the instance's dict, reading works for both
+ # class and instance and is full speed for instances. But the cost
+ # is storage space, and you can't write to it anymore, not without
+ # things getting out of sync.
+ #
+ # (Actually, ``__module__`` was never meant to be writable. Doing
+ # so would break BTrees and normal dictionaries, as well as the
+ # repr, maybe more.)
+ #
+ # That leaves us with a metaclass. (Recall that a class is an
+ # instance of its metaclass, so properties/descriptors defined in
+ # the metaclass are used when accessing attributes on the
+ # instance/class. We'll use that to define ``__module__``.) Here
+ # we can have our cake and eat it too: no extra storage, and
+ # C-speed access to the underlying storage. The only substantial
+ # cost is that metaclasses tend to make people's heads hurt. (But
+ # still less than the descriptor-is-string, hopefully.)
+
+ __slots__ = ()
+
+ def __new__(cls, name, bases, attrs):
+ # Figure out what module defined the interface.
+ # This is copied from ``InterfaceClass.__init__``;
+ # reviewers aren't sure how AttributeError or KeyError
+ # could be raised.
+ __module__ = sys._getframe(1).f_globals['__name__']
+ # Get the C optimized __module__ accessor and give it
+ # to the new class.
+ moduledescr = InterfaceBase.__dict__['__module__']
+ if isinstance(moduledescr, str):
+ # We're working with the Python implementation,
+ # not the C version
+ moduledescr = InterfaceBase.__dict__['__module_property__']
+ attrs['__module__'] = moduledescr
+ kind = type.__new__(cls, name, bases, attrs)
+ kind.__module = __module__
+ return kind
+
+ @property
+ def __module__(cls):
+ return cls.__module
+
+ def __repr__(cls):
+ return "<class '%s.%s'>" % (
+ cls.__module,
+ cls.__name__,
+ )
+
+
+_InterfaceClassBase = _InterfaceMetaClass(
+ 'InterfaceClass',
+ # From least specific to most specific.
+ (InterfaceBase, Specification, Element),
+ {'__slots__': ()}
+)
+
+
+def interfacemethod(func):
+ """
+ Convert a method specification to an actual method of the interface.
+
+ This is a decorator that functions like `staticmethod` et al.
+
+ The primary use of this decorator is to allow interface definitions to
+ define the ``__adapt__`` method, but other interface methods can be
+ overridden this way too.
+
+ .. seealso:: `zope.interface.interfaces.IInterfaceDeclaration.interfacemethod`
+ """
+ f_locals = sys._getframe(1).f_locals
+ methods = f_locals.setdefault(INTERFACE_METHODS, {})
+ methods[func.__name__] = func
+ return _decorator_non_return
+
+
+class InterfaceClass(_InterfaceClassBase):
+ """
+ Prototype (scarecrow) Interfaces Implementation.
+
+ Note that it is not possible to change the ``__name__`` or ``__module__``
+ after an instance of this object has been constructed.
+ """
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ #implements(IInterface)
+
+ def __new__(cls, name=None, bases=(), attrs=None, __doc__=None, # pylint:disable=redefined-builtin
+ __module__=None):
+ assert isinstance(bases, tuple)
+ attrs = attrs or {}
+ needs_custom_class = attrs.pop(INTERFACE_METHODS, None)
+ if needs_custom_class:
+ needs_custom_class.update(
+ {'__classcell__': attrs.pop('__classcell__')}
+ if '__classcell__' in attrs
+ else {}
+ )
+ if '__adapt__' in needs_custom_class:
+ # We need to tell the C code to call this.
+ needs_custom_class['_CALL_CUSTOM_ADAPT'] = 1
+
+ if issubclass(cls, _InterfaceClassWithCustomMethods):
+ cls_bases = (cls,)
+ elif cls is InterfaceClass:
+ cls_bases = (_InterfaceClassWithCustomMethods,)
+ else:
+ cls_bases = (cls, _InterfaceClassWithCustomMethods)
+
+ cls = type(cls)( # pylint:disable=self-cls-assignment
+ name + "<WithCustomMethods>",
+ cls_bases,
+ needs_custom_class
+ )
+ elif PY2 and bases and len(bases) > 1:
+ bases_with_custom_methods = tuple(
+ type(b)
+ for b in bases
+ if issubclass(type(b), _InterfaceClassWithCustomMethods)
+ )
+
+ # If we have a subclass of InterfaceClass in *bases*,
+ # Python 3 is smart enough to pass that as *cls*, but Python
+ # 2 just passes whatever the first base in *bases* is. This means that if
+ # we have multiple inheritance, and one of our bases has already defined
+ # a custom method like ``__adapt__``, we do the right thing automatically
+ # and extend it on Python 3, but not necessarily on Python 2. To fix this, we need
+ # to run the MRO algorithm and get the most derived base manually.
+ # Note that this only works for consistent resolution orders
+ if bases_with_custom_methods:
+ cls = type( # pylint:disable=self-cls-assignment
+ name + "<WithCustomMethods>",
+ bases_with_custom_methods,
+ {}
+ ).__mro__[1] # Not the class we created, the most derived.
+
+ return _InterfaceClassBase.__new__(cls)
+
+ def __init__(self, name, bases=(), attrs=None, __doc__=None, # pylint:disable=redefined-builtin
+ __module__=None):
+ # We don't call our metaclass parent directly
+ # pylint:disable=non-parent-init-called
+ # pylint:disable=super-init-not-called
+ if not all(isinstance(base, InterfaceClass) for base in bases):
+ raise TypeError('Expected base interfaces')
+
+ 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): # pragma: no cover
+ pass
+
+ InterfaceBase.__init__(self, name, __module__)
+ # These asserts assisted debugging the metaclass
+ # assert '__module__' not in self.__dict__
+ # assert self.__ibmodule__ is self.__module__ is __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)
+
+ Specification.__init__(self, bases)
+ self.__attrs = self.__compute_attrs(attrs)
+
+ self.__identifier__ = "%s.%s" % (__module__, name)
+
+ def __compute_attrs(self, attrs):
+ # Make sure that all recorded attributes (and methods) are of type
+ # `Attribute` and `Method`
+ def update_value(aname, aval):
+ if isinstance(aval, Attribute):
+ aval.interface = self
+ if not aval.__name__:
+ aval.__name__ = aname
+ elif isinstance(aval, FunctionType):
+ aval = fromFunction(aval, self, name=aname)
+ else:
+ raise InvalidInterface("Concrete attribute, " + aname)
+ return aval
+
+ return {
+ aname: update_value(aname, aval)
+ for aname, aval in attrs.items()
+ if aname not in (
+ # __locals__: Python 3 sometimes adds this.
+ '__locals__',
+ # __qualname__: PEP 3155 (Python 3.3+)
+ '__qualname__',
+ # __annotations__: PEP 3107 (Python 3.0+)
+ '__annotations__',
+ )
+ and aval is not _decorator_non_return
+ }
+
+ def interfaces(self):
+ """Return an iterator for the interfaces in the specification.
+ """
+ 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): # pylint:disable=redefined-builtin
+ """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): # pylint:disable=redefined-builtin
+ """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 validateInvariants(self, obj, errors=None):
+ """validate object to defined invariants."""
+
+ for iface in self.__iro__:
+ for invariant in iface.queryDirectTaggedValue('invariants', ()):
+ try:
+ invariant(obj)
+ except Invalid as error:
+ if errors is not None:
+ errors.append(error)
+ else:
+ raise
+
+ if errors:
+ raise Invalid(errors)
+
+ def queryTaggedValue(self, tag, default=None):
+ """
+ Queries for the value associated with *tag*, returning it from the nearest
+ interface in the ``__iro__``.
+
+ If not found, returns *default*.
+ """
+ for iface in self.__iro__:
+ value = iface.queryDirectTaggedValue(tag, _marker)
+ if value is not _marker:
+ return value
+ return default
+
+ def getTaggedValue(self, tag):
+ """ Returns the value associated with 'tag'. """
+ value = self.queryTaggedValue(tag, default=_marker)
+ if value is _marker:
+ raise KeyError(tag)
+ return value
+
+ def getTaggedValueTags(self):
+ """ Returns a list of all tags. """
+ keys = set()
+ for base in self.__iro__:
+ keys.update(base.getDirectTaggedValueTags())
+ return keys
+
+ def __repr__(self):
+ try:
+ return self._v_repr
+ except AttributeError:
+ name = str(self)
+ r = "<%s %s>" % (self.__class__.__name__, name)
+ self._v_repr = r # pylint:disable=attribute-defined-outside-init
+ return r
+
+ def __str__(self):
+ name = self.__name__
+ m = self.__ibmodule__
+ if m:
+ name = '%s.%s' % (m, name)
+ return name
+
+ def _call_conform(self, conform):
+ try:
+ return conform(self)
+ except TypeError: # pragma: no cover
+ # 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 # pragma: no cover
+
+ def __reduce__(self):
+ return self.__name__
+
+Interface = InterfaceClass("Interface", __module__='zope.interface')
+# Interface is the only member of its own SRO.
+Interface._calculate_sro = lambda: (Interface,)
+Interface.changed(Interface)
+assert Interface.__sro__ == (Interface,)
+Specification._ROOT = Interface
+ro._ROOT = Interface
+
+class _InterfaceClassWithCustomMethods(InterfaceClass):
+ """
+ Marker class for interfaces with custom methods that override InterfaceClass methods.
+ """
+
+
+class Attribute(Element):
+ """Attribute descriptions
+ """
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ # implements(IAttribute)
+
+ interface = None
+
+ def _get_str_info(self):
+ """Return extra data to put at the end of __str__."""
+ return ""
+
+ def __str__(self):
+ of = ''
+ if self.interface is not None:
+ of = self.interface.__module__ + '.' + self.interface.__name__ + '.'
+ # self.__name__ may be None during construction (e.g., debugging)
+ return of + (self.__name__ or '<unknown>') + self._get_str_info()
+
+ def __repr__(self):
+ return "<%s.%s object at 0x%x %s>" % (
+ type(self).__module__,
+ type(self).__name__,
+ id(self),
+ self
+ )
+
+
+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)
+
+ positional = required = ()
+ _optional = varargs = kwargs = None
+ def _get_optional(self):
+ if self._optional is None:
+ return {}
+ return self._optional
+ def _set_optional(self, opt):
+ self._optional = opt
+ def _del_optional(self):
+ self._optional = None
+ optional = property(_get_optional, _set_optional, _del_optional)
+
+ 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] += "=" + repr(self.optional[v])
+ if self.varargs:
+ sig.append("*" + self.varargs)
+ if self.kwargs:
+ sig.append("**" + self.kwargs)
+
+ return "(%s)" % ", ".join(sig)
+
+ _get_str_info = getSignatureString
+
+
+def fromFunction(func, interface=None, imlevel=0, name=None):
+ name = name or func.__name__
+ method = Method(name, func.__doc__)
+ defaults = getattr(func, '__defaults__', None) or ()
+ code = func.__code__
+ # Number of positional arguments
+ na = code.co_argcount - imlevel
+ names = code.co_varnames[imlevel:]
+ opt = {}
+ # Number of required arguments
+ defaults_count = len(defaults)
+ if not defaults_count:
+ # PyPy3 uses ``__defaults_count__`` for builtin methods
+ # like ``dict.pop``. Surprisingly, these don't have recorded
+ # ``__defaults__``
+ defaults_count = getattr(func, '__defaults_count__', 0)
+
+ nr = na - defaults_count
+ 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):
+ if isinstance(meth, MethodType):
+ func = meth.__func__
+ else:
+ func = meth
+ 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 lest specific to most specific.
+ from zope.interface.interfaces import IElement
+ classImplements(Element, IElement)
+
+ from zope.interface.interfaces import IAttribute
+ classImplements(Attribute, IAttribute)
+
+ from zope.interface.interfaces import IMethod
+ classImplements(Method, IMethod)
+
+ from zope.interface.interfaces import ISpecification
+ classImplements(Specification, ISpecification)
+
+ from zope.interface.interfaces import IInterface
+ classImplements(InterfaceClass, IInterface)
+
+
+# We import this here to deal with module dependencies.
+# pylint:disable=wrong-import-position
+from zope.interface.declarations import implementedBy
+from zope.interface.declarations import providedBy
+from zope.interface.exceptions import InvalidInterface
+from zope.interface.exceptions import BrokenImplementation
+
+# This ensures that ``Interface`` winds up in the flattened()
+# list of the immutable declaration. It correctly overrides changed()
+# as a no-op, so we bypass that.
+from zope.interface.declarations import _empty
+Specification.changed(_empty, _empty)
diff --git a/contrib/python/zope.interface/py2/zope/interface/interfaces.py b/contrib/python/zope.interface/py2/zope/interface/interfaces.py
new file mode 100644
index 0000000000..66aecb9096
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/interfaces.py
@@ -0,0 +1,1593 @@
+##############################################################################
+#
+# 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 implementer
+
+__all__ = [
+ 'ComponentLookupError',
+ 'IAdapterRegistration',
+ 'IAdapterRegistry',
+ 'IAttribute',
+ 'IComponentLookup',
+ 'IComponentRegistry',
+ 'IComponents',
+ 'IDeclaration',
+ 'IElement',
+ 'IHandlerRegistration',
+ 'IInterface',
+ 'IInterfaceDeclaration',
+ 'IMethod',
+ 'Invalid',
+ 'IObjectEvent',
+ 'IRegistered',
+ 'IRegistration',
+ 'IRegistrationEvent',
+ 'ISpecification',
+ 'ISubscriptionAdapterRegistration',
+ 'IUnregistered',
+ 'IUtilityRegistration',
+ 'ObjectEvent',
+ 'Registered',
+ 'Unregistered',
+]
+
+# pylint:disable=inherit-non-class,no-method-argument,no-self-argument
+# pylint:disable=unexpected-special-method-signature
+# pylint:disable=too-many-lines
+
+class IElement(Interface):
+ """
+ Objects that have basic documentation and tagged values.
+
+ Known derivatives include :class:`IAttribute` and its derivative
+ :class:`IMethod`; these have no notion of inheritance.
+ :class:`IInterface` is also a derivative, and it does have a
+ notion of inheritance, expressed through its ``__bases__`` and
+ ordered in its ``__iro__`` (both defined by
+ :class:`ISpecification`).
+ """
+
+ # pylint:disable=arguments-differ
+
+ # Note that defining __doc__ as an Attribute hides the docstring
+ # from introspection. When changing it, also change it in the Sphinx
+ # ReST files.
+
+ __name__ = Attribute('__name__', 'The object name')
+ __doc__ = Attribute('__doc__', 'The object doc string')
+
+ ###
+ # Tagged values.
+ #
+ # Direct values are established in this instance. Others may be
+ # inherited. Although ``IElement`` itself doesn't have a notion of
+ # inheritance, ``IInterface`` *does*. It might have been better to
+ # make ``IInterface`` define new methods
+ # ``getIndirectTaggedValue``, etc, to include inheritance instead
+ # of overriding ``getTaggedValue`` to do that, but that ship has sailed.
+ # So to keep things nice and symmetric, we define the ``Direct`` methods here.
+ ###
+
+ def getTaggedValue(tag):
+ """Returns the value associated with *tag*.
+
+ Raise a `KeyError` if the tag isn't set.
+
+ If the object has a notion of inheritance, this searches
+ through the inheritance hierarchy and returns the nearest result.
+ If there is no such notion, this looks only at this object.
+
+ .. versionchanged:: 4.7.0
+ This method should respect inheritance if present.
+ """
+
+ def queryTaggedValue(tag, default=None):
+ """
+ As for `getTaggedValue`, but instead of raising a `KeyError`, returns *default*.
+
+
+ .. versionchanged:: 4.7.0
+ This method should respect inheritance if present.
+ """
+
+ def getTaggedValueTags():
+ """
+ Returns a collection of all tags in no particular order.
+
+ If the object has a notion of inheritance, this
+ includes all the inherited tagged values. If there is
+ no such notion, this looks only at this object.
+
+ .. versionchanged:: 4.7.0
+ This method should respect inheritance if present.
+ """
+
+ def setTaggedValue(tag, value):
+ """
+ Associates *value* with *key* directly in this object.
+ """
+
+ def getDirectTaggedValue(tag):
+ """
+ As for `getTaggedValue`, but never includes inheritance.
+
+ .. versionadded:: 5.0.0
+ """
+
+ def queryDirectTaggedValue(tag, default=None):
+ """
+ As for `queryTaggedValue`, but never includes inheritance.
+
+ .. versionadded:: 5.0.0
+ """
+
+ def getDirectTaggedValueTags():
+ """
+ As for `getTaggedValueTags`, but includes only tags directly
+ set on this object.
+
+ .. versionadded:: 5.0.0
+ """
+
+
+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 string keys:
+
+ - positional
+ A sequence of the names of positional arguments.
+ - required
+ A sequence of the names of required arguments.
+ - optional
+ A dictionary mapping argument names to their default values.
+ - varargs
+ The name of the varargs argument (or None).
+ - kwargs
+ The name of the kwargs argument (or None).
+ """
+
+ def getSignatureString():
+ """Return a signature string suitable for inclusion in documentation.
+
+ This method returns the function signature string. For example, if you
+ have ``def func(a, b, c=1, d='f')``, then the signature string is ``"(a, b,
+ c=1, d='f')"``.
+ """
+
+class ISpecification(Interface):
+ """Object Behavioral specifications"""
+ # pylint:disable=arguments-differ
+ def providedBy(object): # pylint:disable=redefined-builtin
+ """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 isOrExtends(other):
+ """Test whether the specification is or extends another
+ """
+
+ 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 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 of 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. The specification
+ itself is the first element.
+
+ (This is similar to the method-resolution order for new-style classes.)
+ """)
+
+ __iro__ = Attribute("""Interface-resolution order
+
+ A tuple 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:
+
+ - 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.
+
+ - Descriptions of attributes. Attribute descriptions include
+ the name of the attribute and prose documentation describing
+ the attributes usage.
+
+ - 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.
+
+ - 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 `zope.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:
+
+ - You assert that your object implement the interfaces.
+
+ There are several ways that you can declare that an object
+ provides an interface:
+
+ 1. Call `zope.interface.implementer` on your class definition.
+
+ 2. Call `zope.interface.directlyProvides` on your object.
+
+ 3. Call `zope.interface.classImplements` to declare 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.
+
+ - You query interface meta-data. See the IInterface methods and
+ attributes for details.
+
+ """
+ # pylint:disable=arguments-differ
+ def names(all=False): # pylint:disable=redefined-builtin
+ """Get the interface attribute names
+
+ Return a collection 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): # pylint:disable=redefined-builtin
+ """Get the interface attribute names and descriptions
+
+ Return a collection 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.
+
+ This interface is implemented by :mod:`zope.interface`.
+ """
+ # pylint:disable=arguments-differ
+ ###
+ # Defining interfaces
+ ###
+
+ Interface = Attribute("The base class used to create new interfaces")
+
+ def taggedValue(key, value):
+ """
+ Attach a tagged value to an interface while defining the interface.
+
+ This is a way of executing :meth:`IElement.setTaggedValue` from
+ the definition of the interface. For example::
+
+ class IFoo(Interface):
+ taggedValue('key', 'value')
+
+ .. seealso:: `zope.interface.taggedValue`
+ """
+
+ def invariant(checker_function):
+ """
+ Attach an invariant checker function to an interface while defining it.
+
+ Invariants can later be validated against particular implementations by
+ calling :meth:`IInterface.validateInvariants`.
+
+ For example::
+
+ def check_range(ob):
+ if ob.max < ob.min:
+ raise ValueError("max value is less than min value")
+
+ class IRange(Interface):
+ min = Attribute("The min value")
+ max = Attribute("The max value")
+
+ invariant(check_range)
+
+ .. seealso:: `zope.interface.invariant`
+ """
+
+ def interfacemethod(method):
+ """
+ A decorator that transforms a method specification into an
+ implementation method.
+
+ This is used to override methods of ``Interface`` or provide new methods.
+ Definitions using this decorator will not appear in :meth:`IInterface.names()`.
+ It is possible to have an implementation method and a method specification
+ of the same name.
+
+ For example::
+
+ class IRange(Interface):
+ @interfacemethod
+ def __adapt__(self, obj):
+ if isinstance(obj, range):
+ # Return the builtin ``range`` as-is
+ return obj
+ return super(type(IRange), self).__adapt__(obj)
+
+ You can use ``super`` to call the parent class functionality. Note that
+ the zero-argument version (``super().__adapt__``) works on Python 3.6 and above, but
+ prior to that the two-argument version must be used, and the class must be explicitly
+ passed as the first argument.
+
+ .. versionadded:: 5.1.0
+ .. seealso:: `zope.interface.interfacemethod`
+ """
+
+ ###
+ # Querying interfaces
+ ###
+
+ 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`.
+
+ .. seealso:: `zope.interface.providedBy`
+ """
+
+ def implementedBy(class_):
+ """
+ Return the interfaces implemented for a class's instances.
+
+ The value returned is an `IDeclaration`.
+
+ .. seealso:: `zope.interface.implementedBy`
+ """
+
+ ###
+ # Declaring interfaces
+ ###
+
+ 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. This is equivalent to::
+
+ @implementer(I1, I2)
+ class C(A, B):
+ pass
+
+ .. seealso:: `zope.interface.classImplements`
+ .. seealso:: `zope.interface.implementer`
+ """
+
+ def classImplementsFirst(cls, interface):
+ """
+ See :func:`zope.interface.classImplementsFirst`.
+ """
+
+ def implementer(*interfaces):
+ """
+ Create a decorator for declaring interfaces implemented by a
+ factory.
+
+ A callable is returned that makes an implements declaration on
+ objects passed to it.
+
+ .. seealso:: :meth:`classImplements`
+ """
+
+ 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.
+
+ .. seealso:: `zope.interface.classImplementsOnly`
+ """
+
+ 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.
+
+ .. seealso:: `zope.interface.implementer_only`
+ """
+
+ def directlyProvidedBy(object): # pylint:disable=redefined-builtin
+ """
+ Return the interfaces directly provided by the given object.
+
+ The value returned is an `IDeclaration`.
+
+ .. seealso:: `zope.interface.directlyProvidedBy`
+ """
+
+ def directlyProvides(object, *interfaces): # pylint:disable=redefined-builtin
+ """
+ Declare interfaces declared directly for an object.
+
+ The arguments after the object are one or more interfaces or
+ interface specifications (`IDeclaration` objects).
+
+ .. caution::
+ The interfaces given (including the interfaces in the
+ specifications) *replace* interfaces previously
+ declared for the object. See :meth:`alsoProvides` to add
+ additional interfaces.
+
+ 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.
+
+ .. seealso:: `zope.interface.directlyProvides`
+ """
+
+ def alsoProvides(object, *interfaces): # pylint:disable=redefined-builtin
+ """
+ Declare additional interfaces directly for an object.
+
+ For example::
+
+ alsoProvides(ob, I1)
+
+ is equivalent to::
+
+ directlyProvides(ob, directlyProvidedBy(ob), I1)
+
+ .. seealso:: `zope.interface.alsoProvides`
+ """
+
+ def noLongerProvides(object, interface): # pylint:disable=redefined-builtin
+ """
+ Remove an interface from the list of an object's directly provided
+ interfaces.
+
+ For example::
+
+ 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.
+
+ .. seealso:: `zope.interface.noLongerProvides`
+ """
+
+ def implements(*interfaces):
+ """
+ Declare interfaces implemented by instances of a class.
+
+ .. deprecated:: 5.0
+ This only works for Python 2. The `implementer` decorator
+ is preferred for all versions.
+
+ This function is called in a class definition (Python 2.x only).
+
+ 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 (Python 2.x only)::
+
+ 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.
+
+ .. deprecated:: 5.0
+ This only works for Python 2. The `implementer_only` decorator
+ is preferred for all versions.
+
+ This function is called in a class definition (Python 2.x only).
+
+ 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 (Python 2.x only)::
+
+ 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.
+
+ .. deprecated:: 5.0
+ This only works for Python 2. The `provider` decorator
+ is preferred for all versions.
+
+ 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`.
+
+ .. seealso:: `zope.interface.provider`
+ """
+
+ 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)
+
+ .. seealso:: `zope.interface.moduleProvides`
+ """
+
+ 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.
+
+ .. seealso:: `zope.interface.Declaration`
+ """
+
+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, which must be text.
+ """
+
+ def registered(required, provided, name=u''):
+ """Return the component registered for the given interfaces and name
+
+ name must be text.
+
+ 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, which must be
+ text.
+ """
+
+ 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, which must be
+ text.
+ """
+
+ def queryAdapter(object, provided, name=u'', default=None): # pylint:disable=redefined-builtin
+ """Adapt an object using a registered adapter factory.
+ """
+
+ def adapter_hook(provided, object, name=u'', default=None): # pylint:disable=redefined-builtin
+ """Adapt an object using a registered adapter factory.
+
+ name must be text.
+ """
+
+ 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): # pylint:disable=arguments-differ
+ """Return the names for which there are registered objects
+ """
+
+ def subscribe(required, provided, subscriber): # pylint:disable=arguments-differ
+ """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.
+
+ .. versionchanged:: 5.1.1
+ Correct the method signature to remove the ``name`` parameter.
+ Subscribers have no names.
+ """
+
+ def subscribed(required, provided, subscriber):
+ """
+ Check whether the object *subscriber* is registered directly
+ with this object via a previous call to
+ ``subscribe(required, provided, subscriber)``.
+
+ If the *subscriber*, or one equal to it, has been subscribed,
+ for the given *required* sequence and *provided* interface,
+ return that object. (This does not guarantee whether the *subscriber*
+ itself is returned, or an object equal to it.)
+
+ If it has not, return ``None``.
+
+ Unlike :meth:`subscriptions`, this method won't retrieve
+ components registered for more specific required interfaces or
+ less specific provided interfaces.
+
+ .. versionadded:: 5.3.0
+ """
+
+ def subscriptions(required, provided):
+ """
+ Get a sequence of subscribers.
+
+ Subscribers for a sequence of *required* interfaces, and a *provided*
+ interface are returned. This takes into account subscribers
+ registered with this object, as well as those registered with
+ base adapter registries in the resolution order, and interfaces that
+ extend *provided*.
+
+ .. versionchanged:: 5.1.1
+ Correct the method signature to remove the ``name`` parameter.
+ Subscribers have no names.
+ """
+
+ def subscribers(objects, provided):
+ """
+ Get a sequence of subscription **adapters**.
+
+ This is like :meth:`subscriptions`, but calls the returned
+ subscribers with *objects* (and optionally returns the results
+ of those calls), instead of returning the subscribers directly.
+
+ :param objects: A sequence of objects; they will be used to
+ determine the *required* argument to :meth:`subscriptions`.
+ :param provided: A single interface, or ``None``, to pass
+ as the *provided* parameter to :meth:`subscriptions`.
+ If an interface is given, the results of calling each returned
+ subscriber with the the *objects* are collected and returned
+ from this method; each result should be an object implementing
+ the *provided* interface. If ``None``, the resulting subscribers
+ are still called, but the results are ignored.
+ :return: A sequence of the results of calling the subscribers
+ if *provided* is not ``None``. If there are no registered
+ subscribers, or *provided* is ``None``, this will be an empty
+ sequence.
+
+ .. versionchanged:: 5.1.1
+ Correct the method signature to remove the ``name`` parameter.
+ Subscribers have no names.
+ """
+
+# 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
+ referred to by location.
+ """
+
+ object = Attribute("The subject of the event.")
+
+
+@implementer(IObjectEvent)
+class ObjectEvent(object):
+
+ def __init__(self, object): # pylint:disable=redefined-builtin
+ 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): # pylint:disable=redefined-builtin
+ """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''): # pylint:disable=redefined-builtin
+ """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 computed 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"""
+
+
+@implementer(IRegistrationEvent)
+class RegistrationEvent(ObjectEvent):
+ """There has been a change in a registration
+ """
+ def __repr__(self):
+ return "%s event:\n%r" % (self.__class__.__name__, self.object)
+
+class IRegistered(IRegistrationEvent):
+ """A component or factory was registered
+ """
+
+@implementer(IRegistered)
+class Registered(RegistrationEvent):
+ pass
+
+class IUnregistered(IRegistrationEvent):
+ """A component or factory was unregistered
+ """
+
+@implementer(IUnregistered)
+class Unregistered(RegistrationEvent):
+ """A component or factory was unregistered
+ """
+
+
+class IComponentRegistry(Interface):
+ """Register components
+ """
+
+ def registerUtility(component=None, provided=None, name=u'',
+ info=u'', factory=None):
+ """Register a utility
+
+ :param factory:
+ Factory for the component to be registered.
+
+ :param component:
+ The registered component
+
+ :param 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.
+
+ :param name:
+ The utility name.
+
+ :param 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 `IRegistered` event is generated with an `IUtilityRegistration`.
+ """
+
+ def unregisterUtility(component=None, provided=None, name=u'',
+ factory=None):
+ """Unregister a utility
+
+ :returns:
+ 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.
+
+ :param factory:
+ Factory for the component to be unregistered.
+
+ :param 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.
+
+ :param 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.
+
+ :param name:
+ The utility name.
+
+ Only one of *component* and *factory* can be used.
+ An `IUnregistered` 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
+
+ :param factory:
+ The object used to compute the adapter
+
+ :param 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
+ normally set in class definitions using
+ the `.adapter`
+ decorator. If the factory doesn't have a
+ ``__component_adapts__`` adapts attribute, then this
+ argument is required.
+
+ :param 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.
+
+ :param name:
+ The adapter name.
+
+ :param info:
+ An object that can be converted to a string to provide
+ information about the registration.
+
+ A `IRegistered` event is generated with an `IAdapterRegistration`.
+ """
+
+ def unregisterAdapter(factory=None, required=None,
+ provided=None, name=u''):
+ """Unregister an adapter factory
+
+ :returns:
+ 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.
+
+ :param 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.
+
+ :param 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.
+
+ :param 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.
+
+ :param name:
+ The adapter name.
+
+ An `IUnregistered` 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
+
+ :param factory:
+ The object used to compute the adapter
+
+ :param 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
+ normally set using the adapter
+ decorator. If the factory doesn't have a
+ ``__component_adapts__`` adapts attribute, then this
+ argument is required.
+
+ :param 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.
+
+ :param 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.
+
+ :param info:
+ An object that can be converted to a string to provide
+ information about the registration.
+
+ A `IRegistered` event is generated with an
+ `ISubscriptionAdapterRegistration`.
+ """
+
+ def unregisterSubscriptionAdapter(factory=None, required=None,
+ provides=None, name=u''):
+ """Unregister a subscriber factory.
+
+ :returns:
+ 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.
+
+ :param 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.
+
+ :param 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
+ normally set using the adapter
+ decorator. If the factory doesn't have a
+ ``__component_adapts__`` adapts attribute, then this
+ argument is required.
+
+ :param 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.
+
+ :param 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 `IUnregistered` 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.
+
+ :param handler:
+ The object used to handle some event represented by
+ the objects passed to it.
+
+ :param 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
+ normally set using the adapter
+ decorator. If the factory doesn't have a
+ ``__component_adapts__`` adapts attribute, then this
+ argument is required.
+
+ :param 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.
+
+ :param info:
+ An object that can be converted to a string to provide
+ information about the registration.
+
+
+ A `IRegistered` 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.
+
+ :returns: A boolean is returned indicating whether the registry was
+ changed.
+
+ :param 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.
+
+ :param 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
+ normally set using the adapter
+ decorator. If the factory doesn't have a
+ ``__component_adapts__`` adapts attribute, then this
+ argument is required.
+
+ :param 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 `IUnregistered` 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/contrib/python/zope.interface/py2/zope/interface/registry.py b/contrib/python/zope.interface/py2/zope/interface/registry.py
new file mode 100644
index 0000000000..4fdb120b7f
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/registry.py
@@ -0,0 +1,726 @@
+##############################################################################
+#
+# 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
+"""
+from collections import defaultdict
+
+try:
+ from zope.event import notify
+except ImportError: # pragma: no cover
+ 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 implementer
+from zope.interface.declarations import implementer_only
+from zope.interface.declarations import providedBy
+from zope.interface.adapter import AdapterRegistry
+from zope.interface._compat import CLASS_TYPES
+from zope.interface._compat import STRING_TYPES
+
+__all__ = [
+ # Components is public API, but
+ # the *Registration classes are just implementations
+ # of public interfaces.
+ 'Components',
+]
+
+class _UnhashableComponentCounter(object):
+ # defaultdict(int)-like object for unhashable components
+
+ def __init__(self, otherdict):
+ # [(component, count)]
+ self._data = [item for item in otherdict.items()]
+
+ def __getitem__(self, key):
+ for component, count in self._data:
+ if component == key:
+ return count
+ return 0
+
+ def __setitem__(self, component, count):
+ for i, data in enumerate(self._data):
+ if data[0] == component:
+ self._data[i] = component, count
+ return
+ self._data.append((component, count))
+
+ def __delitem__(self, component):
+ for i, data in enumerate(self._data):
+ if data[0] == component:
+ del self._data[i]
+ return
+ raise KeyError(component) # pragma: no cover
+
+def _defaultdict_int():
+ return defaultdict(int)
+
+class _UtilityRegistrations(object):
+
+ def __init__(self, utilities, utility_registrations):
+ # {provided -> {component: count}}
+ self._cache = defaultdict(_defaultdict_int)
+ self._utilities = utilities
+ self._utility_registrations = utility_registrations
+
+ self.__populate_cache()
+
+ def __populate_cache(self):
+ for ((p, _), data) in iter(self._utility_registrations.items()):
+ component = data[0]
+ self.__cache_utility(p, component)
+
+ def __cache_utility(self, provided, component):
+ try:
+ self._cache[provided][component] += 1
+ except TypeError:
+ # The component is not hashable, and we have a dict. Switch to a strategy
+ # that doesn't use hashing.
+ prov = self._cache[provided] = _UnhashableComponentCounter(self._cache[provided])
+ prov[component] += 1
+
+ def __uncache_utility(self, provided, component):
+ provided = self._cache[provided]
+ # It seems like this line could raise a TypeError if component isn't
+ # hashable and we haven't yet switched to _UnhashableComponentCounter. However,
+ # we can't actually get in that situation. In order to get here, we would
+ # have had to cache the utility already which would have switched
+ # the datastructure if needed.
+ count = provided[component]
+ count -= 1
+ if count == 0:
+ del provided[component]
+ else:
+ provided[component] = count
+ return count > 0
+
+ def _is_utility_subscribed(self, provided, component):
+ try:
+ return self._cache[provided][component] > 0
+ except TypeError:
+ # Not hashable and we're still using a dict
+ return False
+
+ def registerUtility(self, provided, name, component, info, factory):
+ subscribed = self._is_utility_subscribed(provided, component)
+
+ self._utility_registrations[(provided, name)] = component, info, factory
+ self._utilities.register((), provided, name, component)
+
+ if not subscribed:
+ self._utilities.subscribe((), provided, component)
+
+ self.__cache_utility(provided, component)
+
+ def unregisterUtility(self, provided, name, component):
+ del self._utility_registrations[(provided, name)]
+ self._utilities.unregister((), provided, name)
+
+ subscribed = self.__uncache_utility(provided, component)
+
+ if not subscribed:
+ self._utilities.unsubscribe((), provided, component)
+
+
+@implementer(IComponents)
+class Components(object):
+
+ _v_utility_registrations_cache = None
+
+ def __init__(self, name='', bases=()):
+ # __init__ is used for test cleanup as well as initialization.
+ # XXX add a separate API for test cleanup.
+ assert isinstance(name, STRING_TYPES)
+ self.__name__ = name
+ self._init_registries()
+ self._init_registrations()
+ self.__bases__ = tuple(bases)
+ self._v_utility_registrations_cache = None
+
+ def __repr__(self):
+ return "<%s %s>" % (self.__class__.__name__, self.__name__)
+
+ def __reduce__(self):
+ # Mimic what a persistent.Persistent object does and elide
+ # _v_ attributes so that they don't get saved in ZODB.
+ # This allows us to store things that cannot be pickled in such
+ # attributes.
+ reduction = super(Components, self).__reduce__()
+ # (callable, args, state, listiter, dictiter)
+ # We assume the state is always a dict; the last three items
+ # are technically optional and can be missing or None.
+ filtered_state = {k: v for k, v in reduction[2].items()
+ if not k.startswith('_v_')}
+ reduction = list(reduction)
+ reduction[2] = filtered_state
+ return tuple(reduction)
+
+ def _init_registries(self):
+ # Subclasses have never been required to call this method
+ # if they override it, merely to fill in these two attributes.
+ self.adapters = AdapterRegistry()
+ self.utilities = AdapterRegistry()
+
+ def _init_registrations(self):
+ self._utility_registrations = {}
+ self._adapter_registrations = {}
+ self._subscription_registrations = []
+ self._handler_registrations = []
+
+ @property
+ def _utility_registrations_cache(self):
+ # We use a _v_ attribute internally so that data aren't saved in ZODB,
+ # because this object cannot be pickled.
+ cache = self._v_utility_registrations_cache
+ if (cache is None
+ or cache._utilities is not self.utilities
+ or cache._utility_registrations is not self._utility_registrations):
+ cache = self._v_utility_registrations_cache = _UtilityRegistrations(
+ self.utilities,
+ self._utility_registrations)
+ return cache
+
+ 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)
+
+ if name == u'':
+ name = _getName(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)
+
+ self._utility_registrations_cache.registerUtility(
+ provided, name, component, info, factory)
+
+ 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
+ self._utility_registrations_cache.unregisterUtility(
+ provided, name, 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)
+ if name == u'':
+ name = _getName(factory)
+ 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 rebuildUtilityRegistryFromLocalCache(self, rebuild=False):
+ """
+ Emergency maintenance method to rebuild the ``.utilities``
+ registry from the local copy maintained in this object, or
+ detect the need to do so.
+
+ Most users will never need to call this, but it can be helpful
+ in the event of suspected corruption.
+
+ By default, this method only checks for corruption. To make it
+ actually rebuild the registry, pass `True` for *rebuild*.
+
+ :param bool rebuild: If set to `True` (not the default),
+ this method will actually register and subscribe utilities
+ in the registry as needed to synchronize with the local cache.
+
+ :return: A dictionary that's meant as diagnostic data. The keys
+ and values may change over time. When called with a false *rebuild*,
+ the keys ``"needed_registered"`` and ``"needed_subscribed"`` will be
+ non-zero if any corruption was detected, but that will not be corrected.
+
+ .. versionadded:: 5.3.0
+ """
+ regs = dict(self._utility_registrations)
+ utils = self.utilities
+ needed_registered = 0
+ did_not_register = 0
+ needed_subscribed = 0
+ did_not_subscribe = 0
+
+
+ # Avoid the expensive change process during this; we'll call
+ # it once at the end if needed.
+ assert 'changed' not in utils.__dict__
+ utils.changed = lambda _: None
+
+ if rebuild:
+ register = utils.register
+ subscribe = utils.subscribe
+ else:
+ register = subscribe = lambda *args: None
+
+ try:
+ for (provided, name), (value, _info, _factory) in regs.items():
+ if utils.registered((), provided, name) != value:
+ register((), provided, name, value)
+ needed_registered += 1
+ else:
+ did_not_register += 1
+
+ if utils.subscribed((), provided, value) is None:
+ needed_subscribed += 1
+ subscribe((), provided, value)
+ else:
+ did_not_subscribe += 1
+ finally:
+ del utils.changed
+ if rebuild and (needed_subscribed or needed_registered):
+ utils.changed(utils)
+
+ return {
+ 'needed_registered': needed_registered,
+ 'did_not_register': did_not_register,
+ 'needed_subscribed': needed_subscribed,
+ 'did_not_subscribe': did_not_subscribe
+ }
+
+def _getName(component):
+ try:
+ return component.__component_name__
+ except AttributeError:
+ return u''
+
+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, not %r" % type(r)
+ )
+ result.append(r)
+ return tuple(result)
+
+
+@implementer(IUtilityRegistration)
+class UtilityRegistration(object):
+
+ 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)
+
+@implementer(IAdapterRegistration)
+class AdapterRegistration(object):
+
+ 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)
+
+@implementer_only(ISubscriptionAdapterRegistration)
+class SubscriptionRegistration(AdapterRegistration):
+ pass
+
+
+@implementer_only(IHandlerRegistration)
+class HandlerRegistration(AdapterRegistration):
+
+ 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/contrib/python/zope.interface/py2/zope/interface/ro.py b/contrib/python/zope.interface/py2/zope/interface/ro.py
new file mode 100644
index 0000000000..89dde6799b
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/ro.py
@@ -0,0 +1,666 @@
+##############################################################################
+#
+# 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.
+
+.. versionchanged:: 5.0
+ The resolution order is now based on the same C3 order that Python
+ uses for classes. In complex instances of multiple inheritance, this
+ may result in a different ordering.
+
+ In older versions, the ordering wasn't required to be C3 compliant,
+ and for backwards compatibility, it still isn't. If the ordering
+ isn't C3 compliant (if it is *inconsistent*), zope.interface will
+ make a best guess to try to produce a reasonable resolution order.
+ Still (just as before), the results in such cases may be
+ surprising.
+
+.. rubric:: Environment Variables
+
+Due to the change in 5.0, certain environment variables can be used to control errors
+and warnings about inconsistent resolution orders. They are listed in priority order, with
+variables at the bottom generally overriding variables above them.
+
+ZOPE_INTERFACE_WARN_BAD_IRO
+ If this is set to "1", then if there is at least one inconsistent resolution
+ order discovered, a warning (:class:`InconsistentResolutionOrderWarning`) will
+ be issued. Use the usual warning mechanisms to control this behaviour. The warning
+ text will contain additional information on debugging.
+ZOPE_INTERFACE_TRACK_BAD_IRO
+ If this is set to "1", then zope.interface will log information about each
+ inconsistent resolution order discovered, and keep those details in memory in this module
+ for later inspection.
+ZOPE_INTERFACE_STRICT_IRO
+ If this is set to "1", any attempt to use :func:`ro` that would produce a non-C3
+ ordering will fail by raising :class:`InconsistentResolutionOrderError`.
+
+.. important::
+
+ ``ZOPE_INTERFACE_STRICT_IRO`` is intended to become the default in the future.
+
+There are two environment variables that are independent.
+
+ZOPE_INTERFACE_LOG_CHANGED_IRO
+ If this is set to "1", then if the C3 resolution order is different from
+ the legacy resolution order for any given object, a message explaining the differences
+ will be logged. This is intended to be used for debugging complicated IROs.
+ZOPE_INTERFACE_USE_LEGACY_IRO
+ If this is set to "1", then the C3 resolution order will *not* be used. The
+ legacy IRO will be used instead. This is a temporary measure and will be removed in the
+ future. It is intended to help during the transition.
+ It implies ``ZOPE_INTERFACE_LOG_CHANGED_IRO``.
+
+.. rubric:: Debugging Behaviour Changes in zope.interface 5
+
+Most behaviour changes from zope.interface 4 to 5 are related to
+inconsistent resolution orders. ``ZOPE_INTERFACE_STRICT_IRO`` is the
+most effective tool to find such inconsistent resolution orders, and
+we recommend running your code with this variable set if at all
+possible. Doing so will ensure that all interface resolution orders
+are consistent, and if they're not, will immediately point the way to
+where this is violated.
+
+Occasionally, however, this may not be enough. This is because in some
+cases, a C3 ordering can be found (the resolution order is fully
+consistent) that is substantially different from the ad-hoc legacy
+ordering. In such cases, you may find that you get an unexpected value
+returned when adapting one or more objects to an interface. To debug
+this, *also* enable ``ZOPE_INTERFACE_LOG_CHANGED_IRO`` and examine the
+output. The main thing to look for is changes in the relative
+positions of interfaces for which there are registered adapters.
+"""
+from __future__ import print_function
+__docformat__ = 'restructuredtext'
+
+__all__ = [
+ 'ro',
+ 'InconsistentResolutionOrderError',
+ 'InconsistentResolutionOrderWarning',
+]
+
+__logger = None
+
+def _logger():
+ global __logger # pylint:disable=global-statement
+ if __logger is None:
+ import logging
+ __logger = logging.getLogger(__name__)
+ return __logger
+
+def _legacy_mergeOrderings(orderings):
+ """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']
+
+ """
+
+ seen = set()
+ result = []
+ for ordering in reversed(orderings):
+ for o in reversed(ordering):
+ if o not in seen:
+ seen.add(o)
+ result.insert(0, o)
+
+ return result
+
+def _legacy_flatten(begin):
+ result = [begin]
+ 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
+
+def _legacy_ro(ob):
+ return _legacy_mergeOrderings([_legacy_flatten(ob)])
+
+###
+# Compare base objects using identity, not equality. This matches what
+# the CPython MRO algorithm does, and is *much* faster to boot: that,
+# plus some other small tweaks makes the difference between 25s and 6s
+# in loading 446 plone/zope interface.py modules (1925 InterfaceClass,
+# 1200 Implements, 1100 ClassProvides objects)
+###
+
+
+class InconsistentResolutionOrderWarning(PendingDeprecationWarning):
+ """
+ The warning issued when an invalid IRO is requested.
+ """
+
+class InconsistentResolutionOrderError(TypeError):
+ """
+ The error raised when an invalid IRO is requested in strict mode.
+ """
+
+ def __init__(self, c3, base_tree_remaining):
+ self.C = c3.leaf
+ base_tree = c3.base_tree
+ self.base_ros = {
+ base: base_tree[i + 1]
+ for i, base in enumerate(self.C.__bases__)
+ }
+ # Unfortunately, this doesn't necessarily directly match
+ # up to any transformation on C.__bases__, because
+ # if any were fully used up, they were removed already.
+ self.base_tree_remaining = base_tree_remaining
+
+ TypeError.__init__(self)
+
+ def __str__(self):
+ import pprint
+ return "%s: For object %r.\nBase ROs:\n%s\nConflict Location:\n%s" % (
+ self.__class__.__name__,
+ self.C,
+ pprint.pformat(self.base_ros),
+ pprint.pformat(self.base_tree_remaining),
+ )
+
+
+class _NamedBool(int): # cannot actually inherit bool
+
+ def __new__(cls, val, name):
+ inst = super(cls, _NamedBool).__new__(cls, val)
+ inst.__name__ = name
+ return inst
+
+
+class _ClassBoolFromEnv(object):
+ """
+ Non-data descriptor that reads a transformed environment variable
+ as a boolean, and caches the result in the class.
+ """
+
+ def __get__(self, inst, klass):
+ import os
+ for cls in klass.__mro__:
+ my_name = None
+ for k in dir(klass):
+ if k in cls.__dict__ and cls.__dict__[k] is self:
+ my_name = k
+ break
+ if my_name is not None:
+ break
+ else: # pragma: no cover
+ raise RuntimeError("Unable to find self")
+
+ env_name = 'ZOPE_INTERFACE_' + my_name
+ val = os.environ.get(env_name, '') == '1'
+ val = _NamedBool(val, my_name)
+ setattr(klass, my_name, val)
+ setattr(klass, 'ORIG_' + my_name, self)
+ return val
+
+
+class _StaticMRO(object):
+ # A previously resolved MRO, supplied by the caller.
+ # Used in place of calculating it.
+
+ had_inconsistency = None # We don't know...
+
+ def __init__(self, C, mro):
+ self.leaf = C
+ self.__mro = tuple(mro)
+
+ def mro(self):
+ return list(self.__mro)
+
+
+class C3(object):
+ # Holds the shared state during computation of an MRO.
+
+ @staticmethod
+ def resolver(C, strict, base_mros):
+ strict = strict if strict is not None else C3.STRICT_IRO
+ factory = C3
+ if strict:
+ factory = _StrictC3
+ elif C3.TRACK_BAD_IRO:
+ factory = _TrackingC3
+
+ memo = {}
+ base_mros = base_mros or {}
+ for base, mro in base_mros.items():
+ assert base in C.__bases__
+ memo[base] = _StaticMRO(base, mro)
+
+ return factory(C, memo)
+
+ __mro = None
+ __legacy_ro = None
+ direct_inconsistency = False
+
+ def __init__(self, C, memo):
+ self.leaf = C
+ self.memo = memo
+ kind = self.__class__
+
+ base_resolvers = []
+ for base in C.__bases__:
+ if base not in memo:
+ resolver = kind(base, memo)
+ memo[base] = resolver
+ base_resolvers.append(memo[base])
+
+ self.base_tree = [
+ [C]
+ ] + [
+ memo[base].mro() for base in C.__bases__
+ ] + [
+ list(C.__bases__)
+ ]
+
+ self.bases_had_inconsistency = any(base.had_inconsistency for base in base_resolvers)
+
+ if len(C.__bases__) == 1:
+ self.__mro = [C] + memo[C.__bases__[0]].mro()
+
+ @property
+ def had_inconsistency(self):
+ return self.direct_inconsistency or self.bases_had_inconsistency
+
+ @property
+ def legacy_ro(self):
+ if self.__legacy_ro is None:
+ self.__legacy_ro = tuple(_legacy_ro(self.leaf))
+ return list(self.__legacy_ro)
+
+ TRACK_BAD_IRO = _ClassBoolFromEnv()
+ STRICT_IRO = _ClassBoolFromEnv()
+ WARN_BAD_IRO = _ClassBoolFromEnv()
+ LOG_CHANGED_IRO = _ClassBoolFromEnv()
+ USE_LEGACY_IRO = _ClassBoolFromEnv()
+ BAD_IROS = ()
+
+ def _warn_iro(self):
+ if not self.WARN_BAD_IRO:
+ # For the initial release, one must opt-in to see the warning.
+ # In the future (2021?) seeing at least the first warning will
+ # be the default
+ return
+ import warnings
+ warnings.warn(
+ "An inconsistent resolution order is being requested. "
+ "(Interfaces should follow the Python class rules known as C3.) "
+ "For backwards compatibility, zope.interface will allow this, "
+ "making the best guess it can to produce as meaningful an order as possible. "
+ "In the future this might be an error. Set the warning filter to error, or set "
+ "the environment variable 'ZOPE_INTERFACE_TRACK_BAD_IRO' to '1' and examine "
+ "ro.C3.BAD_IROS to debug, or set 'ZOPE_INTERFACE_STRICT_IRO' to raise exceptions.",
+ InconsistentResolutionOrderWarning,
+ )
+
+ @staticmethod
+ def _can_choose_base(base, base_tree_remaining):
+ # From C3:
+ # nothead = [s for s in nonemptyseqs if cand in s[1:]]
+ for bases in base_tree_remaining:
+ if not bases or bases[0] is base:
+ continue
+
+ for b in bases:
+ if b is base:
+ return False
+ return True
+
+ @staticmethod
+ def _nonempty_bases_ignoring(base_tree, ignoring):
+ return list(filter(None, [
+ [b for b in bases if b is not ignoring]
+ for bases
+ in base_tree
+ ]))
+
+ def _choose_next_base(self, base_tree_remaining):
+ """
+ Return the next base.
+
+ The return value will either fit the C3 constraints or be our best
+ guess about what to do. If we cannot guess, this may raise an exception.
+ """
+ base = self._find_next_C3_base(base_tree_remaining)
+ if base is not None:
+ return base
+ return self._guess_next_base(base_tree_remaining)
+
+ def _find_next_C3_base(self, base_tree_remaining):
+ """
+ Return the next base that fits the constraints, or ``None`` if there isn't one.
+ """
+ for bases in base_tree_remaining:
+ base = bases[0]
+ if self._can_choose_base(base, base_tree_remaining):
+ return base
+ return None
+
+ class _UseLegacyRO(Exception):
+ pass
+
+ def _guess_next_base(self, base_tree_remaining):
+ # Narf. We may have an inconsistent order (we won't know for
+ # sure until we check all the bases). Python cannot create
+ # classes like this:
+ #
+ # class B1:
+ # pass
+ # class B2(B1):
+ # pass
+ # class C(B1, B2): # -> TypeError; this is like saying C(B1, B2, B1).
+ # pass
+ #
+ # However, older versions of zope.interface were fine with this order.
+ # A good example is ``providedBy(IOError())``. Because of the way
+ # ``classImplements`` works, it winds up with ``__bases__`` ==
+ # ``[IEnvironmentError, IIOError, IOSError, <implementedBy Exception>]``
+ # (on Python 3). But ``IEnvironmentError`` is a base of both ``IIOError``
+ # and ``IOSError``. Previously, we would get a resolution order of
+ # ``[IIOError, IOSError, IEnvironmentError, IStandardError, IException, Interface]``
+ # but the standard Python algorithm would forbid creating that order entirely.
+
+ # Unlike Python's MRO, we attempt to resolve the issue. A few
+ # heuristics have been tried. One was:
+ #
+ # Strip off the first (highest priority) base of each direct
+ # base one at a time and seeing if we can come to an agreement
+ # with the other bases. (We're trying for a partial ordering
+ # here.) This often resolves cases (such as the IOSError case
+ # above), and frequently produces the same ordering as the
+ # legacy MRO did. If we looked at all the highest priority
+ # bases and couldn't find any partial ordering, then we strip
+ # them *all* out and begin the C3 step again. We take care not
+ # to promote a common root over all others.
+ #
+ # If we only did the first part, stripped off the first
+ # element of the first item, we could resolve simple cases.
+ # But it tended to fail badly. If we did the whole thing, it
+ # could be extremely painful from a performance perspective
+ # for deep/wide things like Zope's OFS.SimpleItem.Item. Plus,
+ # anytime you get ExtensionClass.Base into the mix, you're
+ # likely to wind up in trouble, because it messes with the MRO
+ # of classes. Sigh.
+ #
+ # So now, we fall back to the old linearization (fast to compute).
+ self._warn_iro()
+ self.direct_inconsistency = InconsistentResolutionOrderError(self, base_tree_remaining)
+ raise self._UseLegacyRO
+
+ def _merge(self):
+ # Returns a merged *list*.
+ result = self.__mro = []
+ base_tree_remaining = self.base_tree
+ base = None
+ while 1:
+ # Take last picked base out of the base tree wherever it is.
+ # This differs slightly from the standard Python MRO and is needed
+ # because we have no other step that prevents duplicates
+ # from coming in (e.g., in the inconsistent fallback path)
+ base_tree_remaining = self._nonempty_bases_ignoring(base_tree_remaining, base)
+
+ if not base_tree_remaining:
+ return result
+ try:
+ base = self._choose_next_base(base_tree_remaining)
+ except self._UseLegacyRO:
+ self.__mro = self.legacy_ro
+ return self.legacy_ro
+
+ result.append(base)
+
+ def mro(self):
+ if self.__mro is None:
+ self.__mro = tuple(self._merge())
+ return list(self.__mro)
+
+
+class _StrictC3(C3):
+ __slots__ = ()
+ def _guess_next_base(self, base_tree_remaining):
+ raise InconsistentResolutionOrderError(self, base_tree_remaining)
+
+
+class _TrackingC3(C3):
+ __slots__ = ()
+ def _guess_next_base(self, base_tree_remaining):
+ import traceback
+ bad_iros = C3.BAD_IROS
+ if self.leaf not in bad_iros:
+ if bad_iros == ():
+ import weakref
+ # This is a race condition, but it doesn't matter much.
+ bad_iros = C3.BAD_IROS = weakref.WeakKeyDictionary()
+ bad_iros[self.leaf] = t = (
+ InconsistentResolutionOrderError(self, base_tree_remaining),
+ traceback.format_stack()
+ )
+ _logger().warning("Tracking inconsistent IRO: %s", t[0])
+ return C3._guess_next_base(self, base_tree_remaining)
+
+
+class _ROComparison(object):
+ # Exists to compute and print a pretty string comparison
+ # for differing ROs.
+ # Since we're used in a logging context, and may actually never be printed,
+ # this is a class so we can defer computing the diff until asked.
+
+ # Components we use to build up the comparison report
+ class Item(object):
+ prefix = ' '
+ def __init__(self, item):
+ self.item = item
+ def __str__(self):
+ return "%s%s" % (
+ self.prefix,
+ self.item,
+ )
+
+ class Deleted(Item):
+ prefix = '- '
+
+ class Inserted(Item):
+ prefix = '+ '
+
+ Empty = str
+
+ class ReplacedBy(object): # pragma: no cover
+ prefix = '- '
+ suffix = ''
+ def __init__(self, chunk, total_count):
+ self.chunk = chunk
+ self.total_count = total_count
+
+ def __iter__(self):
+ lines = [
+ self.prefix + str(item) + self.suffix
+ for item in self.chunk
+ ]
+ while len(lines) < self.total_count:
+ lines.append('')
+
+ return iter(lines)
+
+ class Replacing(ReplacedBy):
+ prefix = "+ "
+ suffix = ''
+
+
+ _c3_report = None
+ _legacy_report = None
+
+ def __init__(self, c3, c3_ro, legacy_ro):
+ self.c3 = c3
+ self.c3_ro = c3_ro
+ self.legacy_ro = legacy_ro
+
+ def __move(self, from_, to_, chunk, operation):
+ for x in chunk:
+ to_.append(operation(x))
+ from_.append(self.Empty())
+
+ def _generate_report(self):
+ if self._c3_report is None:
+ import difflib
+ # The opcodes we get describe how to turn 'a' into 'b'. So
+ # the old one (legacy) needs to be first ('a')
+ matcher = difflib.SequenceMatcher(None, self.legacy_ro, self.c3_ro)
+ # The reports are equal length sequences. We're going for a
+ # side-by-side diff.
+ self._c3_report = c3_report = []
+ self._legacy_report = legacy_report = []
+ for opcode, leg1, leg2, c31, c32 in matcher.get_opcodes():
+ c3_chunk = self.c3_ro[c31:c32]
+ legacy_chunk = self.legacy_ro[leg1:leg2]
+
+ if opcode == 'equal':
+ # Guaranteed same length
+ c3_report.extend((self.Item(x) for x in c3_chunk))
+ legacy_report.extend(self.Item(x) for x in legacy_chunk)
+ if opcode == 'delete':
+ # Guaranteed same length
+ assert not c3_chunk
+ self.__move(c3_report, legacy_report, legacy_chunk, self.Deleted)
+ if opcode == 'insert':
+ # Guaranteed same length
+ assert not legacy_chunk
+ self.__move(legacy_report, c3_report, c3_chunk, self.Inserted)
+ if opcode == 'replace': # pragma: no cover (How do you make it output this?)
+ # Either side could be longer.
+ chunk_size = max(len(c3_chunk), len(legacy_chunk))
+ c3_report.extend(self.Replacing(c3_chunk, chunk_size))
+ legacy_report.extend(self.ReplacedBy(legacy_chunk, chunk_size))
+
+ return self._c3_report, self._legacy_report
+
+ @property
+ def _inconsistent_label(self):
+ inconsistent = []
+ if self.c3.direct_inconsistency:
+ inconsistent.append('direct')
+ if self.c3.bases_had_inconsistency:
+ inconsistent.append('bases')
+ return '+'.join(inconsistent) if inconsistent else 'no'
+
+ def __str__(self):
+ c3_report, legacy_report = self._generate_report()
+ assert len(c3_report) == len(legacy_report)
+
+ left_lines = [str(x) for x in legacy_report]
+ right_lines = [str(x) for x in c3_report]
+
+ # We have the same number of lines in the report; this is not
+ # necessarily the same as the number of items in either RO.
+ assert len(left_lines) == len(right_lines)
+
+ padding = ' ' * 2
+ max_left = max(len(x) for x in left_lines)
+ max_right = max(len(x) for x in right_lines)
+
+ left_title = 'Legacy RO (len=%s)' % (len(self.legacy_ro),)
+
+ right_title = 'C3 RO (len=%s; inconsistent=%s)' % (
+ len(self.c3_ro),
+ self._inconsistent_label,
+ )
+ lines = [
+ (padding + left_title.ljust(max_left) + padding + right_title.ljust(max_right)),
+ padding + '=' * (max_left + len(padding) + max_right)
+ ]
+ lines += [
+ padding + left.ljust(max_left) + padding + right
+ for left, right in zip(left_lines, right_lines)
+ ]
+
+ return '\n'.join(lines)
+
+
+# Set to `Interface` once it is defined. This is used to
+# avoid logging false positives about changed ROs.
+_ROOT = None
+
+def ro(C, strict=None, base_mros=None, log_changed_ro=None, use_legacy_ro=None):
+ """
+ ro(C) -> list
+
+ Compute the precedence list (mro) according to C3.
+
+ :return: A fresh `list` object.
+
+ .. versionchanged:: 5.0.0
+ Add the *strict*, *log_changed_ro* and *use_legacy_ro*
+ keyword arguments. These are provisional and likely to be
+ removed in the future. They are most useful for testing.
+ """
+ # The ``base_mros`` argument is for internal optimization and
+ # not documented.
+ resolver = C3.resolver(C, strict, base_mros)
+ mro = resolver.mro()
+
+ log_changed = log_changed_ro if log_changed_ro is not None else resolver.LOG_CHANGED_IRO
+ use_legacy = use_legacy_ro if use_legacy_ro is not None else resolver.USE_LEGACY_IRO
+
+ if log_changed or use_legacy:
+ legacy_ro = resolver.legacy_ro
+ assert isinstance(legacy_ro, list)
+ assert isinstance(mro, list)
+ changed = legacy_ro != mro
+ if changed:
+ # Did only Interface move? The fix for issue #8 made that
+ # somewhat common. It's almost certainly not a problem, though,
+ # so allow ignoring it.
+ legacy_without_root = [x for x in legacy_ro if x is not _ROOT]
+ mro_without_root = [x for x in mro if x is not _ROOT]
+ changed = legacy_without_root != mro_without_root
+
+ if changed:
+ comparison = _ROComparison(resolver, mro, legacy_ro)
+ _logger().warning(
+ "Object %r has different legacy and C3 MROs:\n%s",
+ C, comparison
+ )
+ if resolver.had_inconsistency and legacy_ro == mro:
+ comparison = _ROComparison(resolver, mro, legacy_ro)
+ _logger().warning(
+ "Object %r had inconsistent IRO and used the legacy RO:\n%s"
+ "\nInconsistency entered at:\n%s",
+ C, comparison, resolver.direct_inconsistency
+ )
+ if use_legacy:
+ return legacy_ro
+
+ return mro
+
+
+def is_consistent(C):
+ """
+ Check if the resolution order for *C*, as computed by :func:`ro`, is consistent
+ according to C3.
+ """
+ return not C3.resolver(C, False, None).had_inconsistency
diff --git a/contrib/python/zope.interface/py2/zope/interface/verify.py b/contrib/python/zope.interface/py2/zope/interface/verify.py
new file mode 100644
index 0000000000..0a64aeb65c
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/verify.py
@@ -0,0 +1,218 @@
+##############################################################################
+#
+# 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 __future__ import print_function
+import inspect
+import sys
+from types import FunctionType
+from types import MethodType
+
+from zope.interface._compat import PYPY2
+
+from zope.interface.exceptions import BrokenImplementation
+from zope.interface.exceptions import BrokenMethodImplementation
+from zope.interface.exceptions import DoesNotImplement
+from zope.interface.exceptions import Invalid
+from zope.interface.exceptions import MultipleInvalid
+
+from zope.interface.interface import fromMethod, fromFunction, Method
+
+__all__ = [
+ 'verifyObject',
+ 'verifyClass',
+]
+
+# This will be monkey-patched when running under Zope 2, so leave this
+# here:
+MethodTypes = (MethodType, )
+
+
+def _verify(iface, candidate, tentative=False, vtype=None):
+ """
+ Verify that *candidate* might correctly provide *iface*.
+
+ This involves:
+
+ - Making sure the candidate claims that it provides the
+ interface using ``iface.providedBy`` (unless *tentative* is `True`,
+ in which case this step is skipped). This means that the candidate's class
+ declares that it `implements <zope.interface.implementer>` the interface,
+ or the candidate itself declares that it `provides <zope.interface.provider>`
+ the interface
+
+ - Making sure the candidate defines all the necessary methods
+
+ - Making sure the methods have the correct signature (to the
+ extent possible)
+
+ - Making sure the candidate defines all the necessary attributes
+
+ :return bool: Returns a true value if everything that could be
+ checked passed.
+ :raises zope.interface.Invalid: If any of the previous
+ conditions does not hold.
+
+ .. versionchanged:: 5.0
+ If multiple methods or attributes are invalid, all such errors
+ are collected and reported. Previously, only the first error was reported.
+ As a special case, if only one such error is present, it is raised
+ alone, like before.
+ """
+
+ if vtype == 'c':
+ tester = iface.implementedBy
+ else:
+ tester = iface.providedBy
+
+ excs = []
+ if not tentative and not tester(candidate):
+ excs.append(DoesNotImplement(iface, candidate))
+
+ for name, desc in iface.namesAndDescriptions(all=True):
+ try:
+ _verify_element(iface, name, desc, candidate, vtype)
+ except Invalid as e:
+ excs.append(e)
+
+ if excs:
+ if len(excs) == 1:
+ raise excs[0]
+ raise MultipleInvalid(iface, candidate, excs)
+
+ return True
+
+def _verify_element(iface, name, desc, candidate, vtype):
+ # Here the `desc` is either an `Attribute` or `Method` instance
+ 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__.
+ return
+ # TODO: On Python 3, this should use ``raise...from``
+ raise BrokenImplementation(iface, desc, candidate)
+
+ if not isinstance(desc, Method):
+ # If it's not a method, there's nothing else we can test
+ return
+
+ if inspect.ismethoddescriptor(attr) or inspect.isbuiltin(attr):
+ # The first case is what you get for things like ``dict.pop``
+ # on CPython (e.g., ``verifyClass(IFullMapping, dict))``). The
+ # second case is what you get for things like ``dict().pop`` on
+ # CPython (e.g., ``verifyObject(IFullMapping, dict()))``.
+ # In neither case can we get a signature, so there's nothing
+ # to verify. Even the inspect module gives up and raises
+ # ValueError: no signature found. The ``__text_signature__`` attribute
+ # isn't typically populated either.
+ #
+ # Note that on PyPy 2 or 3 (up through 7.3 at least), these are
+ # not true for things like ``dict.pop`` (but might be true for C extensions?)
+ return
+
+ if isinstance(attr, FunctionType):
+ if sys.version_info[0] >= 3 and isinstance(candidate, type) and vtype == 'c':
+ # This is an "unbound method" in Python 3.
+ # Only unwrap this if we're verifying implementedBy;
+ # otherwise we can unwrap @staticmethod on classes that directly
+ # provide an interface.
+ 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.__func__) is FunctionType):
+ meth = fromMethod(attr, iface, name)
+ elif isinstance(attr, property) and vtype == 'c':
+ # Without an instance we cannot be sure it's not a
+ # callable.
+ # TODO: This should probably check inspect.isdatadescriptor(),
+ # a more general form than ``property``
+ return
+
+ else:
+ if not callable(attr):
+ raise BrokenMethodImplementation(desc, "implementation is not a method",
+ attr, iface, candidate)
+ # sigh, it's callable, but we don't know how to introspect it, so
+ # we have to give it a pass.
+ return
+
+ # Make sure that the required and implemented method signatures are
+ # the same.
+ mess = _incompat(desc.getSignatureInfo(), meth.getSignatureInfo())
+ if mess:
+ if PYPY2 and _pypy2_false_positive(mess, candidate, vtype):
+ return
+ raise BrokenMethodImplementation(desc, mess, attr, iface, candidate)
+
+
+
+def verifyClass(iface, candidate, tentative=False):
+ """
+ Verify that the *candidate* might correctly provide *iface*.
+ """
+ return _verify(iface, candidate, tentative, vtype='c')
+
+def verifyObject(iface, candidate, tentative=False):
+ return _verify(iface, candidate, tentative, vtype='o')
+
+verifyObject.__doc__ = _verify.__doc__
+
+_MSG_TOO_MANY = 'implementation requires too many arguments'
+_KNOWN_PYPY2_FALSE_POSITIVES = frozenset((
+ _MSG_TOO_MANY,
+))
+
+
+def _pypy2_false_positive(msg, candidate, vtype):
+ # On PyPy2, builtin methods and functions like
+ # ``dict.pop`` that take pseudo-optional arguments
+ # (those with no default, something you can't express in Python 2
+ # syntax; CPython uses special internal APIs to implement these methods)
+ # return false failures because PyPy2 doesn't expose any way
+ # to detect this pseudo-optional status. PyPy3 doesn't have this problem
+ # because of __defaults_count__, and CPython never gets here because it
+ # returns true for ``ismethoddescriptor`` or ``isbuiltin``.
+ #
+ # We can't catch all such cases, but we can handle the common ones.
+ #
+ if msg not in _KNOWN_PYPY2_FALSE_POSITIVES:
+ return False
+
+ known_builtin_types = vars(__builtins__).values()
+ candidate_type = candidate if vtype == 'c' else type(candidate)
+ if candidate_type in known_builtin_types:
+ return True
+
+ return False
+
+
+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 _MSG_TOO_MANY
+ 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"