[Zope3-checkins]
SVN: Zope3/branches/srichter-blow-services/src/zope/app/
Made the first registration-related tests pass. See the TXT files in
Stephan Richter
srichter at cosmos.phy.tufts.edu
Thu Dec 23 13:26:32 EST 2004
Log message for revision 28692:
Made the first registration-related tests pass. See the TXT files in
zope.app.component.
Along the way I noticed that there are many circular imports in all of
this code. I think that my refactorings will improve the situation.
Changed:
U Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/adapter.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/__init__.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/__init__.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/adapter.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/localservice.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/registration.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/browser/__init__.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/tests/
U Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/utility/utility.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/contentdirective.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/hooks.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces/
A Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces/__init__.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces/registration.py
D Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py
U Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/registration.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/registration.txt
U Zope3/branches/srichter-blow-services/src/zope/app/component/site.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/statusproperty.txt
D Zope3/branches/srichter-blow-services/src/zope/app/component/tests/service.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/tests/test_registration.py
U Zope3/branches/srichter-blow-services/src/zope/app/publication/zopepublication.py
-=-
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -17,7 +17,30 @@
"""
__docformat__ = "reStructuredText"
+##############################################################################
+# BBB: Backward Compatiblity 12/23/2004
+import sys
+import zope.app
+from zope.app.component.bbb import registration
+sys.modules['zope.app.registration'] = registration
+zope.app.registration = registration
+from zope.app.component.bbb import localservice
+sys.modules['zope.app.component.localservice'] = localservice
+from zope.app.component.bbb import site
+sys.modules['zope.app.site'] = site
+zope.app.site = site
+from zope.app.component.bbb import adapter
+sys.modules['zope.app.adapter'] = adapter
+zope.app.adapter = adapter
+from zope.app.component.bbb import utility
+sys.modules['zope.app.utility'] = utility
+zope.app.utility = utility
+
+##############################################################################
+
+
+
_marker = object()
def getNextUtility(context, interface, name=''):
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/adapter.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/adapter.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/adapter.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -16,26 +16,26 @@
$Id$
"""
__docformat__ = 'restructuredtext'
-
+import sys
from persistent.dict import PersistentDict
from persistent import Persistent
-from zope.app import zapi
-from zope.app.registration.registration import NotifyingRegistrationStack
+
+import zope.component.adapter
+import zope.interface
+import zope.schema
from zope.interface.adapter import adapterImplied, Default
from zope.interface.adapter import Surrogate, AdapterRegistry
from zope.security.proxy import removeSecurityProxy
-import sys
+
import zope.app.component.localservice
import zope.app.container.contained
-import zope.app.registration.interfaces
import zope.app.site.interfaces
-import zope.app.registration
import zope.component.interfaces
-import zope.component.adapter
-import zope.interface
-import zope.schema
+from zope.app import zapi
+from zope.app.component.interfaces.registration import IRegistry
from zope.app.i18n import ZopeMessageIDFactory as _
+
class LocalSurrogate(Surrogate):
"""Local surrogates
@@ -61,20 +61,18 @@
self.adapters = adapters
Surrogate.clean(self)
+
class LocalAdapterRegistry(AdapterRegistry, Persistent):
- """Local/persistent surrogate registry
- """
+ """Local/persistent surrogate registry"""
- zope.interface.implements(
- zope.app.registration.interfaces.IRegistry,
- )
+ zope.interface.implements(IRegistry)
_surrogateClass = LocalSurrogate
# Next local registry, may be None
- next = None
+ nextRegistry = None
- subs = ()
+ subRegistries = ()
def __init__(self, base, next=None):
@@ -82,11 +80,11 @@
self.base = base
self.adapters = {}
- self.stacks = PersistentDict()
+ self.registrations = PersistentDict()
AdapterRegistry.__init__(self)
- self.setNext(next)
+ self.setNextRegistry(next)
- def setNext(self, next, base=None):
+ def setNextRegistry(self, next, base=None):
if base is not None:
self.base = base
if self.next is not None:
@@ -96,10 +94,10 @@
self.next = next
self.adaptersChanged()
- def addSub(self, sub):
+ def addSubRegistry(self, sub):
self.subs += (sub, )
- def removeSub(self, sub):
+ def removeSubRegistry(self, sub):
self.subs = tuple([s for s in self.subs if s is not sub])
def __getstate__(self):
@@ -119,34 +117,6 @@
def baseFor(self, spec):
return self.base.get(spec)
- def queryRegistrationsFor(self, registration, default=None):
- stacks = self.stacks.get(registration.required)
- if stacks:
- stack = stacks.get((False, registration.with, registration.name,
- registration.provided))
- if stack is not None:
- return stack
-
- return default
-
- _stackType = NotifyingRegistrationStack
-
- def createRegistrationsFor(self, registration):
- stacks = self.stacks.get(registration.required)
- if stacks is None:
- stacks = PersistentDict()
- self.stacks[registration.required] = stacks
-
- key = (False, registration.with, registration.name,
- registration.provided)
- stack = stacks.get(key)
- if stack is None:
- stack = self._stackType(self)
- stacks[key] = stack
-
- return stack
-
-
def _updateAdaptersFromLocalData(self, adapters):
for required, stacks in self.stacks.iteritems():
if required is None:
@@ -168,7 +138,7 @@
radapters[key] = removeSecurityProxy(registration.factory)
- def adaptersChanged(self, *args):
+ def adaptersChanged(self):
adapters = {}
if self.next is not None:
@@ -187,8 +157,6 @@
for sub in self.subs:
sub.adaptersChanged()
- notifyActivated = notifyDeactivated = adaptersChanged
-
def baseChanged(self):
"""Someone changed the base service
Added: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/__init__.py
===================================================================
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/__init__.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/__init__.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/__init__.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -16,7 +16,7 @@
$Id$
"""
-from zope.app.adapter.adapter import IAdapterRegistration
-from zope.app.adapter.adapter import LocalAdapterRegistry
-from zope.app.adapter.adapter import LocalAdapterBasedService
+from zope.app.component.bbb.adapter.adapter import IAdapterRegistration
+from zope.app.component.bbb.adapter.adapter import LocalAdapterRegistry
+from zope.app.component.bbb.adapter.adapter import LocalAdapterBasedService
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/adapter.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/adapter.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/adapter/adapter.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -29,7 +29,6 @@
import zope.app.container.contained
import zope.app.registration.interfaces
import zope.app.site.interfaces
-import zope.app.registration
import zope.component.interfaces
import zope.component.adapter
import zope.interface
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/localservice.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/localservice.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/localservice.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -21,7 +21,7 @@
from zope.component.exceptions import ComponentLookupError
from zope.component.service import serviceManager
from zope.component.interfaces import IServiceService
-from zope.app.site.interfaces import ISite, ISiteManager
+from zope.app.component.bbb.site.interfaces import ISite, ISiteManager
from zope.testing.cleanup import addCleanUp
from zope.app.component.hooks import setSite
from zope.component.service import IGlobalServiceManager
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/registration.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/registration.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/registration.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -29,7 +29,7 @@
from zope.app import zapi
from zope.app.annotation.interfaces import IAttributeAnnotatable
-from zope.app.component.localservice import getLocalServices
+#from zope.app.component.localservice import getLocalServices
from zope.app.container.contained import Contained
from zope.app.container.contained import setitem, contained, uncontained
from zope.app.copypastemove import ObjectCopier
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/browser/__init__.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/browser/__init__.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/site/browser/__init__.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -23,7 +23,7 @@
from zope.app.registration.interfaces import UnregisteredStatus
from zope.app.registration.interfaces import RegisteredStatus
from zope.app.registration.interfaces import ActiveStatus
-from zope.app.site.interfaces import ILocalService
+from zope.app.component.bbb.site.interfaces import ILocalService
from zope.app.utility.interfaces import ILocalUtility
from zope.app.site.service import ServiceRegistration
from zope.app.publisher.browser import BrowserView
Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/tests (from rev 28677, Zope3/branches/srichter-blow-services/src/zope/app/component/tests)
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/utility/utility.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/utility/utility.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/utility/utility.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -27,8 +27,8 @@
from zope.app.adapter.adapter import LocalAdapterService
from zope.app.component.localservice import queryNextService
from zope.app.registration.registration import ComponentRegistration
-from zope.app.utility.interfaces import ILocalUtilityService
-from zope.app.utility.interfaces import IUtilityRegistration
+from interfaces import ILocalUtilityService
+from interfaces import IUtilityRegistration
class LocalUtilityService(UtilityService, LocalAdapterService):
"""Local Utility Service
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/contentdirective.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/contentdirective.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/contentdirective.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -18,15 +18,20 @@
__docformat__ = 'restructuredtext'
from types import ModuleType
+from persistent.interfaces import IPersistent
+from zope.component.factory import Factory
from zope.interface import classImplements
from zope.schema.interfaces import IField
from zope.configuration.exceptions import ConfigurationError
from zope.app import zapi
-from zope.component.factory import Factory
-from zope.app.security.protectclass \
- import protectLikeUnto, protectName, protectSetAttribute
+from zope.app.annotation.interfaces import IAttributeAnnotatable
from zope.app.component.interface import provideInterface
+from zope.app.component.interfaces import ILocalUtility
+from zope.app.location.interfaces import ILocation
+from zope.app.security.protectclass import protectLikeUnto, protectName
+from zope.app.security.protectclass import protectSetAttribute
+
from metaconfigure import factory
PublicPermission = 'zope.Public'
@@ -175,3 +180,59 @@
# so addable names must also act as if they were all in the
# same namespace, despite the service/content division
factory(_context, factoryObj, id, title, description)
+
+
+class LocalUtilityDirective(ContentDirective):
+ r"""localUtility directive handler.
+
+ Examples:
+
+ >>> from zope.interface import implements
+ >>> class LU1(object):
+ ... pass
+
+ >>> class LU2(LU1):
+ ... implements(ILocation)
+
+ >>> class LU3(LU1):
+ ... __parent__ = None
+
+ >>> class LU4(LU2):
+ ... implements(IPersistent)
+
+ >>> dir = LocalUtilityDirective(None, LU4)
+ >>> IAttributeAnnotatable.implementedBy(LU4)
+ True
+ >>> ILocalUtility.implementedBy(LU4)
+ True
+
+ >>> LocalUtilityDirective(None, LU3)
+ Traceback (most recent call last):
+ ...
+ ConfigurationError: Class `LU3` does not implement `IPersistent`.
+
+ >>> LocalUtilityDirective(None, LU2)
+ Traceback (most recent call last):
+ ...
+ ConfigurationError: Class `LU2` does not implement `IPersistent`.
+
+ >>> LocalUtilityDirective(None, LU1)
+ Traceback (most recent call last):
+ ...
+ ConfigurationError: Class `LU1` does not implement `ILocation`.
+ """
+
+ def __init__(self, _context, class_):
+ if not ILocation.implementedBy(class_) and \
+ not hasattr(class_, '__parent__'):
+ raise ConfigurationError, \
+ 'Class `%s` does not implement `ILocation`.' %class_.__name__
+
+ if not IPersistent.implementedBy(class_):
+ raise ConfigurationError, \
+ 'Class `%s` does not implement `IPersistent`.' %class_.__name__
+
+ classImplements(class_, IAttributeAnnotatable)
+ classImplements(class_, ILocalUtility)
+
+ super(LocalUtilityDirective, self).__init__(_context, class_)
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/hooks.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/hooks.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/hooks.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -18,7 +18,7 @@
__docformat__ = 'restructuredtext'
import zope.component
-from zope.app.site.interfaces import ISite
+from zope.app.component.interfaces import ISite
from zope.component.exceptions import ComponentLookupError
from zope.security.proxy import removeSecurityProxy
from zope.app.traversing.interfaces import IContainmentRoot
@@ -41,7 +41,7 @@
class SiteInfo(zope.thread.local):
site = None
- services = serviceManager
+ #services = serviceManager
def adapter_hook(self):
services = self.services
Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces/__init__.py (from rev 28687, Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py)
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py 2004-12-22 17:17:53 UTC (rev 28687)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces/__init__.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -0,0 +1,237 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interfaces for the Local Component Architecture
+
+$Id$
+"""
+import zope.interface
+import zope.schema
+from zope.component.interfaces import ISiteManager
+from zope.app.container.interfaces import IContainer
+from zope.app.container.constraints import ContainerTypesConstraint
+from zope.app.container.constraints import ItemTypePrecondition
+from zope.app.i18n import ZopeMessageIDFactory as _
+import registration
+
+class IComponentManager(zope.interface.Interface):
+
+ def queryComponent(type=None, filter=None, all=0):
+ """Return all components that match the given type and filter
+
+ The objects are returned a sequence of mapping objects with keys:
+
+ path -- The component path
+
+ component -- The component
+
+ all -- A flag indicating whether all component managers in
+ this place should be queried, or just the local one.
+ """
+
+class IBindingAware(zope.interface.Interface):
+
+ def bound(name):
+ """Inform a service component that it is providing a service
+
+ Called when an immediately-containing service manager binds
+ this object to perform the named service.
+ """
+
+ def unbound(name):
+ """Inform a service component that it is no longer providing a service
+
+ Called when an immediately-containing service manager unbinds
+ this object from performing the named service.
+ """
+
+class IPossibleSite(zope.interface.Interface):
+ """An object that could be a site
+ """
+
+ def setSiteManager(sitemanager):
+ """Sets the service manager for this object.
+ """
+
+ def getSiteManager():
+ """Returns the service manager contained in this object.
+
+ If there isn't a service manager, raise a component lookup.
+ """
+
+class ISite(IPossibleSite):
+ """Marker interface to indicate that we have a site
+ """
+
+class ILocalSiteManager(ISiteManager, IComponentManager,
+ registration.IRegistry):
+ """Service Managers act as containers for Services.
+
+ If a Service Manager is asked for a service, it checks for those it
+ contains before using a context-based lookup to find another service
+ manager to delegate to. If no other service manager is found they defer
+ to the ComponentArchitecture ServiceManager which contains file based
+ services.
+ """
+
+ def queryRegistrations(name, default=None):
+ """Return an IRegistrationRegistry for the registration name.
+
+ queryRegistrationsFor(cfg, default) is equivalent to
+ queryRegistrations(cfg.name, default)
+ """
+
+ def createRegistrationsFor(registration):
+ """Create and return an IRegistrationRegistry for the registration
+ name.
+
+ createRegistrationsFor(cfg, default) is equivalent to
+ createRegistrations(cfg.name, default)
+ """
+
+ def listRegistrationNames():
+ """Return a list of all registered registration names.
+ """
+
+ def queryActiveComponent(name, default=None):
+ """Finds the registration registry for a given name, checks if it has
+ an active registration, and if so, returns its component. Otherwise
+ returns default.
+ """
+
+ def addSubsite(subsite):
+ """Add a subsite of the site
+
+ Local sites are connected in a tree. Each site knows about
+ its containing sites and its subsites.
+ """
+
+ next = zope.interface.Attribute('The site that this site is a subsite of.')
+
+ def findModule(name):
+ """Find the module of the given name.
+
+ If the module can be find in the folder or a parent folder
+ (within the site manager), then return it, otherwise, delegate
+ to the module service.
+
+ This must return None when the module is not found.
+
+ """
+
+ def resolve(name):
+ """Resolve a dotted object name.
+
+ A dotted object name is a dotted module name and an object
+ name within the module.
+
+ TODO: We really should switch to using some other character than
+ a dot for the delimiter between the module and the object
+ name.
+
+ """
+
+class ISiteManagementFolder(registration.IRegisterableContainer,
+ IContainer):
+ """Component and component registration containers."""
+
+ __parent__ = zope.schema.Field(
+ constraint = ContainerTypesConstraint(
+ ISiteManager,
+ registration.IRegisterableContainer,
+ ),
+ )
+
+class ISiteManagementFolders(IContainer, IComponentManager):
+ """A collection of ISiteManagementFolder objects.
+
+ An ISiteManagementFolders object supports simple containment as
+ well as package query and lookup.
+
+ """
+
+class ILocalUtility(registration.IRegisterable):
+ """Local utility marker.
+
+ A marker interface that indicates that a component can be used as
+ a local utility.
+
+ Utilities should usually also declare they implement
+ IAttributeAnnotatable, so that the standard adapter to
+ IRegistered can be used; otherwise, they must provide
+ another way to be adaptable to IRegistered.
+ """
+
+
+
+
+
+class IAdapterRegistration(registration.IRegistration):
+
+ required = zope.schema.Choice(
+ title = _(u"For interface"),
+ description = _(u"The interface of the objects being adapted"),
+ vocabulary="Interfaces",
+ readonly = True)
+
+ provided = zope.schema.Choice(
+ title = _(u"Provided interface"),
+ description = _(u"The interface provided"),
+ vocabulary="Interfaces",
+ readonly = True,
+ required = True)
+
+ name = zope.schema.TextLine(
+ title=_(u"Name"),
+ readonly=True,
+ required=False,
+ )
+
+ factoryName = zope.schema.BytesLine(
+ title=_(u"The dotted name of a factory for creating the adapter"),
+ readonly = True,
+ required = True,
+ )
+
+ permission = zope.schema.Choice(
+ title=_(u"The permission required for use"),
+ vocabulary="Permission Ids",
+ readonly=False,
+ required=False,
+ )
+
+ factory = zope.interface.Attribute(
+ _("Factory to be called to construct the component")
+ )
+
+class IUtilityRegistration(registration.IComponentRegistration):
+ """Utility registration object.
+
+ This is keyed off name (which may be empty) and interface. It inherits the
+ `component` property.
+ """
+
+ name = zope.schema.TextLine(
+ title=_("Register As"),
+ description=_("The name that is registered"),
+ readonly=True,
+ required=True,
+ )
+
+ interface = zope.schema.Choice(
+ title=_("Provided interface"),
+ description=_("The interface provided by the utility"),
+ vocabulary="Utility Component Interfaces",
+ readonly=True,
+ required=True,
+ )
Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces/registration.py (from rev 28687, Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/interfaces.py)
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/interfaces.py 2004-12-22 17:17:53 UTC (rev 28687)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces/registration.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -0,0 +1,188 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interfaces for objects supporting registration
+
+$Id$
+"""
+import zope.component.interfaces
+from zope.interface import Interface, Attribute, implements
+from zope.schema import TextLine, Field, Choice, Dict
+from zope.schema.interfaces import ITextLine, IField
+
+from zope.app.annotation.interfaces import IAnnotatable
+from zope.app.annotation.interfaces import IAttributeAnnotatable
+from zope.app.container.interfaces import IContainerNamesContainer
+from zope.app.container.interfaces import IContained, IContainer
+from zope.app.container.constraints import contains, containers
+from zope.app.event.interfaces import IObjectEvent
+from zope.app.i18n import ZopeMessageIDFactory as _
+
+InactiveStatus = _('Inactive')
+ActiveStatus = _('Active')
+
+
+class IRegistrationEvent(IObjectEvent):
+ """An event that involves a registration"""
+
+class IRegistrationActivatedEvent(IRegistrationEvent):
+ """This event is fired, when a component's registration is activated."""
+
+class IRegistrationDeactivatedEvent(IRegistrationEvent):
+ """This event is fired, when a component's registration is deactivated."""
+
+
+class IRegistration(Interface):
+ """Registration object
+
+ A registration object represents a specific registration
+ decision, such as registering an adapter or defining a permission.
+
+ In addition to the attributes or methods defined here,
+ registration objects will include additional attributes
+ identifying how they should be used. For example, a service
+ registration will provide a service type. An adapter
+ registration will specify a used-for interface and a provided
+ interface.
+ """
+
+ status = Choice(
+ title=_("Registration status"),
+ values=(InactiveStatus, ActiveStatus),
+ default=InactiveStatus
+ )
+
+class IComponent(IField):
+ """A component path
+
+ This is just the interface for the ComponentPath field below. We'll use
+ this as the basis for looking up an appropriate widget.
+ """
+
+class Component(Field):
+ """A component path
+
+ Values of the field are absolute unicode path strings that can be
+ traversed to get an object.
+ """
+ implements(IComponent)
+
+
+class IComponentRegistration(IRegistration):
+ """Registration object that uses a component path and a permission."""
+
+ permission = Choice(
+ title=_("The permission needed to use the component"),
+ vocabulary="Permissions",
+ required=False,
+ )
+
+ component = Component(
+ title=_("Registration Component"),
+ description=_("The component the registration is for."),
+ required=True)
+
+ def getInterface(self):
+ """Return the interface the component provides through this
+ registration.
+
+ If no interface was specified, return `None`.
+
+ The interface will be used to produce a proxy for the component, if
+ the `permission` is specified.
+ """
+
+
+class IRegistry(zope.component.interfaces.IRegistry):
+ """A component that can be configured using a registration manager."""
+
+ def register(registration):
+ """Register a component with the registry using a registration.
+
+ Once the registration is added to the registry, it will be active. If
+ the registration is already registered with the registry, this method
+ will quietly return.
+ """
+
+ def unregister(registration):
+ """Unregister a component from the registry.
+
+ Unregistering a registration automatically makes the component
+ inactive. If the registration is not registered, this method will
+ quietly return.
+ """
+
+ def registered(registration):
+ """Determine whether a registration is registered with the registry.
+
+ The method will return a Boolean value.
+ """
+
+
+class IRegistrationManager(IContainerNamesContainer):
+ """Manage Registrations"""
+
+ def addRegistration(registration):
+ """Add a registration to the manager.
+
+ The function will automatically choose a name as which the
+ registration will be known. The name of the registration inside this
+ manager is returned.
+ """
+
+
+class IRegisterableContainer(IContainer):
+ """Containers with registration managers
+
+ These are site-management folders of one sort or another.
+
+ The container allows clients to access the registration manager
+ without knowing it's name.
+
+ The registration manager container *also* supports local-module
+ lookup.
+ """
+
+ registrationManager = Field(
+ title=_("Registration Manager"),
+ description=_("The registration manager keeps track of all component "
+ "registrations."))
+
+
+class IRegisterable(IContained):
+ """Mark a component as registerable.
+
+ All registerable components need to implement this interface.
+ """
+ containers(IRegisterableContainer)
+
+
+class IRegisterableContainerContaining(IContainer):
+ """A container that can only contain `IRegisterable`s and
+ `IRegisterableContainer`s.
+
+ This interface was designed to be always used together with the
+ `IRegisterableContainer`.
+ """
+ contains(IRegisterable, IRegisterableContainer)
+
+
+class IRegistered(Interface):
+ """An object that can track down its registrations.
+
+ The object need not implement this functionality itself, but must at
+ least support doing so via an adapter.
+ """
+
+ def registrations():
+ """Return a sequence of registration objects for this object."""
Deleted: Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/interfaces.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -1,218 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Interfaces for the Local Component Architecture
-
-$Id$
-"""
-import zope.interface
-import zope.schema
-from zope.component.interfaces import ISiteManager
-from zope.app.container.interfaces import IContainer
-from zope.app.container.constraints import ContainerTypesConstraint
-from zope.app.container.constraints import ItemTypePrecondition
-from zope.app.registration import interfaces as registration
-
-
-class IComponentManager(zope.interface.Interface):
-
- def queryComponent(type=None, filter=None, all=0):
- """Return all components that match the given type and filter
-
- The objects are returned a sequence of mapping objects with keys:
-
- path -- The component path
-
- component -- The component
-
- all -- A flag indicating whether all component managers in
- this place should be queried, or just the local one.
- """
-
-class IBindingAware(Interface):
-
- def bound(name):
- """Inform a service component that it is providing a service
-
- Called when an immediately-containing service manager binds
- this object to perform the named service.
- """
-
- def unbound(name):
- """Inform a service component that it is no longer providing a service
-
- Called when an immediately-containing service manager unbinds
- this object from performing the named service.
- """
-
-class IPossibleSite(zope.interface.Interface):
- """An object that could be a site
- """
-
- def setSiteManager(sm):
- """Sets the service manager for this object.
- """
-
- def getSiteManager():
- """Returns the service manager contained in this object.
-
- If there isn't a service manager, raise a component lookup.
- """
-
-class ISite(IPossibleSite):
- """Marker interface to indicate that we have a site
- """
-
-class ILocalSiteManager(ISiteManager, IComponentManager,
- registration.IRegistry):
- """Service Managers act as containers for Services.
-
- If a Service Manager is asked for a service, it checks for those it
- contains before using a context-based lookup to find another service
- manager to delegate to. If no other service manager is found they defer
- to the ComponentArchitecture ServiceManager which contains file based
- services.
- """
-
- def queryRegistrations(name, default=None):
- """Return an IRegistrationRegistry for the registration name.
-
- queryRegistrationsFor(cfg, default) is equivalent to
- queryRegistrations(cfg.name, default)
- """
-
- def createRegistrationsFor(registration):
- """Create and return an IRegistrationRegistry for the registration
- name.
-
- createRegistrationsFor(cfg, default) is equivalent to
- createRegistrations(cfg.name, default)
- """
-
- def listRegistrationNames():
- """Return a list of all registered registration names.
- """
-
- def queryActiveComponent(name, default=None):
- """Finds the registration registry for a given name, checks if it has
- an active registration, and if so, returns its component. Otherwise
- returns default.
- """
-
- def queryLocalService(service_type, default=None):
- """Return a local service, if there is one
-
- A local service is one configured in the local service manager.
- """
-
- def addSubsite(subsite):
- """Add a subsite of the site
-
- Local sites are connected in a tree. Each site knows about
- its containing sites and its subsites.
- """
-
- next = Attribute('The site that this site is a subsite of.')
-
-
-class ISiteManagementFolder(registration.IRegisterableContainer,
- IContainer):
- """Component and component registration containers."""
-
- __parent__ = zope.schema.Field(
- constraint = ContainerTypesConstraint(
- ISiteManager,
- registration.IRegisterableContainer,
- ),
- )
-
-class ISiteManagementFolders(IContainer, IComponentManager):
- """A collection of ISiteManagementFolder objects.
-
- An ISiteManagementFolders object supports simple containment as
- well as package query and lookup.
-
- """
-
-class ILocalUtility(registration.IRegisterable):
- """Local utility marker.
-
- A marker interface that indicates that a component can be used as
- a local utility.
-
- Utilities should usually also declare they implement
- IAttributeAnnotatable, so that the standard adapter to
- IRegistered can be used; otherwise, they must provide
- another way to be adaptable to IRegistered.
- """
-
-
-class IAdapterRegistration(registration.IRegistration):
-
- required = zope.schema.Choice(
- title = _(u"For interface"),
- description = _(u"The interface of the objects being adapted"),
- vocabulary="Interfaces",
- readonly = True)
-
- provided = zope.schema.Choice(
- title = _(u"Provided interface"),
- description = _(u"The interface provided"),
- vocabulary="Interfaces",
- readonly = True,
- required = True)
-
- name = zope.schema.TextLine(
- title=_(u"Name"),
- readonly=True,
- required=False,
- )
-
- factoryName = zope.schema.BytesLine(
- title=_(u"The dotted name of a factory for creating the adapter"),
- readonly = True,
- required = True,
- )
-
- permission = zope.schema.Choice(
- title=_(u"The permission required for use"),
- vocabulary="Permission Ids",
- readonly=False,
- required=False,
- )
-
- factory = zope.interface.Attribute(
- _("Factory to be called to construct the component")
- )
-
-class IUtilityRegistration(registration.IComponentRegistration):
- """Utility registration object.
-
- This is keyed off name (which may be empty) and interface. It inherits the
- `component` property.
- """
-
- name = zope.schema.TextLine(
- title=_("Register As"),
- description=_("The name that is registered"),
- readonly=True,
- required=True,
- )
-
- interface = zope.schema.Choice(
- title=_("Provided interface"),
- description=_("The interface provided by the utility"),
- vocabulary="Utility Component Interfaces",
- readonly=True,
- required=True,
- )
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/metaconfigure.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -16,12 +16,11 @@
$Id$
"""
__docformat__ = 'restructuredtext'
-from persistent.interfaces import IPersistent
from zope.component.interfaces import IDefaultViewName, IFactory
from zope.component.service import UndefinedService
from zope.configuration.exceptions import ConfigurationError
-from zope.interface import Interface, classImplements
+from zope.interface import Interface
from zope.interface.interfaces import IInterface
from zope.security.checker import InterfaceChecker, CheckerPublic
@@ -29,11 +28,7 @@
from zope.security.proxy import Proxy, ProxyFactory
from zope.app import zapi
-from zope.app.annotation.interfaces import IAttributeAnnotatable
-from zope.app.component.contentdirective import ContentDirective
from zope.app.component.interface import queryInterface
-from zope.app.component.interfaces import ILocalUtility
-from zope.app.location.interfaces import ILocation
from zope.app.security.adapter import TrustedAdapterFactory
@@ -398,59 +393,3 @@
(type,), IInterface, 'defaultLayer',
lambda request: layer, _context.info)
)
-
-
-class LocalUtilityDirective(ContentDirective):
- r"""localUtility directive handler.
-
- Examples:
-
- >>> from zope.interface import implements
- >>> class LU1(object):
- ... pass
-
- >>> class LU2(LU1):
- ... implements(ILocation)
-
- >>> class LU3(LU1):
- ... __parent__ = None
-
- >>> class LU4(LU2):
- ... implements(IPersistent)
-
- >>> dir = LocalUtilityDirective(None, LU4)
- >>> IAttributeAnnotatable.implementedBy(LU4)
- True
- >>> ILocalUtility.implementedBy(LU4)
- True
-
- >>> LocalUtilityDirective(None, LU3)
- Traceback (most recent call last):
- ...
- ConfigurationError: Class `LU3` does not implement `IPersistent`.
-
- >>> LocalUtilityDirective(None, LU2)
- Traceback (most recent call last):
- ...
- ConfigurationError: Class `LU2` does not implement `IPersistent`.
-
- >>> LocalUtilityDirective(None, LU1)
- Traceback (most recent call last):
- ...
- ConfigurationError: Class `LU1` does not implement `ILocation`.
- """
-
- def __init__(self, _context, class_):
- if not ILocation.implementedBy(class_) and \
- not hasattr(class_, '__parent__'):
- raise ConfigurationError, \
- 'Class `%s` does not implement `ILocation`.' %class_.__name__
-
- if not IPersistent.implementedBy(class_):
- raise ConfigurationError, \
- 'Class `%s` does not implement `IPersistent`.' %class_.__name__
-
- classImplements(class_, IAttributeAnnotatable)
- classImplements(class_, ILocalUtility)
-
- super(LocalUtilityDirective, self).__init__(_context, class_)
Copied: Zope3/branches/srichter-blow-services/src/zope/app/component/registration.py (from rev 28687, Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/registration.py)
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/bbb/registration/registration.py 2004-12-22 17:17:53 UTC (rev 28687)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/registration.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -0,0 +1,227 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Component registration support
+
+$Id$
+"""
+from persistent import Persistent
+
+import zope.event
+from zope.interface import implements
+from zope.security.checker import CheckerPublic
+from zope.security.proxy import removeSecurityProxy
+
+from zope.app import zapi
+from zope.app.container.btree import BTreeContainer
+from zope.app.container.contained import Contained
+from zope.app.dependable.interfaces import IDependable, DependencyError
+from zope.app.event import objectevent
+from zope.app.location import inside
+from zope.app.component.interfaces import registration as interfaces
+
+
+class RegistrationEvent(objectevent.ObjectEvent):
+ """An event that is created when a registration-related activity occured."""
+ implements(interfaces.IRegistrationEvent)
+
+class RegistrationActivatedEvent(RegistrationEvent):
+ """An event that is created when a registration is activated."""
+ implements(interfaces.IRegistrationActivatedEvent)
+
+class RegistrationDeactivatedEvent(RegistrationEvent):
+ """An event that is created when a registration is deactivated."""
+ implements(interfaces.IRegistrationDeactivatedEvent)
+
+
+class RegistrationStatusProperty(object):
+ """A descriptor used to implement `IRegistration`'s `status` property."""
+ def __get__(self, inst, klass):
+ registration = inst
+ if registration is None:
+ return self
+
+ registry = registration.getRegistry()
+ if registry and registry.registered(registration):
+ return interfaces.ActiveStatus
+
+ return interfaces.InactiveStatus
+
+ def __set__(self, inst, value):
+ registration = inst
+ registry = registration.getRegistry()
+ if registry is None:
+ raise ValueError, 'No registry found.'
+
+ if value == interfaces.ActiveStatus:
+ if not registry.registered(registration):
+ registry.register(registration)
+ elif value == interfaces.InactiveStatus:
+ if registry.registered(registration):
+ registry.unregister(registration)
+ else:
+ raise ValueError, value
+
+
+class SimpleRegistration(Persistent, Contained):
+ """Registration objects that just contain registration data"""
+ implements(interfaces.IRegistration)
+
+ # See interfaces.IRegistration
+ status = RegistrationStatusProperty()
+
+ def getRegistry(self):
+ """See interfaces.IRegistration"""
+ raise NotImplementedError, \
+ 'This method must be implemented by each specific regstration.'
+
+
+class ComponentRegistration(SimpleRegistration):
+ """Component registration.
+
+ Subclasses should define a getInterface() method returning the interface
+ of the component.
+ """
+ implements(interfaces.IComponentRegistration)
+
+ def __init__(self, component, permission=None):
+ self.component = component
+ if permission == 'zope.Public':
+ permission = CheckerPublic
+ self.permission = permission
+
+ def _getComponent(self):
+ if self.permission and self.getInterface():
+ checker = InterfaceChecker(self.getInterface(), self.permission)
+ return Proxy(self._component, checker)
+ return self._component
+
+ def _setComponent(self, component):
+ # We always want to set the plain component. Untrusted code will
+ # get back a proxied component anyways.
+ self._component = removeSecurityProxy(component)
+
+ component = property(_getComponent, _setComponent)
+
+ def getInterface(self):
+ return None
+
+
+def SimpleRegistrationRemoveSubscriber(registration, event):
+ """Receive notification of remove event."""
+ sm = zapi.getSiteManager(registration)
+ removed = event.object
+ if (sm == removed) or inside(sm, removed):
+ # we don't really care if the registration is active, since the site
+ # is going away.
+ return
+
+ objectstatus = registration.status
+
+ if objectstatus == interfaces.ActiveStatus:
+ try:
+ objectpath = zapi.getPath(registration)
+ except: # XXX
+ objectpath = str(registration)
+ raise DependencyError("Can't delete active registration (%s)"
+ % objectpath)
+
+
+def ComponentRegistrationRemoveSubscriber(component_registration, event):
+ """Receive notification of remove event."""
+ component = component_registration.component
+ dependents = IDependable(component)
+ objectpath = zapi.getPath(component_registration)
+ dependents.removeDependent(objectpath)
+
+
+def ComponentRegistrationAddSubscriber(component_registration, event):
+ """Receive notification of add event."""
+ component = component_registration.component
+ dependents = IDependable(component)
+ objectpath = zapi.getPath(component_registration)
+ dependents.addDependent(objectpath)
+
+
+def RegisterableMoveSubscriber(registerable, event):
+ """A registerable cannot be moved as long as it has registrations in the
+ registration manager."""
+ if event.oldParent is not None and event.newParent is not None:
+ if event.oldParent is not event.newParent:
+ raise DependencyError(
+ "Can't move a registered component from its container.")
+
+
+class Registered(object):
+ """An adapter from IRegisterable to IRegistered.
+
+ This class is the only place that knows how 'Registered'
+ data is represented.
+ """
+ implements(interfaces.IRegistered)
+ __used_for__ = interfaces.IRegisterable
+
+ def __init__(self, registerable):
+ self.registerable = registerable
+
+ def registrations(self):
+ rm = zapi.getParent(self.registerable).registrationManager
+ return [reg for reg in rm
+ if (IComponentRegistration.providedBy(reg) and
+ reg.component is self.registerable)]
+
+
+class RegistrationManager(BTreeContainer):
+ """Registration manager
+
+ Manages registrations within a package.
+ """
+ implements(interfaces.IRegistrationManager)
+
+ def addRegistration(self, reg):
+ "See IWriteContainer"
+ key = self._chooseName('', reg)
+ self[key] = reg
+ return key
+
+ def _chooseName(self, name, reg):
+ """Choose a name for the registration."""
+ if not name:
+ name = reg.__class__.__name__
+
+ i = 1
+ chosenName = name
+ while chosenName in self:
+ i += 1
+ chosenName = name + str(i)
+
+ return chosenName
+
+
+class RegisterableContainer(object):
+ """Mix-in to implement `IRegisterableContainer`"""
+ implements(interfaces.IRegisterableContainer,
+ interfaces.IRegisterableContainerContaining)
+
+ def __init__(self):
+ super(RegisterableContainer, self).__init__()
+ self.__createRegistrationManager()
+
+ def __createRegistrationManager(self):
+ "Create a registration manager and store it as `registrationManager`"
+ # See interfaces.IRegisterableContainer
+ self.registrationManager = RegistrationManager()
+ self.registrationManager.__parent__ = self
+ self.registrationManager.__name__ = 'RegistrationManager'
+ zope.event.notify(
+ objectevent.ObjectCreatedEvent(self.registrationManager))
Added: Zope3/branches/srichter-blow-services/src/zope/app/component/registration.txt
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/registration.txt 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/registration.txt 2004-12-23 18:26:32 UTC (rev 28692)
@@ -0,0 +1,268 @@
+==========================
+The Registration Framework
+==========================
+
+The registration framework's task is to manage registrations and ensure that
+the correct registrations are inserted into the correct registries. Each
+registration knows to which registry it belongs. If a registration is set
+active, then the registration is added to the regstry; when inactive, it is
+removed from the registry. Please see `statusproperty.txt` for a demonstration
+on how the setting of the registration's status affects the registry.
+
+The true power of the registration framework, however, comes from the ability
+to provide registrations for registerable components. In the context of Zope
+3's component architecture, registerable components are adapters and
+utilities. Since the registration framework can be used for any kind of
+component registration, I am going to refer to registerable components
+(including adapters and interface) as components.
+
+The first task is to create a simple component registry. It will implement all
+required `IRegistry` methods and a `getComponents()` method, which will return
+a list of all registered (active) components.
+
+ >>> import zope.interface
+ >>> from zope.app.component import interfaces
+ >>> class ComponentRegistry(object):
+ ... zope.interface.implements(interfaces.registration.IRegistry)
+ ...
+ ... def __init__(self):
+ ... self._registrations = []
+ ...
+ ... def registrations(self):
+ ... """See zope.component.interfaces.IRegistry"""
+ ... return self._registrations
+ ...
+ ... def register(self, registration):
+ ... """See interfaces.registration.IRegistry"""
+ ... self._registrations.append(registration)
+ ...
+ ... def unregister(self, registration):
+ ... """See interfaces.registration.IRegistry"""
+ ... del self._registrations[self._registrations.index(registration)]
+ ...
+ ... def registered(self, registration):
+ ... """See interfaces.registration.IRegistry"""
+ ... return registration in self._registrations
+ ...
+ ... def getComponents(self):
+ ... return [reg.component for reg in self.registrations()]
+
+ >>> registry = ComponentRegistry()
+
+Effectively, a registry manages a set of active registrations. A simple
+UML diagram would be:
+
+ ---------------------------
+ --------------- * 1 | IRegistration |
+ | IRegistry |-------| - - - - - - - - - - - - |
+ --------------- | status = ActiveStatus |
+ ---------------------------
+
+Next we need to create a registration object that can register components with
+our new registry. The framework already provides a base-class for
+component-based registrations, so that we only need to implement the
+`getRegistry()` method:
+
+ >>> from zope.app.component.registration import ComponentRegistration
+ >>> class Registration(ComponentRegistration):
+ ...
+ ... def getRegistry(self):
+ ... global registry
+ ... return registry
+ ...
+ ... def __repr__(self):
+ ... return "<Registration for '%s'>" %self.component
+
+In the implementation above, all `Registration` instances are simply going to
+use the global `registry` object. Now that we have a registry and a suitable
+registration class, let's test what we have so far. To do that we have to
+create a component that we would like to register:
+
+ >>> from zope.app.container.contained import Contained
+ >>> class Component(Contained):
+ ... zope.interface.implements(interfaces.registration.IRegisterable)
+ ... def __init__(self, title=u''):
+ ... self.title = title
+ ... def __repr__(self):
+ ... return "<Component: '%s'>" %self.title
+
+Note that `Contained` is used as a base class, since `IRegisterable` requires
+it to be. We will later see why this is the case.
+
+Before we are registering any component, the registry is empty:
+
+ >>> registry.getComponents()
+ []
+
+Now we create a component and a registration:
+
+ >>> foo = Component('Foo')
+ >>> regFoo = Registration(foo)
+ >>> regFoo.component
+ <Component: 'Foo'>
+ >>> regFoo.status
+ u'Inactive'
+
+Finally, we activate the registration:
+
+
+ >>> regFoo.status = interfaces.registration.ActiveStatus
+ >>> regFoo.status
+ u'Active'
+ >>> registry.getComponents()
+ [<Component: 'Foo'>]
+
+Of course, we can add a second registered component:
+
+ >>> bar = Component('Bar')
+ >>> regBar = Registration(bar)
+ >>> regBar.component
+ <Component: 'Bar'>
+ >>> regBar.status
+ u'Inactive'
+ >>> regBar.status = interfaces.registration.ActiveStatus
+ >>> regBar.status
+ u'Active'
+ >>> registry.getComponents()
+ [<Component: 'Foo'>, <Component: 'Bar'>]
+
+Of course, when deactivating a registration, it will be gone from the registry
+as well:
+
+ >>> regFoo.status = interfaces.registration.InactiveStatus
+ >>> regFoo.status
+ u'Inactive'
+ >>> registry.getComponents()
+ [<Component: 'Bar'>]
+
+This is everything that there is about registrations and their interaction
+with a registry. However, the point of registrations and registerable
+components is that they should be persistent (otherwise we could use
+ZCML). Thus we need a way of managing local components and their
+registrations.
+
+
+Management of Local Components and Registrations
+------------------------------------------------
+
+The starting point here is the `IRegisterableContainer`, which can contain
+`IRegiserable` and other `IRegisterableContainer` components.
+
+ >>> from zope.app.container.btree import BTreeContainer
+ >>> from zope.app.component.registration import RegisterableContainer
+
+ >>> class RegisterableManager(RegisterableContainer, BTreeContainer):
+ ... pass
+ >>> registerables = RegisterableManager()
+
+The `RegisterableContainer` class is merely a mixin and leaves it up to the
+developer to implement the `IContainer` interface. In our case, we simply used
+the default btree container implementation to provide the container
+interface. However, the `RegisterableContainer` class does implement the
+`IRegisterableContainer` interface, which means it ensures the existance of
+the `registrationManager` attribute, which always contains an
+`IRegistrationManager` instance:
+
+ >>> registerables.registrationManager is not None
+ True
+ >>> interfaces.registration.IRegistrationManager.providedBy(
+ ... registerables.registrationManager)
+ True
+
+The registration manager is a simple container that can only contain
+components providing `IRegistration` and implements a method called
+`addRegistration(registration)` that lets you add a registration to the
+manager without specifying a name. The name will be automatically chosen for
+you and is returned. So let's add our two existing components and their
+registrations:
+
+ >>> regManager = registerables.registrationManager
+
+ >>> registerables['foo'] = foo
+ >>> regManager.addRegistration(regFoo)
+ 'Registration'
+
+ >>> registerables['bar'] = bar
+ >>> regManager.addRegistration(regBar)
+ 'Registration2'
+
+ >>> items = list(registerables.items())
+ >>> items.sort()
+ >>> items
+ [(u'bar', <Component: 'Bar'>), (u'foo', <Component: 'Foo'>)]
+ >>> regs = list(regManager.items())
+ >>> regs.sort()
+ >>> regs #doctest: +NORMALIZE_WHITESPACE
+ [(u'Registration', <Registration for '<Component: 'Foo'>'>),
+ (u'Registration2', <Registration for '<Component: 'Bar'>'>)]
+
+Of course, adding a registration to the registration manager does not mean the
+registration is added to the registry, since it still may not be active:
+
+ >>> registry.getComponents()
+ [<Component: 'Bar'>]
+
+Also, there are no restrictions on how many registrations you can create for a
+single component. For example, we can register the `foo` one more time:
+
+ >>> regFoo2 = Registration(foo)
+ >>> regManager.addRegistration(regFoo2)
+ 'Registration3'
+ >>> regs = list(regManager.items())
+ >>> regs.sort()
+ >>> regs #doctest: +NORMALIZE_WHITESPACE
+ [(u'Registration', <Registration for '<Component: 'Foo'>'>),
+ (u'Registration2', <Registration for '<Component: 'Bar'>'>),
+ (u'Registration3', <Registration for '<Component: 'Foo'>'>)]
+
+This also means that our registry can provide a component multiple times:
+
+ >>> regFoo.status = interfaces.registration.ActiveStatus
+ >>> regFoo2.status = interfaces.registration.ActiveStatus
+ >>> registry.getComponents()
+ [<Component: 'Bar'>, <Component: 'Foo'>, <Component: 'Foo'>]
+
+Here is a UML diagram of the registerable container and registration manager
+and their relationships to the other registration-related components we
+discussed.
+
+ ----------------------------
+ | IRegisterableContainer |
+ | - - - - - - - - - - - - -|
+ | 1 | 1 --------------------------
+ | registrationManager ----+------| IRegistrationManager |
+ | | --------------------------
+ ---------------------------+ | *
+ | * | * | 1 |
+ | | | | 1
+ | 1 +----+ -------------------
+ ------------------- | IRegistration |
+ | IRegisterable | -------------------
+ ------------------- | *
+ |
+ --------------- 1 |
+ | IRegistry |------+ if status == Active
+ ---------------
+
+
+The Component Registration
+--------------------------
+
+provided interface
+permission
+Registered
+
+
+Registration Events
+-------------------
+
+RegistrationActivatedEvent
+RegistrationDeactivatedEvent
+
+
+Registrations and Dependencies
+------------------------------
+
+ComponentRegistrationRemoveSubscriber
+ComponentRegistrationAddSubscriber
+RegisterableMoveSubscriber
\ No newline at end of file
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/site.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/site.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/site.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -26,39 +26,45 @@
$Id$
"""
import sys
-from transaction import get_transaction
from zodbcode.module import PersistentModuleRegistry
import zope.event
import zope.interface
from zope.component.exceptions import ComponentLookupError
-import zope.app.registration.interfaces
from zope.app import zapi
from zope.app.component.hooks import setSite
+from zope.app.component.interfaces.registration import IRegistry
+from zope.app.component.interfaces.registration import IRegisterableContainer
+from zope.app.component.registration import ComponentRegistration
+from zope.app.component.registration import RegistrationStack
from zope.app.container.btree import BTreeContainer
from zope.app.container.constraints import ItemTypePrecondition
from zope.app.container.contained import Contained
from zope.app.container.interfaces import IContainer
from zope.app.event import objectevent
from zope.app.location import inside
-from zope.app.registration.interfaces import IRegistry
-from zope.app.registration.registration import ComponentRegistration
-from zope.app.registration.registration import RegistrationStack
-from zope.app.site.folder import SiteManagementFolder
from zope.app.traversing.interfaces import IContainmentRoot
from zope.app.site.interfaces import IPossibleSite, ISite, ISiteManager
-class IRegisterableContainerContainer(zope.interface.Interface):
- def __setitem__(name, folder):
- """Add a site-management folder
- """
- __setitem__.precondition = ItemTypePrecondition(
- zope.app.registration.interfaces.IRegisterableContainer)
+class SiteManagementFolder(RegisterableContainer, BTreeContainer):
+ implements(ISiteManagementFolder)
+class SMFolderFactory(object):
+ implements(IDirectoryFactory)
+ def __init__(self, context):
+ self.context = context
+
+ def __call__(self, name):
+ return SiteManagementFolder()
+
+class SiteManagementFolders(BTreeContainer):
+ pass
+
+
class LocalSiteManager(BTreeContainer, PersistentModuleRegistry):
zope.interface.implements(ILocalSiteManager,
@@ -184,6 +190,7 @@
return None
return findModule(name)
+
def __import(self, module_name):
mod = self.findModule(module_name)
if mod is None:
@@ -194,13 +201,46 @@
return mod
+ def findModule(self, name):
+ # Used by the persistent modules import hook
+
+ # Look for a .py file first:
+ manager = self.get(name+'.py')
+ if manager is not None:
+ # found an item with that name, make sure it's a module(manager):
+ if IModuleManager.providedBy(manager):
+ return manager.getModule()
+
+ # Look for the module in this folder:
+ manager = self.get(name)
+ if manager is not None:
+ # found an item with that name, make sure it's a module(manager):
+ if IModuleManager.providedBy(manager):
+ return manager.getModule()
+
+
+ # See if out container is a RegisterableContainer:
+ c = self.__parent__
+ if interfaces.IRegisterableContainer.providedBy(c):
+ return c.findModule(name)
+
+ # Use sys.modules in lieu of module service:
+ module = sys.modules.get(name)
+ if module is not None:
+ return module
+
+ raise ImportError(name)
+
+
+ def resolve(self, name):
+ l = name.rfind('.')
+ mod = self.findModule(name[:l])
+ return getattr(mod, name[l+1:])
+
+
class AdapterRegistration(
zope.app.registration.registration.SimpleRegistration):
- zope.interface.implements(IAdapterRegistration)
-
- serviceType = zapi.servicenames.Adapters
-
with = () # Don't support multi-adapters yet
# TODO: These should be positional arguments, except that required
@@ -221,6 +261,9 @@
return factory
factory = property(factory)
+ def getRegistry(self):
+ sm = self.getSiteManager()
+ return sm.adapters
class UtilityRegistration(ComponentRegistration):
@@ -231,8 +274,6 @@
"""
zope.interface.implements(IUtilityRegistration)
- serviceType = zapi.servicenames.Utilities
-
############################################################
# To make adapter code happy. Are we going too far?
#
@@ -248,22 +289,11 @@
self.name = name
self.interface = interface
- def usageSummary(self):
- # Override IRegistration.usageSummary()
- s = self.getInterface().getName()
- if self.name:
- s += " registered as '%s'" % self.name
- s += ", implemented by %s" %self.component.__class__.__name__
- s += " '%s'"%zapi.name(self.component)
- return s
+ def getRegistry(self):
+ sm = self.getSiteManager()
+ return sm.utilities
- def getInterface(self):
- # ComponentRegistration calls this when you specify a
- # permission; it needs the interface to create a security
- # proxy for the interface with the given permission.
- return self.interface
-
def threadSiteSubscriber(event):
"""A subscriber to BeforeTraverseEvent
Added: Zope3/branches/srichter-blow-services/src/zope/app/component/statusproperty.txt
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/statusproperty.txt 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/statusproperty.txt 2004-12-23 18:26:32 UTC (rev 28692)
@@ -0,0 +1,83 @@
+============================
+Registration Status Property
+============================
+
+The registratio status property is a descriptor used to implement the
+`IRegistration`' interface's `status` property.
+
+The property accepts two possible values: `ActiveStatus` and
+`InactiveStatus`. When the registration is active, then the registration is
+also activated in the registry.
+
+ >>> from zope.app.component.interfaces.registration import ActiveStatus
+ >>> from zope.app.component.interfaces.registration import InactiveStatus
+
+When setting the `status` property to `ActiveStatus`, then the registration
+should be added to the nearest matching registry. Here, the registration's
+`getRegistry()` method is used to determine the registry. On the same token,
+if the value is set to `InactiveStatus` the registration should be removed
+from the registry.
+
+To demonstrate this functionality, we first have to create a stub registry
+
+ >>> class Registry(object):
+ ... registrations = []
+ ... def register(self, registration):
+ ... self.registrations.append(registration)
+ ...
+ ... def unregister(self, registration):
+ ... del self.registrations[self.registrations.index(registration)]
+ ...
+ ... def registered(self, registration):
+ ... return registration in self.registrations
+
+ >>> registry = Registry()
+
+and a simple registration object
+
+ >>> from zope.app.component.registration import RegistrationStatusProperty
+ >>> class Registration(object):
+ ... status = RegistrationStatusProperty()
+ ...
+ ... def __init__(self, registry):
+ ... self.registry = registry
+ ...
+ ... def getRegistry(self):
+ ... return self.registry
+
+Note that here only the `getRegistry()` is part of the registration API.
+
+Now that we have a registry and a registration class, let's create a
+registration:
+
+ >>> reg = Registration(registry)
+
+At the beginning the registration is inactive:
+
+ >>> reg.status
+ u'Inactive'
+ >>> reg.status is InactiveStatus
+ True
+ >>> reg in registry.registrations
+ False
+
+Once we activate the registration, it appears in the registry:
+
+ >>> reg.status = ActiveStatus
+ >>> reg.status
+ u'Active'
+ >>> reg.status is ActiveStatus
+ True
+ >>> reg in registry.registrations
+ True
+
+Now, once we deactivate the registration, it is not available in the registry
+anymore:
+
+ >>> reg.status = InactiveStatus
+ >>> reg.status
+ u'Inactive'
+ >>> reg.status is InactiveStatus
+ True
+ >>> reg in registry.registrations
+ False
Deleted: Zope3/branches/srichter-blow-services/src/zope/app/component/tests/service.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/tests/service.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/tests/service.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -1,38 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Service stub for testing
-
-$Id$
-"""
-from zope.interface import Interface, implements
-
-class IFooService(Interface):
-
- def foo(): pass
- def foobar(): pass
-
-class FooService(object):
-
- implements(IFooService)
-
- def foo(self): return "foo here"
- def foobar(self): return "foobarred"
-
- def bar(self): return "you shouldn't get this"
-
-fooService = FooService()
-
-class Foo2(FooService): pass
-
-foo2 = Foo2()
Added: Zope3/branches/srichter-blow-services/src/zope/app/component/tests/test_registration.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/tests/test_registration.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/tests/test_registration.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Registration Tests
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import unittest
+
+from zope.testing import doctest
+
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('../statusproperty.txt'),
+ doctest.DocFileSuite('../registration.txt'),
+ ))
+
+if __name__ == "__main__":
+ unittest.main(defaultTest='test_suite')
Modified: Zope3/branches/srichter-blow-services/src/zope/app/publication/zopepublication.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/publication/zopepublication.py 2004-12-22 23:26:23 UTC (rev 28691)
+++ Zope3/branches/srichter-blow-services/src/zope/app/publication/zopepublication.py 2004-12-23 18:26:32 UTC (rev 28692)
@@ -49,7 +49,7 @@
from zope.app.security.principalregistry import principalRegistry as prin_reg
from zope.app.security.interfaces import IUnauthenticatedPrincipal
from zope.app.security.interfaces import IAuthenticationUtility
-from zope.app.site.interfaces import ISite
+from zope.app.component.interfaces import ISite
from zope.app.traversing.interfaces import IPhysicallyLocatable
class Cleanup(object):
More information about the Zope3-Checkins
mailing list