[Checkins] SVN: grok/trunk/s start integration of the splitted grokcore (xmlrpc, rest, traverser) packages

Christian Klinger cklinger at novareto.de
Mon Dec 27 09:52:47 EST 2010


Log message for revision 119165:
  start integration of the splitted grokcore (xmlrpc, rest, traverser) packages

Changed:
  U   grok/trunk/setup.py
  U   grok/trunk/src/grok/__init__.py
  U   grok/trunk/src/grok/components.py
  U   grok/trunk/src/grok/configure.zcml
  U   grok/trunk/src/grok/directive.py
  U   grok/trunk/src/grok/interfaces.py
  U   grok/trunk/src/grok/meta.py
  U   grok/trunk/src/grok/publication.py
  U   grok/trunk/src/grok/testing.py

-=-
Modified: grok/trunk/setup.py
===================================================================
--- grok/trunk/setup.py	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/setup.py	2010-12-27 14:52:46 UTC (rev 119165)
@@ -48,11 +48,14 @@
         'grokcore.formlib >= 1.4',
         'grokcore.json',
         'grokcore.message',
+        'grokcore.rest',
         'grokcore.security >= 1.1',
         'grokcore.site',
+        'grokcore.traverser',
         'grokcore.view',
         'grokcore.view [security_publication]',
         'grokcore.viewlet >= 1.3',
+        'grokcore.xmlrpc',
         'martian >= 0.14',
         'pytz',
         'setuptools',

Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/src/grok/__init__.py	2010-12-27 14:52:46 UTC (rev 119165)
@@ -83,14 +83,15 @@
 from grok.components import Application
 from grok.components import View, Form, AddForm, EditForm, DisplayForm
 from grok.components import XMLRPC, REST, JSON
-from grok.components import Traverser
+from grokcore.traverser import Traverser
 from grok.components import Indexes
 from grok.components import Role
 from grok.interfaces import IRESTSkinType, IRESTLayer
 from grok.interfaces import IApplicationInitializedEvent
 
+from grokcore.traverser import traversable
 from grok.directive import (
-    permissions, site, restskin, traversable)
+    permissions, site, restskin)
 
 # BBB These two functions are meant for test fixtures and should be
 # imported from grok.testing, not from grok.

Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/src/grok/components.py	2010-12-27 14:52:46 UTC (rev 119165)
@@ -41,6 +41,8 @@
 from grok import interfaces, util
 
 # BBB this is for import backward compatibility.
+from grokcore.xmlrpc import XMLRPC
+from grokcore.rest import REST
 from grokcore.json import JSON
 from grokcore.content import Model, Container, OrderedContainer
 
@@ -177,134 +179,6 @@
         return util.application_url(self.request, self.context, name, data)
 
 
