diff options
| author | Tres Seaver <tseaver@palladion.com> | 2012-04-06 01:15:07 +0000 |
|---|---|---|
| committer | Tres Seaver <tseaver@palladion.com> | 2012-04-06 01:15:07 +0000 |
| commit | 64ea0fad954212106f78cba5069710590bfa9e97 (patch) | |
| tree | 444a4d352d2272f71c739c0b22de021313495719 | |
| parent | f49ecd4cae67ece47e9db4faacc8460afde32812 (diff) | |
| download | zope-interface-64ea0fad954212106f78cba5069710590bfa9e97.tar.gz | |
Fix up snippets to run in Sphinx context.
| -rw-r--r-- | docs/README.rst | 313 | ||||
| -rw-r--r-- | docs/adapter.rst | 196 | ||||
| -rw-r--r-- | docs/api.rst | 160 | ||||
| -rw-r--r-- | docs/foodforthought.rst | 20 | ||||
| -rw-r--r-- | docs/human.rst | 54 | ||||
| -rw-r--r-- | docs/verify.rst | 151 |
6 files changed, 613 insertions, 281 deletions
diff --git a/docs/README.rst b/docs/README.rst index 482cd12..760667d 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -21,7 +21,9 @@ see below. Defining interfaces =================== -Interfaces are defined using Python class statements:: +Interfaces are defined using Python class statements: + +.. doctest:: >>> import zope.interface >>> class IFoo(zope.interface.Interface): @@ -36,25 +38,33 @@ 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`:: +an instance of `InterfaceClass`: + +.. doctest:: >>> type(IFoo) <class 'zope.interface.interface.InterfaceClass'> -We can ask for the interface's documentation:: +We can ask for the interface's documentation: + +.. doctest:: >>> IFoo.__doc__ 'Foo blah blah' -and its name:: +and its name: + +.. doctest:: >>> IFoo.__name__ 'IFoo' -and even its module:: +and even its module: + +.. doctest:: >>> IFoo.__module__ - '__main__' + '__builtin__' The interface defined two attributes: @@ -78,7 +88,9 @@ The interface defined two attributes: methods that are not instance methods. You can access the attributes defined by an interface using mapping -syntax:: +syntax: + +.. doctest:: >>> x = IFoo['x'] >>> type(x) @@ -93,12 +105,16 @@ syntax:: >>> IFoo.get('y') -You can use `in` to determine if an interface defines a name:: +You can use `in` to determine if an interface defines a name: + +.. doctest:: >>> 'x' in IFoo True -You can iterate over interfaces to get the names they define:: +You can iterate over interfaces to get the names they define: + +.. doctest:: >>> names = list(IFoo) >>> names.sort() @@ -106,14 +122,18 @@ You can iterate over interfaces to get the names they define:: ['bar', 'x'] Remember that interfaces aren't classes. You can't access attribute -definitions as attributes of interfaces:: +definitions as attributes of interfaces: + +.. doctest:: >>> 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:: +Methods provide access to the method signature: + +.. doctest:: >>> bar = IFoo['bar'] >>> bar.getSignatureString() @@ -156,7 +176,9 @@ Declaring implemented interfaces -------------------------------- The most common way to declare interfaces is using the implements -function in a class statement:: +function in a class statement: + +.. doctest:: >>> class Foo: ... zope.interface.implements(IFoo) @@ -174,29 +196,39 @@ function in a class statement:: 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:: +can ask an interface whether it is implemented by a class: + +.. doctest:: >>> IFoo.implementedBy(Foo) True -And we can ask whether an interface is provided by an object:: +And we can ask whether an interface is provided by an object: + +.. doctest:: >>> foo = Foo() >>> IFoo.providedBy(foo) True -Of course, `Foo` doesn't provide `IFoo`, it implements it:: +Of course, `Foo` doesn't provide `IFoo`, it implements it: + +.. doctest:: >>> IFoo.providedBy(Foo) False -We can also ask what interfaces are implemented by an object:: +We can also ask what interfaces are implemented by an object: + +.. doctest:: >>> list(zope.interface.implementedBy(Foo)) - [<InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.IFoo>] It's an error to ask for interfaces implemented by a non-callable -object:: +object: + +.. doctest:: >>> IFoo.implementedBy(foo) Traceback (most recent call last): @@ -208,16 +240,20 @@ object:: ... TypeError: ('ImplementedBy called for non-factory', Foo(None)) -Similarly, we can ask what interfaces are provided by an object:: +Similarly, we can ask what interfaces are provided by an object: + +.. doctest:: >>> list(zope.interface.providedBy(foo)) - [<InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.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:: +`implementer`. In versions of Python before 2.4, this looks like: + +.. doctest:: >>> def yfoo(y): ... foo = Foo() @@ -226,13 +262,15 @@ classes). We do this using a Python-2.4-style decorator named >>> yfoo = zope.interface.implementer(IFoo)(yfoo) >>> list(zope.interface.implementedBy(yfoo)) - [<InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.IFoo>] Note that the implementer decorator may modify it's argument. Callers should not assume that a new object is created. Using implementer also works on callable objects. This is used by -zope.formlib, as an example:: +zope.formlib, as an example: + +.. doctest:: >>> class yfactory: ... def __call__(self, y): @@ -243,16 +281,18 @@ zope.formlib, as an example:: >>> yfoo = zope.interface.implementer(IFoo)(yfoo) >>> list(zope.interface.implementedBy(yfoo)) - [<InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.IFoo>] XXX: Double check and update these version numbers: In zope.interface 3.5.2 and lower, the implementer decorator can not -be used for classes, but in 3.6.0 and higher it can:: +be used for classes, but in 3.6.0 and higher it can: + +.. doctest:: >>> Foo = zope.interface.implementer(IFoo)(Foo) >>> list(zope.interface.providedBy(Foo())) - [<InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.IFoo>] Note that class decorators using the @implementer(IFoo) syntax are only supported in Python 2.6 and later. @@ -265,7 +305,9 @@ 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:: +is part of the `Foo`'s `__call__` method: + +.. doctest:: >>> class IFooFactory(zope.interface.Interface): ... """Create foos""" @@ -277,20 +319,26 @@ is part of the `Foo`'s `__call__` method:: ... """ It's the class that provides this interface, so we declare the -interface on the class:: +interface on the class: + +.. doctest:: >>> zope.interface.directlyProvides(Foo, IFooFactory) -And then, we'll see that Foo provides some interfaces:: +And then, we'll see that Foo provides some interfaces: + +.. doctest:: >>> list(zope.interface.providedBy(Foo)) - [<InterfaceClass __main__.IFooFactory>] + [<InterfaceClass __builtin__.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:: +declaration from within a class statement: + +.. doctest:: >>> class Foo2: ... zope.interface.implements(IFoo) @@ -306,7 +354,7 @@ declaration from within a class statement:: ... return "Foo(%s)" % self.x >>> list(zope.interface.providedBy(Foo2)) - [<InterfaceClass __main__.IFooFactory>] + [<InterfaceClass __builtin__.IFooFactory>] >>> IFooFactory.providedBy(Foo2) True @@ -317,7 +365,9 @@ 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`:: +a new interface, `ISpecial`: + +.. doctest:: >>> class ISpecial(zope.interface.Interface): ... reason = zope.interface.Attribute("Reason why we're special") @@ -325,7 +375,9 @@ a new interface, `ISpecial`:: ... "Brag about being special" We can make an existing foo instance special by providing `reason` -and `brag` attributes:: +and `brag` attributes: + +.. doctest:: >>> foo.reason = 'I just am' >>> def brag(): @@ -336,21 +388,27 @@ and `brag` attributes:: >>> foo.brag() "I'm special!" -and by declaring the interface:: +and by declaring the interface: + +.. doctest:: >>> zope.interface.directlyProvides(foo, ISpecial) -then the new interface is included in the provided interfaces:: +then the new interface is included in the provided interfaces: + +.. doctest:: >>> ISpecial.providedBy(foo) True >>> list(zope.interface.providedBy(foo)) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.ISpecial>, <InterfaceClass __builtin__.IFoo>] -We can find out what interfaces are directly provided by an object:: +We can find out what interfaces are directly provided by an object: + +.. doctest:: >>> list(zope.interface.directlyProvidedBy(foo)) - [<InterfaceClass __main__.ISpecial>] + [<InterfaceClass __builtin__.ISpecial>] >>> newfoo = Foo() >>> list(zope.interface.directlyProvidedBy(newfoo)) @@ -359,7 +417,9 @@ We can find out what interfaces are directly provided by an object:: Inherited declarations ---------------------- -Normally, declarations are inherited:: +Normally, declarations are inherited: + +.. doctest:: >>> class SpecialFoo(Foo): ... zope.interface.implements(ISpecial) @@ -368,13 +428,15 @@ Normally, declarations are inherited:: ... return "I'm special because %s" % self.reason >>> list(zope.interface.implementedBy(SpecialFoo)) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.ISpecial>, <InterfaceClass __builtin__.IFoo>] >>> list(zope.interface.providedBy(SpecialFoo())) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.ISpecial>, <InterfaceClass __builtin__.IFoo>] Sometimes, you don't want to inherit declarations. In that case, you -can use `implementsOnly`, instead of `implements`:: +can use `implementsOnly`, instead of `implements`: + +.. doctest:: >>> class Special(Foo): ... zope.interface.implementsOnly(ISpecial) @@ -383,10 +445,10 @@ can use `implementsOnly`, instead of `implements`:: ... return "I'm special because %s" % self.reason >>> list(zope.interface.implementedBy(Special)) - [<InterfaceClass __main__.ISpecial>] + [<InterfaceClass __builtin__.ISpecial>] >>> list(zope.interface.providedBy(Special())) - [<InterfaceClass __main__.ISpecial>] + [<InterfaceClass __builtin__.ISpecial>] External declarations --------------------- @@ -395,23 +457,27 @@ 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:: +be used for this purpose: + +.. doctest:: >>> class C: ... pass >>> zope.interface.classImplements(C, IFoo) >>> list(zope.interface.implementedBy(C)) - [<InterfaceClass __main__.IFoo>] + [<InterfaceClass __builtin__.IFoo>] -We can use `classImplementsOnly` to exclude inherited interfaces:: +We can use `classImplementsOnly` to exclude inherited interfaces: + +.. doctest:: >>> class C(Foo): ... pass >>> zope.interface.classImplementsOnly(C, ISpecial) >>> list(zope.interface.implementedBy(C)) - [<InterfaceClass __main__.ISpecial>] + [<InterfaceClass __builtin__.ISpecial>] @@ -419,7 +485,9 @@ Declaration Objects ------------------- When we declare interfaces, we create *declaration* objects. When we -query declarations, declaration objects are returned:: +query declarations, declaration objects are returned: + +.. doctest:: >>> type(zope.interface.implementedBy(Special)) <class 'zope.interface.declarations.Implements'> @@ -427,7 +495,9 @@ query declarations, declaration objects are returned:: 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:: +declarations. Here's a silly example: + +.. doctest:: >>> class Special2(Foo): ... zope.interface.implementsOnly( @@ -440,17 +510,21 @@ declarations. Here's a silly example:: The declaration here is almost the same as ``zope.interface.implements(ISpecial)``, except that the order of -interfaces in the resulting declaration is different:: +interfaces in the resulting declaration is different: + +.. doctest:: >>> list(zope.interface.implementedBy(Special2)) - [<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.ISpecial>] + [<InterfaceClass __builtin__.IFoo>, <InterfaceClass __builtin__.ISpecial>] Interface Inheritance ===================== Interfaces can extend other interfaces. They do this simply by listing -the other interfaces as base interfaces:: +the other interfaces as base interfaces: + +.. doctest:: >>> class IBlat(zope.interface.Interface): ... """Blat blah blah""" @@ -469,14 +543,16 @@ the other interfaces as base interfaces:: ... >>> IBaz.__bases__ - (<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.IBlat>) + (<InterfaceClass __builtin__.IFoo>, <InterfaceClass __builtin__.IBlat>) >>> names = list(IBaz) >>> names.sort() >>> names ['bar', 'eek', 'x', 'y'] -Note that `IBaz` overrides eek:: +Note that `IBaz` overrides eek: + +.. doctest:: >>> IBlat['eek'].__doc__ 'eek blah blah' @@ -487,19 +563,25 @@ 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:: +We can ask whether one interface extends another: + +.. doctest:: >>> IBaz.extends(IFoo) True >>> IBlat.extends(IFoo) False -Note that interfaces don't extend themselves:: +Note that interfaces don't extend themselves: + +.. doctest:: >>> IBaz.extends(IBaz) False -Sometimes we wish they did, but we can, instead use `isOrExtends`:: +Sometimes we wish they did, but we can, instead use `isOrExtends`: + +.. doctest:: >>> IBaz.isOrExtends(IBaz) True @@ -511,7 +593,9 @@ Sometimes we wish they did, but we can, instead use `isOrExtends`:: 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:: +method for that: + +.. doctest:: >>> list(IBaz.names()) ['eek'] @@ -521,7 +605,9 @@ 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:: +inherited from the most specific interface. For example, with: + +.. doctest:: >>> class IBase(zope.interface.Interface): ... @@ -540,7 +626,9 @@ inherited from the most specific interface. For example, with:: ... pass ISub's definition of foo is the one from IBase2, since IBase2 is more -specific that IBase:: +specific that IBase: + +.. doctest:: >>> ISub['foo'].__doc__ 'base2 foo doc' @@ -549,7 +637,9 @@ 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:: +defined definitions: + +.. doctest:: >>> IBase.direct('foo').__doc__ 'base foo doc' @@ -562,14 +652,16 @@ 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:: +interfaces that they declare: + +.. doctest:: >>> class Baz(object): ... zope.interface.implements(IBaz) >>> baz_implements = zope.interface.implementedBy(Baz) >>> baz_implements.__bases__ - (<InterfaceClass __main__.IBaz>, <implementedBy ...object>) + (<InterfaceClass __builtin__.IBaz>, <implementedBy ...object>) >>> baz_implements.extends(IFoo) True @@ -580,13 +672,16 @@ interfaces that they declare:: True Specifications (interfaces and declarations) provide an `__sro__` -that lists the specification and all of it's ancestors:: +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>, +.. doctest:: + + >>> from pprint import pprint + >>> pprint(baz_implements.__sro__) + (<implementedBy __builtin__.Baz>, + <InterfaceClass __builtin__.IBaz>, + <InterfaceClass __builtin__.IFoo>, + <InterfaceClass __builtin__.IBlat>, <InterfaceClass zope.interface.Interface>, <implementedBy ...object>) @@ -596,7 +691,9 @@ Tagged Values Interfaces and attribute descriptions support an extension mechanism, borrowed from UML, called "tagged values" that lets us store extra -data:: +data: + +.. doctest:: >>> IFoo.setTaggedValue('date-modified', '2004-04-01') >>> IFoo.setTaggedValue('author', 'Jim Fulton') @@ -611,7 +708,9 @@ data:: ['author', 'date-modified'] Function attributes are converted to tagged values when method -attribute definitions are created:: +attribute definitions are created: + +.. doctest:: >>> class IBazFactory(zope.interface.Interface): ... def __call__(): @@ -619,9 +718,11 @@ attribute definitions are created:: ... __call__.return_type = IBaz >>> IBazFactory['__call__'].getTaggedValue('return_type') - <InterfaceClass __main__.IBaz> + <InterfaceClass __builtin__.IBaz> + +Tagged values can also be defined from within an interface definition: -Tagged values can also be defined from within an interface definition:: +.. doctest:: >>> class IWithTaggedValues(zope.interface.Interface): ... zope.interface.taggedValue('squish', 'squash') @@ -635,7 +736,9 @@ 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:: +exception if the condition doesn't hold. Here's an example: + +.. doctest:: >>> class RangeError(zope.interface.Invalid): ... """A range has invalid limits""" @@ -646,7 +749,9 @@ exception if the condition doesn't hold. Here's an example:: ... if ob.max < ob.min: ... raise RangeError(ob) -Given this invariant, we can use it in an interface definition:: +Given this invariant, we can use it in an interface definition: + +.. doctest:: >>> class IRange(zope.interface.Interface): ... min = zope.interface.Attribute("Lower bound") @@ -654,7 +759,9 @@ Given this invariant, we can use it in an interface definition:: ... ... zope.interface.invariant(range_invariant) -Interfaces have a method for checking their invariants:: +Interfaces have a method for checking their invariants: + +.. doctest:: >>> class Range(object): ... zope.interface.implements(IRange) @@ -675,7 +782,9 @@ Interfaces have a method for checking their invariants:: 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:: +exceptions as it's argument: + +.. doctest:: >>> from zope.interface.exceptions import Invalid >>> errors = [] @@ -685,7 +794,9 @@ exceptions as it's argument:: ... str(e) '[RangeError(Range(2, 1))]' -And the list will be filled with the individual exceptions:: +And the list will be filled with the individual exceptions: + +.. doctest:: >>> errors [RangeError(Range(2, 1))] @@ -700,7 +811,9 @@ Interfaces can be called to perform adaptation. The semantics are based on those of the PEP 246 adapt function. -If an object cannot be adapted, then a TypeError is raised:: +If an object cannot be adapted, then a TypeError is raised: + +.. doctest:: >>> class I(zope.interface.Interface): ... pass @@ -708,16 +821,20 @@ If an object cannot be adapted, then a TypeError is raised:: >>> I(0) Traceback (most recent call last): ... - TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>) + TypeError: ('Could not adapt', 0, <InterfaceClass __builtin__.I>) -unless an alternate value is provided as a second positional argument:: +unless an alternate value is provided as a second positional argument: + +.. doctest:: >>> I(0, 'bob') 'bob' -If an object already implements the interface, then it will be returned:: +If an object already implements the interface, then it will be returned: + +.. doctest:: >>> class C(object): ... zope.interface.implements(I) @@ -726,7 +843,9 @@ If an object already implements the interface, then it will be returned:: >>> I(obj) is obj True -If an object implements __conform__, then it will be used:: +If an object implements __conform__, then it will be used: + +.. doctest:: >>> class C(object): ... zope.interface.implements(I) @@ -736,7 +855,9 @@ If an object implements __conform__, then it will be used:: >>> I(C()) 0 -Adapter hooks (see __adapt__) will also be used, if present:: +Adapter hooks (see __adapt__) will also be used, if present: + +.. doctest:: >>> from zope.interface.interface import adapter_hooks >>> def adapt_0_to_42(iface, obj): @@ -751,12 +872,12 @@ Adapter hooks (see __adapt__) will also be used, if present:: >>> I(0) Traceback (most recent call last): ... - TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>) + TypeError: ('Could not adapt', 0, <InterfaceClass __builtin__.I>) __adapt__ --------- -:: +.. doctest:: >>> class I(zope.interface.Interface): ... pass @@ -769,11 +890,15 @@ This method is normally not called directly. It is called by the PEP The adapt method is responsible for adapting an object to the reciever. -The default version returns None:: +The default version returns None: + +.. doctest:: >>> I.__adapt__(0) -unless the object given provides the interface:: +unless the object given provides the interface: + +.. doctest:: >>> class C(object): ... zope.interface.implements(I) @@ -785,7 +910,9 @@ unless the object given provides the interface:: 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:: +list: + +.. doctest:: >>> from zope.interface.interface import adapter_hooks >>> def adapt_0_to_42(iface, obj): @@ -799,7 +926,9 @@ list:: Hooks must either return an adapter, or None if no adapter can be found. -Hooks can be uninstalled by removing them from the list:: +Hooks can be uninstalled by removing them from the list: + +.. doctest:: >>> adapter_hooks.remove(adapt_0_to_42) >>> I.__adapt__(0) diff --git a/docs/adapter.rst b/docs/adapter.rst index 43d100b..f2aecfc 100644 --- a/docs/adapter.rst +++ b/docs/adapter.rst @@ -15,7 +15,9 @@ by a class. Single Adapters =============== -Let's look at a simple example, using a single required specification:: +Let's look at a simple example, using a single required specification: + +.. doctest:: >>> from zope.interface.adapter import AdapterRegistry >>> import zope.interface @@ -29,11 +31,15 @@ Let's look at a simple example, using a single required specification:: >>> registry = AdapterRegistry() -We'll register an object that depends on IR1 and "provides" IP2:: +We'll register an object that depends on IR1 and "provides" IP2: + +.. doctest:: >>> registry.register([IR1], IP2, '', 12) -Given the registration, we can look it up again:: +Given the registration, we can look it up again: + +.. doctest:: >>> registry.lookup([IR1], IP2, '') 12 @@ -46,14 +52,18 @@ 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:: +specification that extends the specification that it depends on: + +.. doctest:: >>> class IR2(IR1): ... pass >>> registry.lookup([IR2], IP2, '') 12 -We can use a class implementation specification to look up the object:: +We can use a class implementation specification to look up the object: + +.. doctest:: >>> class C2: ... zope.interface.implements(IR2) @@ -63,7 +73,9 @@ We can use a class implementation specification to look up the object:: and it can be looked up for interfaces that its provided interface -extends:: +extends: + +.. doctest:: >>> registry.lookup([IR1], IP1, '') 12 @@ -71,45 +83,61 @@ extends:: 12 But if you require a specification that doesn't extend the specification the -object depends on, you won't get anything:: +object depends on, you won't get anything: + +.. doctest:: >>> registry.lookup([zope.interface.Interface], IP1, '') -By the way, you can pass a default value to lookup:: +By the way, you can pass a default value to lookup: + +.. doctest:: >>> 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:: +won't get anything: + +.. doctest:: >>> class IP3(IP2): ... pass >>> registry.lookup([IR1], IP3, '') -You also won't get anything if you use the wrong name:: +You also won't get anything if you use the wrong name: + +.. doctest:: >>> 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:: +You can leave the name off when doing a lookup: + +.. doctest:: >>> registry.lookup([IR1], IP1) 12 -If we register an object that provides IP1:: +If we register an object that provides IP1: + +.. doctest:: >>> registry.register([IR1], IP1, '', 11) -then that object will be prefered over O(12):: +then that object will be prefered over O(12): + +.. doctest:: >>> registry.lookup([IR1], IP1, '') 11 Also, if we register an object for IR2, then that will be prefered -when using IR2:: +when using IR2: + +.. doctest:: >>> registry.register([IR2], IP1, '', 21) >>> registry.lookup([IR2], IP1, '') @@ -120,7 +148,9 @@ 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:: +exact match: + +.. doctest:: >>> print registry.registered([IR1], IP1) 11 @@ -145,7 +175,9 @@ lookup1 ------- Lookup of single adapters is common enough that there is a specialized -version of lookup that takes a single required interface:: +version of lookup that takes a single required interface: + +.. doctest:: >>> registry.lookup1(IR2, IP1, '') 21 @@ -159,7 +191,9 @@ 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:: +factories: + +.. doctest:: >>> class IR(zope.interface.Interface): ... pass @@ -175,7 +209,9 @@ factories:: >>> 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:: +`queryAdapter` to get the adapted object: + +.. doctest:: >>> x = X() >>> y = registry.queryAdapter(x, IP1) @@ -184,7 +220,9 @@ In this case, we registered a class as the factory. Now we can call >>> y.context is x True -We can register and lookup by name too:: +We can register and lookup by name too: + +.. doctest:: >>> class Y2(Y): ... pass @@ -199,7 +237,9 @@ We can register and lookup by name too:: 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:: +the state of the object being adapted: + +.. doctest:: >>> def factory(context): ... if context.name == 'object': @@ -221,7 +261,9 @@ the state of the object being adapted:: 'default' An alternate method that provides the same function as `queryAdapter()` is -`adapter_hook()`:: +`adapter_hook()`: + +.. doctest:: >>> y = registry.adapter_hook(IP1, x) >>> y.__class__.__name__ @@ -243,19 +285,25 @@ Default Adapters ---------------- Sometimes, you want to provide an adapter that will adapt anything. -For that, provide None as the required interface:: +For that, provide None as the required interface: + +.. doctest:: >>> registry.register([None], IP1, '', 1) then we can use that adapter for interfaces we don't have specific -adapters for:: +adapters for: + +.. doctest:: >>> class IQ(zope.interface.Interface): ... pass >>> registry.lookup([IQ], IP1, '') 1 -Of course, specific adapters are still used when applicable:: +Of course, specific adapters are still used when applicable: + +.. doctest:: >>> registry.lookup([IR2], IP1, '') 21 @@ -264,7 +312,9 @@ Class adapters -------------- You can register adapters for class declarations, which is almost the -same as registering them for a class:: +same as registering them for a class: + +.. doctest:: >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', 'C21') >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') @@ -274,7 +324,9 @@ Dict adapters ------------- At some point it was impossible to register dictionary-based adapters due a -bug. Let's make sure this works now:: +bug. Let's make sure this works now: + +.. doctest:: >>> adapter = {} >>> registry.register((), IQ, '', adapter) @@ -284,7 +336,9 @@ bug. Let's make sure this works now:: Unregistering ------------- -You can unregister by registering None, rather than an object:: +You can unregister by registering None, rather than an object: + +.. doctest:: >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', None) >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') @@ -297,7 +351,9 @@ care what gets registered. Multi-adapters ============== -You can adapt multiple specifications:: +You can adapt multiple specifications: + +.. doctest:: >>> registry.register([IR1, IQ], IP2, '', '1q2') >>> registry.lookup([IR1, IQ], IP2, '') @@ -322,12 +378,16 @@ You can adapt multiple specifications:: Multi-adaptation ---------------- -You can adapt multiple objects:: +You can adapt multiple objects: + +.. doctest:: >>> class Q: ... zope.interface.implements(IQ) -As with single adapters, we register a factory, which is often a class:: +As with single adapters, we register a factory, which is often a class: + +.. doctest:: >>> class IM(zope.interface.Interface): ... pass @@ -337,7 +397,9 @@ As with single adapters, we register a factory, which is often a class:: ... self.x, self.q = x, q >>> registry.register([IR, IQ], IM, '', M) -And then we can call `queryMultiAdapter` to compute an adapter:: +And then we can call `queryMultiAdapter` to compute an adapter: + +.. doctest:: >>> q = Q() >>> m = registry.queryMultiAdapter((x, q), IM) @@ -346,7 +408,9 @@ And then we can call `queryMultiAdapter` to compute an adapter:: >>> m.x is x and m.q is q True -and, of course, we can use names:: +and, of course, we can use names: + +.. doctest:: >>> class M2(M): ... pass @@ -361,7 +425,9 @@ Default Adapters ---------------- As with single adapters, you can define default adapters by specifying -None for the *first* specification:: +None for the *first* specification: + +.. doctest:: >>> registry.register([None, IQ], IP2, '', 'q2') >>> registry.lookup([IS, IQ], IP2, '') @@ -370,7 +436,9 @@ None for the *first* specification:: Null Adapters ============= -You can also adapt no specification:: +You can also adapt no specification: + +.. doctest:: >>> registry.register([], IP2, '', 2) >>> registry.lookup([], IP2, '') @@ -382,20 +450,26 @@ Listing named adapters ---------------------- Adapters are named. Sometimes, it's useful to get all of the named -adapters for given interfaces:: +adapters for given interfaces: + +.. doctest:: >>> adapters = list(registry.lookupAll([IR1], IP1)) >>> adapters.sort() >>> assert adapters == [(u'', 11), (u'bob', "Bob's 12")] -This works for multi-adapters too:: +This works for multi-adapters too: + +.. doctest:: >>> registry.register([IR1, IQ2], IP2, 'bob', '1q2 for bob') >>> adapters = list(registry.lookupAll([IR2, IQ2], IP1)) >>> adapters.sort() >>> assert adapters == [(u'', '1q22'), (u'bob', '1q2 for bob')] -And even null adapters:: +And even null adapters: + +.. doctest:: >>> registry.register([], IP2, 'bob', 3) >>> adapters = list(registry.lookupAll([], IP1)) @@ -409,7 +483,9 @@ 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:: +the subscribed objects: + +.. doctest:: >>> registry.subscribe([IR1], IP2, 'sub12 1') >>> registry.subscriptions([IR1], IP2) @@ -417,7 +493,9 @@ the subscribed objects:: Note that, unlike regular adapters, subscriptions are unnamed. -You can have multiple subscribers for the same specification:: +You can have multiple subscribers for the same specification: + +.. doctest:: >>> registry.subscribe([IR1], IP2, 'sub12 2') >>> registry.subscriptions([IR1], IP2) @@ -426,7 +504,9 @@ You can have multiple subscribers for the same specification:: 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:: +You can register subscribers for all specifications using None: + +.. doctest:: >>> registry.subscribe([None], IP1, 'sub_1') >>> registry.subscriptions([IR2], IP1) @@ -436,7 +516,9 @@ Note that the new subscriber is returned first. Subscribers defined for less general required interfaces are returned before subscribers for more general interfaces. -Subscriptions may be combined over multiple compatible specifications:: +Subscriptions may be combined over multiple compatible specifications: + +.. doctest:: >>> registry.subscriptions([IR2], IP1) ['sub_1', 'sub12 1', 'sub12 2'] @@ -449,14 +531,18 @@ Subscriptions may be combined over multiple compatible specifications:: >>> registry.subscriptions([IR2], IP2) ['sub12 1', 'sub12 2', 'sub22'] -Subscriptions can be on multiple specifications:: +Subscriptions can be on multiple specifications: + +.. doctest:: >>> 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:: +specify None for the first required interface, to specify a default: + +.. doctest:: >>> registry.subscribe([None, IQ], IP2, 'sub_q2') >>> registry.subscriptions([IS, IQ], IP2) @@ -464,7 +550,9 @@ specify None for the first required interface, to specify a default:: >>> registry.subscriptions([IR1, IQ], IP2) ['sub_q2', 'sub1q2'] -You can have subscriptions that are indepenent of any specifications:: +You can have subscriptions that are indepenent of any specifications: + +.. doctest:: >>> list(registry.subscriptions([], IP1)) [] @@ -482,14 +570,18 @@ Unregistering subscribers ------------------------- We can unregister subscribers. When unregistering a subscriber, we -can unregister a specific subscriber:: +can unregister a specific subscriber: + +.. doctest:: >>> 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:: +interfaces will be unsubscribed: + +.. doctest:: >>> registry.unsubscribe([IR1], IP2) >>> registry.subscriptions([IR1], IP1) @@ -501,7 +593,9 @@ 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:: +example of multiple-object subscribers: + +.. doctest:: >>> registry.subscribe([IR, IQ], IM, M) >>> registry.subscribe([IR, IQ], IM, M2) @@ -516,7 +610,9 @@ example of multiple-object subscribers:: >>> [(s.x is x and s.q is q) for s in subscribers] [True, True] -adapter factory subcribers can't return None values:: +adapter factory subcribers can't return None values: + +.. doctest:: >>> def M3(x, y): ... return None @@ -533,7 +629,9 @@ 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:: +To register a handler, simply provide None as the provided interface: + +.. doctest:: >>> def handler(event): ... print 'handler', event diff --git a/docs/api.rst b/docs/api.rst index ed43e4b..1d6d06d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -19,8 +19,11 @@ Specification objects implement the API defined by Usage +++++ -For example:: +For example: +.. doctest:: + + >>> from zope.interface.interface import Specification >>> from zope.interface import Interface >>> class I1(Interface): ... pass @@ -33,14 +36,16 @@ For example:: >>> [i.__name__ for i in I2.__bases__] ['I1'] >>> I3.extends(I1) - 1 + True >>> I2.__bases__ = (Interface, ) >>> [i.__name__ for i in I2.__bases__] ['Interface'] >>> I3.extends(I1) - 0 + False + +Exmples for :meth:`Specification.providedBy`: -Exmples for :meth:`Specification.providedBy`:: +.. doctest:: >>> from zope.interface import * >>> class I1(Interface): @@ -64,7 +69,9 @@ Exmples for :meth:`Specification.providedBy`:: >>> I1.providedBy(C) True -Examples for :meth:`Specification.isOrExtends`:: +Examples for :meth:`Specification.isOrExtends`: + +.. doctest:: >>> from zope.interface import Interface >>> from zope.interface.declarations import Declaration @@ -91,7 +98,9 @@ Examples for :meth:`Specification.isOrExtends`:: >>> int(spec.extends(I4)) 0 -Examples for :meth:`Specification.interfaces`:: +Examples for :meth:`Specification.interfaces`: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -110,7 +119,9 @@ Examples for :meth:`Specification.interfaces`:: >>> list(i) [] -Exmples for :meth:`Specification.extends`:: +Exmples for :meth:`Specification.extends`: + +.. doctest:: >>> from zope.interface import Interface >>> from zope.interface.declarations import Declaration @@ -137,11 +148,11 @@ Exmples for :meth:`Specification.extends`:: >>> int(spec.extends(I4)) 0 >>> I2.extends(I2) - 0 + False >>> I2.extends(I2, False) - 1 + True >>> I2.extends(I2, strict=False) - 1 + True :class:`zope.interface.interface.InterfaceClass` @@ -161,7 +172,9 @@ Specification objects implement the API defined by Usage +++++ -Exmples for :meth:`InterfaceClass.extends`:: +Exmples for :meth:`InterfaceClass.extends`: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -191,7 +204,9 @@ Specification objects implement the API defined by Usage +++++ -Exmples for :meth:`Declaration.__contains__`:: +Exmples for :meth:`Declaration.__contains__`: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -213,7 +228,9 @@ Exmples for :meth:`Declaration.__contains__`:: >>> int(I4 in spec) 1 -Exmples for :meth:`Declaration.__iter__`:: +Exmples for :meth:`Declaration.__iter__`: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -232,7 +249,9 @@ Exmples for :meth:`Declaration.__iter__`:: >>> list(i) [] -Exmples for :meth:`Declaration.flattened`:: +Exmples for :meth:`Declaration.flattened`: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -251,7 +270,9 @@ Exmples for :meth:`Declaration.flattened`:: >>> list(i) [] -Exmples for :meth:`Declaration.__sub__`:: +Exmples for :meth:`Declaration.__sub__`: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -282,7 +303,9 @@ Exmples for :meth:`Declaration.__sub__`:: ... in spec - Declaration(I3, I4)] ['I2'] -Exmples for :meth:`Declaration.__add__`:: +Exmples for :meth:`Declaration.__add__`: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -327,7 +350,9 @@ API Usage +++++ -Consider the following example:: +Consider the following example: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -351,7 +376,9 @@ Consider the following example:: Instances of ``C`` provide only ``I1``, ``I2``, and regardless of whatever interfaces instances of ``A`` and ``B`` implement. -Another example:: +Another example: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -370,13 +397,15 @@ Another example:: ['I3', 'I2'] Really, any object should be able to receive a successful answer, even -an instance:: +an instance: + +.. doctest:: >>> class Callable(object): ... def __call__(self): ... return self >>> implementedBy(Callable()) - <implementedBy zope.interface.declarations.?> + <implementedBy __builtin__.?> Note that the name of the spec ends with a '?', because the `Callable` instance does not have a `__name__` attribute. @@ -396,7 +425,9 @@ API Usage +++++ -Consider the following example:: +Consider the following example: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -433,7 +464,9 @@ API Usage +++++ -Consider the following example:: +Consider the following example: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -464,7 +497,7 @@ interfaces instances of ``A`` and ``B`` provide. :class:`zope.interface.declarations.implementer` ------------------------------------------------ +------------------------------------------------ API +++ @@ -475,7 +508,7 @@ API :class:`zope.interface.declarations.implementer_only` ----------------------------------------------------- +----------------------------------------------------- API +++ @@ -519,13 +552,16 @@ API Usage +++++ -Descriptor semantics (via ``Provides.__get__``):: +Descriptor semantics (via ``Provides.__get__``): + +.. doctest:: >>> from zope.interface import Interface >>> class IFooFactory(Interface): pass ... >>> class C(object): ... pass + >>> from zope.interface.declarations import ProvidesClass >>> C.__provides__ = ProvidesClass(C, IFooFactory) >>> [i.getName() for i in C.__provides__] ['IFooFactory'] @@ -551,13 +587,16 @@ the size of the weakvalue dictionary. For the assertions to be meaningful, we need to force garbage collection to make sure garbage objects are, indeed, removed from the system. Depending on how Python is run, we may need to make multiple calls to be sure. We provide a -collect function to help with this:: +collect function to help with this: + +.. doctest:: >>> import gc >>> def collect(): ... for i in range(4): ... gc.collect() >>> collect() + >>> from zope.interface.declarations import InstanceDeclarations >>> before = len(InstanceDeclarations) >>> class C(object): ... pass @@ -567,21 +606,21 @@ collect function to help with this:: >>> c1 = C() >>> c2 = C() >>> len(InstanceDeclarations) == before - 1 + True >>> directlyProvides(c1, I) >>> len(InstanceDeclarations) == before + 1 - 1 + True >>> directlyProvides(c2, I) >>> len(InstanceDeclarations) == before + 1 - 1 + True >>> del c1 >>> collect() >>> len(InstanceDeclarations) == before + 1 - 1 + True >>> del c2 >>> collect() >>> len(InstanceDeclarations) == before - 1 + True :func:`zope.interface.declarations.directlyProvides` @@ -596,7 +635,9 @@ API Usage +++++ -Consider the following example:: +Consider the following example: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -636,7 +677,9 @@ The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces instances have been declared for instances of ``C``. To remove directly provided interfaces, use ``directlyProvidedBy`` and -subtract the unwanted interfaces. For example:: +subtract the unwanted interfaces. For example: + +.. doctest:: >>> directlyProvides(ob, directlyProvidedBy(ob)-I2) >>> int(I1 in providedBy(ob)) @@ -649,13 +692,17 @@ removes I2 from the interfaces directly provided by ``ob``. The object, provide ``I2`` if it's class implements ``I2``. To add directly provided interfaces, use ``directlyProvidedBy`` and -include additional interfaces. For example:: +include additional interfaces. For example: + +.. doctest:: >>> int(I2 in providedBy(ob)) 0 >>> directlyProvides(ob, directlyProvidedBy(ob), I2) -adds ``I2`` to the interfaces directly provided by ob:: +adds ``I2`` to the interfaces directly provided by ob: + +.. doctest:: >>> int(I2 in providedBy(ob)) 1 @@ -678,7 +725,9 @@ API Usage +++++ -Consider the following example:: +Consider the following example: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -744,7 +793,9 @@ API Usage +++++ -Consider the following two interfaces:: +Consider the following two interfaces: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -753,7 +804,9 @@ Consider the following two interfaces:: ... ``I1`` is provided through the class, ``I2`` is directly provided -by the object:: +by the object: + +.. doctest:: >>> class C(object): ... implements(I1) @@ -762,13 +815,17 @@ by the object:: >>> I2.providedBy(c) True -Remove I2 from c again:: +Remove I2 from c again: + +.. doctest:: >>> noLongerProvides(c, I2) >>> I2.providedBy(c) False -Removing an interface that is provided through the class is not possible:: +Removing an interface that is provided through the class is not possible: + +.. doctest:: >>> noLongerProvides(c, I1) Traceback (most recent call last): @@ -797,22 +854,27 @@ API Usage +++++ -For example:: +For example: + +.. doctest:: >>> from zope.interface import Interface + >>> from zope.interface.declarations import implementer >>> class IFooFactory(Interface): ... pass >>> class IFoo(Interface): ... pass >>> @implementer(IFoo) - >>> class C(object): + ... class C(object): ... classProvides(IFooFactory) >>> [i.getName() for i in C.__provides__] ['IFooFactory'] >>> [i.getName() for i in C().__provides__] ['IFoo'] -Which is equivalent to:: +Which is equivalent to: + +.. doctest:: >>> from zope.interface import Interface >>> class IFoo(Interface): pass @@ -820,7 +882,7 @@ Which is equivalent to:: >>> class IFooFactory(Interface): pass ... >>> @implementer(IFoo) - >>> class C(object): + ... class C(object): ... pass >>> directlyProvides(C, IFooFactory) >>> [i.getName() for i in C.__providedBy__] @@ -862,7 +924,9 @@ API Usage +++++ -For example:: +For example: + +.. doctest:: >>> from zope.interface import Interface >>> class I1(Interface): pass @@ -945,7 +1009,9 @@ API Usage +++++ -For example:: +For example: + +.. doctest:: >>> from zope.interface import Interface >>> class IFoo(Interface): pass @@ -953,7 +1019,7 @@ For example:: >>> class IFooFactory(Interface): pass ... >>> @implementer(IFoo) - >>> class C(object): + ... class C(object): ... classProvides(IFooFactory) >>> [i.getName() for i in C.__providedBy__] ['IFooFactory'] diff --git a/docs/foodforthought.rst b/docs/foodforthought.rst index 45d961b..e14e6e5 100644 --- a/docs/foodforthought.rst +++ b/docs/foodforthought.rst @@ -3,7 +3,9 @@ Food-based subscription examples ================================ -This file gives more subscription examples using a cooking-based example:: +This file gives more subscription examples using a cooking-based example: + +.. doctest:: >>> from zope.interface.adapter import AdapterRegistry >>> registry = AdapterRegistry() @@ -19,7 +21,9 @@ This file gives more subscription examples using a cooking-based example:: ... pass Adapting to some other interface for which there is no -subscription adapter returns an empty sequence:: +subscription adapter returns an empty sequence: + +.. doctest:: >>> class IRecipe(zope.interface.Interface): ... pass @@ -33,13 +37,17 @@ subscription adapter returns an empty sequence:: >>> list(registry.subscriptions([IPoultry], IRecipe)) [] -unless we define a subscription:: +unless we define a subscription: + +.. doctest:: >>> registry.subscribe([IAnimal], ISausages, 'sausages') >>> list(registry.subscriptions([IPoultry], ISausages)) ['sausages'] -And define another subscription adapter:: +And define another subscription adapter: + +.. doctest:: >>> registry.subscribe([IPoultry], INoodles, 'noodles') >>> meals = list(registry.subscriptions([IPoultry], IRecipe)) @@ -53,7 +61,9 @@ And define another subscription adapter:: >>> meals ['kfc', 'noodles', 'sausages'] -And the answer for poultry hasn't changed:: +And the answer for poultry hasn't changed: + +.. doctest:: >>> meals = list(registry.subscriptions([IPoultry], IRecipe)) >>> meals.sort() diff --git a/docs/human.rst b/docs/human.rst index 749b87d..f87c637 100644 --- a/docs/human.rst +++ b/docs/human.rst @@ -6,13 +6,17 @@ 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:: +First we have to import the interface package: + +.. doctest:: >>> 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:: +actual file contents: + +.. doctest:: >>> class IFile(zope.interface.Interface): ... @@ -22,7 +26,9 @@ actual file contents:: 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:: +provides the size of something: + +.. doctest:: >>> class ISize(zope.interface.Interface): ... @@ -32,7 +38,9 @@ provides the size of something:: 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):: +value (just to make things simpler for this example): + +.. doctest:: >>> class File(object): ... @@ -52,7 +60,9 @@ 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`:: +use a specific argument name, such as `file`: + +.. doctest:: >>> class FileSize(object): ... @@ -68,7 +78,9 @@ use a specific argument name, such as `file`:: 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:: +global registry; thus we have to instantiate one for our example manually: + +.. doctest:: >>> from zope.interface.adapter import AdapterRegistry >>> registry = AdapterRegistry() @@ -88,18 +100,24 @@ 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:: +different situations. The last argument is simply the adapter class: + +.. doctest:: >>> registry.register([IFile], ISize, '', FileSize) -You can now use the the registry to lookup the adapter:: +You can now use the the registry to lookup the adapter: + +.. doctest:: >>> registry.lookup1(IFile, ISize, '') - <class '__main__.FileSize'> + <class '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()`:: +returns the correct size by calling `getSize()`: + +.. doctest:: >>> file = File() >>> size = registry.lookup1(IFile, ISize, '')(file) @@ -120,7 +138,9 @@ 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:: +`file`). The function returns an adapter, i.e. a `FileSize` instance: + +.. doctest:: >>> def hook(provided, object): ... adapter = registry.lookup1(zope.interface.providedBy(object), @@ -128,19 +148,25 @@ required to expect as first argument the desired output interface (for us ... return adapter(object) ... -We now just add the hook to an `adapter_hooks` list:: +We now just add the hook to an `adapter_hooks` list: + +.. doctest:: >>> from zope.interface.interface import adapter_hooks >>> adapter_hooks.append(hook) -Once the hook is registered, you can use the desired syntax:: +Once the hook is registered, you can use the desired syntax: + +.. doctest:: >>> 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` list: + +.. doctest:: >>> adapter_hooks.remove(hook) diff --git a/docs/verify.rst b/docs/verify.rst index 7eec6d2..2481186 100644 --- a/docs/verify.rst +++ b/docs/verify.rst @@ -34,94 +34,97 @@ Testing for attributes Attributes of the object, be they defined by its class or added by its ``__init__`` method, will be recognized: ->>> from zope.interface import Interface, Attribute, implements ->>> from zope.interface.exceptions import BrokenImplementation ->>> class IFoo(Interface): -... x = Attribute("The X attribute") -... y = Attribute("The Y attribute") - ->>> class Foo(object): -... implements(IFoo) -... x = 1 -... def __init__(self): -... self.y = 2 - ->>> from zope.interface.verify import verifyObject ->>> verifyObject(IFoo, Foo()) -True +.. doctest:: + + >>> from zope.interface import Interface, Attribute, implements + >>> from zope.interface.exceptions import BrokenImplementation + >>> class IFoo(Interface): + ... x = Attribute("The X attribute") + ... y = Attribute("The Y attribute") + + >>> class Foo(object): + ... implements(IFoo) + ... x = 1 + ... def __init__(self): + ... self.y = 2 + + >>> from zope.interface.verify import verifyObject + >>> verifyObject(IFoo, Foo()) + True If either attribute is missing, verification will fail: ->>> class Foo(object): -... implements(IFoo) -... x = 1 - ->>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS -... verifyObject(IFoo, Foo()) -... except BrokenImplementation, e: -... print str(e) -An object has failed to implement interface <InterfaceClass ...IFoo> -<BLANKLINE> - The y attribute was not provided. -<BLANKLINE> - ->>> class Foo(object): -... implements(IFoo) -... def __init__(self): -... self.y = 2 - ->>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS -... verifyObject(IFoo, Foo()) -... except BrokenImplementation, e: -... print str(e) -An object has failed to implement interface <InterfaceClass ...IFoo> -<BLANKLINE> - The x attribute was not provided. -<BLANKLINE> +.. doctest:: + + >>> class Foo(object): + ... implements(IFoo) + ... x = 1 + >>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + ... verifyObject(IFoo, Foo()) + ... except BrokenImplementation, e: + ... print str(e) + An object has failed to implement interface <InterfaceClass ...IFoo> + <BLANKLINE> + The y attribute was not provided. + <BLANKLINE> + >>> class Foo(object): + ... implements(IFoo) + ... def __init__(self): + ... self.y = 2 + >>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + ... verifyObject(IFoo, Foo()) + ... except BrokenImplementation, e: + ... print str(e) + An object has failed to implement interface <InterfaceClass ...IFoo> + <BLANKLINE> + The x attribute was not provided. + <BLANKLINE> If an attribute is implemented as a property that raises an AttributeError when trying to get its value, the attribute is considered missing: ->>> class IFoo(Interface): -... x = Attribute('The X attribute') - ->>> class Foo(object): -... implements(IFoo) -... @property -... def x(self): -... raise AttributeError - ->>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS -... verifyObject(IFoo, Foo()) -... except BrokenImplementation, e: -... print str(e) -An object has failed to implement interface <InterfaceClass ...IFoo> -<BLANKLINE> - The x attribute was not provided. -<BLANKLINE> +.. doctest:: + + >>> class IFoo(Interface): + ... x = Attribute('The X attribute') + >>> class Foo(object): + ... implements(IFoo) + ... @property + ... def x(self): + ... raise AttributeError + >>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + ... verifyObject(IFoo, Foo()) + ... except BrokenImplementation, e: + ... print str(e) + An object has failed to implement interface <InterfaceClass ...IFoo> + <BLANKLINE> + The x attribute was not provided. + <BLANKLINE> Any other exception raised by a property will propagate to the caller of ``verifyObject``: ->>> class Foo(object): -... implements(IFoo) -... @property -... def x(self): -... raise Exception +.. doctest:: ->>> verifyObject(IFoo, Foo()) -Traceback (most recent call last): -Exception + >>> class Foo(object): + ... implements(IFoo) + ... @property + ... def x(self): + ... raise Exception + >>> verifyObject(IFoo, Foo()) + Traceback (most recent call last): + Exception Of course, broken properties that are not required by the interface don't do any harm: ->>> class Foo(object): -... implements(IFoo) -... x = 1 -... @property -... def y(self): -... raise Exception +.. doctest:: ->>> verifyObject(IFoo, Foo()) -True + >>> class Foo(object): + ... implements(IFoo) + ... x = 1 + ... @property + ... def y(self): + ... raise Exception + >>> verifyObject(IFoo, Foo()) + True |
