[Zope3-checkins] SVN: Zope3/branches/srichter-blow-services/src/zope/component/ Rename file, to make space for Jim's README.txt file.

Stephan Richter srichter at cosmos.phy.tufts.edu
Fri Dec 17 12:35:36 EST 2004


Log message for revision 28643:
  Rename file, to make space for Jim's README.txt file.
  

Changed:
  D   Zope3/branches/srichter-blow-services/src/zope/component/README.txt
  A   Zope3/branches/srichter-blow-services/src/zope/component/socketexample.txt

-=-
Deleted: Zope3/branches/srichter-blow-services/src/zope/component/README.txt
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/README.txt	2004-12-17 04:53:33 UTC (rev 28642)
+++ Zope3/branches/srichter-blow-services/src/zope/component/README.txt	2004-12-17 17:35:34 UTC (rev 28643)
@@ -1,594 +0,0 @@
-=================================
-The Zope 3 Component Architecture
-=================================
-
-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.registerAdapter((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.registerAdapter((IGermanSocket,), IUSSocket, 'shaver',
-  ...                    GermanToUSSocketAdapter)
-  >>> gsm.registerAdapter((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>)
-
-
-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.registerAdapter((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>)
-
-
-  >>> 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.registerUtility(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.registerUtility(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.registerUtility(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(None, '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.registerUtility(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`.
-
-

Copied: Zope3/branches/srichter-blow-services/src/zope/component/socketexample.txt (from rev 28632, Zope3/branches/srichter-blow-services/src/zope/component/README.txt)



More information about the Zope3-Checkins mailing list