[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