[Zope3-checkins] SVN: Zope3/trunk/src/zope/component/socketexample.txt Converted DOS EOL endings back to Unix.

Stephan Richter srichter at cosmos.phy.tufts.edu
Wed Feb 23 17:17:22 EST 2005


Log message for revision 29268:
  Converted DOS EOL endings back to Unix.
  

Changed:
  U   Zope3/trunk/src/zope/component/socketexample.txt

-=-
Modified: Zope3/trunk/src/zope/component/socketexample.txt
===================================================================
--- Zope3/trunk/src/zope/component/socketexample.txt	2005-02-23 21:56:07 UTC (rev 29267)
+++ Zope3/trunk/src/zope/component/socketexample.txt	2005-02-23 22:17:22 UTC (rev 29268)
@@ -1,597 +1,597 @@
-==================================================
-The Zope 3 Component Architecture (Socket Example)
-==================================================
-
-The component architecture provides an application framework that provides its
-functionality through loosly-connected components. A *component* can be any
-Python object and has a particular purpose associated with it. Thus, in a
-component-based applications you have many small component in contrast to
-classical object-oriented development, where yoiu have a few big objects. 
-
-Components communicate via specific APIs, which are formally defined by
-interfaces, which are provided by the `zope.interface` package. *Interfaces*
-describe the methods and properties that a component is expected to
-provide. They are also used as a primary mean to provide developer-level
-documentation for the components. For more details about interfaces see
-`zope/interface/README.txt`.
-
-The two main types of components are *adapters* and *utilities*. They will be
-discussed in detail later in this document. Both component types are managed
-by the *site manager*, with which you can register and access these
-components. However, most of the site manager's functionality is hidden behind
-the component architecture's public API, which is documented in
-`IComponentArchitecture`.
-
-
-Adapters
---------
-
-Adapters are a well-established pattern. An *adapter* uses an object providing
-one interface to produce an object that provides another interface. Here an
-example: Imagine that you purchased an electric shaver in the US, and thus
-you require the US socket type. You are now traveling in Germany, where another
-socket style is used. You will need a device, an adapter, that converts from
-the German to the US socket style.
-
-The functionality of adapters is actually natively provided by the
-`zope.interface` package and is thus well decumented there. The `human.txt`
-file provides a gentle introduction to adapters, whereby `adapter.txt` is
-aimed at providing a comprehensive insight into adapters, but is too abstract
-for many as an inital read. Thus, we will only explain adapters in the context
-of the component architecture's API.
-
-So let's say that we have a German socket
-
-  >>> from zope.interface import Interface, implements
-
-  >>> class IGermanSocket(Interface):
-  ...     pass
-
-  >>> class Socket(object):
-  ...     def __repr__(self):
-  ...         return '<instance of %s>' %self.__class__.__name__
-
-  >>> class GermanSocket(Socket):
-  ...     """German wall socket."""
-  ...     implements(IGermanSocket)
-
-and we want to convert it to an US socket
-
-  >>> class IUSSocket(Interface):
-  ...     pass
-
-so that our shaver can be used in Germany. So we go to a German electronics
-store to look for an adapter that we can plug in the wall:
-
-  >>> class GermanToUSSocketAdapter(Socket):
-  ...     implements(IUSSocket)
-  ...     __used_by__ = IGermanSocket
-  ...     
-  ...     def __init__(self, socket):
-  ...         self.context = socket
-
-Note that I could have called the passed in socket any way I like, but
-`context` is the standard name accepted.
-
-
-Single Adapters
-+++++++++++++++
-
-Before we can use the adapter, we have to buy it and make it part of our
-inventory. In the component architecture we do this by registering the adapter
-with the framework, more specifically with the global site manager:
-
-  >>> from zope import component as capi
-  >>> gsm = capi.getGlobalSiteManager()
-  
-  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, '',
-  ...                    GermanToUSSocketAdapter)
-
-`capi` is the component architecture API that is being presented by this
-file. You registered an adapter from `IGermanSocket` to `IUSSocket` having no
-name (thus the empty string).
-
-Anyways, you finally get back to your hotel room and shave, since you have not
-been able to shave in the plane. In the bathroom you discover a socket:
-
-  >>> bathroomDE = GermanSocket()
-  >>> IGermanSocket.providedBy(bathroomDE)
-  True
-
-You now insert the adapter in the German socket
-
-  >>> bathroomUS = capi.getAdapter(bathroomDE, IUSSocket, '')
-
-so that the socket now provides the US version:
-
-  >>> IUSSocket.providedBy(bathroomUS)
-  True
-
-Now you can insert your shaver and get on with your day. 
-
-After a week you travel for a couple of days to the Prague and you notice that
-the Czech have yet another socket type:
-
-  >>> class ICzechSocket(Interface):
-  ...     pass
-
-  >>> class CzechSocket(Socket):
-  ...     implements(ICzechSocket)
-
-  >>> czech = CzechSocket()
-
-You try to find an adapter for your shaver in your bag, but you fail, since
-you do not have one:
-
-  >>> capi.getAdapter(czech, IUSSocket, '') #doctest: +NORMALIZE_WHITESPACE
-  Traceback (most recent call last):
-  ...
-  ComponentLookupError: (<instance of CzechSocket>, 
-                         <InterfaceClass __builtin__.IUSSocket>,
-                         '')
-
-or the more graceful way:
-
-  >>> marker = object()
-  >>> socket = capi.queryAdapter(czech, IUSSocket, '', marker)
-  >>> socket is marker
-  True
-
-In the component architecture API any `get*` method will fail with a specific
-exception, if a query failed, whereby methods starting with `query*` will
-always return a `default` value after a failure.
-
-
-Named Adapters
-++++++++++++++
-
-You are finally back in Germany. You also brought your DVD player and a couple
-DVDs with you, which you would like to watch. Your shaver was able to convert
-automatically from 110 volts to 240 volts, but your DVD player cannot. So you
-have to buy another adapter that also handles converting the voltage and the
-frequency of the AC current:
-
-  >>> class GermanToUSSocketAdapterAndTransformer(object):
-  ...     implements(IUSSocket)
-  ...     __used_by__ = IGermanSocket
-  ...     
-  ...     def __init__(self, socket):
-  ...         self.context = socket
-
-Now, we need a way to keep the two adapters apart. Thus we register them with
-a name:
-
-  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, 'shaver',
-  ...                    GermanToUSSocketAdapter)
-  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, 'dvd',
-  ...                    GermanToUSSocketAdapterAndTransformer)
-
-Now we simply look up the adapters using their labels (called *name*):
-
-  >>> socket = capi.getAdapter(bathroomDE, IUSSocket, 'shaver')
-  >>> socket.__class__ is GermanToUSSocketAdapter
-  True
-
-  >>> socket = capi.getAdapter(bathroomDE, IUSSocket, 'dvd')
-  >>> socket.__class__ is GermanToUSSocketAdapterAndTransformer
-  True
-
-Clearly, we do not have an adapter for the MP3 player
-
-  >>> capi.getAdapter(bathroomDE, IUSSocket, 
-  ...                 'mp3') #doctest: +NORMALIZE_WHITESPACE
-  Traceback (most recent call last):
-  ...
-  ComponentLookupError: (<instance of GermanSocket>, 
-                         <InterfaceClass __builtin__.IUSSocket>,
-                         'mp3')
-
-
-but you could use the 'dvd' adapter in this case of course. ;)
-
-Sometimes you want to know all adapters that are available. Let's say you want
-to know about all the adapters that convert a German to a US socket type:
-
-  >>> sockets = capi.getAdapters((bathroomDE,), IUSSocket)
-  >>> len(sockets)
-  3
-  >>> names = [name for name, socket in sockets]
-  >>> names.sort()
-  >>> names
-  [u'', u'dvd', u'shaver']
-
-`capi.getAdapters()` returns a list of tuples. The first entry of the tuple is
-the name of the adapter and the second is the adapter itself.
-
-
-Multi-Adapters
-++++++++++++++
-
-After watching all the DVDs you brought at least twice, you get tired of them
-and you want to listen to some music using your MP3 player. But darn, the MP3
-player plug has a ground pin and all the adapters you have do not support
-that:
-
-  >>> class IUSGroundedSocket(IUSSocket):
-  ...     pass
-
-So you go out another time to buy an adapter. This time, however, you do not
-buy yet another adapter, but a piece that provides the grounding plug:
-
-  >>> class IGrounder(Interface):
-  ...     pass
-
-  >>> class Grounder(object):
-  ...     implements(IGrounder)
-  ...     def __repr__(self):
-  ...         return '<instance of Grounder>'
-
-
-Then together they will provided a grounded us socket:
-
-  >>> class GroundedGermanToUSSocketAdapter(object):
-  ...     implements(IUSGroundedSocket)
-  ...     __used_for__ = (IGermanSocket, IGrounder)
-  ...     def __init__(self, socket, grounder):
-  ...         self.socket, self.grounder = socket, grounder
-
-You now register the combination, so that you know you can create a
-`IUSGroundedSocket`:
-
-  >>> gsm.provideAdapter((IGermanSocket, IGrounder), IUSGroundedSocket, 'mp3',
-  ...                    GroundedGermanToUSSocketAdapter)
-
-Given the grounder
-
-  >>> grounder = Grounder()
-
-and a German socket
-
-  >>> livingroom = GermanSocket()
-
-we can now get a gounded US socket:
-
-  >>> socket = capi.getMultiAdapter((livingroom, grounder), 
-  ...                               IUSGroundedSocket, 'mp3')
-
-  >>> socket.__class__ is GroundedGermanToUSSocketAdapter
-  True
-  >>> socket.socket is livingroom
-  True
-  >>> socket.grounder is grounder
-  True
-
-Of course, you do not have a 'dvd' grounded US socket available:
-
-  >>> capi.getMultiAdapter((livingroom, grounder), IUSGroundedSocket, 
-  ...                      'dvd') #doctest: +NORMALIZE_WHITESPACE
-  Traceback (most recent call last):
-  ...
-  ComponentLookupError: ((<instance of GermanSocket>, 
-                          <instance of Grounder>), 
-                         <InterfaceClass __builtin__.IUSGroundedSocket>,
-                         'dvd')
-
-
-  >>> socket = capi.queryMultiAdapter((livingroom, grounder), 
-  ...                                 IUSGroundedSocket, 'dvd', marker)
-  >>> socket is marker
-  True
-
-Again, you might want to read `adapter.txt` in `zope.interface` for a more
-comprehensive coverage of multi-adapters.
-
-Subscribers
------------
-
-While subscribers are directly supported by the adapter registry and are
-adapters for all theoretical purposes, practically it might be better to think
-of them as separate components. Subscribers are particularly useful for
-events.
-
-Let's say one of our adapters overheated and caused a small fire:
-
-  >>> class IFire(Interface):
-  ...     pass
-
-  >>> class Fire(object):
-  ...     implements(IFire)
-
-  >>> fire = Fire()
-
-We want to use all available objects to put out the fire:
-
-  >>> class IFireExtinguisher(Interface):
-  ...     def extinguish():
-  ...         pass
-
-  >>> class FireExtinguisher(object):
-  ...     def __init__(self, fire):
-  ...         pass
-  ...     def extinguish(self):
-  ...         "Place extinguish code here."
-  ...         print 'Used ' + self.__class__.__name__ + '.'
-
-Here some specific methods to put out the fire:
-
-  >>> class PowderExtinguisher(FireExtinguisher):
-  ...     pass
-  >>> gsm.subscribe((IFire,), IFireExtinguisher, PowderExtinguisher)
-
-  >>> class Blanket(FireExtinguisher):
-  ...     pass
-  >>> gsm.subscribe((IFire,), IFireExtinguisher, Blanket)
-
-  >>> class SprinklerSystem(FireExtinguisher):
-  ...     pass
-  >>> gsm.subscribe((IFire,), IFireExtinguisher, SprinklerSystem)
-
-Now let use all these things to put out the fire:
-
-  >>> extinguishers = capi.subscribers((fire,), IFireExtinguisher)
-  >>> extinguishers.sort()
-  >>> for extinguisher in extinguishers:
-  ...     extinguisher.extinguish()
-  Used Blanket.
-  Used PowderExtinguisher.
-  Used SprinklerSystem.
-
-If no subscribers are found for a particular object, then an empty list is
-returned: 
-
-  >>> capi.subscribers((object(),), IFireExtinguisher)
-  []
-
-
-Utilities
----------
-
-Utilities are the second type of component, the component architecture
-implements. *Utilities* are simply components that provide an interface. When
-you register an utility, you always register an instance (in cotrast to a
-factory for adapters) since the initialization and setup process of a utility
-might be complex and is not well defined. In some ways a utility is much more
-fundamental than an adapter, because an adapter cannot be used without another
-component, but a utility is always self-contained. I like to think of
-utilities as the foundation of your application and adapters as components
-extending beyond this foundation.
-
-Back to our story...
-
-After your vacation is over you fly back home to Tampa, Florida. But it is
-August now, the middle of the Hurrican season. And, believe it or not, you are
-worried that you will not be able to shave when the power goes out for several
-days. (You just hate wet shavers.)
-
-So you decide to go to your favorite hardware store and by a Diesel-powered
-electric generator. The generator provides of course a US-style socket:
-
-  >>> class Generator(object):
-  ...     implements(IUSSocket)
-  ...     def __repr__(self):
-  ...         return '<instance of Generator>'
-
-  >>> generator = Generator()
-
-Like for adapters, we now have to add the newly-acquired generator to our
-inventory by registering it as a utility:
-
-  >>> gsm.provideUtility(IUSSocket, generator)
-
-We can now get the utility using
-
-  >>> utility = capi.getUtility(IUSSocket)
-  >>> utility is generator
-  True
-
-As you can see, it is very simple to register and retrieve utilities. If a
-utility does not exsist for a particular interface, such as the German socket,
-then the lookup fails
-
-  >>> capi.getUtility(IGermanSocket)
-  Traceback (most recent call last):
-  ...
-  ComponentLookupError: (<InterfaceClass __builtin__.IGermanSocket>, '')
-
-or more gracefully when specifying a default value:
-
-  >>> default = object()
-  >>> utility = capi.queryUtility(IGermanSocket, default=default)
-  >>> utility is default
-  True
-
-Note: The only difference between `getUtility()` and `queryUtility()` is the
-fact that you can specify a default value for the latter function, so that it
-will never cause a `ComponentLookupError`.
-
-
-Named Utilities
-+++++++++++++++
-
-It is often desirable to have several utilities providing the same interface
-per site. This way you can implement any sort of registry using utilities. For
-this reason, utilities -- like adapters -- can be named.
-
-In the context of our story, we might want to do the following: You really do
-not trust gas stations either. What if the roads are blocked after a hurricane
-and the gas stations run out of oil. So you look for another renewable power
-source. Then you think about solar panels! After a storm there is usually very
-nice weather, so why not? Via the Web you order a set of 110V/120W solar
-panels that provide a regular US-style socket as output:
-
-  >>> class SolarPanel(object):
-  ...     implements(IUSSocket)
-  ...     def __repr__(self):
-  ...         return '<instance of Solar Panel>'
-
-  >>> panel = SolarPanel()
-
-Once it arrives, we add it to our inventory:
-
-  >>> gsm.provideUtility(IUSSocket, panel, 'Solar Panel')
-
-You can now access the solar panel using
-
-  >>> utility = capi.getUtility(IUSSocket, 'Solar Panel')
-  >>> utility is panel
-  True
-
-Of course, if a utility is not available, then the lookup will simply fail
-
-  >>> capi.getUtility(IUSSocket, 'Wind Mill')
-  Traceback (most recent call last):
-  ...
-  ComponentLookupError: (<InterfaceClass __builtin__.IUSSocket>, 'Wind Mill')
-
-or more gracefully when specifying a default value:
-
-  >>> default = object()
-  >>> utility = capi.queryUtility(IUSSocket, 'Wind Mill', default=default)
-  >>> utility is default
-  True
-
-Now you want to look at all the utilities you have for a particular kind. The
-following API function will return a list of name/utility pairs:
-
-  >>> utils = list(capi.getUtilitiesFor(IUSSocket))
-  >>> utils.sort()
-  >>> utils #doctest: +NORMALIZE_WHITESPACE
-  [(u'', <instance of Generator>), 
-   (u'Solar Panel', <instance of Solar Panel>)]
-
-Another method of looking up all utilities is by using
-`getAllUtilitiesRegisteredFor(iface)`. This function will return an iteratable
-of utilities (without names); however, it will also return overridden
-utilities. If you are not using multiple site managers, you will not actually
-need this method.
-
-  >>> utils = list(capi.getAllUtilitiesRegisteredFor(IUSSocket))
-  >>> utils.sort()
-  >>> utils
-  [<instance of Generator>, <instance of Solar Panel>]
-
-
-Factories
-+++++++++
-
-A *factory* is a special kind of utility that exists to create other
-components. A factory is always identified by a name. It also provides a title
-and description and is able to tell the developer what interfaces the created
-object will provide. The advantage of using a factory to create an object
-instead of directly isntantiating a class or executing any other callable is
-that we can refer to the factory by name. As long as the name stays fixed, the
-implementation of the callable can be renamed or moved without a breakage in
-code.
-
-Let's say that our solar panel comes in parts and they have to be
-assembled. This assembly would be done by a factory, so let's create one for
-the solar panel. To do this, we can use a standard implementation of the
-`IFactory` interface:
-
-  >>> from zope.component.factory import Factory
-  >>> factory = Factory(SolarPanel, 
-  ...                   'Solar Panel',
-  ...                   'This factory creates a solar panel.')
-
-Optionally, I could have also specifed the interfaces that the created object
-will provide, but the factory class is smart enough to determine the
-implemented interface from the class. We now register the factory:
-
-  >>> from zope.component.interfaces import IFactory
-  >>> gsm.provideUtility(IFactory, factory, 'SolarPanel')
-
-We can now get a list of interfaces the produced object will provide:
-
-  >>> ifaces = capi.getFactoryInterfaces('SolarPanel')
-  >>> IUSSocket in ifaces
-  True
-
-By the way, this is equivalent to
-
-  >>> ifaces2 = factory.getInterfaces()
-  >>> ifaces is ifaces2
-  True
-
-Of course you can also just create an object:
-
-  >>> panel = capi.createObject('SolarPanel')
-  >>> panel.__class__ is SolarPanel
-  True
-
-Note: Ignore the first argument (`None`) for now; it is the context of the
-utility lookup, which is usually an optional argument, but cannot be in this
-case, since all other arguments beside the `name` are passed in as arguments
-to the specified callable.
-
-Once you register several factories
-
-  >>> gsm.provideUtility(IFactory, Factory(Generator), 'Generator')
-
-you can also determine, which available factories will create objects
-providing a certian interface:
-
-  >>> factories = capi.getFactoriesFor(IUSSocket)
-  >>> factories = [(name, factory.__class__) for name, factory in factories]
-  >>> factories.sort()
-  >>> factories #doctest: +NORMALIZE_WHITESPACE
-  [(u'Generator', <class 'zope.component.factory.Factory'>), 
-   (u'SolarPanel', <class 'zope.component.factory.Factory'>)]
-
-
-Site Managers
--------------
-
-Why do we need site managers? Why is the component architecture API not
-sufficient? Some applications, including Zope 3, have a concept of
-locations. It is often desireable to have different configurations for these
-location; this can be done by overwriting existing or adding new component
-registrations. Site managers in locations below the root location, should be
-able to delegate requests to their parent locations. The root site manager is
-commonly known as *global site manager*, since it is always available. You can
-always get the global site manager using the API:
-
-  >>> gsm = capi.getGlobalSiteManager()
-
-  >>> from zope.component.site import globalSiteManager
-  >>> gsm is globalSiteManager
-  True
-  >>> from zope.component.interfaces import ISiteManager
-  >>> ISiteManager.providedBy(gsm)
-  True
-  >>> from zope.component.site import IGlobalSiteManager
-  >>> IGlobalSiteManager.providedBy(gsm)
-  True
-
-You can also lookup at site manager in a given context. The only requirement
-is that the context can be adapted to a site manager. So let's create a
-special site manager:
-
-  >>> from zope.component.site import SiteManager
-  >>> sm = SiteManager()
-
-Now we create a context that adapts to the site manager via the `__conform__`
-method as specied in PEP 246.
-
-  >>> class Context(object):
-  ...     def __init__(self, sm):
-  ...         self.sm = sm
-  ...     def __conform__(self, interface):
-  ...         if interface.isOrExtends(ISiteManager):
-  ...             return self.sm
-
-We now instantiate the `Context` with our special site manager:
-
-  >>> context = Context(sm)
-  >>> context.sm is sm
-  True
-
-We can now ask for the site manager of this context:
-
-  >>> lsm = capi.getSiteManager(context)
-  >>> lsm is sm
-  True
-
-The site manager instance `lsm` is formally known as a *local site manager* of
-`context`.
-
-
+==================================================
+The Zope 3 Component Architecture (Socket Example)
+==================================================
+
+The component architecture provides an application framework that provides its
+functionality through loosly-connected components. A *component* can be any
+Python object and has a particular purpose associated with it. Thus, in a
+component-based applications you have many small component in contrast to
+classical object-oriented development, where yoiu have a few big objects. 
+
+Components communicate via specific APIs, which are formally defined by
+interfaces, which are provided by the `zope.interface` package. *Interfaces*
+describe the methods and properties that a component is expected to
+provide. They are also used as a primary mean to provide developer-level
+documentation for the components. For more details about interfaces see
+`zope/interface/README.txt`.
+
+The two main types of components are *adapters* and *utilities*. They will be
+discussed in detail later in this document. Both component types are managed
+by the *site manager*, with which you can register and access these
+components. However, most of the site manager's functionality is hidden behind
+the component architecture's public API, which is documented in
+`IComponentArchitecture`.
+
+
+Adapters
+--------
+
+Adapters are a well-established pattern. An *adapter* uses an object providing
+one interface to produce an object that provides another interface. Here an
+example: Imagine that you purchased an electric shaver in the US, and thus
+you require the US socket type. You are now traveling in Germany, where another
+socket style is used. You will need a device, an adapter, that converts from
+the German to the US socket style.
+
+The functionality of adapters is actually natively provided by the
+`zope.interface` package and is thus well decumented there. The `human.txt`
+file provides a gentle introduction to adapters, whereby `adapter.txt` is
+aimed at providing a comprehensive insight into adapters, but is too abstract
+for many as an inital read. Thus, we will only explain adapters in the context
+of the component architecture's API.
+
+So let's say that we have a German socket
+
+  >>> from zope.interface import Interface, implements
+
+  >>> class IGermanSocket(Interface):
+  ...     pass
+
+  >>> class Socket(object):
+  ...     def __repr__(self):
+  ...         return '<instance of %s>' %self.__class__.__name__
+
+  >>> class GermanSocket(Socket):
+  ...     """German wall socket."""
+  ...     implements(IGermanSocket)
+
+and we want to convert it to an US socket
+
+  >>> class IUSSocket(Interface):
+  ...     pass
+
+so that our shaver can be used in Germany. So we go to a German electronics
+store to look for an adapter that we can plug in the wall:
+
+  >>> class GermanToUSSocketAdapter(Socket):
+  ...     implements(IUSSocket)
+  ...     __used_by__ = IGermanSocket
+  ...     
+  ...     def __init__(self, socket):
+  ...         self.context = socket
+
+Note that I could have called the passed in socket any way I like, but
+`context` is the standard name accepted.
+
+
+Single Adapters
++++++++++++++++
+
+Before we can use the adapter, we have to buy it and make it part of our
+inventory. In the component architecture we do this by registering the adapter
+with the framework, more specifically with the global site manager:
+
+  >>> from zope import component as capi
+  >>> gsm = capi.getGlobalSiteManager()
+  
+  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, '',
+  ...                    GermanToUSSocketAdapter)
+
+`capi` is the component architecture API that is being presented by this
+file. You registered an adapter from `IGermanSocket` to `IUSSocket` having no
+name (thus the empty string).
+
+Anyways, you finally get back to your hotel room and shave, since you have not
+been able to shave in the plane. In the bathroom you discover a socket:
+
+  >>> bathroomDE = GermanSocket()
+  >>> IGermanSocket.providedBy(bathroomDE)
+  True
+
+You now insert the adapter in the German socket
+
+  >>> bathroomUS = capi.getAdapter(bathroomDE, IUSSocket, '')
+
+so that the socket now provides the US version:
+
+  >>> IUSSocket.providedBy(bathroomUS)
+  True
+
+Now you can insert your shaver and get on with your day. 
+
+After a week you travel for a couple of days to the Prague and you notice that
+the Czech have yet another socket type:
+
+  >>> class ICzechSocket(Interface):
+  ...     pass
+
+  >>> class CzechSocket(Socket):
+  ...     implements(ICzechSocket)
+
+  >>> czech = CzechSocket()
+
+You try to find an adapter for your shaver in your bag, but you fail, since
+you do not have one:
+
+  >>> capi.getAdapter(czech, IUSSocket, '') #doctest: +NORMALIZE_WHITESPACE
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: (<instance of CzechSocket>, 
+                         <InterfaceClass __builtin__.IUSSocket>,
+                         '')
+
+or the more graceful way:
+
+  >>> marker = object()
+  >>> socket = capi.queryAdapter(czech, IUSSocket, '', marker)
+  >>> socket is marker
+  True
+
+In the component architecture API any `get*` method will fail with a specific
+exception, if a query failed, whereby methods starting with `query*` will
+always return a `default` value after a failure.
+
+
+Named Adapters
+++++++++++++++
+
+You are finally back in Germany. You also brought your DVD player and a couple
+DVDs with you, which you would like to watch. Your shaver was able to convert
+automatically from 110 volts to 240 volts, but your DVD player cannot. So you
+have to buy another adapter that also handles converting the voltage and the
+frequency of the AC current:
+
+  >>> class GermanToUSSocketAdapterAndTransformer(object):
+  ...     implements(IUSSocket)
+  ...     __used_by__ = IGermanSocket
+  ...     
+  ...     def __init__(self, socket):
+  ...         self.context = socket
+
+Now, we need a way to keep the two adapters apart. Thus we register them with
+a name:
+
+  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, 'shaver',
+  ...                    GermanToUSSocketAdapter)
+  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, 'dvd',
+  ...                    GermanToUSSocketAdapterAndTransformer)
+
+Now we simply look up the adapters using their labels (called *name*):
+
+  >>> socket = capi.getAdapter(bathroomDE, IUSSocket, 'shaver')
+  >>> socket.__class__ is GermanToUSSocketAdapter
+  True
+
+  >>> socket = capi.getAdapter(bathroomDE, IUSSocket, 'dvd')
+  >>> socket.__class__ is GermanToUSSocketAdapterAndTransformer
+  True
+
+Clearly, we do not have an adapter for the MP3 player
+
+  >>> capi.getAdapter(bathroomDE, IUSSocket, 
+  ...                 'mp3') #doctest: +NORMALIZE_WHITESPACE
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: (<instance of GermanSocket>, 
+                         <InterfaceClass __builtin__.IUSSocket>,
+                         'mp3')
+
+
+but you could use the 'dvd' adapter in this case of course. ;)
+
+Sometimes you want to know all adapters that are available. Let's say you want
+to know about all the adapters that convert a German to a US socket type:
+
+  >>> sockets = capi.getAdapters((bathroomDE,), IUSSocket)
+  >>> len(sockets)
+  3
+  >>> names = [name for name, socket in sockets]
+  >>> names.sort()
+  >>> names
+  [u'', u'dvd', u'shaver']
+
+`capi.getAdapters()` returns a list of tuples. The first entry of the tuple is
+the name of the adapter and the second is the adapter itself.
+
+
+Multi-Adapters
+++++++++++++++
+
+After watching all the DVDs you brought at least twice, you get tired of them
+and you want to listen to some music using your MP3 player. But darn, the MP3
+player plug has a ground pin and all the adapters you have do not support
+that:
+
+  >>> class IUSGroundedSocket(IUSSocket):
+  ...     pass
+
+So you go out another time to buy an adapter. This time, however, you do not
+buy yet another adapter, but a piece that provides the grounding plug:
+
+  >>> class IGrounder(Interface):
+  ...     pass
+
+  >>> class Grounder(object):
+  ...     implements(IGrounder)
+  ...     def __repr__(self):
+  ...         return '<instance of Grounder>'
+
+
+Then together they will provided a grounded us socket:
+
+  >>> class GroundedGermanToUSSocketAdapter(object):
+  ...     implements(IUSGroundedSocket)
+  ...     __used_for__ = (IGermanSocket, IGrounder)
+  ...     def __init__(self, socket, grounder):
+  ...         self.socket, self.grounder = socket, grounder
+
+You now register the combination, so that you know you can create a
+`IUSGroundedSocket`:
+
+  >>> gsm.provideAdapter((IGermanSocket, IGrounder), IUSGroundedSocket, 'mp3',
+  ...                    GroundedGermanToUSSocketAdapter)
+
+Given the grounder
+
+  >>> grounder = Grounder()
+
+and a German socket
+
+  >>> livingroom = GermanSocket()
+
+we can now get a gounded US socket:
+
+  >>> socket = capi.getMultiAdapter((livingroom, grounder), 
+  ...                               IUSGroundedSocket, 'mp3')
+
+  >>> socket.__class__ is GroundedGermanToUSSocketAdapter
+  True
+  >>> socket.socket is livingroom
+  True
+  >>> socket.grounder is grounder
+  True
+
+Of course, you do not have a 'dvd' grounded US socket available:
+
+  >>> capi.getMultiAdapter((livingroom, grounder), IUSGroundedSocket, 
+  ...                      'dvd') #doctest: +NORMALIZE_WHITESPACE
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: ((<instance of GermanSocket>, 
+                          <instance of Grounder>), 
+                         <InterfaceClass __builtin__.IUSGroundedSocket>,
+                         'dvd')
+
+
+  >>> socket = capi.queryMultiAdapter((livingroom, grounder), 
+  ...                                 IUSGroundedSocket, 'dvd', marker)
+  >>> socket is marker
+  True
+
+Again, you might want to read `adapter.txt` in `zope.interface` for a more
+comprehensive coverage of multi-adapters.
+
+Subscribers
+-----------
+
+While subscribers are directly supported by the adapter registry and are
+adapters for all theoretical purposes, practically it might be better to think
+of them as separate components. Subscribers are particularly useful for
+events.
+
+Let's say one of our adapters overheated and caused a small fire:
+
+  >>> class IFire(Interface):
+  ...     pass
+
+  >>> class Fire(object):
+  ...     implements(IFire)
+
+  >>> fire = Fire()
+
+We want to use all available objects to put out the fire:
+
+  >>> class IFireExtinguisher(Interface):
+  ...     def extinguish():
+  ...         pass
+
+  >>> class FireExtinguisher(object):
+  ...     def __init__(self, fire):
+  ...         pass
+  ...     def extinguish(self):
+  ...         "Place extinguish code here."
+  ...         print 'Used ' + self.__class__.__name__ + '.'
+
+Here some specific methods to put out the fire:
+
+  >>> class PowderExtinguisher(FireExtinguisher):
+  ...     pass
+  >>> gsm.subscribe((IFire,), IFireExtinguisher, PowderExtinguisher)
+
+  >>> class Blanket(FireExtinguisher):
+  ...     pass
+  >>> gsm.subscribe((IFire,), IFireExtinguisher, Blanket)
+
+  >>> class SprinklerSystem(FireExtinguisher):
+  ...     pass
+  >>> gsm.subscribe((IFire,), IFireExtinguisher, SprinklerSystem)
+
+Now let use all these things to put out the fire:
+
+  >>> extinguishers = capi.subscribers((fire,), IFireExtinguisher)
+  >>> extinguishers.sort()
+  >>> for extinguisher in extinguishers:
+  ...     extinguisher.extinguish()
+  Used Blanket.
+  Used PowderExtinguisher.
+  Used SprinklerSystem.
+
+If no subscribers are found for a particular object, then an empty list is
+returned: 
+
+  >>> capi.subscribers((object(),), IFireExtinguisher)
+  []
+
+
+Utilities
+---------
+
+Utilities are the second type of component, the component architecture
+implements. *Utilities* are simply components that provide an interface. When
+you register an utility, you always register an instance (in cotrast to a
+factory for adapters) since the initialization and setup process of a utility
+might be complex and is not well defined. In some ways a utility is much more
+fundamental than an adapter, because an adapter cannot be used without another
+component, but a utility is always self-contained. I like to think of
+utilities as the foundation of your application and adapters as components
+extending beyond this foundation.
+
+Back to our story...
+
+After your vacation is over you fly back home to Tampa, Florida. But it is
+August now, the middle of the Hurrican season. And, believe it or not, you are
+worried that you will not be able to shave when the power goes out for several
+days. (You just hate wet shavers.)
+
+So you decide to go to your favorite hardware store and by a Diesel-powered
+electric generator. The generator provides of course a US-style socket:
+
+  >>> class Generator(object):
+  ...     implements(IUSSocket)
+  ...     def __repr__(self):
+  ...         return '<instance of Generator>'
+
+  >>> generator = Generator()
+
+Like for adapters, we now have to add the newly-acquired generator to our
+inventory by registering it as a utility:
+
+  >>> gsm.provideUtility(IUSSocket, generator)
+
+We can now get the utility using
+
+  >>> utility = capi.getUtility(IUSSocket)
+  >>> utility is generator
+  True
+
+As you can see, it is very simple to register and retrieve utilities. If a
+utility does not exsist for a particular interface, such as the German socket,
+then the lookup fails
+
+  >>> capi.getUtility(IGermanSocket)
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: (<InterfaceClass __builtin__.IGermanSocket>, '')
+
+or more gracefully when specifying a default value:
+
+  >>> default = object()
+  >>> utility = capi.queryUtility(IGermanSocket, default=default)
+  >>> utility is default
+  True
+
+Note: The only difference between `getUtility()` and `queryUtility()` is the
+fact that you can specify a default value for the latter function, so that it
+will never cause a `ComponentLookupError`.
+
+
+Named Utilities
++++++++++++++++
+
+It is often desirable to have several utilities providing the same interface
+per site. This way you can implement any sort of registry using utilities. For
+this reason, utilities -- like adapters -- can be named.
+
+In the context of our story, we might want to do the following: You really do
+not trust gas stations either. What if the roads are blocked after a hurricane
+and the gas stations run out of oil. So you look for another renewable power
+source. Then you think about solar panels! After a storm there is usually very
+nice weather, so why not? Via the Web you order a set of 110V/120W solar
+panels that provide a regular US-style socket as output:
+
+  >>> class SolarPanel(object):
+  ...     implements(IUSSocket)
+  ...     def __repr__(self):
+  ...         return '<instance of Solar Panel>'
+
+  >>> panel = SolarPanel()
+
+Once it arrives, we add it to our inventory:
+
+  >>> gsm.provideUtility(IUSSocket, panel, 'Solar Panel')
+
+You can now access the solar panel using
+
+  >>> utility = capi.getUtility(IUSSocket, 'Solar Panel')
+  >>> utility is panel
+  True
+
+Of course, if a utility is not available, then the lookup will simply fail
+
+  >>> capi.getUtility(IUSSocket, 'Wind Mill')
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: (<InterfaceClass __builtin__.IUSSocket>, 'Wind Mill')
+
+or more gracefully when specifying a default value:
+
+  >>> default = object()
+  >>> utility = capi.queryUtility(IUSSocket, 'Wind Mill', default=default)
+  >>> utility is default
+  True
+
+Now you want to look at all the utilities you have for a particular kind. The
+following API function will return a list of name/utility pairs:
+
+  >>> utils = list(capi.getUtilitiesFor(IUSSocket))
+  >>> utils.sort()
+  >>> utils #doctest: +NORMALIZE_WHITESPACE
+  [(u'', <instance of Generator>), 
+   (u'Solar Panel', <instance of Solar Panel>)]
+
+Another method of looking up all utilities is by using
+`getAllUtilitiesRegisteredFor(iface)`. This function will return an iteratable
+of utilities (without names); however, it will also return overridden
+utilities. If you are not using multiple site managers, you will not actually
+need this method.
+
+  >>> utils = list(capi.getAllUtilitiesRegisteredFor(IUSSocket))
+  >>> utils.sort()
+  >>> utils
+  [<instance of Generator>, <instance of Solar Panel>]
+
+
+Factories
++++++++++
+
+A *factory* is a special kind of utility that exists to create other
+components. A factory is always identified by a name. It also provides a title
+and description and is able to tell the developer what interfaces the created
+object will provide. The advantage of using a factory to create an object
+instead of directly isntantiating a class or executing any other callable is
+that we can refer to the factory by name. As long as the name stays fixed, the
+implementation of the callable can be renamed or moved without a breakage in
+code.
+
+Let's say that our solar panel comes in parts and they have to be
+assembled. This assembly would be done by a factory, so let's create one for
+the solar panel. To do this, we can use a standard implementation of the
+`IFactory` interface:
+
+  >>> from zope.component.factory import Factory
+  >>> factory = Factory(SolarPanel, 
+  ...                   'Solar Panel',
+  ...                   'This factory creates a solar panel.')
+
+Optionally, I could have also specifed the interfaces that the created object
+will provide, but the factory class is smart enough to determine the
+implemented interface from the class. We now register the factory:
+
+  >>> from zope.component.interfaces import IFactory
+  >>> gsm.provideUtility(IFactory, factory, 'SolarPanel')
+
+We can now get a list of interfaces the produced object will provide:
+
+  >>> ifaces = capi.getFactoryInterfaces('SolarPanel')
+  >>> IUSSocket in ifaces
+  True
+
+By the way, this is equivalent to
+
+  >>> ifaces2 = factory.getInterfaces()
+  >>> ifaces is ifaces2
+  True
+
+Of course you can also just create an object:
+
+  >>> panel = capi.createObject('SolarPanel')
+  >>> panel.__class__ is SolarPanel
+  True
+
+Note: Ignore the first argument (`None`) for now; it is the context of the
+utility lookup, which is usually an optional argument, but cannot be in this
+case, since all other arguments beside the `name` are passed in as arguments
+to the specified callable.
+
+Once you register several factories
+
+  >>> gsm.provideUtility(IFactory, Factory(Generator), 'Generator')
+
+you can also determine, which available factories will create objects
+providing a certian interface:
+
+  >>> factories = capi.getFactoriesFor(IUSSocket)
+  >>> factories = [(name, factory.__class__) for name, factory in factories]
+  >>> factories.sort()
+  >>> factories #doctest: +NORMALIZE_WHITESPACE
+  [(u'Generator', <class 'zope.component.factory.Factory'>), 
+   (u'SolarPanel', <class 'zope.component.factory.Factory'>)]
+
+
+Site Managers
+-------------
+
+Why do we need site managers? Why is the component architecture API not
+sufficient? Some applications, including Zope 3, have a concept of
+locations. It is often desireable to have different configurations for these
+location; this can be done by overwriting existing or adding new component
+registrations. Site managers in locations below the root location, should be
+able to delegate requests to their parent locations. The root site manager is
+commonly known as *global site manager*, since it is always available. You can
+always get the global site manager using the API:
+
+  >>> gsm = capi.getGlobalSiteManager()
+
+  >>> from zope.component.site import globalSiteManager
+  >>> gsm is globalSiteManager
+  True
+  >>> from zope.component.interfaces import ISiteManager
+  >>> ISiteManager.providedBy(gsm)
+  True
+  >>> from zope.component.site import IGlobalSiteManager
+  >>> IGlobalSiteManager.providedBy(gsm)
+  True
+
+You can also lookup at site manager in a given context. The only requirement
+is that the context can be adapted to a site manager. So let's create a
+special site manager:
+
+  >>> from zope.component.site import SiteManager
+  >>> sm = SiteManager()
+
+Now we create a context that adapts to the site manager via the `__conform__`
+method as specied in PEP 246.
+
+  >>> class Context(object):
+  ...     def __init__(self, sm):
+  ...         self.sm = sm
+  ...     def __conform__(self, interface):
+  ...         if interface.isOrExtends(ISiteManager):
+  ...             return self.sm
+
+We now instantiate the `Context` with our special site manager:
+
+  >>> context = Context(sm)
+  >>> context.sm is sm
+  True
+
+We can now ask for the site manager of this context:
+
+  >>> lsm = capi.getSiteManager(context)
+  >>> lsm is sm
+  True
+
+The site manager instance `lsm` is formally known as a *local site manager* of
+`context`.
+
+



More information about the Zope3-Checkins mailing list