[Zope3-checkins] CVS: Zope3/src/zope/app/services - error.txt:1.1.2.1 factories.py:1.3.2.1 registration.py:1.1.2.1 utility.txt:1.1.2.1 README.txt:1.4.10.1 adapter.py:1.14.2.1 auth.py:1.15.10.1 cache.py:1.9.10.1 configure.zcml:1.29.2.1 connection.py:1.11.10.1 errorr.py:1.8.18.1 event.py:1.24.4.1 field.py:1.7.18.1 folder.py:1.6.10.1 hub.py:1.10.10.1 module.py:1.2.26.1 pagefolder.py:1.5.10.1 principalannotation.py:1.5.14.1 queryfield.py:1.2.22.1 role.py:1.4.18.1 service.py:1.18.10.1 servicecontainer.py:1.2.24.1 session.py:1.9.18.1 utility.py:1.6.10.1 utility.zcml:1.3.14.1 view.py:1.18.4.1 zpt.py:1.10.10.1 configuration.py:NONE
Grégoire Weber
zope@i-con.ch
Sun, 22 Jun 2003 10:23:59 -0400
Update of /cvs-repository/Zope3/src/zope/app/services
In directory cvs.zope.org:/tmp/cvs-serv24874/src/zope/app/services
Modified Files:
Tag: cw-mail-branch
README.txt adapter.py auth.py cache.py configure.zcml
connection.py errorr.py event.py field.py folder.py hub.py
module.py pagefolder.py principalannotation.py queryfield.py
role.py service.py servicecontainer.py session.py utility.py
utility.zcml view.py zpt.py
Added Files:
Tag: cw-mail-branch
error.txt factories.py registration.py utility.txt
Removed Files:
Tag: cw-mail-branch
configuration.py
Log Message:
Synced up with HEAD
=== Added File Zope3/src/zope/app/services/error.txt ===
Under construction.
=== Added File Zope3/src/zope/app/services/factories.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""A collection of factory functions for various registration classes.
See method factory() in class ComponentRegistrationAdapter in file
registration.py.
The functions here may create invalid objects; a subsequent setBody()
call to the adapter's setBody() method will make the object valid.
$Id: factories.py,v 1.3.2.1 2003/06/22 14:23:27 gregweb Exp $
"""
def CacheRegistration():
from zope.app.services.cache import CacheRegistration
return CacheRegistration("", "") # name, componentPath
def ConnectionRegistration():
from zope.app.services.connection import ConnectionRegistration
return ConnectionRegistration("", "") # name, componentPath
def ServiceRegistration():
from zope.app.services.service import ServiceRegistration
return ServiceRegistration("", "") # name, componentPath
def UtilityRegistration():
from zope.app.services.utility import UtilityRegistration
return UtilityRegistration("", None, "") # name, interface, componentPath
=== Added File Zope3/src/zope/app/services/registration.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""Component registration support for services
$Id: registration.py,v 1.1.2.1 2003/06/22 14:23:27 gregweb Exp $
"""
__metaclass__ = type
from persistence import Persistent
from zope.interface import implements
from zope.app.interfaces.annotation import IAnnotations
from zope.app.interfaces.annotation import IAttributeAnnotatable
from zope.app.interfaces.container import IAddNotifiable, IDeleteNotifiable
from zope.app.interfaces.container import IZopeWriteContainer
from zope.app.interfaces.dependable import IDependable, DependencyError
from zope.app.interfaces.services.registration import IRegistrationManager
from zope.app.interfaces.services.registration import IRegistrationStack
from zope.app.interfaces.services.registration \
import INameComponentRegistry
from zope.app.interfaces.services.registration import INamedRegistration
from zope.app.interfaces.services.registration import IRegistration
from zope.app.interfaces.services.registration \
import INamedComponentRegistration
from zope.app.interfaces.services.registration import INameRegistry
from zope.app.interfaces.services.registration \
import INamedComponentRegistration, IComponentRegistration
from zope.app.interfaces.services.registration import IRegistered
from zope.app.interfaces.services.registration \
import NoRegistrationManagerError
from zope.app.interfaces.services.registration import NoLocalServiceError
from zope.app.interfaces.services.registration import UnregisteredStatus
from zope.app.interfaces.services.registration import ActiveStatus
from zope.app.interfaces.services.registration import RegisteredStatus
from zope.app.traversing import getRoot, getPath, traverse
from zope.component import getAdapter, queryAdapter
from zope.component import getServiceManager
from zope.app.context import ContextWrapper
from zope.context import ContextMethod, ContextDescriptor, getWrapperContainer
from zope.proxy import removeAllProxies
from zope.security.checker import InterfaceChecker
from zope.security.proxy import Proxy, trustedRemoveSecurityProxy
from zope.proxy import getProxiedObject
class RegistrationStatusProperty(ContextDescriptor):
def __get__(self, inst, klass):
if inst is None:
return self
registration = inst
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:
if registry.active() == registration:
return ActiveStatus
if registry.registered(registration):
return RegisteredStatus
return UnregisteredStatus
def __set__(self, inst, value):
registration = inst
sm = getServiceManager(registration)
service = sm.queryLocalService(registration.serviceType)
registry = service and service.queryRegistrationsFor(registration)
if value == UnregisteredStatus:
if registry:
registry.unregister(registration)
else:
if not service:
raise NoLocalServiceError(
"This registration change cannot be performed because "
"there isn't a corresponding %s service defined in this "
"site. To proceed, first add a local %s service."
% (registration.serviceType, registration.serviceType))
if registry is None:
registry = service.createRegistrationsFor(registration)
if value == RegisteredStatus:
if registry.active() == registration:
registry.deactivate(registration)
else:
registry.register(registration)
elif value == ActiveStatus:
if not registry.registered(registration):
registry.register(registration)
registry.activate(registration)
class RegistrationStack(Persistent):
"""Registration registry implementation.
The invariants for _data are as follows:
(1) The last element (if any) is not None
(2) No value occurs more than once
(3) Each value except None is a relative path from the nearest
service manager to an object implementing IRegistration
"""
implements(IRegistrationStack)
_data = ()
def _id(self, ob):
# Get and check relative path
path = getPath(ob)
prefix = "/++etc++site/"
lpackages = path.rfind(prefix)
if lpackages < 0:
# XXX Backward compatability
prefix = "/++etc++Services/"
lpackages = path.rfind(prefix)
if lpackages < 0:
raise ValueError("Registration object is in an invalid location",
path)
rpath = path[lpackages+len(prefix):]
if not rpath or (".." in rpath.split("/")):
raise ValueError("Registration object is in an invalid location",
path)
return rpath
def register(wrapped_self, registration):
cid = wrapped_self._id(registration)
if wrapped_self._data:
if cid in wrapped_self._data:
return # already registered
else:
# Nothing registered. Need to stick None in front so that nothing
# is active.
wrapped_self._data = (None, )
wrapped_self._data += (cid, )
register = ContextMethod(register)
def unregister(wrapped_self, registration):
cid = wrapped_self._id(registration)
data = wrapped_self._data
if data:
if data[0] == cid:
# Tell it that it is no longer active
registration.deactivated()
# Remove it from our data
data = tuple([item for item in data if item != cid])
# Check for trailing None
if data and data[-1] is None:
data = data[:-1]
if data and data[0] is not None:
# Activate the newly active component
sm = getServiceManager(wrapped_self)
new = traverse(sm, data[0])
new.activated()
# Write data back
wrapped_self._data = data
unregister = ContextMethod(unregister)
def registered(wrapped_self, registration):
cid = wrapped_self._id(registration)
return cid in wrapped_self._data
registered = ContextMethod(registered)
def activate(wrapped_self, registration):
if registration is None:
cid = None
else:
cid = wrapped_self._id(registration)
data = wrapped_self._data
if cid is None and not data:
return # already in the state we want
if cid is None or cid in data:
if data[0] == cid:
return # already active
if data[0] is not None:
# Deactivate the currently active component
sm = getServiceManager(wrapped_self)
old = traverse(sm, data[0])
old.deactivated()
# Insert it in front, removing it from back
data = (cid, ) + tuple([item for item in data if item != cid])
# Check for trailing None
if data[-1] == None:
data = data[:-1]
# Write data back
wrapped_self._data = data
if registration is not None:
# Tell it that it is now active
registration.activated()
else:
raise ValueError(
"Registration to be activated is not registered",
registration)
activate = ContextMethod(activate)
def deactivate(wrapped_self, registration):
cid = wrapped_self._id(registration)
data = wrapped_self._data
if cid not in data:
raise ValueError(
"Registration to be deactivated is not registered",
registration)
if data[0] != cid:
return # already inactive
# Tell it that it is no longer active
registration.deactivated()
if None not in data:
# Append None
data += (None,)
# Move it to the end
data = data[1:] + data[:1]
if data[0] is not None:
# Activate the newly active component
sm = getServiceManager(wrapped_self)
new = traverse(sm, data[0])
new.activated()
# Write data back
wrapped_self._data = data
deactivate = ContextMethod(deactivate)
def active(wrapped_self):
if wrapped_self._data:
path = wrapped_self._data[0]
if path is not None:
# Make sure we can traverse to it.
sm = getServiceManager(wrapped_self)
registration = traverse(sm, path)
return registration
return None
active = ContextMethod(active)
def __nonzero__(self):
return bool(self._data)
def info(wrapped_self, keep_dummy=False):
sm = getServiceManager(wrapped_self)
data = wrapped_self._data
if not data and keep_dummy:
data += (None,)
result = [{'id': path or "",
'active': False,
'registration': (path and traverse(sm, path))
}
for path in data if path or keep_dummy
]
if keep_dummy or (result and result[0]['registration'] is not None):
result[0]['active'] = True
return result
info = ContextMethod(info)
class SimpleRegistration(Persistent):
"""Registration objects that just contain registration data
Classes that derive from this must make sure they implement
IDeleteNotifiable either by implementing
implementedBy(SimpleRegistration) or explicitly implementing
IDeleteNotifiable.
"""
implements(IRegistration, IDeleteNotifiable,
# We are including this here because we want all of the
# subclasses to get it and we don't really need to be
# flexible about the policy here. At least we don't
# *think* we do. :)
IAttributeAnnotatable,
)
# Methods from IRegistration
def activated(self):
pass
def deactivated(self):
pass
def usageSummary(self):
return self.__class__.__name__
def implementationSummary(self):
return ""
# Methods from IDeleteNotifiable
def beforeDeleteHook(self, registration, container):
"See IDeleteNotifiable"
objectstatus = registration.status
if objectstatus == ActiveStatus:
try:
objectpath = getPath(registration)
except: # XXX
objectpath = str(registration)
raise DependencyError("Can't delete active registration (%s)"
% objectpath)
elif objectstatus == RegisteredStatus:
registration.status = UnregisteredStatus
class NamedRegistration(SimpleRegistration):
"""Named registration
"""
implements(INamedRegistration)
def __init__(self, name):
self.name = name
def usageSummary(self):
return "%s %s" % (self.name, self.__class__.__name__)
class ComponentRegistration(SimpleRegistration):
"""Component registration.
Subclasses should define a getInterface() method returning the interface
of the component.
"""
# SimpleRegistration implements IDeleteNotifiable, so we don't need
# it below.
implements(IComponentRegistration, IAddNotifiable)
def __init__(self, component_path, permission=None):
self.componentPath = component_path
if permission == 'zope.Public':
permission = CheckerPublic
self.permission = permission
def implementationSummary(self):
return self.componentPath
def getComponent(wrapped_self):
service_manager = getServiceManager(wrapped_self)
# The user of the registration object may not have permission
# to traverse to the component. Yet they should be able to
# get it by calling getComponent() on a registration object
# for which they do have permission. What they get will be
# wrapped in a security proxy of course. Hence:
# We have to be clever here. We need to do an honest to
# god unrestricted traveral, which means we have to
# traverse from an unproxied object. But, it's not enough
# for the service manager to be unproxied, because the
# path is an absolute path. When absolute paths are
# traversed, the traverser finds the physical root and
# traverses from there, so we need to make sure the
# physical root isn't proxied.
path = wrapped_self.componentPath
# Get the root and unproxy it
root = removeAllProxies(getRoot(service_manager))
if path.startswith("/"):
# Absolute path
component = traverse(root, path)
else:
# Relative path.
# XXX We do a strange little dance because we want the
# context to inherit the unproxied root, and this is
# the only way to keep it.
ancestor = getWrapperContainer(getWrapperContainer(wrapped_self))
ancestor = traverse(root, getPath(ancestor))
component = traverse(ancestor, path)
if wrapped_self.permission:
if type(component) is Proxy:
# There should be at most one security Proxy around an object.
# So, if we're going to add a new security proxy, we need to
# remove any existing one.
component = trustedRemoveSecurityProxy(component)
interface = wrapped_self.getInterface()
checker = InterfaceChecker(interface, wrapped_self.permission)
component = Proxy(component, checker)
return component
getComponent = ContextMethod(getComponent)
def afterAddHook(self, registration, container):
"See IAddNotifiable"
component = registration.getComponent()
dependents = getAdapter(component, IDependable)
objectpath = getPath(registration)
dependents.addDependent(objectpath)
# Also update usage, if supported
adapter = queryAdapter(component, IRegistered)
if adapter is not None:
adapter.addUsage(getPath(registration))
def beforeDeleteHook(self, registration, container):
"See IDeleteNotifiable"
super(ComponentRegistration, self).beforeDeleteHook(registration,
container)
component = registration.getComponent()
dependents = getAdapter(component, IDependable)
objectpath = getPath(registration)
dependents.removeDependent(objectpath)
# Also update usage, if supported
adapter = queryAdapter(component, IRegistered)
if adapter is not None:
adapter.removeUsage(getPath(registration))
class NamedComponentRegistration(NamedRegistration, ComponentRegistration):
"""Registrations for named components.
This configures components that live in folders, by name.
"""
implements(INamedComponentRegistration)
def __init__(self, name, component_path, permission=None):
NamedRegistration.__init__(self, name)
ComponentRegistration.__init__(self, component_path, permission)
class NameRegistry:
"""Mixin for implementing INameRegistry
"""
implements(INameRegistry)
def __init__(self, *args, **kw):
self._bindings = {}
super(NameRegistry, self).__init__(*args, **kw)
def queryRegistrationsFor(wrapped_self, cfg, default=None):
"""See IRegistry"""
return wrapped_self.queryRegistrations(cfg.name, default)
queryRegistrationsFor = ContextMethod(queryRegistrationsFor)
def queryRegistrations(wrapped_self, name, default=None):
"""See INameRegistry"""
registry = wrapped_self._bindings.get(name, default)
return ContextWrapper(registry, wrapped_self)
queryRegistrations = ContextMethod(queryRegistrations)
def createRegistrationsFor(wrapped_self, cfg):
"""See IRegistry"""
return wrapped_self.createRegistrations(cfg.name)
createRegistrationsFor = ContextMethod(createRegistrationsFor)
def createRegistrations(wrapped_self, name):
"""See INameRegistry"""
try:
registry = wrapped_self._bindings[name]
except KeyError:
wrapped_self._bindings[name] = registry = RegistrationStack()
wrapped_self._p_changed = 1
return ContextWrapper(registry, wrapped_self)
createRegistrations = ContextMethod(createRegistrations)
def listRegistrationNames(wrapped_self):
"""See INameRegistry"""
return filter(wrapped_self._bindings.get,
wrapped_self._bindings.keys())
class NameComponentRegistry(NameRegistry):
"""Mixin for implementing INameComponentRegistry
"""
implements(INameComponentRegistry)
def queryActiveComponent(wrapped_self, name, default=None):
"""See INameComponentRegistry"""
registry = wrapped_self.queryRegistrations(name)
if registry:
registration = registry.active()
if registration is not None:
return registration.getComponent()
return default
queryActiveComponent = ContextMethod(queryActiveComponent)
from zope.app.dependable import PathSetAnnotation
class Registered(PathSetAnnotation):
"""An adapter from IRegisterable to IRegistered.
This class is the only place that knows how 'Registered'
data is represented.
"""
implements(IRegistered)
# We want to use this key:
# key = "zope.app.services.registration.Registered"
# But we have existing annotations with the following key, so we'll keep
# it. :(
key = "zope.app.services.configuration.UseConfiguration"
addUsage = PathSetAnnotation.addPath
removeUsage = PathSetAnnotation.removePath
usages = PathSetAnnotation.getPaths
class RegistrationManager(Persistent):
"""Registration manager
Manages registrations within a package.
"""
implements(IRegistrationManager, IDeleteNotifiable)
def __init__(self):
self._data = ()
self._next = 0
def __getitem__(self, key):
"See IItemContainer"
v = self.get(key)
if v is None:
raise KeyError, key
return v
def get(self, key, default=None):
"See IReadMapping"
for k, v in self._data:
if k == key:
return v
return default
def __contains__(self, key):
"See IReadMapping"
return self.get(key) is not None
def keys(self):
"See IEnumerableMapping"
return [k for k, v in self._data]
def __iter__(self):
return iter(self.keys())
def values(self):
"See IEnumerableMapping"
return [v for k, v in self._data]
def items(self):
"See IEnumerableMapping"
return self._data
def __len__(self):
"See IEnumerableMapping"
return len(self._data)
def setObject(self, key, object):
"See IWriteContainer"
self._next += 1
if key:
if key in self:
raise DuplicationError("key is already registered", key)
try:
n = int(key)
except ValueError:
pass
else:
if n > self._next:
self._next = n
else:
key = str(self._next)
while key in self:
self._next += 1
key = str(self._next)
self._data += ((key, object), )
return key
def __delitem__(self, key):
"See IWriteContainer"
if key not in self:
raise KeyError, key
self._data = tuple(
[item
for item in self._data
if item[0] != key]
)
def moveTop(self, names):
self._data = tuple(
[item for item in self._data if (item[0] in names)]
+
[item for item in self._data if (item[0] not in names)]
)
def moveBottom(self, names):
self._data = tuple(
[item for item in self._data if (item[0] not in names)]
+
[item for item in self._data if (item[0] in names)]
)
def _moveUpOrDown(self, names, direction):
# Move each named item by one position. Note that this
# might require moving some unnamed objects by more than
# one position.
indexes = {}
# Copy named items to positions one less than they currently have
i = -1
for item in self._data:
i += 1
if item[0] in names:
j = max(i + direction, 0)
while j in indexes:
j += 1
indexes[j] = item
# Fill in the rest where there's room.
i = 0
for item in self._data:
if item[0] not in names:
while i in indexes:
i += 1
indexes[i] = item
items = indexes.items()
items.sort()
self._data = tuple([item[1] for item in items])
def moveUp(self, names):
self._moveUpOrDown(names, -1)
def moveDown(self, names):
self._moveUpOrDown(names, 1)
def beforeDeleteHook(self, object, container):
assert object == self
container = getAdapter(object, IZopeWriteContainer)
for k, v in self._data:
del container[k]
class RegistrationManagerContainer(object):
"""Mix-in to implement IRegistrationManagerContainer
"""
def __init__(self):
super(RegistrationManagerContainer, self).__init__()
self.setObject('RegistrationManager', RegistrationManager())
def __delitem__(self, name):
"""Delete an item, but not if it's the last registration manager
"""
item = self[name]
if IRegistrationManager.isImplementedBy(item):
# Check to make sure it's not the last one
if len([i for i in self.values()
if IRegistrationManager.isImplementedBy(i)]) < 2:
raise NoRegistrationManagerError(
"Can't delete the last registration manager")
super(RegistrationManagerContainer, self).__delitem__(name)
def getRegistrationManager(self):
"""Get a registration manager
"""
# Get the registration manager for this folder
for name in self:
item = self[name]
if IRegistrationManager.isImplementedBy(item):
# We found one. Get it in context
return ContextWrapper(item, self, name=name)
else:
raise NoRegistrationManagerError(
"Couldn't find an registration manager")
getRegistrationManager = ContextMethod(getRegistrationManager)
from zope.xmlpickle import dumps, loads
from zope.app.interfaces.fssync import IObjectFile
from zope.app.fssync.classes import ObjectEntryAdapter
class ComponentRegistrationAdapter(ObjectEntryAdapter):
"""Fssync adapter for ComponentRegistration objects and subclasses.
This is fairly generic -- it should apply to most subclasses of
ComponentRegistration. But in order for it to work for a
specific subclass (say, UtilityRegistration), you have to (a) add
an entry to configure.zcml, like this:
<fssync:adapter
class=".utility.UtilityRegistration"
factory=".registration.ComponentRegistrationAdapter"
/>
and (b) add a function to factories.py, like this:
def UtilityRegistration():
from zope.app.services.utility import UtilityRegistration
return UtilityRegistration("", None, "")
The file representation of a registration object is an XML pickle
for a modified version of the instance dict. In this version of
the instance dict, the __annotations__ attribute is omitted,
because annotations are already stored on the filesystem in a
different way (in @@Zope/Annotations/<file>).
"""
implements(IObjectFile)
def factory(self):
"""See IObjectEntry."""
name = self.context.__class__.__name__
return "zope.app.services.factories." + name
def getBody(self):
"""See IObjectEntry."""
obj = removeAllProxies(self.context)
ivars = {}
ivars.update(obj.__getstate__())
aname = "__annotations__"
if aname in ivars:
del ivars[aname]
return dumps(ivars)
def setBody(self, body):
"""See IObjectEntry."""
obj = removeAllProxies(self.context)
ivars = loads(body)
obj.__setstate__(ivars)
# XXX Pickle backward compatability
ConfigurationRegistry = RegistrationStack
ConfigurationManager = RegistrationManager
import sys
sys.modules['zope.app.services.registrationmanager'
] = sys.modules['zope.app.services.registration']
sys.modules['zope.app.services.configuration'
] = sys.modules['zope.app.services.registration']
=== Added File Zope3/src/zope/app/services/utility.txt ===
==================================================
Creating Local Services: The Local Utility Service
==================================================
:Author: Jim Fulton
:Version: $Revision: 1.1.2.1 $
.. contents::
This document describes how to implement a common type of local
service. We'll walk through an example step by step. We'll implement
a local utility service. A utility service must implement the
interface ``zope.component.interfaces.IUtilityService``.
Step 1. Create a minimal service
--------------------------------
Create a minimal service that delagates everything to the
service above it, in the file ``utility.py``::
from persistence import Persistent
from zope.component.exceptions import ComponentLookupError
from zope.context import ContextMethod
from zope.app.component.nextservice import getNextService
from zope.component.interfaces import IUtilityService
from zope.app.interfaces.services.interfaces import ISimpleService
from zope.interface import implements
class LocalUtilityService(Persistent):
implements(IUtilityService, ISimpleService)
def getUtility(self, interface, name=''):
utility = self.queryUtility(interface, name=name)
if utility is None:
raise ComponentLookupError("utility", interface, name)
return utility
getUtility = ContextMethod(getUtility)
def queryUtility(self, interface, default=None, name=''):
next = getNextService(self, "Utilities")
return next.queryUtility(interface, default, name)
queryUtility = ContextMethod(queryUtility)
The local service subclasses ``Persistent`` to provide support for
transparent persistent in the ZODB.
The local service uses the `ContextMethod`` function to convert it's
methods to be context methods. Context methods are called with "self"
arguments that are context wrapped. This is needed if the methods or
properties are going to call APIs that need acquisition context.
The ``getUtility`` method simply delegates to ``queryUtility``. The
``queryUtility`` method delegates to the next utility service using
``getNextService``. (Both methods are specified by the
``IUtilityService`` interface.)
The function ``getNextService`` looks up the next service above the
current service. It takes a location and a service name. We use it
to get the interface service defined above our service, which may be
the global service, and delegate to it.
In addition to implementing ``IUtilityService``, the local service
implements ``ISimpleService``. A Local service must implement
``zope.app.interfaces.services.interfaces.ILocalService`` and a local
service must be annotatable. ``ISimpleService`` simply extends
``ILocalService`` and ``IAttributeAnnotatable``.
I created the service in the ``utility`` module in this package (the
file ``utility.py``). This package is already pretty large. To avoid
a really large zcml file, I've started giving each service its own
zcml file. So I also created an ``utility.zcml`` file::
<zopeConfigure xmlns="http://namespaces.zope.org/zope">
<content class=".utility.LocalUtilityService">
<factory
id="zope.app.services.UtilityService"
permission="zope.ManageServices"
/>
</content>
</zopeConfigure>
and I added an include to the package configuration file::
<!-- Utility Service --> <include file="utility.zcml" />
To make it possible to add the utility service, I need to add an entry to
the ``add_service`` browser menu. The ``add_component`` menu is the menu
used by site folders for adding objects. To do this, I need to add a
browser menu configuration. Eventually, the local interface will
have a number of views, so I create a package, ``utility``, for
it in ``zope/app/browser/services``. [1]_ In that
package, I put a configuration that defines the needed browser menu
item::
<zopeConfigure xmlns="http://namespaces.zope.org/browser">
<menuItem
for="zope.app.interfaces.container.IAdding"
menu="add_service"
action="zope.app.services.UtilityService"
title="Utility Service"
permission="zope.ManageServices"
/>
</zopeConfigure>
and I added an include to the configuration file in
zope.app.browser.services::
<!-- Utility Service --> <include package=".utility" />
With this in place, I can add a local service that does nothing but
delegate to a service above it. (To actually create a utility service
instance, I have to go to the service manager and use its ``Add
service`` action. The service manager is reached from the root folder
by using the ``Manage local services`` action.)
Step 2. Providing functionality
-------------------------------
Now it's time to add some functionality. A utility service keeps
track of utility components by name and interface. It allows
components to be registered and then looked up later.
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.
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::
{ 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.
Similarly, we add a ``createRegistrationsFor`` method that takes a
registration object holding registration parameters and creates a
registration registry 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
assures that updates are made persistently. If there isn't implementor
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:
- name
- interface
- permission
- The location of the actual component.
The registration objects provide access to the component through the
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,
``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).
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
``IRegistration``, giving summary information used by several
predefined views. See the interface for a description of these methods.
We need to provide user interfaces for:
- The utility service,
- The utility registrations, and for
- Registered utilities
Utility service user interface
==============================
The utility service needs a view for showing what utilities have been
registered.
MORE DOCUMENTATION TO FOLLOW
Utility registration user interface
===================================
We need two views for registration objects:
- an add view, and
- an edit view
The registration add view will be created using a schema-driven add
form::
<addform
label="New Utility Registration"
for="zope.app.interfaces.services.utility.ILocalUtility"
name="addRegistration.html"
schema="zope.app.interfaces.services.utility.IUtilityRegistration"
class=".AddRegistration"
permission="zope.ManageServices"
content_factory="zope.app.services.utility.UtilityRegistration"
arguments="name interface componentPath"
set_after_add="status"
fields="name interface componentPath permission status"
/>
The add form is named ``addRegistration.html``. This is a standard
name that a number of other views expect to be defined. The form is
registered for ``ILocalUtility``. ``ILocalUtility`` is a marker
interface thgat extends ``IRegisterable``. We'll require that all
local utilities implement this view. Utility components should also
implement IAttributeAnnotatable, unless they want to provide a
different way to store annotations.
Notice that there's no template! The <addform> directive creates the
form for us using a generic template, zope/app/browser/form/add.pt,
and information about the specific fields to be displayed extracted
from the schema. We do specify a class name: the AddRegistration
class. This class needs some explanation.
The <addform> directive uses the AddRegistration class as a mix-in
class. It may override various methods to customize the add form; the
set of methods that can be customized is described by the
``zope.app.interfaces.browser.form.IAddFormCustomization`` interface.
In this particular case, we must override ``add`` and ``nextURL``
because their default implementations only work when the add form is a
view on an `IAdding` view. That is the normal way to use add forms, but
here we don't do that; this particular add form is a view on a local
utility component. Our ``AddRegistration`` class subclasses
``zope.app.browser.services.registration.AddComponentRegistration``,
which provides the implementations of ``add`` and ``nextURL`` that we
need. The ``add`` method defined in ``AddComponentRegistration`` finds
the congiguration manager in the current folder and adds the new
registration object to it.
The AddRegistration class defines a class attribute::
interface_widget = CustomWidget(UtilityInterfaceWidget)
This tells the forms machinery to use a a custom widget for the
interface field. The custom widget we use is a specialized interface
widget that allows the user to select from the non-trivial interfaces
implemented by the component being configured.
The edit view looks similar to the add view, but its definition
is simpler, because it isn't deviating quite as much from a standard
edit view::
<editform
name="index.html"
menu="zmi_views" title="Edit"
schema="zope.app.interfaces.services.utility.IUtilityRegistration"
label="Utility Registration"
permission="zope.ManageServices"
fields="name interface componentPath permission status"
/>
This is a view on IUtilityRegistration, which is typical for an edit
view. The good news is that it has no template *or* class! The
<editform> directive lets us specifiy all the customization we need:
- ``name=``: The view name. This is the last component of the URL for
the view.
- ``menu=``, ``title=``: Menu information: "zmi_views" means that this
view is one of the "tabs" for this type of object, the title
argument gives the text in the tab.
- ``schema=``: The interface used as the schema. The field
definitions in this interface define which attributes are displayed
in the form, and how.
- ``label=``: The label, used as the title text in the view.
- ``permission=``: A permission needed to access the view.
- ``fields=``: A list of fields to be displayed in the form. This is
used here to force the order in which the fields are displayed. It
can also be used to display only a subset of the fields present in
the schema.
And that's all there is to the edit view. Some observable differences
between the edit view and the add view:
- The add view lets you specify the name or the interface; the edit
view displays these fields read-only.
- When you submit the add view, you are redirected to the
registration manager; the edit view takes you back to itself.
User interface for registered utilities
=======================================
In general, for registerable components, we want to do
the registration through the components themselves. That is, the site
admin should be able to walk up to a component and add or change a
registration for it. The most common case is actually that a site
manager creates a component and configures it right away. (This is
the same common case that is used for creating and configuring
services.) There's a standard view registered for all IRegisterable
components that provides the ability to view and change the
registrations for a component.
IRegisterable is a marker interface that extends IAnnotatable.
Annotations are used to record the registrations for a component.
---------------------------------------------------------------
.. [1] Of course, I initially forgot to include a nearly empty
``__init__.py`` file and had to add one later.
=== Zope3/src/zope/app/services/README.txt 1.4 => 1.4.10.1 ===
--- Zope3/src/zope/app/services/README.txt:1.4 Thu May 1 14:59:30 2003
+++ Zope3/src/zope/app/services/README.txt Sun Jun 22 10:23:26 2003
@@ -5,20 +5,17 @@
:Author: Jim Fulton
:Version: $Revision$
-.. contents::
-
This package includes implementations of several local services.
It also contains infrastructure for implementing local services.
-This document describes how to implement local services. It's not
-too difficult, but there can be a lot of details that are hard to
-remember.
+Implementing lolcal 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*
that has the responsibility to collaborate with services above it.
Local services are stored in the Zope object database, so they also
need to be persistent. Finally, many local services support modular
-configuration through configuration objects.
+registration through registration objects.
A few words on the difference between local and global services:
@@ -34,124 +31,22 @@
them in the object hierarchy, or with the global service; global
services by definition have nothing "above" them.
-Let's walk through an example step by step. We'll implement a
-local utility service. A utility service must implement the
-interface ``zope.component.interfaces.IUtilityService``.
-
-
-Step 1. Create a minimal service
---------------------------------
-
-Create a minimal service that delagates everything to the
-service above it, in the file ``utility.py``::
-
- from persistence import Persistent
- from zope.component.exceptions import ComponentLookupError
- from zope.proxy.context import ContextAware
- from zope.app.component.nextservice import getNextService
- from zope.component.interfaces import IUtilityService
- from zope.app.interfaces.services.interfaces import ISimpleService
-
- class LocalUtilityService(Persistent, ContextAware):
-
- __implements__ = IUtilityService, ISimpleService
-
- def getUtility(self, interface, name=''):
- utility = self.queryUtility(interface, name=name)
- if utility is None:
- raise ComponentLookupError("utility", interface, name)
- return utility
-
- def queryUtility(self, interface, default=None, name=''):
- next = getNextService(self, "Utilities")
- return next.queryUtility(interface, default, name)
-
-The local service subclasses two classes:
-
-``Persistent``
- Provides support for transparent persistent in the ZODB.
-
-``ContextAware``
- Causes all of the methods or properties defined in
- the class (or base classes) to be bound to context-wrapped
- instances. This is needed if the methods or properties are going to
- call APIs that need acquisition context. We could convert each of
- the methods to context methods individually, but it's easier to just
- mix-in context aware.
-
-The ``getUtility`` method simply delegates to ``queryUtility``. The
-``queryUtility`` method delegates to the next utility service using
-``getNextService``. (Both methods are specified by the
-``IUtilityService`` interface.)
-
-The function ``getNextService`` looks up the next service above the
-current service. It takes a location and a service name. We use it
-to get the interface service defined above our service, which may be
-the global service, and delegate to it.
-
-I created the service in the ``utility`` module in this package (the
-file ``utility.py``). This package is already pretty large. To avoid
-a really large zcml file, I've started giving each service its own
-zcml file. So I also created an ``utility.zcml`` file::
-
- <zopeConfigure xmlns="http://namespaces.zope.org/zope">
-
- <content class=".utility.LocalUtilityService">
- <factory
- id="zope.app.services.UtilityService"
- permission="zope.ManageServices"
- />
- </content>
-
- </zopeConfigure>
-
-and I added an include to the package configuration file::
-
- <!-- Utility Service --> <include file="utility.zcml" />
-
-To make it possible to add the utility service, I need to add an entry to
-the ``add_component`` browser menu. The ``add_component`` menu is the menu
-used by site folders for adding objects. To do this, I need to add a
-browser menu configuration. Eventually, the local interface will
-have a number of views, so I create a package, ``utility``, for
-it in ``zope/app/browser/services``. [1]_ In that
-package, I put a configuration that defines the needed browser menu
-item::
-
- <zopeConfigure xmlns="http://namespaces.zope.org/browser">
-
- <menuItem
- for="zope.app.interfaces.container.IAdding"
- menu="add_service"
- action="zope.app.services.UtilityService"
- title="Utility Service"
- permission="zope.ManageServices"
- />
-
- </zopeConfigure>
-
-and I added an include to the configuration file in
-zope.app.browser.services::
-
- <!-- Utility Service --> <include package=".utility" />
-
-With this in place, I can add a local service that does nothing but
-delegate to a service above it. (To actually create a utility service
-instance, I have to go to the service manager and use its ``Add
-service`` action. The service manager is reached from the root folder
-by using the ``Manage local services`` action.)
-
-
-Step 2. Providing functionality
--------------------------------
-
-Now it's time to add some functionality. A utility service keeps
-track of utility components by name and interface. It allows
-components to be registered and then looked up later.
-
-An important feature of component registration services, like the
-utility service, is that they support multiple conflicting
-registrations. At most one of the registrations is active. A site
+ (Note that it's up to the service to decide what form the
+ collaboration will take. An exceptable form of collaboration is to
+ not collaborate at all.
+
+Registration
+------------
+
+Many services act as component registries. Their primary job is to
+allow components to be looked up based on parameters such as names,
+interfaces or both. Examples of component registries include the
+adapter service, the view service, the service service, and the
+utility service.
+
+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.
@@ -160,358 +55,68 @@
it. The new version is active. The site developer then finds a
bug in the new version. Because the old utility is still registered,
the site developer can easily switch back to it by making it active.
+In fact, the site manager only needs to inactivate the new version and
+the old version becomes active again.
-Utilities can be provided in two ways:
-
-- As persistent objects in (site-management) folders.
+To support this registration flexibility, Zope provides a registration
+framework:
-- As module global objects. (A variation is to point to a class
- that can be called without arguments to create a utility.)
+- Registration objects manage registration parameters and other data.
+ They also provide access to registered components. In some cases,
+ such as adapters and views, they are responsible for constructing
+ components on the fly.
+
+- Registration managers support management of registration objects
+ in folders. Each folder has a registration manager containing all
+ of the registration objects for that folder.
-We'd like to avoid making the utility service have to deal with
-these variations directly.
-
-We want to make it possible for folders to provide configurations
-that can be reused in different sites.
-
-To support the configuration flexibility described above, Zope
-provides a configuration framework:
-
-- Configuration registry objects manage multiple configurations for
- the same configuration parameters (at most one of which is active at
+- RegistrationStack objects manage multiple registrations for
+ the same registration parameters (at most one of which is active at
any given time). For example, in the case of a utility service
- these would be configurations for the same interface and name.
-
-- Configuration objects provide configuration data.
+ these would be registrations for the same interface and name.
-- Configuration managers support management of configuration objects
- in folders.
+There are two kinds of registrations:
-We'll start by updating the utility service to support configurations.
-The updated local utility service implementation can be found in
-zope/app/services/utility.py.
-
-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 configuration
-registries.
-
-We also need to implement
-zope.app.interfaces.services.configuration.IConfigurable. This
-defines two methods, ``queryConfigurationsFor`` and
-``createConfigurationsFor``.
-
-A ``queryConfigurationsFor`` method is added to implement
-``IConfigurable``. It takes a configuration object and returns the
-corresponding configuration registry. The configuration object is
-used to provide an abstract way to represent configuration parameters.
-Typically, the configuration parameters are extracted and a more
-concrete method is called. In the local utility service, we extract
-the utility name and interface and call ``queryConfigurations`` with
-the name and interface.
-
-Similarly, we add a ``createConfigurationsFor`` method that takes a
-configuration object holding configuration parameters and creates a
-configuration registry 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
-assures that updates are made persistently. If there isn't implementor
-data for the given interface, we create a configuration registry and
-register it for the interface.
-
-Finally, we modify ``queryUtility`` to use registered utility
-configurations. We try to get a configuration registery by calling
-``queryConfigurations``. If we get one, we call its ``active``
-method to get the active configuration, if any. Finally, we call
-``getComponent`` on the active configuration to get the actual
-component. We leave it up to the configuration object to take care of
-actually finding and returning the component.
-
-Our local utility service is now complete, except for a user
-interface. We need to provide utility configuration objects. The
-utility configuration objects need to manage several bits of
-information:
-
-- name
-
-- interface
-
-- permission
-
-- The location of the actual component.
-
-We'll start by creating a configuration class for utility components
-stored in folders. Somewhat different approaches are taken for
-configuring components contained in folders and objects contained in
-modules. Objects contained in folders provide a configurations view
-that shows the configurations for the object and lets you add
-configurations. When we add these objects, we typically add
-configurations at the same time.
-
-To create the configuration class, we'll start by defining a
-configuration schema in
-``zope/app/interfaces/services/utility.py``. The schema should extend
-``zope.app.interfaces.services.configuration.IConfiguration``.
-There's a more specific interface,
-``zope.app.interfaces.services.configuration.IComponentConfiguration``
-that is much closer to what we need. (XXX Add footnote explaining why
-we can't use INamedComponentConfiguration in this example.)
-We extend this interface as IUtilityConfiguration, 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 ``UtilityConfiguration`` class is added to the ``utility`` module in
-``zope/app/services`` that implements the configuration interface.
-We can subclass ComponentConfiguration, which does much of the work.
-
-
-For utility components stored in folders, we want to do the
-configuration through the components themselves. That is, the site
-admin should be able to walk up to a component that implements a
-utility and add or change a utility configuration for it. The most
-common case is actually that a site manager creates a utility
-component and configures it right away. (This is the same common case
-that is used for creating and configuring services.)
-
-There's a view on utility components for managing their
-configurations; similar to the corresponding view on service
-components, it shows a list of all configurations for the component,
-and a link to add a new one.
-
-To implement this view, we need to keep track of the
-configuration objects for given utility components. The reference
-from a configuration object to the component it configures is
-contained in the configuration object itself. In order to find the
-configurations pertaining to a component, we have to implement back
-pointers somehow. Requiring each component to keep track of these
-back pointers would be impractical; fortunately there's a general
-mechanism that we can use.
-
-The general mechanism is called "annotations". See
-zope/app/interfaces/annotation.py for the full scoop. The short
-version: by adapting an object to IAnnotations, we get a mapping-like
-interface that allows us to store arbitrary named data for the object.
-In the most common implemenation variant (see
-zope/app/attributeannotations.py), all annotation data is stored in a
-dictionary which itself is stored as the attribute __annotations__.
-Because we don't want to stomp on a component's attributes (even if
-they have a __funky__ name) without its permission, a component must
-declare that it implements IAttributeAnnotatable; the implementation
-is registered as an adapter from this interface to IAnnotations.
-
-To store the configuration back pointers on components, we use an
-annotation named "zope.app.services.configuration.UseConfiguration".
-(By convention, annotation keys should contain the full dotted name of
-the module or class that uses them.) By adapting a component to
-IUseConfiguration, we get an interface defining methods ``addUsage``,
-``removeUsage`` and ``usages``, which provide access to the back
-pointers.
-
-We also need to provide two summary lines for the configuration
-manager. These summary lines are returned by two methods that are
-(questionably, but conveniently) defined in the IConfiguration
-interface: usageSummary() and implementationSummary(). We override
-usageSummary() to return a string of the form "<interface> utility
-[named <name>]"; we inherit implementationSummary() from the
-ComponentConfiguration base class, which returns the component
-pathname as a string. These two lines are used in the configuration
-manager's default view, which lists all the configurations it knows
-about; the first line is a a link to an edit view for configuration
-object.
-
-We're now ready to write view code. We will create three views:
-
-- A "Configurations" view for utility components.
-
-- An "add configuration" view to configure a utility.
-
-- An "edit configuration" view to change a utility's configuration.
-
-
-The first view we create is the "Configurations" view for utility
-components. This is very similar to the Configurations view for
-service components, and for several other components that are handled
-by the configuration manager. The view is a "tab" on any object that
-implements ILocalUtility; the view name is useConfigurations.html and
-the tab label is "Configurations". All this is expressed by the ZCML
-for the view, in zope/app/browser/services/utility/configure.zcml::
-
- <page
- for="zope.app.interfaces.services.utility.ILocalUtility"
- name="useConfiguration.html"
- template="useconfiguration.pt"
- class=".useconfiguration.UseConfiguration"
- permission="zope.ManageServices"
- menu="zmi_views" title="Configurations"
- />
-
-We won't show the template (useconfiguration.pt) here; it renders a
-bulleted list giving links to the configurations (each linking to the
-edit view for the configuration object), and a link to add a new
-configuration.
-
-The information for the bulleted list is computed by the
-UseConfiguration class in the file useconfiguration.py, which we also
-won't show here. As described earlier, it adapts the component to
-IUseConfiguration and gets the back pointers to configuration objects
-from the adapter's usages() method. For each configuration object it
-returns enough information to render the utility's interface, name,
-activity status, and URL.
-
-
-The second view we create is the add view for utility configurations.
-Here's the ZCML::
-
- <addform
- for="zope.app.interfaces.services.utility.ILocalUtility"
- name="addConfiguration.html"
- schema="zope.app.interfaces.services.utility.IUtilityConfiguration"
- class=".useconfiguration.AddConfiguration"
- permission="zope.ManageServices"
- content_factory="zope.app.services.utility.UtilityConfiguration"
- arguments="name interface componentPath"
- set_after_add="status"
- fields="name interface componentPath permission status"
- />
-
-(XXX Maybe briefly explain each attribute, like we do below for
-<editform>?)
-
-Notice that there's no template! The <addform> directive creates the
-form for us using a generic template, zope/app/browser/form/add.pt,
-and information about the specific fields to be displayed extracted
-from the schema. We do specify a class name: the AddConfiguration
-class. This class needs some explanation.
-
-The ``for=`` attribute says that this view applies to all objects that
-implement the ILocalUtility interface. All utility components should
-implement this interface in order to be configurable as a utility.
-This interface extends IUseConfigurable, which is required so that a
-utility component can keep track of the back pointers to configuration
-objects that reference it, as was discussed above. Utility components
-should also implement IAttributeAnnotatable, unless they want to
-provide a different way to store annotations.
-
-The <addform> directive uses the AddConfiguration class as a mix-in
-class. It may override various methods to customize the add form; the
-set of methods that can be customized is given by the
-``zope.app.interfaces.browser.form.IAddFormCustomization class``. In this
-particular case, we must override ``add`` and ``nextURL`` because their
-default implementations only work when the add form is a view on an
-IAdding view. That is the normal way to use add forms, but here we
-don't do that; this particular add form is a view on a local utility
-component. Our ``AddConfiguration`` class subclasses
-``zope.app.browser.services.configuration.AddComponentConfiguration``,
-which provides the implementations of ``add`` and ``nextURL`` that we
-need. The ``add`` method defined in ``AddComponentConfiguration``
-finds the congiguration manager in the current folder and adds the new
-configuration object to it.
-
-
-The AddConfiguration class defines a class attribute::
-
- interface = CustomWidget(UtilityInterfaceWidget)
-
-This tells the forms machinery to use a a custom widget for the
-interface field. The custom widget we use is a specialized interface
-widget that allows the user to select from the non-trivial interfaces
-implemented by the component being configured.
-
-The third view we create is the edit view for utility configuration
-objects. This view looks similar to the add view, but its definition
-is simpler, because it isn't deviating quite as much from a standard
-edit view::
-
- <editform
- name="index.html"
- menu="zmi_views" title="Edit"
- schema="zope.app.interfaces.services.utility.IUtilityConfiguration"
- label="Utility Configuration"
- permission="zope.ManageServices"
- fields="name interface componentPath permission status"
- />
-
-This is a view on IUtilityConfiguration, which is typical for an edit
-view. The good news is that it has no template *or* class! The
-<editform> directive lets us specifiy all the customization we need:
-
-- ``name=``: The view name. This is the last component of the URL for
- the view.
-
-- ``menu=``, ``title=``: Menu information: "zmi_views" means that this
- view is one of the "tabs" for this type of object, the title
- argument gives the text in the tab.
-
-- ``schema=``: The interface used as the schema. The field
- definitions in this interface define which attributes are displayed
- in the form, and how.
-
-- ``label=``: The label, used as the title text in the view.
-
-- ``permission=``: A permission needed to access the view.
-
-- ``fields=``: A list of fields to be displayed in the form. This is
- used here to force the order in which the fields are displayed. It
- can also be used to display only a subset of the fields present in
- the schema.
-
-And that's all there is to the edit view. Some observable differences
-between the edit view and the add view:
-
-- The add view lets you specify the name or the interface; the edit
- view displays these fields read-only.
-
-- When you submit the add view, you are redirected to the
- configuration manager; the edit view takes you back to itself.
-
-
-
-To do:
-
- Describe the demo utility
-
- Need a UI for browsing registered utilities in the utility service.
- (Done, need to describe it.)
-
- XXX We decided not to do this after all:
- Configuration of module globals
-
- - Need the configuration object class that keeps track of:
-
- o name
-
- o interface
-
- o dotted name
-
- o permission
-
- - Add view for the configuration
-
- - Edit view for the configuration
-
- - Summary view of the configuration in a configuration registry
-
- - Summary view of the configuration in a configuration manager
+- Local-object registrations register objects in site-management
+ folders, such as service instances, utility instances, database
+ connections, caches, and templates.
+ Local objects are named using a path.
+ Local-object registrations are primarily managed through the objects
+ that they register. The objects have a "Registrations" tab that
+ allows the registrations (usually 1) for the objects to be managed.
+ Local-object registrations can also be browsed and edited in the
+ registration manager for the folder containing the registered
+ components.
+- 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.)
+
+ Module-global objects are named using dotted names.
+ Module-global registrations are added, browsed and edited in
+ registration mananagers.
+Implementation of services that support registration is substantially
+more difficult that implementation of non-registry services.
+Examples
+--------
+Implementation of local services is described through examples.
+- The error reporting service is among the simplest examples because
+ error reporting services don't support registration and don't
+ delegate requests to services above.
+ See error.txt
----------------------------------------------------------------
+- The utility service is an example of a service that supports
+ local-object registration. It also provides a simple example of a
+ service that delegates to services above it.
-.. [1] Of course, I initially forgot to include a nearly empty
- ``__init__.py`` file and had to add one later.
+ See utility.txt.
=== Zope3/src/zope/app/services/adapter.py 1.14 => 1.14.2.1 ===
--- Zope3/src/zope/app/services/adapter.py:1.14 Wed May 21 16:30:04 2003
+++ Zope3/src/zope/app/services/adapter.py Sun Jun 22 10:23:26 2003
@@ -21,20 +21,21 @@
from zope.interface.adapter import AdapterRegistry
from persistence import Persistent
from persistence.dict import PersistentDict
+from zope.interface import implements
from zope.component.interfaces import IAdapterService
from zope.component.exceptions import ComponentLookupError
from zope.component import getServiceManager
from zope.app.services.servicenames import Adapters
-from zope.app.interfaces.services.configuration import IConfigurable
-from zope.app.services.configuration import ConfigurationRegistry
-from zope.app.services.configuration import SimpleConfiguration
-from zope.proxy.context import ContextWrapper
-from zope.proxy.context import ContextMethod
-from zope.app.services.configuration import ConfigurationStatusProperty
+from zope.app.interfaces.services.registration import IRegistry
+from zope.app.services.registration import RegistrationStack
+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
-from zope.app.interfaces.services.adapter import IAdapterConfiguration
+from zope.app.interfaces.services.adapter import IAdapterRegistration
class PersistentAdapterRegistry(Persistent, AdapterRegistry):
@@ -44,22 +45,22 @@
class AdapterService(Persistent):
- __implements__ = IAdapterService, IConfigurable, ISimpleService
+ implements(IAdapterService, IRegistry, ISimpleService)
def __init__(self):
self._byName = PersistentDict()
- def queryConfigurationsFor(self, configuration, default=None):
- "See IConfigurable"
+ def queryRegistrationsFor(self, registration, default=None):
+ "See IRegistry"
# XXX Need to add named adapter support
- return self.queryConfigurations(
- configuration.forInterface, configuration.providedInterface,
- configuration.adapterName,
+ return self.queryRegistrations(
+ registration.forInterface, registration.providedInterface,
+ registration.adapterName,
default)
- queryConfigurationsFor = ContextMethod(queryConfigurationsFor)
+ queryRegistrationsFor = ContextMethod(queryRegistrationsFor)
- def queryConfigurations(self,
+ def queryRegistrations(self,
forInterface, providedInterface, adapterName,
default=None):
@@ -73,18 +74,18 @@
return ContextWrapper(registry, self)
- queryConfigurations = ContextMethod(queryConfigurations)
+ queryRegistrations = ContextMethod(queryRegistrations)
- def createConfigurationsFor(self, configuration):
- "See IConfigurable"
+ def createRegistrationsFor(self, registration):
+ "See IRegistry"
# XXX Need to add named adapter support
- return self.createConfigurations(
- configuration.forInterface, configuration.providedInterface,
- configuration.adapterName)
+ return self.createRegistrations(
+ registration.forInterface, registration.providedInterface,
+ registration.adapterName)
- createConfigurationsFor = ContextMethod(createConfigurationsFor)
+ createRegistrationsFor = ContextMethod(createRegistrationsFor)
- def createConfigurations(self, forInterface, providedInterface, name):
+ def createRegistrations(self, forInterface, providedInterface, name):
adapters = self._byName.get(name)
if adapters is None:
@@ -93,12 +94,12 @@
registry = adapters.getRegistered(forInterface, providedInterface)
if registry is None:
- registry = ConfigurationRegistry()
+ registry = RegistrationStack()
adapters.register(forInterface, providedInterface, registry)
return ContextWrapper(registry, self)
- createConfigurations = ContextMethod(createConfigurations)
+ createRegistrations = ContextMethod(createRegistrations)
def getAdapter(self, object, interface, name=''):
"See IAdapterService"
@@ -186,11 +187,13 @@
return adapters.getRegisteredMatching(for_interfaces,
provided_interfaces)
-class AdapterConfiguration(SimpleConfiguration):
+class AdapterRegistration(SimpleRegistration):
- __implements__ = IAdapterConfiguration, SimpleConfiguration.__implements__
+ implements(IAdapterRegistration)
- status = ConfigurationStatusProperty(Adapters)
+ 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
@@ -216,3 +219,6 @@
return factory(object)
getAdapter = ContextMethod(getAdapter)
+
+# XXX Pickle backward compatability
+AdapterConfiguration = AdapterRegistration
=== Zope3/src/zope/app/services/auth.py 1.15 => 1.15.10.1 ===
--- Zope3/src/zope/app/services/auth.py:1.15 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/auth.py Sun Jun 22 10:23:26 2003
@@ -30,11 +30,12 @@
from zope.app.interfaces.services.auth import IAnnotatableUser
-from zope.proxy.introspection import removeAllProxies
+from zope.proxy import removeAllProxies
from zope.app.attributeannotations import AttributeAnnotations
from zope.app.component.nextservice import getNextService
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
from zope.app.interfaces.services.service import ISimpleService
+from zope.interface import implements
class DuplicateLogin(Exception):
@@ -46,7 +47,7 @@
class AuthenticationService(Persistent):
- __implements__ = IAuthenticationService, IContainer, ISimpleService
+ implements(IAuthenticationService, IContainer, ISimpleService)
def __init__(self):
self._usersbylogin = OOBTree()
@@ -124,6 +125,7 @@
raise ValueError(key)
self._usersbyid[key] = object
self._usersbylogin[object.getLogin()] = object
+ return key
def __delitem__(self, key):
'See IWriteContainer'
@@ -159,11 +161,10 @@
return key in self._usersbyid
-
class User(Persistent):
"""A persistent implementation of the IUser interface """
- __implements__ = IAnnotatableUser
+ implements(IAnnotatableUser)
def __init__(self, id, title, description, login, pw):
self.__id = id
=== Zope3/src/zope/app/services/cache.py 1.9 => 1.9.10.1 ===
--- Zope3/src/zope/app/services/cache.py:1.9 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/cache.py Sun Jun 22 10:23:27 2003
@@ -17,33 +17,29 @@
"""
from persistence import Persistent
-
-from zope.component import getService
-from zope.proxy.context import ContextMethod
-
from zope.app.component.nextservice import queryNextService
from zope.app.interfaces.cache.cache import ICache, ICachingService
from zope.app.interfaces.event import IObjectModifiedEvent
-from zope.app.interfaces.services.cache import ICacheConfiguration
-from zope.app.interfaces.services.configuration \
- import INameComponentConfigurable
+from zope.app.interfaces.services.cache import ICacheRegistration
+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.configuration import ConfigurationStatusProperty
-from zope.app.services.configuration import NameComponentConfigurable
-from zope.app.services.configuration import NamedComponentConfiguration
+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
+from zope.component import getService
+from zope.context import ContextMethod
+from zope.interface import implements
class ILocalCachingService(ICachingService, IEventChannel,
- INameComponentConfigurable):
+ INameComponentRegistry):
"""TTW manageable caching service"""
-class CachingService(ServiceSubscriberEventChannel, NameComponentConfigurable):
+class CachingService(ServiceSubscriberEventChannel, NameComponentRegistry):
- __implements__ = (ILocalCachingService,
- ISimpleService,
- ServiceSubscriberEventChannel.__implements__)
+ implements(ILocalCachingService, ISimpleService)
_subscribeToServiceInterface = IObjectModifiedEvent
@@ -52,9 +48,13 @@
# __init__ with respect to calling
# super(ClassName, self).__init__(*args, **kw), then we can
# replace the following with just a call to super.
+ # XXX Disagree. __init__ doesn't always have the same signature,
+ # hence cllaborative super doesn't apply to __init__, at least
+ # not in general. (It may work by convention for Fields.)
+ # --Guido
Persistent.__init__(self)
ServiceSubscriberEventChannel.__init__(self)
- NameComponentConfigurable.__init__(self)
+ NameComponentRegistry.__init__(self)
def getCache(wrapped_self, name):
'See ICachingService'
@@ -78,8 +78,8 @@
def getAvailableCaches(wrapped_self):
'See ICachingService'
caches = {}
- for name in wrapped_self.listConfigurationNames():
- registry = wrapped_self.queryConfigurations(name)
+ for name in wrapped_self.listRegistrationNames():
+ registry = wrapped_self.queryRegistrations(name)
if registry.active() is not None:
caches[name] = 0
service = queryNextService(wrapped_self, "Caching")
@@ -90,19 +90,17 @@
getAvailableCaches = ContextMethod(getAvailableCaches)
-class CacheConfiguration(NamedComponentConfiguration):
+class CacheRegistration(NamedComponentRegistration):
- __doc__ = ICacheConfiguration.__doc__
+ __doc__ = ICacheRegistration.__doc__
- __implements__ = (ICacheConfiguration,
- NamedComponentConfiguration.__implements__)
+ implements(ICacheRegistration)
- status = ConfigurationStatusProperty('Caching')
+ serviceType = 'Caching'
- label = "Cache"
+ status = RegistrationStatusProperty()
- def __init__(self, *args, **kw):
- super(CacheConfiguration, self).__init__(*args, **kw)
+ label = "Cache"
def activated(wrapped_self):
cache = wrapped_self.getComponent()
@@ -119,3 +117,7 @@
def getInterface(self):
return ICache
+
+
+# XXX Pickle backward compatability
+CacheConfiguration = CacheRegistration
=== Zope3/src/zope/app/services/configure.zcml 1.29 => 1.29.2.1 ===
--- Zope3/src/zope/app/services/configure.zcml:1.29 Thu May 15 17:30:44 2003
+++ Zope3/src/zope/app/services/configure.zcml Sun Jun 22 10:23:27 2003
@@ -3,13 +3,13 @@
xmlns:fssync='http://namespaces.zope.org/fssync'
>
-<!-- Configuration registries -->
+<!-- Registration registries -->
-<content class="zope.app.services.configuration.ConfigurationRegistry">
+<content class="zope.app.services.registration.RegistrationStack">
<require
permission="zope.ManageServices"
interface=
- "zope.app.interfaces.services.configuration.IConfigurationRegistry"
+ "zope.app.interfaces.services.registration.IRegistrationStack"
/>
</content>
@@ -22,16 +22,16 @@
/>
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.services.configuration.IConfigurable"
+ interface="zope.app.interfaces.services.registration.IRegistry"
attributes="getRegisteredMatching"
/>
</content>
-<content class="zope.app.services.adapter.AdapterConfiguration">
+<content class="zope.app.services.adapter.AdapterRegistration">
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.services.adapter.IAdapterConfiguration"
- set_schema="zope.app.interfaces.services.configuration.IConfiguration"
+ interface="zope.app.interfaces.services.adapter.IAdapterRegistration"
+ set_schema="zope.app.interfaces.services.registration.IRegistration"
/>
<require
permission="zope.ManageServices"
@@ -48,16 +48,16 @@
/>
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.services.configuration.IConfigurable"
+ interface="zope.app.interfaces.services.registration.IRegistry"
attributes="getRegisteredMatching"
/>
</content>
-<content class="zope.app.services.view.ViewConfiguration">
+<content class="zope.app.services.view.ViewRegistration">
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.services.view.IViewConfiguration"
- set_schema="zope.app.interfaces.services.configuration.IConfiguration"
+ interface="zope.app.interfaces.services.view.IViewRegistration"
+ set_schema="zope.app.interfaces.services.registration.IRegistration"
/>
<require
permission="zope.ManageServices"
@@ -65,11 +65,11 @@
/>
</content>
-<content class="zope.app.services.view.PageConfiguration">
+<content class="zope.app.services.view.PageRegistration">
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.services.view.IPageConfiguration"
- set_schema="zope.app.interfaces.services.view.IPageConfiguration"
+ interface="zope.app.interfaces.services.view.IPageRegistration"
+ set_schema="zope.app.interfaces.services.view.IPageRegistration"
/>
<require
permission="zope.ManageServices"
@@ -122,9 +122,9 @@
/>
<adapter
- for="zope.app.interfaces.services.configuration.IUseConfigurable"
- provides="zope.app.interfaces.services.configuration.IUseConfiguration"
- factory="zope.app.services.configuration.UseConfiguration"
+ for="zope.app.interfaces.services.registration.IRegisterable"
+ provides="zope.app.interfaces.services.registration.IRegistered"
+ factory="zope.app.services.registration.Registered"
/>
<!-- Role Templates -->
@@ -177,20 +177,20 @@
<require
permission="zope.View"
interface="zope.app.interfaces.cache.cache.ICachingService"
- attributes="queryConfigurations queryConfigurationsFor
- listConfigurationNames" />
+ attributes="queryRegistrations queryRegistrationsFor
+ listRegistrationNames" />
<require
permission="zope.ManageServices"
interface="zope.app.interfaces.container.IContainer" />
</content>
- <content class="zope.app.services.cache.CacheConfiguration">
+ <content class="zope.app.services.cache.CacheRegistration">
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.services.cache.ICacheConfiguration"
+ interface="zope.app.interfaces.services.cache.ICacheRegistration"
set_attributes="name componentPath permission"
set_schema=
- "zope.app.interfaces.services.configuration.IConfiguration" />
+ "zope.app.interfaces.services.registration.IRegistration" />
<require
permission="zope.ManageServices"
interface="zope.app.interfaces.container.IAddNotifiable" />
@@ -213,13 +213,13 @@
interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
</content>
- <content class="zope.app.services.service.ServiceConfiguration">
+ <content class="zope.app.services.service.ServiceRegistration">
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.services.service.IServiceConfiguration"
+ interface="zope.app.interfaces.services.service.IServiceRegistration"
set_attributes="serviceType componentPath permission"
set_schema=
- "zope.app.interfaces.services.configuration.IConfiguration"
+ "zope.app.interfaces.services.registration.IRegistration"
/>
<require
permission="zope.ManageServices"
@@ -250,26 +250,27 @@
</content>
<content class="zope.app.services.folder.SiteManagementFolder">
+ <factory permission="zope.ManageServices" />
<require
permission="zope.View"
interface="zope.app.interfaces.container.IReadContainer" />
<require
permission="zope.ManageServices"
interface="zope.app.interfaces.container.IWriteContainer"
- attributes="getConfigurationManager"
+ attributes="getRegistrationManager"
/>
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
</content>
-<!-- Configuration Manager -->
+<!-- Registration Manager -->
- <content class="zope.app.services.configuration.ConfigurationManager">
+ <content class="zope.app.services.registration.RegistrationManager">
<factory
- id = "zope.app.services.ConfigurationManager"
+ id = "zope.app.services.RegistrationManager"
permission = "zope.ManageServices"
- title = "Configuration Manager" />
+ title = "Registration Manager" />
<require
permission="zope.View"
interface="zope.app.interfaces.container.IReadContainer" />
@@ -277,7 +278,7 @@
permission="zope.ManageServices"
interface="
zope.app.interfaces.container.IWriteContainer
- zope.app.interfaces.services.configuration.IOrderedContainer
+ zope.app.interfaces.services.registration.IOrderedContainer
zope.app.interfaces.container.IDeleteNotifiable
"
/>
@@ -293,6 +294,10 @@
permission="zope.ManageCode"
interface="zodb.code.interfaces.IPersistentModuleManager"
/>
+ <require
+ permission="zope.ManageCode"
+ attributes="beforeDeleteHook"
+ />
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
@@ -314,12 +319,18 @@
interface="zope.app.interfaces.container.IWriteContainer
zope.app.interfaces.services.pagefolder.IPageFolderInfo"
set_schema="zope.app.interfaces.services.pagefolder.IPageFolderInfo"
- attributes="configured getConfigurationManager"
+ attributes="configured getRegistrationManager"
/>
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
</content>
+ <adapter
+ for="zope.app.interfaces.services.pagefolder.IPageFolder"
+ provides="zope.app.interfaces.context.IZopeContextWrapper"
+ factory="zope.app.services.pagefolder.PageFolderContextDecorator"
+ />
+
<!-- Connection Service -->
<content class="zope.app.services.connection.ConnectionService">
@@ -330,17 +341,17 @@
<require
permission="zope.View"
interface="zope.app.interfaces.rdb.IConnectionService"
- attributes="queryConfigurations queryConfigurationsFor
- listConfigurationNames" />
+ attributes="queryRegistrations queryRegistrationsFor
+ listRegistrationNames" />
</content>
- <content class="zope.app.services.connection.ConnectionConfiguration">
+ <content class="zope.app.services.connection.ConnectionRegistration">
<require
permission="zope.ManageServices"
interface=
- "zope.app.interfaces.services.connection.IConnectionConfiguration"
+ "zope.app.interfaces.services.connection.IConnectionRegistration"
set_attributes="name componentPath"
- set_schema="zope.app.interfaces.services.view.IPageConfiguration"
+ set_schema="zope.app.interfaces.services.view.IPageRegistration"
/>
<require
permission="zope.ManageServices"
@@ -477,7 +488,7 @@
<!-- Filesystem synchronization support -->
<fssync:adapter
- class=".configuration.ConfigurationManager"
+ class=".registration.RegistrationManager"
factory="zope.app.content.fssync.DirectoryAdapter"
/>
@@ -488,7 +499,65 @@
<fssync:adapter
class=".service.ServiceManager"
- factory="zope.app.content.fssync.DirectoryAdapter"
+ factory=".service.ServiceManagerAdapter"
+ />
+
+<fssync:adapter
+ class=".pagefolder.PageFolder"
+ factory=".pagefolder.PageFolderAdapter"
+ />
+
+<fssync:adapter
+ class=".zpt.ZPTTemplate"
+ factory=".zpt.ZPTPageAdapter"
+ />
+
+<fssync:adapter
+ class=".module.Manager"
+ factory=".module.ModuleAdapter"
+ />
+
+<fssync:adapter
+ class=".cache.CacheRegistration"
+ factory=".registration.ComponentRegistrationAdapter"
/>
+
+<fssync:adapter
+ class=".connection.ConnectionRegistration"
+ factory=".registration.ComponentRegistrationAdapter"
+ />
+
+<fssync:adapter
+ class=".service.ServiceRegistration"
+ factory=".registration.ComponentRegistrationAdapter"
+ />
+
+<fssync:adapter
+ class=".utility.UtilityRegistration"
+ factory=".registration.ComponentRegistrationAdapter"
+ />
+
+<adapter
+ for="zope.app.interfaces.services.service.IServiceManager"
+ provides="zope.app.interfaces.file.IDirectoryFactory"
+ factory=".folder.SMFolderFactory"
+ permission="zope.ManageContent"
+ />
+
+<adapter
+ for="zope.app.interfaces.services.folder.ISiteManagementFolder"
+ provides="zope.app.interfaces.file.IDirectoryFactory"
+ factory=".pagefolder.PageFolderFactory"
+ permission="zope.ManageContent"
+ />
+
+<adapter
+ for="zope.app.interfaces.services.folder.ISiteManagementFolder"
+ provides="zope.app.interfaces.file.IFileFactory"
+ name=".py"
+ factory=".module.ModuleFactory"
+ permission="zope.ManageContent"
+ />
+
</zopeConfigure>
=== Zope3/src/zope/app/services/connection.py 1.11 => 1.11.10.1 ===
--- Zope3/src/zope/app/services/connection.py:1.11 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/connection.py Sun Jun 22 10:23:27 2003
@@ -16,20 +16,21 @@
"""
from persistence import Persistent
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
from zope.app.interfaces.rdb import IZopeDatabaseAdapter
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.configuration import NameComponentConfigurable
+from zope.app.services.registration import NameComponentRegistry
+from zope.interface import implements
-class ConnectionService(Persistent, NameComponentConfigurable):
+class ConnectionService(Persistent, NameComponentRegistry):
__doc__ = ILocalConnectionService.__doc__
- __implements__ = ILocalConnectionService, ISimpleService
+ implements(ILocalConnectionService, ISimpleService)
def getConnection(self, name):
'See IConnectionService'
@@ -55,8 +56,8 @@
def getAvailableConnections(self):
'See IConnectionService'
connections = {}
- for name in self.listConfigurationNames():
- registry = self.queryConfigurations(name)
+ for name in self.listRegistrationNames():
+ registry = self.queryRegistrations(name)
if registry.active() is not None:
connections[name] = 0
service = queryNextService(self, "SQLDatabaseConnections")
@@ -72,20 +73,25 @@
getAvailableConnections = ContextMethod(getAvailableConnections)
-from zope.app.interfaces.services.connection import IConnectionConfiguration
-from zope.app.services.configuration import NamedComponentConfiguration
-from zope.app.services.configuration import ConfigurationStatusProperty
+from zope.app.interfaces.services.connection import IConnectionRegistration
+from zope.app.services.registration import NamedComponentRegistration
+from zope.app.services.registration import RegistrationStatusProperty
-class ConnectionConfiguration(NamedComponentConfiguration):
+class ConnectionRegistration(NamedComponentRegistration):
- __doc__ = IConnectionConfiguration.__doc__
+ __doc__ = IConnectionRegistration.__doc__
- __implements__ = (IConnectionConfiguration,
- NamedComponentConfiguration.__implements__)
+ implements(IConnectionRegistration)
- status = ConfigurationStatusProperty('SQLDatabaseConnections')
+ serviceType = 'SQLDatabaseConnections'
+
+ status = RegistrationStatusProperty()
label = "Connection"
def getInterface(self):
return IZopeDatabaseAdapter
+
+
+# XXX Pickle backward compatability
+ConnectionConfiguration = ConnectionRegistration
=== Zope3/src/zope/app/services/errorr.py 1.8 => 1.8.18.1 ===
--- Zope3/src/zope/app/services/errorr.py:1.8 Tue Mar 11 11:11:22 2003
+++ Zope3/src/zope/app/services/errorr.py Sun Jun 22 10:23:27 2003
@@ -24,9 +24,10 @@
from types import StringTypes
import logging
from zope.exceptions.exceptionformatter import format_exception
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
from zope.app.interfaces.services.error import IErrorReportingService
from zope.app.interfaces.services.service import ISimpleService
+from zope.interface import implements
#Restrict the rate at which errors are sent to the Event Log
@@ -49,7 +50,7 @@
class ErrorReportingService(Persistent):
"""Error Reporting Service
"""
- __implements__ = IErrorReportingService, ISimpleService
+ implements(IErrorReportingService, ISimpleService)
keep_entries = 20
copy_to_zlog = 0
=== Zope3/src/zope/app/services/event.py 1.24 => 1.24.4.1 ===
--- Zope3/src/zope/app/services/event.py:1.24 Mon May 12 12:31:50 2003
+++ Zope3/src/zope/app/services/event.py Sun Jun 22 10:23:27 2003
@@ -31,8 +31,9 @@
from zope.app.services.servicenames import EventSubscription
from zope.app.component.nextservice import getNextService, queryNextService
-from zope.proxy.context import ContextMethod, ContextSuper
-from zope.proxy.introspection import removeAllProxies
+from zope.context import ContextMethod, ContextSuper
+from zope.proxy import removeAllProxies
+from zope.interface import implements
from zope.app.event.subs import Subscribable, SubscriptionTracker
@@ -61,11 +62,12 @@
return getSubscriptionService(context).unsubscribe(
subscriber, event_type, filter)
-def unsubscribeAll(subscriber, event_type=IEvent, context=None):
+def unsubscribeAll(subscriber, event_type=IEvent, context=None,
+ local_only=False):
if context is None and not isinstance(subscriber, (int, str, unicode)):
context = subscriber
return getSubscriptionService(context).unsubscribeAll(
- subscriber, event_type)
+ subscriber, event_type, local_only=local_only)
def iterSubscriptions(subscriber=None, event_type=None, local_only=False,
context=None):
@@ -77,7 +79,7 @@
class EventChannel(Subscribable):
- __implements__ = IEventChannel
+ implements(IEventChannel)
# needs __init__ from zope.app.event.subs.Subscribable
@@ -139,11 +141,7 @@
event service when bound, and unsubscribe when unbound.
"""
- __implements__ = (
- EventChannel.__implements__,
- SubscriptionTracker.__implements__,
- IBindingAware
- )
+ implements(IBindingAware)
def __init__(self):
SubscriptionTracker.__init__(self)
@@ -210,16 +208,35 @@
# unsubscribe all subscriptions
hubIds = clean_self._hubIds
unsubscribeAll = wrapped_self.unsubscribeAll
+
+ # XXX Temporary hack to make unsubscriptions local in scope when
+ # this mix-in is used as part of a subscriptions service.
+ # The dependences of these mixins need to be documented and
+ # reevaluated.
+ if ISubscriptionService.isImplementedBy(wrapped_self):
+ real_unsubscribeAll = unsubscribeAll
+ unsubscribeAll = lambda x: real_unsubscribeAll(x, local_only=True)
+
try:
clean_self._v_ssecunbinding = True
while hubIds:
hubId = iter(hubIds).next()
- unsubscribeAll(hubId, local_only=True)
+ # XXX This code path needs a unit test!
+ # This code is also wrong.
+ # The call to unsubscribeAll assumes that whatever class
+ # mixes this class in provides an unsubscribeAll method
+ # that correctly uses the self._subscribeToServiceName
+ # to decide what it should be unsubscribing from.
+ # This could be any service that implements
+ # ISubscriptionService
+ unsubscribeAll(hubId)
paths = clean_self._paths
while paths:
path = iter(paths).next()
- unsubscribeAll(path, local_only=True)
+ # XXX This code path needs a unit test!
+ # Also, see comment above.
+ unsubscribeAll(path)
finally:
del clean_self._v_ssecunbinding
@@ -241,8 +258,6 @@
those of the next higher service.
"""
- __implements__ = Subscribable.__implements__
-
_serviceName = None # should be replaced; usually done in "bound"
# method of a subclass that is IBindingAware
@@ -318,13 +333,7 @@
class EventService(ServiceSubscriberEventChannel, ServiceSubscribable):
- __implements__ = (
- IEventService,
- ISubscriptionService,
- ISimpleService,
- ServiceSubscribable.__implements__,
- ServiceSubscriberEventChannel.__implements__
- )
+ implements(IEventService, ISubscriptionService, ISimpleService)
def __init__(self):
ServiceSubscriberEventChannel.__init__(self)
=== Zope3/src/zope/app/services/field.py 1.7 => 1.7.18.1 ===
--- Zope3/src/zope/app/services/field.py:1.7 Thu Mar 13 12:10:37 2003
+++ Zope3/src/zope/app/services/field.py Sun Jun 22 10:23:27 2003
@@ -25,10 +25,11 @@
from zope.app.interfaces.services.field import IComponentLocation
from zope.component import getServiceManager, getAdapter
from zope.app.interfaces.services.module import IModuleService
+from zope.interface import implements
class ComponentPath(Field):
- __implements__ = IComponentPath
+ implements(IComponentPath)
_type = unicode
@@ -52,7 +53,7 @@
class ComponentLocation(Field):
- __implements__ = IComponentLocation
+ implements(IComponentLocation)
_type = unicode
=== Zope3/src/zope/app/services/folder.py 1.6 => 1.6.10.1 ===
--- Zope3/src/zope/app/services/folder.py:1.6 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/folder.py Sun Jun 22 10:23:27 2003
@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""A package contains components and component configurations.
+"""A package contains components and component registrations.
$Id$
"""
@@ -23,16 +23,19 @@
from zope.app.interfaces.services.folder import ISiteManagementFolders
from zope.app.interfaces.services.folder import ISiteManagementFolder
from zope.app.interfaces.services.service import IComponentManager
-from zope.app.services.configuration import ConfigurationManagerContainer
+from zope.app.interfaces.file import IDirectoryFactory
+from zope.app.services.registration import RegistrationManagerContainer
from zope.app.traversing import getPath
-from zope.proxy.context import ContextMethod, ContextWrapper
+from zope.app.context import ContextWrapper
+from zope.context import ContextMethod
+from zope.interface import implements
-class SiteManagementFolder(ConfigurationManagerContainer, BTreeContainer):
- __implements__ = ISiteManagementFolder
+class SiteManagementFolder(RegistrationManagerContainer, BTreeContainer):
+ implements(ISiteManagementFolder)
class SiteManagementFolders(BTreeContainer):
- __implements__ = ISiteManagementFolders
+ implements(ISiteManagementFolders)
def __init__(self):
super(SiteManagementFolders, self).__init__()
@@ -69,6 +72,16 @@
if not ISiteManagementFolder.isImplementedBy(obj):
raise TypeError("Can only add packages")
return super(SiteManagementFolders, self).setObject(name, obj)
+
+class SMFolderFactory(object):
+
+ implements(IDirectoryFactory)
+
+ def __init__(self, context):
+ self.context = context
+
+ def __call__(self, name):
+ return SiteManagementFolder()
# XXX Backward compatability. This is needed to support old pickles.
Package = SiteManagementFolder
=== Zope3/src/zope/app/services/hub.py 1.10 => 1.10.10.1 ===
--- Zope3/src/zope/app/services/hub.py:1.10 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/hub.py Sun Jun 22 10:23:27 2003
@@ -29,8 +29,8 @@
from zope.component import getAdapter
from zope.exceptions import NotFoundError
-from zope.proxy.context import ContextMethod
-from zope.proxy.introspection import removeAllProxies
+from zope.context import ContextMethod
+from zope.proxy import removeAllProxies
from zope.app.interfaces.traversing import ITraverser
from zope.app.interfaces.event import IObjectRemovedEvent, IObjectEvent
@@ -45,6 +45,7 @@
from zope.app.interfaces.services.hub import IObjectRemovedHubEvent
from zope.app.interfaces.traversing import ITraverser
from zope.app.interfaces.services.service import ISimpleService
+from zope.interface import implements
class HubEvent:
"""Convenient mix-in for HubEvents"""
@@ -83,7 +84,7 @@
class ObjectRegisteredHubEvent(HubEvent):
"""A hubid has been freshly created and mapped against an object."""
- __implements__ = IObjectRegisteredHubEvent
+ implements(IObjectRegisteredHubEvent)
class ObjectUnregisteredHubEvent:
@@ -103,7 +104,7 @@
self.__object = object
self.location = location
- __implements__ = IObjectUnregisteredHubEvent
+ implements(IObjectUnregisteredHubEvent)
def __getObject(self):
obj = self.__object
@@ -118,7 +119,7 @@
class ObjectModifiedHubEvent(HubEvent):
"""An object with a hubid has been modified."""
- __implements__ = IObjectModifiedHubEvent
+ implements(IObjectModifiedHubEvent)
class ObjectMovedHubEvent(HubEvent):
@@ -129,13 +130,13 @@
self.fromLocation = fromLocation
HubEvent.__init__(self, hub, hubid, location, object)
- __implements__ = IObjectMovedHubEvent
+ implements(IObjectMovedHubEvent)
class ObjectRemovedHubEvent(ObjectUnregisteredHubEvent):
"""An object with a hubid has been removed."""
- __implements__ = IObjectRemovedHubEvent
+ implements(IObjectRemovedHubEvent)
# ...which is a subclass of IObjectUnregisteredHubEvent
hub = None
@@ -171,10 +172,7 @@
# concerned, and if it doesn't know how to do something, it won't
# ask anything else to try. Everything else is YAGNI for now.
- __implements__ = (
- IObjectHub,
- ISimpleService,
- ServiceSubscriberEventChannel.__implements__)
+ implements(IObjectHub, ISimpleService)
def __init__(self):
ServiceSubscriberEventChannel.__init__(self)
@@ -277,11 +275,6 @@
path = getPath(path_or_object)
pathslash = canonicalSlash(path)
-
- # XXX This check should be done by canonicalPath, but Albert is still
- # refactoring that. So, I'll do it here for now.
- if not pathslash.startswith(u'/'):
- raise ValueError('Path must be absolute, not relative:', path)
path_to_hubid = clean_self.__path_to_hubid
if path_to_hubid.has_key(pathslash):
=== Zope3/src/zope/app/services/module.py 1.2 => 1.2.26.1 ===
--- Zope3/src/zope/app/services/module.py:1.2 Wed Dec 25 09:13:19 2002
+++ Zope3/src/zope/app/services/module.py Sun Jun 22 10:23:27 2003
@@ -19,43 +19,66 @@
from persistence import Persistent
from zodb.code.module import PersistentModuleManager
from zodb.code.interfaces import IPersistentModuleManager
+from zodb.code.interfaces import IPersistentModuleImportRegistry
+from zodb.code.interfaces import IPersistentModuleUpdateRegistry
from zope.component import getServiceManager
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
-class Registry:
+from zope.interface import implements
- # The registry is found via context, but the PersistentModuleManager
- # doesn't know about context. To make it behave contextually, this
- # Registry class collaborates with Manager to delegate to the
- # registry found via context.
+from zope.app.fssync.classes import ObjectEntryAdapter, AttrMapping
+from zope.app.interfaces.fssync import IObjectFile
+from zope.app.interfaces.file import IFileFactory
+from zope.app.interfaces.container import IDeleteNotifiable
+from zope.app.context import ContextWrapper
+
+
+class Registry(Persistent):
+
+ # This is a wrapper around the module service, which is actually
+ # the service manager. The service manager is found via context,
+ # but the PersistentModuleManager doesn't know about context. To
+ # make it behave contextually, this Registry class collaborates
+ # with the Manager class below to delegate to the registry found
+ # via context.
+
+ implements(IPersistentModuleImportRegistry,
+ IPersistentModuleUpdateRegistry)
def __init__(self):
- self._v_manager = None
+ self._v_module_service = None
+
+ def setModuleService(self, ms):
+ # This method is called by methods of Manager below
+ self._v_module_service = ms
- def setManager(self, ctx):
- self._v_manager = ctx
+ # The next three methods are called by the persistent module manager
def findModule(self, name):
- return self._v_manager.findModule(name)
+ return self._v_module_service.findModule(name)
def setModule(self, name, module):
- return self._v_manager.setModule(name, module)
+ return self._v_module_service.setModule(name, module)
def delModule(self, name):
- return self._v_manager.delModule(name)
+ return self._v_module_service.delModule(name)
+
+ def __getstate__(self):
+ # So pickling this object doesn't include the module service
+ return {}
class Manager(Persistent):
- __implements__ = IPersistentModuleManager
+ implements(IPersistentModuleManager, IDeleteNotifiable)
# The registry for the manager is the ServiceManager.
# The association between this manager and the registry
# is static, but the static association can't be stored
# explicitly in Zope.
- # XXX There is no locking, but every call to setManager() for a
- # particular instance should have the same manager argument.
+ # XXX There is no locking, but every call to setModuleService()
+ # for a particular instance should have the same manager argument.
# XXX It would be nice if the lookup via getServiceManager()
# occurred less often. Best would be to do it only when the
@@ -66,16 +89,16 @@
self._manager = PersistentModuleManager(self._registry)
def new(self, name, source):
- self._registry.setManager(getServiceManager(self))
+ self._registry.setModuleService(getServiceManager(self))
self._manager.new(name, source)
def update(self, source):
- self._registry.setManager(getServiceManager(self))
+ self._registry.setModuleService(getServiceManager(self))
self._manager.update(source)
- def remove(self, source):
- self._registry.setManager(getServiceManager(self))
- self._manager.remove(source)
+ def remove(self):
+ self._registry.setModuleService(getServiceManager(self))
+ self._manager.remove()
new = ContextMethod(new)
update = ContextMethod(update)
@@ -83,3 +106,37 @@
name = property(lambda self: self._manager.name)
source = property(lambda self: self._manager.source)
+
+ def beforeDeleteHook(self, obj, container):
+ obj.remove()
+ beforeDeleteHook = ContextMethod(beforeDeleteHook)
+
+
+class ModuleAdapter(ObjectEntryAdapter):
+
+ implements(IObjectFile)
+
+ def getBody(self):
+ return self.context.source
+
+ def setBody(self, source):
+ self.context.update(source)
+
+ def extra(self):
+ return AttrMapping(self.context, ("name",))
+
+
+class ModuleFactory(object):
+
+ implements(IFileFactory)
+
+ def __init__(self, context):
+ self.context = context
+
+ def __call__(self, name, content_type, data):
+ assert name.endswith(".py")
+ name = name[:-3]
+ m = Manager()
+ m = ContextWrapper(m, self.context)
+ m.new(name, data)
+ return m
=== Zope3/src/zope/app/services/pagefolder.py 1.5 => 1.5.10.1 ===
--- Zope3/src/zope/app/services/pagefolder.py:1.5 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/pagefolder.py Sun Jun 22 10:23:27 2003
@@ -13,7 +13,7 @@
##############################################################################
"""Page Folders
-Page folders support easy creation and configuration of page views
+Page folders support easy creation and registration of page views
using folders of templates.
$Id$
@@ -21,20 +21,26 @@
__metaclass__ = type
from zope.app.container.btree import BTreeContainer
+from zope.app.container.zopecontainer import ZopeContainerDecorator
from zope.app.interfaces.services.view import IZPTTemplate
from zope.publisher.interfaces.browser import IBrowserPresentation
from zope.app.traversing import getPath
-from zope.proxy.context import getItem, ContextMethod
-from zope.app.interfaces.services.configuration import Active
-from zope.app.services.configuration import ConfigurationManagerContainer
-from zope.proxy.introspection import removeAllProxies
-from zope.app.services.view import PageConfiguration
+from zope.app.context import getItem
+from zope.context import ContextMethod
+from zope.app.interfaces.services.registration import ActiveStatus
+from zope.app.services.registration import RegistrationManagerContainer
+from zope.proxy import removeAllProxies
+from zope.app.services.view import PageRegistration
from zope.app.interfaces.services.pagefolder import IPageFolder
-from zope.app.interfaces.services.configuration import IConfigurationManager
+from zope.app.interfaces.services.registration import IRegistrationManager
+from zope.app.interfaces.file import IDirectoryFactory
+from zope.app.fssync.classes import ObjectEntryAdapter, AttrMapping
+from zope.app.interfaces.fssync import IObjectDirectory
+from zope.interface import implements
-class PageFolder(ConfigurationManagerContainer, BTreeContainer):
+class PageFolder(RegistrationManagerContainer, BTreeContainer):
- __implements__ = IPageFolder
+ implements(IPageFolder)
presentationType = IBrowserPresentation
layer = "default"
@@ -45,45 +51,76 @@
template = None
def setObject(self, name, object):
- if IConfigurationManager.isImplementedBy(object):
- # We allow configuration managers as well as templates
+ if (IRegistrationManager.isImplementedBy(object) or
+ IZPTTemplate.isImplementedBy(object)):
return super(PageFolder, self).setObject(name, object)
-
- if not IZPTTemplate.isImplementedBy(object):
+ else:
raise TypeError("Can only add templates", object)
- # super() does not work on a context wrapped instance
- base = removeAllProxies(self)
-
- name = super(PageFolder, base).setObject(name, object)
- template = getItem(self, name)
- template = getPath(template)
- config = PageConfiguration(
- forInterface=self.forInterface,
- viewName=name,
- permission=self.permission,
- class_=self.factoryName,
- template=template,
- layer=self.layer,
- )
- configure = self.getConfigurationManager()
- id = configure.setObject('', config)
- config = getItem(configure, id)
- config.status = Active
- return name
-
- setObject = ContextMethod(setObject)
-
def configured(self):
return (hasattr(self, 'permission')
and hasattr(self, 'forInterface')
)
def activated(self):
- "See IConfiguration"
+ "See IRegistration"
def deactivated(self):
- "See IConfiguration"
+ "See IRegistration"
+
+
+_attrNames = (
+ 'factoryName',
+ 'forInterface',
+ 'layer',
+ 'permission',
+ )
+
+class PageFolderAdapter(ObjectEntryAdapter):
+ """ObjectFile adapter for PageFolder objects."""
+
+ implements(IObjectDirectory)
+
+ def contents(self):
+ return self.context.items()
+
+ def extra(self):
+ return AttrMapping(self.context, _attrNames)
+
+
+class PageFolderFactory:
+
+ implements(IDirectoryFactory)
+
+ def __init__(self, context):
+ self.context = context
+
+ def __call__(self, name):
+ return PageFolder()
+
+class PageFolderContextDecorator(ZopeContainerDecorator):
+
+ def setObject(self, name, object):
+ name = super(PageFolderContextDecorator, self).setObject(name, object)
+
+ # If a template is added, we need to configure it too.
+ if IZPTTemplate.isImplementedBy(object):
+ template = getItem(self, name)
+ template = getPath(template)
+ config = PageRegistration(
+ forInterface=self.forInterface,
+ viewName=name,
+ permission=self.permission,
+ class_=self.factoryName,
+ template=template,
+ layer=self.layer,
+ )
+ configure = self.getRegistrationManager()
+ id = configure.setObject('', config)
+ config = getItem(configure, id)
+ config.status = ActiveStatus
+ return name
+
# XXX Backward compatibility. This is needed to support old pickles.
ViewPackage = PageFolder
=== Zope3/src/zope/app/services/principalannotation.py 1.5 => 1.5.14.1 ===
--- Zope3/src/zope/app/services/principalannotation.py:1.5 Tue Apr 8 13:43:43 2003
+++ Zope3/src/zope/app/services/principalannotation.py Sun Jun 22 10:23:27 2003
@@ -20,14 +20,17 @@
# Zope3 imports
from persistence import Persistent
+from persistence.dict import PersistentDict
from zodb.btrees.OOBTree import OOBTree
-from zope.app.component.nextservice import getNextService
-from zope.proxy.context import ContextMethod
-from zope.proxy.context import ContextWrapper
+from zope.app.component.nextservice import queryNextService
+from zope.context import ContextMethod
+from zope.app.context import ContextWrapper
from zope.app.interfaces.annotation import IAnnotations
+from zope.interface import implements
# Sibling imports
-from zope.app.interfaces.services.principalannotation import IPrincipalAnnotationService
+from zope.app.interfaces.services.principalannotation \
+ import IPrincipalAnnotationService
from zope.app.interfaces.services.service import ISimpleService
class PrincipalAnnotationService(Persistent):
@@ -36,8 +39,7 @@
The service ID is 'PrincipalAnnotation'.
"""
- __implements__ = (IPrincipalAnnotationService, Persistent.__implements__,
- ISimpleService)
+ implements(IPrincipalAnnotationService, ISimpleService)
def __init__(self):
self.annotations = OOBTree()
@@ -45,54 +47,76 @@
# implementation of IPrincipalAnnotationService
- def getAnnotation(self, principalId):
+ def getAnnotations(self, principal):
"""Return object implementing IAnnotations for the given principal.
If there is no IAnnotations it will be created and then returned.
"""
- if not self.annotations.has_key(principalId):
- self.annotations[principalId] = Annotations(principalId)
- return ContextWrapper(self.annotations[principalId], self, name=principalId)
- getAnnotation = ContextMethod(getAnnotation)
+ return self.getAnnotationsById(principal.getId())
+ getAnnotations = ContextMethod(getAnnotations)
- def hasAnnotation(self, principalId):
+ def getAnnotationsById(self, principalId):
+ """Return object implementing IAnnotations for the given principal.
+
+ If there is no IAnnotations it will be created and then returned.
+ """
+
+ annotations = self.annotations.get(principalId)
+ if annotations is None:
+ annotations = Annotations(principalId, store=self.annotations)
+
+ return ContextWrapper(annotations, self, name=principalId)
+
+ getAnnotationsById = ContextMethod(getAnnotationsById)
+
+ def hasAnnotations(self, principal):
"""Return boolean indicating if given principal has IAnnotations."""
- return self.annotations.has_key(principalId)
+ return principal.getId() in self.annotations
class Annotations(Persistent):
"""Stores annotations."""
- __implements__ = IAnnotations, Persistent.__implements__
+ implements(IAnnotations)
- def __init__(self, principalId):
+ def __init__(self, principalId, store=None):
self.principalId = principalId
- self.data = OOBTree()
+ self.data = PersistentDict() # We don't really expect that many
+
+ # _v_store is used to remember a mapping object that we should
+ # be saved in if we ever change
+ self._v_store = store
def __getitem__(wrapped_self, key):
try:
return wrapped_self.data[key]
except KeyError:
# We failed locally: delegate to a higher-level service.
- service = getNextService(wrapped_self, 'PrincipalAnnotation')
- if service:
- return service.getAnnotation(wrapped_self.principalId)[key]
+ service = queryNextService(wrapped_self, 'PrincipalAnnotation')
+ if service is not None:
+ annotations = service.getAnnotationsById(
+ wrapped_self.principalId)
+ return annotations[key]
raise
__getitem__ = ContextMethod(__getitem__)
def __setitem__(self, key, value):
+
+ if getattr(self, '_v_store', None) is not None:
+ # _v_store is used to remember a mapping object that we should
+ # be saved in if we ever change
+ self._v_store[self.principalId] = self
+ del self._v_store
+
self.data[key] = value
def __delitem__(self, key):
del self.data[key]
def get(self, key, default=None):
- try:
- return self.data[key]
- except KeyError:
- return default
+ return self.data.get(key, default)
class AnnotationsForPrincipal(object):
@@ -105,4 +129,4 @@
self.service = service
def __call__(self, principal):
- return self.service.getAnnotation(principal.getId())
+ return self.service.getAnnotationsById(principal.getId())
=== Zope3/src/zope/app/services/queryfield.py 1.2 => 1.2.22.1 ===
--- Zope3/src/zope/app/services/queryfield.py:1.2 Tue Feb 11 10:59:56 2003
+++ Zope3/src/zope/app/services/queryfield.py Sun Jun 22 10:23:27 2003
@@ -19,7 +19,7 @@
from zope.schema import Tuple
from zope.schema.interfaces import ValidationError
from zope.component import getAdapter
-from zope.interface.implements import implements
+from zope.interface import classImplements
# See end of file for further imports
class QueryProcessorsField(Tuple):
@@ -48,5 +48,5 @@
from zope.app.interfaces.services.query import IQueryProcessorsField
from zope.app.interfaces.services.query import IQueryProcessable
from zope.app.interfaces.services.query import IQueryProcessor
-implements(QueryProcessorsField, IQueryProcessorsField)
+classImplements(QueryProcessorsField, IQueryProcessorsField)
=== Zope3/src/zope/app/services/role.py 1.4 => 1.4.18.1 ===
--- Zope3/src/zope/app/services/role.py:1.4 Tue Mar 11 11:11:22 2003
+++ Zope3/src/zope/app/services/role.py Sun Jun 22 10:23:27 2003
@@ -22,9 +22,10 @@
from zope.app.container.btree import BTreeContainer
from zope.app.interfaces.security import IRoleService
from zope.app.interfaces.container import IContainer
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
from zope.app.component.nextservice import getNextService
from zope.app.interfaces.services.service import ISimpleService
+from zope.interface import implements
class Role(Role, Persistent):
"Persistent Role"
@@ -34,7 +35,7 @@
class RoleService(BTreeContainer):
- __implements__ = ILocalRoleService, ISimpleService
+ implements(ILocalRoleService, ISimpleService)
def getRole(wrapped_self, rid):
'''See interface IRoleService'''
=== Zope3/src/zope/app/services/service.py 1.18 => 1.18.10.1 ===
--- Zope3/src/zope/app/services/service.py:1.18 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/service.py Sun Jun 22 10:23:27 2003
@@ -31,12 +31,14 @@
from zodb.code.module import PersistentModule
from zodb.code.module import PersistentModuleRegistry
+from zope.interface import implements
+
from zope.component import getServiceManager
from zope.component.exceptions import ComponentLookupError
-from zope.proxy.context import ContextMethod
-from zope.proxy.context import ContextWrapper
-from zope.proxy.introspection import removeAllProxies
+from zope.context import ContextMethod
+from zope.app.context import ContextWrapper
+from zope.proxy import removeAllProxies
from zope.app.component.nextservice import getNextService
from zope.app.component.nextservice import getNextServiceManager
@@ -44,30 +46,28 @@
from zope.app.interfaces.container import IContainer
from zope.app.interfaces.services.service import IBindingAware
from zope.app.interfaces.services.module import IModuleService
-from zope.app.interfaces.services.service import IServiceConfiguration
+from zope.app.interfaces.services.service import IServiceRegistration
from zope.app.interfaces.services.service import IServiceManager
-# XXX This makes no sense?
+# Declare a tuple of all types we consider to be modules
+# (used as 2nd argument to isinstance() in method resolve() below)
ModuleType = type(IModuleService), PersistentModule
-from zope.app.services.configuration import ConfigurationStatusProperty
-from zope.app.services.configuration import NameComponentConfigurable
-from zope.app.services.configuration import NamedComponentConfiguration
+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
from zope.app.interfaces.services.service import ILocalService
from zope.app.traversing import getPath
-class ServiceManager(PersistentModuleRegistry, NameComponentConfigurable):
+class ServiceManager(PersistentModuleRegistry, NameComponentRegistry):
- __implements__ = (IServiceManager, IContainer,
- PersistentModuleRegistry.__implements__,
- NameComponentConfigurable.__implements__,
- IModuleService)
+ implements(IServiceManager, IContainer, IModuleService)
def __init__(self):
- super(ServiceManager, self).__init__()
- NameComponentConfigurable.__init__(self)
+ PersistentModuleRegistry.__init__(self)
+ NameComponentRegistry.__init__(self)
self.Packages = SiteManagementFolders()
def getServiceDefinitions(wrapped_self):
@@ -231,6 +231,9 @@
def setObject(self, name, value):
return self.Packages.setObject(name, value)
+ def __delitem__(self, key):
+ return self.Packages.__delitem__(key)
+
def findModule(wrapped_self, name):
# override to pass call up to next service manager
mod = super(ServiceManager,
@@ -292,19 +295,20 @@
resolve = ContextMethod(resolve)
-class ServiceConfiguration(NamedComponentConfiguration):
+class ServiceRegistration(NamedComponentRegistration):
+
+ __doc__ = IServiceRegistration.__doc__
- __doc__ = IServiceConfiguration.__doc__
+ implements(IServiceRegistration)
- __implements__ = (IServiceConfiguration,
- NamedComponentConfiguration.__implements__)
+ serviceType = 'Services'
- status = ConfigurationStatusProperty('Services')
+ status = RegistrationStatusProperty()
label = "Service"
def __init__(self, name, path, context=None):
- super(ServiceConfiguration, self).__init__(name, path)
+ super(ServiceRegistration, self).__init__(name, path)
if context is not None:
# Check that the object implements stuff we need
wrapped_self = ContextWrapper(self, context)
@@ -336,3 +340,23 @@
def usageSummary(self):
return self.name + " Service"
+
+
+# XXX Pickle backward compatability
+ServiceConfiguration = ServiceRegistration
+
+# Fssync stuff
+
+from zope.app.fssync.classes import AttrMapping
+from zope.app.content.fssync import DirectoryAdapter
+
+_smattrs = (
+ '_modules', # PersistentModuleRegistry
+ '_bindings', # NameComponentRegistry
+)
+
+class ServiceManagerAdapter(DirectoryAdapter):
+
+ def extra(self):
+ obj = removeAllProxies(self.context)
+ return AttrMapping(obj, _smattrs)
=== Zope3/src/zope/app/services/servicecontainer.py 1.2 => 1.2.24.1 ===
--- Zope3/src/zope/app/services/servicecontainer.py:1.2 Tue Feb 4 05:30:07 2003
+++ Zope3/src/zope/app/services/servicecontainer.py Sun Jun 22 10:23:27 2003
@@ -11,38 +11,45 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
+"""ServiceManagerContainer implementation.
+
+$Id$
+"""
from zope.component.exceptions import ComponentLookupError
-from zope.app.interfaces.services.service import IServiceManagerContainer
+from zope.app.interfaces.services.service import IServiceManagerContainer
from zope.component.interfaces import IServiceService
+from zope.interface import implements
class ServiceManagerContainer:
- __implements__ = IServiceManagerContainer
+ """Implement access to the service manager (++etc++site).
+
+ This is a mix-in that implements the IServiceManagerContainer
+ interface; for example, it is used by the Folder implementation.
+ """
+
+ implements(IServiceManagerContainer)
+
+ __sm = None
def hasServiceManager(self):
- '''See interface IReadServiceManagerContainer'''
- return hasattr(self, '_ServiceManagerContainer__sm')
+ return self.__sm is not None
def getServiceManager(self):
- '''See interface IReadServiceManagerContainer'''
-
- try:
+ if self.__sm is not None:
return self.__sm
- except AttributeError:
+ else:
raise ComponentLookupError('no service manager defined')
def queryServiceManager(self, default=None):
- '''See interface IReadServiceManagerContainer'''
-
- return getattr(self, '_ServiceManagerContainer__sm', default)
+ if self.__sm is not None:
+ return self.__sm
+ else:
+ return default
def setServiceManager(self, sm):
- '''See interface IWriteServiceManagerContainer'''
-
if IServiceService.isImplementedBy(sm):
self.__sm = sm
else:
raise ValueError('setServiceManager requires an IServiceService')
-
-
=== Zope3/src/zope/app/services/session.py 1.9 => 1.9.18.1 ===
--- Zope3/src/zope/app/services/session.py:1.9 Tue Mar 11 11:11:22 2003
+++ Zope3/src/zope/app/services/session.py Sun Jun 22 10:23:27 2003
@@ -26,6 +26,7 @@
from persistence.dict import PersistentDict
from zope.server.http.http_date import build_http_date
from zope.component import getService
+from zope.interface import implements
# Sibling imports
from zope.app.interfaces.services.session import ISessionService
@@ -43,8 +44,7 @@
class CookieSessionService(Persistent):
"""Session service implemented using cookies."""
- __implements__ = (Persistent.__implements__, ISessionService,
- IConfigureSessionService, ISimpleService)
+ implements(ISessionService, IConfigureSessionService, ISimpleService)
def __init__(self):
self.dataManagers = PersistentDict()
=== Zope3/src/zope/app/services/utility.py 1.6 => 1.6.10.1 ===
--- Zope3/src/zope/app/services/utility.py:1.6 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/utility.py Sun Jun 22 10:23:27 2003
@@ -17,24 +17,25 @@
$Id$
"""
+from zope.interface import implements
from persistence.dict import PersistentDict
from persistence import Persistent
from zope.app.component.nextservice import getNextService
-from zope.app.interfaces.services.configuration import IConfigurable
+from zope.app.interfaces.services.registration import IRegistry
from zope.app.interfaces.services.service import ISimpleService
-from zope.app.interfaces.services.utility import IUtilityConfiguration
+from zope.app.interfaces.services.utility import IUtilityRegistration
from zope.app.interfaces.services.utility import ILocalUtilityService
-from zope.app.services.configuration import ConfigurationRegistry
-from zope.app.services.configuration import ConfigurationStatusProperty
-from zope.app.services.configuration import ComponentConfiguration
+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
-from zope.proxy.context import ContextAware
-from zope.proxy.context import ContextWrapper
+from zope.context import ContextMethod
+from zope.app.context import ContextWrapper
-class LocalUtilityService(Persistent, ContextAware):
+class LocalUtilityService(Persistent):
- __implements__ = ILocalUtilityService, IConfigurable, ISimpleService
+ implements(ILocalUtilityService, IRegistry, ISimpleService)
def __init__(self):
self._utilities = PersistentDict()
@@ -44,48 +45,55 @@
if utility is None:
raise ComponentLookupError("utility", interface, name)
return utility
+ getUtility = ContextMethod(getUtility)
def queryUtility(self, interface, default=None, name=''):
- registry = self.queryConfigurations(name, interface)
- if registry is not None:
- configuration = registry.active()
- if configuration is not None:
- return configuration.getComponent()
+ stack = self.queryRegistrations(name, interface)
+ if stack is not None:
+ registration = stack.active()
+ if registration is not None:
+ return registration.getComponent()
next = getNextService(self, "Utilities")
return next.queryUtility(interface, default, name)
+ queryUtility = ContextMethod(queryUtility)
- def queryConfigurationsFor(self, configuration, default=None):
- return self.queryConfigurations(configuration.name,
- configuration.interface,
+ def queryRegistrationsFor(self, registration, default=None):
+ return self.queryRegistrations(registration.name,
+ registration.interface,
default)
+ queryRegistrationsFor = ContextMethod(queryRegistrationsFor)
- def queryConfigurations(self, name, interface, default=None):
+ def queryRegistrations(self, name, interface, default=None):
utilities = self._utilities.get(name)
if utilities is None:
return default
- registry = utilities.getRegistered(interface)
- if registry is None:
+ stack = utilities.getRegistered(interface)
+ if stack is None:
return default
- return ContextWrapper(registry, self)
+ return ContextWrapper(stack, self)
+ queryRegistrations = ContextMethod(queryRegistrations)
- def createConfigurationsFor(self, configuration):
- return self.createConfigurations(configuration.name,
- configuration.interface)
+ def createRegistrationsFor(self, registration):
+ return self.createRegistrations(registration.name,
+ registration.interface)
- def createConfigurations(self, name, interface):
+ createRegistrationsFor = ContextMethod(createRegistrationsFor)
+
+ def createRegistrations(self, name, interface):
utilities = self._utilities.get(name)
if utilities is None:
utilities = ImplementorRegistry(PersistentDict())
self._utilities[name] = utilities
- registry = utilities.getRegistered(interface)
- if registry is None:
- registry = ConfigurationRegistry()
- utilities.register(interface, registry)
+ stack = utilities.getRegistered(interface)
+ if stack is None:
+ stack = RegistrationStack()
+ utilities.register(interface, stack)
- return ContextWrapper(registry, self)
+ return ContextWrapper(stack, self)
+ createRegistrations = ContextMethod(createRegistrations)
def getRegisteredMatching(self):
L = []
@@ -95,36 +103,42 @@
continue
L.append((iface, name, ContextWrapper(cr, self)))
return L
+ getRegisteredMatching = ContextMethod(getRegisteredMatching)
-class UtilityConfiguration(ComponentConfiguration):
- """Utility component configuration for persistent components
+class UtilityRegistration(ComponentRegistration):
+ """Utility component registration for persistent components
- This configuration configures persistent components in packages to
+ This registration configures persistent components in packages to
be utilities.
"""
- status = ConfigurationStatusProperty('Utilities')
+ serviceType = 'Utilities'
+
+ status = RegistrationStatusProperty()
- __implements__ = (IUtilityConfiguration,
- ComponentConfiguration.__implements__)
+ implements(IUtilityRegistration)
def __init__(self, name, interface, component_path, permission=None):
- ComponentConfiguration.__init__(self, component_path, permission)
+ ComponentRegistration.__init__(self, component_path, permission)
self.name = name
self.interface = interface
def usageSummary(self):
- # Override IConfiguration.usageSummary()
+ # Override IRegistration.usageSummary()
s = "%s utility" % self.interface.__name__
if self.name:
s += " named %s" % self.name
return s
def getInterface(self):
- # ComponentConfiguration calls this when you specify a
+ # ComponentRegistration calls this when you specify a
# permission; it needs the interface to create a security
# proxy for the interface with the given permission.
# XXX Smells like a dead chicken to me.
return self.interface
+
+
+# XXX Pickle backward compatability
+UtilityConfiguration = UtilityRegistration
=== Zope3/src/zope/app/services/utility.zcml 1.3 => 1.3.14.1 ===
--- Zope3/src/zope/app/services/utility.zcml:1.3 Thu Apr 3 17:05:34 2003
+++ Zope3/src/zope/app/services/utility.zcml Sun Jun 22 10:23:27 2003
@@ -7,17 +7,17 @@
/>
<require
permission="zope.ManageServices"
- attributes="getRegisteredMatching queryConfigurations"
+ attributes="getRegisteredMatching queryRegistrations"
/>
</content>
-<content class=".utility.UtilityConfiguration">
+<content class=".utility.UtilityRegistration">
<require
permission="zope.ManageServices"
- interface="zope.app.interfaces.services.utility.IUtilityConfiguration
+ interface="zope.app.interfaces.services.utility.IUtilityRegistration
zope.app.interfaces.container.IAddNotifiable
zope.app.interfaces.container.IDeleteNotifiable"
- set_schema="zope.app.interfaces.services.utility.IUtilityConfiguration"
+ set_schema="zope.app.interfaces.services.utility.IUtilityRegistration"
/>
</content>
=== Zope3/src/zope/app/services/view.py 1.18 => 1.18.4.1 ===
--- Zope3/src/zope/app/services/view.py:1.18 Tue May 6 07:18:54 2003
+++ Zope3/src/zope/app/services/view.py Sun Jun 22 10:23:27 2003
@@ -24,44 +24,45 @@
from zope.component.interfaces import IViewService
from zope.component.exceptions import ComponentLookupError
from zope.component import getServiceManager
-from zope.app.interfaces.services.configuration import IConfigurable
-from zope.app.services.configuration import ConfigurationRegistry
-from zope.app.services.configuration import SimpleConfiguration
-from zope.proxy.context import ContextWrapper
-from zope.proxy.context import ContextMethod
-from zope.app.services.configuration import ConfigurationStatusProperty
+from zope.app.interfaces.services.registration import IRegistry
+from zope.app.services.registration import RegistrationStack
+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
from zope.security.checker import NamesChecker, ProxyFactory
-from zope.proxy.introspection import removeAllProxies
+from zope.proxy import removeAllProxies
from zope.app.traversing import getRoot, traverse
from zope.exceptions import NotFoundError
-from zope.app.interfaces.services.view import IViewConfiguration
-from zope.app.interfaces.services.view import IPageConfiguration
+from zope.app.interfaces.services.view import IViewRegistration
+from zope.app.interfaces.services.view import IPageRegistration
from zope.app.services.adapter import PersistentAdapterRegistry
from zope.configuration.exceptions import ConfigurationError
from zope.app.interfaces.services.service import ISimpleService
class ViewService(Persistent):
- __implements__ = IViewService, IConfigurable, ISimpleService
+ implements(IViewService, IRegistry, ISimpleService)
def __init__(self):
self._layers = PersistentDict()
- def queryConfigurationsFor(self, configuration, default=None):
- "See IConfigurable"
- return self.queryConfigurations(
- configuration.viewName, configuration.layer,
- configuration.forInterface, configuration.presentationType,
+ def queryRegistrationsFor(self, registration, default=None):
+ "See IRegistry"
+ return self.queryRegistrations(
+ registration.viewName, registration.layer,
+ registration.forInterface, registration.presentationType,
default)
- queryConfigurationsFor = ContextMethod(queryConfigurationsFor)
+ queryRegistrationsFor = ContextMethod(queryRegistrationsFor)
- def queryConfigurations(self, name, layer,
+ def queryRegistrations(self, name, layer,
forInterface, presentationType, default=None):
names = self._layers.get(layer)
@@ -80,17 +81,17 @@
return ContextWrapper(registry, self)
- queryConfigurations = ContextMethod(queryConfigurations)
+ queryRegistrations = ContextMethod(queryRegistrations)
- def createConfigurationsFor(self, configuration):
- "See IConfigurable"
- return self.createConfigurations(
- configuration.viewName, configuration.layer,
- configuration.forInterface, configuration.presentationType)
+ def createRegistrationsFor(self, registration):
+ "See IRegistry"
+ return self.createRegistrations(
+ registration.viewName, registration.layer,
+ registration.forInterface, registration.presentationType)
- createConfigurationsFor = ContextMethod(createConfigurationsFor)
+ createRegistrationsFor = ContextMethod(createRegistrationsFor)
- def createConfigurations(self,
+ def createRegistrations(self,
viewName, layer, forInterface, presentationType):
names = self._layers.get(layer)
@@ -107,12 +108,12 @@
forInterface, presentationType)
if registry is None:
- registry = ConfigurationRegistry()
+ registry = RegistrationStack()
adapter_registry.register(forInterface, presentationType, registry)
return ContextWrapper(registry, self)
- createConfigurations = ContextMethod(createConfigurations)
+ createRegistrations = ContextMethod(createRegistrations)
def getView(self, object, name, request):
view = self.queryView(object, name, request)
@@ -214,11 +215,13 @@
return result
-class ViewConfiguration(SimpleConfiguration):
+class ViewRegistration(SimpleRegistration):
- __implements__ = IViewConfiguration, SimpleConfiguration.__implements__
+ implements(IViewRegistration)
- status = ConfigurationStatusProperty('Views')
+ serviceType = 'Views'
+
+ status = RegistrationStatusProperty()
_what = "View" # For usageSummary(); subclass may override
@@ -247,9 +250,9 @@
s = "%s in layer %s" % (s, self.layer)
return s
-class PageConfiguration(ViewConfiguration):
+class PageRegistration(ViewRegistration):
- __implements__ = IPageConfiguration, ViewConfiguration.__implements__
+ implements(IPageRegistration)
# We only care about browser pages
presentationType = IBrowserPresentation
@@ -261,7 +264,7 @@
class_=None, template=None, attribute=None,
layer='default'):
- super(PageConfiguration, self).__init__(
+ super(PageRegistration, self).__init__(
forInterface, viewName, self.presentationType,
class_, permission, layer)
@@ -286,19 +289,19 @@
def validate(self):
if self.template and self.attribute:
raise ConfigurationError(
- "PageConfiguration for %s view name %s: "
+ "PageRegistration for %s view name %s: "
"Cannot have both 'template' and 'attribute' at the same time." %
(self.forInterface, self.viewName))
if not self.template and not self.attribute:
raise ConfigurationError(
- "PageConfiguration for %s view name %s: "
+ "PageRegistration for %s view name %s: "
"Should have a 'template' or 'attribute' attribute." %
(self.forInterface, self.viewName))
if not self.class_ and self.attribute:
raise ConfigurationError(
- "PageConfiguration for %s view name %s: "
+ "PageRegistration for %s view name %s: "
"Cannot have an 'attribute' without a 'class_'." %
(self.forInterface, self.viewName))
@@ -332,7 +335,6 @@
getView = ContextMethod(getView)
-
class DefaultClass:
def __init__(self, context, request):
@@ -349,3 +351,8 @@
if not template_usage:
kw["template_usage"] = template_usage
return self.template.render(self.view, *args, **kw)
+
+
+# XXX Pickle backward compatability
+PageConfiguration = PageRegistration
+ViewConfiguration = ViewRegistration
=== Zope3/src/zope/app/services/zpt.py 1.10 => 1.10.10.1 ===
--- Zope3/src/zope/app/services/zpt.py:1.10 Thu May 1 15:35:34 2003
+++ Zope3/src/zope/app/services/zpt.py Sun Jun 22 10:23:27 2003
@@ -19,16 +19,19 @@
from persistence import Persistent
+from zope.interface import implements
from zope.security.proxy import ProxyFactory
from zope.pagetemplate.pagetemplate import PageTemplate
from zope.app.pagetemplate.engine import AppPT
from zope.app.interfaces.services.view import IZPTTemplate
from zope.app.interfaces.index.text import ISearchableText
from zope.app.interfaces.file import IReadFile, IWriteFile, IFileFactory
+from zope.app.fssync.classes import ObjectEntryAdapter, AttrMapping
+from zope.app.interfaces.fssync import IObjectFile
class ZPTTemplate(AppPT, PageTemplate, Persistent):
- __implements__ = IZPTTemplate
+ implements(IZPTTemplate)
contentType = 'text/html'
expand = False
@@ -71,7 +74,7 @@
tag = re.compile(r"<[^>]+>")
class SearchableText:
- __implements__ = ISearchableText
+ implements(ISearchableText)
__used_for__ = IZPTTemplate
def __init__(self, page):
@@ -95,7 +98,7 @@
class ReadFile:
- __implements__ = IReadFile
+ implements(IReadFile)
def __init__(self, context):
self.context = context
@@ -105,11 +108,11 @@
def size(self):
return len(self.context.source)
-
+
class WriteFile:
- __implements__ = IWriteFile
+ implements(IWriteFile)
def __init__(self, context):
self.context = context
@@ -120,7 +123,7 @@
class ZPTFactory:
- __implements__ = IFileFactory
+ implements(IFileFactory)
def __init__(self, context):
self.context = context
@@ -129,3 +132,21 @@
r = ZPTTemplate()
r.source = data
return r
+
+
+class ZPTPageAdapter(ObjectEntryAdapter):
+ """ObjectFile adapter for ZPTTemplate objects."""
+
+ implements(IObjectFile)
+
+ def getBody(self):
+ return self.context.source
+
+ def setBody(self, data):
+ # Convert the data to Unicode, since that's what ZPTTemplate
+ # wants; it's normally read from a file so it'll be bytes.
+ # XXX This will die if it's not ASCII. Guess encoding???
+ self.context.source = unicode(data)
+
+ def extra(self):
+ return AttrMapping(self.context, ('contentType', 'expand'))
=== Removed File Zope3/src/zope/app/services/configuration.py ===