[Zope3-checkins] CVS: Zope3/src/zope/app/services - error.py:1.1.2.1 interface.zcml:1.1.2.1 README.txt:1.4.10.2 adapter.py:1.14.2.2 auth.py:1.15.10.2 cache.py:1.9.10.2 configure.zcml:1.29.2.2 connection.py:1.11.10.2 event.py:1.24.4.2 field.py:1.7.18.2 folder.py:1.6.10.2 hub.py:1.10.10.2 interface.py:1.5.4.1 module.py:1.2.26.2 pagefolder.py:1.5.10.2 queryfield.py:1.2.22.2 registration.py:1.1.2.2 role.py:1.4.18.2 service.py:1.18.10.2 utility.py:1.6.10.2 utility.txt:1.1.2.2 view.py:1.18.4.2 zpt.py:1.10.10.2

Albertas Agejevas alga@codeworks.lt
Mon, 23 Jun 2003 10:20:53 -0400


Update of /cvs-repository/Zope3/src/zope/app/services
In directory cvs.zope.org:/tmp/cvs-serv16963/src/zope/app/services

Modified Files:
      Tag: cw-mail-branch
	README.txt adapter.py auth.py cache.py configure.zcml 
	connection.py event.py field.py folder.py hub.py interface.py 
	module.py pagefolder.py queryfield.py registration.py role.py 
	service.py utility.py utility.txt view.py zpt.py 
Added Files:
      Tag: cw-mail-branch
	error.py interface.zcml 
Log Message:
One more sync with HEAD.

=== Added File Zope3/src/zope/app/services/error.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Error reporting service

This is a port of the Zope 2 error reporting object