-class XMLRPC(ViewishViewSupport):
-    """Base class for XML-RPC endpoints in Grok applications.
-
-    When an application creates a subclass of `grok.XMLRPC`, it is
-    creating an XML-RPC view.  Like other Grok views, each `grok.XMLRPC`
-    component can either use an explicit `grok.context()` directive to
-    specify the kind of object it wraps, or else Grok will look through
-    the same module for exactly one `grok.Model` or `grok.Container` (or
-    other `IGrokContext` implementor) and make that class its context
-    instead.
-
-    Every object that is an instance of the wrapped class or interface
-    becomes a legitimate XML-RPC server URL, offering as available
-    procedures whatever methods have been defined inside of that
-    `grok.XMLRPC` component.  When a method is called over XML-RPC, any
-    parameters are translated into normal Python data types and supplied
-    as normal positional arguments.  When the method returns a value or
-    raises an exception, the result is converted back into an XML-RPC
-    response for the client.  In both directions, values are marshalled
-    transparently to and from XML-RPC data structures.
-
-    During the execution of an XML-RPC method, the object whose URL was
-    used for the XML-RPC call is available as ``self.context``.
-
-    """
-
-
-class REST(zope.location.Location, ViewishViewSupport):
-    """Base class for REST views in Grok applications."""
-    interface.implements(interfaces.IREST)
-
-    def __init__(self, context, request):
-        self.context = self.__parent__ = context
-        self.request = request
-
-
-class Traverser(object):
-    """Base class for traversers in Grok applications."""
-    interface.implements(IBrowserPublisher)
-
-    def __init__(self, context, request):
-        self.context = context
-        self.request = request
-
-    def browserDefault(self, request):
-        # if we have a RESTful request, we will handle
-        # GET, POST and HEAD differently (PUT and DELETE are handled already
-        # but not on the BrowserRequest layer but the HTTPRequest layer)
-        if interfaces.IRESTLayer.providedBy(request):
-            rest_view = component.getMultiAdapter(
-                (self.context, self.request), name=request.method)
-            return rest_view, ()
-        view_name = getDefaultViewName(self.context, request)
-        view_uri = "@@%s" % view_name
-        return self.context, (view_uri,)
-
-    def publishTraverse(self, request, name):
-        subob = self.traverse(name)
-        if subob is not None:
-            return util.safely_locate_maybe(subob, self.context, name)
-
-        traversable_dict = grok.traversable.bind().get(self.context)
-        if traversable_dict:
-            if name in traversable_dict:
-                subob = getattr(self.context, traversable_dict[name])
-                if callable(subob):
-                    subob = subob()
-                return util.safely_locate_maybe(subob, self.context, name)
-
-        # XXX Special logic here to deal with containers.  It would be
-        # good if we wouldn't have to do this here. One solution is to
-        # rip this out and make you subclass ContainerTraverser if you
-        # wanted to override the traversal behaviour of containers.
-        if IReadContainer.providedBy(self.context):
-            item = self.context.get(name)
-            if item is not None:
-                return item
-
-        view = component.queryMultiAdapter((self.context, request), name=name)
-        if view is not None:
-            return view
-
-        raise NotFound(self.context, name, request)
-
-    def traverse(self, name):
-        # this will be overridden by subclasses
-        pass
-
-
-class ContextTraverser(Traverser):
-    """Base class for context traversers in Grok applications.
-
-    A context traverser is like a normal `grok.Traverser` but, instead
-    of supplying its own `traverse()` method, it directs Grok to go call
-    the ``traverse()`` method on the context itself in order to process
-    the next name in the URL.
-
-    """
-    component.adapts(interfaces.IContext, IHTTPRequest)
-
-    def traverse(self, name):
-        traverse = getattr(self.context, 'traverse', None)
-        if traverse:
-            return traverse(name)
-
-
-class ContainerTraverser(Traverser):
-    """Base class for container traversers in Grok applications.
-
-    A container traverser is like a normal `grok.Traverser` but, instead
-    of supplying its own ``traverse()`` method, Grok will either call
-    the ``traverse()`` method on the context itself, if any, else call
-    ``get()`` on the container (a getitem-style lookup) in order to
-    resolve the next name in the URL.
-
-    """
-    component.adapts(interfaces.IContainer, IHTTPRequest)
-
-    def traverse(self, name):
-        traverse = getattr(self.context, 'traverse', None)
-        if traverse:
-            result = traverse(name)
-            if result is not None:
-                return result
-        # try to get the item from the container
-        return self.context.get(name)
-
-
 class IndexesClass(object):
     """Base class for index collections in a Grok application.
 

Modified: grok/trunk/src/grok/configure.zcml
===================================================================
--- grok/trunk/src/grok/configure.zcml	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/src/grok/configure.zcml	2010-12-27 14:52:46 UTC (rev 119165)
@@ -39,49 +39,20 @@
   <include package="grokcore.formlib" />
   <include package="grokcore.json" />
   <include package="grokcore.site" />
+  <include package="grokcore.traverser" />
   <include package="grokcore.view" />
   <include package="grokcore.view" file="publication_security.zcml" />
   <include package="grokcore.viewlet" />
+  <include package="grokcore.rest" />
+  <include package="grokcore.xmlrpc" />
 
+
   <securityPolicy
       component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy" />
 
-  <adapter factory=".components.ContextTraverser" />
-  <adapter factory=".components.ContainerTraverser" />
-
   <browser:defaultView
       for=".interfaces.IContext"
       name="index"
       />
 
-  <!-- we register a ++rest++ traversal namespace -->
-  <adapter
-      factory=".rest.rest_skin"
-      for="* zope.publisher.interfaces.browser.IHTTPRequest"
-      provides="zope.traversing.interfaces.ITraversable"
-      name="rest"
-      />
-
-  <!-- this overrides Zope 3's publication factories because they have
-       the same name; we also need to change the priority because of
-       the ZCML discriminator -->
-  <publisher
-      name="XMLRPC"
-      factory=".publication.GrokXMLRPCFactory"
-      methods="POST"
-      mimetypes="text/xml"
-      priority="21"
-      />
-
-  <publisher
-      name="HTTP"
-      factory=".publication.GrokHTTPFactory"
-      methods="*"
-      mimetypes="*"
-      priority="1"
-      />
-
-  <!-- need to grok this for some basic REST support -->
-  <grok:grok package=".rest" />
-
 </configure>

Modified: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/src/grok/directive.py	2010-12-27 14:52:46 UTC (rev 119165)
@@ -34,6 +34,7 @@
 import martian
 import martian.util
 from grokcore.view.directive import TaggedValueStoreOnce
+from grokcore.rest.directive import restskin
 
 
 class site(martian.Directive):
@@ -84,50 +85,3 @@
             else:
                 permission_ids.append(value)
         return permission_ids
-
-
-class traversable(martian.Directive):
-    """The `grok.traversable()` directive.
-
-    Each time this directive is used inside of a class, it designates an
-    attribute of that class which URLs should be able to traverse.  For
-    example, the declaration:
-
-        class Mammoth(grok.Model):
-            grok.traversable('thighbone')
-
-    means that if the URL `/app/mymammoth` designates a Mammoth, then
-    `/app/mymammoth/thighbone` will also be a valid URL (assuming that
-    the Mammoth instance, at runtime, indeed has an attribute by that
-    name)!  By default, the name that must be appended to the URL should
-    simply be the same as the name of the attribute; but by providing a
-    `name` keyword argument, the programmer can designate another name
-    to appear in the URL instead of the raw attribute name.
-
-    """
-    scope = martian.CLASS
-    store = martian.DICT
-
-    def factory(self, attr, name=None):
-        if name is None:
-            name = attr
-        return (name, attr)
-
-
-class restskin(martian.Directive):
-    """The `grok.restskin()` directive.
-
-    This directive is placed inside of `grok.IRESTLayer` subclasses to
-    indicate what their layer name will be within a REST URL.  Giving
-    the skin ``grok.restskin('b')``, for example, will enable URLs that
-    look something like `http://localhost/++rest++b/app`.
-
-    """
-    # We cannot do any better than to check for a class scope. Ideally we
-    # would've checked whether the context is indeed an Interface class.
-    scope = martian.CLASS
-    store = TaggedValueStoreOnce()
-    validate = martian.validateText
-
-    def factory(self, value=None):
-        return value

Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/src/grok/interfaces.py	2010-12-27 14:52:46 UTC (rev 119165)
@@ -25,28 +25,33 @@
 import grokcore.formlib.interfaces
 import grokcore.json.interfaces
 import grokcore.security.interfaces
+import grokcore.rest.interfaces
 import grokcore.site.interfaces
 import grokcore.view.interfaces
 import grokcore.viewlet.interfaces
+import grokcore.xmlrpc.interfaces
+import grokcore.traverser.interfaces
 
 from grokcore.component.interfaces import IContext
 from grokcore.component.interfaces import IGrokErrors
 
 
+from grokcore.rest.interfaces import IREST, IRESTSkinType, IRESTLayer
+
 class IGrokBaseClasses(grokcore.annotation.interfaces.IBaseClasses,
                        grokcore.component.interfaces.IBaseClasses,
                        grokcore.security.interfaces.IBaseClasses,
+                       grokcore.rest.interfaces.IBaseClasses,
                        grokcore.site.interfaces.IBaseClasses,
                        grokcore.view.interfaces.IBaseClasses,
-                       grokcore.json.interfaces.IBaseClasses):
+                       grokcore.json.interfaces.IBaseClasses,
+                       grokcore.traverser.interfaces.IBaseClasses,
+                       grokcore.xmlrpc.interfaces.IBaseClasses):
     Model = interface.Attribute("Base class for persistent content objects "
                                 "(models).")
     Container = interface.Attribute("Base class for containers.")
     OrderedContainer = interface.Attribute("Base class for ordered containers.")
     Application = interface.Attribute("Base class for applications.")
-    XMLRPC = interface.Attribute("Base class for XML-RPC methods.")
-    REST = interface.Attribute("Base class for REST views.")
-    Traverser = interface.Attribute("Base class for custom traversers.")
     Indexes = interface.Attribute("Base class for catalog index definitions.")
     Role = interface.Attribute("Base class for roles.")
 
@@ -167,16 +172,6 @@
     """All Grok forms provides this interface."""
 
 
-class IREST(interface.Interface):
-    context = interface.Attribute("Object that the REST handler presents.")
-
-    request = interface.Attribute("Request that REST handler was looked"
-                                  "up with.")
-
-    body = interface.Attribute(
-        """The text of the request body.""")
-
-
 class IIndexDefinition(interface.Interface):
     """Define an index for grok.Indexes.
     """
@@ -189,18 +184,6 @@
         """
 
 
