[Checkins] SVN: z3c.componentdebug/trunk/src/z3c/componentdebug/
First implementation with reportRequiredAdapters
Ross Patterson
me at rpatterson.net
Wed May 30 15:33:18 EDT 2007
Log message for revision 76007:
First implementation with reportRequiredAdapters
Changed:
A z3c.componentdebug/trunk/src/z3c/componentdebug/README.txt
A z3c.componentdebug/trunk/src/z3c/componentdebug/__init__.py
A z3c.componentdebug/trunk/src/z3c/componentdebug/component.py
A z3c.componentdebug/trunk/src/z3c/componentdebug/tests.py
-=-
Added: z3c.componentdebug/trunk/src/z3c/componentdebug/README.txt
===================================================================
--- z3c.componentdebug/trunk/src/z3c/componentdebug/README.txt (rev 0)
+++ z3c.componentdebug/trunk/src/z3c/componentdebug/README.txt 2007-05-30 19:33:18 UTC (rev 76007)
@@ -0,0 +1,98 @@
+;-*-Doctest-*-
+===================
+Component Debugging
+===================
+
+The Zope component registry is a black box in normal operation.
+Requests are made of the registry for components appropriate to the
+request and it returns them. If something goes wrong, it raises
+ComponentLookupError. This is very much as it should be since the
+inner workings of the registry should no more be apart of application
+design than should the inner workings of Python.
+
+In the process, however, of developing an application that uses the
+registry, it is often desirable to have more introspection of the
+registry available.
+
+Component Debugging provides a set of tools for inspecting the
+component registry of site managers. It also provides a patch that
+catches various different ComponentLookupError exceptions and adds
+more verbose reporting.
+
+--------------------
+Component Inspection
+--------------------
+
+A set of interfaces are needed to demonstrate the inspection
+functions::
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface): pass
+ >>> class IBar(Interface): pass
+ >>> class IBaz(Interface): pass
+
+reportRequiredAdapters
+----------------------
+
+reportRequiredAdapters provides inspection of registrations that
+provide a specific interface. Unlike
+zope.app.apidoc.getRequiredAdapters, however, it takes a list of
+objects to adapt and for each object reports which registrations
+require an interface provided by that object for the correct position
+in the list of objects.
+
+Start with some objects that provide some interfaces::
+
+ >>> from zope.interface import alsoProvides
+ >>> class Foo(object): pass
+ >>> foo = Foo()
+ >>> alsoProvides(foo, IFoo)
+ >>> class Bar(object): pass
+ >>> bar = Bar()
+ >>> alsoProvides(bar, IBar)
+
+At this point there's nothing in the registry::
+
+ >>> from zope.component import queryMultiAdapter
+ >>> queryMultiAdapter((foo, bar), IBaz)
+
+ >>> from pprint import pprint
+ >>> from z3c.componentdebug import reportRequiredAdapters
+ >>> pprint([i for i in reportRequiredAdapters((foo, bar), IBaz)])
+ [(<Foo object at ...>, {}), (<Bar object at ...>, {})]
+
+Register a factory for this lookup::
+
+ >>> from zope.component import provideAdapter
+ >>> def getBaz(foo, bar): return 'baz'
+ >>> provideAdapter(getBaz, (IFoo, IBar), IBaz)
+
+Now the registrations can be inspected::
+
+ >>> queryMultiAdapter((foo, bar), IBaz)
+ 'baz'
+
+ >>> pprint([i for i in reportRequiredAdapters((foo, bar), IBaz)])
+ [(<Foo object at ...>,
+ {<InterfaceClass __builtin__.IFoo>:
+ AdapterRegistration(<BaseGlobalComponents base>, [IFoo, IBar],
+ IBaz, '', getBaz, u'')}),
+ (<Bar object at ...>,
+ {<InterfaceClass __builtin__.IBar>:
+ AdapterRegistration(<BaseGlobalComponents base>, [IFoo, IBar],
+ IBaz, '', getBaz, u'')})]
+
+When we remove one of the required interfaces, we can see what
+regisration might have otherwise fulfilled the lookup::
+
+ >>> from zope.interface import noLongerProvides
+ >>> noLongerProvides(bar, IBar)
+
+ >>> queryMultiAdapter((foo, bar), IBaz)
+
+ >>> pprint([i for i in reportRequiredAdapters((foo, bar), IBaz)])
+ [(<Foo object at ...>,
+ {<InterfaceClass __builtin__.IFoo>:
+ AdapterRegistration(<BaseGlobalComponents base>, [IFoo, IBar],
+ IBaz, '', getBaz, u'')}),
+ (<Bar object at ...>, {})]
Added: z3c.componentdebug/trunk/src/z3c/componentdebug/__init__.py
===================================================================
--- z3c.componentdebug/trunk/src/z3c/componentdebug/__init__.py (rev 0)
+++ z3c.componentdebug/trunk/src/z3c/componentdebug/__init__.py 2007-05-30 19:33:18 UTC (rev 76007)
@@ -0,0 +1,3 @@
+"""Tools for debgging the Zope component registry."""
+
+from component import reportRequiredAdapters
Added: z3c.componentdebug/trunk/src/z3c/componentdebug/component.py
===================================================================
--- z3c.componentdebug/trunk/src/z3c/componentdebug/component.py (rev 0)
+++ z3c.componentdebug/trunk/src/z3c/componentdebug/component.py 2007-05-30 19:33:18 UTC (rev 76007)
@@ -0,0 +1,53 @@
+"""Component lookup debugging."""
+
+from zope.interface import providedBy
+from zope.component import getSiteManager
+from zope.app.component import queryNextSiteManager
+
+_marker = object()
+def getSiteManagers(context=None, sm=None):
+ """Return an iterator over the chain of site managers."""
+ assert None in (context, sm)
+ if sm is None:
+ sm = getSiteManager(context)
+ while sm is not _marker:
+ yield sm
+ sm = queryNextSiteManager(sm, _marker)
+
+def reportRequired(regs, objects, iface, name=u''):
+ order = len(objects)
+ idxs = xrange(order)
+
+ # Only bother with registrations that provide the interface and
+ # require the same number of objects, and has the right name
+ regs = [reg for reg in regs
+ if reg.provided is iface
+ and len(reg.required) == order
+ and reg.name == name]
+
+ for idx in idxs:
+ object = objects[idx]
+ provided = providedBy(object)
+ result = {}
+ for reg in regs:
+ req = reg.required[idx]
+ for prov in provided:
+ if prov.isOrExtends(req):
+ result[req] = reg
+ break
+ yield object, result
+
+def getRegistrations(methods, context=None, sm=None):
+ for sm_ in getSiteManagers(context, sm):
+ for method in methods:
+ for reg in getattr(sm_, method)():
+ yield reg
+
+adapter_methods=('registeredAdapters',
+ 'registeredSubscriptionAdapters',
+ 'registeredHandlers')
+def reportRequiredAdapters(objects, iface, name=u'',
+ context=None, sm=None):
+ return reportRequired(
+ getRegistrations(adapter_methods, context, sm),
+ objects, iface, name)
Added: z3c.componentdebug/trunk/src/z3c/componentdebug/tests.py
===================================================================
--- z3c.componentdebug/trunk/src/z3c/componentdebug/tests.py (rev 0)
+++ z3c.componentdebug/trunk/src/z3c/componentdebug/tests.py 2007-05-30 19:33:18 UTC (rev 76007)
@@ -0,0 +1,11 @@
+import unittest
+from zope.testing import doctest
+
+def test_suite():
+ suite = doctest.DocFileSuite(
+ 'README.txt',
+ optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE)
+ return suite
+
+if __name__ == "__main__":
+ unittest.main(defaultTest='test_suite')
More information about the Checkins
mailing list