[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