[Checkins] SVN: five.localsitemanager/trunk/ - restored sprint
changes (revision 76442)
Yvo Schubbe
y.2007- at wcm-solutions.de
Sat Jun 23 07:00:02 EDT 2007
Log message for revision 76978:
- restored sprint changes (revision 76442)
- fixed REQUEST handling
- made new registry subclass obsolete by replacing the LookupClass of the instance
Changed:
U five.localsitemanager/trunk/CHANGES.txt
U five.localsitemanager/trunk/src/five/localsitemanager/registry.py
-=-
Modified: five.localsitemanager/trunk/CHANGES.txt
===================================================================
--- five.localsitemanager/trunk/CHANGES.txt 2007-06-23 10:57:51 UTC (rev 76977)
+++ five.localsitemanager/trunk/CHANGES.txt 2007-06-23 11:00:01 UTC (rev 76978)
@@ -5,6 +5,12 @@
five.localsitemanager 0.1.1 (unreleased)
========================================
+* Refactored and fixed aq wrapping: Nested site managers now return utilities
+ wrapped in the right context. RequestContainers are removed and wrapped
+ utilities are cached. This requires a special LookupClass called
+ 'FiveVerifyingAdapterLookup' in all 'utilities' registries used below a
+ five.localsitemanager site.
+
* Fixed aq wrapping when looking up a utility that is actually the component
registry's parent (the ISite).
Modified: five.localsitemanager/trunk/src/five/localsitemanager/registry.py
===================================================================
--- five.localsitemanager/trunk/src/five/localsitemanager/registry.py 2007-06-23 10:57:51 UTC (rev 76977)
+++ five.localsitemanager/trunk/src/five/localsitemanager/registry.py 2007-06-23 11:00:01 UTC (rev 76978)
@@ -1,69 +1,178 @@
import Acquisition
-from zope.component.interfaces import ComponentLookupError
-import zope.component.persistentregistry
import OFS.ObjectManager
+from Acquisition.interfaces import IAcquirer
+from zope.app.component.hooks import getSite
+from zope.app.component.interfaces import ISite
+from zope.component.persistentregistry import PersistentAdapterRegistry
+from zope.component.persistentregistry import PersistentComponents
+from zope.component.registry import UtilityRegistration
+from zope.interface.adapter import VerifyingAdapterLookup
+from zope.interface.adapter import _lookup
+from zope.interface.adapter import _lookupAll
+from zope.interface.adapter import _subscriptions
+from ZPublisher.BaseRequest import RequestContainer
+from five.localsitemanager.utils import get_parent
+
_marker = object()
-class PersistentComponents \
- (zope.component.persistentregistry.PersistentComponents,
- OFS.ObjectManager.ObjectManager):
- """An implementation of a component registry that can be persisted
- and looks like a standard ObjectManager. It also ensures that all
- utilities have the the parent of this site manager (which should be
- the ISite) as their acquired parent.
- """
+class FiveVerifyingAdapterLookup(VerifyingAdapterLookup):
- def _wrap(self, comp):
- """Return an aq wrapped component with the site as the parent but
- only if the comp has an aq wrapper to begin with.
- """
+ # override some AdapterLookupBase methods for acquisition wrapping
- # BBB: The primary reason for doing this sort of wrapping of
- # returned utilities is to support CMF tool-like functionality where
- # a tool expects it's aq_parent to be the portal object. New code
- # (ie new utilities) should not rely on this predictability to
- # get the portal object and should search out an alternate means
- # (possibly retrieve the ISiteRoot utility). Although in most
- # cases getting at the portal object shouldn't be the required pattern
- # but instead looking up required functionality via other (possibly
- # local) components.
+ def _uncached_lookup(self, required, provided, name=u''):
+ result = None
+ order = len(required)
+ for registry in self._registry.ro:
+ byorder = registry._adapters
+ if order >= len(byorder):
+ continue
- if Acquisition.interfaces.IAcquirer.providedBy(comp):
- parent = Acquisition.aq_parent(self)
- if parent is None:
- raise ValueError('Not enough context to acquire parent')
+ extendors = registry._v_lookup._extendors.get(provided)
+ if not extendors:
+ continue
- base = Acquisition.aq_base(comp)
+ components = byorder[order]
+ result = _lookup(components, required, extendors, name, 0,
+ order)
+ if result is not None:
+ result = _wrap(result, registry)
+ break
- if base is not Acquisition.aq_base(parent):
- # If the component is not the cmoponent registry container,
- # wrap it in the parent
- comp = base.__of__(parent)
+ self._subscribe(*required)
+
+ return result
+
+ def _uncached_lookupAll(self, required, provided):
+ order = len(required)
+ result = {}
+ for registry in reversed(self._registry.ro):
+ byorder = registry._adapters
+ if order >= len(byorder):
+ continue
+ extendors = registry._v_lookup._extendors.get(provided)
+ if not extendors:
+ continue
+ components = byorder[order]
+ tmp_result = {}
+ _lookupAll(components, required, extendors, tmp_result, 0, order)
+ for k, v in tmp_result.iteritems():
+ tmp_result[k] = _wrap(v, registry)
+ result.update(tmp_result)
+
+ self._subscribe(*required)
+
+ return tuple(result.iteritems())
+
+ def _uncached_subscriptions(self, required, provided):
+ order = len(required)
+ result = []
+ for registry in reversed(self._registry.ro):
+ byorder = registry._subscribers
+ if order >= len(byorder):
+ continue
+
+ if provided is None:
+ extendors = (provided, )
else:
- # If the component happens to be the component registry
- # container we are looking up a ISiteRoot.
- # We are not wrapping it in itself but in its own parent
- comp = base.__of__(Acquisition.aq_parent(parent))
+ extendors = registry._v_lookup._extendors.get(provided)
+ if extendors is None:
+ continue
- return comp
+ tmp_result = []
+ _subscriptions(byorder[order], required, extendors, u'',
+ result, 0, order)
+ result = [ _wrap(r, registry) for r in result ]
- def queryUtility(self, provided, name=u'', default=None):
- comp = self.utilities.lookup((), provided, name, default)
- if comp is not default:
- comp = self._wrap(comp)
- return comp
+ self._subscribe(*required)
- def getUtility(self, provided, name=u''):
- utility = self.queryUtility(provided, name, _marker)
- if utility is _marker:
- raise ComponentLookupError(provided, name)
- return utility
+ return result
- def getUtilitiesFor(self, interface):
- return ((name, self._wrap(utility))
- for name, utility in self.utilities.lookupAll((), interface))
- def getAllUtilitiesRegisteredFor(self, interface):
- return (self._wrap(x)
- for x in self.utilities.subscriptions((), interface))
+def _recurse_to_site(current, wanted):
+ if not Acquisition.aq_base(current) == wanted:
+ current = _recurse_to_site(get_parent(current), wanted)
+ return current
+
+def _wrap(comp, registry):
+ """Return an aq wrapped component with the site as the parent but
+ only if the comp has an aq wrapper to begin with.
+ """
+
+ # BBB: The primary reason for doing this sort of wrapping of
+ # returned utilities is to support CMF tool-like functionality where
+ # a tool expects its aq_parent to be the portal object. New code
+ # (ie new utilities) should not rely on this predictability to
+ # get the portal object and should search out an alternate means
+ # (possibly retrieve the ISiteRoot utility). Although in most
+ # cases getting at the portal object shouldn't be the required pattern
+ # but instead looking up required functionality via other (possibly
+ # local) components.
+
+ if registry.__bases__ and IAcquirer.providedBy(comp):
+ current_site = getSite()
+ registry_site = Acquisition.aq_base(registry.__parent__)
+ if not ISite.providedBy(registry_site):
+ registry_site = registry_site.__parent__
+
+ if current_site is None:
+ # If no current site can be found, return utilities wrapped in
+ # the site they where registered in. We loose the whole aq chain
+ # here though
+ current_site = Acquisition.aq_base(registry_site)
+
+ parent = None
+
+ if current_site == registry_site:
+ parent = current_site
+ else:
+ parent = _recurse_to_site(current_site, registry_site)
+
+ if parent is None:
+ raise ValueError('Not enough context to acquire parent')
+
+ base = Acquisition.aq_base(comp)
+ # clean up aq_chain, removing REQUEST objects
+ parent = _rewrap(parent)
+
+ if base is not Acquisition.aq_base(parent):
+ # If the component is not the component registry container,
+ # wrap it in the parent
+ comp = base.__of__(parent)
+ else:
+ # If the component happens to be the component registry
+ # container we are looking up a ISiteRoot.
+ # We are not wrapping it in itself but in its own parent
+ comp = base.__of__(Acquisition.aq_parent(parent))
+
+ return comp
+
+def _rewrap(obj):
+ obj = Acquisition.aq_inner(obj)
+ base = Acquisition.aq_base(obj)
+ parent = Acquisition.aq_parent(obj)
+ if not parent or isinstance(parent, RequestContainer):
+ return base
+ return base.__of__(_rewrap(parent))
+
+
+class PersistentComponents \
+ (PersistentComponents,
+ OFS.ObjectManager.ObjectManager):
+ """An implementation of a component registry that can be persisted
+ and looks like a standard ObjectManager. It also ensures that all
+ utilities have the the parent of this site manager (which should be
+ the ISite) as their acquired parent.
+ """
+
+ def _init_registries(self):
+ super(PersistentComponents, self)._init_registries()
+ self.utilities.LookupClass = FiveVerifyingAdapterLookup
+ self.utilities._createLookup()
+ self.utilities.__parent__ = self
+
+ def registeredUtilities(self):
+ for ((provided, name), (component, info)
+ ) in self._utility_registrations.iteritems():
+ yield UtilityRegistration(self, provided, name,
+ _wrap(component, self), info)
More information about the Checkins
mailing list