[Checkins] SVN: zope.introspector/trunk/src/zope/introspector/ Merged ulif-grokkedintrospector-branch changes r87649:87937 into the trunk.

Uli Fouquet uli at gnufix.de
Wed Jul 2 17:32:46 EDT 2008


Log message for revision 87938:
  Merged ulif-grokkedintrospector-branch changes r87649:87937 into the trunk.

Changed:
  A   zope.introspector/trunk/src/zope/introspector/descriptionprovider.py
  A   zope.introspector/trunk/src/zope/introspector/descriptionprovider.txt
  U   zope.introspector/trunk/src/zope/introspector/interfaces.py
  U   zope.introspector/trunk/src/zope/introspector/objectinfo.py

-=-
Copied: zope.introspector/trunk/src/zope/introspector/descriptionprovider.py (from rev 87937, zope.introspector/branches/ulif-grokkedintrospector/src/zope/introspector/descriptionprovider.py)
===================================================================
--- zope.introspector/trunk/src/zope/introspector/descriptionprovider.py	                        (rev 0)
+++ zope.introspector/trunk/src/zope/introspector/descriptionprovider.py	2008-07-02 21:32:46 UTC (rev 87938)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2008 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.
+#
+##############################################################################
+"""Provide description objects for arbitrary objects.
+"""
+import grokcore.component as grok
+import martian
+from zope.introspector.interfaces import (IObjectDescriptionProvider,
+                                          IObjectInfo)
+
+descriptor_registry = []
+
+class DescriptionFinder(grok.GlobalUtility):
+    grok.implements(IObjectDescriptionProvider)
+
+    def getDescription(self, obj_or_dotted_path, *args, **kw):
+        for descriptor in descriptor_registry:
+            handler = descriptor['handler']
+            if handler.canHandle(obj_or_dotted_path):
+                return handler.getDescription(obj_or_dotted_path)
+        # If no descriptor could be found, we return the plainest one.
+        return ObjectInfo(obj_or_dotted_path)
+
+class DescriptionProvider(object):
+    pass
+
+class DescriptionProviderGrokker(martian.ClassGrokker):
+    """Grok descriptor providers.
+
+    Groks classes derived from ``DescriptorProvider`` on startup and
+    adds them to the local descriptor registry.
+    """
+    martian.component(DescriptionProvider)
+
+    def execute(self, obj=None, *args, **kw):
+        name = getattr(obj, 'name', '')
+        descriptor_registry.insert(0, dict(name=name, handler=obj()))
+        return True
+
+module_grokker = martian.ModuleGrokker()
+module_grokker.register(DescriptionProviderGrokker())
+

