r956 - in /python-zope.interface/branches/upstream/current: ./ src/zope.interface.egg-info/ src/zope/ src/zope/interface/ src/zope/interface/common/ src/zope/interface/common/tests/ src/zope/interface/tests/
jinty-guest at users.alioth.debian.org
jinty-guest at users.alioth.debian.org
Thu Jul 19 08:44:24 UTC 2007
Author: jinty-guest
Date: Thu Jul 19 08:44:23 2007
New Revision: 956
URL: http://svn.debian.org/wsvn/pkg-zope/?sc=1&rev=956
Log:
[svn-upgrade] Integrating new upstream version, python-zope.interface (3.4.0b1)
Added:
python-zope.interface/branches/upstream/current/bootstrap.py (with props)
python-zope.interface/branches/upstream/current/buildout.cfg
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/namespace_packages.txt (with props)
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/requires.txt (with props)
python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_import_interfaces.py (with props)
Removed:
python-zope.interface/branches/upstream/current/INSTALL.txt
python-zope.interface/branches/upstream/current/MANIFEST.in
python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/native_libs.txt
Modified:
python-zope.interface/branches/upstream/current/CHANGES.txt
python-zope.interface/branches/upstream/current/PKG-INFO
python-zope.interface/branches/upstream/current/README.txt
python-zope.interface/branches/upstream/current/setup.py
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/__init__.py
python-zope.interface/branches/upstream/current/src/zope/interface/README.txt
python-zope.interface/branches/upstream/current/src/zope/interface/__init__.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/common/interfaces.py
python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py
python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py
python-zope.interface/branches/upstream/current/src/zope/interface/interface.py
python-zope.interface/branches/upstream/current/src/zope/interface/ro.py
python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py
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/test_adapter.py
Modified: python-zope.interface/branches/upstream/current/CHANGES.txt
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/CHANGES.txt?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/CHANGES.txt (original)
+++ python-zope.interface/branches/upstream/current/CHANGES.txt Thu Jul 19 08:44:23 2007
@@ -1,20 +1,75 @@
-zope.interface Package Changelog
-================================
+zope.interface Package Changes
+******************************
+===========================================
+3.4.0b3 (2007/05/22)
+===========================================
+
+Bug Fixes
+=========
+
+- Objects with picky custom comparison methods couldn't be added to
+ component registries. Now, when checking whether an object is
+ already registered, identity comparison is used.
+
+===========================================
+3.3.0.1 (2007/01/03)
+===========================================
+
+Bug Fixes
+=========
+
+- Made a reference to OverflowWarning, which disappeared in Python
+ 2.5, conditional.
+
+===========================================
+3.3.0 (2007/01/03)
+===========================================
+
+New Features
+============
+
+- The adapter-lookup algorithim was refactored to make it
+ much simpler and faster.
+
+ Also, more of the adapter-lookup logic is implemented in C, making
+ debugging of application code easier, since there is less
+ infrastructre code to step through.
+
+- We now treat objects without interafce declarations as if they
+ declared that they provide zope.interface.Interface.
+
+- There are a number of richer new adapter-registration interfaces
+ that provide greater control and introspection.
+
+- Added a new interface decorator to zope.interface that allows the
+ setting of tagged values on an interface at definition time (see
+ zope.interface.taggedValue).
+
+Bug Fixes
+=========
+
+- A bug in multi-adapter lookup sometimes caused incorrect adapters to
+ be returned.
+
+
+===========================================
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.
@@ -22,8 +77,9 @@
- 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.
@@ -37,8 +93,9 @@
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.
@@ -47,8 +104,9 @@
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.
Modified: python-zope.interface/branches/upstream/current/PKG-INFO
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/PKG-INFO?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/PKG-INFO (original)
+++ python-zope.interface/branches/upstream/current/PKG-INFO Thu Jul 19 08:44:23 2007
@@ -1,10 +1,1649 @@
Metadata-Version: 1.0
Name: zope.interface
-Version: 3.3.0b2
+Version: 3.4.0b1
Summary: Zope 3 Interface Infrastructure
-Home-page: http://svn.zope.org/zope.interface
+Home-page: http://www.python.org/pypi/zope.interface
Author: Zope Corporation and Contributors
Author-email: zope3-dev at zope.org
License: ZPL 2.1
-Description: UNKNOWN
+Description: ***************
+ Zope Interfaces
+ ***************
+
+ .. contents::
+
+ Interfaces are a mechanism for labeling objects as conforming to a given
+ API or contract.
+
+ zope.interface Package Changes
+ ******************************
+
+ ===========================================
+ 3.4.0b3 (2007/05/22)
+ ===========================================
+
+ Bug Fixes
+ =========
+
+ - Objects with picky custom comparison methods couldn't be added to
+ component registries. Now, when checking whether an object is
+ already registered, identity comparison is used.
+
+ ===========================================
+ 3.3.0.1 (2007/01/03)
+ ===========================================
+
+ Bug Fixes
+ =========
+
+ - Made a reference to OverflowWarning, which disappeared in Python
+ 2.5, conditional.
+
+ ===========================================
+ 3.3.0 (2007/01/03)
+ ===========================================
+
+ New Features
+ ============
+
+ - The adapter-lookup algorithim was refactored to make it
+ much simpler and faster.
+
+ Also, more of the adapter-lookup logic is implemented in C, making
+ debugging of application code easier, since there is less
+ infrastructre code to step through.
+
+ - We now treat objects without interafce declarations as if they
+ declared that they provide zope.interface.Interface.
+
+ - There are a number of richer new adapter-registration interfaces
+ that provide greater control and introspection.
+
+ - Added a new interface decorator to zope.interface that allows the
+ setting of tagged values on an interface at definition time (see
+ zope.interface.taggedValue).
+
+ Bug Fixes
+ =========
+
+ - A bug in multi-adapter lookup sometimes caused incorrect adapters to
+ be returned.
+
+
+ ===========================================
+ 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.
+
+ Detailed Documentation
+ **********************
+
+ ==========
+ Interfaces
+ ==========
+
+ Interfaces are objects that specify (document) the external behavior
+ of objects that "provide" them. An interface specifies behavior
+ through:
+
+ - Informal documentation in a doc string
+
+ - Attribute definitions
+
+ - Invariants, which are conditions that must hold for objects that
+ provide the interface
+
+ Attribute definitions specify specific attributes. They define the
+ attribute name and provide documentation and constraints of attribute
+ values. Attribute definitions can take a number of forms, as we'll
+ see below.
+
+ Defining interfaces
+ ===================
+
+ Interfaces are defined using Python class statements:
+
+ >>> import zope.interface
+ >>> class IFoo(zope.interface.Interface):
+ ... """Foo blah blah"""
+ ...
+ ... x = zope.interface.Attribute("""X blah blah""")
+ ...
+ ... def bar(q, r=None):
+ ... """bar blah blah"""
+
+ In the example above, we've created an interface, `IFoo`. We
+ subclassed `zope.interface.Interface`, which is an ancestor interface for
+ all interfaces, much as `object` is an ancestor of all new-style
+ classes [#create]_. The interface is not a class, it's an Interface,
+ an instance of `InterfaceClass`::
+
+ >>> type(IFoo)
+ <class 'zope.interface.interface.InterfaceClass'>
+
+ We can ask for the interface's documentation::
+
+ >>> IFoo.__doc__
+ 'Foo blah blah'
+
+ and its name::
+
+ >>> IFoo.__name__
+ 'IFoo'
+
+ and even its module::
+
+ >>> IFoo.__module__
+ '__main__'
+
+ The interface defined two attributes:
+
+ `x`
+ This is the simplest form of attribute definition. It has a name
+ and a doc string. It doesn't formally specify anything else.
+
+ `bar`
+ This is a method. A method is defined via a function definition. A
+ method is simply an attribute constrained to be a callable with a
+ particular signature, as provided by the function definition.
+
+ Note that `bar` doesn't take a `self` argument. Interfaces document
+ how an object is *used*. When calling instance methods, you don't
+ pass a `self` argument, so a `self` argument isn't included in the
+ interface signature. The `self` argument in instance methods is
+ really an implementation detail of Python instances. Other objects,
+ besides instances can provide interfaces and their methods might not
+ be instance methods. For example, modules can provide interfaces and
+ their methods are usually just functions. Even instances can have
+ methods that are not instance methods.
+
+ You can access the attributes defined by an interface using mapping
+ syntax::
+
+ >>> x = IFoo['x']
+ >>> type(x)
+ <class 'zope.interface.interface.Attribute'>
+ >>> x.__name__
+ 'x'
+ >>> x.__doc__
+ 'X blah blah'
+
+ >>> IFoo.get('x').__name__
+ 'x'
+
+ >>> IFoo.get('y')
+
+ You can use `in` to determine if an interface defines a name::
+
+ >>> 'x' in IFoo
+ True
+
+ You can iterate over interfaces to get the names they define::
+
+ >>> names = list(IFoo)
+ >>> names.sort()
+ >>> names
+ ['bar', 'x']
+
+ Remember that interfaces aren't classes. You can't access attribute
+ definitions as attributes of interfaces::
+
+ >>> IFoo.x
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ AttributeError: 'InterfaceClass' object has no attribute 'x'
+
+ Methods provide access to the method signature::
+
+ >>> bar = IFoo['bar']
+ >>> bar.getSignatureString()
+ '(q, r=None)'
+
+ TODO
+ Methods really should have a better API. This is something that
+ needs to be improved.
+
+ Declaring interfaces
+ ====================
+
+ Having defined interfaces, we can *declare* that objects provide
+ them. Before we describe the details, lets define some terms:
+
+ *provide*
+ We say that objects *provide* interfaces. If an object provides an
+ interface, then the interface specifies the behavior of the
+ object. In other words, interfaces specify the behavior of the
+ objects that provide them.
+
+ *implement*
+ We normally say that classes *implement* interfaces. If a class
+ implements an interface, then the instances of the class provide
+ the interface. Objects provide interfaces that their classes
+ implement [#factory]_. (Objects can provide interfaces directly,
+ in addition to what their classes implement.)
+
+ It is important to note that classes don't usually provide the
+ interfaces that they implement.
+
+ We can generalize this to factories. For any callable object we
+ can declare that it produces objects that provide some interfaces
+ by saying that the factory implements the interfaces.
+
+ Now that we've defined these terms, we can talk about the API for
+ declaring interfaces.
+
+ Declaring implemented interfaces
+ --------------------------------
+
+ The most common way to declare interfaces is using the implements
+ function in a class statement::
+
+ >>> class Foo:
+ ... zope.interface.implements(IFoo)
+ ...
+ ... def __init__(self, x=None):
+ ... self.x = x
+ ...
+ ... def bar(self, q, r=None):
+ ... return q, r, self.x
+ ...
+ ... def __repr__(self):
+ ... return "Foo(%s)" % self.x
+
+
+ In this example, we declared that `Foo` implements `IFoo`. This means
+ that instances of `Foo` provide `IFoo`. Having made this declaration,
+ there are several ways we can introspect the declarations. First, we
+ can ask an interface whether it is implemented by a class::
+
+ >>> IFoo.implementedBy(Foo)
+ True
+
+ And we can ask whether an interface is provided by an object::
+
+ >>> foo = Foo()
+ >>> IFoo.providedBy(foo)
+ True
+
+ Of course, `Foo` doesn't provide `IFoo`, it implements it::
+
+ >>> IFoo.providedBy(Foo)
+ False
+
+ We can also ask what interfaces are implemented by an object::
+
+ >>> list(zope.interface.implementedBy(Foo))
+ [<InterfaceClass __main__.IFoo>]
+
+ It's an error to ask for interfaces implemented by a non-callable
+ object::
+
+ >>> IFoo.implementedBy(foo)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+ >>> list(zope.interface.implementedBy(foo))
+ Traceback (most recent call last):
+ ...
+ TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+ Similarly, we can ask what interfaces are provided by an object::
+
+ >>> list(zope.interface.providedBy(foo))
+ [<InterfaceClass __main__.IFoo>]
+ >>> list(zope.interface.providedBy(Foo))
+ []
+
+ We can declare interfaces implemented by other factories (besides
+ classes). We do this using a Python-2.4-style decorator named
+ `implementer`. In versions of Python before 2.4, this looks like:
+
+
+ >>> def yfoo(y):
+ ... foo = Foo()
+ ... foo.y = y
+ ... return foo
+ >>> yfoo = zope.interface.implementer(IFoo)(yfoo)
+
+ >>> list(zope.interface.implementedBy(yfoo))
+ [<InterfaceClass __main__.IFoo>]
+
+ Note that the implementer decorator may modify it's argument. Callers
+ should not assume that a new object is created.
+
+ 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>
+
+ Tagged values can also be defined from within an interface definition:
+
+ >>> class IWithTaggedValues(zope.interface.Interface):
+ ... zope.interface.taggedValue('squish', 'squash')
+ >>> IWithTaggedValues.getTaggedValue('squish')
+ 'squash'
+
+ Invariants
+ ==========
+
+ Interfaces can express conditions that must hold for objects that
+ provide them. These conditions are expressed using one or more
+ invariants. Invariants are callable objects that will be called with
+ an object that provides an interface. An invariant raises an `Invalid`
+ exception if the condition doesn't hold. Here's an example::
+
+ >>> class RangeError(zope.interface.Invalid):
+ ... """A range has invalid limits"""
+ ... def __repr__(self):
+ ... return "RangeError(%r)" % self.args
+
+ >>> def range_invariant(ob):
+ ... if ob.max < ob.min:
+ ... raise RangeError(ob)
+
+ Given this invariant, we can use it in an interface definition::
+
+ >>> class IRange(zope.interface.Interface):
+ ... min = zope.interface.Attribute("Lower bound")
+ ... max = zope.interface.Attribute("Upper bound")
+ ...
+ ... zope.interface.invariant(range_invariant)
+
+ Interfaces have a method for checking their invariants::
+
+ >>> class Range(object):
+ ... zope.interface.implements(IRange)
+ ...
+ ... def __init__(self, min, max):
+ ... self.min, self.max = min, max
+ ...
+ ... def __repr__(self):
+ ... return "Range(%s, %s)" % (self.min, self.max)
+
+ >>> IRange.validateInvariants(Range(1,2))
+ >>> IRange.validateInvariants(Range(1,1))
+ >>> IRange.validateInvariants(Range(2,1))
+ Traceback (most recent call last):
+ ...
+ RangeError: Range(2, 1)
+
+ If you have multiple invariants, you may not want to stop checking
+ after the first error. If you pass a list to `validateInvariants`,
+ then a single `Invalid` exception will be raised with the list of
+ exceptions as it's argument::
+
+ >>> 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.
+
+ ================
+ 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
+
+ ==========================
+ 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!
+
+ Download
+ **********************
+
Platform: UNKNOWN
Modified: python-zope.interface/branches/upstream/current/README.txt
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/README.txt?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/README.txt (original)
+++ python-zope.interface/branches/upstream/current/README.txt Thu Jul 19 08:44:23 2007
@@ -1,40 +1,8 @@
-zope.interface Package Readme
-=============================
+***************
+Zope Interfaces
+***************
-Overview
---------
+.. contents::
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).
Added: python-zope.interface/branches/upstream/current/bootstrap.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/bootstrap.py?rev=956&op=file
==============================================================================
--- python-zope.interface/branches/upstream/current/bootstrap.py (added)
+++ python-zope.interface/branches/upstream/current/bootstrap.py Thu Jul 19 08:44:23 2007
@@ -1,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 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.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 72703 2007-02-20 11:49:26Z jim $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Propchange: python-zope.interface/branches/upstream/current/bootstrap.py
------------------------------------------------------------------------------
svn:eol-style = native
Added: python-zope.interface/branches/upstream/current/buildout.cfg
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/buildout.cfg?rev=956&op=file
==============================================================================
--- python-zope.interface/branches/upstream/current/buildout.cfg (added)
+++ python-zope.interface/branches/upstream/current/buildout.cfg Thu Jul 19 08:44:23 2007
@@ -1,0 +1,8 @@
+[buildout]
+develop = .
+parts = test
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = zope.interface
+
Modified: python-zope.interface/branches/upstream/current/setup.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/setup.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/setup.py (original)
+++ python-zope.interface/branches/upstream/current/setup.py Thu Jul 19 08:44:23 2007
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2004-2006 Zope Corporation and Contributors.
+# Copyright (c) 2004-2007 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -13,30 +13,64 @@
##############################################################################
"""Setup for zope.interface package
-$Id$
+$Id: setup.py 75145 2007-05-03 21:59:24Z ctheune $
"""
-import os
+import os, sys
try:
- from setuptools import setup, Extension
+ from setuptools import setup, Extension, find_packages
except ImportError, e:
from distutils.core import setup, Extension
+ if sys.version_info[:2] >= (2, 4):
+ extra = dict(
+ package_data={
+ 'zope.interface': ['*.txt'],
+ 'zope.interface.tests': ['*.txt'],
+ }
+ )
+ else:
+ extra = {}
+
+else:
+ extra = dict(
+ namespace_packages=["zope"],
+ include_package_data = True,
+ zip_safe = False,
+ tests_require = ['zope.testing'],
+ install_requires = ['setuptools'],
+ )
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
setup(name='zope.interface',
- version='3.3.0b2',
-
- url='http://svn.zope.org/zope.interface',
+ version = '3.4.0b1',
+ url='http://www.python.org/pypi/zope.interface',
license='ZPL 2.1',
description='Zope 3 Interface Infrastructure',
author='Zope Corporation and Contributors',
author_email='zope3-dev at zope.org',
+ long_description=(
+ read('README.txt')
+ + '\n' +
+ read('CHANGES.txt')
+ + '\n' +
+ 'Detailed Documentation\n'
+ '**********************\n'
+ + '\n' +
+ read('src', 'zope', 'interface', 'README.txt')
+ + '\n' +
+ read('src', 'zope', 'interface', 'adapter.txt')
+ + '\n' +
+ read('src', 'zope', 'interface', 'human.txt')
+ + '\n' +
+ 'Download\n'
+ '**********************\n'
+ ),
- packages=["zope",
- "zope.interface",
- "zope.interface.common",
- "zope.interface.tests",
- ],
+ packages=find_packages('src'),
package_dir = {'': 'src'},
ext_package='zope.interface',
ext_modules=[Extension("_zope_interface_coptimizations",
@@ -44,8 +78,4 @@
"_zope_interface_coptimizations.c")
]),
],
-
- tests_require = ['zope.testing'],
- include_package_data = True,
- zip_safe = False,
- )
+ **extra)
Modified: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/PKG-INFO
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/PKG-INFO?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/PKG-INFO (original)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/PKG-INFO Thu Jul 19 08:44:23 2007
@@ -1,10 +1,1649 @@
Metadata-Version: 1.0
Name: zope.interface
-Version: 3.3.0b2
+Version: 3.4.0b1
Summary: Zope 3 Interface Infrastructure
-Home-page: http://svn.zope.org/zope.interface
+Home-page: http://www.python.org/pypi/zope.interface
Author: Zope Corporation and Contributors
Author-email: zope3-dev at zope.org
License: ZPL 2.1
-Description: UNKNOWN
+Description: ***************
+ Zope Interfaces
+ ***************
+
+ .. contents::
+
+ Interfaces are a mechanism for labeling objects as conforming to a given
+ API or contract.
+
+ zope.interface Package Changes
+ ******************************
+
+ ===========================================
+ 3.4.0b3 (2007/05/22)
+ ===========================================
+
+ Bug Fixes
+ =========
+
+ - Objects with picky custom comparison methods couldn't be added to
+ component registries. Now, when checking whether an object is
+ already registered, identity comparison is used.
+
+ ===========================================
+ 3.3.0.1 (2007/01/03)
+ ===========================================
+
+ Bug Fixes
+ =========
+
+ - Made a reference to OverflowWarning, which disappeared in Python
+ 2.5, conditional.
+
+ ===========================================
+ 3.3.0 (2007/01/03)
+ ===========================================
+
+ New Features
+ ============
+
+ - The adapter-lookup algorithim was refactored to make it
+ much simpler and faster.
+
+ Also, more of the adapter-lookup logic is implemented in C, making
+ debugging of application code easier, since there is less
+ infrastructre code to step through.
+
+ - We now treat objects without interafce declarations as if they
+ declared that they provide zope.interface.Interface.
+
+ - There are a number of richer new adapter-registration interfaces
+ that provide greater control and introspection.
+
+ - Added a new interface decorator to zope.interface that allows the
+ setting of tagged values on an interface at definition time (see
+ zope.interface.taggedValue).
+
+ Bug Fixes
+ =========
+
+ - A bug in multi-adapter lookup sometimes caused incorrect adapters to
+ be returned.
+
+
+ ===========================================
+ 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.
+
+ Detailed Documentation
+ **********************
+
+ ==========
+ Interfaces
+ ==========
+
+ Interfaces are objects that specify (document) the external behavior
+ of objects that "provide" them. An interface specifies behavior
+ through:
+
+ - Informal documentation in a doc string
+
+ - Attribute definitions
+
+ - Invariants, which are conditions that must hold for objects that
+ provide the interface
+
+ Attribute definitions specify specific attributes. They define the
+ attribute name and provide documentation and constraints of attribute
+ values. Attribute definitions can take a number of forms, as we'll
+ see below.
+
+ Defining interfaces
+ ===================
+
+ Interfaces are defined using Python class statements:
+
+ >>> import zope.interface
+ >>> class IFoo(zope.interface.Interface):
+ ... """Foo blah blah"""
+ ...
+ ... x = zope.interface.Attribute("""X blah blah""")
+ ...
+ ... def bar(q, r=None):
+ ... """bar blah blah"""
+
+ In the example above, we've created an interface, `IFoo`. We
+ subclassed `zope.interface.Interface`, which is an ancestor interface for
+ all interfaces, much as `object` is an ancestor of all new-style
+ classes [#create]_. The interface is not a class, it's an Interface,
+ an instance of `InterfaceClass`::
+
+ >>> type(IFoo)
+ <class 'zope.interface.interface.InterfaceClass'>
+
+ We can ask for the interface's documentation::
+
+ >>> IFoo.__doc__
+ 'Foo blah blah'
+
+ and its name::
+
+ >>> IFoo.__name__
+ 'IFoo'
+
+ and even its module::
+
+ >>> IFoo.__module__
+ '__main__'
+
+ The interface defined two attributes:
+
+ `x`
+ This is the simplest form of attribute definition. It has a name
+ and a doc string. It doesn't formally specify anything else.
+
+ `bar`
+ This is a method. A method is defined via a function definition. A
+ method is simply an attribute constrained to be a callable with a
+ particular signature, as provided by the function definition.
+
+ Note that `bar` doesn't take a `self` argument. Interfaces document
+ how an object is *used*. When calling instance methods, you don't
+ pass a `self` argument, so a `self` argument isn't included in the
+ interface signature. The `self` argument in instance methods is
+ really an implementation detail of Python instances. Other objects,
+ besides instances can provide interfaces and their methods might not
+ be instance methods. For example, modules can provide interfaces and
+ their methods are usually just functions. Even instances can have
+ methods that are not instance methods.
+
+ You can access the attributes defined by an interface using mapping
+ syntax::
+
+ >>> x = IFoo['x']
+ >>> type(x)
+ <class 'zope.interface.interface.Attribute'>
+ >>> x.__name__
+ 'x'
+ >>> x.__doc__
+ 'X blah blah'
+
+ >>> IFoo.get('x').__name__
+ 'x'
+
+ >>> IFoo.get('y')
+
+ You can use `in` to determine if an interface defines a name::
+
+ >>> 'x' in IFoo
+ True
+
+ You can iterate over interfaces to get the names they define::
+
+ >>> names = list(IFoo)
+ >>> names.sort()
+ >>> names
+ ['bar', 'x']
+
+ Remember that interfaces aren't classes. You can't access attribute
+ definitions as attributes of interfaces::
+
+ >>> IFoo.x
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ AttributeError: 'InterfaceClass' object has no attribute 'x'
+
+ Methods provide access to the method signature::
+
+ >>> bar = IFoo['bar']
+ >>> bar.getSignatureString()
+ '(q, r=None)'
+
+ TODO
+ Methods really should have a better API. This is something that
+ needs to be improved.
+
+ Declaring interfaces
+ ====================
+
+ Having defined interfaces, we can *declare* that objects provide
+ them. Before we describe the details, lets define some terms:
+
+ *provide*
+ We say that objects *provide* interfaces. If an object provides an
+ interface, then the interface specifies the behavior of the
+ object. In other words, interfaces specify the behavior of the
+ objects that provide them.
+
+ *implement*
+ We normally say that classes *implement* interfaces. If a class
+ implements an interface, then the instances of the class provide
+ the interface. Objects provide interfaces that their classes
+ implement [#factory]_. (Objects can provide interfaces directly,
+ in addition to what their classes implement.)
+
+ It is important to note that classes don't usually provide the
+ interfaces that they implement.
+
+ We can generalize this to factories. For any callable object we
+ can declare that it produces objects that provide some interfaces
+ by saying that the factory implements the interfaces.
+
+ Now that we've defined these terms, we can talk about the API for
+ declaring interfaces.
+
+ Declaring implemented interfaces
+ --------------------------------
+
+ The most common way to declare interfaces is using the implements
+ function in a class statement::
+
+ >>> class Foo:
+ ... zope.interface.implements(IFoo)
+ ...
+ ... def __init__(self, x=None):
+ ... self.x = x
+ ...
+ ... def bar(self, q, r=None):
+ ... return q, r, self.x
+ ...
+ ... def __repr__(self):
+ ... return "Foo(%s)" % self.x
+
+
+ In this example, we declared that `Foo` implements `IFoo`. This means
+ that instances of `Foo` provide `IFoo`. Having made this declaration,
+ there are several ways we can introspect the declarations. First, we
+ can ask an interface whether it is implemented by a class::
+
+ >>> IFoo.implementedBy(Foo)
+ True
+
+ And we can ask whether an interface is provided by an object::
+
+ >>> foo = Foo()
+ >>> IFoo.providedBy(foo)
+ True
+
+ Of course, `Foo` doesn't provide `IFoo`, it implements it::
+
+ >>> IFoo.providedBy(Foo)
+ False
+
+ We can also ask what interfaces are implemented by an object::
+
+ >>> list(zope.interface.implementedBy(Foo))
+ [<InterfaceClass __main__.IFoo>]
+
+ It's an error to ask for interfaces implemented by a non-callable
+ object::
+
+ >>> IFoo.implementedBy(foo)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+ >>> list(zope.interface.implementedBy(foo))
+ Traceback (most recent call last):
+ ...
+ TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+ Similarly, we can ask what interfaces are provided by an object::
+
+ >>> list(zope.interface.providedBy(foo))
+ [<InterfaceClass __main__.IFoo>]
+ >>> list(zope.interface.providedBy(Foo))
+ []
+
+ We can declare interfaces implemented by other factories (besides
+ classes). We do this using a Python-2.4-style decorator named
+ `implementer`. In versions of Python before 2.4, this looks like:
+
+
+ >>> def yfoo(y):
+ ... foo = Foo()
+ ... foo.y = y
+ ... return foo
+ >>> yfoo = zope.interface.implementer(IFoo)(yfoo)
+
+ >>> list(zope.interface.implementedBy(yfoo))
+ [<InterfaceClass __main__.IFoo>]
+
+ Note that the implementer decorator may modify it's argument. Callers
+ should not assume that a new object is created.
+
+ 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>
+
+ Tagged values can also be defined from within an interface definition:
+
+ >>> class IWithTaggedValues(zope.interface.Interface):
+ ... zope.interface.taggedValue('squish', 'squash')
+ >>> IWithTaggedValues.getTaggedValue('squish')
+ 'squash'
+
+ Invariants
+ ==========
+
+ Interfaces can express conditions that must hold for objects that
+ provide them. These conditions are expressed using one or more
+ invariants. Invariants are callable objects that will be called with
+ an object that provides an interface. An invariant raises an `Invalid`
+ exception if the condition doesn't hold. Here's an example::
+
+ >>> class RangeError(zope.interface.Invalid):
+ ... """A range has invalid limits"""
+ ... def __repr__(self):
+ ... return "RangeError(%r)" % self.args
+
+ >>> def range_invariant(ob):
+ ... if ob.max < ob.min:
+ ... raise RangeError(ob)
+
+ Given this invariant, we can use it in an interface definition::
+
+ >>> class IRange(zope.interface.Interface):
+ ... min = zope.interface.Attribute("Lower bound")
+ ... max = zope.interface.Attribute("Upper bound")
+ ...
+ ... zope.interface.invariant(range_invariant)
+
+ Interfaces have a method for checking their invariants::
+
+ >>> class Range(object):
+ ... zope.interface.implements(IRange)
+ ...
+ ... def __init__(self, min, max):
+ ... self.min, self.max = min, max
+ ...
+ ... def __repr__(self):
+ ... return "Range(%s, %s)" % (self.min, self.max)
+
+ >>> IRange.validateInvariants(Range(1,2))
+ >>> IRange.validateInvariants(Range(1,1))
+ >>> IRange.validateInvariants(Range(2,1))
+ Traceback (most recent call last):
+ ...
+ RangeError: Range(2, 1)
+
+ If you have multiple invariants, you may not want to stop checking
+ after the first error. If you pass a list to `validateInvariants`,
+ then a single `Invalid` exception will be raised with the list of
+ exceptions as it's argument::
+
+ >>> 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.
+
+ ================
+ 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
+
+ ==========================
+ 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!
+
+ Download
+ **********************
+
Platform: UNKNOWN
Modified: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt (original)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/SOURCES.txt Thu Jul 19 08:44:23 2007
@@ -1,14 +1,15 @@
CHANGES.txt
-INSTALL.txt
-MANIFEST.in
README.txt
+bootstrap.py
+buildout.cfg
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/namespace_packages.txt
src/zope.interface.egg-info/not-zip-safe
+src/zope.interface.egg-info/requires.txt
src/zope.interface.egg-info/top_level.txt
src/zope/interface/DEPENDENCIES.cfg
src/zope/interface/PUBLICATION.cfg
@@ -38,6 +39,7 @@
src/zope/interface/common/tests/__init__.py
src/zope/interface/common/tests/basemapping.py
src/zope/interface/common/tests/test_idatetime.py
+src/zope/interface/common/tests/test_import_interfaces.py
src/zope/interface/tests/__init__.py
src/zope/interface/tests/dummy.py
src/zope/interface/tests/foodforthought.txt
Added: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/namespace_packages.txt
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/namespace_packages.txt?rev=956&op=file
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/namespace_packages.txt (added)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/namespace_packages.txt Thu Jul 19 08:44:23 2007
@@ -1,0 +1,1 @@
+zope
Propchange: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/namespace_packages.txt
------------------------------------------------------------------------------
svn:eol-style = native
Added: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/requires.txt
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/requires.txt?rev=956&op=file
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/requires.txt (added)
+++ python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/requires.txt Thu Jul 19 08:44:23 2007
@@ -1,0 +1,1 @@
+setuptools
Propchange: python-zope.interface/branches/upstream/current/src/zope.interface.egg-info/requires.txt
------------------------------------------------------------------------------
svn:eol-style = native
Modified: python-zope.interface/branches/upstream/current/src/zope/__init__.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/__init__.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/__init__.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/__init__.py Thu Jul 19 08:44:23 2007
@@ -1,1 +1,7 @@
-__import__('pkg_resources').declare_namespace(__name__)
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/README.txt
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/README.txt?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/README.txt (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/README.txt Thu Jul 19 08:44:23 2007
@@ -1,8 +1,6 @@
==========
Interfaces
==========
-
-.. contents::
Interfaces are objects that specify (document) the external behavior
of objects that "provide" them. An interface specifies behavior
@@ -606,6 +604,12 @@
>>> IBazFactory['__call__'].getTaggedValue('return_type')
<InterfaceClass __main__.IBaz>
+Tagged values can also be defined from within an interface definition:
+
+ >>> class IWithTaggedValues(zope.interface.Interface):
+ ... zope.interface.taggedValue('squish', 'squash')
+ >>> IWithTaggedValues.getTaggedValue('squish')
+ 'squash'
Invariants
==========
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/__init__.py Thu Jul 19 08:44:23 2007
@@ -48,7 +48,7 @@
See the module doc strings for more information.
-$Id: __init__.py 67630 2006-04-27 00:54:03Z jim $
+$Id: __init__.py 70082 2006-09-08 22:09:27Z ctheune $
"""
__docformat__ = 'restructuredtext'
@@ -58,7 +58,7 @@
_wire()
del _wire
-from zope.interface.interface import Attribute, invariant
+from zope.interface.interface import Attribute, invariant, taggedValue
from zope.interface.declarations import providedBy, implementedBy
from zope.interface.declarations import classImplements, classImplementsOnly
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/_zope_interface_coptimizations.c
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/_zope_interface_coptimizations.c?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/_zope_interface_coptimizations.c (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/_zope_interface_coptimizations.c Thu Jul 19 08:44:23 2007
@@ -63,7 +63,7 @@
if (! PyType_Check(i))
{
PyErr_SetString(PyExc_TypeError,
- "zope.declarations.Implements is not a type");
+ "zope.interface.declarations.Implements is not a type");
return -1;
}
@@ -1624,7 +1624,7 @@
/* 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 $");
+ "$Id: _zope_interface_coptimizations.c 69150 2006-07-17 03:20:44Z fdrake $");
if (m == NULL)
return;
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/adapter.py Thu Jul 19 08:44:23 2007
@@ -106,7 +106,7 @@
components[k] = d
components = d
- if components.get(name) == value:
+ if components.get(name) is value:
return
components[name] = value
@@ -155,7 +155,7 @@
old = components.get(name)
if old is None:
return
- if (value is not None) and (old != value):
+ if (value is not None) and (old is not value):
return
del components[name]
@@ -220,7 +220,7 @@
if value is None:
new = ()
else:
- new = tuple([v for v in old if v != value])
+ new = tuple([v for v in old if v is not value])
if new == old:
return
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/interfaces.py Thu Jul 19 08:44:23 2007
@@ -13,7 +13,7 @@
##############################################################################
"""Interfaces for standard python exceptions
-$Id: interfaces.py 25177 2004-06-02 13:17:31Z jim $
+$Id: interfaces.py 72677 2007-02-19 12:26:58Z jim $
"""
from zope.interface import Interface
from zope.interface import classImplements
@@ -77,7 +77,10 @@
classImplements(NotImplementedError, INotImplementedError)
classImplements(OSError, IOSError)
classImplements(OverflowError, IOverflowError)
-classImplements(OverflowWarning, IOverflowWarning)
+try:
+ classImplements(OverflowWarning, IOverflowWarning)
+except NameError:
+ pass # OverflowWarning was removed in Python 2.5
classImplements(ReferenceError, IReferenceError)
classImplements(RuntimeError, IRuntimeError)
classImplements(RuntimeWarning, IRuntimeWarning)
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/sequence.py Thu Jul 19 08:44:23 2007
@@ -13,21 +13,31 @@
##############################################################################
"""Sequence Interfaces
-$Id: sequence.py 39752 2005-10-30 20:16:09Z srichter $
+$Id: sequence.py 71145 2006-11-16 19:37:42Z fdrake $
"""
__docformat__ = 'restructuredtext'
from zope import interface
class IMinimalSequence(interface.Interface):
+ """Most basic sequence interface.
+
+ All sequences are iterable. This requires at least one of the
+ following:
+
+ - a `__getitem__()` method that takes a single argument; interger
+ values starting at 0 must be supported, and `IndexError` should
+ be raised for the first index for which there is no value, or
+
+ - an `__iter__()` method that returns an iterator as defined in
+ the Python documentation (http://docs.python.org/lib/typeiter.html).
+
+ """
def __getitem__(index):
"""`x.__getitem__(index)` <==> `x[index]`
Declaring this interface does not specify whether `__getitem__`
supports slice objects."""
-
- def __iter__():
- """`x.__iter__()` <==> `iter(x)`"""
class IFiniteSequence(IMinimalSequence):
Added: python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_import_interfaces.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_import_interfaces.py?rev=956&op=file
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_import_interfaces.py (added)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_import_interfaces.py Thu Jul 19 08:44:23 2007
@@ -1,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+import unittest
+from zope.testing import doctest
+
+def test_interface_import():
+ """
+ >>> import zope.interface.common.interfaces
+ """
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocTestSuite(),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Propchange: python-zope.interface/branches/upstream/current/src/zope/interface/common/tests/test_import_interfaces.py
------------------------------------------------------------------------------
svn:eol-style = native
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/declarations.py Thu Jul 19 08:44:23 2007
@@ -24,17 +24,16 @@
provided by objects.
-$Id: declarations.py 67745 2006-04-29 00:44:10Z poster $
+$Id: declarations.py 72236 2007-01-26 16:50:29Z alga $
"""
__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 types import ClassType, ModuleType
from zope.interface.advice import addClassAdvisor
# Registry of class-implementation specifications
@@ -1066,7 +1065,7 @@
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::
+ way to call directlyProvides for a class. For example::
classProvides(I1)
@@ -1170,9 +1169,7 @@
raise TypeError(
"moduleProvides can only be used once in a module definition.")
- module = sys.modules[__name__]
-
- locals["__provides__"] = Provides(type(module),
+ locals["__provides__"] = Provides(ModuleType,
*_normalizeargs(interfaces))
##############################################################################
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/interface.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/interface.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/interface.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/interface.py Thu Jul 19 08:44:23 2007
@@ -13,7 +13,7 @@
##############################################################################
"""Interface object implementation
-$Id: interface.py 67761 2006-04-30 13:56:44Z jim $
+$Id: interface.py 70211 2006-09-17 14:45:07Z flox $
"""
from __future__ import generators
@@ -25,6 +25,7 @@
from ro import ro
from zope.interface.exceptions import Invalid
+
CO_VARARGS = 4
CO_VARKEYWORDS = 8
TAGGED_DATA = '__interface_tagged_values__'
@@ -37,6 +38,15 @@
invariants = tags.setdefault('invariants', [])
invariants.append(call)
return _decorator_non_return
+
+
+def taggedValue(key, value):
+ """Attaches a tagged value to an interface at definition time."""
+ f_locals = sys._getframe(1).f_locals
+ tagged_values = f_locals.setdefault(TAGGED_DATA, {})
+ tagged_values[key] = value
+ return _decorator_non_return
+
class Element(object):
@@ -245,26 +255,6 @@
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()
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/ro.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/ro.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/ro.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/ro.py Thu Jul 19 08:44:23 2007
@@ -13,8 +13,10 @@
##############################################################################
"""Compute a resolution order for an object and it's bases
-$Id: ro.py 25177 2004-06-02 13:17:31Z jim $
+$Id: ro.py 70897 2006-10-24 08:21:55Z flox $
"""
+__docformat__ = 'restructuredtext'
+
def ro(object):
"""Compute a "resolution order" for an object
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/dummy.py Thu Jul 19 08:44:23 2007
@@ -13,7 +13,7 @@
##############################################################################
"""Dummy Module
-$Id$
+$Id: dummy.py 70826 2006-10-20 03:41:16Z baijum $
"""
from zope.interface import moduleProvides
from zope.interface.tests.ifoo import IFoo
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/ifoo.py Thu Jul 19 08:44:23 2007
@@ -13,7 +13,7 @@
##############################################################################
"""IFoo test module
-$Id$
+$Id: ifoo.py 70826 2006-10-20 03:41:16Z baijum $
"""
from zope.interface import Interface
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/m1.py Thu Jul 19 08:44:23 2007
@@ -13,7 +13,7 @@
##############################################################################
"""Test module that declares an interface
-$Id$
+$Id: m1.py 70826 2006-10-20 03:41:16Z baijum $
"""
from zope.interface import Interface, moduleProvides
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/m2.py Thu Jul 19 08:44:23 2007
@@ -13,5 +13,5 @@
##############################################################################
"""Test module that doesn't declare an interface
-$Id$
+$Id: m2.py 70826 2006-10-20 03:41:16Z baijum $
"""
Modified: python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py
URL: http://svn.debian.org/wsvn/pkg-zope/python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py?rev=956&op=diff
==============================================================================
--- python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py (original)
+++ python-zope.interface/branches/upstream/current/src/zope/interface/tests/test_adapter.py Thu Jul 19 08:44:23 2007
@@ -321,6 +321,28 @@
'Y'
"""
+def test_register_objects_with_cmp():
+ """
+ The registry should never use == as that will tend to fail when
+ objects are picky about what they are compared with:
+
+ >>> class Picky:
+ ... def __cmp__(self, other):
+ ... raise TypeError("I\'m too picky for comparison!")
+ >>> class I(zope.interface.Interface):
+ ... pass
+ >>> class I2(I, I):
+ ... pass
+
+ >>> registry = AdapterRegistry()
+ >>> picky = Picky()
+ >>> registry.register([I2], IR0, '', picky)
+ >>> registry.unregister([I2], IR0, '', picky)
+
+ >>> registry.subscribe([I2], IR0, picky)
+ >>> registry.unsubscribe([I2], IR0, picky)
+
+ """
def test_suite():
from zope.testing import doctest, doctestunit
More information about the pkg-zope-commits
mailing list