[Zope3-checkins] CVS: Zope3/src/zope/app/registration -
__init__.py:1.1 configure.zcml:1.1 interfaces.py:1.1
registration.py:1.1
Stephan Richter
srichter at cosmos.phy.tufts.edu
Sat Mar 13 13:01:19 EST 2004
Update of /cvs-repository/Zope3/src/zope/app/registration
In directory cvs.zope.org:/tmp/cvs-serv27233/src/zope/app/registration
Added Files:
__init__.py configure.zcml interfaces.py registration.py
Log Message:
Moved registration code to zope.app.registration. Created module aliases, so
that old ZODBs work.
=== Added File Zope3/src/zope/app/registration/__init__.py ===
# Import this.
=== Added File Zope3/src/zope/app/registration/configure.zcml ===
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:fssync="http://namespaces.zope.org/fssync"
>
<!-- For backward compatibility -->
<modulealias
module=".registration"
alias="zope.app.services.registration"
/>
<modulealias
module=".interfaces"
alias="zope.app.interfaces.services.registration"
/>
<!-- Registration registries -->
<content class=".registration.RegistrationStack">
<require
permission="zope.ManageServices"
interface=".interfaces.IRegistrationStack"
/>
</content>
<adapter
for=".interfaces.IRegisterable"
provides=".interfaces.IRegistered"
factory=".registration.Registered"
/>
<!-- Registration Manager -->
<content class=".registration.RegistrationManager">
<factory
id = "zope.app.services.RegistrationManager"
title = "Registration Manager" />
<require
permission="zope.View"
interface="zope.app.container.interfaces.IReadContainer" />
<require
permission="zope.ManageServices"
interface="
zope.app.container.interfaces.IWriteContainer
.interfaces.IOrderedContainer
zope.app.container.interfaces.IRemoveNotifiable
zope.app.container.interfaces.INameChooser
"
/>
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
</content>
<!-- Filesystem synchronization support -->
<fssync:adapter
class=".registration.RegistrationManager"
factory="zope.fssync.server.entryadapter.DirectoryAdapter"
/>
</configure>
=== Added File Zope3/src/zope/app/registration/interfaces.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.
#
##############################################################################
"""Interfaces for objects supporting registration
$Id: interfaces.py,v 1.1 2004/03/13 18:01:16 srichter Exp $
"""
from zope.app.i18n import ZopeMessageIDFactory as _
from zope.app.interfaces.annotation import IAnnotatable
from zope.app.interfaces.annotation import IAttributeAnnotatable
from zope.app.container.interfaces import IContainerNamesContainer
from zope.app.container.interfaces import IContained, IContainer
from zope.app.security.permission import PermissionField
from zope.interface import Interface, Attribute, implements
from zope.schema import TextLine, Field
from zope.schema.interfaces import ITextLine
from zope.app.container.constraints import ItemTypePrecondition
from zope.app.container.constraints import ContainerTypesConstraint
UnregisteredStatus = _('Unregistered')
RegisteredStatus = _('Registered')
ActiveStatus = _('Active')
class IRegistrationStatus(ITextLine):
"""The status of a registration
"""
class RegistrationStatus(TextLine):
implements(IRegistrationStatus)
def __init__(self, *args, **kw):
super(RegistrationStatus, self).__init__(*args, **kw)
self.allowed_values = (UnregisteredStatus,
RegisteredStatus,
ActiveStatus)
class INoLocalServiceError(Interface):
"""No local service to register with.
"""
class NoLocalServiceError(Exception):
"""No local service to configure
An attempt was made to register a registration for which there is
no local service.
"""
implements(INoLocalServiceError)
class IRegistration(Interface):
"""Registration object
A registration object represents a specific registration
decision, such as registering an adapter or defining a permission.
In addition to the attributes or methods defined here,
registration objects will include additional attributes
identifying how they should be used. For example, a service
registration will provide a service type. An adapter
registration will specify a used-for interface and a provided
interface.
"""
serviceType = Attribute("service type that manages "
"this registration type")
# A string; typically a class attribute
status = RegistrationStatus(
title=_("Registration status")
)
def activated():
"""Method called when a registration is made active.
"""
def deactivated():
"""Method called when a registration is made inactive.
"""
def usageSummary():
"""Single-line usage summary.
This should include the registrayion keys and the kind of
registration. For example, a service registration will have a
usage summary that indicates a registration for a service of
some type. (e.g. "View Service")
"""
def implementationSummary():
"""Single-line implementation summary.
This summarizes about the implementation of the thing being
registered. For example, for local-component registrations,
this will include the component path. For a page registration,
this might include a template path and a dotted class name.
"""
class IComponentPath(ITextLine):
"""A component path
"""
# This is juse the interface for the ComponentPath field below.
# We'll use this as the basis for looking up an appriate widget.
class ComponentPath(TextLine):
"""A component path
Values of the field are absolute unicode path strings that can be
traversed to get an object.
"""
implements(IComponentPath)
class IComponentRegistration(IRegistration):
"""Registration object that uses a component path and a permission."""
componentPath = ComponentPath(
title=_("Component path"),
description=_("The path to the component; this may be absolute, "
"or relative to the nearest site management folder"),
required=True)
permission = PermissionField(
title=_("The permission needed to use the component"),
required=False,
)
def getComponent():
"""Return the component named in the registration.
"""
class IRegistrationStack(Interface):
"""A stack of registrations for a set of parameters
A service will have a registry containing registry stacks
for specific parameters. For example, an adapter service will
have a registry stack for each given used-for and provided
interface.
The registry stack works like a stack: the first element is
active; when it is removed, the element after it is automatically
activated. An explicit None may be present (at most once) to
signal that nothing is active. To deactivate an element, it is
moved to the end.
"""
def register(registration):
"""Register the given registration without activating it.
Do nothing if the registration is already registered.
"""
def unregister(registration):
"""Unregister the given registration.
Do nothing if the registration is not registered.
Implies deactivate() if the registration is active.
"""
def registered(registration):
"""Is the registration registered?
Return a boolean indicating whether the registration has been
registered.
"""
def activate(registration):
"""Make the registration active.
The activated() method is called on the registration. If
another registration was previously active, its deactivated()
method is called first.
If the argument is None, the currently active registration if
any is disabled and no new registration is activated.
Raises a ValueError if the given registration is not registered.
"""
def deactivate(registration):
"""Make the registration inactive.
If the registration is active, the deactivated() method is
called on the registration. If this reveals a registration
that was previously active, that registration's activated()
method is called.
Raises a ValueError if the given registration is not registered.
The call has no effect if the registration is registered but
not active.
"""
def active():
"""Return the active registration, if any.
Otherwise, returns None.
"""
def info(keep_dummy=False):
"""Return a sequence of registration information.
The sequence items are mapping objects with keys:
id -- A string that can be used to uniquely identify the
registration.
active -- A boolean indicating whether the registration is
active.
registration -- The registration object.
If keep_dummy is true, an entry corresponding to the dummy
entry's position is returned whose value is
{id: '',
active: (True iff it is the first entry),
registration: None}.
"""
def __nonzero__(self):
"""The registry is true iff it has no registrations."""
class IRegistry(Interface):
"""A component that can be configured using a registration manager."""
def queryRegistrationsFor(registration, default=None):
"""Return an IRegistrationStack for the registration.
Data on the registration is used to decide which registry to
return. For example, a service manager will use the
registration name attribute to decide which registry
to return.
Typically, an object that implements this method will also
implement a method named queryRegistrations, which takes
arguments for each of the parameters needed to specify a set
of registrations.
The registry must be in the context of the registry.
"""
def createRegistrationsFor(registration):
"""Create and return an IRegistrationStack for the registration.
Data on the registration is used to decide which regsitry to
create. For example, a service manager will use the
registration name attribute to decide which regsitry
to create.
Typically, an object that implements this method will also
implement a method named createRegistrations, which takes
arguments for each of the parameters needed to specify a set
of registrations.
Calling createRegistrationsFor twice for the same registration
returns the same registry.
The registry must be in the context of the registry.
"""
class IOrderedContainer(Interface):
"""Containers whose items can be reorderd.
XXX This is likely to go.
"""
def moveTop(names):
"""Move the objects corresponding to the given names to the top.
"""
def moveUp(names):
"""Move the objects corresponding to the given names up.
"""
def moveBottom(names):
"""Move the objects corresponding to the given names to the bottom.
"""
def moveDown(names):
"""Move the objects corresponding to the given names down.
"""
class IRegistrationManager(IContainerNamesContainer, IOrderedContainer):
"""Manage Registrations
"""
class IRegistrationManagerContainer(IContainer):
"""Containers with registration managers
These are site-management folders of one sort or another.
The container allows clients to access the registration manager
without knowing it's name.
XXX at this point, it doesn't really make sense for regsitration
managers to be items. It would probably be better to expose the
registrations as a separate tab.
The container prevents deletion of the last registration manager.
The container may allow more than one registration manager. If it
has more than one, the one returned from an unnamed access is
undefined. XXX the container should allow one and only one.
The registration manager container *also* supports local-module
lookup.
"""
def getRegistrationManager():
"""get a registration manager.
Find a registration manager. Clients can get the
registration manager without knowing it's name. Normally,
folders have one registration manager. If there is more than
one, this method will return one; which one is undefined.
An error is raised if no registration manager can be found.
"""
def findModule(name):
"""Find the module of the given name.
If the module can be find in the folder or a parent folder
(within the site manager), then return it, otherwise, delegate
to the module service.
This must return None when the module is not found.
"""
def resolve(name):
"""Resolve a dotted object name.
A dotted object name is a dotted module name and an object
name within the module.
XXX We really should switch to using some other character than
a dot for the delimiter between the module and the object
name.
"""
def __setitem__(name, object):
"""Add to object"""
class IRegisterable(IAnnotatable, IContained):
"""A marker interface."""
__parent__ = Field(
constraint = ContainerTypesConstraint(IRegistrationManagerContainer))
IRegistrationManagerContainer['__setitem__'].setTaggedValue(
'precondition',
ItemTypePrecondition(IRegisterable, IRegistrationManagerContainer))
class IRegistered(Interface):
"""An object that can keep track of its configured uses.
The object need not implement this functionality itself, but must at
least support doing so via an adapter.
"""
def addUsage(location):
"""Add a usage by location.
The location is the physical path to the registration object that
configures the usage.
"""
def removeUsage(location):
"""Remove a usage by location.
The location is the physical path to the registration object that
configures the usage.
"""
def usages():
"""Return a sequence of locations.
A location is a physical path to a registration object that
configures a usage.
"""
def registrations():
"""Return a sequence of registration objects for this object."""
class IAttributeRegisterable(IAttributeAnnotatable, IRegisterable):
"""A marker interface."""
class INoRegistrationManagerError(Interface):
"""No registration manager error
"""
class NoRegistrationManagerError(Exception):
"""No registration manager
There is no registration manager in a site-management folder, or
an operation would result in no registration manager in a
site-management folder.
"""
implements(INoRegistrationManagerError)
# XXX Pickle backward compatability
IUseConfigurable = IRegisterable
import sys
sys.modules['zope.app.interfaces.services.configuration'
] = sys.modules['zope.app.registration.interfaces']
=== Added File Zope3/src/zope/app/registration/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 2004/03/13 18:01:16 srichter Exp $
"""
from persistent import Persistent
from zope.app.container.contained import Contained
from zope.app.container.contained import setitem, contained, uncontained
from zope.app.container.interfaces import IAddNotifiable, IRemoveNotifiable
from zope.app import zapi
from zope.app.interfaces.annotation import IAttributeAnnotatable
from zope.app.interfaces.dependable import IDependable, DependencyError
from zope.app.module.interfaces import IModuleManager
from zope.exceptions import DuplicationError
from zope.fssync.server.entryadapter import ObjectEntryAdapter
from zope.fssync.server.interfaces import IObjectFile
from zope.interface import implements
from zope.proxy import removeAllProxies, getProxiedObject
from zope.security.checker import InterfaceChecker, CheckerPublic
from zope.security.proxy import Proxy, trustedRemoveSecurityProxy
from zope.xmlpickle import dumps, loads
import interfaces
class RegistrationStatusProperty(object):
def __get__(self, inst, klass):
if inst is None:
return self
registration = inst
service = self._get_service(registration)
registry = service and service.queryRegistrationsFor(registration)
if registry:
if registry.active() == registration:
return interfaces.ActiveStatus
if registry.registered(registration):
return interfaces.RegisteredStatus
return interfaces.UnregisteredStatus
def __set__(self, inst, value):
registration = inst
service = self._get_service(registration)
registry = service and service.queryRegistrationsFor(registration)
if value == interfaces.UnregisteredStatus:
if registry:
registry.unregister(registration)
else:
if not service:
raise interfaces.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 == interfaces.RegisteredStatus:
if registry.active() == registration:
registry.deactivate(registration)
else:
registry.register(registration)
elif value == interfaces.ActiveStatus:
if not registry.registered(registration):
registry.register(registration)
registry.activate(registration)
def _get_service(self, registration):
# how we get the service is factored out so subclasses can
# approach this differently
sm = zapi.getServiceManager(registration)
return sm.queryLocalService(registration.serviceType)
class RegistrationStack(Persistent, Contained):
"""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(interfaces.IRegistrationStack)
_data = () # tuple of strings (ivar)
def __init__(self, container):
self.__parent__ = container
def _id(self, ob):
"""Turn ob into a path relative to the site management folder."""
# Get and check relative path
path = zapi.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(self, registration):
cid = self._id(registration)
if self._data:
if cid in self._data:
return # already registered
else:
# Nothing registered. Need to stick None in front so that nothing
# is active.
self._data = (None, )
self._data += (cid, )
def unregister(self, registration):
cid = self._id(registration)
data = self._data
if data:
if data[0] == cid:
data = data[1:]
self._data = data
# Tell it that it is no longer active
registration.deactivated()
if data and data[0] is not None:
# Activate the newly active component
sm = zapi.getServiceManager(self)
new = zapi.traverse(sm, data[0])
new.activated()
else:
# 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]
self._data = data
def registered(self, registration):
cid = self._id(registration)
return cid in self._data
def activate(self, registration):
if registration is None:
cid = None
else:
cid = self._id(registration)
data = self._data
if cid is None and not data:
return # already in the state we want
if cid is None or cid in data:
old = data[0]
if old == cid:
return # already active
# 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
self._data = data
if old is not None:
# Deactivated the currently active component
sm = zapi.getServiceManager(self)
old = zapi.traverse(sm, old)
old.deactivated()
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)
def deactivate(self, registration):
cid = self._id(registration)
data = self._data
if cid not in data:
raise ValueError(
"Registration to be deactivated is not registered",
registration)
if data[0] != cid:
return # already inactive
if None not in data:
# Append None
data += (None,)
# Move it to the end
data = data[1:] + data[:1]
# Write data back
self._data = data
# Tell it that it is no longer active
registration.deactivated()
if data[0] is not None:
# Activate the newly active component
sm = zapi.getServiceManager(self)
new = zapi.traverse(sm, data[0])
new.activated()
def active(self):
if self._data:
path = self._data[0]
if path is not None:
# Make sure we can zapi.traverse to it.
sm = zapi.getServiceManager(self)
registration = zapi.traverse(sm, path)
return registration
return None
def __nonzero__(self):
return bool(self._data)
def info(self, keep_dummy=False):
sm = zapi.getServiceManager(self)
data = self._data
if None not in data:
data += (None,)
result = [{'id': path or "",
'active': False,
'registration': (path and zapi.traverse(sm, path))
}
for path in data
]
result[0]['active'] = True
if not keep_dummy:
# Throw away dummy:
result = [x for x in result if x['id']]
return result
class NotifyingRegistrationStack(RegistrationStack):
def activate(self, registration):
RegistrationStack.activate(self, registration)
self.__parent__.notifyActivated(self, registration)
def deactivate(self, registration):
RegistrationStack.deactivate(self, registration)
self.__parent__.notifyDeactivated(self, registration)
class SimpleRegistration(Persistent, Contained):
"""Registration objects that just contain registration data
Classes that derive from this must make sure they implement
IRemoveNotifiable either by implementing
implementedBy(SimpleRegistration) or explicitly implementing
IRemoveNotifiable.
"""
implements(interfaces.IRegistration, IRemoveNotifiable,
# 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,
)
status = RegistrationStatusProperty()
# Methods from IRegistration
def activated(self):
pass
def deactivated(self):
pass
def usageSummary(self):
return self.__class__.__name__
def implementationSummary(self):
return ""
# Methods from IRemoveNotifiable
def removeNotify(self, event):
"See IRemoveNotifiable"
objectstatus = self.status
if objectstatus == interfaces.ActiveStatus:
try:
objectpath = zapi.getPath(self)
except: # XXX
objectpath = str(self)
raise DependencyError("Can't delete active registration (%s)"
% objectpath)
elif objectstatus == interfaces.RegisteredStatus:
self.status = interfaces.UnregisteredStatus
class ComponentRegistration(SimpleRegistration):
"""Component registration.
Subclasses should define a getInterface() method returning the interface
of the component.
"""
# SimpleRegistration implements IRemoveNotifiable, so we don't need
# it below.
implements(interfaces.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(self):
service_manager = zapi.getServiceManager(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 = self.componentPath
# Get the root and unproxy it
if path.startswith("/"):
# Absolute path
root = removeAllProxies(zapi.getRoot(service_manager))
component = zapi.traverse(root, path)
else:
# Relative path.
ancestor = self.__parent__.__parent__
component = zapi.traverse(ancestor, path)
if 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 = self.getInterface()
checker = InterfaceChecker(interface, self.permission)
component = Proxy(component, checker)
return component
def addNotify(self, event):
"See IAddNotifiable"
component = self.getComponent()
dependents = IDependable(component)
objectpath = zapi.getPath(self)
dependents.addDependent(objectpath)
# Also update usage, if supported
adapter = interfaces.IRegistered(component, None)
if adapter is not None:
adapter.addUsage(objectpath)
def removeNotify(self, event):
"See IRemoveNotifiable"
super(ComponentRegistration, self).removeNotify(event)
component = self.getComponent()
dependents = IDependable(component)
objectpath = zapi.getPath(self)
dependents.removeDependent(objectpath)
# Also update usage, if supported
adapter = interfaces.IRegistered(component, None)
if adapter is not None:
adapter.removeUsage(zapi.getPath(self))
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(interfaces.IRegistered)
# We want to use this key:
# key = "zope.app.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
def registrations(self):
return [zapi.traverse(self.context, path)
for path in self.getPaths()]
class RegistrationManager(Persistent, Contained):
"""Registration manager
Manages registrations within a package.
"""
implements(interfaces.IRegistrationManager, IRemoveNotifiable)
def __init__(self):
self._data = ()
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 __setitem__(self, key, v):
setitem(self, self.__setitem, key, v)
def __setitem(self, key, v):
if key in self:
raise DuplicationError(key)
self._data += ((key, v), )
def addRegistration(self, object):
"See IWriteContainer"
key = self._chooseName('', object)
self[key] = object
return key
def _chooseName(self, name, object):
if not name:
name = object.__class__.__name__
i = 1
n = name
while n in self:
i += 1
n = name + str(i)
return n
def __delitem__(self, key):
"See IWriteContainer"
uncontained(self[key], self, 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 removeNotify(self, event):
assert event.object == self
for name in self:
del self[name]
class RegistrationManagerContainer(object):
"""Mix-in to implement IRegistrationManagerContainer
"""
implements(interfaces.IRegistrationManagerContainer)
def __init__(self):
super(RegistrationManagerContainer, self).__init__()
rm = RegistrationManager()
rm.__parent__ = self
rm.__name__ = 'RegistrationManager'
self[rm.__name__] = rm
def __delitem__(self, name):
"""Delete an item, but not if it's the last registration manager
"""
item = self[name]
if interfaces.IRegistrationManager.providedBy(item):
# Check to make sure it's not the last one
if len([i for i in self.values()
if interfaces.IRegistrationManager.providedBy(i)
]
) < 2:
raise interfaces.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 interfaces.IRegistrationManager.providedBy(item):
# We found one. Get it in context
return item
else:
raise interfaces.NoRegistrationManagerError(
"Couldn't find an registration manager")
def findModule(self, name):
# Used by the persistent modules import hook
# Look for a .py file first:
manager = self.get(name+'.py')
if manager is not None:
# found an item with that name, make sure it's a module(manager):
if IModuleManager.providedBy(manager):
return manager.getModule()
# Look for the module in this folder:
manager = self.get(name)
if manager is not None:
# found an item with that name, make sure it's a module(manager):
if IModuleManager.providedBy(manager):
return manager.getModule()
# See if out container is a RegistrationManagerContainer:
c = self.__parent__
if interfaces.IRegistrationManagerContainer.providedBy(c):
return c.findModule(name)
# Use sys.modules in lieu of module service:
module = sys.modules.get(name)
if module is not None:
return module
raise ImportError(name)
def resolve(self, name):
l = name.rfind('.')
mod = self.findModule(name[:l])
return getattr(mod, name[l+1:])
class 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.registration']
sys.modules['zope.app.services.configuration'
] = sys.modules['zope.app.registration']
More information about the Zope3-Checkins
mailing list