-class IRESTLayer(IHTTPRequest):
-    """REST-specific Request functionality.
-
-    Base Interfaces for defining REST-layers.
-    """
-
-
-class IRESTSkinType(IInterface):
-    """Skin type for REST requests.
-    """
-
-
 class IContainer(IContext, IContainerBase):
     """A Grok container.
     """

Modified: grok/trunk/src/grok/meta.py
===================================================================
--- grok/trunk/src/grok/meta.py	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/src/grok/meta.py	2010-12-27 14:52:46 UTC (rev 119165)
@@ -53,164 +53,6 @@
 from grokcore.view import make_checker
 
 
-class MethodPublisher(XMLRPCView, Location):
-    """Copied from zope.app.publisher.xmlrpc to get rid of that dependency.
-    """
-    def __getParent(self):
-        return hasattr(self, '_parent') and self._parent or self.context
-
-    def __setParent(self, parent):
-        self._parent = parent
-
-    __parent__ = property(__getParent, __setParent)
-
-
-class XMLRPCGrokker(martian.MethodGrokker):
-    """Grokker for methods of a `grok.XMLRPC` subclass.
-
-    When an application defines a `grok.XMLRPC` view, we do not actually
-    register the view with the Component Architecture.  Instead, we grok
-    each of its methods separately, placing them each inside of a new
-    class that we create on-the-fly by calling `type()`.  We make each
-    method the `__call__()` method of its new class, since that is how
-    Zope always invokes views.  And it is this new class that is then
-    made the object of the two configuration actions that we schedule:
-    one to activate it as an XML-RPC adapter for the context, and the
-    other to prepare a security check for the adapter.
-
-    """
-    martian.component(grok.XMLRPC)
-    martian.directive(grok.context)
-    martian.directive(grok.require, name='permission')
-
-    def execute(self, factory, method, config, context, permission, **kw):
-        name = method.__name__
-
-        # Make sure that the class inherits MethodPublisher, so that the
-        # views have a location
-        method_view = type(
-            factory.__name__, (factory, MethodPublisher),
-            {'__call__': method})
-
-        adapts = (context, IXMLRPCRequest)
-        config.action(
-            discriminator=('adapter', adapts, interface.Interface, name),
-            callable=component.provideAdapter,
-            args=(method_view, adapts, interface.Interface, name),
-            )
-        config.action(
-            discriminator=('protectName', method_view, '__call__'),
-            callable=make_checker,
-            args=(factory, method_view, permission),
-            )
-        return True
-
-
-class RESTGrokker(martian.MethodGrokker):
-    """Grokker for methods of a `grok.REST` subclass.
-
-    When an application defines a `grok.REST` view, we do not actually
-    register the view with the Component Architecture.  Instead, we grok
-    each of its methods separately, placing them each inside of a new
-    class that we create on-the-fly by calling `type()`.  We make each
-    method the `__call__()` method of its new class, since that is how
-    Zope always invokes views.  And it is this new class that is then
-    made the object of the two configuration actions that we schedule:
-    one to activate it as a REST adapter for the context, and the other
-    to prepare a security check for the adapter.
-
-    This results in several registered views, typically with names like
-    `GET`, `PUT`, and `POST` - one for each method that the `grok.REST`
-    subclass defines.
-
-    """
-    martian.component(grok.REST)
-    martian.directive(grok.context)
-    martian.directive(grok.layer, default=grok.IRESTLayer)
-    martian.directive(grok.require, name='permission')
-
-    def execute(self, factory, method, config, permission, context,
-                layer, **kw):
-        name = method.__name__
-
-        method_view = type(
-            factory.__name__, (factory,),
-            {'__call__': method})
-
-        adapts = (context, layer)
-        config.action(
-            discriminator=('adapter', adapts, interface.Interface, name),
-            callable=component.provideAdapter,
-            args=(method_view, adapts, interface.Interface, name),
-            )
-        config.action(
-            discriminator=('protectName', method_view, '__call__'),
-            callable=make_checker,
-            args=(factory, method_view, permission),
-            )
-        return True
-
-
-_restskin_not_used = object()
-
-
-class RestskinInterfaceDirectiveGrokker(martian.InstanceGrokker):
-    """Grokker for interfaces providing the `grok.restskin()` directive.
-
-    Applications create REST skins by subclassing `grok.IRESTLayer`
-    and providing the subclass with a `grok.restskin()` directive giving
-    the prefix string which distinguishes that REST layers from others.
-    This grokker registers those skins.
-
-    """
-    martian.component(InterfaceClass)
-
-    def grok(self, name, interface, module_info, config, **kw):
-        # This `InstanceGrokker` will be called for every instance of
-        # `InterfaceClass` - that is, for every interface defined in an
-        # application module!  So we have to do our own filtering, by
-        # checking whether each interface includes the `grok.restskin()`
-        # directive, and skipping those that do not.
-        restskin = grok.restskin.bind(default=_restskin_not_used
-                                      ).get(interface)
-        if restskin is _restskin_not_used:
-            # The restskin directive is not actually used on the found
-            # interface.
-            return False
-
-        if not interface.extends(grok.IRESTLayer):
-            # For REST layers it is required to extend IRESTLayer.
-            raise GrokError(
-                "The grok.restskin() directive is used on interface %r. "
-                "However, %r does not extend IRESTLayer which is "
-                "required for interfaces that are used as layers and are to "
-                "be registered as a restskin."
-                % (interface.__identifier__, interface.__identifier__),
-                interface)
-
-        config.action(
-            discriminator=('restprotocol', restskin),
-            callable=zope.component.interface.provideInterface,
-            args=(restskin, interface, IRESTSkinType))
-
-        return True
-
-
-class TraverserGrokker(martian.ClassGrokker):
-    """Grokker for subclasses of `grok.Traverser`."""
-    martian.component(grok.Traverser)
-    martian.directive(grok.context)
-
-    def execute(self, factory, config, context, **kw):
-        adapts = (context, IHTTPRequest)
-        config.action(
-            discriminator=('adapter', adapts, IBrowserPublisher, ''),
-            callable=component.provideAdapter,
-            args=(factory, adapts, IBrowserPublisher),
-            )
-        return True
-
-
 def default_fallback_to_name(factory, module, name, **data):
     return name
 