$Id: error.py,v 1.1.2.1 2003/06/23 14:20:21 alga Exp $
"""

from persistence import Persistent
from random import random
from thread import allocate_lock
from types import StringTypes
from zope.app.interfaces.services.error import IErrorReportingService
from zope.app.interfaces.services.error import ILocalErrorReportingService
from zope.app.interfaces.services.service import ISimpleService
from zope.context import ContextMethod
from zope.exceptions.exceptionformatter import format_exception
from zope.interface import implements
import logging
import time


#Restrict the rate at which errors are sent to the Event Log
_rate_restrict_pool = {}

# The number of seconds that must elapse on average between sending two
# exceptions of the same name into the the Event Log. one per minute.
_rate_restrict_period = 60

# The number of exceptions to allow in a burst before the above limit
# kicks in. We allow five exceptions, before limiting them to one per
# minute.
_rate_restrict_burst = 5

# _temp_logs holds the logs.
_temp_logs = {}  # { oid -> [ traceback string ] }

cleanup_lock = allocate_lock()

class ErrorReportingService(Persistent):
    """Error Reporting Service
    """
    implements(IErrorReportingService,
               ILocalErrorReportingService,
               ISimpleService,
               )

    keep_entries = 20
    copy_to_zlog = 0
    _ignored_exceptions = ('Unauthorized',)


    def _getLog(self):
        """Returns the log for this object.
        Careful, the log is shared between threads.
        """
        log = _temp_logs.get(self._p_oid, None)
        if log is None:
            log = []
            _temp_logs[self._p_oid] = log
        return log

    # Exceptions that happen all the time, so we dont need
    # to log them. Eventually this should be configured
    # through-the-web.
    def raising(self, info, request=None):
        """Log an exception.
        Called by ZopePublication.handleException method.
        """
        now = time.time()
        try:
            tb_text = None
            tb_html = None

            strtype = str(getattr(info[0], '__name__', info[0]))
            if strtype in self._ignored_exceptions:
                return

            if not isinstance(info[2], StringTypes):
                tb_text = ''.join(
                        format_exception(*info, **{'as_html': 0}))
                tb_html = ''.join(
                    format_exception(*info, **{'as_html': 1}))
            else:
                tb_text = info[2]

            url = None
            username = None
            req_html = None
            if request:
                # XXX: Temporary fix, which Steve should undo. URL is
                #      just too HTTPRequest-specific.
                if hasattr(request, 'URL'):
                    url = request.URL
                try:
                    # XXX: UnauthenticatedPrincipal does not have getLogin()
                    if hasattr(request.user, 'getLogin'):
                        login = request.user.getLogin()
                    else:
                        login = 'unauthenticated'
                    username = ', '.join((login,
                                          request.user.getId(),
                                          request.user.getTitle(),
                                          request.user.getDescription()
                                         ))
                # When there's an unauthorized access, request.user is
                # not set, so we get an AttributeError
                # XXX is this right? Surely request.user should be set!
                # XXX Answer: Catching AttributeError is correct for the
                #             simple reason that UnauthenticatedUser (which
                #             I always use during coding), has no 'getLogin()'
                #             method. However, for some reason this except
                #             does **NOT** catch these errors.
                except AttributeError:
                    pass

                req_html = ''.join(['%s : %s<br>' % item
                                    for item in request.items()])
            try:
                strv = str(info[1])
            # A call to str(obj) could raise anything at all.
            # We'll ignore these errors, and print something
            # useful instead, but also log the error.
            except:
                logging.getLogger('SiteError').exception(
                    'Error in ErrorReportingService while getting a str '
                    'representation of an object')
                strv = '<unprintable %s object>' % (
                        str(type(info[1]).__name__)
                        )

            log = self._getLog()
            entry_id = str(now) + str(random()) # Low chance of collision

            log.append({
                'type': strtype,
                'value': strv,
                'time': time.ctime(now),
                'id': entry_id,
                'tb_text': tb_text,
                'tb_html': tb_html,
                'username': username,
                'url': url,
                'req_html': req_html,
                })
            cleanup_lock.acquire()
            try:
                if len(log) >= self.keep_entries:
                    del log[:-self.keep_entries]
            finally:
                cleanup_lock.release()

            if self.copy_to_zlog:
                self._do_copy_to_zlog(now, strtype, str(url), info)
        finally:
            info = None
    raising = ContextMethod(raising)

    def _do_copy_to_zlog(self, now, strtype, url, info):
        # XXX info is unused; logging.exception() will call sys.exc_info()
        # work around this with an evil hack
        when = _rate_restrict_pool.get(strtype,0)
        if now > when:
            next_when = max(when,
                            now - _rate_restrict_burst*_rate_restrict_period)
            next_when += _rate_restrict_period
            _rate_restrict_pool[strtype] = next_when
            try:
                raise info[0], info[1], info[2]
            except:
                logging.getLogger('SiteError').exception(str(url))

    def getProperties(self):
        return {
            'keep_entries': self.keep_entries,
            'copy_to_zlog': self.copy_to_zlog,
            'ignored_exceptions': self._ignored_exceptions,
            }
    getProperties = ContextMethod(getProperties)

    def setProperties(self, keep_entries, copy_to_zlog=0,
                      ignored_exceptions=()):
        """Sets the properties of this site error log.
        """
        copy_to_zlog = bool(copy_to_zlog)
        self.keep_entries = int(keep_entries)
        self.copy_to_zlog = copy_to_zlog
        self._ignored_exceptions = tuple(
                filter(None, map(str, ignored_exceptions))
                )
    setProperties = ContextMethod(setProperties)
    def getLogEntries(self):
        """Returns the entries in the log, most recent first.

        Makes a copy to prevent changes.
        """
        res = [entry.copy() for entry in self._getLog()]
        res.reverse()
        return res
    getLogEntries = ContextMethod(getLogEntries)

    def getLogEntryById(self, id):
        """Returns the specified log entry.
        Makes a copy to prevent changes.  Returns None if not found.
        """
        for entry in self._getLog():
            if entry['id'] == id:
                return entry.copy()
        return None
    getLogEntryById = ContextMethod(getLogEntryById)


def _cleanup_temp_log():
    _temp_logs.clear()

_clear = _cleanup_temp_log
# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
from zope.testing.cleanup import addCleanUp
addCleanUp(_clear)
del addCleanUp



# XXX Pickle backward compatability
import sys
sys.modules['zope.app.services.errorr'
            ] = sys.modules['zope.app.services.error']


=== Added File Zope3/src/zope/app/services/interface.zcml ===
<zopeConfigure xmlns="http://namespaces.zope.org/zope">

<content class=".interface.LocalInterfaceService">
  <factory
      id="zope.app.services.LocalInterfaceService"
      permission="zope.ManageServices"
      />
  <require
      permission="zope.ManageServices"
      interface="zope.app.interfaces.component.IInterfaceService"
      />
</content>

</zopeConfigure>


=== Zope3/src/zope/app/services/README.txt 1.4.10.1 => 1.4.10.2 ===
--- Zope3/src/zope/app/services/README.txt:1.4.10.1	Sun Jun 22 10:23:26 2003
+++ Zope3/src/zope/app/services/README.txt	Mon Jun 23 10:20:21 2003
@@ -8,7 +8,7 @@
 This package includes implementations of several local services.
 It also contains infrastructure for implementing local services.
 
-Implementing lolcal services is not too difficult, but there can be a
+Implementing local services is not too difficult, but there can be a
 lot of details that are hard to remember.
 
 A service is a component that implements a specific interface *and*
@@ -32,7 +32,7 @@
   services by definition have nothing "above" them.
 
   (Note that it's up to the service to decide what form the
-  collaboration will take.  An exceptable form of collaboration is to
+  collaboration will take.  An acceptable form of collaboration is to
   not collaborate at all.
 
 Registration
@@ -46,9 +46,9 @@
 
 An important feature of component registration services is that they
 support multiple conflicting registrations for the same registration
-parameters.  At most one of the registrations is active.  A site
-developer can switch between alternate components by simply changing
-which one is active.
+parameters.  At most one of the conflicting registrations is active.
+A site developer can switch between alternate components by simply
+changing which one is active.
 
 Consider the following scenario.  A product provides a utility.  A
 site manager gets a new version of the utility and installs
@@ -93,8 +93,8 @@
 
 - Module-global registrations register objects stored in
   modules. Objects in modules aren't managable directly, so we can't
-  manage their registrations trough them.  (The state of an object
-  stored in a module must be respresented soley by the module source.)
+  manage their registrations through them.  (The state of an object
+  stored in a module must be represented solely by the module source.)
   
   Module-global objects are named using dotted names.
 


=== Zope3/src/zope/app/services/adapter.py 1.14.2.1 => 1.14.2.2 ===
--- Zope3/src/zope/app/services/adapter.py:1.14.2.1	Sun Jun 22 10:23:26 2003
+++ Zope3/src/zope/app/services/adapter.py	Mon Jun 23 10:20:21 2003
@@ -31,7 +31,6 @@
 from zope.app.services.registration import SimpleRegistration
 from zope.app.context import ContextWrapper
 from zope.context import ContextMethod
-from zope.app.services.registration import RegistrationStatusProperty
 from zope.app.component.nextservice import getNextService
 from zope.app.interfaces.services.service import ISimpleService
 
@@ -192,8 +191,6 @@
     implements(IAdapterRegistration)
 
     serviceType = Adapters
-
-    status = RegistrationStatusProperty()
 
     # XXX These should be positional arguments, except that forInterface
     #     isn't passed in if it is omitted. To fix this, we need a


=== Zope3/src/zope/app/services/auth.py 1.15.10.1 => 1.15.10.2 ===


=== Zope3/src/zope/app/services/cache.py 1.9.10.1 => 1.9.10.2 ===
--- Zope3/src/zope/app/services/cache.py:1.9.10.1	Sun Jun 22 10:23:27 2003
+++ Zope3/src/zope/app/services/cache.py	Mon Jun 23 10:20:21 2003
@@ -24,7 +24,6 @@
 from zope.app.interfaces.services.registration import INameComponentRegistry
 from zope.app.interfaces.services.event import IEventChannel
 from zope.app.interfaces.services.service import ISimpleService
-from zope.app.services.registration import RegistrationStatusProperty
 from zope.app.services.registration import NameComponentRegistry
 from zope.app.services.registration import NamedComponentRegistration
 from zope.app.services.event import ServiceSubscriberEventChannel
@@ -97,8 +96,6 @@
     implements(ICacheRegistration)
 
     serviceType = 'Caching'
-
-    status = RegistrationStatusProperty()
 
     label = "Cache"
 


=== Zope3/src/zope/app/services/configure.zcml 1.29.2.1 => 1.29.2.2 ===
--- Zope3/src/zope/app/services/configure.zcml:1.29.2.1	Sun Jun 22 10:23:27 2003
+++ Zope3/src/zope/app/services/configure.zcml	Mon Jun 23 10:20:21 2003
@@ -390,16 +390,23 @@
 
   <serviceType
       id="ErrorLogging"
-      interface="zope.app.interfaces.services.error.IErrorReportingService" />
+      interface="zope.app.interfaces.services.error.IErrorReportingService" 
+      />
 
-  <content class='zope.app.services.errorr.ErrorReportingService'>
+  <content class='zope.app.services.error.ErrorReportingService'>
     <require
         permission="zope.Public"
         interface="zope.app.interfaces.services.error.IErrorReportingService"
         />
+    <require
+        permission="zope.ManageServices"
+        interface="
+          zope.app.interfaces.services.error.ILocalErrorReportingService"
+        />
     <factory
         id='ErrorLogging'
-        permission='zope.Public' />
+        permission='zope.Public' 
+        />
     </content>
 
 <!-- Object Hub -->
@@ -559,5 +566,7 @@
   permission="zope.ManageContent"
   />
 
+<!-- Local Interface Service -->
+<include file="interface.zcml" />
 
 </zopeConfigure>


=== Zope3/src/zope/app/services/connection.py 1.11.10.1 => 1.11.10.2 ===
--- Zope3/src/zope/app/services/connection.py:1.11.10.1	Sun Jun 22 10:23:27 2003
+++ Zope3/src/zope/app/services/connection.py	Mon Jun 23 10:20:21 2003
@@ -11,19 +11,20 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""
+"""Connection service
+
 $Id$
 """
 
 from persistence import Persistent
-from zope.context import ContextMethod
-
+from zope.app.component.nextservice import queryNextService
 from zope.app.interfaces.rdb import IZopeDatabaseAdapter
+from zope.app.interfaces.services.connection import IConnectionRegistration
 from zope.app.interfaces.services.connection import ILocalConnectionService
 from zope.app.interfaces.services.service import ISimpleService
-
-from zope.app.component.nextservice import queryNextService
 from zope.app.services.registration import NameComponentRegistry
+from zope.app.services.registration import NamedComponentRegistration
+from zope.context import ContextMethod
 from zope.interface import implements
 
 class ConnectionService(Persistent, NameComponentRegistry):
@@ -73,10 +74,6 @@
     getAvailableConnections = ContextMethod(getAvailableConnections)
 
 
-from zope.app.interfaces.services.connection import IConnectionRegistration
-from zope.app.services.registration import NamedComponentRegistration
-from zope.app.services.registration import RegistrationStatusProperty
-
 class ConnectionRegistration(NamedComponentRegistration):
 
     __doc__ = IConnectionRegistration.__doc__
@@ -84,8 +81,6 @@
     implements(IConnectionRegistration)
 
     serviceType = 'SQLDatabaseConnections'
-
-    status = RegistrationStatusProperty()
 
     label = "Connection"
 


=== Zope3/src/zope/app/services/event.py 1.24.4.1 => 1.24.4.2 ===


=== Zope3/src/zope/app/services/field.py 1.7.18.1 => 1.7.18.2 ===


=== Zope3/src/zope/app/services/folder.py 1.6.10.1 => 1.6.10.2 ===


=== Zope3/src/zope/app/services/hub.py 1.10.10.1 => 1.10.10.2 ===


=== Zope3/src/zope/app/services/interface.py 1.5 => 1.5.4.1 ===
--- Zope3/src/zope/app/services/interface.py:1.5	Sat May  3 12:32:59 2003
+++ Zope3/src/zope/app/services/interface.py	Mon Jun 23 10:20:21 2003
@@ -11,12 +11,24 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Interfaces for persistent modules."""
+"""Code about services and interfaces.
+
+This module contains code for interfaces in persistent modules, and
+for the local interface service.
+"""
 
 from persistence import Persistent
 from zodb.code.patch import registerWrapper, Wrapper
 from zope.interface.interface import InterfaceClass
 