Copied: zope.introspector/trunk/src/zope/introspector/descriptionprovider.txt (from rev 87937, zope.introspector/branches/ulif-grokkedintrospector/src/zope/introspector/descriptionprovider.txt)
===================================================================
--- zope.introspector/trunk/src/zope/introspector/descriptionprovider.txt	                        (rev 0)
+++ zope.introspector/trunk/src/zope/introspector/descriptionprovider.txt	2008-07-02 21:32:46 UTC (rev 87938)
@@ -0,0 +1,207 @@
+Description Providers
+*********************
+
+:Test-Layer: functional
+
+or: how to get a description providers for arbitrary objects in an
+extensible and flexible manner.
+
+``zope.introspector.descriptionprovider`` offers objects, grokkers and
+utilities to get a suitable description for arbitrary objects in a
+running Zope framework.
+
+
+Introspecting objects
+=====================
+
+Before we go into the details of the local implementation some words
+might be allowed about the problem that has to be solved here and how
+other packages cope with it.
+
+``zope.introspector`` is a package for getting information about a
+runtime system running a Zope framework. As such it has to provide
+descriptions for many kinds of objects. The descriptions in turn are
+generally thought to be used by viewing components, that might be
+specialists for the different kinds of objects that the introspector
+is able to handle.
+
+Stage 1: Transforming an request/URL into an object/dotted path
+---------------------------------------------------------------
+
+The decision about the right kind of descriptor could for instance be
+made by a traverser, that looks up a certain object in the runtime
+system based on a request sent. The traverser could transform a URL
+into a dotted path or a certain object (and possibly additional
+context parameters), ask the introspector for an appropriate
+description object and render that using an approriate view.
+
+A traversable URL for retrieving a description of the
+``zope.introspector`` package therefore could look like this:
+
+  http://localhost/code/zope/introspector
+
+where the `code` part of the URL describes the type of information we
+want and `zope/introspector` would denote the dotted path we want to
+examine. 
+
+All this could of course also be done by HTTP parameters in an URL
+like this::
+
+  http://localhost/?type=code&object=zope.introspector
+
+It doesn't matter which type of URL transformation we finally
+implement (most likely we will use skins), but we need such a
+transformer in our information flow.
+
+
+Stage 2: Transforming an object/dotted path into a description
+--------------------------------------------------------------
+
+This leads to the question: how can we know what type of object we
+currently handle and what handler(s) is/are available to describe it?
+
+For this purpose we need a component that is able to do the
+transformation as described in the headline. The information flow
+looks like this::
+
+  URL --> object/dotted path --> description object
+
+One general problem we have to deal with therefore is: how can we
+automatically provide a description as concise as possible while
+giving third-party developers the opportunity to extend the
+introspection machine as easy and flexible as possible.
+
+
+Using fixed sets for object-description transformation
+------------------------------------------------------
+
+One solution of the problem is to define a fixed set of things that
+can be introspected, say, Python modules, classes and
+functions. Having such a fixrd set of descriptors (let's call it
+``ModuleInfo``, ``ClassInfo``, etc.) we can do a simple if-elif-else
+cascade like this::
+
+  if isinstance(obj, Interface):
+    return InterfaceInfo(obj)
+  elif self.isPackage(obj):
+    return PackageInfo(obj)
+  ...
+  else:
+    return ObjectInfo(obj)
+
+This is the way ``zope.app.apidoc`` handles things. It is clean, plain
+and works.
+
+Unforuntately, it also suffers from an important shortcoming: the set
+of objects to describe is fixed and cannot be extended easily by
+third-party modules. This can be a problem.
+
+Let's imagine, we'd like to describe a Grok application. Grok
+applications are classes derived from ``grok.application`` and they
+can be configured using Grok directives and other nice things.
+
+When we ask ``zope.app.apidoc`` to describe a ``grok.Application``
+class, we get a plain class description, which does not mention the
+direcives used or (possibly more important) not used.
+
+We can, of course, write a representation of Grok applications
+ourselves, that is able to deliver us all directives (used and
+unused), but: we cannot hook that representation into
+``zope.app.apidoc`` documentation. That's because the package uses the
+above described fixed set of representations.
+
+
+Using grokkers for object-description transformation
+----------------------------------------------------
+
+So the new question is: how can we define object descriptions in a
+way, that thid-party developers are able to extend it with their own
+descriptions?
+
+
+The grok.admin.docgrok approach
+-------------------------------
+
+The ``grok.admin.docgrok`` module solves this problem by using martian
+grokkers and providing a module function that looks up a registry to
+hook up any special representations found in the runtime system.
+
+Adding a representation then means to write a class that derives from
+a certain base and is able to decide itself whether it is able to
+handle certain objects. At framework startup this class then will be
+grokked and added as a possible description deliverer to a registry of
+all description providers.
+
+A module level function then looks up this registry on request, asks
+the different description providers whether they are able to handle a
+certain object and returns the first that approves it.
+
+The whole thing looks like this:
+
+1) At startup:
+
+  - Create registry with object description providers
+
+  - Fill registry with all object description providers (done by
+    class grokker)
+
+2) On request:
+
+  a) transform URL into object/dotted path to look up
+
+  b) call get_descriptor_for(dotted_path)
+
+     i) ask all description providers in registry for description
+        of dotted_path
+
+     ii) return first description
+
+  c) publisher looks up a view for the specific description returned
+
+Afterwards we can for instance get any object, pass it to
+the representation function and aks: are you able to handle this
+object? The class answers by delivering a description object or
+``None``.
+
+The following is a modified variant of this grok.admin.docgrok
+approach.
+
+
+We do similar but even more flexible processing in
+``zope.introspection``. Instead of a module function we provide a
+utility implementing ``IObjectDescriptorProvider``. This way a
+third-party package has not to care for the exact location or type of
+the callable.
+
+
+Providing descriptions for arbitrary objects
+============================================
+
+We define a simple object that we want to have described later on::
+
+  >>> obj = object()
+
+``zope.introspector`` provides many different kinds of descriptions
+for different object types. To get the description that suits an
+object best, there is a utility available. It implements the
+``IObjectDescriptionProvider`` interface. We get this utility::
+
+  >>> from zope.component import getUtility
+  >>> from zope.introspector.interfaces import IObjectDescriptionProvider
+  >>> provider = getUtility(IObjectDescriptionProvider)
+  >>> provider
+  <zope.introspector.descriptionprovider.DescriptionFinder object at 0x...>
+
+This utility takes objects and returns descriptions for it::
+
+  >>> provider.getDescription(obj)
+  <zope.introspector.objectinfo.ObjectInfo object at 0x...>
+
+If we pass another kind of object, we might get a different kind of
+description. We load the zope.introspector package and want a
+description for it::
+
+  >>> import zope.introspector.tests
+  >>> provider.getDescription(zope.introspector.tests)
+  <zope.introspector.objectinfo.ModuleInfo object at 0x...>
+

