Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First cut at adapter-registry refactoring. The refactoring makes
adapter lookup work more like method lookup. This provides: - a much simpler algorithm, - a basis for super-like adapter lookup, and - a fix for a bug in multi-adapter lookup. These changes also remove the distinction between objects with no interface declarations and objects that declare that they provide Interface. Unfortunately, these version is *much* too slow. I'm checking this version in to save it before trying some variations.
- Loading branch information
Jim Fulton
committed
Sep 8, 2005
0 parents
commit 3b672ba
Showing
5 changed files
with
3,009 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
############################################################################## | ||
# | ||
# Copyright (c) 2002 Zope Corporation and Contributors. | ||
# All Rights Reserved. | ||
# | ||
# This software is subject to the provisions of the Zope Public License, | ||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. | ||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | ||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | ||
# FOR A PARTICULAR PURPOSE. | ||
# | ||
############################################################################## | ||
"""Local/Persistent Adapter Registry | ||
$Id$ | ||
""" | ||
__docformat__ = 'restructuredtext' | ||
import persistent | ||
|
||
import zope.interface | ||
from zope.security.proxy import removeSecurityProxy | ||
|
||
from zope.app.component import registration | ||
from zope.app.component import interfaces | ||
|
||
|
||
class LocalAdapterRegistry(zope.interface.adapter.AdapterRegistry, | ||
persistent.Persistent): | ||
"""Local/persistent surrogate registry""" | ||
zope.interface.implements(interfaces.ILocalAdapterRegistry) | ||
|
||
# See interfaces.registration.ILocatedRegistry | ||
next = None | ||
subs = () | ||
|
||
def __init__(self, base, next=None): | ||
# Base registry. This is always a global registry | ||
self.base = base | ||
# `adapters` is simple dict, since it is populated during every load | ||
self.adapters = {} | ||
self._registrations = () | ||
super(LocalAdapterRegistry, self).__init__() | ||
self.setNext(next) | ||
|
||
def addSub(self, sub): | ||
"""See interfaces.registration.ILocatedRegistry""" | ||
self.subs += (sub, ) | ||
|
||
def removeSub(self, sub): | ||
"""See interfaces.registration.ILocatedRegistry""" | ||
self.subs = tuple( | ||
[s for s in self.subs if s is not sub] ) | ||
|
||
def setNext(self, next, base=None): | ||
"""See interfaces.registration.ILocatedRegistry""" | ||
if base is not None: | ||
self.base = base | ||
|
||
if next != self.next: | ||
if self.next is not None: | ||
self.next.removeSub(self) | ||
if next is not None: | ||
next.addSub(self) | ||
self.next = next | ||
|
||
self.__bases__ = tuple([b for b in (next, self.base) if b is not None]) | ||
|
||
for sub in self.subs: | ||
sub.setNext(self) | ||
|
||
|
||
def register(self, registration): | ||
"""See zope.app.component.interfaces.registration.IRegistry""" | ||
self._registrations += (registration,) | ||
|
||
zope.interface.adapter.AdapterRegistry.register( | ||
self, | ||
(registration.required, ) + registration.with, | ||
registration.provided, registration.name, | ||
registration.component, | ||
) | ||
|
||
def unregister(self, registration): | ||
"""See zope.app.component.interfaces.registration.IRegistry""" | ||
self._registrations = tuple([reg for reg in self._registrations | ||
if reg is not registration]) | ||
|
||
zope.interface.adapter.AdapterRegistry.unregister( | ||
self, | ||
(registration.required, ) + registration.with, | ||
registration.provided, registration.name, | ||
registration.component, | ||
) | ||
|
||
def registered(self, registration): | ||
"""See zope.app.component.interfaces.registration.IRegistry""" | ||
return registration in self._registrations | ||
|
||
def registrations(self): | ||
"""See zope.app.component.interfaces.registration.IRegistry""" | ||
return self._registrations | ||
|
||
class AdapterRegistration(registration.ComponentRegistration): | ||
"""A simple implementation of the adapter registration interface.""" | ||
zope.interface.implements(interfaces.IAdapterRegistration) | ||
|
||
def __init__(self, required, provided, factory, | ||
name='', permission=None, registry=None): | ||
if not isinstance(required, (tuple, list)): | ||
self.required = required | ||
self.with = () | ||
else: | ||
self.required = required[0] | ||
self.with = tuple(required[1:]) | ||
self.provided = provided | ||
self.name = name | ||
self.component = factory | ||
self.permission = permission | ||
self.registry = registry | ||
|
||
def getRegistry(self): | ||
return self.registry | ||
|
||
def __repr__(self): | ||
return ('<%s: ' %self.__class__.__name__ + | ||
'required=%r, ' %self.required + | ||
'with=' + `self.with` + ', ' + | ||
'provided=%r, ' %self.provided + | ||
'name=%r, ' %self.name + | ||
'component=%r, ' %self.component + | ||
'permission=%r' %self.permission + | ||
'>') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
############################################################################## | ||
# | ||
# Copyright (c) 2002 Zope Corporation and Contributors. | ||
# All Rights Reserved. | ||
# | ||
# This software is subject to the provisions of the Zope Public License, | ||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. | ||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | ||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | ||
# FOR A PARTICULAR PURPOSE. | ||
# | ||
############################################################################## | ||
"""Interfaces for the Local Component Architecture | ||
$Id$ | ||
""" | ||
import zope.interface | ||
import zope.schema | ||
import zope.component | ||
from zope.app.container.interfaces import IContainer | ||
from zope.app.container.constraints import ContainerTypesConstraint | ||
from zope.app.container.constraints import ItemTypePrecondition | ||
from zope.app.i18n import ZopeMessageIDFactory as _ | ||
import registration | ||
|
||
class ILocalAdapterRegistry(registration.IRegistry, | ||
registration.ILocatedRegistry): | ||
pass | ||
|
||
class IPossibleSite(zope.interface.Interface): | ||
"""An object that could be a site | ||
""" | ||
|
||
def setSiteManager(sitemanager): | ||
"""Sets the site manager for this object. | ||
""" | ||
|
||
def getSiteManager(): | ||
"""Returns the site manager contained in this object. | ||
If there isn't a site manager, raise a component lookup. | ||
""" | ||
|
||
class ISite(IPossibleSite): | ||
"""Marker interface to indicate that we have a site""" | ||
|
||
class ILocalSiteManager(zope.component.interfaces.ISiteManager, | ||
registration.ILocatedRegistry, | ||
registration.IRegistry): | ||
"""Site Managers act as containers for registerable components. | ||
If a Site Manager is asked for an adapter or utility, it checks for those | ||
it contains before using a context-based lookup to find another site | ||
manager to delegate to. If no other site manager is found they defer to | ||
the global site manager which contains file based utilities and adapters. | ||
""" | ||
|
||
class INewLocalSite(zope.interface.Interface): | ||
|
||
manager = zope.interface.Attribute("The new site manager") | ||
|
||
class NewLocalSite: | ||
zope.interface.implements(INewLocalSite) | ||
|
||
def __init__(self, manager): | ||
self.manager = manager | ||
|
||
|
||
class ISiteManagementFolder(registration.IRegisterableContainer, | ||
IContainer): | ||
"""Component and component registration containers.""" | ||
|
||
__parent__ = zope.schema.Field( | ||
constraint = ContainerTypesConstraint( | ||
ILocalSiteManager, | ||
registration.IRegisterableContainer, | ||
), | ||
) | ||
|
||
class ILocalUtility(registration.IRegisterable): | ||
"""Local utility marker. | ||
A marker interface that indicates that a component can be used as | ||
a local utility. | ||
Utilities should usually also declare they implement | ||
IAttributeAnnotatable, so that the standard adapter to | ||
IRegistered can be used; otherwise, they must provide | ||
another way to be adaptable to IRegistered. | ||
""" | ||
|
||
|
||
class IAdapterRegistration(registration.IComponentRegistration): | ||
"""Local Adapter Registration for Local Adapter Registry | ||
The adapter registration is used to provide local adapters via the | ||
adapter registry. It is an extended component registration, whereby the | ||
component is the adapter factory in this case. | ||
""" | ||
required = zope.schema.Choice( | ||
title = _("For interface"), | ||
description = _("The interface of the objects being adapted"), | ||
vocabulary="Interfaces", | ||
readonly = True, | ||
required=False, | ||
default=None) | ||
|
||
with = zope.schema.Tuple( | ||
title = _("With interfaces"), | ||
description = _("Additionally required interfaces"), | ||
readonly=True, | ||
value_type = zope.schema.Choice(vocabulary='Interfaces'), | ||
required=False, | ||
default=()) | ||
|
||
provided = zope.schema.Choice( | ||
title = _("Provided interface"), | ||
description = _("The interface provided"), | ||
vocabulary="Interfaces", | ||
readonly = True, | ||
required = True) | ||
|
||
name = zope.schema.TextLine( | ||
title=_(u"Name"), | ||
readonly=False, | ||
required=True, | ||
default=u'' | ||
) | ||
|
||
permission = zope.schema.Choice( | ||
title=_("The permission required for use"), | ||
vocabulary="Permission Ids", | ||
readonly=False, | ||
required=False, | ||
) | ||
|
||
# TODO: for now until we figure out a way to specify the factory directly | ||
factoryName = zope.schema.TextLine( | ||
title=_(u"Factory Name"), | ||
readonly=False, | ||
required=False, | ||
) | ||
|
||
|
||
class IUtilityRegistration(IAdapterRegistration): | ||
"""Utility registration object. | ||
Adapter registries are also used to to manage utilities, since utilities | ||
are adapters that are instantiated and have no required interfaces. Thus, | ||
utility registrations must fulfill all requirements of an adapter | ||
registration as well. | ||
""" | ||
|
||
name = zope.schema.TextLine( | ||
title=_("Register As"), | ||
description=_("The name under which the utility will be known."), | ||
readonly=False, | ||
required=True, | ||
default=u'' | ||
) | ||
|
||
provided = zope.schema.Choice( | ||
title=_("Provided interface"), | ||
description=_("The interface provided by the utility"), | ||
vocabulary="Utility Component Interfaces", | ||
readonly=True, | ||
required=True, | ||
) |
Oops, something went wrong.