+from zope.app.component.nextservice import getNextService
+from zope.app.interfaces.services.service import ISimpleService
+from zope.app.interfaces.component import IInterfaceService
+from zope.app import zapi
+from zope.app.services.servicenames import Interfaces
+from zope.component import ComponentLookupError
+from zope.interface import implements
+
 class PersistentInterfaceClass(Persistent, InterfaceClass):
     pass
 
@@ -30,8 +42,45 @@
     def unwrap(self):
         return PersistentInterfaceClass(self._obj.__name__)
 
-def register():
+def register(): # XXX has been refactored on a branch
     registerWrapper(InterfaceClass, PersistentInterfaceWrapper,
                     lambda iface: (),
                     lambda iface: iface.__dict__,
                     )
+
+class LocalInterfaceService(object):
+    """I need a doc string."""
+    
+    implements(IInterfaceService,
+               ISimpleService)
+
+    # All the methods defined here are context methods
+    zapi.ContextAwareDescriptors()
+    
+    def getInterface(self, id):
+        # Return the interface registered for the given id
+        i = self.queryInterface(id)
+        if i is None:
+            raise ComponentLookupError(id)
+        return i
+
+    def queryInterface(self, id, default=None):
+        # Return the interface registered for the given id
+        next = getNextService(self, Interfaces)
+        return next.queryInterface(id, default)
+
+    def searchInterface(self, search_string="", base=None):
+        # Return the interfaces that match the search criteria
+        next = getNextService(self, Interfaces)
+        return next.searchInterface(search_string, base)
+
+    def searchInterfaceIds(self, search_string="", base=None):
+        # Return the ids of the interfaces that match the search criteria.
+        next = getNextService(self, Interfaces)
+        return next.searchInterfaceIds(search_string, base)
+
+    def items(self, search_string="", base=None):
+        # Return id, interface pairs for all items matching criteria.
+        next = getNextService(self, Interfaces)
+        return next.items(search_string, base)
+        


