[Checkins] SVN: five.localsitemanager/branches/1.0/ branching version 1.0 (last version to support zope.component < 3.5.0)
Michael Howitz
mh at gocept.com
Tue Aug 26 11:25:35 EDT 2008
Log message for revision 90343:
branching version 1.0 (last version to support zope.component < 3.5.0)
Changed:
A five.localsitemanager/branches/1.0/
D five.localsitemanager/branches/1.0/CHANGES.txt
A five.localsitemanager/branches/1.0/CHANGES.txt
D five.localsitemanager/branches/1.0/src/five/localsitemanager/localsitemanager.txt
A five.localsitemanager/branches/1.0/src/five/localsitemanager/localsitemanager.txt
D five.localsitemanager/branches/1.0/src/five/localsitemanager/registry.py
A five.localsitemanager/branches/1.0/src/five/localsitemanager/registry.py
-=-
Copied: five.localsitemanager/branches/1.0 (from rev 90340, five.localsitemanager/trunk)
Deleted: five.localsitemanager/branches/1.0/CHANGES.txt
===================================================================
--- five.localsitemanager/trunk/CHANGES.txt 2008-08-26 15:17:06 UTC (rev 90340)
+++ five.localsitemanager/branches/1.0/CHANGES.txt 2008-08-26 15:25:34 UTC (rev 90343)
@@ -1,50 +0,0 @@
-Changelog
-=========
-
-0.5 - Unreleased
-----------------
-
-* Added buildout for project, so testing can be done using ``bin/test``.
-
-0.4 - 2008-07-23
-----------------
-
-* Rewrite PersistentComponents.registeredUtilities to not use
- internal methods. This makes it compatible with both zope.component <3.5.0dev
- and >3.5.0dev.
-
-
-0.3 - 2007-12-24
-----------------
-
-* Fixed potential aq problem when assigning various values to the utilities
- registry of the component registry.
-
-0.2 - 2007-06-30
-----------------
-
-* 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.
-
-
-0.1.2 - 2007-06-23
-------------------
-
-* Corrected the zip-safe flag to be False.
-
-
-0.1.1 - 2007-03-05
-------------------
-
-* Fixed aq wrapping when looking up a utility that is actually the component
- registry's parent (the ISite).
-
-
-0.1 (2007-02-27)
-----------------
-
-* Initial version
-
Copied: five.localsitemanager/branches/1.0/CHANGES.txt (from rev 90341, five.localsitemanager/trunk/CHANGES.txt)
===================================================================
--- five.localsitemanager/branches/1.0/CHANGES.txt (rev 0)
+++ five.localsitemanager/branches/1.0/CHANGES.txt 2008-08-26 15:25:34 UTC (rev 90343)
@@ -0,0 +1,66 @@
+Changelog
+=========
+
+0.5 - Unreleased
+----------------
+
+* Added buildout for project, so testing can be done using ``bin/test``.
+
+* Added ability to register utilities with an absolute path. These
+ utilities are returned wrapped into their original context. This
+ change is backward compatible to existing registries.
+
+ But registering utilities having an acquisition context will behave
+ different because these utilities will be returned in their original
+ context. To restore the previous behavior, register utilities
+ unwrapped (aq_base).
+
+ For storing path information the component must implement
+ getPhysicalPath and have an absolute path.
+
+ When a component registered as utility is moved and registered again
+ the path stored in registry gets updated.
+
+
+0.4 - 2008-07-23
+----------------
+
+* Rewrite PersistentComponents.registeredUtilities to not use
+ internal methods. This makes it compatible with both zope.component <3.5.0dev
+ and >3.5.0dev.
+
+
+0.3 - 2007-12-24
+----------------
+
+* Fixed potential aq problem when assigning various values to the utilities
+ registry of the component registry.
+
+0.2 - 2007-06-30
+----------------
+
+* 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.
+
+
+0.1.2 - 2007-06-23
+------------------
+
+* Corrected the zip-safe flag to be False.
+
+
+0.1.1 - 2007-03-05
+------------------
+
+* Fixed aq wrapping when looking up a utility that is actually the component
+ registry's parent (the ISite).
+
+
+0.1 (2007-02-27)
+----------------
+
+* Initial version
+
Deleted: five.localsitemanager/branches/1.0/src/five/localsitemanager/localsitemanager.txt
===================================================================
--- five.localsitemanager/trunk/src/five/localsitemanager/localsitemanager.txt 2008-08-26 15:17:06 UTC (rev 90340)
+++ five.localsitemanager/branches/1.0/src/five/localsitemanager/localsitemanager.txt 2008-08-26 15:25:34 UTC (rev 90343)
@@ -1,380 +0,0 @@
-Local Site Manager
-==================
-
-We start from an empty folder. Since ``OFS.Folder``'s extend
-``ObjectSiteManager`` they all get to be ``IPossibleSite``'s.
-
- >>> from OFS.Folder import Folder
- >>> site = Folder('site')
-
-Of course we now need to transform that IPossibleSite into a real ISite.
-
- >>> import zope.component
- >>> from zope.app.component.hooks import setSite as setActiveSite
- >>> from zope.app.component.hooks import clearSite
-
- >>> from zope.app.component.hooks import setHooks
- >>> setHooks()
-
- >>> from five.localsitemanager import make_objectmanager_site
- >>> make_objectmanager_site(site)
- >>> sitemanager = site.getSiteManager()
- >>> sitemanager
- <PersistentComponents ...>
-
-Make sure this site has it's ``__bases__`` configure appropriately.
-
- >>> sitemanager.__bases__
- (<BaseGlobalComponents ...>,)
-
-Utilities
----------
-
-Utilities can now be registered with our site manager. We can confirm this by
-setting up a test utility.
-
- >>> from OFS.SimpleItem import SimpleItem
- >>> from zope import interface
-
- >>> class ITestUtility(interface.Interface): pass
- >>> class TestUtility(object):
- ... interface.implements(ITestUtility)
- ... def __init__(self, id):
- ... self.id = id
- ... def __repr__(self):
- ... return '<Utility %s "%s">' % (self.__class__.__name__, self.id)
-
- >>> sitemanager.registerUtility(TestUtility('test'),
- ... name=u'hello_world',
- ... provided=ITestUtility)
- >>> sitemanager.getUtility(ITestUtility, name=u'hello_world')
- <Utility TestUtility "test">
-
-Make sure the utility lookup only works when the correct active site has
-been configured.
-
- >>> setActiveSite(None)
- >>> zope.component.queryUtility(ITestUtility, name=u'hello_world') is None
- True
-
- >>> setActiveSite(site)
- >>> zope.component.queryUtility(ITestUtility, name=u'hello_world')
- <Utility TestUtility "test">
-
-Adapters
----------
-
-Adapters can now be registered with our site manager. We can confirm this by
-setting up a test adapter.
-
- >>> from OFS.SimpleItem import SimpleItem
- >>> from zope import interface
-
- >>> class IFoo(interface.Interface): pass
- >>> class Foo(object):
- ... interface.implements(IFoo)
- ... def __init__(self, id):
- ... self.id = id
-
- >>> class ITestAdapter(interface.Interface): pass
- >>> class TestAdapter(object):
- ... interface.implements(ITestAdapter)
- ... def __init__(self, context):
- ... self.context = context
- ... def __repr__(self):
- ... return '<Adapter %s adapting "%s">' % (self.__class__.__name__,
- ... self.context.id)
-
- >>> sitemanager.registerAdapter(TestAdapter,
- ... required=(IFoo,),
- ... provided=ITestAdapter)
- >>> sitemanager.getAdapter(Foo('foo'), ITestAdapter)
- <Adapter TestAdapter adapting "foo">
-
-Make sure the adapter lookup only works when the correct active site has
-been configured.
-
- >>> setActiveSite(None)
- >>> zope.component.queryAdapter(Foo('foo'), ITestAdapter) is None
- True
-
- >>> setActiveSite(site)
- >>> zope.component.queryAdapter(Foo('foo'), ITestAdapter)
- <Adapter TestAdapter adapting "foo">
- >>> ITestAdapter(Foo('foo'))
- <Adapter TestAdapter adapting "foo">
-
-Acquisition
------------
-
-Now to mix a little required Zope 2 confusion into everything, we must ensure
-that the aq chain is predictable. And based on consensus we decided that the
-acquired parent of a returned utility should be the ``ISite`` that owns the
-``ISiteManager`` that returned the utility. We need to ensure all the ways of
-getting a utility have been covered. Of course this should only happen if the
-utility is acquisition aware to begin with.
-
- >>> import Acquisition
- >>> from Acquisition.interfaces import IAcquirer
-
-First off, our utility isn't aq-wrapped so asking it what is aq_parent is
-should return None.
-
- >>> comp = sitemanager.queryUtility(ITestUtility, name=u'hello_world')
- >>> Acquisition.aq_parent(comp) is None
- True
-
-So now we setup a utility that is aq-aware.
-
- >>> class AQTestUtility(Acquisition.Explicit, TestUtility): pass
- >>> sitemanager.registerUtility(AQTestUtility('test'),
- ... name=u'aq_wrapped',
- ... provided=ITestUtility)
-
-And of course the aq parent should be the site now.
-
- >>> comp = sitemanager.getUtility(ITestUtility, name=u'aq_wrapped')
- >>> Acquisition.aq_parent(comp) is site
- True
-
-And just to mix things up a bit. Getting back multiple utilities should allow
-us to test both aq and non-aq based components.
-
-We start with getUtilitiesFor():
-
- >>> utils = [x for x in sitemanager.getUtilitiesFor(ITestUtility)]
- >>> len(utils)
- 2
-
- >>> nonaqutils = [(name, comp)
- ... for name, comp in utils if not IAcquirer.providedBy(comp)]
- >>> len(nonaqutils)
- 1
- >>> name, comp = nonaqutils[0]
- >>> Acquisition.aq_parent(comp) is None
- True
-
- >>> aqutils = [(name, comp)
- ... for name, comp in utils if IAcquirer.providedBy(comp)]
- >>> len(aqutils)
- 1
- >>> name, comp = aqutils[0]
- >>> Acquisition.aq_parent(comp) is site
- True
-
-And then getAllUtilitiesRegisteredFor():
-
- >>> utils = [x for x in
- ... sitemanager.getAllUtilitiesRegisteredFor(ITestUtility)]
- >>> len(utils)
- 2
-
- >>> nonaqutils = [comp for comp in utils if not IAcquirer.providedBy(comp)]
- >>> len(nonaqutils)
- 1
- >>> comp = nonaqutils[0]
- >>> Acquisition.aq_parent(comp) is None
- True
-
- >>> aqutils = [comp for comp in utils if IAcquirer.providedBy(comp)]
- >>> len(aqutils)
- 1
- >>> comp = aqutils[0]
- >>> Acquisition.aq_parent(comp) is site
- True
-
-And registeredUtilities():
-
- >>> utils = [ r.component for r in sitemanager.registeredUtilities() ]
- >>> len(utils)
- 2
-
- >>> nonaqutils = [comp for comp in utils if not IAcquirer.providedBy(comp)]
- >>> len(nonaqutils)
- 1
- >>> comp = nonaqutils[0]
- >>> Acquisition.aq_parent(comp) is None
- True
-
- >>> aqutils = [comp for comp in utils if IAcquirer.providedBy(comp)]
- >>> len(aqutils)
- 1
- >>> comp = aqutils[0]
- >>> Acquisition.aq_parent(comp) is site
- True
-
-Nested Sites
-------------
-
-Whenever a component is queried using the component registry, the active
-component registry (ie site manager) needs to be smart enough to check all
-*parent* component registries as well.
-
-Implementation-wise this means that each component registry needs to have an
-appropriate ``__bases__`` attribute configured that is aware of containment
-and (in the case of Zope 2) acquisition to some respect.
-
-Start by creating some nested sites.
-
- >>> from five.localsitemanager import update_sitemanager_bases
-
- >>> folder1 = Folder('folder1')
- >>> make_objectmanager_site(folder1)
- >>> update_sitemanager_bases(folder1)
-
- >>> folder1_1 = Folder('folder1_1')
- >>> make_objectmanager_site(folder1_1)
- >>> ignored = folder1._setObject('folder1_1', folder1_1)
- >>> folder1_1 = folder1['folder1_1']
- >>> update_sitemanager_bases(folder1_1)
-
-Now we check the actual next-site-lookup logic to make sure it's working.
-
- >>> from five.localsitemanager import find_next_sitemanager, get_parent
-
-Needed to implement our own get_parent (zope3 has one) that is acquisition
-aware.
-
- >>> get_parent(folder1)
- Traceback (most recent call last):
- ...
- TypeError: ('Not enough context...
-
- >>> get_parent(folder1_1)
- <Folder at folder1>
-
-Any logic that sets up a site manager's ``__bases__`` will use the
-``find_next_sitemanager`` function to figure out the next closest place
-to look.
-
- >>> find_next_sitemanager(folder1) is None
- True
-
- >>> find_next_sitemanager(folder1_1)
- <PersistentComponents ...>
-
-Now we make sure that that the ``__bases__`` have been setup appropriately.
-
- >>> folder1.getSiteManager().__bases__
- (<BaseGlobalComponents base>,)
-
- >>> folder1_1.getSiteManager().__bases__
- (<PersistentComponents ...>,)
-
-
-Acquisition Context with Nested Sites
--------------------------------------
-
- >>> from zope.component import queryUtility
-
-Register a utility with both of the nested site managers:
-
- >>> sm1 = folder1.getSiteManager()
- >>> sm1.registerUtility(AQTestUtility('util1'),
- ... name=u'util1',
- ... provided=ITestUtility)
-
- >>> sm1_1 = folder1_1.getSiteManager()
- >>> sm1_1.registerUtility(AQTestUtility('util1_1'),
- ... name=u'util1_1',
- ... provided=ITestUtility)
-
- >>> folder1_1.getSiteManager().__bases__
- (<PersistentComponents ...>,)
-
-Lookup both utilities in the context of the first site manager:
-
- >>> setActiveSite(folder1)
- >>> util1 = queryUtility(ITestUtility, name=u'util1')
- >>> util1
- <Utility AQTestUtility "util1">
-
- >>> util1.aq_chain
- [<Utility AQTestUtility "util1">, <Folder at folder1>]
-
-The second utility isn't available in the first site manager:
-
- >>> queryUtility(ITestUtility, name=u'util_1') is None
- True
-
-Lookup both utilities in the context of the second site manager:
-
- >>> setActiveSite(folder1_1)
- >>> util1 = queryUtility(ITestUtility, name=u'util1')
- >>> util1
- <Utility AQTestUtility "util1">
-
-We expect to get wrapped in the context of the site manager the utility is
-registered with:
-
- >>> util1.aq_chain
- [<Utility AQTestUtility "util1">, <Folder at folder1>]
-
- >>> util1_1 = queryUtility(ITestUtility, name=u'util1_1')
- >>> util1_1
- <Utility AQTestUtility "util1_1">
-
- >>> util1_1.aq_chain
- [<Utility AQTestUtility "util1_1">, <Folder at folder1/folder1_1>, <Folder at folder1>]
-
-
-Acquisition Context of Global Utilities
----------------------------------------
-
- >>> from zope.component import getGlobalSiteManager
-
-Register a utility with both of the nested site managers:
-
- >>> gsm = getGlobalSiteManager()
- >>> gsm.registerUtility(AQTestUtility('globalutil1'),
- ... name=u'globalutil1',
- ... provided=ITestUtility)
-
- >>> sm1 = folder1.getSiteManager()
- >>> sm1.registerUtility(AQTestUtility('localutil1'),
- ... name=u'localutil1',
- ... provided=ITestUtility)
-
-Lookup both utilities in the context of the global site manager:
-
- >>> clearSite()
- >>> globalutil1 = queryUtility(ITestUtility, name=u'globalutil1')
- >>> globalutil1
- <Utility AQTestUtility "globalutil1">
-
- >>> getattr(globalutil1, 'aq_chain', None) is None
- True
-
-The local utility isn't available in the global site manager:
-
- >>> queryUtility(ITestUtility, name=u'localutil1') is None
- True
-
-Lookup both utilities in the context of the local site manager:
-
- >>> setActiveSite(folder1)
- >>> globalutil1 = queryUtility(ITestUtility, name=u'globalutil1')
- >>> globalutil1
- <Utility AQTestUtility "globalutil1">
-
-We expect the global utility to get no Acquisition context:
-
- >>> getattr(globalutil1, 'aq_chain', None) is None
- True
-
-For the local utility we expect to get wrapped in the context of the local
-site manager:
-
- >>> localutil1 = queryUtility(ITestUtility, name=u'localutil1')
- >>> localutil1
- <Utility AQTestUtility "localutil1">
-
- >>> localutil1.aq_chain
- [<Utility AQTestUtility "localutil1">, <Folder at folder1>]
-
-Clean up
---------
-
- >>> from zope.testing.cleanup import cleanUp
- >>> clearSite()
- >>> cleanUp()
Copied: five.localsitemanager/branches/1.0/src/five/localsitemanager/localsitemanager.txt (from rev 90341, five.localsitemanager/trunk/src/five/localsitemanager/localsitemanager.txt)
===================================================================
--- five.localsitemanager/branches/1.0/src/five/localsitemanager/localsitemanager.txt (rev 0)
+++ five.localsitemanager/branches/1.0/src/five/localsitemanager/localsitemanager.txt 2008-08-26 15:25:34 UTC (rev 90343)
@@ -0,0 +1,549 @@
+Local Site Manager
+==================
+
+We start from an empty folder. Since ``OFS.Folder``'s extend
+``ObjectSiteManager`` they all get to be ``IPossibleSite``'s.
+
+ >>> from OFS.Folder import Folder
+ >>> site = Folder('site')
+
+Of course we now need to transform that IPossibleSite into a real ISite.
+
+ >>> import zope.component
+ >>> from zope.app.component.hooks import setSite as setActiveSite
+ >>> from zope.app.component.hooks import clearSite
+
+ >>> from zope.app.component.hooks import setHooks
+ >>> setHooks()
+
+ >>> from five.localsitemanager import make_objectmanager_site
+ >>> make_objectmanager_site(site)
+ >>> sitemanager = site.getSiteManager()
+ >>> sitemanager
+ <PersistentComponents ...>
+
+Make sure this site has it's ``__bases__`` configure appropriately.
+
+ >>> sitemanager.__bases__
+ (<BaseGlobalComponents ...>,)
+
+Utilities
+---------
+
+Utilities can now be registered with our site manager. We can confirm this by
+setting up a test utility.
+
+ >>> from OFS.SimpleItem import SimpleItem
+ >>> from zope import interface
+
+ >>> class ITestUtility(interface.Interface): pass
+ >>> class TestUtility(object):
+ ... interface.implements(ITestUtility)
+ ... def __init__(self, id):
+ ... self.id = id
+ ... def __repr__(self):
+ ... return '<Utility %s "%s">' % (self.__class__.__name__, self.id)
+
+ >>> sitemanager.registerUtility(TestUtility('test'),
+ ... name=u'hello_world',
+ ... provided=ITestUtility)
+ >>> sitemanager.getUtility(ITestUtility, name=u'hello_world')
+ <Utility TestUtility "test">
+
+Make sure the utility lookup only works when the correct active site has
+been configured.
+
+ >>> setActiveSite(None)
+ >>> zope.component.queryUtility(ITestUtility, name=u'hello_world') is None
+ True
+
+ >>> setActiveSite(site)
+ >>> zope.component.queryUtility(ITestUtility, name=u'hello_world')
+ <Utility TestUtility "test">
+
+Adapters
+---------
+
+Adapters can now be registered with our site manager. We can confirm this by
+setting up a test adapter.
+
+ >>> from OFS.SimpleItem import SimpleItem
+ >>> from zope import interface
+
+ >>> class IFoo(interface.Interface): pass
+ >>> class Foo(object):
+ ... interface.implements(IFoo)
+ ... def __init__(self, id):
+ ... self.id = id
+
+ >>> class ITestAdapter(interface.Interface): pass
+ >>> class TestAdapter(object):
+ ... interface.implements(ITestAdapter)
+ ... def __init__(self, context):
+ ... self.context = context
+ ... def __repr__(self):
+ ... return '<Adapter %s adapting "%s">' % (self.__class__.__name__,
+ ... self.context.id)
+
+ >>> sitemanager.registerAdapter(TestAdapter,
+ ... required=(IFoo,),
+ ... provided=ITestAdapter)
+ >>> sitemanager.getAdapter(Foo('foo'), ITestAdapter)
+ <Adapter TestAdapter adapting "foo">
+
+Make sure the adapter lookup only works when the correct active site has
+been configured.
+
+ >>> setActiveSite(None)
+ >>> zope.component.queryAdapter(Foo('foo'), ITestAdapter) is None
+ True
+
+ >>> setActiveSite(site)
+ >>> zope.component.queryAdapter(Foo('foo'), ITestAdapter)
+ <Adapter TestAdapter adapting "foo">
+ >>> ITestAdapter(Foo('foo'))
+ <Adapter TestAdapter adapting "foo">
+
+Acquisition
+-----------
+
+Now to mix a little required Zope 2 confusion into everything, we must ensure
+that the aq chain is predictable.
+
+Path relative to component registry
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+And based on consensus we decided that the
+acquired parent of a returned utility should be the ``ISite`` that owns the
+``ISiteManager`` that returned the utility. We need to ensure all the ways of
+getting a utility have been covered. Of course this should only happen if the
+utility is acquisition aware to begin with.
+
+ >>> import Acquisition
+ >>> from Acquisition.interfaces import IAcquirer
+
+First off, our utility isn't aq-wrapped so asking it what is aq_parent is
+should return None.
+
+ >>> comp = sitemanager.queryUtility(ITestUtility, name=u'hello_world')
+ >>> Acquisition.aq_parent(comp) is None
+ True
+
+So now we setup a utility that is aq-aware.
+
+ >>> class AQTestUtility(Acquisition.Explicit, TestUtility): pass
+ >>> sitemanager.registerUtility(AQTestUtility('test'),
+ ... name=u'aq_wrapped',
+ ... provided=ITestUtility)
+
+And of course the aq parent should be the site now.
+
+ >>> comp = sitemanager.getUtility(ITestUtility, name=u'aq_wrapped')
+ >>> Acquisition.aq_parent(comp) is site
+ True
+
+And just to mix things up a bit. Getting back multiple utilities should allow
+us to test both aq and non-aq based components.
+
+We start with getUtilitiesFor():
+
+ >>> utils = [x for x in sitemanager.getUtilitiesFor(ITestUtility)]
+ >>> len(utils)
+ 2
+
+ >>> nonaqutils = [(name, comp)
+ ... for name, comp in utils if not IAcquirer.providedBy(comp)]
+ >>> len(nonaqutils)
+ 1
+ >>> name, comp = nonaqutils[0]
+ >>> Acquisition.aq_parent(comp) is None
+ True
+
+ >>> aqutils = [(name, comp)
+ ... for name, comp in utils if IAcquirer.providedBy(comp)]
+ >>> len(aqutils)
+ 1
+ >>> name, comp = aqutils[0]
+ >>> Acquisition.aq_parent(comp) is site
+ True
+
+And then getAllUtilitiesRegisteredFor():
+
+ >>> utils = [x for x in
+ ... sitemanager.getAllUtilitiesRegisteredFor(ITestUtility)]
+ >>> len(utils)
+ 2
+
+ >>> nonaqutils = [comp for comp in utils if not IAcquirer.providedBy(comp)]
+ >>> len(nonaqutils)
+ 1
+ >>> comp = nonaqutils[0]
+ >>> Acquisition.aq_parent(comp) is None
+ True
+
+ >>> aqutils = [comp for comp in utils if IAcquirer.providedBy(comp)]
+ >>> len(aqutils)
+ 1
+ >>> comp = aqutils[0]
+ >>> Acquisition.aq_parent(comp) is site
+ True
+
+And registeredUtilities():
+
+ >>> utils = [ r.component for r in sitemanager.registeredUtilities() ]
+ >>> len(utils)
+ 2
+
+ >>> nonaqutils = [comp for comp in utils if not IAcquirer.providedBy(comp)]
+ >>> len(nonaqutils)
+ 1
+ >>> comp = nonaqutils[0]
+ >>> Acquisition.aq_parent(comp) is None
+ True
+
+ >>> aqutils = [comp for comp in utils if IAcquirer.providedBy(comp)]
+ >>> len(aqutils)
+ 1
+ >>> comp = aqutils[0]
+ >>> Acquisition.aq_parent(comp) is site
+ True
+
+Absolute Path
+~~~~~~~~~~~~~
+
+The approach to return utilites with a acquisition chain relative to
+the component registry has the problem that it can return the wrong
+physical path for the utility so computed URLs for the utility are
+also wrong.
+
+This can be fixed when the parent object of a utility is a local
+component registry. But this is not like in Zope3 and has the problem
+that utility registration is only visible below its registry.
+
+Alternative solution: register the utility with its acquisition
+context and it will be returned wrapped into its original
+context. (Only the physical path is stored not the context itself.)
+
+We set up a hierarchy of folders to show the behavior:
+
+ >>> a = self.app._setObject('a', Folder('a'), set_owner=False)
+ >>> b = self.app.a._setObject('b', Folder('b'), set_owner=False)
+ >>> util = self.app.a.b._setObject(
+ ... 'util', AQTestUtility('util'), set_owner=False)
+
+Now we can make `a` a local component registry an register `util`
+there. We expect the utility to implement getPhysicalPath and raise an
+exception otherwise:
+
+ >>> make_objectmanager_site(self.app.a)
+ >>> setActiveSite(self.app.a)
+ >>> sitemanager_a = self.app.a.getSiteManager()
+ >>> sitemanager_a.registerUtility(self.app.a.b.util,
+ ... name=u'with_aq_chain',
+ ... provided=ITestUtility)
+ Traceback (most recent call last):
+ AttributeError: Component <Utility AQTestUtility "util"> does not implement getPhysicalPath, so register it unwrapped or implement this method.
+ >>> import OFS.SimpleItem
+ >>> class SITestUtility(OFS.SimpleItem.SimpleItem, TestUtility): pass
+ >>> si_util = self.app.a.b._setObject('si_util', SITestUtility('si_util'))
+ >>> sitemanager_a.registerUtility(self.app.a.b.si_util,
+ ... name=u'with_aq_chain',
+ ... provided=ITestUtility)
+
+When we query the utility, it is returned with its original context:
+
+ >>> si_util = sitemanager_a.getUtility(ITestUtility, name='with_aq_chain')
+ >>> si_util
+ <SITestUtility at /a/b/si_util>
+ >>> si_util.getPhysicalPath()
+ ('', 'a', 'b', 'si_util')
+ >>> si_util.aq_chain
+ [<SITestUtility at /a/b/si_util>, <Folder at /a/b>, <Folder at /a>, <Application at >, <ZPublisher.BaseRequest.RequestContainer object at 0x...>]
+ >>> si_util.absolute_url()
+ 'http://nohost/a/b/si_util'
+
+ >>> zope.component.getUtility(ITestUtility, name='with_aq_chain')
+ <SITestUtility at /a/b/si_util>
+
+If we move a registered component (which has an absolute path) to new
+place, the registration gets updated after calling registerUtility
+again:
+
+ >>> ignored = self.app.a.b._setObject('c', Folder('c'))
+ >>> si_util = self.app.a.b.si_util.aq_base
+ >>> self.app.a.b._delObject('si_util')
+ >>> si_util.id = 'si_util_cped'
+ >>> ignored = self.app.a.b.c._setObject('si_util_cped', si_util)
+ >>> sitemanager_a.registerUtility(
+ ... self.app.a.b.c.si_util_cped,
+ ... name=u'with_aq_chain',
+ ... provided=ITestUtility)
+ >>> zope.component.getUtility(ITestUtility, name='with_aq_chain')
+ <SITestUtility at /a/b/c/si_util_cped>
+
+And just to mix things up a bit. Getting back multiple utilities
+should allow us to test aq, non-aq based components and components
+having an absolute aqusition path.
+
+First we have to register aq and non-aq based components in our
+registry (a component having an absolute aqusition path already exists):
+
+ >>> sitemanager_a.registerUtility(AQTestUtility('test'),
+ ... name=u'aq_wrapped',
+ ... provided=ITestUtility)
+ >>> sitemanager_a.registerUtility(TestUtility('test'),
+ ... name=u'hello_world',
+ ... provided=ITestUtility)
+
+We start with getUtilitiesFor():
+
+ >>> utils = [x for x in sitemanager_a.getUtilitiesFor(ITestUtility)]
+ >>> len(utils)
+ 3
+
+ >>> nonaqutils = [(name, comp)
+ ... for name, comp in utils if not IAcquirer.providedBy(comp)]
+ >>> len(nonaqutils)
+ 1
+ >>> name, comp = nonaqutils[0]
+ >>> Acquisition.aq_parent(comp) is None
+ True
+
+ >>> aqutils = [(name, comp)
+ ... for name, comp in utils if IAcquirer.providedBy(comp)]
+ >>> len(aqutils)
+ 2
+ >>> aqutils
+ [(u'aq_wrapped', <Utility AQTestUtility "test">),
+ (u'with_aq_chain', <SITestUtility at /a/b/c/si_util_cped>)]
+
+And then getAllUtilitiesRegisteredFor():
+
+ >>> utils = [x for x in
+ ... sitemanager_a.getAllUtilitiesRegisteredFor(ITestUtility)]
+ >>> len(utils)
+ 3
+
+ >>> nonaqutils = [comp for comp in utils if not IAcquirer.providedBy(comp)]
+ >>> len(nonaqutils)
+ 1
+ >>> comp = nonaqutils[0]
+ >>> Acquisition.aq_parent(comp) is None
+ True
+
+ >>> aqutils = [comp for comp in utils if IAcquirer.providedBy(comp)]
+ >>> len(aqutils)
+ 2
+ >>> aqutils
+ [<SITestUtility at /a/b/c/si_util_cped>, <Utility AQTestUtility "test">]
+
+And registeredUtilities():
+
+ >>> utils = [r.component for r in sitemanager_a.registeredUtilities()]
+ >>> len(utils)
+ 3
+
+ >>> nonaqutils = [comp for comp in utils if not IAcquirer.providedBy(comp)]
+ >>> len(nonaqutils)
+ 1
+ >>> comp = nonaqutils[0]
+ >>> Acquisition.aq_parent(comp) is None
+ True
+
+ >>> aqutils = [comp for comp in utils if IAcquirer.providedBy(comp)]
+ >>> len(aqutils)
+ 2
+ >>> aqutils
+ [<SITestUtility at /a/b/c/si_util_cped>, <Utility AQTestUtility "test">]
+
+Nested Sites
+------------
+
+Whenever a component is queried using the component registry, the active
+component registry (ie site manager) needs to be smart enough to check all
+*parent* component registries as well.
+
+Implementation-wise this means that each component registry needs to have an
+appropriate ``__bases__`` attribute configured that is aware of containment
+and (in the case of Zope 2) acquisition to some respect.
+
+Start by creating some nested sites.
+
+ >>> from five.localsitemanager import update_sitemanager_bases
+
+ >>> folder1 = Folder('folder1')
+ >>> make_objectmanager_site(folder1)
+ >>> update_sitemanager_bases(folder1)
+
+ >>> folder1_1 = Folder('folder1_1')
+ >>> make_objectmanager_site(folder1_1)
+ >>> ignored = folder1._setObject('folder1_1', folder1_1)
+ >>> folder1_1 = folder1['folder1_1']
+ >>> update_sitemanager_bases(folder1_1)
+
+Now we check the actual next-site-lookup logic to make sure it's working.
+
+ >>> from five.localsitemanager import find_next_sitemanager, get_parent
+
+Needed to implement our own get_parent (zope3 has one) that is acquisition
+aware.
+
+ >>> get_parent(folder1)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Not enough context...
+
+ >>> get_parent(folder1_1)
+ <Folder at folder1>
+
+Any logic that sets up a site manager's ``__bases__`` will use the
+``find_next_sitemanager`` function to figure out the next closest place
+to look.
+
+ >>> find_next_sitemanager(folder1) is None
+ True
+
+ >>> find_next_sitemanager(folder1_1)
+ <PersistentComponents ...>
+
+Now we make sure that that the ``__bases__`` have been setup appropriately.
+
+ >>> folder1.getSiteManager().__bases__
+ (<BaseGlobalComponents base>,)
+
+ >>> folder1_1.getSiteManager().__bases__
+ (<PersistentComponents ...>,)
+
+
+Acquisition Context with Nested Sites
+-------------------------------------
+
+ >>> from zope.component import queryUtility
+
+Register a utility with both of the nested site managers:
+
+ >>> sm1 = folder1.getSiteManager()
+ >>> sm1.registerUtility(AQTestUtility('util1'),
+ ... name=u'util1',
+ ... provided=ITestUtility)
+
+ >>> sm1_1 = folder1_1.getSiteManager()
+ >>> sm1_1.registerUtility(AQTestUtility('util1_1'),
+ ... name=u'util1_1',
+ ... provided=ITestUtility)
+
+ >>> folder1_1.getSiteManager().__bases__
+ (<PersistentComponents ...>,)
+
+Lookup both utilities in the context of the first site manager:
+
+ >>> setActiveSite(folder1)
+ >>> util1 = queryUtility(ITestUtility, name=u'util1')
+ >>> util1
+ <Utility AQTestUtility "util1">
+
+ >>> util1.aq_chain
+ [<Utility AQTestUtility "util1">, <Folder at folder1>]
+
+The second utility isn't available in the first site manager:
+
+ >>> queryUtility(ITestUtility, name=u'util_1') is None
+ True
+
+Lookup both utilities in the context of the second site manager:
+
+ >>> setActiveSite(folder1_1)
+ >>> util1 = queryUtility(ITestUtility, name=u'util1')
+ >>> util1
+ <Utility AQTestUtility "util1">
+
+We expect to get wrapped in the context of the site manager the utility is
+registered with:
+
+ >>> util1.aq_chain
+ [<Utility AQTestUtility "util1">, <Folder at folder1>]
+
+ >>> util1_1 = queryUtility(ITestUtility, name=u'util1_1')
+ >>> util1_1
+ <Utility AQTestUtility "util1_1">
+
+ >>> util1_1.aq_chain
+ [<Utility AQTestUtility "util1_1">, <Folder at folder1/folder1_1>, <Folder at folder1>]
+
+Utilities stored with relative path
+-----------------------------------
+
+If we register a utility which has only a relative path, the path is
+_not_ stored and the utility is returned relative to the registry. (In
+the example we register folder_1/folder1_1/util in the registry of
+folder_1.):
+
+ >>> folder1_1._setObject('util', SITestUtility('util'), set_owner=False)
+ 'util'
+ >>> sm1.registerUtility(folder1_1.util,
+ ... name=u'util2',
+ ... provided=ITestUtility)
+ >>> sm1.getUtility(ITestUtility, name='util2')
+ <SITestUtility at folder1/util>
+
+
+Acquisition Context of Global Utilities
+---------------------------------------
+
+ >>> from zope.component import getGlobalSiteManager
+
+Register a utility with both of the nested site managers:
+
+ >>> gsm = getGlobalSiteManager()
+ >>> gsm.registerUtility(AQTestUtility('globalutil1'),
+ ... name=u'globalutil1',
+ ... provided=ITestUtility)
+
+ >>> sm1 = folder1.getSiteManager()
+ >>> sm1.registerUtility(AQTestUtility('localutil1'),
+ ... name=u'localutil1',
+ ... provided=ITestUtility)
+
+Lookup both utilities in the context of the global site manager:
+
+ >>> clearSite()
+ >>> globalutil1 = queryUtility(ITestUtility, name=u'globalutil1')
+ >>> globalutil1
+ <Utility AQTestUtility "globalutil1">
+
+ >>> getattr(globalutil1, 'aq_chain', None) is None
+ True
+
+The local utility isn't available in the global site manager:
+
+ >>> queryUtility(ITestUtility, name=u'localutil1') is None
+ True
+
+Lookup both utilities in the context of the local site manager:
+
+ >>> setActiveSite(folder1)
+ >>> globalutil1 = queryUtility(ITestUtility, name=u'globalutil1')
+ >>> globalutil1
+ <Utility AQTestUtility "globalutil1">
+
+We expect the global utility to get no Acquisition context:
+
+ >>> getattr(globalutil1, 'aq_chain', None) is None
+ True
+
+For the local utility we expect to get wrapped in the context of the local
+site manager:
+
+ >>> localutil1 = queryUtility(ITestUtility, name=u'localutil1')
+ >>> localutil1
+ <Utility AQTestUtility "localutil1">
+
+ >>> localutil1.aq_chain
+ [<Utility AQTestUtility "localutil1">, <Folder at folder1>]
+
+Clean up
+--------
+
+ >>> from zope.testing.cleanup import cleanUp
+ >>> clearSite()
+ >>> cleanUp()
Deleted: five.localsitemanager/branches/1.0/src/five/localsitemanager/registry.py
===================================================================
--- five.localsitemanager/trunk/src/five/localsitemanager/registry.py 2008-08-26 15:17:06 UTC (rev 90340)
+++ five.localsitemanager/branches/1.0/src/five/localsitemanager/registry.py 2008-08-26 15:25:34 UTC (rev 90343)
@@ -1,179 +0,0 @@
-import Acquisition
-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 FiveVerifyingAdapterLookup(VerifyingAdapterLookup):
-
- # override some AdapterLookupBase methods for acquisition wrapping
-
- 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
-
- extendors = registry._v_lookup._extendors.get(provided)
- if not extendors:
- continue
-
- components = byorder[order]
- result = _lookup(components, required, extendors, name, 0,
- order)
- if result is not None:
- result = _wrap(result, registry)
- break
-
- 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:
- extendors = registry._v_lookup._extendors.get(provided)
- if extendors is None:
- continue
-
- tmp_result = []
- _subscriptions(byorder[order], required, extendors, u'',
- result, 0, order)
- result = [ _wrap(r, registry) for r in result ]
-
- self._subscribe(*required)
-
- return result
-
-
-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()
- utilities = Acquisition.aq_base(self.utilities)
- utilities.LookupClass = FiveVerifyingAdapterLookup
- utilities._createLookup()
- utilities.__parent__ = self
-
- def registeredUtilities(self):
- for reg in super(PersistentComponents, self).registeredUtilities():
- reg.component=_wrap(reg.component, self)
- yield reg
-
Copied: five.localsitemanager/branches/1.0/src/five/localsitemanager/registry.py (from rev 90341, five.localsitemanager/trunk/src/five/localsitemanager/registry.py)
===================================================================
--- five.localsitemanager/branches/1.0/src/five/localsitemanager/registry.py (rev 0)
+++ five.localsitemanager/branches/1.0/src/five/localsitemanager/registry.py 2008-08-26 15:25:34 UTC (rev 90343)
@@ -0,0 +1,245 @@
+import Acquisition
+import persistent
+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, _getUtilityProvided
+from zope.interface.adapter import VerifyingAdapterLookup
+from zope.interface.adapter import _lookup
+from zope.interface.adapter import _lookupAll
+from zope.interface.adapter import _subscriptions
+import zope.event
+import zope.component.interfaces
+from ZPublisher.BaseRequest import RequestContainer
+
+from five.localsitemanager.utils import get_parent
+
+_marker = object()
+
+class FiveVerifyingAdapterLookup(VerifyingAdapterLookup):
+
+ # override some AdapterLookupBase methods for acquisition wrapping
+
+ 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
+
+ extendors = registry._v_lookup._extendors.get(provided)
+ if not extendors:
+ continue
+
+ components = byorder[order]
+ result = _lookup(components, required, extendors, name, 0,
+ order)
+ if result is not None:
+ result = _wrap(result, registry)
+ break
+
+ 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:
+ extendors = registry._v_lookup._extendors.get(provided)
+ if extendors is None:
+ continue
+
+ tmp_result = []
+ _subscriptions(byorder[order], required, extendors, u'',
+ result, 0, order)
+ result = [ _wrap(r, registry) for r in result ]
+
+ self._subscribe(*required)
+
+ return result
+
+
+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.
+ """
+
+ # If component is stored as a ComponentPathWrapper, we traverse to
+ # the component using the stored path:
+ if isinstance(comp, ComponentPathWrapper):
+ return getSite().unrestrictedTraverse(comp.path)
+
+ # 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 ComponentPathWrapper(persistent.Persistent):
+
+ def __init__(self, component, path):
+ self.component = component
+ self.path = path
+
+ def __eq__(self, other):
+ return self.component == other
+
+
+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()
+ utilities = Acquisition.aq_base(self.utilities)
+ utilities.LookupClass = FiveVerifyingAdapterLookup
+ utilities._createLookup()
+ utilities.__parent__ = self
+
+ def registeredUtilities(self):
+ for reg in super(PersistentComponents, self).registeredUtilities():
+ reg.component=_wrap(reg.component, self)
+ yield reg
+
+ def registerUtility(self, component, provided=None, name=u'', info=u'',
+ event=True):
+ if provided is None:
+ provided = _getUtilityProvided(component)
+
+ registration = self._utility_registrations.get((provided, name))
+ if (registration == (component, info)):
+ # already registered
+ if isinstance(registration[0], ComponentPathWrapper):
+ self.utilities.unsubscribe((), provided, registration[0])
+ # update path
+ registration[0].path = component.getPhysicalPath()
+ self.utilities.subscribe((), provided, registration[0])
+ return
+
+ subscribed = False
+ for ((p, _), data) in self._utility_registrations.iteritems():
+ if p == provided and data[0] == component:
+ subscribed = True
+ break
+
+ wrapped_component = component
+ if hasattr(component, 'aq_parent'):
+ # component is acquisition wrapped, so try to store path
+ if not hasattr(component, 'getPhysicalPath'):
+ raise AttributeError(
+ 'Component %r does not implement getPhysicalPath, '
+ 'so register it unwrapped or implement this method.' %
+ component)
+ path = component.getPhysicalPath()
+ # If the path is relative we can't store it because we
+ # have nearly no chance to use the path for traversal in
+ # getUtility.
+ if path[0] == '':
+ # We have an absolute path, so we can store it.
+ wrapped_component = ComponentPathWrapper(
+ Acquisition.aq_base(component), path)
+ self._utility_registrations[(provided, name)] = wrapped_component, info
+ self.utilities.register((), provided, name, wrapped_component)
+
+ if not subscribed:
+ self.utilities.subscribe((), provided, wrapped_component)
+
+ if event:
+ zope.event.notify(zope.component.interfaces.Registered(
+ UtilityRegistration(self, provided, name, component, info)
+ ))
+
More information about the Checkins
mailing list