Modified: grok/trunk/src/grok/publication.py
===================================================================
--- grok/trunk/src/grok/publication.py	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/src/grok/publication.py	2010-12-27 14:52:46 UTC (rev 119165)
@@ -32,29 +32,8 @@
 from zope.publisher.interfaces.http import IHTTPException
 
 from zope.app.publication.http import BaseHTTPPublication, HTTPPublication
-from zope.app.publication.requestpublicationfactories import (
-    XMLRPCFactory, HTTPFactory)
 
 
-class GrokXMLRPCPublication(ZopePublicationSansProxy, BaseHTTPPublication):
-    """Combines `BaseHTTPPublication` with the Grok sans-proxy mixin."""
-
-
-class GrokXMLRPCFactory(XMLRPCFactory):
-    """Returns the classes Grok uses for browser requests and publication.
-
-    When an instance of this class is called, it returns a 2-element
-    tuple containing:
-
-    - The request class that Grok uses for XML-RPC requests.
-    - The publication class that Grok uses to publish to a XML-RPC.
-
-    """
-    def __call__(self):
-        request, publication = super(GrokXMLRPCFactory, self).__call__()
-        return request, GrokXMLRPCPublication
-
-
 class GrokHTTPPublication(ZopePublicationSansProxy, HTTPPublication):
     """Combines `HTTPPublication` with the Grok sans-proxy mixin.
 

Modified: grok/trunk/src/grok/testing.py
===================================================================
--- grok/trunk/src/grok/testing.py	2010-12-27 14:51:55 UTC (rev 119164)
+++ grok/trunk/src/grok/testing.py	2010-12-27 14:52:46 UTC (rev 119165)
@@ -30,6 +30,9 @@
     zcml.do_grok('grokcore.formlib.meta', config)
     zcml.do_grok('grokcore.annotation.meta', config)
     zcml.do_grok('grokcore.site.meta', config)
+    zcml.do_grok('grokcore.traverser.meta', config)
+    zcml.do_grok('grokcore.rest.meta', config)
+    zcml.do_grok('grokcore.xmlrpc.meta', config)
     zcml.do_grok('grok.meta', config)
     zcml.do_grok(module_name, config)
     config.execute_actions()



More information about the checkins mailing list