=== Zope3/src/zope/app/services/module.py 1.2.26.1 => 1.2.26.2 ===


=== Zope3/src/zope/app/services/pagefolder.py 1.5.10.1 => 1.5.10.2 ===


=== Zope3/src/zope/app/services/queryfield.py 1.2.22.1 => 1.2.22.2 ===


=== Zope3/src/zope/app/services/registration.py 1.1.2.1 => 1.1.2.2 ===
--- Zope3/src/zope/app/services/registration.py:1.1.2.1	Sun Jun 22 10:23:27 2003
+++ Zope3/src/zope/app/services/registration.py	Mon Jun 23 10:20:21 2003
@@ -66,9 +66,6 @@
 
         sm = getServiceManager(registration)
         service = sm.queryLocalService(registration.serviceType)
-        # XXX The following may fail; there's a subtle bug here when
-        # the returned service isn't in the same service manager as
-        # the one owning the registration.
         registry = service and service.queryRegistrationsFor(registration)
 
         if registry:
@@ -325,6 +322,9 @@
                       # *think* we do. :)
                       IAttributeAnnotatable,
                       )
+
+    
+    status = RegistrationStatusProperty()
 
     # Methods from IRegistration
 


=== Zope3/src/zope/app/services/role.py 1.4.18.1 => 1.4.18.2 ===


