r374 - / python-zope.interface python-zope.interface/branches
python-zope.interface/branches/upstream
python-zope.interface/branches/upstream/current
python-zope.interface/branches/upstream/current/src
python-zope.interface/branches/upstream/current/src/zope
python-zope.interface/branches/upstream/current/src/zope/interface
python-zope.interface/branches/upstream/current/src/zope/interface/common
python-zope.interface/branches/upstream/current/src/zope/interface/common/tests
python-zope.interface/branches/upstream/current/src/zope/interface/tests
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info
Brian Sutherland
jinty-guest at alioth.debian.org
Sun Oct 29 20:29:27 CET 2006
Author: jinty-guest
Date: 2006-10-29 20:28:25 +0100 (Sun, 29 Oct 2006)
New Revision: 374
Added:
python-zope.interface/
python-zope.interface/branches/
python-zope.interface/branches/upstream/
python-zope.interface/branches/upstream/current/
python-zope.interface/branches/upstream/current/CHANGES.txt
python-zope.interface/branches/upstream/current/INSTALL.txt
python-zope.interface/branches/upstream/current/MANIFEST.in
python-zope.interface/branches/upstream/current/PKG-INFO
python-zope.interface/branches/upstream/current/README.txt
python-zope.interface/branches/upstream/current/setup.cfg
python-zope.interface/branches/upstream/current/setup.py
python-zope.interface/branches/upstream/current/src/
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/PKG-INFO
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/dependency_links.txt
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/native_libs.txt
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/not-zip-safe
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/top_level.txt
python-zope.interface/branches/upstream/current/src/zope/
python-zope.interface/branches/upstream/current/src/zope/__init__.py
python-zope.interface/branches/upstream/current/src/zope/interface/
python-zope.interface/branches/upstream/current/src/zope/interface/DEPENDENCIES.cfg
python-zope.interface/branches/upstream/current/src/zope/interface/PUBLICATION.cfg
python-zope.interface/branches/upstream/current/src/zope/interface/README.ru.txt
python-zope.interface/branches/upstream/current/src/zope/interface/README.txt
python-zope.interface/branches/upstream/current/src/zope/interface/SETUP.cfg
python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py
python-zope.interface/branches/upstream/current/src/zope/interface/_flatten.py
python-zope.interface/branches/upstream/current/src/zope/interface/_zope_interface_coptimizations.c
python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py
python-zope.interface/branches/upstream/current/src/zope/interface/adapter.txt
python-zope.interface/branches/upstream/current/src/zope/interface/advice.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/
python-zope.interface/branches/upstream/current/src/zope/interface/common/__init__.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/idatetime.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/mapping.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/
python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/__init__.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/basemapping.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_idatetime.py
python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py
python-zope.interface/branches/upstream/current/src/zope/interface/document.py
python-zope.interface/branches/upstream/current/src/zope/interface/exceptions.py
python-zope.interface/branches/upstream/current/src/zope/interface/human.ru.txt
python-zope.interface/branches/upstream/current/src/zope/interface/human.txt
python-zope.interface/branches/upstream/current/src/zope/interface/interface.py
python-zope.interface/branches/upstream/current/src/zope/interface/interfaces.py
python-zope.interface/branches/upstream/current/src/zope/interface/ro.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/
python-zope.interface/branches/upstream/current/src/zope/interface/tests/__init__.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/foodforthought.txt
python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/odd.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_advice.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_declarations.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_document.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_element.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_interface.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_odd_declarations.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_sorting.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_verify.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/unitfixtures.py
python-zope.interface/branches/upstream/current/src/zope/interface/verify.py
python-zope.interface/tags/
Log:
[svn-inject] Installing original source of python-zope.interface
Added: python-zope.interface/branches/upstream/current/CHANGES.txt
===================================================================
--- python-zope.interface/branches/upstream/current/CHANGES.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/CHANGES.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,54 @@
+zope.interface Package Changelog
+================================
+
+zope.interface version 3.2.0.2 (2006/04/15)
+-------------------------------------------
+
+- Fix packaging bug: 'package_dir' must be a *relative* path.
+
+
+zope.interface version 3.2.0.1 (2006/04/14)
+-------------------------------------------
+
+- Packaging change: suppress inclusion of 'setup.cfg' in 'sdist' builds.
+
+
+zope.interface version 3.2.0 (2006/01/05)
+-----------------------------------------
+
+- Corresponds to the verison of the zope.interface package shipped as part of
+ the Zope 3.2.0 release.
+
+- TODO: note other changes
+
+
+zope.interface version 3.1.0 (2005/10/03)
+-----------------------------------------
+
+- Corresponds to the verison of the zope.interface package shipped as part of
+ the Zope 3.1.0 release.
+
+- TODO: note other changes
+
+- Made attribute resolution order consistent with component lookup order,
+ i.e. new-style class MRO semantics.
+
+- Deprecated 'isImplementedBy' and 'isImplementedByInstancesOf' APIs in
+ favor of 'implementedBy' and 'providedBy'.
+
+
+zope.interface version 3.0.1 (2005/07/27)
+-----------------------------------------
+
+- Corresponds to the verison of the zope.interface package shipped as part of
+ the Zope X3.0.1 release.
+
+- Fixed a bug reported by James Knight, which caused adapter registries
+ to fail occasionally to reflect declaration changes.
+
+
+zope.interface version 3.0.0 (2004/11/07)
+-----------------------------------------
+
+- Corresponds to the verison of the zope.interface package shipped as part of
+ the Zope X3.0.0 release.
Property changes on: python-zope.interface/branches/upstream/current/CHANGES.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/INSTALL.txt
===================================================================
--- python-zope.interface/branches/upstream/current/INSTALL.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/INSTALL.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,83 @@
+Installing This Package
+=======================
+
+Prerequisites
+-------------
+
+The installation steps below assume that you have the cool new 'setuptools'
+package installed in your Python. Here is where to get it:
+
+ $ wget http://peak.telecommunity.com/dist/ez_setup.py
+ $ /path/to/your/python ez_setup.py # req. write access to 'site-packages'
+
+
+ - Docs for EasyInstall:
+ http://peak.telecommunity.com/DevCenter/EasyInstall
+
+ - Docs for setuptools:
+ http://peak.telecommunity.com/DevCenter/setuptools
+
+ - Docs for eggs:
+ http://peak.telecommunity.com/DevCenter/PythonEggs
+
+
+Installing a Development Checkout
+---------------------------------
+
+Check out the package from subversion:
+
+ $ svn co svn+ssh://svn.zope.org/repos/main/zope.interface/trunk \
+ src/zope.interface
+ $ cd src/zope.interface
+
+Install it as a "devlopment egg" (which also installs its "hard"
+dependencies):
+
+ $ /path/to/your/python setup.py develop
+
+The installation of dependency eggs uses the 'setup.cfg' file in
+the checkout. You can supply '--find-links' on the command line to
+point it at a non-standard package repository.
+
+
+Running the Tests
+-----------------
+
+To test the package, you will also need the 'zope.testing' package, which
+can't (yet) be automatically installed. Eventually, you should be able to
+type:
+
+ $ /path/to/your/python setup.py test
+
+and have it install the "testing dependencies." Today, the workaround
+is to install it manually:
+
+ $ /path/to/easy_install --find-links="...." zope.testing
+
+You can then run the tests (finally) from the checkout directory:
+
+ $ /path/to/your/python test.py
+ Running:
+ .............
+ Ran 13 tests with 0 failures and 0 errors in 0.094 seconds.
+
+
+Installing a Source Distribution
+--------------------------------
+
+You can also install it from a source distribution:
+
+ $ /path/to/easy_install --find-links="...." -eb src zope.interface
+ $ cd src/zope.interface
+ $ /path/to/your/python setup.py develop
+
+
+Installing a Binary Egg
+-----------------------
+
+Install the package as a "binary egg" (which also installs its "hard"
+dependencies):
+
+ $ /path/to/easy_install --find-links="...." zope.interface
+
+
Property changes on: python-zope.interface/branches/upstream/current/INSTALL.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/MANIFEST.in
===================================================================
--- python-zope.interface/branches/upstream/current/MANIFEST.in 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/MANIFEST.in 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1 @@
+exclude setup.cfg
Added: python-zope.interface/branches/upstream/current/PKG-INFO
===================================================================
--- python-zope.interface/branches/upstream/current/PKG-INFO 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/PKG-INFO 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: zope.interface
+Version: 3.3.0b2
+Summary: Zope 3 Interface Infrastructure
+Home-page: http://svn.zope.org/zope.interface
+Author: Zope Corporation and Contributors
+Author-email: zope3-dev at zope.org
+License: ZPL 2.1
+Description: UNKNOWN
+Platform: UNKNOWN
Added: python-zope.interface/branches/upstream/current/README.txt
===================================================================
--- python-zope.interface/branches/upstream/current/README.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/README.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,40 @@
+zope.interface Package Readme
+=============================
+
+Overview
+--------
+
+Interfaces are a mechanism for labeling objects as conforming to a given
+API or contract.
+
+See ./src/zope/interface/README.txt for details and example usage.
+
+Changes
+-------
+
+See CHANGES.txt.
+
+Installation
+------------
+
+See INSTALL.txt.
+
+
+Developer Resources
+-------------------
+
+- Subversion browser:
+
+ http://svn.zope.org/zope.interface/
+
+- Read-only Subversion checkout:
+
+ $ svn co svn://svn.zope.org/repos/main/zope.interface/trunk
+
+- Writable Subversion checkout:
+
+ $ svn co svn://svn.zope.org/repos/main/zope.interface/trunk
+
+- Note that the 'src/zope/interface' package is acutally a 'svn:externals'
+ link to the corresponding package in the Zope3 trunk (or to a specific tag,
+ for released versions of the package).
Property changes on: python-zope.interface/branches/upstream/current/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/setup.cfg
===================================================================
--- python-zope.interface/branches/upstream/current/setup.cfg 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/setup.cfg 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build =
+tag_date = 0
+tag_svn_revision = 0
+
Added: python-zope.interface/branches/upstream/current/setup.py
===================================================================
--- python-zope.interface/branches/upstream/current/setup.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/setup.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,51 @@
+##############################################################################
+#
+# Copyright (c) 2004-2006 Zope Corporation 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.
+#
+##############################################################################
+"""Setup for zope.interface package
+
+$Id$
+"""
+
+import os
+
+try:
+ from setuptools import setup, Extension
+except ImportError, e:
+ from distutils.core import setup, Extension
+
+setup(name='zope.interface',
+ version='3.3.0b2',
+
+ url='http://svn.zope.org/zope.interface',
+ license='ZPL 2.1',
+ description='Zope 3 Interface Infrastructure',
+ author='Zope Corporation and Contributors',
+ author_email='zope3-dev at zope.org',
+
+ packages=["zope",
+ "zope.interface",
+ "zope.interface.common",
+ "zope.interface.tests",
+ ],
+ package_dir = {'': 'src'},
+ ext_package='zope.interface',
+ ext_modules=[Extension("_zope_interface_coptimizations",
+ [os.path.join('src', 'zope', 'interface',
+ "_zope_interface_coptimizations.c")
+ ]),
+ ],
+
+ tests_require = ['zope.testing'],
+ include_package_data = True,
+ zip_safe = False,
+ )
Property changes on: python-zope.interface/branches/upstream/current/setup.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/__init__.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/__init__.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/__init__.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
Property changes on: python-zope.interface/branches/upstream/current/src/zope/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/DEPENDENCIES.cfg
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/DEPENDENCIES.cfg 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/DEPENDENCIES.cfg 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1 @@
+zope.testing
Added: python-zope.interface/branches/upstream/current/src/zope/interface/PUBLICATION.cfg
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/PUBLICATION.cfg 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/PUBLICATION.cfg 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,8 @@
+Metadata-Version: 1.0
+Name: zope.interface
+Summary: Zope 3 Interface Infrastructure
+Author: Zope Corporation and Contributors
+Author-email: zope3-dev at zope.org
+License: ZPL 2.1
+Description:
+ The implementation of interface definitions for Zope 3.
Added: python-zope.interface/branches/upstream/current/src/zope/interface/README.ru.txt
===================================================================
(Binary files differ)
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/README.ru.txt
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/README.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/README.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/README.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,807 @@
+==========
+Interfaces
+==========
+
+.. contents::
+
+Interfaces are objects that specify (document) the external behavior
+of objects that "provide" them. An interface specifies behavior
+through:
+
+- Informal documentation in a doc string
+
+- Attribute definitions
+
+- Invariants, which are conditions that must hold for objects that
+ provide the interface
+
+Attribute definitions specify specific attributes. They define the
+attribute name and provide documentation and constraints of attribute
+values. Attribute definitions can take a number of forms, as we'll
+see below.
+
+Defining interfaces
+===================
+
+Interfaces are defined using Python class statements:
+
+ >>> import zope.interface
+ >>> class IFoo(zope.interface.Interface):
+ ... """Foo blah blah"""
+ ...
+ ... x = zope.interface.Attribute("""X blah blah""")
+ ...
+ ... def bar(q, r=None):
+ ... """bar blah blah"""
+
+In the example above, we've created an interface, `IFoo`. We
+subclassed `zope.interface.Interface`, which is an ancestor interface for
+all interfaces, much as `object` is an ancestor of all new-style
+classes [#create]_. The interface is not a class, it's an Interface,
+an instance of `InterfaceClass`::
+
+ >>> type(IFoo)
+ <class 'zope.interface.interface.InterfaceClass'>
+
+We can ask for the interface's documentation::
+
+ >>> IFoo.__doc__
+ 'Foo blah blah'
+
+and its name::
+
+ >>> IFoo.__name__
+ 'IFoo'
+
+and even its module::
+
+ >>> IFoo.__module__
+ '__main__'
+
+The interface defined two attributes:
+
+`x`
+ This is the simplest form of attribute definition. It has a name
+ and a doc string. It doesn't formally specify anything else.
+
+`bar`
+ This is a method. A method is defined via a function definition. A
+ method is simply an attribute constrained to be a callable with a
+ particular signature, as provided by the function definition.
+
+ Note that `bar` doesn't take a `self` argument. Interfaces document
+ how an object is *used*. When calling instance methods, you don't
+ pass a `self` argument, so a `self` argument isn't included in the
+ interface signature. The `self` argument in instance methods is
+ really an implementation detail of Python instances. Other objects,
+ besides instances can provide interfaces and their methods might not
+ be instance methods. For example, modules can provide interfaces and
+ their methods are usually just functions. Even instances can have
+ methods that are not instance methods.
+
+You can access the attributes defined by an interface using mapping
+syntax::
+
+ >>> x = IFoo['x']
+ >>> type(x)
+ <class 'zope.interface.interface.Attribute'>
+ >>> x.__name__
+ 'x'
+ >>> x.__doc__
+ 'X blah blah'
+
+ >>> IFoo.get('x').__name__
+ 'x'
+
+ >>> IFoo.get('y')
+
+You can use `in` to determine if an interface defines a name::
+
+ >>> 'x' in IFoo
+ True
+
+You can iterate over interfaces to get the names they define::
+
+ >>> names = list(IFoo)
+ >>> names.sort()
+ >>> names
+ ['bar', 'x']
+
+Remember that interfaces aren't classes. You can't access attribute
+definitions as attributes of interfaces::
+
+ >>> IFoo.x
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ AttributeError: 'InterfaceClass' object has no attribute 'x'
+
+Methods provide access to the method signature::
+
+ >>> bar = IFoo['bar']
+ >>> bar.getSignatureString()
+ '(q, r=None)'
+
+TODO
+ Methods really should have a better API. This is something that
+ needs to be improved.
+
+Declaring interfaces
+====================
+
+Having defined interfaces, we can *declare* that objects provide
+them. Before we describe the details, lets define some terms:
+
+*provide*
+ We say that objects *provide* interfaces. If an object provides an
+ interface, then the interface specifies the behavior of the
+ object. In other words, interfaces specify the behavior of the
+ objects that provide them.
+
+*implement*
+ We normally say that classes *implement* interfaces. If a class
+ implements an interface, then the instances of the class provide
+ the interface. Objects provide interfaces that their classes
+ implement [#factory]_. (Objects can provide interfaces directly,
+ in addition to what their classes implement.)
+
+ It is important to note that classes don't usually provide the
+ interfaces that they implement.
+
+ We can generalize this to factories. For any callable object we
+ can declare that it produces objects that provide some interfaces
+ by saying that the factory implements the interfaces.
+
+Now that we've defined these terms, we can talk about the API for
+declaring interfaces.
+
+Declaring implemented interfaces
+--------------------------------
+
+The most common way to declare interfaces is using the implements
+function in a class statement::
+
+ >>> class Foo:
+ ... zope.interface.implements(IFoo)
+ ...
+ ... def __init__(self, x=None):
+ ... self.x = x
+ ...
+ ... def bar(self, q, r=None):
+ ... return q, r, self.x
+ ...
+ ... def __repr__(self):
+ ... return "Foo(%s)" % self.x
+
+
+In this example, we declared that `Foo` implements `IFoo`. This means
+that instances of `Foo` provide `IFoo`. Having made this declaration,
+there are several ways we can introspect the declarations. First, we
+can ask an interface whether it is implemented by a class::
+
+ >>> IFoo.implementedBy(Foo)
+ True
+
+And we can ask whether an interface is provided by an object::
+
+ >>> foo = Foo()
+ >>> IFoo.providedBy(foo)
+ True
+
+Of course, `Foo` doesn't provide `IFoo`, it implements it::
+
+ >>> IFoo.providedBy(Foo)
+ False
+
+We can also ask what interfaces are implemented by an object::
+
+ >>> list(zope.interface.implementedBy(Foo))
+ [<InterfaceClass __main__.IFoo>]
+
+It's an error to ask for interfaces implemented by a non-callable
+object::
+
+ >>> IFoo.implementedBy(foo)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+ >>> list(zope.interface.implementedBy(foo))
+ Traceback (most recent call last):
+ ...
+ TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+Similarly, we can ask what interfaces are provided by an object::
+
+ >>> list(zope.interface.providedBy(foo))
+ [<InterfaceClass __main__.IFoo>]
+ >>> list(zope.interface.providedBy(Foo))
+ []
+
+We can declare interfaces implemented by other factories (besides
+classes). We do this using a Python-2.4-style decorator named
+`implementer`. In versions of Python before 2.4, this looks like:
+
+
+ >>> def yfoo(y):
+ ... foo = Foo()
+ ... foo.y = y
+ ... return foo
+ >>> yfoo = zope.interface.implementer(IFoo)(yfoo)
+
+ >>> list(zope.interface.implementedBy(yfoo))
+ [<InterfaceClass __main__.IFoo>]
+
+Note that the implementer decorator may modify it's argument. Callers
+should not assume that a new object is created.
+
+Also note that, at least for now, implementer can't be used with
+classes:
+
+ >>> zope.interface.implementer(IFoo)(Foo)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't use implementer with classes.
+ Use one of the class-declaration functions instead.
+
+Declaring provided interfaces
+-----------------------------
+
+We can declare interfaces directly provided by objects. Suppose that
+we want to document what the `__init__` method of the `Foo` class
+does. It's not *really* part of `IFoo`. You wouldn't normally call
+the `__init__` method on Foo instances. Rather, the `__init__` method
+is part of the `Foo`'s `__call__` method::
+
+ >>> class IFooFactory(zope.interface.Interface):
+ ... """Create foos"""
+ ...
+ ... def __call__(x=None):
+ ... """Create a foo
+ ...
+ ... The argument provides the initial value for x ...
+ ... """
+
+It's the class that provides this interface, so we declare the
+interface on the class::
+
+ >>> zope.interface.directlyProvides(Foo, IFooFactory)
+
+And then, we'll see that Foo provides some interfaces::
+
+ >>> list(zope.interface.providedBy(Foo))
+ [<InterfaceClass __main__.IFooFactory>]
+ >>> IFooFactory.providedBy(Foo)
+ True
+
+Declaring class interfaces is common enough that there's a special
+declaration function for it, `classProvides`, that allows the
+declaration from within a class statement::
+
+ >>> class Foo2:
+ ... zope.interface.implements(IFoo)
+ ... zope.interface.classProvides(IFooFactory)
+ ...
+ ... def __init__(self, x=None):
+ ... self.x = x
+ ...
+ ... def bar(self, q, r=None):
+ ... return q, r, self.x
+ ...
+ ... def __repr__(self):
+ ... return "Foo(%s)" % self.x
+
+ >>> list(zope.interface.providedBy(Foo2))
+ [<InterfaceClass __main__.IFooFactory>]
+ >>> IFooFactory.providedBy(Foo2)
+ True
+
+There's a similar function, `moduleProvides`, that supports interface
+declarations from within module definitions. For example, see the use
+of `moduleProvides` call in `zope.interface.__init__`, which declares that
+the package `zope.interface` provides `IInterfaceDeclaration`.
+
+Sometimes, we want to declare interfaces on instances, even though
+those instances get interfaces from their classes. Suppose we create
+a new interface, `ISpecial`::
+
+ >>> class ISpecial(zope.interface.Interface):
+ ... reason = zope.interface.Attribute("Reason why we're special")
+ ... def brag():
+ ... "Brag about being special"
+
+We can make an existing foo instance special by providing `reason`
+and `brag` attributes::
+
+ >>> foo.reason = 'I just am'
+ >>> def brag():
+ ... return "I'm special!"
+ >>> foo.brag = brag
+ >>> foo.reason
+ 'I just am'
+ >>> foo.brag()
+ "I'm special!"
+
+and by declaring the interface::
+
+ >>> zope.interface.directlyProvides(foo, ISpecial)
+
+then the new interface is included in the provided interfaces::
+
+ >>> ISpecial.providedBy(foo)
+ True
+ >>> list(zope.interface.providedBy(foo))
+ [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+We can find out what interfaces are directly provided by an object::
+
+ >>> list(zope.interface.directlyProvidedBy(foo))
+ [<InterfaceClass __main__.ISpecial>]
+
+ >>> newfoo = Foo()
+ >>> list(zope.interface.directlyProvidedBy(newfoo))
+ []
+
+Inherited declarations
+----------------------
+
+Normally, declarations are inherited::
+
+ >>> class SpecialFoo(Foo):
+ ... zope.interface.implements(ISpecial)
+ ... reason = 'I just am'
+ ... def brag(self):
+ ... return "I'm special because %s" % self.reason
+
+ >>> list(zope.interface.implementedBy(SpecialFoo))
+ [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+ >>> list(zope.interface.providedBy(SpecialFoo()))
+ [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+Sometimes, you don't want to inherit declarations. In that case, you
+can use `implementsOnly`, instead of `implements`::
+
+ >>> class Special(Foo):
+ ... zope.interface.implementsOnly(ISpecial)
+ ... reason = 'I just am'
+ ... def brag(self):
+ ... return "I'm special because %s" % self.reason
+
+ >>> list(zope.interface.implementedBy(Special))
+ [<InterfaceClass __main__.ISpecial>]
+
+ >>> list(zope.interface.providedBy(Special()))
+ [<InterfaceClass __main__.ISpecial>]
+
+External declarations
+---------------------
+
+Normally, we make implementation declarations as part of a class
+definition. Sometimes, we may want to make declarations from outside
+the class definition. For example, we might want to declare interfaces
+for classes that we didn't write. The function `classImplements` can
+be used for this purpose::
+
+ >>> class C:
+ ... pass
+
+ >>> zope.interface.classImplements(C, IFoo)
+ >>> list(zope.interface.implementedBy(C))
+ [<InterfaceClass __main__.IFoo>]
+
+We can use `classImplementsOnly` to exclude inherited interfaces::
+
+ >>> class C(Foo):
+ ... pass
+
+ >>> zope.interface.classImplementsOnly(C, ISpecial)
+ >>> list(zope.interface.implementedBy(C))
+ [<InterfaceClass __main__.ISpecial>]
+
+
+
+Declaration Objects
+-------------------
+
+When we declare interfaces, we create *declaration* objects. When we
+query declarations, declaration objects are returned::
+
+ >>> type(zope.interface.implementedBy(Special))
+ <class 'zope.interface.declarations.Implements'>
+
+Declaration objects and interface objects are similar in many ways. In
+fact, they share a common base class. The important thing to realize
+about them is that they can be used where interfaces are expected in
+declarations. Here's a silly example::
+
+ >>> class Special2(Foo):
+ ... zope.interface.implementsOnly(
+ ... zope.interface.implementedBy(Foo),
+ ... ISpecial,
+ ... )
+ ... reason = 'I just am'
+ ... def brag(self):
+ ... return "I'm special because %s" % self.reason
+
+The declaration here is almost the same as
+``zope.interface.implements(ISpecial)``, except that the order of
+interfaces in the resulting declaration is different::
+
+ >>> list(zope.interface.implementedBy(Special2))
+ [<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.ISpecial>]
+
+
+Interface Inheritance
+=====================
+
+Interfaces can extend other interfaces. They do this simply by listing
+the other interfaces as base interfaces::
+
+ >>> class IBlat(zope.interface.Interface):
+ ... """Blat blah blah"""
+ ...
+ ... y = zope.interface.Attribute("y blah blah")
+ ... def eek():
+ ... """eek blah blah"""
+
+ >>> IBlat.__bases__
+ (<InterfaceClass zope.interface.Interface>,)
+
+ >>> class IBaz(IFoo, IBlat):
+ ... """Baz blah"""
+ ... def eek(a=1):
+ ... """eek in baz blah"""
+ ...
+
+ >>> IBaz.__bases__
+ (<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.IBlat>)
+
+ >>> names = list(IBaz)
+ >>> names.sort()
+ >>> names
+ ['bar', 'eek', 'x', 'y']
+
+Note that `IBaz` overrides eek::
+
+ >>> IBlat['eek'].__doc__
+ 'eek blah blah'
+ >>> IBaz['eek'].__doc__
+ 'eek in baz blah'
+
+We were careful to override eek in a compatible way. When extending
+an interface, the extending interface should be compatible [#compat]_
+with the extended interfaces.
+
+We can ask whether one interface extends another::
+
+ >>> IBaz.extends(IFoo)
+ True
+ >>> IBlat.extends(IFoo)
+ False
+
+Note that interfaces don't extend themselves::
+
+ >>> IBaz.extends(IBaz)
+ False
+
+Sometimes we wish they did, but we can, instead use `isOrExtends`::
+
+ >>> IBaz.isOrExtends(IBaz)
+ True
+ >>> IBaz.isOrExtends(IFoo)
+ True
+ >>> IFoo.isOrExtends(IBaz)
+ False
+
+When we iterate over an interface, we get all of the names it defines,
+including names defined by base interfaces. Sometimes, we want *just*
+the names defined by the interface directly. We bane use the `names`
+method for that::
+
+ >>> list(IBaz.names())
+ ['eek']
+
+Inheritance of attribute specifications
+---------------------------------------
+
+An interface may override attribute definitions from base interfaces.
+If two base interfaces define the same attribute, the attribute is
+inherited from the most specific interface. For example, with:
+
+ >>> class IBase(zope.interface.Interface):
+ ...
+ ... def foo():
+ ... "base foo doc"
+
+ >>> class IBase1(IBase):
+ ... pass
+
+ >>> class IBase2(IBase):
+ ...
+ ... def foo():
+ ... "base2 foo doc"
+
+ >>> class ISub(IBase1, IBase2):
+ ... pass
+
+ISub's definition of foo is the one from IBase2, since IBase2 is more
+specific that IBase:
+
+ >>> ISub['foo'].__doc__
+ 'base2 foo doc'
+
+Note that this differs from a depth-first search.
+
+Sometimes, it's useful to ask whether an interface defines an
+attribute directly. You can use the direct method to get a directly
+defined definitions:
+
+ >>> IBase.direct('foo').__doc__
+ 'base foo doc'
+
+ >>> ISub.direct('foo')
+
+Specifications
+--------------
+
+Interfaces and declarations are both special cases of specifications.
+What we described above for interface inheritance applies to both
+declarations and specifications. Declarations actually extend the
+interfaces that they declare:
+
+ >>> class Baz:
+ ... zope.interface.implements(IBaz)
+
+ >>> baz_implements = zope.interface.implementedBy(Baz)
+ >>> baz_implements.__bases__
+ (<InterfaceClass __main__.IBaz>,)
+
+ >>> baz_implements.extends(IFoo)
+ True
+
+ >>> baz_implements.isOrExtends(IFoo)
+ True
+ >>> baz_implements.isOrExtends(baz_implements)
+ True
+
+Specifications (interfaces and declarations) provide an `__sro__`
+that lists the specification and all of it's ancestors:
+
+ >>> baz_implements.__sro__
+ (<implementedBy __main__.Baz>,
+ <InterfaceClass __main__.IBaz>,
+ <InterfaceClass __main__.IFoo>,
+ <InterfaceClass __main__.IBlat>,
+ <InterfaceClass zope.interface.Interface>)
+
+
+Tagged Values
+=============
+
+Interfaces and attribute descriptions support an extension mechanism,
+borrowed from UML, called "tagged values" that lets us store extra
+data::
+
+ >>> IFoo.setTaggedValue('date-modified', '2004-04-01')
+ >>> IFoo.setTaggedValue('author', 'Jim Fulton')
+ >>> IFoo.getTaggedValue('date-modified')
+ '2004-04-01'
+ >>> IFoo.queryTaggedValue('date-modified')
+ '2004-04-01'
+ >>> IFoo.queryTaggedValue('datemodified')
+ >>> tags = list(IFoo.getTaggedValueTags())
+ >>> tags.sort()
+ >>> tags
+ ['author', 'date-modified']
+
+Function attributes are converted to tagged values when method
+attribute definitions are created::
+
+ >>> class IBazFactory(zope.interface.Interface):
+ ... def __call__():
+ ... "create one"
+ ... __call__.return_type = IBaz
+
+ >>> IBazFactory['__call__'].getTaggedValue('return_type')
+ <InterfaceClass __main__.IBaz>
+
+
+Invariants
+==========
+
+Interfaces can express conditions that must hold for objects that
+provide them. These conditions are expressed using one or more
+invariants. Invariants are callable objects that will be called with
+an object that provides an interface. An invariant raises an `Invalid`
+exception if the condition doesn't hold. Here's an example::
+
+ >>> class RangeError(zope.interface.Invalid):
+ ... """A range has invalid limits"""
+ ... def __repr__(self):
+ ... return "RangeError(%r)" % self.args
+
+ >>> def range_invariant(ob):
+ ... if ob.max < ob.min:
+ ... raise RangeError(ob)
+
+Given this invariant, we can use it in an interface definition::
+
+ >>> class IRange(zope.interface.Interface):
+ ... min = zope.interface.Attribute("Lower bound")
+ ... max = zope.interface.Attribute("Upper bound")
+ ...
+ ... zope.interface.invariant(range_invariant)
+
+Interfaces have a method for checking their invariants::
+
+ >>> class Range(object):
+ ... zope.interface.implements(IRange)
+ ...
+ ... def __init__(self, min, max):
+ ... self.min, self.max = min, max
+ ...
+ ... def __repr__(self):
+ ... return "Range(%s, %s)" % (self.min, self.max)
+
+ >>> IRange.validateInvariants(Range(1,2))
+ >>> IRange.validateInvariants(Range(1,1))
+ >>> IRange.validateInvariants(Range(2,1))
+ Traceback (most recent call last):
+ ...
+ RangeError: Range(2, 1)
+
+If you have multiple invariants, you may not want to stop checking
+after the first error. If you pass a list to `validateInvariants`,
+then a single `Invalid` exception will be raised with the list of
+exceptions as it's argument::
+
+ >>> errors = []
+ >>> IRange.validateInvariants(Range(2,1), errors)
+ Traceback (most recent call last):
+ ...
+ Invalid: [RangeError(Range(2, 1))]
+
+And the list will be filled with the individual exceptions::
+
+ >>> errors
+ [RangeError(Range(2, 1))]
+
+
+ >>> del errors[:]
+
+==========
+Adaptation
+==========
+
+Interfaces can be called to perform adaptation.
+
+The sematics based on those of the PEP 246 adapt function.
+
+If an object cannot be adapted, then a TypeError is raised::
+
+ >>> class I(zope.interface.Interface):
+ ... pass
+
+ >>> I(0)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>)
+
+
+
+unless an alternate value is provided as a second positional argument::
+
+ >>> I(0, 'bob')
+ 'bob'
+
+If an object already implements the interface, then it will be returned::
+
+ >>> class C(object):
+ ... zope.interface.implements(I)
+
+ >>> obj = C()
+ >>> I(obj) is obj
+ True
+
+If an object implements __conform__, then it will be used::
+
+ >>> class C(object):
+ ... zope.interface.implements(I)
+ ... def __conform__(self, proto):
+ ... return 0
+
+ >>> I(C())
+ 0
+
+Adapter hooks (see __adapt__) will also be used, if present:
+
+ >>> from zope.interface.interface import adapter_hooks
+ >>> def adapt_0_to_42(iface, obj):
+ ... if obj == 0:
+ ... return 42
+
+ >>> adapter_hooks.append(adapt_0_to_42)
+ >>> I(0)
+ 42
+
+ >>> adapter_hooks.remove(adapt_0_to_42)
+ >>> I(0)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>)
+
+__adapt__
+=========
+
+ >>> class I(zope.interface.Interface):
+ ... pass
+
+Interfaces implement the PEP 246 __adapt__ method.
+
+This method is normally not called directly. It is called by the PEP
+246 adapt framework and by the interface __call__ operator.
+
+The adapt method is responsible for adapting an object to the
+reciever.
+
+The default version returns None::
+
+ >>> I.__adapt__(0)
+
+unless the object given provides the interface::
+
+ >>> class C(object):
+ ... zope.interface.implements(I)
+
+ >>> obj = C()
+ >>> I.__adapt__(obj) is obj
+ True
+
+Adapter hooks can be provided (or removed) to provide custom
+adaptation. We'll install a silly hook that adapts 0 to 42.
+We install a hook by simply adding it to the adapter_hooks
+list::
+
+ >>> from zope.interface.interface import adapter_hooks
+ >>> def adapt_0_to_42(iface, obj):
+ ... if obj == 0:
+ ... return 42
+
+ >>> adapter_hooks.append(adapt_0_to_42)
+ >>> I.__adapt__(0)
+ 42
+
+Hooks must either return an adapter, or None if no adapter can
+be found.
+
+Hooks can be uninstalled by removing them from the list::
+
+ >>> adapter_hooks.remove(adapt_0_to_42)
+ >>> I.__adapt__(0)
+
+
+.. [#create] The main reason we subclass `Interface` is to cause the
+ Python class statement to create an interface, rather
+ than a class.
+
+ It's possible to create interfaces by calling a special
+ interface class directly. Doing this, it's possible
+ (and, on rare occasions, useful) to create interfaces
+ that don't descend from `Interface`. Using this
+ technique is beyond the scope of this document.
+
+.. [#factory] Classes are factories. They can be called to create
+ their instances. We expect that we will eventually
+ extend the concept of implementation to other kinds of
+ factories, so that we can declare the interfaces
+ provided by the objects created.
+
+.. [#compat] The goal is substitutability. An object that provides an
+ extending interface should be substitutable for an object
+ that provides the extended interface. In our example, an
+ object that provides IBaz should be usable whereever an
+ object that provides IBlat is expected.
+
+ The interface implementation doesn't enforce this.
+ but maybe it should do some checks.
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/SETUP.cfg
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/SETUP.cfg 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/SETUP.cfg 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,5 @@
+# Extension information for zpkg:
+
+<extension _zope_interface_coptimizations>
+ source _zope_interface_coptimizations.c
+</extension>
Added: python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,80 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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.
+
+$Id: __init__.py 67630 2006-04-27 00:54:03Z jim $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.interface.interface import Interface, _wire
+
+# Need to actually get the interface elements to implement the right interfaces
+_wire()
+del _wire
+
+from zope.interface.interface import Attribute, invariant
+
+from zope.interface.declarations import providedBy, implementedBy
+from zope.interface.declarations import classImplements, classImplementsOnly
+from zope.interface.declarations import directlyProvidedBy, directlyProvides
+from zope.interface.declarations import alsoProvides, implementer
+from zope.interface.declarations import implements, implementsOnly
+from zope.interface.declarations import classProvides, moduleProvides
+from zope.interface.declarations import noLongerProvides, Declaration
+from zope.interface.exceptions import Invalid
+
+# The following are to make spec pickles cleaner
+from zope.interface.declarations import Provides
+
+
+from zope.interface.interfaces import IInterfaceDeclaration
+
+moduleProvides(IInterfaceDeclaration)
+
+__all__ = ('Interface', 'Attribute') + tuple(IInterfaceDeclaration)
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/_flatten.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/_flatten.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/_flatten.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation 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.
+
+$Id: _flatten.py 26551 2004-07-15 07:06:37Z srichter $
+"""
+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
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/_flatten.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/_zope_interface_coptimizations.c
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/_zope_interface_coptimizations.c 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/_zope_interface_coptimizations.c 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,1647 @@
+/*###########################################################################
+ #
+ # Copyright (c) 2003 Zope Corporation and Contributors.
+ # All Rights Reserved.
+ #
+ # This software is subject to the provisions of the Zope Public License,
+ # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+ # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+ # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+ # FOR A PARTICULAR PURPOSE.
+ #
+ ############################################################################*/
+
+#include "Python.h"
+#include "structmember.h"
+
+#define TYPE(O) ((PyTypeObject*)(O))
+#define OBJECT(O) ((PyObject*)(O))
+#define CLASSIC(O) ((PyClassObject*)(O))
+
+static PyObject *str__dict__, *str__implemented__, *strextends;
+static PyObject *BuiltinImplementationSpecifications, *str__provides__;
+static PyObject *str__class__, *str__providedBy__;
+static PyObject *empty, *fallback, *str_implied, *str_cls, *str_implements;
+static PyObject *str__conform__, *str_call_conform, *adapter_hooks;
+static PyObject *str_uncached_lookup, *str_uncached_lookupAll;
+static PyObject *str_uncached_subscriptions;
+static PyObject *str_registry, *strro, *str_generation, *strchanged;
+
+static PyTypeObject *Implements;
+
+static int imported_declarations = 0;
+
+static int
+import_declarations(void)
+{
+ PyObject *declarations, *i;
+
+ declarations = PyImport_ImportModule("zope.interface.declarations");
+ if (declarations == NULL)
+ return -1;
+
+ BuiltinImplementationSpecifications = PyObject_GetAttrString(
+ declarations, "BuiltinImplementationSpecifications");
+ if (BuiltinImplementationSpecifications == NULL)
+ return -1;
+
+ empty = PyObject_GetAttrString(declarations, "_empty");
+ if (empty == NULL)
+ return -1;
+
+ fallback = PyObject_GetAttrString(declarations, "implementedByFallback");
+ if (fallback == NULL)
+ return -1;
+
+
+
+ i = PyObject_GetAttrString(declarations, "Implements");
+ if (i == NULL)
+ return -1;
+
+ if (! PyType_Check(i))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "zope.declarations.Implements is not a type");
+ return -1;
+ }
+
+ Implements = (PyTypeObject *)i;
+
+ Py_DECREF(declarations);
+
+ imported_declarations = 1;
+ return 0;
+}
+
+static PyTypeObject SpecType; /* Forward */
+
+static PyObject *
+implementedByFallback(PyObject *cls)
+{
+ if (imported_declarations == 0 && import_declarations() < 0)
+ return NULL;
+
+ return PyObject_CallFunctionObjArgs(fallback, cls, NULL);
+}
+
+static PyObject *
+implementedBy(PyObject *ignored, PyObject *cls)
+{
+ /* Fast retrieval of implements spec, if possible, to optimize
+ common case. Use fallback code if we get stuck.
+ */
+
+ PyObject *dict = NULL, *spec;
+
+ if (PyType_Check(cls))
+ {
+ dict = TYPE(cls)->tp_dict;
+ Py_XINCREF(dict);
+ }
+
+ if (dict == NULL)
+ dict = PyObject_GetAttr(cls, str__dict__);
+
+ if (dict == NULL)
+ {
+ /* Probably a security proxied class, use more expensive fallback code */
+ PyErr_Clear();
+ return implementedByFallback(cls);
+ }
+
+ spec = PyObject_GetItem(dict, str__implemented__);
+ Py_DECREF(dict);
+ if (spec)
+ {
+ if (imported_declarations == 0 && import_declarations() < 0)
+ return NULL;
+
+ if (PyObject_TypeCheck(spec, Implements))
+ return spec;
+
+ /* Old-style declaration, use more expensive fallback code */
+ Py_DECREF(spec);
+ return implementedByFallback(cls);
+ }
+
+ PyErr_Clear();
+
+ /* Maybe we have a builtin */
+ if (imported_declarations == 0 && import_declarations() < 0)
+ return NULL;
+
+ spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls);
+ if (spec != NULL)
+ {
+ Py_INCREF(spec);
+ return spec;
+ }
+
+ /* We're stuck, use fallback */
+ return implementedByFallback(cls);
+}
+
+static PyObject *
+getObjectSpecification(PyObject *ignored, PyObject *ob)
+{
+ PyObject *cls, *result;
+
+ result = PyObject_GetAttr(ob, str__provides__);
+ if (result != NULL)
+ return result;
+
+ PyErr_Clear();
+
+ /* We do a getattr here so as not to be defeated by proxies */
+ cls = PyObject_GetAttr(ob, str__class__);
+ if (cls == NULL)
+ {
+ PyErr_Clear();
+ if (imported_declarations == 0 && import_declarations() < 0)
+ return NULL;
+ Py_INCREF(empty);
+ return empty;
+ }
+
+ result = implementedBy(NULL, cls);
+ Py_DECREF(cls);
+
+ return result;
+}
+
+static PyObject *
+providedBy(PyObject *ignored, PyObject *ob)
+{
+ PyObject *result, *cls, *cp;
+
+ result = PyObject_GetAttr(ob, str__providedBy__);
+ if (result == NULL)
+ {
+ PyErr_Clear();
+ return getObjectSpecification(NULL, ob);
+ }
+
+
+ /* We want to make sure we have a spec. We can't do a type check
+ because we may have a proxy, so we'll just try to get the
+ only attribute.
+ */
+ if (PyObject_TypeCheck(result, &SpecType)
+ ||
+ PyObject_HasAttr(result, strextends)
+ )
+ return result;
+
+ /*
+ The object's class doesn't understand descriptors.
+ Sigh. We need to get an object descriptor, but we have to be
+ careful. We want to use the instance's __provides__,l if
+ there is one, but only if it didn't come from the class.
+ */
+ Py_DECREF(result);
+
+ cls = PyObject_GetAttr(ob, str__class__);
+ if (cls == NULL)
+ return NULL;
+
+ result = PyObject_GetAttr(ob, str__provides__);
+ if (result == NULL)
+ {
+ /* No __provides__, so just fall back to implementedBy */
+ PyErr_Clear();
+ result = implementedBy(NULL, cls);
+ Py_DECREF(cls);
+ return result;
+ }
+
+ cp = PyObject_GetAttr(cls, str__provides__);
+ if (cp == NULL)
+ {
+ /* The the class has no provides, assume we're done: */
+ PyErr_Clear();
+ Py_DECREF(cls);
+ return result;
+ }
+
+ if (cp == result)
+ {
+ /*
+ Oops, we got the provides from the class. This means
+ the object doesn't have it's own. We should use implementedBy
+ */
+ Py_DECREF(result);
+ result = implementedBy(NULL, cls);
+ }
+
+ Py_DECREF(cls);
+ Py_DECREF(cp);
+
+ return result;
+}
+
+/*
+ Get an attribute from an inst dict. Return a borrowed reference.
+
+ This has a number of advantages:
+
+ - It avoids layers of Python api
+
+ - It doesn't waste time looking for descriptors
+
+ - It fails wo raising an exception, although that shouldn't really
+ matter.
+
+*/
+static PyObject *
+inst_attr(PyObject *self, PyObject *name)
+{
+ PyObject **dictp, *v;
+
+ dictp = _PyObject_GetDictPtr(self);
+ if (dictp && *dictp && (v = PyDict_GetItem(*dictp, name)))
+ return v;
+ PyErr_SetObject(PyExc_AttributeError, name);
+ return NULL;
+}
+
+
+static PyObject *
+Spec_extends(PyObject *self, PyObject *other)
+{
+ PyObject *implied;
+
+ implied = inst_attr(self, str_implied);
+ if (implied == NULL)
+ return NULL;
+
+#ifdef Py_True
+ if (PyDict_GetItem(implied, other) != NULL)
+ {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ Py_INCREF(Py_False);
+ return Py_False;
+#else
+ return PyInt_FromLong(PyDict_GetItem(implied, other) != NULL);
+#endif
+}
+
+static char Spec_extends__doc__[] =
+"Test whether a specification is or extends another"
+;
+
+static char Spec_providedBy__doc__[] =
+"Test whether an interface is implemented by the specification"
+;
+
+static PyObject *
+Spec_call(PyObject *self, PyObject *args, PyObject *kw)
+{
+ PyObject *spec;
+
+ if (! PyArg_ParseTuple(args, "O", &spec))
+ return NULL;
+ return Spec_extends(self, spec);
+}
+
+static PyObject *
+Spec_providedBy(PyObject *self, PyObject *ob)
+{
+ PyObject *decl, *item;
+
+ decl = providedBy(NULL, ob);
+ if (decl == NULL)
+ return NULL;
+
+ if (PyObject_TypeCheck(decl, &SpecType))
+ item = Spec_extends(decl, self);
+ else
+ /* decl is probably a security proxy. We have to go the long way
+ around.
+ */
+ item = PyObject_CallFunctionObjArgs(decl, self, NULL);
+
+ Py_DECREF(decl);
+ return item;
+}
+
+
+static char Spec_implementedBy__doc__[] =
+"Test whether the specification is implemented by a class or factory.\n"
+"Raise TypeError if argument is neither a class nor a callable."
+;
+
+static PyObject *
+Spec_implementedBy(PyObject *self, PyObject *cls)
+{
+ PyObject *decl, *item;
+
+ decl = implementedBy(NULL, cls);
+ if (decl == NULL)
+ return NULL;
+
+ if (PyObject_TypeCheck(decl, &SpecType))
+ item = Spec_extends(decl, self);
+ else
+ item = PyObject_CallFunctionObjArgs(decl, self, NULL);
+
+ Py_DECREF(decl);
+ return item;
+}
+
+static struct PyMethodDef Spec_methods[] = {
+ {"providedBy",
+ (PyCFunction)Spec_providedBy, METH_O,
+ Spec_providedBy__doc__},
+ {"implementedBy",
+ (PyCFunction)Spec_implementedBy, METH_O,
+ Spec_implementedBy__doc__},
+ {"isOrExtends", (PyCFunction)Spec_extends, METH_O,
+ Spec_extends__doc__},
+
+ {NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject SpecType = {
+ PyObject_HEAD_INIT(NULL)
+ /* ob_size */ 0,
+ /* tp_name */ "_interface_coptimizations."
+ "SpecificationBase",
+ /* tp_basicsize */ 0,
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor)0,
+ /* tp_print */ (printfunc)0,
+ /* tp_getattr */ (getattrfunc)0,
+ /* tp_setattr */ (setattrfunc)0,
+ /* tp_compare */ (cmpfunc)0,
+ /* tp_repr */ (reprfunc)0,
+ /* tp_as_number */ 0,
+ /* tp_as_sequence */ 0,
+ /* tp_as_mapping */ 0,
+ /* tp_hash */ (hashfunc)0,
+ /* tp_call */ (ternaryfunc)Spec_call,
+ /* tp_str */ (reprfunc)0,
+ /* tp_getattro */ (getattrofunc)0,
+ /* tp_setattro */ (setattrofunc)0,
+ /* tp_as_buffer */ 0,
+ /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ "Base type for Specification objects",
+ /* tp_traverse */ (traverseproc)0,
+ /* tp_clear */ (inquiry)0,
+ /* tp_richcompare */ (richcmpfunc)0,
+ /* tp_weaklistoffset */ (long)0,
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ Spec_methods,
+};
+
+static PyObject *
+OSD_descr_get(PyObject *self, PyObject *inst, PyObject *cls)
+{
+ PyObject *provides;
+
+ if (inst == NULL)
+ return getObjectSpecification(NULL, cls);
+
+ provides = PyObject_GetAttr(inst, str__provides__);
+ if (provides != NULL)
+ return provides;
+ PyErr_Clear();
+ return implementedBy(NULL, cls);
+}
+
+static PyTypeObject OSDType = {
+ PyObject_HEAD_INIT(NULL)
+ /* ob_size */ 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 */ (cmpfunc)0,
+ /* tp_repr */ (reprfunc)0,
+ /* tp_as_number */ 0,
+ /* tp_as_sequence */ 0,
+ /* tp_as_mapping */ 0,
+ /* tp_hash */ (hashfunc)0,
+ /* tp_call */ (ternaryfunc)0,
+ /* tp_str */ (reprfunc)0,
+ /* tp_getattro */ (getattrofunc)0,
+ /* tp_setattro */ (setattrofunc)0,
+ /* tp_as_buffer */ 0,
+ /* tp_flags */ Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_BASETYPE ,
+ "Object Specification Descriptor",
+ /* tp_traverse */ (traverseproc)0,
+ /* tp_clear */ (inquiry)0,
+ /* tp_richcompare */ (richcmpfunc)0,
+ /* tp_weaklistoffset */ (long)0,
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ 0,
+ /* tp_members */ 0,
+ /* tp_getset */ 0,
+ /* tp_base */ 0,
+ /* tp_dict */ 0, /* internal use */
+ /* tp_descr_get */ (descrgetfunc)OSD_descr_get,
+};
+
+static PyObject *
+CPB_descr_get(PyObject *self, PyObject *inst, PyObject *cls)
+{
+ PyObject *mycls, *implements;
+
+ mycls = inst_attr(self, str_cls);
+ if (mycls == NULL)
+ return NULL;
+
+ if (cls == mycls)
+ {
+ if (inst == NULL)
+ {
+ Py_INCREF(self);
+ return OBJECT(self);
+ }
+
+ implements = inst_attr(self, str_implements);
+ Py_XINCREF(implements);
+ return implements;
+ }
+
+ PyErr_SetObject(PyExc_AttributeError, str__provides__);
+ return NULL;
+}
+
+static PyTypeObject CPBType = {
+ PyObject_HEAD_INIT(NULL)
+ /* ob_size */ 0,
+ /* tp_name */ "_interface_coptimizations."
+ "ClassProvidesBase",
+ /* tp_basicsize */ 0,
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor)0,
+ /* tp_print */ (printfunc)0,
+ /* tp_getattr */ (getattrfunc)0,
+ /* tp_setattr */ (setattrfunc)0,
+ /* tp_compare */ (cmpfunc)0,
+ /* tp_repr */ (reprfunc)0,
+ /* tp_as_number */ 0,
+ /* tp_as_sequence */ 0,
+ /* tp_as_mapping */ 0,
+ /* tp_hash */ (hashfunc)0,
+ /* tp_call */ (ternaryfunc)0,
+ /* tp_str */ (reprfunc)0,
+ /* tp_getattro */ (getattrofunc)0,
+ /* tp_setattro */ (setattrofunc)0,
+ /* tp_as_buffer */ 0,
+ /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ "C Base class for ClassProvides",
+ /* tp_traverse */ (traverseproc)0,
+ /* tp_clear */ (inquiry)0,
+ /* tp_richcompare */ (richcmpfunc)0,
+ /* tp_weaklistoffset */ (long)0,
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ 0,
+ /* tp_members */ 0,
+ /* tp_getset */ 0,
+ /* tp_base */ &SpecType,
+ /* tp_dict */ 0, /* internal use */
+ /* tp_descr_get */ (descrgetfunc)CPB_descr_get,
+};
+
+/* ==================================================================== */
+/* ========== Begin: __call__ and __adapt__ =========================== */
+
+/*
+ def __adapt__(self, obj):
+ """Adapt an object to the reciever
+ """
+ if self.providedBy(obj):
+ return obj
+
+ for hook in adapter_hooks:
+ adapter = hook(self, obj)
+ if adapter is not None:
+ return adapter
+
+
+*/
+static PyObject *
+__adapt__(PyObject *self, PyObject *obj)
+{
+ PyObject *decl, *args, *adapter;
+ int implements, i, l;
+
+ decl = providedBy(NULL, obj);
+ if (decl == NULL)
+ return NULL;
+
+ if (PyObject_TypeCheck(decl, &SpecType))
+ {
+ PyObject *implied;
+
+ implied = inst_attr(decl, str_implied);
+ if (implied == NULL)
+ {
+ Py_DECREF(decl);
+ return NULL;
+ }
+
+ implements = PyDict_GetItem(implied, self) != NULL;
+ Py_DECREF(decl);
+ }
+ else
+ {
+ /* decl is probably a security proxy. We have to go the long way
+ around.
+ */
+ PyObject *r;
+ r = PyObject_CallFunctionObjArgs(decl, self, NULL);
+ Py_DECREF(decl);
+ if (r == NULL)
+ return NULL;
+ implements = PyObject_IsTrue(r);
+ Py_DECREF(r);
+ }
+
+ if (implements)
+ {
+ Py_INCREF(obj);
+ return obj;
+ }
+
+ l = PyList_GET_SIZE(adapter_hooks);
+ args = PyTuple_New(2);
+ if (args == NULL)
+ return NULL;
+ Py_INCREF(self);
+ PyTuple_SET_ITEM(args, 0, self);
+ Py_INCREF(obj);
+ PyTuple_SET_ITEM(args, 1, obj);
+ for (i = 0; i < l; i++)
+ {
+ adapter = PyObject_CallObject(PyList_GET_ITEM(adapter_hooks, i), args);
+ if (adapter == NULL || adapter != Py_None)
+ {
+ Py_DECREF(args);
+ return adapter;
+ }
+ Py_DECREF(adapter);
+ }
+
+ Py_DECREF(args);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct PyMethodDef ib_methods[] = {
+ {"__adapt__", (PyCFunction)__adapt__, METH_O,
+ "Adapt an object to the reciever"},
+ {NULL, NULL} /* sentinel */
+};
+
+/*
+ def __call__(self, obj, alternate=_marker):
+ conform = getattr(obj, '__conform__', None)
+ if conform is not None:
+ adapter = self._call_conform(conform)
+ if adapter is not None:
+ return adapter
+
+ adapter = self.__adapt__(obj)
+
+ if adapter is not None:
+ return adapter
+ elif alternate is not _marker:
+ return alternate
+ else:
+ raise TypeError("Could not adapt", obj, self)
+*/
+static PyObject *
+ib_call(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *conform, *obj, *alternate=NULL, *adapter;
+
+ static char *kwlist[] = {"obj", "alternate", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist,
+ &obj, &alternate))
+ return NULL;
+
+ conform = PyObject_GetAttr(obj, str__conform__);
+ if (conform != NULL)
+ {
+ adapter = PyObject_CallMethodObjArgs(self, str_call_conform,
+ conform, NULL);
+ Py_DECREF(conform);
+ if (adapter == NULL || adapter != Py_None)
+ return adapter;
+ Py_DECREF(adapter);
+ }
+ else
+ PyErr_Clear();
+
+ adapter = __adapt__(self, obj);
+ if (adapter == NULL || adapter != Py_None)
+ return adapter;
+ Py_DECREF(adapter);
+
+ if (alternate != NULL)
+ {
+ Py_INCREF(alternate);
+ return alternate;
+ }
+
+ adapter = Py_BuildValue("sOO", "Could not adapt", obj, self);
+ if (adapter != NULL)
+ {
+ PyErr_SetObject(PyExc_TypeError, adapter);
+ Py_DECREF(adapter);
+ }
+ return NULL;
+}
+
+static PyTypeObject InterfaceBase = {
+ PyObject_HEAD_INIT(NULL)
+ /* ob_size */ 0,
+ /* tp_name */ "_zope_interface_coptimizations."
+ "InterfaceBase",
+ /* tp_basicsize */ 0,
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor)0,
+ /* tp_print */ (printfunc)0,
+ /* tp_getattr */ (getattrfunc)0,
+ /* tp_setattr */ (setattrfunc)0,
+ /* tp_compare */ (cmpfunc)0,
+ /* tp_repr */ (reprfunc)0,
+ /* tp_as_number */ 0,
+ /* tp_as_sequence */ 0,
+ /* tp_as_mapping */ 0,
+ /* tp_hash */ (hashfunc)0,
+ /* tp_call */ (ternaryfunc)ib_call,
+ /* tp_str */ (reprfunc)0,
+ /* tp_getattro */ (getattrofunc)0,
+ /* tp_setattro */ (setattrofunc)0,
+ /* tp_as_buffer */ 0,
+ /* tp_flags */ Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_BASETYPE ,
+ /* tp_doc */ "Interface base type providing __call__ and __adapt__",
+ /* tp_traverse */ (traverseproc)0,
+ /* tp_clear */ (inquiry)0,
+ /* tp_richcompare */ (richcmpfunc)0,
+ /* tp_weaklistoffset */ (long)0,
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ ib_methods,
+};
+
+/* =================== End: __call__ and __adapt__ ==================== */
+/* ==================================================================== */
+
+/* ==================================================================== */
+/* ========================== Begin: Lookup Bases ===================== */
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *_cache;
+ PyObject *_mcache;
+ PyObject *_scache;
+} lookup;
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *_cache;
+ PyObject *_mcache;
+ PyObject *_scache;
+ PyObject *_verify_ro;
+ PyObject *_verify_generations;
+} verify;
+
+static int
+lookup_traverse(lookup *self, visitproc visit, void *arg)
+{
+ int vret;
+
+ if (self->_cache) {
+ vret = visit(self->_cache, arg);
+ if (vret != 0)
+ return vret;
+ }
+
+ if (self->_mcache) {
+ vret = visit(self->_mcache, arg);
+ if (vret != 0)
+ return vret;
+ }
+
+ if (self->_scache) {
+ vret = visit(self->_scache, arg);
+ if (vret != 0)
+ return vret;
+ }
+
+ return 0;
+}
+
+static int
+lookup_clear(lookup *self)
+{
+ Py_CLEAR(self->_cache);
+ Py_CLEAR(self->_mcache);
+ Py_CLEAR(self->_scache);
+ return 0;
+}
+
+static void
+lookup_dealloc(lookup *self)
+{
+ lookup_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+/*
+ def changed(self, ignored=None):
+ self._cache.clear()
+ self._mcache.clear()
+ self._scache.clear()
+*/
+static PyObject *
+lookup_changed(lookup *self, PyObject *ignored)
+{
+ lookup_clear(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#define ASSURE_DICT(N) if (N == NULL) { N = PyDict_New(); \
+ if (N == NULL) return NULL; \
+ }
+
+/*
+ def _getcache(self, provided, name):
+ cache = self._cache.get(provided)
+ if cache is None:
+ cache = {}
+ self._cache[provided] = cache
+ if name:
+ c = cache.get(name)
+ if c is None:
+ c = {}
+ cache[name] = c
+ cache = c
+ return cache
+*/
+static PyObject *
+_subcache(PyObject *cache, PyObject *key)
+{
+ PyObject *subcache;
+
+ subcache = PyDict_GetItem(cache, key);
+ if (subcache == NULL)
+ {
+ int status;
+
+ subcache = PyDict_New();
+ if (subcache == NULL)
+ return NULL;
+ status = PyDict_SetItem(cache, key, subcache);
+ Py_DECREF(subcache);
+ if (status < 0)
+ return NULL;
+ }
+
+ return subcache;
+}
+static PyObject *
+_getcache(lookup *self, PyObject *provided, PyObject *name)
+{
+ PyObject *cache;
+
+ ASSURE_DICT(self->_cache);
+ cache = _subcache(self->_cache, provided);
+ if (cache == NULL)
+ return NULL;
+
+ if (name != NULL && PyObject_IsTrue(name))
+ cache = _subcache(cache, name);
+
+ return cache;
+}
+
+
+/*
+ def lookup(self, required, provided, name=u'', default=None):
+ cache = self._getcache(provided, name)
+ if len(required) == 1:
+ result = cache.get(required[0], _not_in_mapping)
+ else:
+ result = cache.get(tuple(required), _not_in_mapping)
+
+ if result is _not_in_mapping:
+ result = self._uncached_lookup(required, provided, name)
+ if len(required) == 1:
+ cache[required[0]] = result
+ else:
+ cache[tuple(required)] = result
+
+ if result is None:
+ return default
+
+ return result
+*/
+static PyObject *
+tuplefy(PyObject *v)
+{
+ if (! PyTuple_Check(v))
+ {
+ v = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), v, NULL);
+ if (v == NULL)
+ return NULL;
+ }
+ else
+ Py_INCREF(v);
+
+ return v;
+}
+static PyObject *
+_lookup(lookup *self,
+ PyObject *required, PyObject *provided, PyObject *name,
+ PyObject *default_)
+{
+ PyObject *result, *key, *cache;
+
+ cache = _getcache(self, provided, name);
+ if (cache == NULL)
+ return NULL;
+
+ required = tuplefy(required);
+ if (required == NULL)
+ return NULL;
+
+ if (PyTuple_GET_SIZE(required) == 1)
+ key = PyTuple_GET_ITEM(required, 0);
+ else
+ key = required;
+
+ result = PyDict_GetItem(cache, key);
+ if (result == NULL)
+ {
+ int status;
+
+ result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookup,
+ required, provided, name, NULL);
+ if (result == NULL)
+ {
+ Py_DECREF(required);
+ return NULL;
+ }
+ status = PyDict_SetItem(cache, key, result);
+ Py_DECREF(required);
+ if (status < 0)
+ {
+ Py_DECREF(result);
+ return NULL;
+ }
+ }
+ else
+ {
+ Py_INCREF(result);
+ Py_DECREF(required);
+ }
+
+ if (result == Py_None && default_ != NULL)
+ {
+ Py_DECREF(Py_None);
+ Py_INCREF(default_);
+ return default_;
+ }
+
+ return result;
+}
+static PyObject *
+lookup_lookup(lookup *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+ PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+ &required, &provided, &name, &default_))
+ return NULL;
+
+ return _lookup(self, required, provided, name, default_);
+}
+
+
+/*
+ def lookup1(self, required, provided, name=u'', default=None):
+ cache = self._getcache(provided, name)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ return self.lookup((required, ), provided, name, default)
+
+ if result is None:
+ return default
+
+ return result
+*/
+static PyObject *
+_lookup1(lookup *self,
+ PyObject *required, PyObject *provided, PyObject *name,
+ PyObject *default_)
+{
+ PyObject *result, *cache;
+
+ cache = _getcache(self, provided, name);
+ if (cache == NULL)
+ return NULL;
+
+ result = PyDict_GetItem(cache, required);
+ if (result == NULL)
+ {
+ PyObject *tup;
+
+ tup = PyTuple_New(1);
+ if (tup == NULL)
+ return NULL;
+ Py_INCREF(required);
+ PyTuple_SET_ITEM(tup, 0, required);
+ result = _lookup(self, tup, provided, name, default_);
+ Py_DECREF(tup);
+ }
+ else
+ Py_INCREF(result);
+
+ return result;
+}
+static PyObject *
+lookup_lookup1(lookup *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+ PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+ &required, &provided, &name, &default_))
+ return NULL;
+
+ return _lookup1(self, required, provided, name, default_);
+}
+
+/*
+ def adapter_hook(self, provided, object, name=u'', default=None):
+ required = providedBy(object)
+ cache = self._getcache(provided, name)
+ factory = cache.get(required, _not_in_mapping)
+ if factory is _not_in_mapping:
+ factory = self.lookup((required, ), provided, name)
+
+ if factory is not None:
+ result = factory(object)
+ if result is not None:
+ return result
+
+ return default
+*/
+static PyObject *
+_adapter_hook(lookup *self,
+ PyObject *provided, PyObject *object, PyObject *name,
+ PyObject *default_)
+{
+ PyObject *required, *factory, *result;
+
+ required = providedBy(NULL, object);
+ if (required == NULL)
+ return NULL;
+
+ factory = _lookup1(self, required, provided, name, Py_None);
+ Py_DECREF(required);
+ if (factory == NULL)
+ return NULL;
+
+ if (factory != Py_None)
+ {
+ result = PyObject_CallFunctionObjArgs(factory, object, NULL);
+ Py_DECREF(factory);
+ if (result == NULL || result != Py_None)
+ return result;
+ }
+ else
+ result = factory; /* None */
+
+ if (default_ == NULL || default_ == result) /* No default specified, */
+ return result; /* Return None. result is owned None */
+
+ Py_DECREF(result);
+ Py_INCREF(default_);
+
+ return default_;
+}
+static PyObject *
+lookup_adapter_hook(lookup *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"provided", "object", "name", "default", NULL};
+ PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+ &provided, &object, &name, &default_))
+ return NULL;
+
+ return _adapter_hook(self, provided, object, name, default_);
+}
+
+static PyObject *
+lookup_queryAdapter(lookup *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"object", "provided", "name", "default", NULL};
+ PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+ &object, &provided, &name, &default_))
+ return NULL;
+
+ return _adapter_hook(self, provided, object, name, default_);
+}
+
+/*
+ def lookupAll(self, required, provided):
+ cache = self._mcache.get(provided)
+ if cache is None:
+ cache = {}
+ self._mcache[provided] = cache
+
+ required = tuple(required)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ result = self._uncached_lookupAll(required, provided)
+ cache[required] = result
+
+ return result
+*/
+static PyObject *
+_lookupAll(lookup *self, PyObject *required, PyObject *provided)
+{
+ PyObject *cache, *result;
+
+ ASSURE_DICT(self->_mcache);
+ cache = _subcache(self->_mcache, provided);
+ if (cache == NULL)
+ return NULL;
+
+ required = tuplefy(required);
+ if (required == NULL)
+ return NULL;
+
+ result = PyDict_GetItem(cache, required);
+ if (result == NULL)
+ {
+ int status;
+
+ result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookupAll,
+ required, provided, NULL);
+ if (result == NULL)
+ {
+ Py_DECREF(required);
+ return NULL;
+ }
+ status = PyDict_SetItem(cache, required, result);
+ Py_DECREF(required);
+ if (status < 0)
+ {
+ Py_DECREF(result);
+ return NULL;
+ }
+ }
+ else
+ {
+ Py_INCREF(result);
+ Py_DECREF(required);
+ }
+
+ return result;
+}
+static PyObject *
+lookup_lookupAll(lookup *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"required", "provided", NULL};
+ PyObject *required, *provided;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+ &required, &provided))
+ return NULL;
+
+ return _lookupAll(self, required, provided);
+}
+
+/*
+ def subscriptions(self, required, provided):
+ cache = self._scache.get(provided)
+ if cache is None:
+ cache = {}
+ self._scache[provided] = cache
+
+ required = tuple(required)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ result = self._uncached_subscriptions(required, provided)
+ cache[required] = result
+
+ return result
+*/
+static PyObject *
+_subscriptions(lookup *self, PyObject *required, PyObject *provided)
+{
+ PyObject *cache, *result;
+
+ ASSURE_DICT(self->_scache);
+ cache = _subcache(self->_scache, provided);
+ if (cache == NULL)
+ return NULL;
+
+ required = tuplefy(required);
+ if (required == NULL)
+ return NULL;
+
+ result = PyDict_GetItem(cache, required);
+ if (result == NULL)
+ {
+ int status;
+
+ result = PyObject_CallMethodObjArgs(
+ OBJECT(self), str_uncached_subscriptions,
+ required, provided, NULL);
+ if (result == NULL)
+ {
+ Py_DECREF(required);
+ return NULL;
+ }
+ status = PyDict_SetItem(cache, required, result);
+ Py_DECREF(required);
+ if (status < 0)
+ {
+ Py_DECREF(result);
+ return NULL;
+ }
+ }
+ else
+ {
+ Py_INCREF(result);
+ Py_DECREF(required);
+ }
+
+ return result;
+}
+static PyObject *
+lookup_subscriptions(lookup *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"required", "provided", NULL};
+ PyObject *required, *provided;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+ &required, &provided))
+ return NULL;
+
+ return _subscriptions(self, required, provided);
+}
+
+static struct PyMethodDef lookup_methods[] = {
+ {"changed", (PyCFunction)lookup_changed, METH_O, ""},
+ {"lookup", (PyCFunction)lookup_lookup, METH_KEYWORDS, ""},
+ {"lookup1", (PyCFunction)lookup_lookup1, METH_KEYWORDS, ""},
+ {"queryAdapter", (PyCFunction)lookup_queryAdapter, METH_KEYWORDS, ""},
+ {"adapter_hook", (PyCFunction)lookup_adapter_hook, METH_KEYWORDS, ""},
+ {"lookupAll", (PyCFunction)lookup_lookupAll, METH_KEYWORDS, ""},
+ {"subscriptions", (PyCFunction)lookup_subscriptions, METH_KEYWORDS, ""},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject LookupBase = {
+ PyObject_HEAD_INIT(NULL)
+ /* ob_size */ 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 */ (cmpfunc)0,
+ /* tp_repr */ (reprfunc)0,
+ /* tp_as_number */ 0,
+ /* tp_as_sequence */ 0,
+ /* tp_as_mapping */ 0,
+ /* tp_hash */ (hashfunc)0,
+ /* tp_call */ (ternaryfunc)0,
+ /* tp_str */ (reprfunc)0,
+ /* tp_getattro */ (getattrofunc)0,
+ /* tp_setattro */ (setattrofunc)0,
+ /* tp_as_buffer */ 0,
+ /* tp_flags */ Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_BASETYPE
+ | Py_TPFLAGS_HAVE_GC,
+ /* tp_doc */ "",
+ /* tp_traverse */ (traverseproc)lookup_traverse,
+ /* tp_clear */ (inquiry)lookup_clear,
+ /* tp_richcompare */ (richcmpfunc)0,
+ /* tp_weaklistoffset */ (long)0,
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ lookup_methods,
+};
+
+static int
+verifying_traverse(verify *self, visitproc visit, void *arg)
+{
+ int vret;
+
+ vret = lookup_traverse((lookup *)self, visit, arg);
+ if (vret != 0)
+ return vret;
+
+ if (self->_verify_ro) {
+ vret = visit(self->_verify_ro, arg);
+ if (vret != 0)
+ return vret;
+ }
+ if (self->_verify_generations) {
+ vret = visit(self->_verify_generations, arg);
+ if (vret != 0)
+ return vret;
+ }
+
+ return 0;
+}
+
+static int
+verifying_clear(verify *self)
+{
+ lookup_clear((lookup *)self);
+ Py_CLEAR(self->_verify_generations);
+ Py_CLEAR(self->_verify_ro);
+ return 0;
+}
+
+
+static void
+verifying_dealloc(verify *self)
+{
+ verifying_clear(self);
+ self->ob_type->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_Compare(self->_verify_generations, generations);
+ Py_DECREF(generations);
+ if (PyErr_Occurred())
+ return -1;
+
+ if (changed == 0)
+ return 0;
+ }
+
+ changed_result = PyObject_CallMethodObjArgs(OBJECT(self), strchanged,
+ Py_None, NULL);
+ if (changed_result == NULL)
+ return -1;
+
+ Py_DECREF(changed_result);
+ return 0;
+}
+
+static PyObject *
+verifying_lookup(verify *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+ PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+ &required, &provided, &name, &default_))
+ return NULL;
+
+ if (_verify(self) < 0)
+ return NULL;
+
+ return _lookup((lookup *)self, required, provided, name, default_);
+}
+
+static PyObject *
+verifying_lookup1(verify *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+ PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+ &required, &provided, &name, &default_))
+ return NULL;
+
+ if (_verify(self) < 0)
+ return NULL;
+
+ return _lookup1((lookup *)self, required, provided, name, default_);
+}
+
+static PyObject *
+verifying_adapter_hook(verify *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"provided", "object", "name", "default", NULL};
+ PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+ &provided, &object, &name, &default_))
+ return NULL;
+
+ if (_verify(self) < 0)
+ return NULL;
+
+ return _adapter_hook((lookup *)self, provided, object, name, default_);
+}
+
+static PyObject *
+verifying_queryAdapter(verify *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"object", "provided", "name", "default", NULL};
+ PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+ &object, &provided, &name, &default_))
+ return NULL;
+
+ if (_verify(self) < 0)
+ return NULL;
+
+ return _adapter_hook((lookup *)self, provided, object, name, default_);
+}
+
+static PyObject *
+verifying_lookupAll(verify *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"required", "provided", NULL};
+ PyObject *required, *provided;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+ &required, &provided))
+ return NULL;
+
+ if (_verify(self) < 0)
+ return NULL;
+
+ return _lookupAll((lookup *)self, required, provided);
+}
+
+static PyObject *
+verifying_subscriptions(verify *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"required", "provided", NULL};
+ PyObject *required, *provided;
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+ &required, &provided))
+ return NULL;
+
+ if (_verify(self) < 0)
+ return NULL;
+
+ return _subscriptions((lookup *)self, required, provided);
+}
+
+static struct PyMethodDef verifying_methods[] = {
+ {"changed", (PyCFunction)verifying_changed, METH_O, ""},
+ {"lookup", (PyCFunction)verifying_lookup, METH_KEYWORDS, ""},
+ {"lookup1", (PyCFunction)verifying_lookup1, METH_KEYWORDS, ""},
+ {"queryAdapter", (PyCFunction)verifying_queryAdapter, METH_KEYWORDS, ""},
+ {"adapter_hook", (PyCFunction)verifying_adapter_hook, METH_KEYWORDS, ""},
+ {"lookupAll", (PyCFunction)verifying_lookupAll, METH_KEYWORDS, ""},
+ {"subscriptions", (PyCFunction)verifying_subscriptions, METH_KEYWORDS, ""},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject VerifyingBase = {
+ PyObject_HEAD_INIT(NULL)
+ /* ob_size */ 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 */ (cmpfunc)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 */
+};
+
+#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+init_zope_interface_coptimizations(void)
+{
+ PyObject *m;
+
+#define DEFINE_STRING(S) \
+ if(! (str ## S = PyString_FromString(# S))) return
+
+ DEFINE_STRING(__dict__);
+ DEFINE_STRING(__implemented__);
+ DEFINE_STRING(__provides__);
+ DEFINE_STRING(__class__);
+ DEFINE_STRING(__providedBy__);
+ DEFINE_STRING(extends);
+ DEFINE_STRING(_implied);
+ DEFINE_STRING(_implements);
+ DEFINE_STRING(_cls);
+ DEFINE_STRING(__conform__);
+ DEFINE_STRING(_call_conform);
+ DEFINE_STRING(_uncached_lookup);
+ DEFINE_STRING(_uncached_lookupAll);
+ DEFINE_STRING(_uncached_subscriptions);
+ DEFINE_STRING(_registry);
+ DEFINE_STRING(_generation);
+ DEFINE_STRING(ro);
+ DEFINE_STRING(changed);
+#undef DEFINE_STRING
+ adapter_hooks = PyList_New(0);
+ if (adapter_hooks == NULL)
+ return;
+
+ /* Initialize types: */
+ SpecType.tp_new = PyBaseObject_Type.tp_new;
+ if (PyType_Ready(&SpecType) < 0)
+ return;
+ OSDType.tp_new = PyBaseObject_Type.tp_new;
+ if (PyType_Ready(&OSDType) < 0)
+ return;
+ CPBType.tp_new = PyBaseObject_Type.tp_new;
+ if (PyType_Ready(&CPBType) < 0)
+ return;
+
+ InterfaceBase.tp_new = PyBaseObject_Type.tp_new;
+ if (PyType_Ready(&InterfaceBase) < 0)
+ return;
+
+ LookupBase.tp_new = PyBaseObject_Type.tp_new;
+ if (PyType_Ready(&LookupBase) < 0)
+ return;
+
+ VerifyingBase.tp_new = PyBaseObject_Type.tp_new;
+ if (PyType_Ready(&VerifyingBase) < 0)
+ return;
+
+
+ /* Create the module and add the functions */
+ m = Py_InitModule3("_zope_interface_coptimizations", m_methods,
+ "C optimizations for zope.interface\n\n"
+ "$Id: _zope_interface_coptimizations.c 67796 2006-05-01 13:55:44Z jim $");
+ if (m == NULL)
+ return;
+
+ /* Add types: */
+ if (PyModule_AddObject(m, "SpecificationBase", OBJECT(&SpecType)) < 0)
+ return;
+ if (PyModule_AddObject(m, "ObjectSpecificationDescriptor",
+ (PyObject *)&OSDType) < 0)
+ return;
+ if (PyModule_AddObject(m, "ClassProvidesBase", OBJECT(&CPBType)) < 0)
+ return;
+ if (PyModule_AddObject(m, "InterfaceBase", OBJECT(&InterfaceBase)) < 0)
+ return;
+ if (PyModule_AddObject(m, "LookupBase", OBJECT(&LookupBase)) < 0)
+ return;
+ if (PyModule_AddObject(m, "VerifyingBase", OBJECT(&VerifyingBase)) < 0)
+ return;
+ if (PyModule_AddObject(m, "adapter_hooks", adapter_hooks) < 0)
+ return;
+}
Added: python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,644 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Adapter management
+
+$Id: adapter.py 67796 2006-05-01 13:55:44Z jim $
+"""
+
+import weakref
+from zope.interface import providedBy, Interface, ro
+
+_marker = object
+class BaseAdapterRegistry(object):
+
+ # List of methods copied from lookup sub-objects:
+ _delegated = ('lookup', 'queryMultiAdapter', 'lookup1', 'queryAdapter',
+ 'adapter_hook', 'lookupAll', 'names',
+ 'subscriptions', 'subscribers')
+
+ # All registries maintain a generation that can be used by verifying
+ # registries
+ _generation = 0
+
+ def __init__(self, bases=()):
+
+ # {order -> {required -> {provided -> {name -> value}}}}
+ # where "interfaces" is really a nested key. So, for example:
+ # for order == 0, we have:
+ # {provided -> {name -> valie}}
+ # but for order == 2, we have:
+ # {r1 -> {r2 -> {provided -> {name -> valie}}}}
+ self._adapters = []
+
+ # {order -> {required -> {provided -> {name -> [value]}}}}
+ # where the remarks about adapters above apply
+ self._subscribers = []
+
+ # Set, with a reference count, keeping track of the interfaces
+ # for which we have provided components:
+ self._provided = {}
+
+ # Looup object to perform lookup. We make this a separate object to
+ # to make it easier, in the furture, to implement just the lookup
+ # functionality in C.
+ self._createLookup()
+
+ # Cache invalidation data. There are really 2 kinds of registries:
+
+ # Invalidating registries have caches that are invalidated
+ # when they or when base registies change. An invalidating
+ # registry can only have invalidating registries as bases.
+
+ # Verifying registies can't rely on getting invalidation message,
+ # so have to check the generations of base registries to determine
+ # if their cache data are current
+
+ # Base registries:
+ self.__bases__ = bases
+
+ def _setBases(self, bases):
+ self.__dict__['__bases__'] = bases
+ self.ro = ro.ro(self)
+ self.changed(self)
+
+ __bases__ = property(lambda self: self.__dict__['__bases__'],
+ lambda self, bases: self._setBases(bases),
+ )
+
+ def _createLookup(self):
+ self._v_lookup = self.LookupClass(self)
+ for name in self._delegated:
+ self.__dict__[name] = getattr(self._v_lookup, name)
+
+ def changed(self, originally_changed):
+ self._generation += 1
+ self._v_lookup.changed(originally_changed)
+
+ def register(self, required, provided, name, value):
+ if value is None:
+ self.unregister(required, provided, name, value)
+ return
+
+ required = tuple(map(_convert_None_to_Interface, required))
+ name = _normalize_name(name)
+ order = len(required)
+ byorder = self._adapters
+ while len(byorder) <= order:
+ byorder.append({})
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ d = {}
+ components[k] = d
+ components = d
+
+ if components.get(name) == value:
+ return
+
+ components[name] = value
+
+ n = self._provided.get(provided, 0) + 1
+ self._provided[provided] = n
+ if n == 1:
+ self._v_lookup.add_extendor(provided)
+
+ self.changed(self)
+
+ def registered(self, required, provided, name=u''):
+ required = tuple(map(_convert_None_to_Interface, required))
+ name = _normalize_name(name)
+ order = len(required)
+ byorder = self._adapters
+ if len(byorder) <= order:
+ return None
+
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ return None
+ components = d
+
+ return components.get(name)
+
+ def unregister(self, required, provided, name, value=None):
+ required = tuple(map(_convert_None_to_Interface, required))
+ order = len(required)
+ byorder = self._adapters
+ if order >= len(byorder):
+ return False
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ return
+ components = d
+
+ old = components.get(name)
+ if old is None:
+ return
+ if (value is not None) and (old != value):
+ return
+
+ del components[name]
+ 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)
+
+ return
+
+
+ def subscribe(self, required, provided, value):
+ required = tuple(map(_convert_None_to_Interface, required))
+ name = u''
+ order = len(required)
+ byorder = self._subscribers
+ while len(byorder) <= order:
+ byorder.append({})
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ d = {}
+ components[k] = d
+ components = d
+
+ components[name] = components.get(name, ()) + (value, )
+
+ if provided is not None:
+ n = self._provided.get(provided, 0) + 1
+ self._provided[provided] = n
+ if n == 1:
+ self._v_lookup.add_extendor(provided)
+
+ self.changed(self)
+
+ def unsubscribe(self, required, provided, value=None):
+ required = tuple(map(_convert_None_to_Interface, required))
+ order = len(required)
+ byorder = self._subscribers
+ if order >= len(byorder):
+ return
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ return
+ components = d
+
+ old = components.get(u'')
+ if not old:
+ return
+
+ if value is None:
+ new = ()
+ else:
+ new = tuple([v for v in old if v != value])
+
+ if new == old:
+ return
+
+ components[u''] = new
+
+ if provided is not None:
+ n = self._provided[provided] + len(new) - len(old)
+ if n == 0:
+ del self._provided[provided]
+ self._v_lookup.remove_extendor(provided)
+
+ self.changed(self)
+
+ # XXX hack to fake out twisted's use of a private api. We need to get them
+ # to use the new registed method.
+ def get(self, _):
+ class XXXTwistedFakeOut:
+ selfImplied = {}
+ return XXXTwistedFakeOut
+
+
+_not_in_mapping = object()
+class LookupBasePy(object):
+
+ def __init__(self):
+ self._cache = {}
+ self._mcache = {}
+ self._scache = {}
+
+ def changed(self, ignored=None):
+ self._cache.clear()
+ self._mcache.clear()
+ self._scache.clear()
+
+ def _getcache(self, provided, name):
+ cache = self._cache.get(provided)
+ if cache is None:
+ cache = {}
+ self._cache[provided] = cache
+ if name:
+ c = cache.get(name)
+ if c is None:
+ c = {}
+ cache[name] = c
+ cache = c
+ return cache
+
+ def lookup(self, required, provided, name=u'', default=None):
+ cache = self._getcache(provided, name)
+ if len(required) == 1:
+ result = cache.get(required[0], _not_in_mapping)
+ else:
+ result = cache.get(tuple(required), _not_in_mapping)
+
+ if result is _not_in_mapping:
+ result = self._uncached_lookup(required, provided, name)
+ if len(required) == 1:
+ cache[required[0]] = result
+ else:
+ cache[tuple(required)] = result
+
+ if result is None:
+ return default
+
+ return result
+
+ def lookup1(self, required, provided, name=u'', default=None):
+ cache = self._getcache(provided, name)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ return self.lookup((required, ), provided, name, default)
+
+ if result is None:
+ return default
+
+ return result
+
+ def queryAdapter(self, object, provided, name=u'', default=None):
+ return self.adapter_hook(provided, object, name, default)
+
+ def adapter_hook(self, provided, object, name=u'', default=None):
+ required = providedBy(object)
+ cache = self._getcache(provided, name)
+ factory = cache.get(required, _not_in_mapping)
+ if factory is _not_in_mapping:
+ factory = self.lookup((required, ), provided, name)
+
+ if factory is not None:
+ result = factory(object)
+ if result is not None:
+ return result
+
+ return default
+
+ def lookupAll(self, required, provided):
+ cache = self._mcache.get(provided)
+ if cache is None:
+ cache = {}
+ self._mcache[provided] = cache
+
+ required = tuple(required)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ result = self._uncached_lookupAll(required, provided)
+ cache[required] = result
+
+ return result
+
+
+ def subscriptions(self, required, provided):
+ cache = self._scache.get(provided)
+ if cache is None:
+ cache = {}
+ self._scache[provided] = cache
+
+ required = tuple(required)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ result = self._uncached_subscriptions(required, provided)
+ cache[required] = result
+
+ return result
+
+LookupBase = LookupBasePy
+
+class VerifyingBasePy(LookupBasePy):
+
+ def changed(self, originally_changed):
+ LookupBasePy.changed(self, originally_changed)
+ self._verify_ro = self._registry.ro[1:]
+ self._verify_generations = [r._generation for r in self._verify_ro]
+
+ def _verify(self):
+ if ([r._generation for r in self._verify_ro]
+ != self._verify_generations):
+ self.changed(None)
+
+ def _getcache(self, provided, name):
+ self._verify()
+ return LookupBasePy._getcache(self, provided, name)
+
+ def lookupAll(self, required, provided):
+ self._verify()
+ return LookupBasePy.lookupAll(self, required, provided)
+
+ def subscriptions(self, required, provided):
+ self._verify()
+ return LookupBasePy.subscriptions(self, required, provided)
+
+VerifyingBase = VerifyingBasePy
+
+
+try:
+ import _zope_interface_coptimizations
+except ImportError:
+ pass
+else:
+ from _zope_interface_coptimizations import LookupBase, VerifyingBase
+
+class AdapterLookupBase(object):
+
+ def __init__(self, registry):
+ self._registry = registry
+ self._required = {}
+ self.init_extendors()
+ super(AdapterLookupBase, self).__init__()
+
+ def changed(self, ignored=None):
+ super(AdapterLookupBase, self).changed(None)
+ for r in self._required.keys():
+ r = r()
+ if r is not None:
+ r.unsubscribe(self)
+ self._required.clear()
+
+
+ # Extendors
+ # ---------
+
+ # When given an target interface for an adapter lookup, we need to consider
+ # adapters for interfaces that extend the target interface. This is
+ # what the extendors dictionary is about. It tells us all of the
+ # interfaces that extend an interface for which there are adapters
+ # registered.
+
+ # We could separate this by order and name, thus reducing the
+ # number of provided interfaces to search at run time. The tradeoff,
+ # however, is that we have to store more information. For example,
+ # is the same interface is provided for multiple names and if the
+ # interface extends many interfaces, we'll have to keep track of
+ # a fair bit of information for each name. It's better to
+ # be space efficient here and be time efficient in the cache
+ # implementation.
+
+ # TODO: add invalidation when a provided interface changes, in case
+ # the interface's __iro__ has changed. This is unlikely enough that
+ # we'll take our chances for now.
+
+ def init_extendors(self):
+ self._extendors = {}
+ for p in self._registry._provided:
+ self.add_extendor(p)
+
+ def add_extendor(self, provided):
+ _extendors = self._extendors
+ for i in provided.__iro__:
+ extendors = _extendors.get(i, ())
+ _extendors[i] = (
+ [e for e in extendors if provided.isOrExtends(e)]
+ +
+ [provided]
+ +
+ [e for e in extendors if not provided.isOrExtends(e)]
+ )
+
+ def remove_extendor(self, provided):
+ _extendors = self._extendors
+ for i in provided.__iro__:
+ _extendors[i] = [e for e in _extendors.get(i, ())
+ if e != provided]
+
+
+ def _subscribe(self, *required):
+ _refs = self._required
+ for r in required:
+ ref = r.weakref()
+ if ref not in _refs:
+ r.subscribe(self)
+ _refs[ref] = 1
+
+ def _uncached_lookup(self, required, provided, name=u''):
+ result = None
+ order = len(required)
+ for registry in self._registry.ro:
+ byorder = registry._adapters
+ if order >= len(byorder):
+ continue
+
+ extendors = registry._v_lookup._extendors.get(provided)
+ if not extendors:
+ continue
+
+ components = byorder[order]
+ result = _lookup(components, required, extendors, name, 0,
+ order)
+ if result is not None:
+ break
+
+ self._subscribe(*required)
+
+ return result
+
+ def queryMultiAdapter(self, objects, provided, name=u'', default=None):
+ factory = self.lookup(map(providedBy, objects), provided, name)
+ if factory is None:
+ return default
+
+ result = factory(*objects)
+ if result is None:
+ return default
+
+ return result
+
+ def _uncached_lookupAll(self, required, provided):
+ order = len(required)
+ result = {}
+ for registry in reversed(self._registry.ro):
+ byorder = registry._adapters
+ if order >= len(byorder):
+ continue
+ extendors = registry._v_lookup._extendors.get(provided)
+ if not extendors:
+ continue
+ components = byorder[order]
+ _lookupAll(components, required, extendors, result, 0, order)
+
+ self._subscribe(*required)
+
+ return tuple(result.iteritems())
+
+ def names(self, required, provided):
+ return [c[0] for c in self.lookupAll(required, provided)]
+
+ def _uncached_subscriptions(self, required, provided):
+ order = len(required)
+ result = []
+ for registry in reversed(self._registry.ro):
+ byorder = registry._subscribers
+ if order >= len(byorder):
+ continue
+
+ if provided is None:
+ extendors = (provided, )
+ else:
+ extendors = registry._v_lookup._extendors.get(provided)
+ if extendors is None:
+ continue
+
+ _subscriptions(byorder[order], required, extendors, u'',
+ result, 0, order)
+
+ self._subscribe(*required)
+
+ return result
+
+ def subscribers(self, objects, provided):
+ subscriptions = self.subscriptions(map(providedBy, objects), provided)
+ if provided is None:
+ result = ()
+ for subscription in subscriptions:
+ subscription(*objects)
+ else:
+ result = []
+ for subscription in subscriptions:
+ subscriber = subscription(*objects)
+ if subscriber is not None:
+ result.append(subscriber)
+ return result
+
+class AdapterLookup(AdapterLookupBase, LookupBase):
+ pass
+
+class AdapterRegistry(BaseAdapterRegistry):
+
+ LookupClass = AdapterLookup
+
+ def __init__(self, bases=()):
+ # AdapterRegisties are invalidating registries, so
+ # we need to keep track of out invalidating subregistries.
+ self._v_subregistries = weakref.WeakKeyDictionary()
+
+ super(AdapterRegistry, self).__init__(bases)
+
+ def _addSubregistry(self, r):
+ self._v_subregistries[r] = 1
+
+ def _removeSubregistry(self, r):
+ if r in self._v_subregistries:
+ del self._v_subregistries[r]
+
+ def _setBases(self, bases):
+ old = self.__dict__.get('__bases__', ())
+ for r in old:
+ if r not in bases:
+ r._removeSubregistry(self)
+ for r in bases:
+ if r not in old:
+ r._addSubregistry(self)
+
+ super(AdapterRegistry, self)._setBases(bases)
+
+ def changed(self, originally_changed):
+ super(AdapterRegistry, self).changed(originally_changed)
+
+ for sub in self._v_subregistries.keys():
+ sub.changed(originally_changed)
+
+
+class VerifyingAdapterLookup(AdapterLookupBase, VerifyingBase):
+ pass
+
+class VerifyingAdapterRegistry(BaseAdapterRegistry):
+
+ LookupClass = VerifyingAdapterLookup
+
+def _convert_None_to_Interface(x):
+ if x is None:
+ return Interface
+ else:
+ return x
+
+def _normalize_name(name):
+ if isinstance(name, basestring):
+ return unicode(name)
+
+ raise TypeError("name must be a regular or unicode string")
+
+def _lookup(components, specs, provided, name, i, l):
+ if i < l:
+ for spec in specs[i].__sro__:
+ comps = components.get(spec)
+ if comps:
+ r = _lookup(comps, specs, provided, name, i+1, l)
+ if r is not None:
+ return r
+ else:
+ for iface in provided:
+ comps = components.get(iface)
+ if comps:
+ r = comps.get(name)
+ if r is not None:
+ return r
+
+ return None
+
+def _lookupAll(components, specs, provided, result, i, l):
+ if i < l:
+ for spec in reversed(specs[i].__sro__):
+ comps = components.get(spec)
+ if comps:
+ _lookupAll(comps, specs, provided, result, i+1, l)
+ else:
+ for iface in reversed(provided):
+ comps = components.get(iface)
+ if comps:
+ result.update(comps)
+
+def _subscriptions(components, specs, provided, name, result, i, l):
+ if i < l:
+ for spec in reversed(specs[i].__sro__):
+ comps = components.get(spec)
+ if comps:
+ _subscriptions(comps, specs, provided, name, result, i+1, l)
+ else:
+ for iface in reversed(provided):
+ comps = components.get(iface)
+ if comps:
+ comps = comps.get(name)
+ if comps:
+ result.extend(comps)
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/adapter.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/adapter.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/adapter.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,546 @@
+================
+Adapter Registry
+================
+
+Adapter registries provide a way to register objects that depend on
+one or more interface specifications and provide (perhaps indirectly)
+some interface. In addition, the registrations have names. (You can
+think of the names as qualifiers of the provided interfaces.)
+
+The term "interface specification" refers both to interfaces and to
+interface declarations, such as declarations of interfaces implemented
+by a class.
+
+
+Single Adapters
+===============
+
+Let's look at a simple example, using a single required specification::
+
+ >>> from zope.interface.adapter import AdapterRegistry
+ >>> import zope.interface
+
+ >>> class IR1(zope.interface.Interface):
+ ... pass
+ >>> class IP1(zope.interface.Interface):
+ ... pass
+ >>> class IP2(IP1):
+ ... pass
+
+ >>> registry = AdapterRegistry()
+
+We'll register an object that depends on IR1 and "provides" IP2::
+
+ >>> registry.register([IR1], IP2, '', 12)
+
+Given the registration, we can look it up again::
+
+ >>> registry.lookup([IR1], IP2, '')
+ 12
+
+Note that we used an integer in the example. In real applications,
+one would use some objects that actually depend on or provide
+interfaces. The registry doesn't care about what gets registered, so
+we'll use integers and strings to keep the examples simple. There is
+one exception. Registering a value of None unregisters any
+previously-registered value.
+
+If an object depends on a specification, it can be looked up with a
+specification that extends the specification that it depends on::
+
+ >>> class IR2(IR1):
+ ... pass
+ >>> registry.lookup([IR2], IP2, '')
+ 12
+
+We can use a class implementation specification to look up the object::
+
+ >>> class C2:
+ ... zope.interface.implements(IR2)
+
+ >>> registry.lookup([zope.interface.implementedBy(C2)], IP2, '')
+ 12
+
+
+and it can be looked up for interfaces that its provided interface
+extends::
+
+ >>> registry.lookup([IR1], IP1, '')
+ 12
+ >>> registry.lookup([IR2], IP1, '')
+ 12
+
+But if you require a specification that doesn't extend the specification the
+object depends on, you won't get anything::
+
+ >>> registry.lookup([zope.interface.Interface], IP1, '')
+
+By the way, you can pass a default value to lookup::
+
+ >>> registry.lookup([zope.interface.Interface], IP1, '', 42)
+ 42
+
+If you try to get an interface the object doesn't provide, you also
+won't get anything::
+
+ >>> class IP3(IP2):
+ ... pass
+ >>> registry.lookup([IR1], IP3, '')
+
+You also won't get anything if you use the wrong name::
+
+ >>> registry.lookup([IR1], IP1, 'bob')
+ >>> registry.register([IR1], IP2, 'bob', "Bob's 12")
+ >>> registry.lookup([IR1], IP1, 'bob')
+ "Bob's 12"
+
+You can leave the name off when doing a lookup::
+
+ >>> registry.lookup([IR1], IP1)
+ 12
+
+If we register an object that provides IP1::
+
+ >>> registry.register([IR1], IP1, '', 11)
+
+then that object will be prefered over O(12)::
+
+ >>> registry.lookup([IR1], IP1, '')
+ 11
+
+Also, if we register an object for IR2, then that will be prefered
+when using IR2::
+
+ >>> registry.register([IR2], IP1, '', 21)
+ >>> registry.lookup([IR2], IP1, '')
+ 21
+
+Finding out what, if anything, is registered
+--------------------------------------------
+
+We can ask if there is an adapter registered for a collection of
+interfaces. This is different than lookup, because it looks for an
+exact match.
+
+ >>> print registry.registered([IR1], IP1)
+ 11
+
+ >>> print registry.registered([IR1], IP2)
+ 12
+
+ >>> print registry.registered([IR1], IP2, 'bob')
+ Bob's 12
+
+
+ >>> print registry.registered([IR2], IP1)
+ 21
+
+ >>> print registry.registered([IR2], IP2)
+ None
+
+In the last example, None was returned because nothing was registered
+exactly for the given interfaces.
+
+lookup1
+-------
+
+Lookup of single adapters is common enough that there is a specialized
+version of lookup that takes a single required interface::
+
+ >>> registry.lookup1(IR2, IP1, '')
+ 21
+ >>> registry.lookup1(IR2, IP1)
+ 21
+
+Actual Adaptation
+-----------------
+
+The adapter registry is intended to support adaptation, where one
+object that implements an interface is adapted to another object that
+supports a different interface. The adapter registry supports the
+computation of adapters. In this case, we have to register adapter
+factories::
+
+ >>> class IR(zope.interface.Interface):
+ ... pass
+
+ >>> class X:
+ ... zope.interface.implements(IR)
+
+ >>> class Y:
+ ... zope.interface.implements(IP1)
+ ... def __init__(self, context):
+ ... self.context = context
+
+ >>> registry.register([IR], IP1, '', Y)
+
+In this case, we registered a class as the factory. Now we can call
+`queryAdapter` to get the adapted object::
+
+ >>> x = X()
+ >>> y = registry.queryAdapter(x, IP1)
+ >>> y.__class__.__name__
+ 'Y'
+ >>> y.context is x
+ True
+
+We can register and lookup by name too::
+
+ >>> class Y2(Y):
+ ... pass
+
+ >>> registry.register([IR], IP1, 'bob', Y2)
+ >>> y = registry.queryAdapter(x, IP1, 'bob')
+ >>> y.__class__.__name__
+ 'Y2'
+ >>> y.context is x
+ True
+
+When the adapter factory produces `None`, then this is treated as if no
+adapter has been found. This allows us to prevent adaptation (when desired)
+and let the adapter factory determine whether adaptation is possible based on
+the state of the object being adapted.
+
+ >>> def factory(context):
+ ... if context.name == 'object':
+ ... return 'adapter'
+ ... return None
+
+ >>> class Object(object):
+ ... zope.interface.implements(IR)
+ ... name = 'object'
+
+ >>> registry.register([IR], IP1, 'conditional', factory)
+ >>> obj = Object()
+ >>> registry.queryAdapter(obj, IP1, 'conditional')
+ 'adapter'
+ >>> obj.name = 'no object'
+ >>> registry.queryAdapter(obj, IP1, 'conditional') is None
+ True
+ >>> registry.queryAdapter(obj, IP1, 'conditional', 'default')
+ 'default'
+
+An alternate method that provides the same function as `queryAdapter()` is
+`adapter_hook()`::
+
+ >>> y = registry.adapter_hook(IP1, x)
+ >>> y.__class__.__name__
+ 'Y'
+ >>> y.context is x
+ True
+ >>> y = registry.adapter_hook(IP1, x, 'bob')
+ >>> y.__class__.__name__
+ 'Y2'
+ >>> y.context is x
+ True
+
+The `adapter_hook()` simply switches the order of the object and
+interface arguments. It is used to hook into the interface call
+mechanism.
+
+
+Default Adapters
+----------------
+
+Sometimes, you want to provide an adapter that will adapt anything.
+For that, provide None as the required interface::
+
+ >>> registry.register([None], IP1, '', 1)
+
+then we can use that adapter for interfaces we don't have specific
+adapters for::
+
+ >>> class IQ(zope.interface.Interface):
+ ... pass
+ >>> registry.lookup([IQ], IP1, '')
+ 1
+
+Of course, specific adapters are still used when applicable::
+
+ >>> registry.lookup([IR2], IP1, '')
+ 21
+
+Class adapters
+--------------
+
+You can register adapters for class declarations, which is almost the
+same as registering them for a class::
+
+ >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', 'C21')
+ >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '')
+ 'C21'
+
+Dict adapters
+-------------
+
+At some point it was impossible to register dictionary-based adapters due a
+bug. Let's make sure this works now:
+
+ >>> adapter = {}
+ >>> registry.register((), IQ, '', adapter)
+ >>> registry.lookup((), IQ, '') is adapter
+ True
+
+Unregistering
+-------------
+
+You can unregister by registering None, rather than an object::
+
+ >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', None)
+ >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '')
+ 21
+
+Of course, this means that None can't be registered. This is an
+exception to the statement, made earlier, that the registry doesn't
+care what gets registered.
+
+Multi-adapters
+==============
+
+You can adapt multiple specifications::
+
+ >>> registry.register([IR1, IQ], IP2, '', '1q2')
+ >>> registry.lookup([IR1, IQ], IP2, '')
+ '1q2'
+ >>> registry.lookup([IR2, IQ], IP1, '')
+ '1q2'
+
+ >>> class IS(zope.interface.Interface):
+ ... pass
+ >>> registry.lookup([IR2, IS], IP1, '')
+
+ >>> class IQ2(IQ):
+ ... pass
+
+ >>> registry.lookup([IR2, IQ2], IP1, '')
+ '1q2'
+
+ >>> registry.register([IR1, IQ2], IP2, '', '1q22')
+ >>> registry.lookup([IR2, IQ2], IP1, '')
+ '1q22'
+
+Multi-adaptation
+----------------
+
+You can adapt multiple objects::
+
+ >>> class Q:
+ ... zope.interface.implements(IQ)
+
+As with single adapters, we register a factory, which is often a class::
+
+ >>> class IM(zope.interface.Interface):
+ ... pass
+ >>> class M:
+ ... zope.interface.implements(IM)
+ ... def __init__(self, x, q):
+ ... self.x, self.q = x, q
+ >>> registry.register([IR, IQ], IM, '', M)
+
+And then we can call `queryMultiAdapter` to compute an adapter::
+
+ >>> q = Q()
+ >>> m = registry.queryMultiAdapter((x, q), IM)
+ >>> m.__class__.__name__
+ 'M'
+ >>> m.x is x and m.q is q
+ True
+
+and, of course, we can use names::
+
+ >>> class M2(M):
+ ... pass
+ >>> registry.register([IR, IQ], IM, 'bob', M2)
+ >>> m = registry.queryMultiAdapter((x, q), IM, 'bob')
+ >>> m.__class__.__name__
+ 'M2'
+ >>> m.x is x and m.q is q
+ True
+
+Default Adapters
+----------------
+
+As with single adapters, you can define default adapters by specifying
+None for the *first* specification::
+
+ >>> registry.register([None, IQ], IP2, '', 'q2')
+ >>> registry.lookup([IS, IQ], IP2, '')
+ 'q2'
+
+Null Adapters
+=============
+
+You can also adapt no specification::
+
+ >>> registry.register([], IP2, '', 2)
+ >>> registry.lookup([], IP2, '')
+ 2
+ >>> registry.lookup([], IP1, '')
+ 2
+
+Listing named adapters
+----------------------
+
+Adapters are named. Sometimes, it's useful to get all of the named
+adapters for given interfaces::
+
+ >>> adapters = list(registry.lookupAll([IR1], IP1))
+ >>> adapters.sort()
+ >>> adapters
+ [(u'', 11), (u'bob', "Bob's 12")]
+
+This works for multi-adapters too::
+
+ >>> registry.register([IR1, IQ2], IP2, 'bob', '1q2 for bob')
+ >>> adapters = list(registry.lookupAll([IR2, IQ2], IP1))
+ >>> adapters.sort()
+ >>> adapters
+ [(u'', '1q22'), (u'bob', '1q2 for bob')]
+
+And even null adapters::
+
+ >>> registry.register([], IP2, 'bob', 3)
+ >>> adapters = list(registry.lookupAll([], IP1))
+ >>> adapters.sort()
+ >>> adapters
+ [(u'', 2), (u'bob', 3)]
+
+Subscriptions
+=============
+
+Normally, we want to look up an object that most-closely matches a
+specification. Sometimes, we want to get all of the objects that
+match some specification. We use subscriptions for this. We
+subscribe objects against specifications and then later find all of
+the subscribed objects::
+
+ >>> registry.subscribe([IR1], IP2, 'sub12 1')
+ >>> registry.subscriptions([IR1], IP2)
+ ['sub12 1']
+
+Note that, unlike regular adapters, subscriptions are unnamed.
+
+You can have multiple subscribers for the same specification::
+
+ >>> registry.subscribe([IR1], IP2, 'sub12 2')
+ >>> registry.subscriptions([IR1], IP2)
+ ['sub12 1', 'sub12 2']
+
+If subscribers are registered for the same required interfaces, they
+are returned in the order of definition.
+
+You can register subscribers for all specifications using None::
+
+ >>> registry.subscribe([None], IP1, 'sub_1')
+ >>> registry.subscriptions([IR2], IP1)
+ ['sub_1', 'sub12 1', 'sub12 2']
+
+Note that the new subscriber is returned first. Subscribers defined
+for more general required interfaces are returned before subscribers
+for more general interfaces.
+
+Subscriptions may be combined over multiple compatible specifications::
+
+ >>> registry.subscriptions([IR2], IP1)
+ ['sub_1', 'sub12 1', 'sub12 2']
+ >>> registry.subscribe([IR1], IP1, 'sub11')
+ >>> registry.subscriptions([IR2], IP1)
+ ['sub_1', 'sub12 1', 'sub12 2', 'sub11']
+ >>> registry.subscribe([IR2], IP2, 'sub22')
+ >>> registry.subscriptions([IR2], IP1)
+ ['sub_1', 'sub12 1', 'sub12 2', 'sub11', 'sub22']
+ >>> registry.subscriptions([IR2], IP2)
+ ['sub12 1', 'sub12 2', 'sub22']
+
+Subscriptions can be on multiple specifications::
+
+ >>> registry.subscribe([IR1, IQ], IP2, 'sub1q2')
+ >>> registry.subscriptions([IR1, IQ], IP2)
+ ['sub1q2']
+
+As with single subscriptions and non-subscription adapters, you can
+specify None for the first required interface, to specify a default::
+
+ >>> registry.subscribe([None, IQ], IP2, 'sub_q2')
+ >>> registry.subscriptions([IS, IQ], IP2)
+ ['sub_q2']
+ >>> registry.subscriptions([IR1, IQ], IP2)
+ ['sub_q2', 'sub1q2']
+
+You can have subscriptions that are indepenent of any specifications::
+
+ >>> list(registry.subscriptions([], IP1))
+ []
+
+ >>> registry.subscribe([], IP2, 'sub2')
+ >>> registry.subscriptions([], IP1)
+ ['sub2']
+ >>> registry.subscribe([], IP1, 'sub1')
+ >>> registry.subscriptions([], IP1)
+ ['sub2', 'sub1']
+ >>> registry.subscriptions([], IP2)
+ ['sub2']
+
+Unregistering subscribers
+-------------------------
+
+We can unregister subscribers. When unregistering a subscriber, we
+can unregister a specific subscriber:
+
+ >>> registry.unsubscribe([IR1], IP1, 'sub11')
+ >>> registry.subscriptions([IR1], IP1)
+ ['sub_1', 'sub12 1', 'sub12 2']
+
+If we don't specify a value, then all subscribers matching the given
+interfaces will be unsubscribed:
+
+ >>> registry.unsubscribe([IR1], IP2)
+ >>> registry.subscriptions([IR1], IP1)
+ ['sub_1']
+
+
+Subscription adapters
+---------------------
+
+We normally register adapter factories, which then allow us to compute
+adapters, but with subscriptions, we get multiple adapters. Here's an
+example of multiple-object subscribers::
+
+ >>> registry.subscribe([IR, IQ], IM, M)
+ >>> registry.subscribe([IR, IQ], IM, M2)
+
+ >>> subscribers = registry.subscribers((x, q), IM)
+ >>> len(subscribers)
+ 2
+ >>> class_names = [s.__class__.__name__ for s in subscribers]
+ >>> class_names.sort()
+ >>> class_names
+ ['M', 'M2']
+ >>> [(s.x is x and s.q is q) for s in subscribers]
+ [True, True]
+
+adapter factory subcribers can't return None values
+
+ >>> def M3(x, y):
+ ... return None
+
+ >>> registry.subscribe([IR, IQ], IM, M3)
+ >>> subscribers = registry.subscribers((x, q), IM)
+ >>> len(subscribers)
+ 2
+
+Handlers
+--------
+
+A handler is a subscriber factory that doesn't produce any normal
+output. It returns None. A handler is unlike adapters in that it does
+all of its work when the factory is called.
+
+To register a handler, simply provide None as the provided interface::
+
+ >>> def handler(event):
+ ... print 'handler', event
+
+ >>> registry.subscribe([IR1], None, handler)
+ >>> registry.subscriptions([IR1], None) == [handler]
+ True
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/adapter.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/advice.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/advice.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/advice.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,192 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation 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 at telecommunity.com and tsarna at 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.
+
+$Id: advice.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+from types import ClassType, FunctionType
+import sys
+
+def getFrameInfo(frame):
+ """Return (kind,module,locals,globals) for a frame
+
+ 'kind' is one of "exec", "module", "class", "function call", or "unknown".
+ """
+
+ f_locals = frame.f_locals
+ f_globals = frame.f_globals
+
+ sameNamespace = f_locals is f_globals
+ hasModule = '__module__' in f_locals
+ hasName = '__name__' in f_globals
+
+ sameName = hasModule and hasName
+ sameName = sameName and f_globals['__name__']==f_locals['__module__']
+
+ module = hasName and sys.modules.get(f_globals['__name__']) or None
+
+ namespaceIsModule = module and module.__dict__ is f_globals
+
+ if not namespaceIsModule:
+ # some kind of funky exec
+ kind = "exec"
+ elif sameNamespace and not hasModule:
+ kind = "module"
+ elif sameName and not sameNamespace:
+ kind = "class"
+ elif not sameNamespace:
+ kind = "function call"
+ else:
+ # How can you have f_locals is f_globals, and have '__module__' set?
+ # This is probably module-level code, but with a '__module__' variable.
+ kind = "unknown"
+ return kind, module, f_locals, f_globals
+
+
+def addClassAdvisor(callback, depth=2):
+ """Set up 'callback' to be passed the containing class upon creation
+
+ This function is designed to be called by an "advising" function executed
+ in a class suite. The "advising" function supplies a callback that it
+ wishes to have executed when the containing class is created. The
+ callback will be given one argument: the newly created containing class.
+ The return value of the callback will be used in place of the class, so
+ the callback should return the input if it does not wish to replace the
+ class.
+
+ The optional 'depth' argument to this function determines the number of
+ frames between this function and the targeted class suite. 'depth'
+ defaults to 2, since this skips this function's frame and one calling
+ function frame. If you use this function from a function called directly
+ in the class suite, the default will be correct, otherwise you will need
+ to determine the correct depth yourself.
+
+ This function works by installing a special class factory function in
+ place of the '__metaclass__' of the containing class. Therefore, only
+ callbacks *after* the last '__metaclass__' assignment in the containing
+ class will be executed. Be sure that classes using "advising" functions
+ declare any '__metaclass__' *first*, to ensure all callbacks are run."""
+
+ frame = sys._getframe(depth)
+ kind, module, caller_locals, caller_globals = getFrameInfo(frame)
+
+ # This causes a problem when zope interfaces are used from doctest.
+ # In these cases, kind == "exec".
+ #
+ #if kind != "class":
+ # raise SyntaxError(
+ # "Advice must be in the body of a class statement"
+ # )
+
+ previousMetaclass = caller_locals.get('__metaclass__')
+ defaultMetaclass = caller_globals.get('__metaclass__', ClassType)
+
+
+ def advise(name, bases, cdict):
+
+ if '__metaclass__' in cdict:
+ del cdict['__metaclass__']
+
+ if previousMetaclass is None:
+ if bases:
+ # find best metaclass or use global __metaclass__ if no bases
+ meta = determineMetaclass(bases)
+ else:
+ meta = defaultMetaclass
+
+ elif isClassAdvisor(previousMetaclass):
+ # special case: we can't compute the "true" metaclass here,
+ # so we need to invoke the previous metaclass and let it
+ # figure it out for us (and apply its own advice in the process)
+ meta = previousMetaclass
+
+ else:
+ meta = determineMetaclass(bases, previousMetaclass)
+
+ newClass = meta(name,bases,cdict)
+
+ # this lets the callback replace the class completely, if it wants to
+ return callback(newClass)
+
+ # introspection data only, not used by inner function
+ advise.previousMetaclass = previousMetaclass
+ advise.callback = callback
+
+ # install the advisor
+ caller_locals['__metaclass__'] = advise
+
+
+def isClassAdvisor(ob):
+ """True if 'ob' is a class advisor function"""
+ return isinstance(ob,FunctionType) and hasattr(ob,'previousMetaclass')
+
+
+def determineMetaclass(bases, explicit_mc=None):
+ """Determine metaclass from 1+ bases and optional explicit __metaclass__"""
+
+ meta = [getattr(b,'__class__',type(b)) for b in bases]
+
+ if explicit_mc is not None:
+ # The explicit metaclass needs to be verified for compatibility
+ # as well, and allowed to resolve the incompatible bases, if any
+ meta.append(explicit_mc)
+
+ if len(meta)==1:
+ # easy case
+ return meta[0]
+
+ candidates = minimalBases(meta) # minimal set of metaclasses
+
+ if not candidates:
+ # they're all "classic" classes
+ 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"""
+
+ 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
+
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/advice.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/__init__.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/__init__.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/__init__.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/common/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/idatetime.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/idatetime.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/idatetime.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,577 @@
+##############################################################################
+# Copyright (c) 2002 Zope Corporation 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.
+
+$Id: idatetime.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+from zope.interface import Interface, Attribute
+from zope.interface import classImplements, directlyProvides
+
+from datetime import timedelta, date, datetime, time, tzinfo
+
+
+class ITimeDeltaClass(Interface):
+ """This is the timedelta class interface."""
+
+ min = Attribute("The most negative timedelta object")
+
+ max = Attribute("The most positive timedelta object")
+
+ resolution = Attribute(
+ "The smallest difference between non-equal timedelta objects")
+
+
+class ITimeDelta(ITimeDeltaClass):
+ """Represent the difference between two datetime objects.
+
+ Supported operators:
+
+ - add, subtract timedelta
+ - unary plus, minus, abs
+ - compare to timedelta
+ - multiply, divide by int/long
+
+ In addition, datetime supports subtraction of two datetime objects
+ returning a timedelta, and addition or subtraction of a datetime
+ and a timedelta giving a datetime.
+
+ Representation: (days, seconds, microseconds).
+ """
+
+ days = Attribute("Days between -999999999 and 999999999 inclusive")
+
+ seconds = Attribute("Seconds between 0 and 86399 inclusive")
+
+ microseconds = Attribute("Microseconds between 0 and 999999 inclusive")
+
+
+class IDateClass(Interface):
+ """This is the date class interface."""
+
+ min = Attribute("The earliest representable date")
+
+ max = Attribute("The latest representable date")
+
+ resolution = Attribute(
+ "The smallest difference between non-equal date objects")
+
+ def today():
+ """Return the current local time.
+
+ This is equivalent to date.fromtimestamp(time.time())"""
+
+ def fromtimestamp(timestamp):
+ """Return the local date from a POSIX timestamp (like time.time())
+
+ This may raise ValueError, if the timestamp is out of the range of
+ values supported by the platform C localtime() function. It's common
+ for this to be restricted to years from 1970 through 2038. Note that
+ on non-POSIX systems that include leap seconds in their notion of a
+ timestamp, leap seconds are ignored by fromtimestamp().
+ """
+
+ def fromordinal(ordinal):
+ """Return the date corresponding to the proleptic Gregorian ordinal.
+
+ January 1 of year 1 has ordinal 1. ValueError is raised unless
+ 1 <= ordinal <= date.max.toordinal().
+ For any date d, date.fromordinal(d.toordinal()) == d.
+ """
+
+
+class IDate(IDateClass):
+ """Represents a date (year, month and day) in an idealized calendar.
+
+ Operators:
+
+ __repr__, __str__
+ __cmp__, __hash__
+ __add__, __radd__, __sub__ (add/radd only with timedelta arg)
+ """
+
+ year = Attribute("Between MINYEAR and MAXYEAR inclusive.")
+
+ month = Attribute("Between 1 and 12 inclusive")
+
+ day = Attribute(
+ "Between 1 and the number of days in the given month of the given year.")
+
+ def replace(year, month, day):
+ """Return a date with the same value.
+
+ Except for those members given new values by whichever keyword
+ arguments are specified. For example, if d == date(2002, 12, 31), then
+ d.replace(day=26) == date(2000, 12, 26).
+ """
+
+ def timetuple():
+ """Return a 9-element tuple of the form returned by time.localtime().
+
+ The hours, minutes and seconds are 0, and the DST flag is -1.
+ d.timetuple() is equivalent to
+ (d.year, d.month, d.day, 0, 0, 0, d.weekday(), d.toordinal() -
+ date(d.year, 1, 1).toordinal() + 1, -1)
+ """
+
+ def toordinal():
+ """Return the proleptic Gregorian ordinal of the date
+
+ January 1 of year 1 has ordinal 1. For any date object d,
+ date.fromordinal(d.toordinal()) == d.
+ """
+
+ def weekday():
+ """Return the day of the week as an integer.
+
+ Monday is 0 and Sunday is 6. For example,
+ date(2002, 12, 4).weekday() == 2, a Wednesday.
+
+ See also isoweekday().
+ """
+
+ def isoweekday():
+ """Return the day of the week as an integer.
+
+ Monday is 1 and Sunday is 7. For example,
+ date(2002, 12, 4).isoweekday() == 3, a Wednesday.
+
+ See also weekday(), isocalendar().
+ """
+
+ def isocalendar():
+ """Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
+
+ The ISO calendar is a widely used variant of the Gregorian calendar.
+ See http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm for a good
+ explanation.
+
+ The ISO year consists of 52 or 53 full weeks, and where a week starts
+ on a Monday and ends on a Sunday. The first week of an ISO year is the
+ first (Gregorian) calendar week of a year containing a Thursday. This
+ is called week number 1, and the ISO year of that Thursday is the same
+ as its Gregorian year.
+
+ For example, 2004 begins on a Thursday, so the first week of ISO year
+ 2004 begins on Monday, 29 Dec 2003 and ends on Sunday, 4 Jan 2004, so
+ that date(2003, 12, 29).isocalendar() == (2004, 1, 1) and
+ date(2004, 1, 4).isocalendar() == (2004, 1, 7).
+ """
+
+ def isoformat():
+ """Return a string representing the date in ISO 8601 format.
+
+ This is 'YYYY-MM-DD'.
+ For example, date(2002, 12, 4).isoformat() == '2002-12-04'.
+ """
+
+ def __str__():
+ """For a date d, str(d) is equivalent to d.isoformat()."""
+
+ def ctime():
+ """Return a string representing the date.
+
+ For example date(2002, 12, 4).ctime() == 'Wed Dec 4 00:00:00 2002'.
+ d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple()))
+ on platforms where the native C ctime() function
+ (which time.ctime() invokes, but which date.ctime() does not invoke)
+ conforms to the C standard.
+ """
+
+ def strftime(format):
+ """Return a string representing the date.
+
+ Controlled by an explicit format string. Format codes referring to
+ hours, minutes or seconds will see 0 values.
+ """
+
+
+class IDateTimeClass(Interface):
+ """This is the datetime class interface."""
+
+ min = Attribute("The earliest representable datetime")
+
+ max = Attribute("The latest representable datetime")
+
+ resolution = Attribute(
+ "The smallest possible difference between non-equal datetime objects")
+
+ def today():
+ """Return the current local datetime, with tzinfo None.
+
+ This is equivalent to datetime.fromtimestamp(time.time()).
+ See also now(), fromtimestamp().
+ """
+
+ def now(tz=None):
+ """Return the current local date and time.
+
+ If optional argument tz is None or not specified, this is like today(),
+ but, if possible, supplies more precision than can be gotten from going
+ through a time.time() timestamp (for example, this may be possible on
+ platforms supplying the C gettimeofday() function).
+
+ Else tz must be an instance of a class tzinfo subclass, and the current
+ date and time are converted to tz's time zone. In this case the result
+ is equivalent to tz.fromutc(datetime.utcnow().replace(tzinfo=tz)).
+
+ See also today(), utcnow().
+ """
+
+ def utcnow():
+ """Return the current UTC date and time, with tzinfo None.
+
+ This is like now(), but returns the current UTC date and time, as a
+ naive datetime object.
+
+ See also now().
+ """
+
+ def fromtimestamp(timestamp, tz=None):
+ """Return the local date and time corresponding to the POSIX timestamp.
+
+ Same as is returned by time.time(). If optional argument tz is None or
+ not specified, the timestamp is converted to the platform's local date
+ and time, and the returned datetime object is naive.
+
+ Else tz must be an instance of a class tzinfo subclass, and the
+ timestamp is converted to tz's time zone. In this case the result is
+ equivalent to
+ tz.fromutc(datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz)).
+
+ fromtimestamp() may raise ValueError, if the timestamp is out of the
+ range of values supported by the platform C localtime() or gmtime()
+ functions. It's common for this to be restricted to years in 1970
+ through 2038. Note that on non-POSIX systems that include leap seconds
+ in their notion of a timestamp, leap seconds are ignored by
+ fromtimestamp(), and then it's possible to have two timestamps
+ differing by a second that yield identical datetime objects.
+
+ See also utcfromtimestamp().
+ """
+
+ def utcfromtimestamp(timestamp):
+ """Return the UTC datetime from the POSIX timestamp with tzinfo None.
+
+ This may raise ValueError, if the timestamp is out of the range of
+ values supported by the platform C gmtime() function. It's common for
+ this to be restricted to years in 1970 through 2038.
+
+ See also fromtimestamp().
+ """
+
+ def fromordinal(ordinal):
+ """Return the datetime from the proleptic Gregorian ordinal.
+
+ January 1 of year 1 has ordinal 1. ValueError is raised unless
+ 1 <= ordinal <= datetime.max.toordinal().
+ The hour, minute, second and microsecond of the result are all 0, and
+ tzinfo is None.
+ """
+
+ def combine(date, time):
+ """Return a new datetime object.
+
+ Its date members are equal to the given date object's, and whose time
+ and tzinfo members are equal to the given time object's. For any
+ datetime object d, d == datetime.combine(d.date(), d.timetz()).
+ If date is a datetime object, its time and tzinfo members are ignored.
+ """
+
+
+class IDateTime(IDate, IDateTimeClass):
+ """Object contains all the information from a date object and a time object.
+ """
+
+ year = Attribute("Year between MINYEAR and MAXYEAR inclusive")
+
+ month = Attribute("Month between 1 and 12 inclusive")
+
+ day = Attribute(
+ "Day between 1 and the number of days in the given month of the year")
+
+ hour = Attribute("Hour in range(24)")
+
+ minute = Attribute("Minute in range(60)")
+
+ second = Attribute("Second in range(60)")
+
+ microsecond = Attribute("Microsecond in range(1000000)")
+
+ tzinfo = Attribute(
+ """The object passed as the tzinfo argument to the datetime constructor
+ or None if none was passed""")
+
+ def date():
+ """Return date object with same year, month and day."""
+
+ def time():
+ """Return time object with same hour, minute, second, microsecond.
+
+ tzinfo is None. See also method timetz().
+ """
+
+ def timetz():
+ """Return time object with same hour, minute, second, microsecond,
+ and tzinfo.
+
+ See also method time().
+ """
+
+ def replace(year, month, day, hour, minute, second, microsecond, tzinfo):
+ """Return a datetime with the same members, except for those members
+ given new values by whichever keyword arguments are specified.
+
+ Note that tzinfo=None can be specified to create a naive datetime from
+ an aware datetime with no conversion of date and time members.
+ """
+
+ def astimezone(tz):
+ """Return a datetime object with new tzinfo member tz, adjusting the
+ date and time members so the result is the same UTC time as self, but
+ in tz's local time.
+
+ tz must be an instance of a tzinfo subclass, and its utcoffset() and
+ dst() methods must not return None. self must be aware (self.tzinfo
+ must not be None, and self.utcoffset() must not return None).
+
+ If self.tzinfo is tz, self.astimezone(tz) is equal to self: no
+ adjustment of date or time members is performed. Else the result is
+ local time in time zone tz, representing the same UTC time as self:
+ after astz = dt.astimezone(tz), astz - astz.utcoffset()
+ will usually have the same date and time members as dt - dt.utcoffset().
+ The discussion of class tzinfo explains the cases at Daylight Saving
+ Time transition boundaries where this cannot be achieved (an issue only
+ if tz models both standard and daylight time).
+
+ If you merely want to attach a time zone object tz to a datetime dt
+ without adjustment of date and time members, use dt.replace(tzinfo=tz).
+ If you merely want to remove the time zone object from an aware
+ datetime dt without conversion of date and time members, use
+ dt.replace(tzinfo=None).
+
+ Note that the default tzinfo.fromutc() method can be overridden in a
+ tzinfo subclass to effect the result returned by astimezone().
+ """
+
+ def utcoffset():
+ """Return the timezone offset in minutes east of UTC (negative west of
+ UTC)."""
+
+ def dst():
+ """Return 0 if DST is not in effect, or the DST offset (in minutes
+ eastward) if DST is in effect.
+ """
+
+ def tzname():
+ """Return the timezone name."""
+
+ def timetuple():
+ """Return a 9-element tuple of the form returned by time.localtime()."""
+
+ def utctimetuple():
+ """Return UTC time tuple compatilble with time.gmtimr()."""
+
+ def toordinal():
+ """Return the proleptic Gregorian ordinal of the date.
+
+ The same as self.date().toordinal().
+ """
+
+ def weekday():
+ """Return the day of the week as an integer.
+
+ Monday is 0 and Sunday is 6. The same as self.date().weekday().
+ See also isoweekday().
+ """
+
+ def isoweekday():
+ """Return the day of the week as an integer.
+
+ Monday is 1 and Sunday is 7. The same as self.date().isoweekday.
+ See also weekday(), isocalendar().
+ """
+
+ def isocalendar():
+ """Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
+
+ The same as self.date().isocalendar().
+ """
+
+ def isoformat(sep='T'):
+ """Return a string representing the date and time in ISO 8601 format.
+
+ YYYY-MM-DDTHH:MM:SS.mmmmmm or YYYY-MM-DDTHH:MM:SS if microsecond is 0
+
+ If utcoffset() does not return None, a 6-character string is appended,
+ giving the UTC offset in (signed) hours and minutes:
+
+ YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or YYYY-MM-DDTHH:MM:SS+HH:MM
+ if microsecond is 0.
+
+ The optional argument sep (default 'T') is a one-character separator,
+ placed between the date and time portions of the result.
+ """
+
+ def __str__():
+ """For a datetime instance d, str(d) is equivalent to d.isoformat(' ').
+ """
+
+ def ctime():
+ """Return a string representing the date and time.
+
+ datetime(2002, 12, 4, 20, 30, 40).ctime() == 'Wed Dec 4 20:30:40 2002'.
+ d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple())) on
+ platforms where the native C ctime() function (which time.ctime()
+ invokes, but which datetime.ctime() does not invoke) conforms to the
+ C standard.
+ """
+
+ def strftime(format):
+ """Return a string representing the date and time.
+
+ This is controlled by an explicit format string.
+ """
+
+
+class ITimeClass(Interface):
+ """This is the time class interface."""
+
+ min = Attribute("The earliest representable time")
+
+ max = Attribute("The latest representable time")
+
+ resolution = Attribute(
+ "The smallest possible difference between non-equal time objects")
+
+
+class ITime(ITimeClass):
+ """Represent time with time zone.
+
+ Operators:
+
+ __repr__, __str__
+ __cmp__, __hash__
+ """
+
+ hour = Attribute("Hour in range(24)")
+
+ minute = Attribute("Minute in range(60)")
+
+ second = Attribute("Second in range(60)")
+
+ microsecond = Attribute("Microsecond in range(1000000)")
+
+ tzinfo = Attribute(
+ """The object passed as the tzinfo argument to the time constructor
+ or None if none was passed.""")
+
+ def replace(hour, minute, second, microsecond, tzinfo):
+ """Return a time with the same value.
+
+ Except for those members given new values by whichever keyword
+ arguments are specified. Note that tzinfo=None can be specified
+ to create a naive time from an aware time, without conversion of the
+ time members.
+ """
+
+ def isoformat():
+ """Return a string representing the time in ISO 8601 format.
+
+ That is HH:MM:SS.mmmmmm or, if self.microsecond is 0, HH:MM:SS
+ If utcoffset() does not return None, a 6-character string is appended,
+ giving the UTC offset in (signed) hours and minutes:
+ HH:MM:SS.mmmmmm+HH:MM or, if self.microsecond is 0, HH:MM:SS+HH:MM
+ """
+
+ def __str__():
+ """For a time t, str(t) is equivalent to t.isoformat()."""
+
+ def strftime(format):
+ """Return a string representing the time.
+
+ This is controlled by an explicit format string.
+ """
+
+ def utcoffset():
+ """Return the timezone offset in minutes east of UTC (negative west of
+ UTC).
+
+ If tzinfo is None, returns None, else returns
+ self.tzinfo.utcoffset(None), and raises an exception if the latter
+ doesn't return None or a timedelta object representing a whole number
+ of minutes with magnitude less than one day.
+ """
+
+ def dst():
+ """Return 0 if DST is not in effect, or the DST offset (in minutes
+ eastward) if DST is in effect.
+
+ If tzinfo is None, returns None, else returns self.tzinfo.dst(None),
+ and raises an exception if the latter doesn't return None, or a
+ timedelta object representing a whole number of minutes with
+ magnitude less than one day.
+ """
+
+ def tzname():
+ """Return the timezone name.
+
+ If tzinfo is None, returns None, else returns self.tzinfo.tzname(None),
+ or raises an exception if the latter doesn't return None or a string
+ object.
+ """
+
+
+class ITZInfo(Interface):
+ """Time zone info class.
+ """
+
+ def utcoffset(dt):
+ """Return offset of local time from UTC, in minutes east of UTC.
+
+ If local time is west of UTC, this should be negative.
+ Note that this is intended to be the total offset from UTC;
+ for example, if a tzinfo object represents both time zone and DST
+ adjustments, utcoffset() should return their sum. If the UTC offset
+ isn't known, return None. Else the value returned must be a timedelta
+ object specifying a whole number of minutes in the range -1439 to 1439
+ inclusive (1440 = 24*60; the magnitude of the offset must be less
+ than one day).
+ """
+
+ def dst(dt):
+ """Return the daylight saving time (DST) adjustment, in minutes east
+ of UTC, or None if DST information isn't known.
+ """
+
+ def tzname(dt):
+ """Return the time zone name corresponding to the datetime object as
+ a string.
+ """
+
+ def fromutc(dt):
+ """Return an equivalent datetime in self's local time."""
+
+
+classImplements(timedelta, ITimeDelta)
+classImplements(date, IDate)
+classImplements(datetime, IDateTime)
+classImplements(time, ITime)
+classImplements(tzinfo, ITZInfo)
+
+## directlyProvides(timedelta, ITimeDeltaClass)
+## directlyProvides(date, IDateClass)
+## directlyProvides(datetime, IDateTimeClass)
+## directlyProvides(time, ITimeClass)
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/common/idatetime.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,98 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation 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
+
+$Id: interfaces.py 25177 2004-06-02 13:17:31Z jim $
+"""
+from zope.interface import Interface
+from zope.interface import classImplements
+
+class IException(Interface): pass
+class IStandardError(IException): pass
+class IWarning(IException): pass
+class ISyntaxError(IStandardError): pass
+class ILookupError(IStandardError): pass
+class IValueError(IStandardError): pass
+class IRuntimeError(IStandardError): pass
+class IArithmeticError(IStandardError): pass
+class IAssertionError(IStandardError): pass
+class IAttributeError(IStandardError): pass
+class IDeprecationWarning(IWarning): pass
+class IEOFError(IStandardError): pass
+class IEnvironmentError(IStandardError): pass
+class IFloatingPointError(IArithmeticError): pass
+class IIOError(IEnvironmentError): pass
+class IImportError(IStandardError): pass
+class IIndentationError(ISyntaxError): pass
+class IIndexError(ILookupError): pass
+class IKeyError(ILookupError): pass
+class IKeyboardInterrupt(IStandardError): pass
+class IMemoryError(IStandardError): pass
+class INameError(IStandardError): pass
+class INotImplementedError(IRuntimeError): pass
+class IOSError(IEnvironmentError): pass
+class IOverflowError(IArithmeticError): pass
+class IOverflowWarning(IWarning): pass
+class IReferenceError(IStandardError): pass
+class IRuntimeWarning(IWarning): pass
+class IStopIteration(IException): pass
+class ISyntaxWarning(IWarning): pass
+class ISystemError(IStandardError): pass
+class ISystemExit(IException): pass
+class ITabError(IIndentationError): pass
+class ITypeError(IStandardError): pass
+class IUnboundLocalError(INameError): pass
+class IUnicodeError(IValueError): pass
+class IUserWarning(IWarning): pass
+class IZeroDivisionError(IArithmeticError): pass
+
+classImplements(ArithmeticError, IArithmeticError)
+classImplements(AssertionError, IAssertionError)
+classImplements(AttributeError, IAttributeError)
+classImplements(DeprecationWarning, IDeprecationWarning)
+classImplements(EnvironmentError, IEnvironmentError)
+classImplements(EOFError, IEOFError)
+classImplements(Exception, IException)
+classImplements(FloatingPointError, IFloatingPointError)
+classImplements(ImportError, IImportError)
+classImplements(IndentationError, IIndentationError)
+classImplements(IndexError, IIndexError)
+classImplements(IOError, IIOError)
+classImplements(KeyboardInterrupt, IKeyboardInterrupt)
+classImplements(KeyError, IKeyError)
+classImplements(LookupError, ILookupError)
+classImplements(MemoryError, IMemoryError)
+classImplements(NameError, INameError)
+classImplements(NotImplementedError, INotImplementedError)
+classImplements(OSError, IOSError)
+classImplements(OverflowError, IOverflowError)
+classImplements(OverflowWarning, IOverflowWarning)
+classImplements(ReferenceError, IReferenceError)
+classImplements(RuntimeError, IRuntimeError)
+classImplements(RuntimeWarning, IRuntimeWarning)
+classImplements(StandardError, IStandardError)
+classImplements(StopIteration, IStopIteration)
+classImplements(SyntaxError, ISyntaxError)
+classImplements(SyntaxWarning, ISyntaxWarning)
+classImplements(SystemError, ISystemError)
+classImplements(SystemExit, ISystemExit)
+classImplements(TabError, ITabError)
+classImplements(TypeError, ITypeError)
+classImplements(UnboundLocalError, IUnboundLocalError)
+classImplements(UnicodeError, IUnicodeError)
+classImplements(UserWarning, IUserWarning)
+classImplements(ValueError, IValueError)
+classImplements(Warning, IWarning)
+classImplements(ZeroDivisionError, IZeroDivisionError)
+
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/mapping.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/mapping.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/mapping.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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
+
+$Id: mapping.py 29359 2005-03-01 15:45:04Z poster $
+"""
+from zope.interface import Interface
+
+class IItemMapping(Interface):
+ """Simplest readable mapping object
+ """
+
+ def __getitem__(key):
+ """Get a value for a key
+
+ A KeyError is raised if there is no value for the key.
+ """
+
+
+class IReadMapping(IItemMapping):
+ """Basic mapping interface
+ """
+
+ def get(key, default=None):
+ """Get a value for a key
+
+ The default is returned if there is no value for the key.
+ """
+
+ def __contains__(key):
+ """Tell if a key exists in the mapping."""
+
+
+class IWriteMapping(Interface):
+ """Mapping methods for changing data"""
+
+ def __delitem__(key):
+ """Delete a value from the mapping using the key."""
+
+ def __setitem__(key, value):
+ """Set a new item in the mapping."""
+
+
+class IEnumerableMapping(IReadMapping):
+ """Mapping objects whose items can be enumerated.
+ """
+
+ def keys():
+ """Return the keys of the mapping object.
+ """
+
+ def __iter__():
+ """Return an iterator for the keys of the mapping object.
+ """
+
+ def values():
+ """Return the values of the mapping object.
+ """
+
+ def items():
+ """Return the items of the mapping object.
+ """
+
+ def __len__():
+ """Return the number of items.
+ """
+
+class IMapping(IWriteMapping, IEnumerableMapping):
+ ''' Simple mapping interface '''
+
+class IIterableMapping(IEnumerableMapping):
+
+ def iterkeys():
+ "iterate over keys; equivalent to __iter__"
+
+ def itervalues():
+ "iterate over values"
+
+ def iteritems():
+ "iterate over items"
+
+class IClonableMapping(Interface):
+
+ def copy():
+ "return copy of dict"
+
+class IExtendedReadMapping(IIterableMapping):
+
+ def has_key(key):
+ """Tell if a key exists in the mapping; equivalent to __contains__"""
+
+class IExtendedWriteMapping(IWriteMapping):
+
+ def clear():
+ "delete all items"
+
+ def update(d):
+ " Update D from E: for k in E.keys(): D[k] = E[k]"
+
+ def setdefault(key, default=None):
+ "D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"
+
+ def pop(k, *args):
+ """remove specified key and return the corresponding value
+ *args may contain a single default value, or may not be supplied.
+ If key is not found, default is returned if given, otherwise
+ KeyError is raised"""
+
+ def popitem():
+ """remove and return some (key, value) pair as a
+ 2-tuple; but raise KeyError if mapping is empty"""
+
+class IFullMapping(
+ IExtendedReadMapping, IExtendedWriteMapping, IClonableMapping, IMapping):
+ ''' Full mapping interface ''' # IMapping included so tests for IMapping
+ # succeed with IFullMapping
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/common/mapping.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,152 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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
+
+$Id: sequence.py 39752 2005-10-30 20:16:09Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope import interface
+
+class IMinimalSequence(interface.Interface):
+
+ def __getitem__(index):
+ """`x.__getitem__(index)` <==> `x[index]`
+
+ Declaring this interface does not specify whether `__getitem__`
+ supports slice objects."""
+
+ def __iter__():
+ """`x.__iter__()` <==> `iter(x)`"""
+
+class IFiniteSequence(IMinimalSequence):
+
+ def __len__():
+ """`x.__len__()` <==> `len(x)`"""
+
+class IReadSequence(IFiniteSequence):
+ """read interface shared by tuple and list"""
+
+ def __contains__(item):
+ """`x.__contains__(item)` <==> `item in x`"""
+
+ def __lt__(other):
+ """`x.__lt__(other)` <==> `x < other`"""
+
+ def __le__(other):
+ """`x.__le__(other)` <==> `x <= other`"""
+
+ def __eq__(other):
+ """`x.__eq__(other)` <==> `x == other`"""
+
+ def __ne__(other):
+ """`x.__ne__(other)` <==> `x != other`"""
+
+ def __gt__(other):
+ """`x.__gt__(other)` <==> `x > other`"""
+
+ def __ge__(other):
+ """`x.__ge__(other)` <==> `x >= other`"""
+
+ def __add__(other):
+ """`x.__add__(other)` <==> `x + other`"""
+
+ def __mul__(n):
+ """`x.__mul__(n)` <==> `x * n`"""
+
+ def __rmul__(n):
+ """`x.__rmul__(n)` <==> `n * x`"""
+
+ def __getslice__(i, j):
+ """`x.__getslice__(i, j)` <==> `x[i:j]`
+
+ Use of negative indices is not supported.
+
+ Deprecated since Python 2.0 but still a part of `UserList`.
+ """
+
+class IExtendedReadSequence(IReadSequence):
+ """Full read interface for lists"""
+
+ def count(item):
+ """Return number of occurrences of value"""
+
+ def index(item, *args):
+ """Return first index of value
+
+ `L.index(value, [start, [stop]])` -> integer"""
+
+class IUniqueMemberWriteSequence(interface.Interface):
+ """The write contract for a sequence that may enforce unique members"""
+
+ def __setitem__(index, item):
+ """`x.__setitem__(index, item)` <==> `x[index] = item`
+
+ Declaring this interface does not specify whether `__setitem__`
+ supports slice objects.
+ """
+
+ def __delitem__(index):
+ """`x.__delitem__(index)` <==> `del x[index]`
+
+ Declaring this interface does not specify whether `__delitem__`
+ supports slice objects.
+ """
+
+ def __setslice__(i, j, other):
+ """`x.__setslice__(i, j, other)` <==> `x[i:j]=other`
+
+ Use of negative indices is not supported.
+
+ Deprecated since Python 2.0 but still a part of `UserList`.
+ """
+
+ def __delslice__(i, j):
+ """`x.__delslice__(i, j)` <==> `del x[i:j]`
+
+ Use of negative indices is not supported.
+
+ Deprecated since Python 2.0 but still a part of `UserList`.
+ """
+ def __iadd__(y):
+ """`x.__iadd__(y)` <==> `x += y`"""
+
+ def append(item):
+ """Append item to end"""
+
+ def insert(index, item):
+ """Insert item before index"""
+
+ def pop(index=-1):
+ """Remove and return item at index (default last)"""
+
+ def remove(item):
+ """Remove first occurrence of value"""
+
+ def reverse():
+ """Reverse *IN PLACE*"""
+
+ def sort(cmpfunc=None):
+ """Stable sort *IN PLACE*; `cmpfunc(x, y)` -> -1, 0, 1"""
+
+ def extend(iterable):
+ """Extend list by appending elements from the iterable"""
+
+class IWriteSequence(IUniqueMemberWriteSequence):
+ """Full write contract for sequences"""
+
+ def __imul__(n):
+ """`x.__imul__(n)` <==> `x *= n`"""
+
+class ISequence(IReadSequence, IWriteSequence):
+ """Full sequence contract"""
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/__init__.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/__init__.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/__init__.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/basemapping.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/basemapping.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/basemapping.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,115 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Base Mapping tests
+
+$Id: basemapping.py 26560 2004-07-15 21:38:42Z srichter $
+"""
+from operator import __getitem__
+
+def testIReadMapping(self, inst, state, absent):
+ for key in state:
+ self.assertEqual(inst[key], state[key])
+ self.assertEqual(inst.get(key, None), state[key])
+ self.failUnless(key in inst)
+
+ for key in absent:
+ self.assertEqual(inst.get(key, None), None)
+ self.assertEqual(inst.get(key), None)
+ self.assertEqual(inst.get(key, self), self)
+ self.assertRaises(KeyError, __getitem__, inst, key)
+
+
+def test_keys(self, inst, state):
+ # Return the keys of the mapping object
+ inst_keys = list(inst.keys()); inst_keys.sort()
+ state_keys = list(state.keys()) ; state_keys.sort()
+ self.assertEqual(inst_keys, state_keys)
+
+def test_iter(self, inst, state):
+ # Return the keys of the mapping object
+ inst_keys = list(inst); inst_keys.sort()
+ state_keys = list(state.keys()) ; state_keys.sort()
+ self.assertEqual(inst_keys, state_keys)
+
+def test_values(self, inst, state):
+ # Return the values of the mapping object
+ inst_values = list(inst.values()); inst_values.sort()
+ state_values = list(state.values()) ; state_values.sort()
+ self.assertEqual(inst_values, state_values)
+
+def test_items(self, inst, state):
+ # Return the items of the mapping object
+ inst_items = list(inst.items()); inst_items.sort()
+ state_items = list(state.items()) ; state_items.sort()
+ self.assertEqual(inst_items, state_items)
+
+def test___len__(self, inst, state):
+ # Return the number of items
+ self.assertEqual(len(inst), len(state))
+
+def testIEnumerableMapping(self, inst, state):
+ test_keys(self, inst, state)
+ test_items(self, inst, state)
+ test_values(self, inst, state)
+ test___len__(self, inst, state)
+
+
+class BaseTestIReadMapping(object):
+ def testIReadMapping(self):
+ inst = self._IReadMapping__sample()
+ state = self._IReadMapping__stateDict()
+ absent = self._IReadMapping__absentKeys()
+ testIReadMapping(self, inst, state, absent)
+
+
+class BaseTestIEnumerableMapping(BaseTestIReadMapping):
+ # Mapping objects whose items can be enumerated
+ def test_keys(self):
+ # Return the keys of the mapping object
+ inst = self._IEnumerableMapping__sample()
+ state = self._IEnumerableMapping__stateDict()
+ test_keys(self, inst, state)
+
+ def test_values(self):
+ # Return the values of the mapping object
+ inst = self._IEnumerableMapping__sample()
+ state = self._IEnumerableMapping__stateDict()
+ test_values(self, inst, state)
+
+ def test_values(self):
+ # Return the values of the mapping object
+ inst = self._IEnumerableMapping__sample()
+ state = self._IEnumerableMapping__stateDict()
+ test_iter(self, inst, state)
+
+ def test_items(self):
+ # Return the items of the mapping object
+ inst = self._IEnumerableMapping__sample()
+ state = self._IEnumerableMapping__stateDict()
+ test_items(self, inst, state)
+
+ def test___len__(self):
+ # Return the number of items
+ inst = self._IEnumerableMapping__sample()
+ state = self._IEnumerableMapping__stateDict()
+ test___len__(self, inst, state)
+
+ def _IReadMapping__stateDict(self):
+ return self._IEnumerableMapping__stateDict()
+
+ def _IReadMapping__sample(self):
+ return self._IEnumerableMapping__sample()
+
+ def _IReadMapping__absentKeys(self):
+ return self._IEnumerableMapping__absentKeys()
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/basemapping.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_idatetime.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_idatetime.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_idatetime.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,49 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test for datetime interfaces
+
+$Id: test_idatetime.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+import unittest
+
+from zope.interface.verify import verifyObject, verifyClass
+from zope.interface.common.idatetime import ITimeDelta, ITimeDeltaClass
+from zope.interface.common.idatetime import IDate, IDateClass
+from zope.interface.common.idatetime import IDateTime, IDateTimeClass
+from zope.interface.common.idatetime import ITime, ITimeClass, ITZInfo
+from datetime import timedelta, date, datetime, time, tzinfo
+
+class TestDateTimeInterfaces(unittest.TestCase):
+
+ def test_interfaces(self):
+ verifyObject(ITimeDelta, timedelta(minutes=20))
+ verifyObject(IDate, date(2000, 1, 2))
+ verifyObject(IDateTime, datetime(2000, 1, 2, 10, 20))
+ verifyObject(ITime, time(20, 30, 15, 1234))
+ verifyObject(ITZInfo, tzinfo())
+ verifyClass(ITimeDeltaClass, timedelta)
+ verifyClass(IDateClass, date)
+ verifyClass(IDateTimeClass, datetime)
+ verifyClass(ITimeClass, time)
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestDateTimeInterfaces))
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_idatetime.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,1388 @@
+##############################################################################
+# Copyright (c) 2003 Zope Corporation 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.
+
+
+$Id: declarations.py 67745 2006-04-29 00:44:10Z poster $
+"""
+__docformat__ = 'restructuredtext'
+
+import sys
+import types
+import weakref
+from zope.interface.interface import InterfaceClass, Specification
+from ro import mergeOrderings, ro
+import exceptions
+from types import ClassType
+from zope.interface.advice import addClassAdvisor
+
+# Registry of class-implementation specifications
+BuiltinImplementationSpecifications = {}
+
+class Declaration(Specification):
+ """Interface declarations"""
+
+ def __init__(self, *interfaces):
+ Specification.__init__(self, _normalizeargs(interfaces))
+
+ def changed(self, originally_changed):
+ Specification.changed(self, originally_changed)
+ try:
+ del self._v_attrs
+ except AttributeError:
+ pass
+
+ def __contains__(self, interface):
+ """Test whether an interface is in the specification
+
+ for example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration(I2, I3)
+ >>> spec = Declaration(I4, spec)
+ >>> int(I1 in spec)
+ 0
+ >>> int(I2 in spec)
+ 1
+ >>> int(I3 in spec)
+ 1
+ >>> int(I4 in spec)
+ 1
+ """
+ return self.extends(interface) and interface in self.interfaces()
+
+ def __iter__(self):
+ """Return an iterator for the interfaces in the specification
+
+ for example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration(I2, I3)
+ >>> spec = Declaration(I4, spec)
+ >>> i = iter(spec)
+ >>> i.next().getName()
+ 'I4'
+ >>> i.next().getName()
+ 'I2'
+ >>> i.next().getName()
+ 'I3'
+ >>> list(i)
+ []
+ """
+ return self.interfaces()
+
+ def flattened(self):
+ """Return an iterator of all included and extended interfaces
+
+ for example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration(I2, I3)
+ >>> spec = Declaration(I4, spec)
+ >>> i = spec.flattened()
+ >>> i.next().getName()
+ 'I4'
+ >>> i.next().getName()
+ 'I2'
+ >>> i.next().getName()
+ 'I1'
+ >>> i.next().getName()
+ 'I3'
+ >>> i.next().getName()
+ 'Interface'
+ >>> list(i)
+ []
+
+ """
+ return iter(self.__iro__)
+
+ def __sub__(self, other):
+ """Remove interfaces from a specification
+
+ Examples:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration()
+ >>> [iface.getName() for iface in spec]
+ []
+ >>> spec -= I1
+ >>> [iface.getName() for iface in spec]
+ []
+ >>> spec -= Declaration(I1, I2)
+ >>> [iface.getName() for iface in spec]
+ []
+ >>> spec = Declaration(I2, I4)
+ >>> [iface.getName() for iface in spec]
+ ['I2', 'I4']
+ >>> [iface.getName() for iface in spec - I4]
+ ['I2']
+ >>> [iface.getName() for iface in spec - I1]
+ ['I4']
+ >>> [iface.getName() for iface
+ ... in spec - Declaration(I3, I4)]
+ ['I2']
+
+ """
+
+ return Declaration(
+ *[i for i in self.interfaces()
+ if not [j for j in other.interfaces()
+ if i.extends(j, 0)]
+ ]
+ )
+
+ def __add__(self, other):
+ """Add two specifications or a specification and an interface
+
+ Examples:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration()
+ >>> [iface.getName() for iface in spec]
+ []
+ >>> [iface.getName() for iface in spec+I1]
+ ['I1']
+ >>> [iface.getName() for iface in I1+spec]
+ ['I1']
+ >>> spec2 = spec
+ >>> spec += I1
+ >>> [iface.getName() for iface in spec]
+ ['I1']
+ >>> [iface.getName() for iface in spec2]
+ []
+ >>> spec2 += Declaration(I3, I4)
+ >>> [iface.getName() for iface in spec2]
+ ['I3', 'I4']
+ >>> [iface.getName() for iface in spec+spec2]
+ ['I1', 'I3', 'I4']
+ >>> [iface.getName() for iface in spec2+spec]
+ ['I3', 'I4', 'I1']
+
+ """
+
+ seen = {}
+ result = []
+ for i in self.interfaces():
+ if i not in seen:
+ seen[i] = 1
+ result.append(i)
+ for i in other.interfaces():
+ if i not in seen:
+ seen[i] = 1
+ result.append(i)
+
+ return Declaration(*result)
+
+ __radd__ = __add__
+
+
+##############################################################################
+#
+# Implementation specifications
+#
+# These specify interfaces implemented by instances of classes
+
+class Implements(Declaration):
+
+ # class whose specification should be used as additional base
+ inherit = None
+
+ # interfaces actually declared for a class
+ declared = ()
+
+ __name__ = '?'
+
+ def __repr__(self):
+ return '<implementedBy %s>' % (self.__name__)
+
+ def __reduce__(self):
+ return implementedBy, (self.inherit, )
+
+def implementedByFallback(cls):
+ """Return the interfaces implemented for a class' instances
+
+ The value returned is an IDeclaration.
+
+ for example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> class C1(object):
+ ... implements(I2)
+ >>> class C2(C1):
+ ... implements(I3)
+ >>> [i.getName() for i in implementedBy(C2)]
+ ['I3', 'I2']
+
+ Really, any object should be able to receive a successful answer, even
+ an instance:
+
+ >>> class Callable(object):
+ ... def __call__(self):
+ ... return self
+
+ >>> implementedBy(Callable())
+ <implementedBy zope.interface.declarations.?>
+
+ Note that the name of the spec ends with a '?', because the `Callable`
+ instance does not have a `__name__` attribute.
+ """
+ # This also manages storage of implementation specifications
+
+ try:
+ spec = cls.__dict__.get('__implemented__')
+ except AttributeError:
+
+ # we can't get the class dict. This is probably due to a
+ # security proxy. If this is the case, then probably no
+ # descriptor was installed for the class.
+
+ # We don't want to depend directly on zope.security in
+ # zope.interface, but we'll try to make reasonable
+ # accommodations in an indirect way.
+
+ # We'll check to see if there's an implements:
+
+ spec = getattr(cls, '__implemented__', None)
+ if spec is None:
+ # There's no spec stred in the class. Maybe its a builtin:
+ spec = BuiltinImplementationSpecifications.get(cls)
+ if spec is not None:
+ return spec
+ return _empty
+
+ if spec.__class__ == Implements:
+ # we defaulted to _empty or there was a spec. Good enough.
+ # Return it.
+ return spec
+
+ # TODO: need old style __implements__ compatibility?
+ # Hm, there's an __implemented__, but it's not a spec. Must be
+ # an old-style declaration. Just compute a spec for it
+ return Declaration(*_normalizeargs((spec, )))
+
+ if isinstance(spec, Implements):
+ return spec
+
+ if spec is None:
+ spec = BuiltinImplementationSpecifications.get(cls)
+ if spec is not None:
+ return spec
+
+ # TODO: need old style __implements__ compatibility?
+ if spec is not None:
+ # old-style __implemented__ = foo declaration
+ spec = (spec, ) # tuplefy, as it might be just an int
+ spec = Implements(*_normalizeargs(spec))
+ spec.inherit = None # old-style implies no inherit
+ del cls.__implemented__ # get rid of the old-style declaration
+ else:
+ try:
+ bases = cls.__bases__
+ except AttributeError:
+ if not callable(cls):
+ raise TypeError("ImplementedBy called for non-factory", cls)
+ bases = ()
+
+ spec = Implements(*[implementedBy(c) for c in bases])
+ spec.inherit = cls
+
+ spec.__name__ = (getattr(cls, '__module__', '?') or '?') + \
+ '.' + (getattr(cls, '__name__', '?') or '?')
+
+ try:
+ cls.__implemented__ = spec
+ if not hasattr(cls, '__providedBy__'):
+ cls.__providedBy__ = objectSpecificationDescriptor
+
+ if (isinstance(cls, DescriptorAwareMetaClasses)
+ and
+ '__provides__' not in cls.__dict__):
+ # Make sure we get a __provides__ descriptor
+ cls.__provides__ = ClassProvides(
+ cls,
+ getattr(cls, '__class__', type(cls)),
+ )
+
+ except TypeError:
+ if not isinstance(cls, type):
+ raise TypeError("ImplementedBy called for non-type", cls)
+ BuiltinImplementationSpecifications[cls] = spec
+
+ return spec
+
+implementedBy = implementedByFallback
+
+def classImplementsOnly(cls, *interfaces):
+ """Declare the only interfaces implemented by instances of a class
+
+ The arguments after the class are one or more interfaces or interface
+ specifications (``IDeclaration`` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ replace any previous declarations.
+
+ Consider the following example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(Interface): pass
+ ...
+ >>> class A(object):
+ ... implements(I3)
+ >>> class B(object):
+ ... implements(I4)
+ >>> class C(A, B):
+ ... pass
+ >>> classImplementsOnly(C, I1, I2)
+ >>> [i.getName() for i in implementedBy(C)]
+ ['I1', 'I2']
+
+ Instances of ``C`` provide only ``I1``, ``I2``, and regardless of
+ whatever interfaces instances of ``A`` and ``B`` implement.
+ """
+ spec = implementedBy(cls)
+ spec.declared = ()
+ spec.inherit = None
+ classImplements(cls, *interfaces)
+
+def classImplements(cls, *interfaces):
+ """Declare additional interfaces implemented for instances of a class
+
+ The arguments after the class are one or more interfaces or
+ interface specifications (``IDeclaration`` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ are added to any interfaces previously declared.
+
+ Consider the following example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(Interface): pass
+ ...
+ >>> class I5(Interface): pass
+ ...
+ >>> class A(object):
+ ... implements(I3)
+ >>> class B(object):
+ ... implements(I4)
+ >>> class C(A, B):
+ ... pass
+ >>> classImplements(C, I1, I2)
+ >>> [i.getName() for i in implementedBy(C)]
+ ['I1', 'I2', 'I3', 'I4']
+ >>> classImplements(C, I5)
+ >>> [i.getName() for i in implementedBy(C)]
+ ['I1', 'I2', 'I5', 'I3', 'I4']
+
+ Instances of ``C`` provide ``I1``, ``I2``, ``I5``, and whatever
+ interfaces instances of ``A`` and ``B`` provide.
+ """
+
+ spec = implementedBy(cls)
+ spec.declared += tuple(_normalizeargs(interfaces))
+
+ # compute the bases
+ bases = []
+ seen = {}
+ for b in spec.declared:
+ if b not in seen:
+ seen[b] = 1
+ bases.append(b)
+
+ if spec.inherit is not None:
+
+ for c in spec.inherit.__bases__:
+ b = implementedBy(c)
+ if b not in seen:
+ seen[b] = 1
+ bases.append(b)
+
+ spec.__bases__ = tuple(bases)
+
+def _implements_advice(cls):
+ interfaces, classImplements = cls.__dict__['__implements_advice_data__']
+ del cls.__implements_advice_data__
+ classImplements(cls, *interfaces)
+ return cls
+
+
+class implementer:
+
+ def __init__(self, *interfaces):
+ self.interfaces = interfaces
+
+ def __call__(self, ob):
+ if isinstance(ob, DescriptorAwareMetaClasses):
+ raise TypeError("Can't use implementer with classes. Use one of "
+ "the class-declaration functions instead."
+ )
+ spec = Implements(*self.interfaces)
+ try:
+ ob.__implemented__ = spec
+ except AttributeError:
+ raise TypeError("Can't declare implements", ob)
+ return ob
+
+def _implements(name, interfaces, classImplements):
+ frame = sys._getframe(2)
+ locals = frame.f_locals
+
+ # Try to make sure we were called from a class def. In 2.2.0 we can't
+ # check for __module__ since it doesn't seem to be added to the locals
+ # until later on.
+ if (locals is frame.f_globals) or (
+ ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)):
+ raise TypeError(name+" can be used only from a class definition.")
+
+ if '__implements_advice_data__' in locals:
+ raise TypeError(name+" can be used only once in a class definition.")
+
+ locals['__implements_advice_data__'] = interfaces, classImplements
+ addClassAdvisor(_implements_advice, depth=3)
+
+def implements(*interfaces):
+ """Declare interfaces implemented by instances of a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) are added to any interfaces previously
+ declared.
+
+ Previous declarations include declarations for base classes
+ unless implementsOnly was used.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call classImplements. For example::
+
+ implements(I1)
+
+ is equivalent to calling::
+
+ classImplements(C, I1)
+
+ after the class has been created.
+
+ Consider the following example::
+
+
+ >>> from zope.interface import Interface
+ >>> class IA1(Interface): pass
+ ...
+ >>> class IA2(Interface): pass
+ ...
+ >>> class IB(Interface): pass
+ ...
+ >>> class IC(Interface): pass
+ ...
+ >>> class A(object): implements(IA1, IA2)
+ ...
+ >>> class B(object): implements(IB)
+ ...
+
+ >>> class C(A, B):
+ ... implements(IC)
+
+ >>> ob = C()
+ >>> int(IA1 in providedBy(ob))
+ 1
+ >>> int(IA2 in providedBy(ob))
+ 1
+ >>> int(IB in providedBy(ob))
+ 1
+ >>> int(IC in providedBy(ob))
+ 1
+
+ Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces
+ instances of ``A`` and ``B`` implement.
+
+ """
+ _implements("implements", interfaces, classImplements)
+
+def implementsOnly(*interfaces):
+ """Declare the only interfaces implemented by instances of a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ Previous declarations including declarations for base classes
+ are overridden.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call classImplementsOnly. For example::
+
+ implementsOnly(I1)
+
+ is equivalent to calling::
+
+ classImplementsOnly(I1)
+
+ after the class has been created.
+
+ Consider the following example::
+
+ >>> from zope.interface import Interface
+ >>> class IA1(Interface): pass
+ ...
+ >>> class IA2(Interface): pass
+ ...
+ >>> class IB(Interface): pass
+ ...
+ >>> class IC(Interface): pass
+ ...
+ >>> class A(object): implements(IA1, IA2)
+ ...
+ >>> class B(object): implements(IB)
+ ...
+
+ >>> class C(A, B):
+ ... implementsOnly(IC)
+
+ >>> ob = C()
+ >>> int(IA1 in providedBy(ob))
+ 0
+ >>> int(IA2 in providedBy(ob))
+ 0
+ >>> int(IB in providedBy(ob))
+ 0
+ >>> int(IC in providedBy(ob))
+ 1
+
+
+ Instances of ``C`` implement ``IC``, regardless of what
+ instances of ``A`` and ``B`` implement.
+
+ """
+ _implements("implementsOnly", interfaces, classImplementsOnly)
+
+##############################################################################
+#
+# Instance declarations
+
+class Provides(Declaration): # Really named ProvidesClass
+ """Implement __provides__, the instance-specific specification
+
+ When an object is pickled, we pickle the interfaces that it implements.
+ """
+
+ def __init__(self, cls, *interfaces):
+ self.__args = (cls, ) + interfaces
+ self._cls = cls
+ Declaration.__init__(self, *(interfaces + (implementedBy(cls), )))
+
+ def __reduce__(self):
+ return Provides, self.__args
+
+ __module__ = 'zope.interface'
+
+ def __get__(self, inst, cls):
+ """Make sure that a class __provides__ doesn't leak to an instance
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class IFooFactory(Interface): pass
+ ...
+
+ >>> class C(object):
+ ... pass
+
+ >>> C.__provides__ = ProvidesClass(C, IFooFactory)
+ >>> [i.getName() for i in C.__provides__]
+ ['IFooFactory']
+ >>> getattr(C(), '__provides__', 0)
+ 0
+
+ """
+ if inst is None and cls is self._cls:
+ # We were accessed through a class, so we are the class'
+ # provides spec. Just return this object, but only if we are
+ # being called on the same class that we were defined for:
+ return self
+
+ raise AttributeError('__provides__')
+
+ProvidesClass = Provides
+
+# Registry of instance declarations
+# This is a memory optimization to allow objects to share specifications.
+InstanceDeclarations = weakref.WeakValueDictionary()
+
+def Provides(*interfaces):
+ """Cache instance declarations
+
+ Instance declarations are shared among instances that have the same
+ declaration. The declarations are cached in a weak value dictionary.
+
+ (Note that, in the examples below, we are going to make assertions about
+ the size of the weakvalue dictionary. For the assertions to be
+ meaningful, we need to force garbage collection to make sure garbage
+ objects are, indeed, removed from the system. Depending on how Python
+ is run, we may need to make multiple calls to be sure. We provide a
+ collect function to help with this:
+
+ >>> import gc
+ >>> def collect():
+ ... for i in range(4):
+ ... gc.collect()
+
+ )
+
+ >>> collect()
+ >>> before = len(InstanceDeclarations)
+
+ >>> class C(object):
+ ... pass
+
+ >>> from zope.interface import Interface
+ >>> class I(Interface):
+ ... pass
+
+ >>> c1 = C()
+ >>> c2 = C()
+
+ >>> len(InstanceDeclarations) == before
+ 1
+
+ >>> directlyProvides(c1, I)
+ >>> len(InstanceDeclarations) == before + 1
+ 1
+
+ >>> directlyProvides(c2, I)
+ >>> len(InstanceDeclarations) == before + 1
+ 1
+
+ >>> del c1
+ >>> collect()
+ >>> len(InstanceDeclarations) == before + 1
+ 1
+
+ >>> del c2
+ >>> collect()
+ >>> len(InstanceDeclarations) == before
+ 1
+ """
+
+ spec = InstanceDeclarations.get(interfaces)
+ if spec is None:
+ spec = ProvidesClass(*interfaces)
+ InstanceDeclarations[interfaces] = spec
+
+ return spec
+Provides.__safe_for_unpickling__ = True
+
+
+DescriptorAwareMetaClasses = ClassType, type
+def directlyProvides(object, *interfaces):
+ """Declare interfaces declared directly for an object
+
+ The arguments after the object are one or more interfaces or interface
+ specifications (``IDeclaration`` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ replace interfaces previously declared for the object.
+
+ Consider the following example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class IA1(Interface): pass
+ ...
+ >>> class IA2(Interface): pass
+ ...
+ >>> class IB(Interface): pass
+ ...
+ >>> class IC(Interface): pass
+ ...
+ >>> class A(object): implements(IA1, IA2)
+ ...
+ >>> class B(object): implements(IB)
+ ...
+
+ >>> class C(A, B):
+ ... implements(IC)
+
+ >>> ob = C()
+ >>> directlyProvides(ob, I1, I2)
+ >>> int(I1 in providedBy(ob))
+ 1
+ >>> int(I2 in providedBy(ob))
+ 1
+ >>> int(IA1 in providedBy(ob))
+ 1
+ >>> int(IA2 in providedBy(ob))
+ 1
+ >>> int(IB in providedBy(ob))
+ 1
+ >>> int(IC in providedBy(ob))
+ 1
+
+ The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+ instances have been declared for instances of ``C``.
+
+ To remove directly provided interfaces, use ``directlyProvidedBy`` and
+ subtract the unwanted interfaces. For example:
+
+ >>> directlyProvides(ob, directlyProvidedBy(ob)-I2)
+ >>> int(I1 in providedBy(ob))
+ 1
+ >>> int(I2 in providedBy(ob))
+ 0
+
+ removes I2 from the interfaces directly provided by ``ob``. The object,
+ ``ob`` no longer directly provides ``I2``, although it might still
+ provide ``I2`` if it's class implements ``I2``.
+
+ To add directly provided interfaces, use ``directlyProvidedBy`` and
+ include additional interfaces. For example:
+
+ >>> int(I2 in providedBy(ob))
+ 0
+ >>> directlyProvides(ob, directlyProvidedBy(ob), I2)
+
+ adds ``I2`` to the interfaces directly provided by ob::
+
+ >>> int(I2 in providedBy(ob))
+ 1
+
+ """
+
+ # We need to avoid setting this attribute on meta classes that
+ # don't support descriptors.
+ # We can do away with this check when we get rid of the old EC
+ cls = getattr(object, '__class__', None)
+ if cls is not None and getattr(cls, '__class__', None) is cls:
+ # It's a meta class (well, at least it it could be an extension class)
+ if not isinstance(object, DescriptorAwareMetaClasses):
+ raise TypeError("Attempt to make an interface declaration on a "
+ "non-descriptor-aware class")
+
+ interfaces = _normalizeargs(interfaces)
+ if cls is None:
+ cls = type(object)
+
+ issub = False
+ for damc in DescriptorAwareMetaClasses:
+ if issubclass(cls, damc):
+ issub = True
+ break
+ if issub:
+ # we have a class or type. We'll use a special descriptor
+ # that provides some extra caching
+ object.__provides__ = ClassProvides(object, cls, *interfaces)
+ else:
+ object.__provides__ = Provides(cls, *interfaces)
+
+
+def alsoProvides(object, *interfaces):
+ """Declare interfaces declared directly for an object
+
+ The arguments after the object are one or more interfaces or interface
+ specifications (``IDeclaration`` objects).
+
+ The interfaces given (including the interfaces in the specifications) are
+ added to the interfaces previously declared for the object.
+
+ Consider the following example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class IA1(Interface): pass
+ ...
+ >>> class IA2(Interface): pass
+ ...
+ >>> class IB(Interface): pass
+ ...
+ >>> class IC(Interface): pass
+ ...
+ >>> class A(object): implements(IA1, IA2)
+ ...
+ >>> class B(object): implements(IB)
+ ...
+
+ >>> class C(A, B):
+ ... implements(IC)
+
+ >>> ob = C()
+ >>> directlyProvides(ob, I1)
+ >>> int(I1 in providedBy(ob))
+ 1
+ >>> int(I2 in providedBy(ob))
+ 0
+ >>> int(IA1 in providedBy(ob))
+ 1
+ >>> int(IA2 in providedBy(ob))
+ 1
+ >>> int(IB in providedBy(ob))
+ 1
+ >>> int(IC in providedBy(ob))
+ 1
+
+ >>> alsoProvides(ob, I2)
+ >>> int(I1 in providedBy(ob))
+ 1
+ >>> int(I2 in providedBy(ob))
+ 1
+ >>> int(IA1 in providedBy(ob))
+ 1
+ >>> int(IA2 in providedBy(ob))
+ 1
+ >>> int(IB in providedBy(ob))
+ 1
+ >>> int(IC in providedBy(ob))
+ 1
+
+ The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+ instances have been declared for instances of ``C``. Notice that the
+ alsoProvides just extends the provided interfaces.
+ """
+ directlyProvides(object, directlyProvidedBy(object), *interfaces)
+
+def noLongerProvides(object, interface):
+ """
+ This removes a directly provided interface from an object.
+ Consider the following two interfaces:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+
+ ``I1`` is provided through the class, ``I2`` is directly provided
+ by the object:
+
+ >>> class C(object):
+ ... implements(I1)
+ >>> c = C()
+ >>> alsoProvides(c, I2)
+ >>> I2.providedBy(c)
+ True
+
+ Remove I2 from c again:
+
+ >>> noLongerProvides(c, I2)
+ >>> I2.providedBy(c)
+ False
+
+ Removing an interface that is provided through the class is not possible:
+
+ >>> noLongerProvides(c, I1)
+ Traceback (most recent call last):
+ ...
+ ValueError: Can only remove directly provided interfaces.
+
+ """
+ directlyProvides(object, directlyProvidedBy(object)-interface)
+ if interface.providedBy(object):
+ raise ValueError("Can only remove directly provided interfaces.")
+
+class ClassProvidesBasePy(object):
+
+ def __get__(self, inst, cls):
+ if cls is self._cls:
+ # We only work if called on the class we were defined for
+
+ if inst is None:
+ # We were accessed through a class, so we are the class'
+ # provides spec. Just return this object as is:
+ return self
+
+ return self._implements
+
+ raise AttributeError('__provides__')
+
+ClassProvidesBase = ClassProvidesBasePy
+
+# Try to get C base:
+try:
+ import _zope_interface_coptimizations
+except ImportError:
+ pass
+else:
+ from _zope_interface_coptimizations import ClassProvidesBase
+
+
+class ClassProvides(Declaration, ClassProvidesBase):
+ """Special descriptor for class __provides__
+
+ The descriptor caches the implementedBy info, so that
+ we can get declarations for objects without instance-specific
+ interfaces a bit quicker.
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class IFooFactory(Interface):
+ ... pass
+ >>> class IFoo(Interface):
+ ... pass
+ >>> class C(object):
+ ... implements(IFoo)
+ ... classProvides(IFooFactory)
+ >>> [i.getName() for i in C.__provides__]
+ ['IFooFactory']
+
+ >>> [i.getName() for i in C().__provides__]
+ ['IFoo']
+ """
+
+ def __init__(self, cls, metacls, *interfaces):
+ self._cls = cls
+ self._implements = implementedBy(cls)
+ self.__args = (cls, metacls, ) + interfaces
+ Declaration.__init__(self, *(interfaces + (implementedBy(metacls), )))
+
+ def __reduce__(self):
+ return self.__class__, self.__args
+
+ # Copy base-class method for speed
+ __get__ = ClassProvidesBase.__get__
+
+def directlyProvidedBy(object):
+ """Return the interfaces directly provided by the given object
+
+ The value returned is an ``IDeclaration``.
+ """
+ provides = getattr(object, "__provides__", None)
+ if (provides is None # no spec
+ or
+ # We might have gotten the implements spec, as an
+ # optimization. If so, it's like having only one base, that we
+ # lop off to exclude class-supplied declarations:
+ isinstance(provides, Implements)
+ ):
+ return _empty
+
+ # Strip off the class part of the spec:
+ return Declaration(provides.__bases__[:-1])
+
+def classProvides(*interfaces):
+ """Declare interfaces provided directly by a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface specifications
+ (``IDeclaration`` objects).
+
+ The given interfaces (including the interfaces in the specifications)
+ are used to create the class's direct-object interface specification.
+ An error will be raised if the module class has an direct interface
+ specification. In other words, it is an error to call this function more
+ than once in a class definition.
+
+ Note that the given interfaces have nothing to do with the interfaces
+ implemented by instances of the class.
+
+ This function is provided for convenience. It provides a more convenient
+ way to call directlyProvidedByProvides for a class. For example::
+
+ classProvides(I1)
+
+ is equivalent to calling::
+
+ directlyProvides(theclass, I1)
+
+ after the class has been created.
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface): pass
+ ...
+ >>> class IFooFactory(Interface): pass
+ ...
+ >>> class C(object):
+ ... implements(IFoo)
+ ... classProvides(IFooFactory)
+ >>> [i.getName() for i in C.__providedBy__]
+ ['IFooFactory']
+ >>> [i.getName() for i in C().__providedBy__]
+ ['IFoo']
+
+ if equivalent to:
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface): pass
+ ...
+ >>> class IFooFactory(Interface): pass
+ ...
+ >>> class C(object):
+ ... implements(IFoo)
+ >>> directlyProvides(C, IFooFactory)
+ >>> [i.getName() for i in C.__providedBy__]
+ ['IFooFactory']
+ >>> [i.getName() for i in C().__providedBy__]
+ ['IFoo']
+
+ If classProvides is called outside of a class definition, it fails.
+
+ >>> classProvides(IFooFactory)
+ Traceback (most recent call last):
+ ...
+ TypeError: classProvides can be used only from a class definition.
+
+ """
+ frame = sys._getframe(1)
+ locals = frame.f_locals
+
+ # Try to make sure we were called from a class def
+ if (locals is frame.f_globals) or ('__module__' not in locals):
+ raise TypeError("classProvides can be used only from a class definition.")
+
+ if '__provides__' in locals:
+ raise TypeError(
+ "classProvides can only be used once in a class definition.")
+
+ locals["__provides__"] = _normalizeargs(interfaces)
+
+ addClassAdvisor(_classProvides_advice, depth=2)
+
+def _classProvides_advice(cls):
+ interfaces = cls.__dict__['__provides__']
+ del cls.__provides__
+ directlyProvides(cls, *interfaces)
+ return cls
+
+def moduleProvides(*interfaces):
+ """Declare interfaces provided by a module
+
+ This function is used in a module definition.
+
+ The arguments are one or more interfaces or interface specifications
+ (``IDeclaration`` objects).
+
+ The given interfaces (including the interfaces in the specifications) are
+ used to create the module's direct-object interface specification. An
+ error will be raised if the module already has an interface specification.
+ In other words, it is an error to call this function more than once in a
+ module definition.
+
+ This function is provided for convenience. It provides a more convenient
+ way to call directlyProvides. For example::
+
+ moduleImplements(I1)
+
+ is equivalent to::
+
+ directlyProvides(sys.modules[__name__], I1)
+ """
+ frame = sys._getframe(1)
+ locals = frame.f_locals
+
+ # Try to make sure we were called from a class def
+ if (locals is not frame.f_globals) or ('__name__' not in locals):
+ raise TypeError(
+ "moduleProvides can only be used from a module definition.")
+
+ if '__provides__' in locals:
+ raise TypeError(
+ "moduleProvides can only be used once in a module definition.")
+
+ module = sys.modules[__name__]
+
+ locals["__provides__"] = Provides(type(module),
+ *_normalizeargs(interfaces))
+
+##############################################################################
+#
+# Declaration querying support
+
+def ObjectSpecification(direct, cls):
+ """Provide object specifications
+
+ These combine information for the object and for it's classes.
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I31(I3): pass
+ ...
+ >>> class I4(Interface): pass
+ ...
+ >>> class I5(Interface): pass
+ ...
+ >>> class A(object): implements(I1)
+ ...
+ >>> class B(object): __implemented__ = I2
+ ...
+ >>> class C(A, B): implements(I31)
+ ...
+ >>> c = C()
+ >>> directlyProvides(c, I4)
+ >>> [i.getName() for i in providedBy(c)]
+ ['I4', 'I31', 'I1', 'I2']
+ >>> [i.getName() for i in providedBy(c).flattened()]
+ ['I4', 'I31', 'I3', 'I1', 'I2', 'Interface']
+ >>> int(I1 in providedBy(c))
+ 1
+ >>> int(I3 in providedBy(c))
+ 0
+ >>> int(providedBy(c).extends(I3))
+ 1
+ >>> int(providedBy(c).extends(I31))
+ 1
+ >>> int(providedBy(c).extends(I5))
+ 0
+ >>> class COnly(A, B): implementsOnly(I31)
+ ...
+ >>> class D(COnly): implements(I5)
+ ...
+ >>> c = D()
+ >>> directlyProvides(c, I4)
+ >>> [i.getName() for i in providedBy(c)]
+ ['I4', 'I5', 'I31']
+ >>> [i.getName() for i in providedBy(c).flattened()]
+ ['I4', 'I5', 'I31', 'I3', 'Interface']
+ >>> int(I1 in providedBy(c))
+ 0
+ >>> int(I3 in providedBy(c))
+ 0
+ >>> int(providedBy(c).extends(I3))
+ 1
+ >>> int(providedBy(c).extends(I1))
+ 0
+ >>> int(providedBy(c).extends(I31))
+ 1
+ >>> int(providedBy(c).extends(I5))
+ 1
+ """
+
+ return Provides(cls, direct)
+
+def getObjectSpecification(ob):
+
+ provides = getattr(ob, '__provides__', None)
+ if provides is not None:
+ return provides
+
+ try:
+ cls = ob.__class__
+ except AttributeError:
+ # We can't get the class, so just consider provides
+ return _empty
+
+ return implementedBy(cls)
+
+def providedBy(ob):
+
+ # Here we have either a special object, an old-style declaration
+ # or a descriptor
+
+ # Try to get __providedBy__
+ try:
+ r = ob.__providedBy__
+ except AttributeError:
+ # Not set yet. Fall back to lower-level thing that computes it
+ return getObjectSpecification(ob)
+
+ try:
+ # We might have gotten a descriptor from an instance of a
+ # class (like an ExtensionClass) that doesn't support
+ # descriptors. We'll make sure we got one by trying to get
+ # the only attribute, which all specs have.
+ r.extends
+
+ except AttributeError:
+
+ # The object's class doesn't understand descriptors.
+ # Sigh. We need to get an object descriptor, but we have to be
+ # careful. We want to use the instance's __provides__, if
+ # there is one, but only if it didn't come from the class.
+
+ try:
+ r = ob.__provides__
+ except AttributeError:
+ # No __provides__, so just fall back to implementedBy
+ return implementedBy(ob.__class__)
+
+ # We need to make sure we got the __provides__ from the
+ # instance. We'll do this by making sure we don't get the same
+ # thing from the class:
+
+ try:
+ cp = ob.__class__.__provides__
+ except AttributeError:
+ # The ob doesn't have a class or the class has no
+ # provides, assume we're done:
+ return r
+
+ if r is cp:
+ # Oops, we got the provides from the class. This means
+ # the object doesn't have it's own. We should use implementedBy
+ return implementedBy(ob.__class__)
+
+ return r
+
+class ObjectSpecificationDescriptorPy(object):
+ """Implement the `__providedBy__` attribute
+
+ The `__providedBy__` attribute computes the interfaces peovided by
+ an object.
+ """
+
+ def __get__(self, inst, cls):
+ """Get an object specification for an object
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface): pass
+ ...
+ >>> class IFooFactory(Interface): pass
+ ...
+ >>> class C(object):
+ ... implements(IFoo)
+ ... classProvides(IFooFactory)
+ >>> [i.getName() for i in C.__providedBy__]
+ ['IFooFactory']
+ >>> [i.getName() for i in C().__providedBy__]
+ ['IFoo']
+
+ """
+
+ # Get an ObjectSpecification bound to either an instance or a class,
+ # depending on how we were accessed.
+
+ if inst is None:
+ return getObjectSpecification(cls)
+
+ provides = getattr(inst, '__provides__', None)
+ if provides is not None:
+ return provides
+
+ return implementedBy(cls)
+
+ObjectSpecificationDescriptor = ObjectSpecificationDescriptorPy
+
+##############################################################################
+
+def _normalizeargs(sequence, output = None):
+ """Normalize declaration arguments
+
+ Normalization arguments might contain Declarions, tuples, or single
+ interfaces.
+
+ Anything but individial interfaces or implements specs will be expanded.
+ """
+ if output is None:
+ output = []
+
+ cls = sequence.__class__
+ if InterfaceClass in cls.__mro__ or Implements in cls.__mro__:
+ output.append(sequence)
+ else:
+ for v in sequence:
+ _normalizeargs(v, output)
+
+ return output
+
+_empty = Declaration()
+
+try:
+ import _zope_interface_coptimizations
+except ImportError:
+ pass
+else:
+ from _zope_interface_coptimizations import implementedBy, providedBy
+ from _zope_interface_coptimizations import getObjectSpecification
+ from _zope_interface_coptimizations import ObjectSpecificationDescriptor
+
+objectSpecificationDescriptor = ObjectSpecificationDescriptor()
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/document.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/document.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/document.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,107 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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.
+
+$Id: document.py 39768 2005-10-31 13:57:35Z tlotze $
+"""
+import zope.interface
+
+def asStructuredText(I, munge=0):
+ """ Output structured text format. Note, this will whack any existing
+ 'structured' format of the text. """
+
+ r = [I.getName()]
+ outp = r.append
+ level = 1
+
+ if I.getDoc():
+ outp(_justify_and_indent(_trim_doc_string(I.getDoc()), level))
+
+ bases = [base
+ for base in I.__bases__
+ if base is not zope.interface.Interface
+ ]
+ if bases:
+ outp(_justify_and_indent("This interface extends:", level, munge))
+ level += 1
+ for b in bases:
+ item = "o %s" % b.getName()
+ outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+ level -= 1
+
+ namesAndDescriptions = I.namesAndDescriptions()
+ namesAndDescriptions.sort()
+
+ outp(_justify_and_indent("Attributes:", level, munge))
+ level += 1
+ for name, desc in namesAndDescriptions:
+ if not hasattr(desc, 'getSignatureString'): # ugh...
+ item = "%s -- %s" % (desc.getName(),
+ desc.getDoc() or 'no documentation')
+ outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+ level -= 1
+
+ outp(_justify_and_indent("Methods:", level, munge))
+ level += 1
+ for name, desc in namesAndDescriptions:
+ if hasattr(desc, 'getSignatureString'): # ugh...
+ item = "%s%s -- %s" % (desc.getName(),
+ desc.getSignatureString(),
+ desc.getDoc() or 'no documentation')
+ outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+
+ return "\n\n".join(r) + "\n\n"
+
+
+def _trim_doc_string(text):
+ """ Trims a doc string to make it format
+ correctly with structured text. """
+
+ lines = text.replace('\r\n', '\n').split('\n')
+ nlines = [lines.pop(0)]
+ if lines:
+ min_indent = min([len(line) - len(line.lstrip())
+ for line in lines])
+ for line in lines:
+ nlines.append(line[min_indent:])
+
+ return '\n'.join(nlines)
+
+
+def _justify_and_indent(text, level, munge=0, width=72):
+ """ indent and justify text, rejustify (munge) if specified """
+
+ indent = " " * level
+
+ if munge:
+ lines = []
+ line = indent
+ text = text.split()
+
+ for word in text:
+ line = ' '.join([line, word])
+ if len(line) > width:
+ lines.append(line)
+ line = indent
+ else:
+ lines.append(line)
+
+ return '\n'.join(lines)
+
+ else:
+ return indent + \
+ text.strip().replace("\r\n", "\n") .replace("\n", "\n" + indent)
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/document.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/exceptions.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/exceptions.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/exceptions.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,69 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation 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
+
+$Id: exceptions.py 67174 2006-04-20 14:11:55Z flindner $
+"""
+
+class Invalid(Exception):
+ """A specification is violated
+ """
+
+class DoesNotImplement(Invalid):
+ """ This object does not implement """
+ def __init__(self, interface):
+ self.interface = interface
+
+ def __str__(self):
+ return """An object does not implement interface %(interface)s
+
+ """ % self.__dict__
+
+class BrokenImplementation(Invalid):
+ """An attribute is not completely implemented.
+ """
+
+ def __init__(self, interface, name):
+ self.interface=interface
+ self.name=name
+
+ def __str__(self):
+ return """An object has failed to implement interface %(interface)s
+
+ The %(name)s attribute was not provided.
+ """ % self.__dict__
+
+class BrokenMethodImplementation(Invalid):
+ """An method is not completely implemented.
+ """
+
+ def __init__(self, method, mess):
+ self.method=method
+ self.mess=mess
+
+ def __str__(self):
+ return """The implementation of %(method)s violates its contract
+ because %(mess)s.
+ """ % self.__dict__
+
+class InvalidInterface(Exception):
+ """The interface has invalid contents
+ """
+
+class BadImplements(TypeError):
+ """An implementation assertion is invalid
+
+ because it doesn't contain an interface or a sequence of valid
+ implementation assertions.
+ """
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/exceptions.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/human.ru.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/human.ru.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/human.ru.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,154 @@
+===============================
+Использование реестра адаптеров
+===============================
+
+Данный документ содержит небольшую демонстрацию пакета ``zope.interface`` и его
+реестра адаптеров. Документ рассчитывался как конкретный, но более узкий пример
+того как использовать интерфейсы и адаптеры вне Zope 3.
+
+Сначала нам необходимо импортировать пакет для работы с интерфейсами.
+
+ >>> import zope.interface
+
+Теперь мы разработаем интерфейс для нашего объекта - простого файла. Наш файл
+будет содержать всего один атрибут - body, в котором фактически будет сохранено
+содержимое файла.
+
+ >>> class IFile(zope.interface.Interface):
+ ...
+ ... body = zope.interface.Attribute(u'Содержимое файла.')
+ ...
+
+Для статистики нам часто необходимо знать размер файла. Но было бы несколько
+топорно релизовывать определение размера прямо для объекта файла, т.к. размер
+больше относится к мета-данным. Таким образом мы создаем еще один интерфейс для
+представления размера какого-либо объекта.
+
+ >>> class ISize(zope.interface.Interface):
+ ...
+ ... def getSize():
+ ... 'Return the size of an object.'
+ ...
+
+Теперь мы должны создать класс реализующий наш файл. Необходимо что бы наш
+объект хранил информацию о том, что он реализует интерфейс `IFile`. Мы также
+создаем атрибут с содержимым файла по умолчанию (для упрощения нашего примера).
+
+ >>> class File(object):
+ ...
+ ... zope.interface.implements(IFile)
+ ... body = 'foo bar'
+ ...
+
+Дальше мы создаем адаптер, который будет предоставлять интерфейс `ISize`
+получая любой объект предоставляющий интерфейс `IFile`. По соглашению мы
+используем атрибут `__used_for__` для указания интерфейса который как мы
+ожидаем предоставляет адаптируемый объект, `IFile` в нашем случае. На самом
+деле этот атрибут используется только для документирования. В случае если
+адаптер используется для нескольких интерфейсов можно указать их все в виде
+кортежа.
+
+Опять же по соглашению конструктор адаптера получает один аргумент - context
+(контекст). В нашем случае контекст - это экземпляр `IFile` (объект,
+предоставляющий `IFile`) который используется для получения из него размера.
+Так же по соглашению контекст сохраняется а адаптере в атрибуте с именем
+`context`. Twisted комьюнити ссылается на контекст как на объект `original`.
+Таким образом можно также дать аргументу любое подходящее имя, например `file`.
+
+ >>> class FileSize(object):
+ ...
+ ... zope.interface.implements(ISize)
+ ... __used_for__ = IFile
+ ...
+ ... def __init__(self, context):
+ ... self.context = context
+ ...
+ ... def getSize(self):
+ ... return len(self.context.body)
+ ...
+
+Теперь когда мы написали наш адаптер мы должны зарегистрировать его в реестре
+адаптеров, что бы его можно было запросить когда он понадобится. Здесь нет
+какого-либо глобального реестра адаптеров, таким образом мы должны
+самостоятельно создать для нашего примера реестр.
+
+ >>> from zope.interface.adapter import AdapterRegistry
+ >>> registry = AdapterRegistry()
+
+Реестр содержит отображение того, что адаптер реализует на основе другого
+интерфейса который предоставляет объект. Поэтому дальше мы регистрируем адаптер
+который адаптирует интерфейс `IFile` к интерфейсу `ISize`. Первый аргумент к
+методу `register()` реестра - это список адаптируемых интерфейсов. В нашем
+случае мы имеем только один адаптируемый интерфейс - `IFile`. Список
+интерфейсов имеет смысл для использования концепции мульти-адаптеров, которые
+требуют нескольких оригинальных объектов для адаптации к новому интерфейсу. В
+этой ситуации конструктор адаптера будет требовать новый аргумент для каждого
+оригинального интерфейса.
+
+Второй аргумент метода `register()` - это интерфейс который предоставляет
+адаптер, в нашем случае `ISize`. Третий аргумент - имя адаптера. Сейчас нам не
+важно имя адаптера и мы передаем его как пустую строку. Обычно имена полезны
+если используются адаптеры для одинакового набора интерфейсов, но в различных
+ситуациях. Последний аргумент - это класс адаптера.
+
+ >>> registry.register([IFile], ISize, '', FileSize)
+
+Теперь мы можем использовать реестр для запроса адаптера.
+
+ >>> registry.lookup1(IFile, ISize, '')
+ <class '__main__.FileSize'>
+
+Попробуем более практичный пример. Создадим экземпляр `File` и создадим адаптер
+использующий запрос реестра. Затем мы увидим возвращает ли адаптер корректный
+размер при вызове `getSize()`.
+
+ >>> file = File()
+ >>> size = registry.lookup1(IFile, ISize, '')(file)
+ >>> size.getSize()
+ 7
+
+На самом деле это не очень практично, т.к. нам нужно самим передавать все
+аргументы методу запроса. Существует некоторый "синтаксический лединец" который
+позволяет нам получить экземпляр адаптера просто вызвав `ISize(file)`. Что бы
+использовать эту функциональность нам понадобится добавить наш реестр к списку
+adapter_hooks, который находится в модуле с адаптерами. Этот список хранит
+коллекцию вызываемых объектов которые вызываются автоматически когда вызывается
+IFoo(obj); их предназначение - найти адаптеры которые реализуют интерфейс
+для определенного экземпляра контекста.
+
+Необходимо реализовать свою собственную функцию для поиска адаптера; данный
+пример описывает одну из простейших функций для использования с реестром, но
+также можно реализовать поисковые функции которые, например, используют
+кэширование, или адаптеры сохраняемые в базе. Функция поиска должна принимать
+желаемый на выходе интерфейс (в нашем случае `ISize`) как первый аргумент и
+контекст для адаптации (`file`) как второй. Функция должна вернуть адаптер,
+т.е. экзмепляр `FileSize`.
+
+ >>> def hook(provided, object):
+ ... adapter = registry.lookup1(zope.interface.providedBy(object),
+ ... provided, '')
+ ... return adapter(object)
+ ...
+
+Теперь мы просто добавляем нашу функцию к списку `adapter_hooks`.
+
+ >>> from zope.interface.interface import adapter_hooks
+ >>> adapter_hooks.append(hook)
+
+Как только функция зарегистрирована мы можем использовать желаемый синтаксис.
+
+ >>> size = ISize(file)
+ >>> size.getSize()
+ 7
+
+После нам нужно прибраться за собой, что бы другие получили чистый список
+`adaper_hooks` после нас.
+
+ >>> adapter_hooks.remove(hook)
+
+Это все. Здесь намеренно отложена дискуссия об именованных и мульти-адаптерах,
+т.к. данный текст рассчитан как практическое и простое введение в интерфейсы и
+адаптеры Zope 3. Для более подробной информации имеет смысл прочитать
+`adapter.txt` из пакета `zope.interface`, что бы получить более формальное,
+справочное и полное трактование пакета. Внимание: многие жаловались, что
+`adapter.txt` приводит их мозг к расплавленному состоянию!
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/human.ru.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/human.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/human.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/human.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,152 @@
+==========================
+Using the Adapter Registry
+==========================
+
+This is a small demonstration of the ``zope.interface`` package including its
+adapter registry. It is intended to provide a concrete but narrow example on
+how to use interfaces and adapters outside of Zope 3.
+
+First we have to import the interface package.
+
+ >>> import zope.interface
+
+We now develop an interface for our object, which is a simple file in this
+case. For now we simply support one attribute, the body, which contains the
+actual file contents.
+
+ >>> class IFile(zope.interface.Interface):
+ ...
+ ... body = zope.interface.Attribute('Contents of the file.')
+ ...
+
+For statistical reasons we often want to know the size of a file. However, it
+would be clumsy to implement the size directly in the file object, since the
+size really represents meta-data. Thus we create another interface that
+provides the size of something.
+
+ >>> class ISize(zope.interface.Interface):
+ ...
+ ... def getSize():
+ ... 'Return the size of an object.'
+ ...
+
+Now we need to implement the file. It is essential that the object states
+that it implements the `IFile` interface. We also provide a default body
+value (just to make things simpler for this example).
+
+ >>> class File(object):
+ ...
+ ... zope.interface.implements(IFile)
+ ... body = 'foo bar'
+ ...
+
+Next we implement an adapter that can provide the `ISize` interface given any
+object providing `IFile`. By convention we use `__used_for__` to specify the
+interface that we expect the adapted object to provide, in our case
+`IFile`. However, this attribute is not used for anything. If you have
+multiple interfaces for which an adapter is used, just specify the interfaces
+via a tuple.
+
+Again by convention, the constructor of an adapter takes one argument, the
+context. The context in this case is an instance of `File` (providing `IFile`)
+that is used to extract the size from. Also by convention the context is
+stored in an attribute named `context` on the adapter. The twisted community
+refers to the context as the `original` object. However, you may feel free to
+use a specific argument name, such as `file`.
+
+ >>> class FileSize(object):
+ ...
+ ... zope.interface.implements(ISize)
+ ... __used_for__ = IFile
+ ...
+ ... def __init__(self, context):
+ ... self.context = context
+ ...
+ ... def getSize(self):
+ ... return len(self.context.body)
+ ...
+
+Now that we have written our adapter, we have to register it with an adapter
+registry, so that it can be looked up when needed. There is no such thing as a
+global registry; thus we have to instantiate one for our example manually.
+
+ >>> from zope.interface.adapter import AdapterRegistry
+ >>> registry = AdapterRegistry()
+
+
+The registry keeps a map of what adapters implement based on another
+interface, the object already provides. Therefore, we next have to register an
+adapter that adapts from `IFile` to `ISize`. The first argument to
+the registry's `register()` method is a list of original interfaces.In our
+cause we have only one original interface, `IFile`. A list makes sense, since
+the interface package has the concept of multi-adapters, which are adapters
+that require multiple objects to adapt to a new interface. In these
+situations, your adapter constructor will require an argument for each
+specified interface.
+
+The second argument is the interface the adapter provides, in our case
+`ISize`. The third argument is the name of the adapter. Since we do not care
+about names, we simply leave it as an empty string. Names are commonly useful,
+if you have adapters for the same set of interfaces, but they are useful in
+different situations. The last argument is simply the adapter class.
+
+ >>> registry.register([IFile], ISize, '', FileSize)
+
+You can now use the the registry to lookup the adapter.
+
+ >>> registry.lookup1(IFile, ISize, '')
+ <class '__main__.FileSize'>
+
+Let's get a little bit more practical. Let's create a `File` instance and
+create the adapter using a registry lookup. Then we see whether the adapter
+returns the correct size by calling `getSize()`.
+
+ >>> file = File()
+ >>> size = registry.lookup1(IFile, ISize, '')(file)
+ >>> size.getSize()
+ 7
+
+However, this is not very practical, since I have to manually pass in the
+arguments to the lookup method. There is some syntactic candy that will allow
+us to get an adapter instance by simply calling `ISize(file)`. To make use of
+this functionality, we need to add our registry to the adapter_hooks list,
+which is a member of the adapters module. This list stores a collection of
+callables that are automatically invoked when IFoo(obj) is called; their
+purpose is to locate adapters that implement an interface for a certain
+context instance.
+
+You are required to implement your own adapter hook; this example covers one
+of the simplest hooks that use the registry, but you could implement one that
+used an adapter cache or persistent adapters, for instance. The helper hook is
+required to expect as first argument the desired output interface (for us
+`ISize`) and as the second argument the context of the adapter (here
+`file`). The function returns an adapter, i.e. a `FileSize` instance.
+
+ >>> def hook(provided, object):
+ ... adapter = registry.lookup1(zope.interface.providedBy(object),
+ ... provided, '')
+ ... return adapter(object)
+ ...
+
+We now just add the hook to an `adapter_hooks` list.
+
+ >>> from zope.interface.interface import adapter_hooks
+ >>> adapter_hooks.append(hook)
+
+Once the hook is registered, you can use the desired syntax.
+
+ >>> size = ISize(file)
+ >>> size.getSize()
+ 7
+
+Now we have to cleanup after ourselves, so that others after us have a clean
+`adapter_hooks` list.
+
+ >>> adapter_hooks.remove(hook)
+
+That's it. I have intentionally left out a discussion of named adapters and
+multi-adapters, since this text is intended as a practical and simple
+introduction to Zope 3 interfaces and adapters. You might want to read the
+`adapter.txt` in the `zope.interface` package for a more formal, referencial
+and complete treatment of the package. Warning: People have reported that
+`adapter.txt` makes their brain feel soft!
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/human.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/interface.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/interface.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/interface.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,821 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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
+
+$Id: interface.py 67761 2006-04-30 13:56:44Z jim $
+"""
+
+from __future__ import generators
+
+import sys
+import warnings
+import weakref
+from types import FunctionType
+from ro import ro
+from zope.interface.exceptions import Invalid
+
+CO_VARARGS = 4
+CO_VARKEYWORDS = 8
+TAGGED_DATA = '__interface_tagged_values__'
+
+_decorator_non_return = object()
+
+def invariant(call):
+ f_locals = sys._getframe(1).f_locals
+ tags = f_locals.setdefault(TAGGED_DATA, {})
+ invariants = tags.setdefault('invariants', [])
+ invariants.append(call)
+ return _decorator_non_return
+
+class Element(object):
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ #implements(IElement)
+
+ def __init__(self, __name__, __doc__=''):
+ """Create an 'attribute' description
+ """
+ if not __doc__ and __name__.find(' ') >= 0:
+ __doc__ = __name__
+ __name__ = None
+
+ self.__name__=__name__
+ self.__doc__=__doc__
+ self.__tagged_values = {}
+
+ def getName(self):
+ """ Returns the name of the object. """
+ return self.__name__
+
+ def getDoc(self):
+ """ Returns the documentation for the object. """
+ return self.__doc__
+
+ def getTaggedValue(self, tag):
+ """ Returns the value associated with 'tag'. """
+ return self.__tagged_values[tag]
+
+ def queryTaggedValue(self, tag, default=None):
+ """ Returns the value associated with 'tag'. """
+ return self.__tagged_values.get(tag, default)
+
+ def getTaggedValueTags(self):
+ """ Returns a list of all tags. """
+ return self.__tagged_values.keys()
+
+ def setTaggedValue(self, tag, value):
+ """ Associates 'value' with 'key'. """
+ self.__tagged_values[tag] = value
+
+class SpecificationBasePy(object):
+
+ def providedBy(self, ob):
+ """Is the interface implemented by an object
+
+ >>> from zope.interface import *
+ >>> class I1(Interface):
+ ... pass
+ >>> class C(object):
+ ... implements(I1)
+ >>> c = C()
+ >>> class X(object):
+ ... pass
+ >>> x = X()
+ >>> I1.providedBy(x)
+ False
+ >>> I1.providedBy(C)
+ False
+ >>> I1.providedBy(c)
+ True
+ >>> directlyProvides(x, I1)
+ >>> I1.providedBy(x)
+ True
+ >>> directlyProvides(C, I1)
+ >>> I1.providedBy(C)
+ True
+
+ """
+ spec = providedBy(ob)
+ return self in spec._implied
+
+ def implementedBy(self, cls):
+ """Test whether the specification is implemented by a class or factory.
+ Raise TypeError if argument is neither a class nor a callable."""
+ spec = implementedBy(cls)
+ return self in spec._implied
+
+ def isOrExtends(self, interface):
+ """Is the interface the same as or extend the given interface
+
+ Examples::
+
+ >>> from zope.interface import Interface
+ >>> from zope.interface.declarations import Declaration
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration()
+ >>> int(spec.extends(Interface))
+ 1
+ >>> spec = Declaration(I2)
+ >>> int(spec.extends(Interface))
+ 1
+ >>> int(spec.extends(I1))
+ 1
+ >>> int(spec.extends(I2))
+ 1
+ >>> int(spec.extends(I3))
+ 0
+ >>> int(spec.extends(I4))
+ 0
+
+ """
+ return interface in self._implied
+
+ __call__ = isOrExtends
+
+SpecificationBase = SpecificationBasePy
+
+_marker = object()
+class InterfaceBasePy(object):
+ """Base class that wants to be replaced with a C base :)
+ """
+
+ def __call__(self, obj, alternate=_marker):
+ """Adapt an object to the interface
+ """
+ conform = getattr(obj, '__conform__', None)
+ if conform is not None:
+ adapter = self._call_conform(conform)
+ if adapter is not None:
+ return adapter
+
+ adapter = self.__adapt__(obj)
+
+ if adapter is not None:
+ return adapter
+ elif alternate is not _marker:
+ return alternate
+ else:
+ raise TypeError("Could not adapt", obj, self)
+
+ def __adapt__(self, obj):
+ """Adapt an object to the reciever
+ """
+ if self.providedBy(obj):
+ return obj
+
+ for hook in adapter_hooks:
+ adapter = hook(self, obj)
+ if adapter is not None:
+ return adapter
+
+InterfaceBase = InterfaceBasePy
+
+adapter_hooks = []
+
+try:
+ import _zope_interface_coptimizations
+except ImportError:
+ pass
+else:
+ from _zope_interface_coptimizations import SpecificationBase
+ from _zope_interface_coptimizations import InterfaceBase, 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 cases, their
+ relations with other specifications are adjusted accordingly.
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface):
+ ... pass
+ >>> class I2(I1):
+ ... pass
+ >>> class I3(I2):
+ ... pass
+
+ >>> [i.__name__ for i in I1.__bases__]
+ ['Interface']
+
+ >>> [i.__name__ for i in I2.__bases__]
+ ['I1']
+
+ >>> I3.extends(I1)
+ 1
+
+ >>> I2.__bases__ = (Interface, )
+
+ >>> [i.__name__ for i in I2.__bases__]
+ ['Interface']
+
+ >>> I3.extends(I1)
+ 0
+
+ """
+
+ # Copy some base class methods for speed
+ isOrExtends = SpecificationBase.isOrExtends
+ providedBy = SpecificationBase.providedBy
+
+ #########################################################################
+ # BBB 2004-07-13: Backward compatabilty. These methods have been
+ # deprecated in favour of providedBy and implementedBy.
+
+ def isImplementedByInstancesOf(self, cls):
+ warnings.warn(
+ "isImplementedByInstancesOf has been renamed to implementedBy",
+ DeprecationWarning, stacklevel=2,
+ )
+ return self.implementedBy(cls)
+
+ def isImplementedBy(self, ob):
+ warnings.warn(
+ "isImplementedBy has been renamed to providedBy",
+ DeprecationWarning, stacklevel=2,
+ )
+ return self.providedBy(ob)
+ #
+ #########################################################################
+
+ def __init__(self, bases=()):
+ self._implied = {}
+ self.dependents = weakref.WeakKeyDictionary()
+ self.__bases__ = tuple(bases)
+
+ def subscribe(self, dependent):
+ self.dependents[dependent] = self.dependents.get(dependent, 0) + 1
+
+ def unsubscribe(self, dependent):
+ n = self.dependents.get(dependent, 0) - 1
+ if not n:
+ del self.dependents[dependent]
+ elif n > 0:
+ self.dependents[dependent] = n
+ else:
+ raise KeyError(dependent)
+
+ def __setBases(self, bases):
+ # Register ourselves as a dependent of our old bases
+ for b in self.__bases__:
+ b.unsubscribe(self)
+
+ # Register ourselves as a dependent of our bases
+ self.__dict__['__bases__'] = bases
+ for b in bases:
+ b.subscribe(self)
+
+ self.changed(self)
+
+ __bases__ = property(
+
+ lambda self: self.__dict__.get('__bases__', ()),
+ __setBases,
+ )
+
+ def changed(self, originally_changed):
+ """We, or something we depend on, have changed
+ """
+
+ implied = self._implied
+ implied.clear()
+
+ ancestors = ro(self)
+
+ try:
+ if Interface not in ancestors:
+ ancestors.append(Interface)
+ except NameError:
+ pass # defining Interface itself
+
+ self.__sro__ = tuple(ancestors)
+ self.__iro__ = tuple([ancestor for ancestor in ancestors
+ if isinstance(ancestor, InterfaceClass)
+ ])
+
+ for ancestor in ancestors:
+ # We directly imply our ancestors:
+ implied[ancestor] = ()
+
+ # Now, advise our dependents of change:
+ for dependent in self.dependents.keys():
+ dependent.changed(originally_changed)
+
+
+ def interfaces(self):
+ """Return an iterator for the interfaces in the specification
+
+ for example::
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Specification((I2, I3))
+ >>> spec = Specification((I4, spec))
+ >>> i = spec.interfaces()
+ >>> i.next().getName()
+ 'I4'
+ >>> i.next().getName()
+ 'I2'
+ >>> i.next().getName()
+ 'I3'
+ >>> list(i)
+ []
+ """
+ seen = {}
+ for base in self.__bases__:
+ for interface in base.interfaces():
+ if interface not in seen:
+ seen[interface] = 1
+ yield interface
+
+
+ def extends(self, interface, strict=True):
+ """Does the specification extend the given interface?
+
+ Test whether an interface in the specification extends the
+ given interface
+
+ Examples::
+
+ >>> from zope.interface import Interface
+ >>> from zope.interface.declarations import Declaration
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration()
+ >>> int(spec.extends(Interface))
+ 1
+ >>> spec = Declaration(I2)
+ >>> int(spec.extends(Interface))
+ 1
+ >>> int(spec.extends(I1))
+ 1
+ >>> int(spec.extends(I2))
+ 1
+ >>> int(spec.extends(I3))
+ 0
+ >>> int(spec.extends(I4))
+ 0
+ >>> I2.extends(I2)
+ 0
+ >>> I2.extends(I2, False)
+ 1
+ >>> I2.extends(I2, strict=False)
+ 1
+
+ """
+ return ((interface in self._implied)
+ and
+ ((not strict) or (self != interface))
+ )
+
+ def weakref(self, callback=None):
+ return weakref.ref(self, callback)
+
+ def get(self, name, default=None):
+ """Query for an attribute description
+ """
+ try:
+ attrs = self._v_attrs
+ except AttributeError:
+ attrs = self._v_attrs = {}
+ attr = attrs.get(name)
+ if attr is None:
+ for iface in self.__iro__:
+ attr = iface.direct(name)
+ if attr is not None:
+ attrs[name] = attr
+ break
+
+ if attr is None:
+ return default
+ else:
+ return attr
+
+class InterfaceClass(Element, InterfaceBase, Specification):
+ """Prototype (scarecrow) Interfaces Implementation."""
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ #implements(IInterface)
+
+ def __init__(self, name, bases=(), attrs=None, __doc__=None,
+ __module__=None):
+
+ if attrs is None:
+ attrs = {}
+
+ if __module__ is None:
+ __module__ = attrs.get('__module__')
+ if isinstance(__module__, str):
+ del attrs['__module__']
+ else:
+ try:
+ # Figure out what module defined the interface.
+ # This is how cPython figures out the module of
+ # a class, but of course it does it in C. :-/
+ __module__ = sys._getframe(1).f_globals['__name__']
+ except (AttributeError, KeyError):
+ pass
+
+ self.__module__ = __module__
+
+ d = attrs.get('__doc__')
+ if d is not None:
+ if not isinstance(d, Attribute):
+ if __doc__ is None:
+ __doc__ = d
+ del attrs['__doc__']
+
+ if __doc__ is None:
+ __doc__ = ''
+
+ Element.__init__(self, name, __doc__)
+
+ tagged_data = attrs.pop(TAGGED_DATA, None)
+ if tagged_data is not None:
+ for key, val in tagged_data.items():
+ self.setTaggedValue(key, val)
+
+ for base in bases:
+ if not isinstance(base, InterfaceClass):
+ raise TypeError('Expected base interfaces')
+
+ Specification.__init__(self, bases)
+
+ # Make sure that all recorded attributes (and methods) are of type
+ # `Attribute` and `Method`
+ for name, attr in attrs.items():
+ if isinstance(attr, Attribute):
+ attr.interface = self
+ if not attr.__name__:
+ attr.__name__ = name
+ elif isinstance(attr, FunctionType):
+ attrs[name] = fromFunction(attr, self, name=name)
+ elif attr is _decorator_non_return:
+ del attrs[name]
+ else:
+ raise InvalidInterface("Concrete attribute, " + name)
+
+ self.__attrs = attrs
+
+ self.__identifier__ = "%s.%s" % (self.__module__, self.__name__)
+
+ def interfaces(self):
+ """Return an iterator for the interfaces in the specification
+
+ for example::
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>>
+ >>> i = I1.interfaces()
+ >>> i.next().getName()
+ 'I1'
+ >>> list(i)
+ []
+ """
+ yield self
+
+ def getBases(self):
+ return self.__bases__
+
+ def isEqualOrExtendedBy(self, other):
+ """Same interface or extends?"""
+ return self == other or other.extends(self)
+
+ def names(self, all=False):
+ """Return the attribute names defined by the interface."""
+ if not all:
+ return self.__attrs.keys()
+
+ r = self.__attrs.copy()
+
+ for base in self.__bases__:
+ r.update(dict.fromkeys(base.names(all)))
+
+ return r.keys()
+
+ def __iter__(self):
+ return iter(self.names(all=True))
+
+ def namesAndDescriptions(self, all=False):
+ """Return attribute names and descriptions defined by interface."""
+ if not all:
+ return self.__attrs.items()
+
+ r = {}
+ for base in self.__bases__[::-1]:
+ r.update(dict(base.namesAndDescriptions(all)))
+
+ r.update(self.__attrs)
+
+ return r.items()
+
+ def getDescriptionFor(self, name):
+ """Return the attribute description for the given name."""
+ r = self.get(name)
+ if r is not None:
+ return r
+
+ raise KeyError(name)
+
+ __getitem__ = getDescriptionFor
+
+ def __contains__(self, name):
+ return self.get(name) is not None
+
+ def direct(self, name):
+ return self.__attrs.get(name)
+
+ def queryDescriptionFor(self, name, default=None):
+ return self.get(name, default)
+
+ def deferred(self):
+ """Return a defered class corresponding to the interface."""
+ if hasattr(self, "_deferred"): return self._deferred
+
+ klass={}
+ exec "class %s: pass" % self.__name__ in klass
+ klass=klass[self.__name__]
+
+ self.__d(klass.__dict__)
+
+ self._deferred=klass
+
+ return klass
+
+ def validateInvariants(self, obj, errors=None):
+ """validate object to defined invariants."""
+ for call in self.queryTaggedValue('invariants', []):
+ try:
+ call(obj)
+ except Invalid, e:
+ if errors is None:
+ raise
+ else:
+ errors.append(e)
+ for base in self.__bases__:
+ try:
+ base.validateInvariants(obj, errors)
+ except Invalid:
+ if errors is None:
+ raise
+ if errors:
+ raise Invalid(errors)
+
+ def _getInterface(self, ob, name):
+ """Retrieve a named interface."""
+ return None
+
+ def __d(self, dict):
+
+ for k, v in self.__attrs.items():
+ if isinstance(v, Method) and not (k in dict):
+ dict[k]=v
+
+ for b in self.__bases__:
+ b.__d(dict)
+
+ def __repr__(self):
+ try:
+ return self._v_repr
+ except AttributeError:
+ name = self.__name__
+ m = self.__module__
+ if m:
+ name = '%s.%s' % (m, name)
+ r = "<%s %s>" % (self.__class__.__name__, name)
+ self._v_repr = r
+ return r
+
+ def _call_conform(self, conform):
+ try:
+ return conform(self)
+ except TypeError:
+ # We got a TypeError. It might be an error raised by
+ # the __conform__ implementation, or *we* may have
+ # made the TypeError by calling an unbound method
+ # (object is a class). In the later case, we behave
+ # as though there is no __conform__ method. We can
+ # detect this case by checking whether there is more
+ # than one traceback object in the traceback chain:
+ if sys.exc_info()[2].tb_next is not None:
+ # There is more than one entry in the chain, so
+ # reraise the error:
+ raise
+ # This clever trick is from Phillip Eby
+
+ return None
+
+ def __reduce__(self):
+ return self.__name__
+
+ def __cmp(self, o1, o2):
+ # Yes, I did mean to name this __cmp, rather than __cmp__.
+ # It is a private method used by __lt__ and __gt__.
+ # I don't want to override __eq__ because I want the default
+ # __eq__, which is really fast.
+ """Make interfaces sortable
+
+ TODO: It would ne nice if:
+
+ More specific interfaces should sort before less specific ones.
+ Otherwise, sort on name and module.
+
+ But this is too complicated, and we're going to punt on it
+ for now.
+
+ For now, sort on interface and module name.
+
+ None is treated as a pseudo interface that implies the loosest
+ contact possible, no contract. For that reason, all interfaces
+ sort before None.
+
+ """
+ if o1 == o2:
+ return 0
+
+ if o1 is None:
+ return 1
+ if o2 is None:
+ return -1
+
+ n1 = (getattr(o1, '__name__', ''),
+ getattr(getattr(o1, '__module__', None), '__name__', ''))
+ n2 = (getattr(o2, '__name__', ''),
+ getattr(getattr(o2, '__module__', None), '__name__', ''))
+
+ return cmp(n1, n2)
+
+ def __lt__(self, other):
+ c = self.__cmp(self, other)
+ #print '<', self, other, c < 0, c
+ return c < 0
+
+ def __gt__(self, other):
+ c = self.__cmp(self, other)
+ #print '>', self, other, c > 0, c
+ return c > 0
+
+
+Interface = InterfaceClass("Interface", __module__ = 'zope.interface')
+
+class Attribute(Element):
+ """Attribute descriptions
+ """
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ # implements(IAttribute)
+
+ interface = None
+
+
+class Method(Attribute):
+ """Method interfaces
+
+ The idea here is that you have objects that describe methods.
+ This provides an opportunity for rich meta-data.
+ """
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ # implements(IMethod)
+
+ def __call__(self, *args, **kw):
+ raise BrokenImplementation(self.interface, self.__name__)
+
+ def getSignatureInfo(self):
+ return {'positional': self.positional,
+ 'required': self.required,
+ 'optional': self.optional,
+ 'varargs': self.varargs,
+ 'kwargs': self.kwargs,
+ }
+
+ def getSignatureString(self):
+ sig = []
+ for v in self.positional:
+ sig.append(v)
+ if v in self.optional.keys():
+ sig[-1] += "=" + `self.optional[v]`
+ if self.varargs:
+ sig.append("*" + self.varargs)
+ if self.kwargs:
+ sig.append("**" + self.kwargs)
+
+ return "(%s)" % ", ".join(sig)
+
+
+def fromFunction(func, interface=None, imlevel=0, name=None):
+ name = name or func.__name__
+ method = Method(name, func.__doc__)
+ defaults = func.func_defaults or ()
+ code = func.func_code
+ # Number of positional arguments
+ na = code.co_argcount-imlevel
+ names = code.co_varnames[imlevel:]
+ opt = {}
+ # Number of required arguments
+ nr = na-len(defaults)
+ if nr < 0:
+ defaults=defaults[-nr:]
+ nr = 0
+
+ # Determine the optional arguments.
+ opt.update(dict(zip(names[nr:], defaults)))
+
+ method.positional = names[:na]
+ method.required = names[:nr]
+ method.optional = opt
+
+ argno = na
+
+ # Determine the function's variable argument's name (i.e. *args)
+ if code.co_flags & CO_VARARGS:
+ method.varargs = names[argno]
+ argno = argno + 1
+ else:
+ method.varargs = None
+
+ # Determine the function's keyword argument's name (i.e. **kw)
+ if code.co_flags & CO_VARKEYWORDS:
+ method.kwargs = names[argno]
+ else:
+ method.kwargs = None
+
+ method.interface = interface
+
+ for key, value in func.__dict__.items():
+ method.setTaggedValue(key, value)
+
+ return method
+
+
+def fromMethod(meth, interface=None, name=None):
+ func = meth.im_func
+ return fromFunction(func, interface, imlevel=1, name=name)
+
+
+# Now we can create the interesting interfaces and wire them up:
+def _wire():
+ from zope.interface.declarations import classImplements
+
+ from zope.interface.interfaces import IAttribute
+ classImplements(Attribute, IAttribute)
+
+ from zope.interface.interfaces import IMethod
+ classImplements(Method, IMethod)
+
+ from zope.interface.interfaces import IInterface, ISpecification
+ classImplements(InterfaceClass, IInterface)
+ classImplements(Specification, ISpecification)
+
+# We import this here to deal with module dependencies.
+from zope.interface.declarations import providedBy, implementedBy
+from zope.interface.exceptions import InvalidInterface
+from zope.interface.exceptions import BrokenImplementation
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/interface.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/interfaces.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/interfaces.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/interfaces.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,730 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation 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
+
+$Id: interfaces.py 67803 2006-05-01 15:20:47Z jim $
+"""
+__docformat__ = 'restructuredtext'
+
+
+from zope.interface import Interface
+from zope.interface.interface import Attribute
+
+class IElement(Interface):
+ """Objects that have basic documentation and tagged values.
+ """
+
+ __name__ = Attribute('__name__', 'The object name')
+ __doc__ = Attribute('__doc__', 'The object doc string')
+
+ def getTaggedValue(tag):
+ """Returns the value associated with `tag`.
+
+ Raise a `KeyError` of the tag isn't set.
+ """
+
+ def queryTaggedValue(tag, default=None):
+ """Returns the value associated with `tag`.
+
+ Return the default value of the tag isn't set.
+ """
+
+ def getTaggedValueTags():
+ """Returns a list of all tags."""
+
+ def setTaggedValue(tag, value):
+ """Associates `value` with `key`."""
+
+
+class IAttribute(IElement):
+ """Attribute descriptors"""
+
+ interface = Attribute('interface',
+ 'Stores the interface instance in which the '
+ 'attribute is located.')
+
+
+class IMethod(IAttribute):
+ """Method attributes"""
+
+ def getSignatureInfo():
+ """Returns the signature information.
+
+ This method returns a dictionary with the following keys:
+
+ o `positional` - All positional arguments.
+
+ o `required` - A list of all required arguments.
+
+ o `optional` - A list of all optional arguments.
+
+ o `varargs` - The name of the varargs argument.
+
+ o `kwargs` - The name of the kwargs argument.
+ """
+
+ def getSignatureString():
+ """Return a signature string suitable for inclusion in documentation.
+
+ This method returns the function signature string. For example, if you
+ have `func(a, b, c=1, d='f')`, then the signature string is `(a, b,
+ c=1, d='f')`.
+ """
+
+class ISpecification(Interface):
+ """Object Behavioral specifications"""
+
+ def extends(other, strict=True):
+ """Test whether a specification extends another
+
+ The specification extends other if it has other as a base
+ interface or if one of it's bases extends other.
+
+ If strict is false, then the specification extends itself.
+ """
+
+ def isOrExtends(other):
+ """Test whether the specification is or extends another
+ """
+
+ def weakref(callback=None):
+ """Return a weakref to the specification
+
+ This method is, regrettably, needed to allow weakrefs to be
+ computed to security-proxied specifications. While the
+ zope.interface package does not require zope.security or
+ zope.proxy, it has to be able to coexist with it.
+
+ """
+
+ __bases__ = Attribute("""Base specifications
+
+ A tuple if specifications from which this specification is
+ directly derived.
+
+ """)
+
+ __sro__ = Attribute("""Specification-resolution order
+
+ A tuple of the specification and all of it's ancestor
+ specifications from most specific to least specific.
+
+ (This is similar to the method-resolution order for new-style classes.)
+ """)
+
+ def get(name, default=None):
+ """Look up the description for a name
+
+ If the named attribute is not defined, the default is
+ returned.
+ """
+
+
+class IInterface(ISpecification, IElement):
+ """Interface objects
+
+ Interface objects describe the behavior of an object by containing
+ useful information about the object. This information includes:
+
+ o Prose documentation about the object. In Python terms, this
+ is called the "doc string" of the interface. In this element,
+ you describe how the object works in prose language and any
+ other useful information about the object.
+
+ o Descriptions of attributes. Attribute descriptions include
+ the name of the attribute and prose documentation describing
+ the attributes usage.
+
+ o Descriptions of methods. Method descriptions can include:
+
+ - Prose "doc string" documentation about the method and its
+ usage.
+
+ - A description of the methods arguments; how many arguments
+ are expected, optional arguments and their default values,
+ the position or arguments in the signature, whether the
+ method accepts arbitrary arguments and whether the method
+ accepts arbitrary keyword arguments.
+
+ o Optional tagged data. Interface objects (and their attributes and
+ methods) can have optional, application specific tagged data
+ associated with them. Examples uses for this are examples,
+ security assertions, pre/post conditions, and other possible
+ information you may want to associate with an Interface or its
+ attributes.
+
+ Not all of this information is mandatory. For example, you may
+ only want the methods of your interface to have prose
+ documentation and not describe the arguments of the method in
+ exact detail. Interface objects are flexible and let you give or
+ take any of these components.
+
+ Interfaces are created with the Python class statement using
+ either Interface.Interface or another interface, as in::
+
+ from zope.interface import Interface
+
+ class IMyInterface(Interface):
+ '''Interface documentation'''
+
+ def meth(arg1, arg2):
+ '''Documentation for meth'''
+
+ # Note that there is no self argument
+
+ class IMySubInterface(IMyInterface):
+ '''Interface documentation'''
+
+ def meth2():
+ '''Documentation for meth2'''
+
+ You use interfaces in two ways:
+
+ o You assert that your object implement the interfaces.
+
+ There are several ways that you can assert that an object
+ implements an interface:
+
+ 1. Call zope.interface.implements in your class definition.
+
+ 2. Call zope.interfaces.directlyProvides on your object.
+
+ 3. Call 'zope.interface.classImplements' to assert that instances
+ of a class implement an interface.
+
+ For example::
+
+ from zope.interface import classImplements
+
+ classImplements(some_class, some_interface)
+
+ This approach is useful when it is not an option to modify
+ the class source. Note that this doesn't affect what the
+ class itself implements, but only what its instances
+ implement.
+
+ o You query interface meta-data. See the IInterface methods and
+ attributes for details.
+
+ """
+
+ def providedBy(object):
+ """Test whether the interface is implemented by the object
+
+ Return true of the object asserts that it implements the
+ interface, including asserting that it implements an extended
+ interface.
+ """
+
+ def implementedBy(class_):
+ """Test whether the interface is implemented by instances of the class
+
+ Return true of the class asserts that its instances implement the
+ interface, including asserting that they implement an extended
+ interface.
+ """
+
+ def names(all=False):
+ """Get the interface attribute names
+
+ Return a sequence of the names of the attributes, including
+ methods, included in the interface definition.
+
+ Normally, only directly defined attributes are included. If
+ a true positional or keyword argument is given, then
+ attributes defined by base classes will be included.
+ """
+
+ def namesAndDescriptions(all=False):
+ """Get the interface attribute names and descriptions
+
+ Return a sequence of the names and descriptions of the
+ attributes, including methods, as name-value pairs, included
+ in the interface definition.
+
+ Normally, only directly defined attributes are included. If
+ a true positional or keyword argument is given, then
+ attributes defined by base classes will be included.
+ """
+
+ def __getitem__(name):
+ """Get the description for a name
+
+ If the named attribute is not defined, a KeyError is raised.
+ """
+
+ def direct(name):
+ """Get the description for the name if it was defined by the interface
+
+ If the interface doesn't define the name, returns None.
+ """
+
+ def validateInvariants(obj, errors=None):
+ """Validate invariants
+
+ Validate object to defined invariants. If errors is None,
+ raises first Invalid error; if errors is a list, appends all errors
+ to list, then raises Invalid with the errors as the first element
+ of the "args" tuple."""
+
+ def __contains__(name):
+ """Test whether the name is defined by the interface"""
+
+ def __iter__():
+ """Return an iterator over the names defined by the interface
+
+ The names iterated include all of the names defined by the
+ interface directly and indirectly by base interfaces.
+ """
+
+ __module__ = Attribute("""The name of the module defining the interface""")
+
+class IDeclaration(ISpecification):
+ """Interface declaration
+
+ Declarations are used to express the interfaces implemented by
+ classes or provided by objects.
+ """
+
+ def __contains__(interface):
+ """Test whether an interface is in the specification
+
+ Return true if the given interface is one of the interfaces in
+ the specification and false otherwise.
+ """
+
+ def __iter__():
+ """Return an iterator for the interfaces in the specification
+ """
+
+ def flattened():
+ """Return an iterator of all included and extended interfaces
+
+ An iterator is returned for all interfaces either included in
+ or extended by interfaces included in the specifications
+ without duplicates. The interfaces are in "interface
+ resolution order". The interface resolution order is such that
+ base interfaces are listed after interfaces that extend them
+ and, otherwise, interfaces are included in the order that they
+ were defined in the specification.
+ """
+
+ def __sub__(interfaces):
+ """Create an interface specification with some interfaces excluded
+
+ The argument can be an interface or an interface
+ specifications. The interface or interfaces given in a
+ specification are subtracted from the interface specification.
+
+ Removing an interface that is not in the specification does
+ not raise an error. Doing so has no effect.
+
+ Removing an interface also removes sub-interfaces of the interface.
+
+ """
+
+ def __add__(interfaces):
+ """Create an interface specification with some interfaces added
+
+ The argument can be an interface or an interface
+ specifications. The interface or interfaces given in a
+ specification are added to the interface specification.
+
+ Adding an interface that is already in the specification does
+ not raise an error. Doing so has no effect.
+ """
+
+ def __nonzero__():
+ """Return a true value of the interface specification is non-empty
+ """
+
+class IInterfaceDeclaration(Interface):
+ """Declare and check the interfaces of objects
+
+ The functions defined in this interface are used to declare the
+ interfaces that objects provide and to query the interfaces that have
+ been declared.
+
+ Interfaces can be declared for objects in two ways:
+
+ - Interfaces are declared for instances of the object's class
+
+ - Interfaces are declared for the object directly.
+
+ The interfaces declared for an object are, therefore, the union of
+ interfaces declared for the object directly and the interfaces
+ declared for instances of the object's class.
+
+ Note that we say that a class implements the interfaces provided
+ by it's instances. An instance can also provide interfaces
+ directly. The interfaces provided by an object are the union of
+ the interfaces provided directly and the interfaces implemented by
+ the class.
+ """
+
+ def providedBy(ob):
+ """Return the interfaces provided by an object
+
+ This is the union of the interfaces directly provided by an
+ object and interfaces implemented by it's class.
+
+ The value returned is an IDeclaration.
+ """
+
+ def implementedBy(class_):
+ """Return the interfaces implemented for a class' instances
+
+ The value returned is an IDeclaration.
+ """
+
+ def classImplements(class_, *interfaces):
+ """Declare additional interfaces implemented for instances of a class
+
+ The arguments after the class are one or more interfaces or
+ interface specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) are added to any interfaces previously
+ declared.
+
+ Consider the following example::
+
+ class C(A, B):
+ ...
+
+ classImplements(C, I1, I2)
+
+
+ Instances of ``C`` provide ``I1``, ``I2``, and whatever interfaces
+ instances of ``A`` and ``B`` provide.
+ """
+
+ def implementer(*interfaces):
+ """Create a decorator for declaring interfaces implemented by a facory
+
+ A callable is returned that makes an implements declaration on
+ objects passed to it.
+ """
+
+ def classImplementsOnly(class_, *interfaces):
+ """Declare the only interfaces implemented by instances of a class
+
+ The arguments after the class are one or more interfaces or
+ interface specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) replace any previous declarations.
+
+ Consider the following example::
+
+ class C(A, B):
+ ...
+
+ classImplements(C, IA, IB. IC)
+ classImplementsOnly(C. I1, I2)
+
+ Instances of ``C`` provide only ``I1``, ``I2``, and regardless of
+ whatever interfaces instances of ``A`` and ``B`` implement.
+ """
+
+ def directlyProvidedBy(object):
+ """Return the interfaces directly provided by the given object
+
+ The value returned is an IDeclaration.
+ """
+
+ def directlyProvides(object, *interfaces):
+ """Declare interfaces declared directly for an object
+
+ The arguments after the object are one or more interfaces or
+ interface specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) replace interfaces previously
+ declared for the object.
+
+ Consider the following example::
+
+ class C(A, B):
+ ...
+
+ ob = C()
+ directlyProvides(ob, I1, I2)
+
+ The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+ instances have been declared for instances of ``C``.
+
+ To remove directly provided interfaces, use ``directlyProvidedBy`` and
+ subtract the unwanted interfaces. For example::
+
+ directlyProvides(ob, directlyProvidedBy(ob)-I2)
+
+ removes I2 from the interfaces directly provided by
+ ``ob``. The object, ``ob`` no longer directly provides ``I2``,
+ although it might still provide ``I2`` if it's class
+ implements ``I2``.
+
+ To add directly provided interfaces, use ``directlyProvidedBy`` and
+ include additional interfaces. For example::
+
+ directlyProvides(ob, directlyProvidedBy(ob), I2)
+
+ adds I2 to the interfaces directly provided by ob.
+ """
+
+ def alsoProvides(object, *interfaces):
+ """Declare additional interfaces directly for an object::
+
+ alsoProvides(ob, I1)
+
+ is equivalent to::
+
+ directivelyProvides(ob, directlyProvidedBy(ob), I1)
+ """
+
+ def noLongerProvides(object, interface):
+ """Remove an interface from the list of an object's directly
+ provided interfaces::
+
+ noLongerProvides(ob, I1)
+
+ is equivalent to::
+
+ directlyProvides(ob, directlyProvidedBy(ob)-I1)
+
+ with the exception that if ``I1`` is an interface that is
+ provided by ``ob`` through the class's implementation,
+ ValueError is raised.
+ """
+
+ def implements(*interfaces):
+ """Declare interfaces implemented by instances of a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) are added to any interfaces previously
+ declared.
+
+ Previous declarations include declarations for base classes
+ unless implementsOnly was used.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call classImplements. For example::
+
+ implements(I1)
+
+ is equivalent to calling::
+
+ classImplements(C, I1)
+
+ after the class has been created.
+
+ Consider the following example::
+
+ class C(A, B):
+ implements(I1, I2)
+
+
+ Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces
+ instances of ``A`` and ``B`` implement.
+ """
+
+ def implementsOnly(*interfaces):
+ """Declare the only interfaces implemented by instances of a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ Previous declarations including declarations for base classes
+ are overridden.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call classImplementsOnly. For example::
+
+ implementsOnly(I1)
+
+ is equivalent to calling::
+
+ classImplementsOnly(I1)
+
+ after the class has been created.
+
+ Consider the following example::
+
+ class C(A, B):
+ implementsOnly(I1, I2)
+
+
+ Instances of ``C`` implement ``I1``, ``I2``, regardless of what
+ instances of ``A`` and ``B`` implement.
+ """
+
+ def classProvides(*interfaces):
+ """Declare interfaces provided directly by a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ The given interfaces (including the interfaces in the
+ specifications) are used to create the class's direct-object
+ interface specification. An error will be raised if the module
+ class has an direct interface specification. In other words, it is
+ an error to call this function more than once in a class
+ definition.
+
+ Note that the given interfaces have nothing to do with the
+ interfaces implemented by instances of the class.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call directlyProvides for a class. For example::
+
+ classProvides(I1)
+
+ is equivalent to calling::
+
+ directlyProvides(theclass, I1)
+
+ after the class has been created.
+ """
+
+ def moduleProvides(*interfaces):
+ """Declare interfaces provided by a module
+
+ This function is used in a module definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ The given interfaces (including the interfaces in the
+ specifications) are used to create the module's direct-object
+ interface specification. An error will be raised if the module
+ already has an interface specification. In other words, it is
+ an error to call this function more than once in a module
+ definition.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call directlyProvides for a module. For example::
+
+ moduleImplements(I1)
+
+ is equivalent to::
+
+ directlyProvides(sys.modules[__name__], I1)
+ """
+
+ def Declaration(*interfaces):
+ """Create an interface specification
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ A new interface specification (IDeclaration) with
+ the given interfaces is returned.
+ """
+
+class IAdapterRegistry(Interface):
+ """Provide an interface-based registry for adapters
+
+ This registry registers objects that are in some sense "from" a
+ sequence of specification to an interface and a name.
+
+ No specific semantics are assumed for the registered objects,
+ however, the most common application will be to register factories
+ that adapt objects providing required specifications to a provided
+ interface.
+ """
+
+ def register(required, provided, name, value):
+ """Register a value
+
+ A value is registered for a *sequence* of required specifications, a
+ provided interface, and a name.
+ """
+
+ def registered(required, provided, name=u''):
+ """Return the component registered for the given interfaces and name
+
+ Unlike the lookup method, this methods won't retrieve
+ components registered for more specific required interfaces or
+ less specific provided interfaces.
+
+ If no component was registered exactly for the given
+ interfaces and name, then None is returned.
+
+ """
+
+ def lookup(required, provided, name='', default=None):
+ """Lookup a value
+
+ A value is looked up based on a *sequence* of required
+ specifications, a provided interface, and a name.
+ """
+
+ def queryMultiAdapter(objects, provided, name=u'', default=None):
+ """Adapt a sequence of objects to a named, provided, interface
+ """
+
+ def lookup1(required, provided, name=u'', default=None):
+ """Lookup a value using a single required interface
+
+ A value is looked up based on a single required
+ specifications, a provided interface, and a name.
+ """
+
+ def queryAdapter(object, provided, name=u'', default=None):
+ """Adapt an object using a registered adapter factory.
+ """
+
+ def adapter_hook(provided, object, name=u'', default=None):
+ """Adapt an object using a registered adapter factory.
+ """
+
+ def lookupAll(required, provided):
+ """Find all adapters from the required to the provided interfaces
+
+ An iterable object is returned that provides name-value two-tuples.
+ """
+
+ def names(required, provided):
+ """Return the names for which there are registered objects
+ """
+
+ def subscribe(required, provided, subscriber, name=u''):
+ """Register a subscriber
+
+ A subscriber is registered for a *sequence* of required
+ specifications, a provided interface, and a name.
+
+ Multiple subscribers may be registered for the same (or
+ equivalent) interfaces.
+ """
+
+ def subscriptions(required, provided, name=u''):
+ """Get a sequence of subscribers
+
+ Subscribers for a *sequence* of required interfaces, and a provided
+ interface are returned.
+ """
+
+ def subscribers(objects, provided, name=u''):
+ """Get a sequence of subscription adapters
+ """
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/interfaces.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/ro.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/ro.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/ro.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,63 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation 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 it's bases
+
+$Id: ro.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+def ro(object):
+ """Compute a "resolution order" for an object
+ """
+ return mergeOrderings([_flatten(object, [])])
+
+def mergeOrderings(orderings, seen=None):
+ """Merge multiple orderings so that within-ordering order is preserved
+
+ Orderings are constrained in such a way that if an object appears
+ in two or more orderings, then the suffix that begins with the
+ object must be in both orderings.
+
+ For example:
+
+ >>> _mergeOrderings([
+ ... ['x', 'y', 'z'],
+ ... ['q', 'z'],
+ ... [1, 3, 5],
+ ... ['z']
+ ... ])
+ ['x', 'y', 'q', 1, 3, 5, 'z']
+
+ """
+
+ if seen is None:
+ seen = {}
+ result = []
+ orderings.reverse()
+ for ordering in orderings:
+ ordering = list(ordering)
+ ordering.reverse()
+ for o in ordering:
+ if o not in seen:
+ seen[o] = 1
+ result.append(o)
+
+ result.reverse()
+ return result
+
+def _flatten(ob, result):
+ result.append(ob)
+ for base in ob.__bases__:
+ _flatten(base, result)
+
+ return result
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/ro.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/__init__.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/__init__.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/__init__.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,25 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Dummy Module
+
+$Id$
+"""
+from zope.interface import moduleProvides
+from zope.interface.tests.ifoo import IFoo
+from zope.interface import moduleProvides
+
+moduleProvides(IFoo)
+
+def bar(baz):
+ pass
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/foodforthought.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/foodforthought.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/foodforthought.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,61 @@
+================================
+Food-based subscription examples
+================================
+
+
+This file gives more subscription examples using a cooking-based example::
+
+ >>> from zope.interface.adapter import AdapterRegistry
+ >>> registry = AdapterRegistry()
+
+ >>> import zope.interface
+ >>> class IAnimal(zope.interface.Interface):
+ ... pass
+ >>> class IPoultry(IAnimal):
+ ... pass
+ >>> class IChicken(IPoultry):
+ ... pass
+ >>> class ISeafood(IAnimal):
+ ... pass
+
+Adapting to some other interface for which there is no
+subscription adapter returns an empty sequence::
+
+ >>> class IRecipe(zope.interface.Interface):
+ ... pass
+ >>> class ISausages(IRecipe):
+ ... pass
+ >>> class INoodles(IRecipe):
+ ... pass
+ >>> class IKFC(IRecipe):
+ ... pass
+
+ >>> list(registry.subscriptions([IPoultry], IRecipe))
+ []
+
+unless we define a subscription::
+
+ >>> registry.subscribe([IAnimal], ISausages, 'sausages')
+ >>> list(registry.subscriptions([IPoultry], ISausages))
+ ['sausages']
+
+And define another subscription adapter::
+
+ >>> registry.subscribe([IPoultry], INoodles, 'noodles')
+ >>> meals = list(registry.subscriptions([IPoultry], IRecipe))
+ >>> meals.sort()
+ >>> meals
+ ['noodles', 'sausages']
+
+ >>> registry.subscribe([IChicken], IKFC, 'kfc')
+ >>> meals = list(registry.subscriptions([IChicken], IRecipe))
+ >>> meals.sort()
+ >>> meals
+ ['kfc', 'noodles', 'sausages']
+
+And the answer for poultry hasn't changed::
+
+ >>> meals = list(registry.subscriptions([IPoultry], IRecipe))
+ >>> meals.sort()
+ >>> meals
+ ['noodles', 'sausages']
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/foodforthought.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""IFoo test module
+
+$Id$
+"""
+from zope.interface import Interface
+
+class IFoo(Interface):
+ """
+ Dummy interface for unit tests.
+ """
+
+ def bar(baz):
+ """
+ Just a note.
+ """
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test module that declares an interface
+
+$Id$
+"""
+from zope.interface import Interface, moduleProvides
+
+class I1(Interface): pass
+class I2(Interface): pass
+
+moduleProvides(I1, I2)
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test module that doesn't declare an interface
+
+$Id$
+"""
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/odd.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/odd.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/odd.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Odd meta class that doesn't subclass type.
+
+This is used for testing support for ExtensionClass in new interfaces.
+
+ >>> class A(object):
+ ... __metaclass__ = MetaClass
+ ... a = 1
+ ...
+ >>> A.__name__
+ 'A'
+ >>> A.__bases__
+ ()
+ >>> class B(object):
+ ... __metaclass__ = MetaClass
+ ... b = 1
+ ...
+ >>> class C(A, B): pass
+ ...
+ >>> C.__name__
+ 'C'
+ >>> int(C.__bases__ == (A, B))
+ 1
+ >>> a = A()
+ >>> aa = A()
+ >>> a.a
+ 1
+ >>> aa.a
+ 1
+ >>> aa.a = 2
+ >>> a.a
+ 1
+ >>> aa.a
+ 2
+ >>> c = C()
+ >>> c.a
+ 1
+ >>> c.b
+ 1
+ >>> c.b = 2
+ >>> c.b
+ 2
+ >>> C.c = 1
+ >>> c.c
+ 1
+ >>> from types import ClassType
+ >>> int(isinstance(C, (type, ClassType)))
+ 0
+ >>> int(C.__class__.__class__ is C.__class__)
+ 1
+
+$Id: odd.py 38178 2005-08-30 21:50:19Z mj $
+"""
+
+# class OddClass is an odd meta class
+
+class MetaMetaClass(type):
+
+ def __getattribute__(self, name):
+ if name == '__class__':
+ return self
+ return type.__getattribute__(self, name)
+
+
+class MetaClass(object):
+ """Odd classes
+ """
+ __metaclass__ = MetaMetaClass
+
+ def __init__(self, name, bases, dict):
+ self.__name__ = name
+ self.__bases__ = bases
+ self.__dict__.update(dict)
+
+ def __call__(self):
+ return OddInstance(self)
+
+ def __getattr__(self, name):
+ for b in self.__bases__:
+ v = getattr(b, name, self)
+ if v is not self:
+ return v
+ raise AttributeError(name)
+
+ def __repr__(self):
+ return "<odd class %s at %s>" % (self.__name__, hex(id(self)))
+
+class OddInstance(object):
+
+ def __init__(self, cls):
+ self.__dict__['__class__'] = cls
+
+ def __getattribute__(self, name):
+ dict = object.__getattribute__(self, '__dict__')
+ if name == '__dict__':
+ return dict
+ v = dict.get(name, self)
+ if v is not self:
+ return v
+ return getattr(dict['__class__'], name)
+
+ def __setattr__(self, name, v):
+ self.__dict__[name] = v
+
+ def __delattr__(self, name):
+ del self.__dict__[name]
+
+ def __repr__(self):
+ return "<odd %s instance at %s>" % (
+ self.__class__.__name__, hex(id(self)))
+
+
+
+# DocTest:
+if __name__ == "__main__":
+ import doctest, __main__
+ doctest.testmod(__main__, isprivate=lambda *a: False)
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/odd.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,335 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Adapter registry tests
+
+$Id: test_adapter.py 67795 2006-05-01 13:55:42Z jim $
+"""
+import unittest
+import zope.interface
+from zope.interface.adapter import AdapterRegistry
+import zope.interface
+
+
+class IF0(zope.interface.Interface):
+ pass
+class IF1(IF0):
+ pass
+
+class IB0(zope.interface.Interface):
+ pass
+class IB1(IB0):
+ pass
+
+class IR0(zope.interface.Interface):
+ pass
+class IR1(IR0):
+ pass
+
+def test_multi_adapter_get_best_match():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> class IB2(IB0):
+ ... pass
+ >>> class IB3(IB2, IB1):
+ ... pass
+ >>> class IB4(IB1, IB2):
+ ... pass
+
+ >>> registry.register([None, IB1], IR0, '', 'A1')
+ >>> registry.register([None, IB0], IR0, '', 'A0')
+ >>> registry.register([None, IB2], IR0, '', 'A2')
+
+ >>> registry.lookup((IF1, IB1), IR0, '')
+ 'A1'
+ >>> registry.lookup((IF1, IB2), IR0, '')
+ 'A2'
+ >>> registry.lookup((IF1, IB0), IR0, '')
+ 'A0'
+ >>> registry.lookup((IF1, IB3), IR0, '')
+ 'A2'
+ >>> registry.lookup((IF1, IB4), IR0, '')
+ 'A1'
+ """
+
+def test_multi_adapter_lookupAll_get_best_matches():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> class IB2(IB0):
+ ... pass
+ >>> class IB3(IB2, IB1):
+ ... pass
+ >>> class IB4(IB1, IB2):
+ ... pass
+
+ >>> registry.register([None, IB1], IR0, '', 'A1')
+ >>> registry.register([None, IB0], IR0, '', 'A0')
+ >>> registry.register([None, IB2], IR0, '', 'A2')
+
+ >>> tuple(registry.lookupAll((IF1, IB1), IR0))[0][1]
+ 'A1'
+ >>> tuple(registry.lookupAll((IF1, IB2), IR0))[0][1]
+ 'A2'
+ >>> tuple(registry.lookupAll((IF1, IB0), IR0))[0][1]
+ 'A0'
+ >>> tuple(registry.lookupAll((IF1, IB3), IR0))[0][1]
+ 'A2'
+ >>> tuple(registry.lookupAll((IF1, IB4), IR0))[0][1]
+ 'A1'
+ """
+
+
+def test_multi_adapter_w_default():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> registry.register([None, None], IB1, 'bob', 'A0')
+
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A0'
+
+ >>> registry.register([None, IR0], IB1, 'bob', 'A1')
+
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A1'
+
+ >>> registry.lookup((IF1, IR1), IB0, 'bruce')
+
+ >>> registry.register([None, IR1], IB1, 'bob', 'A2')
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A2'
+ """
+
+def test_multi_adapter_w_inherited_and_multiple_registrations():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> class IX(zope.interface.Interface):
+ ... pass
+
+ >>> registry.register([IF0, IR0], IB1, 'bob', 'A1')
+ >>> registry.register([IF1, IX], IB1, 'bob', 'AX')
+
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A1'
+ """
+
+def test_named_adapter_with_default():
+ """Query a named simple adapter
+
+ >>> registry = AdapterRegistry()
+
+ If we ask for a named adapter, we won't get a result unless there
+ is a named adapter, even if the object implements the interface:
+
+ >>> registry.lookup([IF1], IF0, 'bob')
+
+ >>> registry.register([None], IB1, 'bob', 'A1')
+ >>> registry.lookup([IF1], IB0, 'bob')
+ 'A1'
+
+ >>> registry.lookup([IF1], IB0, 'bruce')
+
+ >>> registry.register([None], IB0, 'bob', 'A2')
+ >>> registry.lookup([IF1], IB0, 'bob')
+ 'A2'
+ """
+
+def test_multi_adapter_gets_closest_provided():
+ """
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+ >>> registry.register((IF1, IR0), IB1, 'bob', 'A2')
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A1'
+
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF1, IR0], IB1, 'bob', 'A2')
+ >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+ >>> registry.lookup([IF1, IR0], IB0, 'bob')
+ 'A1'
+
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+ >>> registry.register([IF1, IR1], IB1, 'bob', 'A2')
+ >>> registry.lookup([IF1, IR1], IB0, 'bob')
+ 'A2'
+
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF1, IR1], IB1, 'bob', 2)
+ >>> registry.register([IF1, IR0], IB0, 'bob', 1)
+ >>> registry.lookup([IF1, IR1], IB0, 'bob')
+ 2
+ """
+
+def test_multi_adapter_check_non_default_dont_hide_default():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> class IX(zope.interface.Interface):
+ ... pass
+
+
+ >>> registry.register([None, IR0], IB0, 'bob', 1)
+ >>> registry.register([IF1, IX], IB0, 'bob', 2)
+ >>> registry.lookup([IF1, IR1], IB0, 'bob')
+ 1
+ """
+
+def test_adapter_hook_with_factory_producing_None():
+ """
+ >>> registry = AdapterRegistry()
+ >>> default = object()
+
+ >>> class Object1(object):
+ ... zope.interface.implements(IF0)
+ >>> class Object2(object):
+ ... zope.interface.implements(IF0)
+
+ >>> def factory(context):
+ ... if isinstance(context, Object1):
+ ... return 'adapter'
+ ... return None
+
+ >>> registry.register([IF0], IB0, '', factory)
+
+ >>> registry.adapter_hook(IB0, Object1())
+ 'adapter'
+ >>> registry.adapter_hook(IB0, Object2()) is None
+ True
+ >>> registry.adapter_hook(IB0, Object2(), default=default) is default
+ True
+ """
+
+def test_adapter_registry_update_upon_interface_bases_change():
+ """
+ Let's first create a adapter registry and a simple adaptation hook:
+
+ >>> globalRegistry = AdapterRegistry()
+
+ >>> def _hook(iface, ob, lookup=globalRegistry.lookup1):
+ ... factory = lookup(zope.interface.providedBy(ob), iface)
+ ... if factory is None:
+ ... return None
+ ... else:
+ ... return factory(ob)
+
+ >>> zope.interface.interface.adapter_hooks.append(_hook)
+
+ Now we create some interfaces and an implementation:
+
+ >>> class IX(zope.interface.Interface):
+ ... pass
+
+ >>> class IY(zope.interface.Interface):
+ ... pass
+
+ >>> class X(object):
+ ... pass
+
+ >>> class Y(object):
+ ... zope.interface.implements(IY)
+ ... def __init__(self, original):
+ ... self.original=original
+
+ and register an adapter:
+
+ >>> globalRegistry.register((IX,), IY, '', Y)
+
+ at first, we still expect the adapter lookup from `X` to `IY` to fail:
+
+ >>> IY(X()) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt',
+ <zope.interface.tests.test_adapter.X object at ...>,
+ <InterfaceClass zope.interface.tests.test_adapter.IY>)
+
+ But after we declare an interface on the class `X`, it should pass:
+
+ >>> zope.interface.classImplementsOnly(X, IX)
+
+ >>> IY(X()) #doctest: +ELLIPSIS
+ <zope.interface.tests.test_adapter.Y object at ...>
+
+ >>> hook = zope.interface.interface.adapter_hooks.pop()
+ """
+
+
+def test_changing_declarations():
+ """
+
+ If we change declarations for a class, those adapter lookup should
+ eflect the changes:
+
+ >>> class I1(zope.interface.Interface):
+ ... pass
+ >>> class I2(zope.interface.Interface):
+ ... pass
+
+ >>> registry = AdapterRegistry()
+ >>> registry.register([I1], I2, '', 42)
+
+ >>> class C:
+ ... pass
+
+ >>> registry.lookup([zope.interface.implementedBy(C)], I2, '')
+
+ >>> zope.interface.classImplements(C, I1)
+
+ >>> registry.lookup([zope.interface.implementedBy(C)], I2, '')
+ 42
+ """
+
+def test_correct_multi_adapter_lookup():
+ """
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF0, IB1], IR0, '', 'A01')
+ >>> registry.register([IF1, IB0], IR0, '', 'A10')
+ >>> registry.lookup((IF1, IB1), IR0, '')
+ 'A10'
+ """
+
+def test_duplicate_bases():
+ """
+There was a bug that caused problems if a spec had multiple bases:
+
+ >>> class I(zope.interface.Interface):
+ ... pass
+ >>> class I2(I, I):
+ ... pass
+ >>> registry = AdapterRegistry()
+ >>> registry.register([I2], IR0, 'x', 'X')
+ >>> registry.lookup((I2, ), IR0, 'x')
+ 'X'
+ >>> registry.register([I2], IR0, 'y', 'Y')
+ >>> registry.lookup((I2, ), IR0, 'x')
+ 'X'
+ >>> registry.lookup((I2, ), IR0, 'y')
+ 'Y'
+"""
+
+
+def test_suite():
+ from zope.testing import doctest, doctestunit
+ return unittest.TestSuite((
+ doctestunit.DocFileSuite('../adapter.txt', '../human.txt',
+ '../human.ru.txt', 'foodforthought.txt',
+ globs={'__name__': '__main__'}),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_advice.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_advice.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_advice.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,178 @@
+
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for advice
+
+This module was adapted from 'protocols.tests.advice', part of the Python
+Enterprise Application Kit (PEAK). Please notify the PEAK authors
+(pje at telecommunity.com and tsarna at 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.
+
+$Id: test_advice.py 40836 2005-12-16 22:40:51Z benji_york $
+"""
+
+import unittest
+from unittest import TestCase, makeSuite, TestSuite
+from zope.interface.advice import *
+from types import ClassType
+import sys
+
+def ping(log, value):
+
+ def pong(klass):
+ log.append((value,klass))
+ return [klass]
+
+ addClassAdvisor(pong)
+
+class ClassicClass:
+ __metaclass__ = ClassType
+ classLevelFrameInfo = getFrameInfo(sys._getframe())
+
+class NewStyleClass:
+ __metaclass__ = type
+ classLevelFrameInfo = getFrameInfo(sys._getframe())
+
+moduleLevelFrameInfo = getFrameInfo(sys._getframe())
+
+class FrameInfoTest(TestCase):
+
+ classLevelFrameInfo = getFrameInfo(sys._getframe())
+
+ def checkModuleInfo(self):
+ kind, module, f_locals, f_globals = moduleLevelFrameInfo
+ self.assertEquals(kind, "module")
+ for d in module.__dict__, f_locals, f_globals:
+ self.assert_(d is globals())
+
+ def checkClassicClassInfo(self):
+ kind, module, f_locals, f_globals = ClassicClass.classLevelFrameInfo
+ self.assertEquals(kind, "class")
+
+ self.assert_(f_locals is ClassicClass.__dict__) # ???
+ for d in module.__dict__, f_globals:
+ self.assert_(d is globals())
+
+ def checkNewStyleClassInfo(self):
+ kind, module, f_locals, f_globals = NewStyleClass.classLevelFrameInfo
+ self.assertEquals(kind, "class")
+
+ for d in module.__dict__, f_globals:
+ self.assert_(d is globals())
+
+ def checkCallInfo(self):
+ kind, module, f_locals, f_globals = getFrameInfo(sys._getframe())
+ self.assertEquals(kind, "function call")
+ self.assert_(f_locals is locals()) # ???
+ for d in module.__dict__, f_globals:
+ self.assert_(d is globals())
+
+
+class AdviceTests(TestCase):
+
+ def checkOrder(self):
+ log = []
+ class Foo(object):
+ ping(log, 1)
+ ping(log, 2)
+ ping(log, 3)
+
+ # Strip the list nesting
+ for i in 1,2,3:
+ self.assert_(isinstance(Foo, list))
+ Foo, = Foo
+
+ self.assertEquals(log, [(1, Foo), (2, [Foo]), (3, [[Foo]])])
+
+ def TODOcheckOutside(self):
+ # Disabled because the check does not work with doctest tests.
+ try:
+ ping([], 1)
+ except SyntaxError:
+ pass
+ else:
+ raise AssertionError(
+ "Should have detected advice outside class body"
+ )
+
+ def checkDoubleType(self):
+ if sys.hexversion >= 0x02030000:
+ return # you can't duplicate bases in 2.3
+ class aType(type,type):
+ ping([],1)
+ aType, = aType
+ self.assert_(aType.__class__ is type)
+
+ def checkSingleExplicitMeta(self):
+
+ class M(type):
+ pass
+
+ class C(M):
+ __metaclass__ = M
+ ping([],1)
+
+ C, = C
+ self.assert_(C.__class__ is M)
+
+
+ def checkMixedMetas(self):
+
+ class M1(type): pass
+ class M2(type): pass
+
+ class B1: __metaclass__ = M1
+ class B2: __metaclass__ = M2
+
+ try:
+ class C(B1,B2):
+ ping([],1)
+ except TypeError:
+ pass
+ else:
+ raise AssertionError("Should have gotten incompatibility error")
+
+ class M3(M1,M2): pass
+
+ class C(B1,B2):
+ __metaclass__ = M3
+ ping([],1)
+
+ self.assert_(isinstance(C,list))
+ C, = C
+ self.assert_(isinstance(C,M3))
+
+ def checkMetaOfClass(self):
+
+ class metameta(type):
+ pass
+
+ class meta(type):
+ __metaclass__ = metameta
+
+ self.assertEquals(determineMetaclass((meta, type)), metameta)
+
+TestClasses = (AdviceTests, FrameInfoTest)
+
+def test_suite():
+ return TestSuite([makeSuite(t,'check') for t in TestClasses])
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_advice.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_declarations.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_declarations.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_declarations.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,416 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test the new API for making and checking interface declarations
+
+$Id: test_declarations.py 67630 2006-04-27 00:54:03Z jim $
+"""
+import unittest
+from zope.interface import *
+from zope.testing.doctestunit import DocTestSuite
+from zope.interface import Interface
+
+class I1(Interface): pass
+class I2(Interface): pass
+class I3(Interface): pass
+class I4(Interface): pass
+class I5(Interface): pass
+
+class A(object):
+ implements(I1)
+class B(object):
+ implements(I2)
+class C(A, B):
+ implements(I3)
+
+class COnly(A, B):
+ implementsOnly(I3)
+
+class COnly_old(A, B):
+ __implemented__ = I3
+
+class D(COnly):
+ implements(I5)
+
+def test_ObjectSpecification_Simple():
+ """
+ >>> c = C()
+ >>> directlyProvides(c, I4)
+ >>> [i.__name__ for i in providedBy(c)]
+ ['I4', 'I3', 'I1', 'I2']
+ """
+
+def test_ObjectSpecification_Simple_w_only():
+ """
+ >>> c = COnly()
+ >>> directlyProvides(c, I4)
+ >>> [i.__name__ for i in providedBy(c)]
+ ['I4', 'I3']
+ """
+
+def test_ObjectSpecification_Simple_old_style():
+ """
+ >>> c = COnly_old()
+ >>> directlyProvides(c, I4)
+ >>> [i.__name__ for i in providedBy(c)]
+ ['I4', 'I3']
+ """
+
+
+class Test(unittest.TestCase):
+
+ # Note that most of the tests are in the doc strings of the
+ # declarations module.
+
+ def test_backward_compat(self):
+
+ class C1(object): __implemented__ = I1
+ class C2(C1): __implemented__ = I2, I5
+ class C3(C2): __implemented__ = I3, C2.__implemented__
+
+ self.assert_(C3.__implemented__.__class__ is tuple)
+
+ self.assertEqual(
+ [i.getName() for i in providedBy(C3())],
+ ['I3', 'I2', 'I5'],
+ )
+
+ class C4(C3):
+ implements(I4)
+
+ self.assertEqual(
+ [i.getName() for i in providedBy(C4())],
+ ['I4', 'I3', 'I2', 'I5'],
+ )
+
+ self.assertEqual(
+ [i.getName() for i in C4.__implemented__],
+ ['I4', 'I3', 'I2', 'I5'],
+ )
+
+ # Note that C3.__implemented__ should now be a sequence of interfaces
+ self.assertEqual(
+ [i.getName() for i in C3.__implemented__],
+ ['I3', 'I2', 'I5'],
+ )
+ self.failIf(C3.__implemented__.__class__ is tuple)
+
+ def test_module(self):
+ import zope.interface.tests.m1
+ import zope.interface.tests.m2
+ directlyProvides(zope.interface.tests.m2,
+ zope.interface.tests.m1.I1,
+ zope.interface.tests.m1.I2,
+ )
+ self.assertEqual(list(providedBy(zope.interface.tests.m1)),
+ list(providedBy(zope.interface.tests.m2)),
+ )
+
+ def test_builtins(self):
+ # Setup
+
+ intspec = implementedBy(int)
+ olddeclared = intspec.declared
+
+ classImplements(int, I1)
+ class myint(int):
+ implements(I2)
+
+ x = 42
+ self.assertEqual([i.getName() for i in providedBy(x)],
+ ['I1'])
+
+ x = myint(42)
+ directlyProvides(x, I3)
+ self.assertEqual([i.getName() for i in providedBy(x)],
+ ['I3', 'I2', 'I1'])
+
+ # cleanup
+ intspec.declared = olddeclared
+ classImplements(int)
+
+ x = 42
+ self.assertEqual([i.getName() for i in providedBy(x)],
+ [])
+
+
+def test_signature_w_no_class_interfaces():
+ """
+ >>> from zope.interface import *
+ >>> class C(object):
+ ... pass
+ >>> c = C()
+ >>> list(providedBy(c))
+ []
+
+ >>> class I(Interface):
+ ... pass
+ >>> directlyProvides(c, I)
+ >>> list(providedBy(c)) == list(directlyProvidedBy(c))
+ 1
+ """
+
+def test_classImplement_on_deeply_nested_classes():
+ """This test is in response to a bug found, which is why it's a bit
+ contrived
+
+ >>> from zope.interface import *
+ >>> class B1(object):
+ ... pass
+ >>> class B2(B1):
+ ... pass
+ >>> class B3(B2):
+ ... pass
+ >>> class D(object):
+ ... implements()
+ >>> class S(B3, D):
+ ... implements()
+
+ This failed due to a bug in the code for finding __providedBy__
+ descriptors for old-style classes.
+
+ """
+
+def test_pickle_provides_specs():
+ """
+ >>> from pickle import dumps, loads
+ >>> a = A()
+ >>> I2.providedBy(a)
+ 0
+ >>> directlyProvides(a, I2)
+ >>> I2.providedBy(a)
+ 1
+ >>> a2 = loads(dumps(a))
+ >>> I2.providedBy(a2)
+ 1
+
+ """
+
+def test_that_we_dont_inherit_class_provides():
+ """
+ >>> class X(object):
+ ... classProvides(I1)
+ >>> class Y(X):
+ ... pass
+ >>> [i.__name__ for i in X.__provides__]
+ ['I1']
+ >>> Y.__provides__
+ Traceback (most recent call last):
+ ...
+ AttributeError: __provides__
+
+ """
+
+def test_that_we_dont_inherit_provides_optimizations():
+ """
+
+ When we make a declaration for a class, we install a __provides__
+ descriptors that provides a default for instances that don't have
+ instance-specific declarations:
+
+ >>> class A(object):
+ ... implements(I1)
+
+ >>> class B(object):
+ ... implements(I2)
+
+ >>> [i.__name__ for i in A().__provides__]
+ ['I1']
+ >>> [i.__name__ for i in B().__provides__]
+ ['I2']
+
+ But it's important that we don't use this for subclasses without
+ declarations. This would cause incorrect results:
+
+ >>> class X(A, B):
+ ... pass
+
+ >>> X().__provides__
+ Traceback (most recent call last):
+ ...
+ AttributeError: __provides__
+
+ However, if we "induce" a declaration, by calling implementedBy
+ (even indirectly through providedBy):
+
+ >>> [i.__name__ for i in providedBy(X())]
+ ['I1', 'I2']
+
+
+ then the optimization will work:
+
+ >>> [i.__name__ for i in X().__provides__]
+ ['I1', 'I2']
+
+ """
+
+def test_classProvides_before_implements():
+ """Special descriptor for class __provides__
+
+ The descriptor caches the implementedBy info, so that
+ we can get declarations for objects without instance-specific
+ interfaces a bit quicker.
+
+ For example::
+
+ >>> from zope.interface import Interface
+ >>> class IFooFactory(Interface):
+ ... pass
+ >>> class IFoo(Interface):
+ ... pass
+ >>> class C(object):
+ ... classProvides(IFooFactory)
+ ... implements(IFoo)
+ >>> [i.getName() for i in C.__provides__]
+ ['IFooFactory']
+
+ >>> [i.getName() for i in C().__provides__]
+ ['IFoo']
+ """
+
+def test_getting_spec_for_proxied_builtin_class():
+ """
+
+ In general, we should be able to get a spec
+ for a proxied class if someone has declared or
+ asked for a spec before.
+
+ We don't want to depend on proxies in this (zope.interface)
+ package, but we do want to work with proxies. Proxies have the
+ effect that a class's __dict__ cannot be gotten. Further, for
+ built-in classes, we can't save, and thus, cannot get, any class
+ attributes. We'll emulate this by treating a plain object as a class:
+
+ >>> cls = object()
+
+ We'll create an implements specification:
+
+ >>> import zope.interface.declarations
+ >>> impl = zope.interface.declarations.Implements(I1, I2)
+
+ Now, we'll emulate a declaration for a built-in type by putting
+ it in BuiltinImplementationSpecifications:
+
+ >>> zope.interface.declarations.BuiltinImplementationSpecifications[
+ ... cls] = impl
+
+ Now, we should be able to get it back:
+
+ >>> implementedBy(cls) is impl
+ True
+
+ Of course, we don't want to leave it there. :)
+
+ >>> del zope.interface.declarations.BuiltinImplementationSpecifications[
+ ... cls]
+
+ """
+
+def test_declaration_get():
+ """
+ We can get definitions from a declaration:
+
+ >>> import zope.interface
+ >>> class I1(zope.interface.Interface):
+ ... a11 = zope.interface.Attribute('a11')
+ ... a12 = zope.interface.Attribute('a12')
+ >>> class I2(zope.interface.Interface):
+ ... a21 = zope.interface.Attribute('a21')
+ ... a22 = zope.interface.Attribute('a22')
+ ... a12 = zope.interface.Attribute('a212')
+ >>> class I11(I1):
+ ... a11 = zope.interface.Attribute('a111')
+
+ >>> decl = Declaration(I11, I2)
+ >>> decl.get('a11') is I11.get('a11')
+ True
+ >>> decl.get('a12') is I1.get('a12')
+ True
+ >>> decl.get('a21') is I2.get('a21')
+ True
+ >>> decl.get('a22') is I2.get('a22')
+ True
+ >>> decl.get('a')
+ >>> decl.get('a', 42)
+ 42
+
+ We get None even with no interfaces:
+
+ >>> decl = Declaration()
+ >>> decl.get('a11')
+ >>> decl.get('a11', 42)
+ 42
+
+ We get new data if e change interface bases:
+
+ >>> decl.__bases__ = I11, I2
+ >>> decl.get('a11') is I11.get('a11')
+ True
+ """
+
+def test_classImplements_after_classImplementsOnly_issue_402():
+ """http://www.zope.org/Collectors/Zope3-dev/402
+
+>>> from zope.interface import *
+>>> class I1(Interface):
+... pass
+>>> class I2(Interface):
+... pass
+>>> class C:
+... implements(I1)
+>>> class C2:
+... implementsOnly(I2)
+>>> class I3(Interface):
+... pass
+
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'Interface']
+
+>>> classImplements(C2, I3)
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'I3', 'Interface']
+
+>>> class I4(Interface):
+... pass
+>>> classImplements(C2, I4)
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'I3', 'I4', 'Interface']
+
+
+"""
+
+def test_picklability_of_implements_specifications():
+ """
+
+ Sometimes, we need to pickle implements specs. We should be able
+ to do so as long as the class is picklable.
+
+ >>> import pickle
+ >>> pickle.loads(pickle.dumps(implementedBy(C))) is implementedBy(C)
+ True
+
+
+ """
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(Test))
+ suite.addTest(DocTestSuite("zope.interface.declarations"))
+ suite.addTest(DocTestSuite())
+
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_declarations.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_document.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_document.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_document.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,71 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Documentation tests.
+
+$Id: test_document.py 26560 2004-07-15 21:38:42Z srichter $
+"""
+from unittest import TestCase, main, makeSuite
+
+from zope.interface import Interface, Attribute
+
+class Test(TestCase):
+
+ def testBlech(self):
+ from zope.interface.document import asStructuredText
+
+ self.assertEqual(asStructuredText(I2), '''\
+I2
+
+ I2 doc
+
+ This interface extends:
+
+ o _I1
+
+ Attributes:
+
+ a1 -- no documentation
+
+ a2 -- a2 doc
+
+ Methods:
+
+ f21() -- f21 doc
+
+ f22() -- no documentation
+
+ f23() -- f23 doc
+
+''')
+
+
+def test_suite():
+ return makeSuite(Test)
+
+class _I1(Interface):
+ def f11(): pass
+ def f12(): pass
+
+class I2(_I1):
+ "I2 doc"
+
+ a1 = Attribute('a1')
+ a2 = Attribute('a2', 'a2 doc')
+
+ def f21(): "f21 doc"
+ def f22(): pass
+ def f23(): "f23 doc"
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_document.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_element.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_element.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_element.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,43 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test Element meta-class.
+
+$Id: test_element.py 39768 2005-10-31 13:57:35Z tlotze $
+"""
+
+import unittest
+from zope.interface.interface import Element
+
+class TestElement(unittest.TestCase):
+
+ def test_taggedValues(self):
+ """Test that we can update tagged values of more than one element
+ """
+
+ e1 = Element("foo")
+ e2 = Element("bar")
+ e1.setTaggedValue("x", 1)
+ e2.setTaggedValue("x", 2)
+ self.assertEqual(e1.getTaggedValue("x"), 1)
+ self.assertEqual(e2.getTaggedValue("x"), 2)
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestElement))
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_element.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_interface.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_interface.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_interface.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,352 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test Interface implementation
+
+$Id: test_interface.py 67761 2006-04-30 13:56:44Z jim $
+"""
+import sys
+import unittest
+from zope.testing.doctestunit import DocTestSuite
+from zope.interface.tests.unitfixtures import * # hehehe
+from zope.interface.exceptions import BrokenImplementation, Invalid
+from zope.interface import implementedBy, providedBy
+from zope.interface import Interface, directlyProvides, Attribute
+from zope import interface
+
+class InterfaceTests(unittest.TestCase):
+
+ def testInterfaceSetOnAttributes(self):
+ self.assertEqual(FooInterface['foobar'].interface,
+ FooInterface)
+ self.assertEqual(FooInterface['aMethod'].interface,
+ FooInterface)
+
+ def testClassImplements(self):
+ self.assert_(IC.implementedBy(C))
+
+ self.assert_(I1.implementedBy(A))
+ self.assert_(I1.implementedBy(B))
+ self.assert_(not I1.implementedBy(C))
+ self.assert_(I1.implementedBy(D))
+ self.assert_(I1.implementedBy(E))
+
+ self.assert_(not I2.implementedBy(A))
+ self.assert_(I2.implementedBy(B))
+ self.assert_(not I2.implementedBy(C))
+
+ # No longer after interfacegeddon
+ # self.assert_(not I2.implementedBy(D))
+
+ self.assert_(not I2.implementedBy(E))
+
+ def testUtil(self):
+ self.assert_(IC in implementedBy(C))
+ self.assert_(I1 in implementedBy(A))
+ self.assert_(not I1 in implementedBy(C))
+ self.assert_(I2 in implementedBy(B))
+ self.assert_(not I2 in implementedBy(C))
+
+ self.assert_(IC in providedBy(C()))
+ self.assert_(I1 in providedBy(A()))
+ self.assert_(not I1 in providedBy(C()))
+ self.assert_(I2 in providedBy(B()))
+ self.assert_(not I2 in providedBy(C()))
+
+
+ def testObjectImplements(self):
+ self.assert_(IC.providedBy(C()))
+
+ self.assert_(I1.providedBy(A()))
+ self.assert_(I1.providedBy(B()))
+ self.assert_(not I1.providedBy(C()))
+ self.assert_(I1.providedBy(D()))
+ self.assert_(I1.providedBy(E()))
+
+ self.assert_(not I2.providedBy(A()))
+ self.assert_(I2.providedBy(B()))
+ self.assert_(not I2.providedBy(C()))
+
+ # Not after interface geddon
+ # self.assert_(not I2.providedBy(D()))
+
+ self.assert_(not I2.providedBy(E()))
+
+ def testDeferredClass(self):
+ a = A()
+ self.assertRaises(BrokenImplementation, a.ma)
+
+
+ def testInterfaceExtendsInterface(self):
+ self.assert_(BazInterface.extends(BobInterface))
+ self.assert_(BazInterface.extends(BarInterface))
+ self.assert_(BazInterface.extends(FunInterface))
+ self.assert_(not BobInterface.extends(FunInterface))
+ self.assert_(not BobInterface.extends(BarInterface))
+ self.assert_(BarInterface.extends(FunInterface))
+ self.assert_(not BarInterface.extends(BazInterface))
+
+ def testVerifyImplementation(self):
+ from zope.interface.verify import verifyClass
+ self.assert_(verifyClass(FooInterface, Foo))
+ self.assert_(Interface.providedBy(I1))
+
+ def test_names(self):
+ names = list(_I2.names()); names.sort()
+ self.assertEqual(names, ['f21', 'f22', 'f23'])
+ names = list(_I2.names(all=True)); names.sort()
+ self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+ def test_namesAndDescriptions(self):
+ names = [nd[0] for nd in _I2.namesAndDescriptions()]; names.sort()
+ self.assertEqual(names, ['f21', 'f22', 'f23'])
+ names = [nd[0] for nd in _I2.namesAndDescriptions(1)]; names.sort()
+ self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+ for name, d in _I2.namesAndDescriptions(1):
+ self.assertEqual(name, d.__name__)
+
+ def test_getDescriptionFor(self):
+ self.assertEqual(_I2.getDescriptionFor('f11').__name__, 'f11')
+ self.assertEqual(_I2.getDescriptionFor('f22').__name__, 'f22')
+ self.assertEqual(_I2.queryDescriptionFor('f33', self), self)
+ self.assertRaises(KeyError, _I2.getDescriptionFor, 'f33')
+
+ def test___getitem__(self):
+ self.assertEqual(_I2['f11'].__name__, 'f11')
+ self.assertEqual(_I2['f22'].__name__, 'f22')
+ self.assertEqual(_I2.get('f33', self), self)
+ self.assertRaises(KeyError, _I2.__getitem__, 'f33')
+
+ def test___contains__(self):
+ self.failUnless('f11' in _I2)
+ self.failIf('f33' in _I2)
+
+ def test___iter__(self):
+ names = list(iter(_I2))
+ names.sort()
+ self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+ def testAttr(self):
+ description = _I2.getDescriptionFor('a1')
+ self.assertEqual(description.__name__, 'a1')
+ self.assertEqual(description.__doc__, 'This is an attribute')
+
+ def testFunctionAttributes(self):
+ # Make sure function attributes become tagged values.
+ meth = _I1['f12']
+ self.assertEqual(meth.getTaggedValue('optional'), 1)
+
+ def testInvariant(self):
+ # set up
+ o = InvariantC()
+ directlyProvides(o, IInvariant)
+ # a helper
+ def errorsEqual(self, o, error_len, error_msgs, interface=None):
+ if interface is None:
+ interface = IInvariant
+ self.assertRaises(Invalid, interface.validateInvariants, o)
+ e = []
+ try:
+ interface.validateInvariants(o, e)
+ except Invalid, error:
+ self.assertEquals(error.args[0], e)
+ else:
+ self._assert(0) # validateInvariants should always raise
+ # Invalid
+ self.assertEquals(len(e), error_len)
+ msgs = [error.args[0] for error in e]
+ msgs.sort()
+ for msg in msgs:
+ self.assertEquals(msg, error_msgs.pop(0))
+ # the tests
+ self.assertEquals(IInvariant.getTaggedValue('invariants'),
+ [ifFooThenBar])
+ self.assertEquals(IInvariant.validateInvariants(o), None)
+ o.bar = 27
+ self.assertEquals(IInvariant.validateInvariants(o), None)
+ o.foo = 42
+ self.assertEquals(IInvariant.validateInvariants(o), None)
+ del o.bar
+ errorsEqual(self, o, 1, ['If Foo, then Bar!'])
+ # nested interfaces with invariants:
+ self.assertEquals(ISubInvariant.getTaggedValue('invariants'),
+ [BarGreaterThanFoo])
+ o = InvariantC()
+ directlyProvides(o, ISubInvariant)
+ o.foo = 42
+ # even though the interface has changed, we should still only have one
+ # error.
+ errorsEqual(self, o, 1, ['If Foo, then Bar!'], ISubInvariant)
+ # however, if we set foo to 0 (Boolean False) and bar to a negative
+ # number then we'll get the new error
+ o.foo = 2
+ o.bar = 1
+ errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'],
+ ISubInvariant)
+ # and if we set foo to a positive number and boo to 0, we'll
+ # get both errors!
+ o.foo = 1
+ o.bar = 0
+ errorsEqual(self, o, 2, ['If Foo, then Bar!',
+ 'Please, Boo MUST be greater than Foo!'],
+ ISubInvariant)
+ # for a happy ending, we'll make the invariants happy
+ o.foo = 1
+ o.bar = 2
+ self.assertEquals(IInvariant.validateInvariants(o), None) # woohoo
+ # now we'll do two invariants on the same interface,
+ # just to make sure that a small
+ # multi-invariant interface is at least minimally tested.
+ o = InvariantC()
+ directlyProvides(o, IInvariant)
+ o.foo = 42
+ old_invariants = IInvariant.getTaggedValue('invariants')
+ invariants = old_invariants[:]
+ invariants.append(BarGreaterThanFoo) # if you really need to mutate,
+ # then this would be the way to do it. Probably a bad idea, though. :-)
+ IInvariant.setTaggedValue('invariants', invariants)
+ #
+ # even though the interface has changed, we should still only have one
+ # error.
+ errorsEqual(self, o, 1, ['If Foo, then Bar!'])
+ # however, if we set foo to 0 (Boolean False) and bar to a negative
+ # number then we'll get the new error
+ o.foo = 2
+ o.bar = 1
+ errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'])
+ # and if we set foo to a positive number and boo to 0, we'll
+ # get both errors!
+ o.foo = 1
+ o.bar = 0
+ errorsEqual(self, o, 2, ['If Foo, then Bar!',
+ 'Please, Boo MUST be greater than Foo!'])
+ # for another happy ending, we'll make the invariants happy again
+ o.foo = 1
+ o.bar = 2
+ self.assertEquals(IInvariant.validateInvariants(o), None) # bliss
+ # clean up
+ IInvariant.setTaggedValue('invariants', old_invariants)
+
+ def test___doc___element(self):
+ class I(Interface):
+ "xxx"
+
+ self.assertEqual(I.__doc__, "xxx")
+ self.assertEqual(list(I), [])
+
+ class I(Interface):
+ "xxx"
+
+ __doc__ = Attribute('the doc')
+
+ self.assertEqual(I.__doc__, "")
+ self.assertEqual(list(I), ['__doc__'])
+
+ def testIssue228(self):
+ # Test for http://collector.zope.org/Zope3-dev/228
+ class I(Interface):
+ "xxx"
+ class Bad:
+ __providedBy__ = None
+ # Old style classes don't have a '__class__' attribute
+ self.failUnlessRaises(AttributeError, I.providedBy, Bad)
+
+
+class _I1(Interface):
+
+ a1 = Attribute("This is an attribute")
+
+ def f11(): pass
+ def f12(): pass
+ f12.optional = 1
+
+class _I1_(_I1): pass
+class _I1__(_I1_): pass
+
+class _I2(_I1__):
+ def f21(): pass
+ def f22(): pass
+ f23 = f22
+
+
+
+if sys.version_info >= (2, 4):
+ def test_invariant_as_decorator():
+ """Invaiants can be deined in line
+
+ >>> class IRange(interface.Interface):
+ ... min = interface.Attribute("Lower bound")
+ ... max = interface.Attribute("Upper bound")
+ ...
+ ... @interface.invariant
+ ... def range_invariant(ob):
+ ... if ob.max < ob.min:
+ ... raise Invalid('max < min')
+
+
+ >>> class Range(object):
+ ... interface.implements(IRange)
+ ...
+ ... def __init__(self, min, max):
+ ... self.min, self.max = min, max
+
+ >>> IRange.validateInvariants(Range(1,2))
+ >>> IRange.validateInvariants(Range(1,1))
+ >>> IRange.validateInvariants(Range(2,1))
+ Traceback (most recent call last):
+ ...
+ Invalid: max < min
+
+
+ """
+
+def duplicate_bases_management():
+ """
+There was a bug that surfaced when an interface was repeated in
+a set of bases and the bases were changed:
+
+ >>> class I(interface.Interface):
+ ... pass
+
+ >>> class I2(I, I):
+ ... pass
+
+ >>> I2.__bases__ = (I,)
+
+
+"""
+
+def test_suite():
+ from zope.testing import doctest
+ suite = unittest.makeSuite(InterfaceTests)
+ suite.addTest(doctest.DocTestSuite("zope.interface.interface"))
+ if sys.version_info >= (2, 4):
+ suite.addTest(doctest.DocTestSuite())
+ suite.addTest(doctest.DocFileSuite(
+ '../README.txt',
+ globs={'__name__': '__main__'},
+ optionflags=doctest.NORMALIZE_WHITESPACE,
+ ))
+ suite.addTest(doctest.DocFileSuite(
+ '../README.ru.txt',
+ globs={'__name__': '__main__'},
+ optionflags=doctest.NORMALIZE_WHITESPACE,
+ ))
+ return suite
+
+def main():
+ unittest.TextTestRunner().run(test_suite())
+
+if __name__=="__main__":
+ main()
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_interface.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_odd_declarations.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_odd_declarations.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_odd_declarations.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,204 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test interface declarations against ExtensionClass-like classes.
+
+These tests are to make sure we do something sane in the presense of
+classic ExtensionClass classes and instances.
+
+$Id: test_odd_declarations.py 40836 2005-12-16 22:40:51Z benji_york $
+"""
+import unittest, odd
+from zope.interface import Interface, implements, implementsOnly
+from zope.interface import directlyProvides, providedBy, directlyProvidedBy
+from zope.interface import classImplements, classImplementsOnly, implementedBy
+
+class I1(Interface): pass
+class I2(Interface): pass
+class I3(Interface): pass
+class I31(I3): pass
+class I4(Interface): pass
+class I5(Interface): pass
+
+class Odd(object): __metaclass__ = odd.MetaClass
+
+class B(Odd): __implemented__ = I2
+
+
+# TODO: We are going to need more magic to make classProvides work with odd
+# classes. This will work in the next iteration. For now, we'll use
+# a different mechanism.
+
+# from zope.interface import classProvides
+
+class A(Odd):
+ implements(I1)
+
+class C(A, B):
+ implements(I31)
+
+
+class Test(unittest.TestCase):
+
+ def test_ObjectSpecification(self):
+ c = C()
+ directlyProvides(c, I4)
+ self.assertEqual([i.getName() for i in providedBy(c)],
+ ['I4', 'I31', 'I1', 'I2']
+ )
+ self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+ ['I4', 'I31', 'I3', 'I1', 'I2', 'Interface']
+ )
+ self.assert_(I1 in providedBy(c))
+ self.failIf(I3 in providedBy(c))
+ self.assert_(providedBy(c).extends(I3))
+ self.assert_(providedBy(c).extends(I31))
+ self.failIf(providedBy(c).extends(I5))
+
+ class COnly(A, B):
+ implementsOnly(I31)
+
+ class D(COnly):
+ implements(I5)
+
+ classImplements(D, I5)
+
+ c = D()
+ directlyProvides(c, I4)
+ self.assertEqual([i.getName() for i in providedBy(c)],
+ ['I4', 'I5', 'I31'])
+ self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+ ['I4', 'I5', 'I31', 'I3', 'Interface'])
+ self.failIf(I1 in providedBy(c))
+ self.failIf(I3 in providedBy(c))
+ self.assert_(providedBy(c).extends(I3))
+ self.failIf(providedBy(c).extends(I1))
+ self.assert_(providedBy(c).extends(I31))
+ self.assert_(providedBy(c).extends(I5))
+
+ class COnly(A, B): __implemented__ = I31
+ class D(COnly):
+ implements(I5)
+
+ classImplements(D, I5)
+ c = D()
+ directlyProvides(c, I4)
+ self.assertEqual([i.getName() for i in providedBy(c)],
+ ['I4', 'I5', 'I31'])
+ self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+ ['I4', 'I5', 'I31', 'I3', 'Interface'])
+ self.failIf(I1 in providedBy(c))
+ self.failIf(I3 in providedBy(c))
+ self.assert_(providedBy(c).extends(I3))
+ self.failIf(providedBy(c).extends(I1))
+ self.assert_(providedBy(c).extends(I31))
+ self.assert_(providedBy(c).extends(I5))
+
+ def test_classImplements(self):
+ class A(Odd):
+ implements(I3)
+
+ class B(Odd):
+ implements(I4)
+
+ class C(A, B):
+ pass
+ classImplements(C, I1, I2)
+ self.assertEqual([i.getName() for i in implementedBy(C)],
+ ['I1', 'I2', 'I3', 'I4'])
+ classImplements(C, I5)
+ self.assertEqual([i.getName() for i in implementedBy(C)],
+ ['I1', 'I2', 'I5', 'I3', 'I4'])
+
+ def test_classImplementsOnly(self):
+ class A(Odd):
+ implements(I3)
+
+ class B(Odd):
+ implements(I4)
+
+ class C(A, B):
+ pass
+ classImplementsOnly(C, I1, I2)
+ self.assertEqual([i.__name__ for i in implementedBy(C)],
+ ['I1', 'I2'])
+
+
+ def test_directlyProvides(self):
+ class IA1(Interface): pass
+ class IA2(Interface): pass
+ class IB(Interface): pass
+ class IC(Interface): pass
+ class A(Odd):
+ implements(IA1, IA2)
+
+ class B(Odd):
+ implements(IB)
+
+ class C(A, B):
+ implements(IC)
+
+
+ ob = C()
+ directlyProvides(ob, I1, I2)
+ self.assert_(I1 in providedBy(ob))
+ self.assert_(I2 in providedBy(ob))
+ self.assert_(IA1 in providedBy(ob))
+ self.assert_(IA2 in providedBy(ob))
+ self.assert_(IB in providedBy(ob))
+ self.assert_(IC in providedBy(ob))
+
+ directlyProvides(ob, directlyProvidedBy(ob)-I2)
+ self.assert_(I1 in providedBy(ob))
+ self.failIf(I2 in providedBy(ob))
+ self.failIf(I2 in providedBy(ob))
+ directlyProvides(ob, directlyProvidedBy(ob), I2)
+ self.assert_(I2 in providedBy(ob))
+
+ def test_directlyProvides_fails_for_odd_class(self):
+ self.assertRaises(TypeError, directlyProvides, C, I5)
+
+ # see above
+ def TODO_test_classProvides_fails_for_odd_class(self):
+ try:
+ class A(Odd):
+ classProvides(I1)
+ except TypeError:
+ pass # Sucess
+ self.assert_(False,
+ "Shouldn't be able to use directlyProvides on odd class."
+ )
+
+ def test_implementedBy(self):
+ class I2(I1): pass
+
+ class C1(Odd):
+ implements(I2)
+
+ class C2(C1):
+ implements(I3)
+
+ self.assertEqual([i.getName() for i in implementedBy(C2)],
+ ['I3', 'I2'])
+
+
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(Test))
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_odd_declarations.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_sorting.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_sorting.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_sorting.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,49 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test interface sorting
+
+$Id: test_sorting.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+from unittest import TestCase, TestSuite, main, makeSuite
+
+from zope.interface import Interface
+
+class I1(Interface): pass
+class I2(I1): pass
+class I3(I1): pass
+class I4(Interface): pass
+class I5(I4): pass
+class I6(I2): pass
+
+
+class Test(TestCase):
+
+ def test(self):
+ l = [I1, I3, I5, I6, I4, I2]
+ l.sort()
+ self.assertEqual(l, [I1, I2, I3, I4, I5, I6])
+
+ def test_w_None(self):
+ l = [I1, None, I3, I5, None, I6, I4, I2]
+ l.sort()
+ self.assertEqual(l, [I1, I2, I3, I4, I5, I6, None, None])
+
+def test_suite():
+ return TestSuite((
+ makeSuite(Test),
+ ))
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_sorting.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_verify.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_verify.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_verify.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,196 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interface Verify tests
+
+$Id: test_verify.py 26866 2004-08-02 20:57:00Z jim $
+"""
+from zope.interface import Interface, implements, classImplements, Attribute
+from zope.interface.verify import verifyClass, verifyObject
+from zope.interface.exceptions import DoesNotImplement, BrokenImplementation
+from zope.interface.exceptions import BrokenMethodImplementation
+
+import unittest
+
+class Test(unittest.TestCase):
+
+ def testNotImplemented(self):
+
+ class C(object): pass
+
+ class I(Interface): pass
+
+ self.assertRaises(DoesNotImplement, verifyClass, I, C)
+
+ classImplements(C, I)
+
+ verifyClass(I, C)
+
+ def testMissingAttr(self):
+
+ class I(Interface):
+ def f(): pass
+
+ class C(object):
+ implements(I)
+
+ self.assertRaises(BrokenImplementation, verifyClass, I, C)
+
+ C.f=lambda self: None
+
+ verifyClass(I, C)
+
+ def testMissingAttr_with_Extended_Interface(self):
+
+ class II(Interface):
+ def f():
+ pass
+
+ class I(II):
+ pass
+
+ class C(object):
+ implements(I)
+
+ self.assertRaises(BrokenImplementation, verifyClass, I, C)
+
+ C.f=lambda self: None
+
+ verifyClass(I, C)
+
+ def testWrongArgs(self):
+
+ class I(Interface):
+ def f(a): pass
+
+ class C(object):
+ def f(self, b): pass
+
+ implements(I)
+
+ # We no longer require names to match.
+ #self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a: None
+
+ verifyClass(I, C)
+
+ C.f=lambda self, **kw: None
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a, *args: None
+
+ verifyClass(I, C)
+
+ C.f=lambda self, a, *args, **kw: None
+
+ verifyClass(I, C)
+
+ C.f=lambda self, *args: None
+
+ verifyClass(I, C)
+
+ def testExtraArgs(self):
+
+ class I(Interface):
+ def f(a): pass
+
+ class C(object):
+ def f(self, a, b): pass
+
+ implements(I)
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a: None
+
+ verifyClass(I, C)
+
+ C.f=lambda self, a, b=None: None
+
+ verifyClass(I, C)
+
+ def testNoVar(self):
+
+ class I(Interface):
+ def f(a, *args): pass
+
+ class C(object):
+ def f(self, a): pass
+
+ implements(I)
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a, *foo: None
+
+ verifyClass(I, C)
+
+ def testNoKW(self):
+
+ class I(Interface):
+ def f(a, **args): pass
+
+ class C(object):
+ def f(self, a): pass
+
+ implements(I)
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a, **foo: None
+
+ verifyClass(I, C)
+
+ def testModule(self):
+
+ from zope.interface.tests.ifoo import IFoo
+ from zope.interface.tests import dummy
+
+ verifyObject(IFoo, dummy)
+
+ def testMethodForAttr(self):
+
+ class IFoo(Interface):
+ foo = Attribute("The foo Attribute")
+
+
+ class Foo:
+ implements(IFoo)
+
+ def foo(self):
+ pass
+
+ verifyClass(IFoo, Foo)
+
+ def testNonMethodForMethod(self):
+
+ class IBar(Interface):
+ def foo():
+ pass
+
+ class Bar:
+ implements(IBar)
+
+ foo = 1
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, IBar, Bar)
+
+
+def test_suite():
+ loader=unittest.TestLoader()
+ return loader.loadTestsFromTestCase(Test)
+
+if __name__=='__main__':
+ unittest.TextTestRunner().run(test_suite())
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_verify.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/tests/unitfixtures.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/unitfixtures.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/unitfixtures.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,142 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Unit Test Fixtures
+
+$Id: unitfixtures.py 26898 2004-08-04 09:38:12Z hdima $
+"""
+from zope.interface import Interface, invariant
+from zope.interface.interface import Attribute
+from zope.interface.exceptions import Invalid
+
+class mytest(Interface):
+ pass
+
+class C(object):
+ def m1(self, a, b):
+ "return 1"
+ return 1
+
+ def m2(self, a, b):
+ "return 2"
+ return 2
+
+# testInstancesOfClassImplements
+
+# YAGNI IC=Interface.impliedInterface(C)
+class IC(Interface):
+ def m1(a, b):
+ "return 1"
+
+ def m2(a, b):
+ "return 2"
+
+
+
+C.__implemented__=IC
+
+class I1(Interface):
+ def ma():
+ "blah"
+
+class I2(I1): pass
+
+class I3(Interface): pass
+
+class I4(Interface): pass
+
+class A(I1.deferred()):
+ __implemented__=I1
+
+class B(object):
+ __implemented__=I2, I3
+
+class D(A, B): pass
+
+class E(A, B):
+ __implemented__ = A.__implemented__, C.__implemented__
+
+
+class FooInterface(Interface):
+ """ This is an Abstract Base Class """
+
+ foobar = Attribute("fuzzed over beyond all recognition")
+
+ def aMethod(foo, bar, bingo):
+ """ This is aMethod """
+
+ def anotherMethod(foo=6, bar="where you get sloshed", bingo=(1,3,)):
+ """ This is anotherMethod """
+
+ def wammy(zip, *argues):
+ """ yadda yadda """
+
+ def useless(**keywords):
+ """ useless code is fun! """
+
+class Foo(object):
+ """ A concrete class """
+
+ __implemented__ = FooInterface,
+
+ foobar = "yeah"
+
+ def aMethod(self, foo, bar, bingo):
+ """ This is aMethod """
+ return "barf!"
+
+ def anotherMethod(self, foo=6, bar="where you get sloshed", bingo=(1,3,)):
+ """ This is anotherMethod """
+ return "barf!"
+
+ def wammy(self, zip, *argues):
+ """ yadda yadda """
+ return "barf!"
+
+ def useless(self, **keywords):
+ """ useless code is fun! """
+ return "barf!"
+
+foo_instance = Foo()
+
+class Blah(object):
+ pass
+
+new = Interface.__class__
+FunInterface = new('FunInterface')
+BarInterface = new('BarInterface', [FunInterface])
+BobInterface = new('BobInterface')
+BazInterface = new('BazInterface', [BobInterface, BarInterface])
+
+# fixtures for invariant tests
+def ifFooThenBar(obj):
+ if getattr(obj, 'foo', None) and not getattr(obj, 'bar', None):
+ raise Invalid('If Foo, then Bar!')
+class IInvariant(Interface):
+ foo = Attribute('foo')
+ bar = Attribute('bar; must eval to Boolean True if foo does')
+ invariant(ifFooThenBar)
+def BarGreaterThanFoo(obj):
+ foo = getattr(obj, 'foo', None)
+ bar = getattr(obj, 'bar', None)
+ if foo is not None and isinstance(foo, type(bar)):
+ # type checking should be handled elsewhere (like, say,
+ # schema); these invariants should be intra-interface
+ # constraints. This is a hacky way to do it, maybe, but you
+ # get the idea
+ if not bar > foo:
+ raise Invalid('Please, Boo MUST be greater than Foo!')
+class ISubInvariant(IInvariant):
+ invariant(BarGreaterThanFoo)
+class InvariantC(object):
+ pass
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/tests/unitfixtures.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope/interface/verify.py
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/verify.py 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/verify.py 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,111 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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
+
+$Id: verify.py 37426 2005-07-26 06:24:15Z hdima $
+"""
+from zope.interface.exceptions import BrokenImplementation, DoesNotImplement
+from zope.interface.exceptions import BrokenMethodImplementation
+from types import FunctionType, MethodType
+from zope.interface.interface import fromMethod, fromFunction, Method
+
+# This will be monkey-patched when running under Zope 2, so leave this
+# here:
+MethodTypes = (MethodType, )
+
+
+def _verify(iface, candidate, tentative=0, vtype=None):
+ """Verify that 'candidate' might correctly implements 'iface'.
+
+ This involves:
+
+ o Making sure the candidate defines all the necessary methods
+
+ o Making sure the methods have the correct signature
+
+ o Making sure the candidate asserts that it implements the interface
+
+ Note that this isn't the same as verifying that the class does
+ implement the interface.
+
+ If optional tentative is true, suppress the "is implemented by" test.
+ """
+
+ if vtype == 'c':
+ tester = iface.implementedBy
+ else:
+ tester = iface.providedBy
+
+ if not tentative and not tester(candidate):
+ raise DoesNotImplement(iface)
+
+ # Here the `desc` is either an `Attribute` or `Method` instance
+ for name, desc in iface.namesAndDescriptions(1):
+ if not hasattr(candidate, name):
+ if (not isinstance(desc, Method)) and vtype == 'c':
+ # We can't verify non-methods on classes, since the
+ # class may provide attrs in it's __init__.
+ continue
+
+ raise BrokenImplementation(iface, name)
+
+ attr = getattr(candidate, name)
+ if not isinstance(desc, Method):
+ # If it's not a method, there's nothing else we can test
+ continue
+
+ if isinstance(attr, FunctionType):
+ # should never get here, since classes should not provide functions
+ meth = fromFunction(attr, iface, name=name)
+ elif (isinstance(attr, MethodTypes)
+ and type(attr.im_func) is FunctionType):
+ meth = fromMethod(attr, iface, name)
+ else:
+ if not callable(attr):
+ raise BrokenMethodImplementation(name, "Not a method")
+ # sigh, it's callable, but we don't know how to intrspect it, so
+ # we have to give it a pass.
+ continue
+
+ # Make sure that the required and implemented method signatures are
+ # the same.
+ desc = desc.getSignatureInfo()
+ meth = meth.getSignatureInfo()
+
+ mess = _incompat(desc, meth)
+ if mess:
+ raise BrokenMethodImplementation(name, mess)
+
+ return True
+
+def verifyClass(iface, candidate, tentative=0):
+ return _verify(iface, candidate, tentative, vtype='c')
+
+def verifyObject(iface, candidate, tentative=0):
+ return _verify(iface, candidate, tentative, vtype='o')
+
+def _incompat(required, implemented):
+ #if (required['positional'] !=
+ # implemented['positional'][:len(required['positional'])]
+ # and implemented['kwargs'] is None):
+ # return 'imlementation has different argument names'
+ if len(implemented['required']) > len(required['required']):
+ return 'implementation requires too many arguments'
+ if ((len(implemented['positional']) < len(required['positional']))
+ and not implemented['varargs']):
+ return "implementation doesn't allow enough arguments"
+ if required['kwargs'] and not implemented['kwargs']:
+ return "implementation doesn't support keyword arguments"
+ if required['varargs'] and not implemented['varargs']:
+ return "implementation doesn't support variable arguments"
Property changes on: python-zope.interface/branches/upstream/current/src/zope/interface/verify.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/PKG-INFO
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/PKG-INFO 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/PKG-INFO 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: zope.interface
+Version: 3.3.0b2
+Summary: Zope 3 Interface Infrastructure
+Home-page: http://svn.zope.org/zope.interface
+Author: Zope Corporation and Contributors
+Author-email: zope3-dev at zope.org
+License: ZPL 2.1
+Description: UNKNOWN
+Platform: UNKNOWN
Added: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,57 @@
+CHANGES.txt
+INSTALL.txt
+MANIFEST.in
+README.txt
+setup.py
+src/zope/__init__.py
+src/zope.interface.egg-info/PKG-INFO
+src/zope.interface.egg-info/SOURCES.txt
+src/zope.interface.egg-info/dependency_links.txt
+src/zope.interface.egg-info/native_libs.txt
+src/zope.interface.egg-info/not-zip-safe
+src/zope.interface.egg-info/top_level.txt
+src/zope/interface/DEPENDENCIES.cfg
+src/zope/interface/PUBLICATION.cfg
+src/zope/interface/README.ru.txt
+src/zope/interface/README.txt
+src/zope/interface/SETUP.cfg
+src/zope/interface/__init__.py
+src/zope/interface/_flatten.py
+src/zope/interface/_zope_interface_coptimizations.c
+src/zope/interface/adapter.py
+src/zope/interface/adapter.txt
+src/zope/interface/advice.py
+src/zope/interface/declarations.py
+src/zope/interface/document.py
+src/zope/interface/exceptions.py
+src/zope/interface/human.ru.txt
+src/zope/interface/human.txt
+src/zope/interface/interface.py
+src/zope/interface/interfaces.py
+src/zope/interface/ro.py
+src/zope/interface/verify.py
+src/zope/interface/common/__init__.py
+src/zope/interface/common/idatetime.py
+src/zope/interface/common/interfaces.py
+src/zope/interface/common/mapping.py
+src/zope/interface/common/sequence.py
+src/zope/interface/common/tests/__init__.py
+src/zope/interface/common/tests/basemapping.py
+src/zope/interface/common/tests/test_idatetime.py
+src/zope/interface/tests/__init__.py
+src/zope/interface/tests/dummy.py
+src/zope/interface/tests/foodforthought.txt
+src/zope/interface/tests/ifoo.py
+src/zope/interface/tests/m1.py
+src/zope/interface/tests/m2.py
+src/zope/interface/tests/odd.py
+src/zope/interface/tests/test_adapter.py
+src/zope/interface/tests/test_advice.py
+src/zope/interface/tests/test_declarations.py
+src/zope/interface/tests/test_document.py
+src/zope/interface/tests/test_element.py
+src/zope/interface/tests/test_interface.py
+src/zope/interface/tests/test_odd_declarations.py
+src/zope/interface/tests/test_sorting.py
+src/zope/interface/tests/test_verify.py
+src/zope/interface/tests/unitfixtures.py
Property changes on: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/dependency_links.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/dependency_links.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/dependency_links.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1 @@
+
Property changes on: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/dependency_links.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/native_libs.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/native_libs.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/native_libs.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1 @@
+zope/interface/_zope_interface_coptimizations.so
Property changes on: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/native_libs.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/not-zip-safe
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/not-zip-safe 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/not-zip-safe 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1 @@
+
Added: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/top_level.txt
===================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/top_level.txt 2006-10-29 19:27:20 UTC (rev 373)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/top_level.txt 2006-10-29 19:28:25 UTC (rev 374)
@@ -0,0 +1,2 @@
+zope
+_zope_interface_coptimizations
Property changes on: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/top_level.txt
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the pkg-zope-commits
mailing list