Modified: zope.introspector/trunk/src/zope/introspector/interfaces.py
===================================================================
--- zope.introspector/trunk/src/zope/introspector/interfaces.py	2008-07-02 21:00:24 UTC (rev 87937)
+++ zope.introspector/trunk/src/zope/introspector/interfaces.py	2008-07-02 21:32:46 UTC (rev 87938)
@@ -21,7 +21,8 @@
     PackageInfo = interface.Attribute("Information about a package")
     TypeInfo = interface.Attribute("Information about a basic type")
     UtilityInfo = interface.Attribute("Utilities an object can access")
-    RegistryInfo = interface.Attribute("Information about the component registry")
+    RegistryInfo = interface.Attribute(
+        "Information about the component registry")
 
 class IIntrospectorAPI(IIntrospectorBaseClasses):
     """The API of zope.introspector.
@@ -149,3 +150,10 @@
         The default layer will be returned with u'' as the skin name.
         """
         
+class IObjectDescriptionProvider(interface.Interface):
+    """Provide description objects for arbitrary objects.
+    """
+    def getDescription(obj_or_dotted_path, *args, **kw):
+        """Get one description object for the object denoted by
+        ``obj_or_dotted_path``.
+        """

Modified: zope.introspector/trunk/src/zope/introspector/objectinfo.py
===================================================================
--- zope.introspector/trunk/src/zope/introspector/objectinfo.py	2008-07-02 21:00:24 UTC (rev 87937)
+++ zope.introspector/trunk/src/zope/introspector/objectinfo.py	2008-07-02 21:32:46 UTC (rev 87938)
@@ -16,10 +16,11 @@
 import os
 import inspect
 import types
+import grokcore.component as grok
 from zope.interface import Interface
 from zope.introspector.interfaces import (IObjectInfo, IModuleInfo,
                                           IPackageInfo, ITypeInfo)
-import grokcore.component as grok
+from zope.introspector.descriptionprovider import DescriptionProvider
 
 class ObjectInfo(grok.Adapter):
     grok.implements(IObjectInfo)
@@ -56,3 +57,11 @@
     grok.implements(ITypeInfo)
     grok.provides(IObjectInfo)
     grok.context(types.TypeType)
+
+class SimpleDescriptionProvider(DescriptionProvider):
+    name = 'simple'
+    def getDescription(self, obj, *args, **kw):
+        return IObjectInfo(obj)
+
+    def canHandle(self, obj, *args, **kw):
+        return True



More information about the Checkins mailing list