=== Zope3/src/zope/app/services/service.py 1.18.10.1 => 1.18.10.2 ===
--- Zope3/src/zope/app/services/service.py:1.18.10.1	Sun Jun 22 10:23:27 2003
+++ Zope3/src/zope/app/services/service.py	Mon Jun 23 10:20:21 2003
@@ -53,7 +53,6 @@
 # (used as 2nd argument to isinstance() in method resolve() below)
 ModuleType = type(IModuleService), PersistentModule
 
-from zope.app.services.registration import RegistrationStatusProperty
 from zope.app.services.registration import NameComponentRegistry
 from zope.app.services.registration import NamedComponentRegistration
 from zope.app.services.folder import SiteManagementFolders
@@ -124,8 +123,9 @@
         # This is rather tricky. Normally, getting a service requires
         # the use of other services, like the adapter service.  We
         # need to be careful not to get into an infinate recursion by
-        # getting out getService to be called while looking up
-        # services, so we'll
+        # getting our getService to be called while looking up
+        # services, so we'll use _v_calling to prevent recursive
+        # getService calls.
 
         if name == 'Services':
             return wrapped_self # We are the service service
@@ -302,8 +302,6 @@
     implements(IServiceRegistration)
 
     serviceType = 'Services'
-
-    status = RegistrationStatusProperty()
 
     label = "Service"
 


=== Zope3/src/zope/app/services/utility.py 1.6.10.1 => 1.6.10.2 ===
--- Zope3/src/zope/app/services/utility.py:1.6.10.1	Sun Jun 22 10:23:27 2003
+++ Zope3/src/zope/app/services/utility.py	Mon Jun 23 10:20:21 2003
@@ -26,7 +26,6 @@
 from zope.app.interfaces.services.utility import IUtilityRegistration
 from zope.app.interfaces.services.utility import ILocalUtilityService
 from zope.app.services.registration import RegistrationStack
-from zope.app.services.registration import RegistrationStatusProperty
 from zope.app.services.registration import ComponentRegistration
 from zope.component.exceptions import ComponentLookupError
 from zope.interface.implementor import ImplementorRegistry
@@ -115,8 +114,6 @@
     """
 
     serviceType = 'Utilities'
-
-    status = RegistrationStatusProperty()
 
     implements(IUtilityRegistration)
 


=== Zope3/src/zope/app/services/utility.txt 1.1.2.1 => 1.1.2.2 ===
--- Zope3/src/zope/app/services/utility.txt:1.1.2.1	Sun Jun 22 10:23:27 2003
+++ Zope3/src/zope/app/services/utility.txt	Mon Jun 23 10:20:21 2003
@@ -128,35 +128,33 @@
 
 We'll start by updating the utility service to support registrations.
 The updated local utility service implementation can be found in
-zope/app/services/utility.py.
+``zope/app/services/utility.py``. It's a good idea to refer to the
+source file as you read the description here.
 
 First, we'll pick a data structure.  We'll use a persistent dictionary
 mapping utility names to implementor registries.  An implementor
-registry implements a mapping from interfaces to objects; it's not
-quite the same as a mapping because it understands subclassing
-relationships between the interfaces used as keys.  In this case, the
-implementor registries themselves map interfaces to
-RegistrationStacks::
+registry implements a mapping from interfaces to objects; it's a
+special mapping because it understands subclassing relationships
+between the interfaces used as keys.  In this case, the implementor
+registries themselves map interfaces to RegistrationStacks. The
+overall data structure looks like::
 
   { utility_name -> { interface -> stack } }
 
-
 We also need to implement
-zope.app.interfaces.services.registration.IRegistry.  This defines two
-methods, ``queryRegistrationsFor`` and ``createRegistrationsFor``.
-
-A ``queryRegistrationsFor`` method is added to implement
-``IRegistry``.  It takes a registration object and returns the
-corresponding registration registry.  The registration object is
-used to provide an abstract way to represent registration parameters.
-Typically, the registration parameters are extracted and a more
-concrete method is called.  In the local utility service, we extract
-the utility name and interface and call ``queryRegistrations`` with
-the name and interface.
+``zope.app.interfaces.services.registration.IRegistry``.  This defines
+two methods, ``queryRegistrationsFor`` and ``createRegistrationsFor``.
+The ``queryRegistrationsFor`` method takes a registration object and
+returns the corresponding registration stack.  The registration
+object is used to provide an abstract way to represent registration
+parameters.  Typically, the registration parameters are extracted and
+a more concrete method is called.  In the local utility service, we
+extract the utility name and interface and call ``queryRegistrations``
+with the name and interface.
 
-Similarly, we add a ``createRegistrationsFor`` method that takes a
+Similarly, the``createRegistrationsFor`` method takes a
 registration object holding registration parameters and creates a
-registration registry for the parameters (if none already exists).
+registration stack for the parameters (if none already exists).
 If we don't have a implementor registry for a utility name, we create
 one and add it.  When we create the implementor registry, we pass a
 ``PersistentDict`` for it to use to store registration data.  This
@@ -164,17 +162,17 @@
 data for the given interface, we create a registration registry and
 register it for the interface.
 
-Finally, we modify ``queryUtility`` to use registered utility
-registrations.  We try to get a registration registery by calling
-``queryRegistrations``.  If we get one, we call its ``active``
-method to get the active registration, if any.  Finally, we call
-``getComponent`` on the active registration to get the actual
-component.  We leave it up to the registration object to take care of
-actually finding and returning the component.
-
-We need to provide utility registration objects.  The
-utility registration objects need to manage several bits of
-information:
+Finally, we modify ``queryUtility`` to use registered utilities.  We
+try to get a registration stack by calling ``queryRegistrations``.  If
+we get one, we call its ``active`` method to get the active
+registration, if any.  Finally, we call ``getComponent`` on the active
+registration to get the actual component.  We leave it up to the
+registration object to take care of actually finding and returning the
+component.
+
+In addition to the utility service, We need to provide utility
+registration objects.  The utility registration objects need to manage
+several bits of information:
 
 - name
 
@@ -185,29 +183,30 @@
 - The location of the actual component.
 
 The registration objects provide access to the component through the
-getComponent method.
+``getComponent`` method.
 
 To create the registration class, we'll start by defining a
-registration schema in
-``zope/app/interfaces/services/utility.py``.  The schema should extend
-``zope.app.interfaces.services.registration.IRegistration``.
-There's a more specific interface,
+registration schema in ``zope/app/interfaces/services/utility.py``.
+The schema should extend
+``zope.app.interfaces.services.registration.IRegistration``.  There's
+a more specific interface,
 ``zope.app.interfaces.services.registration.IComponentRegistration``
-that is much closer to what we need.  (XXX Add footnote explaining why
-we can't use INamedComponentRegistration in this example.)
-We extend this interface as IUtilityRegistration, which adds a name
-field (which is required but may be empty -- note the subtle
-difference, because the empty string is still used as part of the
-lookup key) and an interface field.  We also override the
-componentPath field to make it read-only (this is for the UI
-definition).
+that is much closer to what we need. [2]_ We extend this interface as
+IUtilityRegistration, which adds a name field (which is required but
+may be empty -- note the subtle difference, because the empty string
+is still used as part of the lookup key) and an interface field.  We
+also override the componentPath field to make it read-only (this is
+for the UI definition).
 
 A ``UtilityRegistration`` class is added to the ``utility`` module in
 ``zope/app/services`` that implements the registration interface.  We
-can subclass ComponentRegistration, which does much of the work.  Note
-that registration component includes two methods, defined in
+can subclass ComponentRegistration, which does much of the work.  The
+class definition includes a ``serviceType`` attribute. This attribute
+is used by the registration framework to decide which service a
+registration is used with.  The class includes two methods, defined in
 ``IRegistration``, giving summary information used by several
-predefined views.  See the interface for a description of these methods.
+predefined views.  See the interface for a description of these
+methods.
 
 We need to provide user interfaces for:
 
@@ -355,3 +354,11 @@
 
 .. [1] Of course, I initially forgot to include a nearly empty
    ``__init__.py`` file and had to add one later.
+
+.. [2] It's tempting to use ``INamedComponentRegistration`, but
+   ``INamedComponentRegistration`` is based on ``INamedRegistration``,
+   which is for registring components looked up by name alone.
+   ``INamedRegistration`` requires a non-empty name, but we want to
+   allow empty names, as we are looking up objects based on **both**
+   name and interface.
+ 


=== Zope3/src/zope/app/services/view.py 1.18.4.1 => 1.18.4.2 ===
--- Zope3/src/zope/app/services/view.py:1.18.4.1	Sun Jun 22 10:23:27 2003
+++ Zope3/src/zope/app/services/view.py	Mon Jun 23 10:20:21 2003
@@ -29,7 +29,6 @@
 from zope.app.services.registration import SimpleRegistration
 from zope.app.context import ContextWrapper
 from zope.context import ContextMethod
-from zope.app.services.registration import RegistrationStatusProperty
 from zope.app.component.nextservice import getNextService
 from zope.component import getSkin
 from zope.interface import implements
@@ -220,8 +219,6 @@
     implements(IViewRegistration)
 
     serviceType = 'Views'
-
-    status = RegistrationStatusProperty()
 
     _what = "View" # For usageSummary(); subclass may override
 


=== Zope3/src/zope/app/services/zpt.py 1.10.10.1 => 1.10.10.2 ===