[Checkins] SVN: grok/trunk/ - added xmlrpc

Christian Theune ct at gocept.com
Wed Oct 18 12:52:50 EDT 2006


Log message for revision 70787:
   - added xmlrpc 
  

Changed:
  U   grok/trunk/TODO.txt
  U   grok/trunk/src/grok/__init__.py
  U   grok/trunk/src/grok/_grok.py
  U   grok/trunk/src/grok/ftests/test_grok_functional.py
  A   grok/trunk/src/grok/ftests/xmlrpc/
  A   grok/trunk/src/grok/ftests/xmlrpc/__init__.py
  A   grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py
  A   grok/trunk/src/grok/ftests/xmlrpc_helper.py
  U   grok/trunk/src/grok/tests/test_grok.py
  A   grok/trunk/src/grok/tests/xmlrpc/
  A   grok/trunk/src/grok/tests/xmlrpc/__init__.py
  A   grok/trunk/src/grok/tests/xmlrpc/nocontext.py

-=-
Modified: grok/trunk/TODO.txt
===================================================================
--- grok/trunk/TODO.txt	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/TODO.txt	2006-10-18 16:52:48 UTC (rev 70787)
@@ -30,8 +30,6 @@
 
 - local registrations (philikon)
 
-- xml-rpc (theuni)
-
 - make it easier to write tests (wosc, faassen)
 
 - grok.App (philikon)
@@ -43,6 +41,10 @@
 - error reporting during grokking (provide file/line-number information
   on our extrinsically generated errors) (philikon)
 
+- maybe: transform register_foo() functions that take lists into functions
+  that operate on a single entity and provide a decorator (@iterate) to 
+  call the function for each item (theuni)
+
 Need to discuss
 ---------------
 

Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/__init__.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -21,17 +21,22 @@
     IObjectCreatedEvent, ObjectCreatedEvent,
     IObjectModifiedEvent, ObjectModifiedEvent,
     IObjectCopiedEvent, ObjectCopiedEvent)
+
 from zope.app.container.contained import (
     IObjectAddedEvent, ObjectAddedEvent,
     IObjectMovedEvent, ObjectMovedEvent, 
     IObjectRemovedEvent, ObjectRemovedEvent,
     IContainerModifiedEvent, ContainerModifiedEvent)
 
-from grok._grok import (Model, Adapter, MultiAdapter, View, PageTemplate, Utility,
-                        grok, context, name, template, templatedir, )
+from grok._grok import Model, Adapter, MultiAdapter, View, XMLRPC
+from grok._grok import PageTemplate, Utility
+
+from grok._grok import grok, context, name, template, templatedir
+
 from grok._grok import SubscribeDecorator as subscribe
 from grok.error import GrokError, GrokImportError
 
+# Our __init__ provides the grok API directly so using 'import grok' is enough.
 from grok.interfaces import IGrokAPI
 from zope.interface import moduleProvides
 moduleProvides(IGrokAPI)

Modified: grok/trunk/src/grok/_grok.py
===================================================================
--- grok/trunk/src/grok/_grok.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/_grok.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -15,6 +15,7 @@
 """
 import os
 import sys
+import inspect
 
 import persistent
 from zope import component
@@ -29,10 +30,13 @@
 from zope.publisher.interfaces.browser import (IDefaultBrowserLayer,
                                                IBrowserRequest)
 from zope.pagetemplate import pagetemplate
+
 from zope.app.pagetemplate.engine import TrustedAppPT
 from zope.app.publisher.browser import directoryresource
 from zope.app.publisher.browser.pagetemplateresource import \
     PageTemplateResourceFactory
+from zope.app.publisher.xmlrpc import MethodPublisher
+from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
 
 from grok import util, scan
 from grok.error import GrokError, GrokImportError
@@ -41,6 +45,7 @@
                             TextDirective, InterfaceOrClassDirective,
                             frame_is_module)
 
+
 AMBIGUOUS_CONTEXT = object()
 
 class Model(persistent.Persistent):
@@ -86,6 +91,12 @@
     def before(self):
         pass
 
+
+class XMLRPC(object):
+    pass
+
+
+
 class PageTemplate(TrustedAppPT, pagetemplate.PageTemplate):
     expand = 0
 
@@ -140,7 +151,7 @@
                 raise GrokError("A package can not contain both a 'static' "
                                 "resource directory and a module named "
                                 "'static.py'", module_info.getModule())
-                
+
         register_static_resources(module_info.dotted_name, resource_path)
 
     for sub_module_info in module_info.getSubModuleInfos():
@@ -149,7 +160,7 @@
 
 def grok_module(module_info):
     (models, adapters, multiadapters, utilities,
-     views, templates, subscribers) = scan_module(module_info)
+     views, xmlrpc_views, templates, subscribers) = scan_module(module_info)
 
     find_filesystem_templates(module_info, templates)
 
@@ -160,15 +171,20 @@
     register_multiadapters(multiadapters)
     register_utilities(utilities)
     register_views(context, views, templates)
+    register_xmlrpc(context, xmlrpc_views)
     register_unassociated_templates(context, templates)
     register_subscribers(subscribers)
 
+
 def scan_module(module_info):
-    models = []
-    adapters = []
-    multiadapters = []
-    utilities = []
-    views = []
+    components = {
+            Model: [],
+            Adapter: [],
+            MultiAdapter: [],
+            Utility: [],
+            View: [],
+            XMLRPC: []
+            }
     templates = TemplateRegistry()
     subscribers = module_info.getAnnotation('grok.subscribers', [])
 
@@ -179,23 +195,20 @@
         if not defined_locally(obj, module_info.dotted_name):
             continue
 
-        if util.check_subclass(obj, Model):
-            models.append(obj)
-        elif util.check_subclass(obj, Adapter):
-            adapters.append(obj)
-        elif util.check_subclass(obj, MultiAdapter):
-            multiadapters.append(obj)
-        elif util.check_subclass(obj, View):
-            views.append(obj)
-        elif util.check_subclass(obj, Utility):
-            utilities.append(obj)
-        elif isinstance(obj, PageTemplate):
+        if isinstance(obj, PageTemplate):
             templates.register(name, obj)
             obj._annotateGrokInfo(module_info, name, module_info.dotted_name)
+            continue
 
-    return (models, adapters, multiadapters, utilities,
-            views, templates, subscribers)
+        for candidate_class, found_list in components.items():
+            if util.check_subclass(obj, candidate_class):
+                found_list.append(obj)
+                break
 
+    return (components[Model], components[Adapter], 
+            components[MultiAdapter], components[Utility],
+            components[View], components[XMLRPC], templates, subscribers)
+
 def find_filesystem_templates(module_info, templates):
     template_dir_name = module_info.getAnnotation('grok.templatedir', module_info.name)
     template_dir = module_info.getResourcePath(template_dir_name)
@@ -321,6 +334,22 @@
         name = class_annotation(factory, 'grok.name', '')
         component.provideUtility(factory(), name=name)
 
+def register_xmlrpc(context, views):
+    for view in views:
+        view_context = determine_class_context(view, context)
+        candidates = [getattr(view, name) for name in dir(view)]
+        methods = [c for c in candidates if inspect.ismethod(c)]
+
+        for method in methods:
+            # Make sure that the class inherits MethodPublisher, so that the views
+            # have a location
+            method_view = type(view.__name__, (view, MethodPublisher), 
+                               {'__call__':method,
+                                '__Security_checker__':GrokChecker()})
+            component.provideAdapter(
+                method_view, (view_context, IXMLRPCRequest), interface.Interface,
+                name=method.__name__)
+
 def register_views(context, views, templates):
     for factory in views:
         view_context = determine_class_context(factory, context)

Modified: grok/trunk/src/grok/ftests/test_grok_functional.py
===================================================================
--- grok/trunk/src/grok/ftests/test_grok_functional.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/ftests/test_grok_functional.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -56,7 +56,7 @@
 
 def test_suite():
     suite = unittest.TestSuite()
-    for name in ['view', 'static']:
+    for name in ['view', 'static', 'xmlrpc']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Added: grok/trunk/src/grok/ftests/xmlrpc/__init__.py
===================================================================
--- grok/trunk/src/grok/ftests/xmlrpc/__init__.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/ftests/xmlrpc/__init__.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -0,0 +1 @@
+# this is a package


Property changes on: grok/trunk/src/grok/ftests/xmlrpc/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Added: grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py
===================================================================
--- grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -0,0 +1,29 @@
+"""
+  >>> import grok
+  >>> grok.grok('grok.ftests.xmlrpc.xmlrpc')
+  >>> from grok.ftests.xmlrpc.xmlrpc import Mammoth
+  >>> getRootFolder()["Manfred"] = Mammoth()
+
+  >>> from grok.ftests.xmlrpc_helper import ServerProxy
+
+  >>> server = ServerProxy("http://localhost/")
+  >>> server.Manfred.stomp()
+  'Manfred stomped.'
+  >>> server.Manfred.dance()
+  "Manfred doesn't like to dance."
+
+"""
+import grok
+
+
+class Mammoth(grok.Model):
+    pass
+
+
+class MammothRPC(grok.XMLRPC):
+
+    def stomp(self):
+        return '%s stomped.' % self.context.__name__
+
+    def dance(self):
+        return '%s doesn\'t like to dance.' % self.context.__name__


Property changes on: grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Added: grok/trunk/src/grok/ftests/xmlrpc_helper.py
===================================================================
--- grok/trunk/src/grok/ftests/xmlrpc_helper.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/ftests/xmlrpc_helper.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -0,0 +1,75 @@
+# XXX This code is duplicated from Zope 3 trunk (future Zope 3.4) as we want to
+# stay compatible with Zope 3.3
+#
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""XMLRPC testing helpers for Zope 3.
+
+$Id$
+"""
+
+import StringIO
+import xmlrpclib 
+
+from zope.app.testing.functional import HTTPCaller
+
+
+class ZopeTestTransport(xmlrpclib.Transport):
+    """xmlrpclib transport that delegates to
+    zope.app.testing.functional.HTTPCaller.
+
+    It can be used like a normal transport, including support for basic
+    authentication.
+    """
+
+    verbose = False
+    handleErrors = True
+
+    def request(self, host, handler, request_body, verbose=0):
+        request = "POST %s HTTP/1.0\n" % (handler,)
+        request += "Content-Length: %i\n" % len(request_body)
+        request += "Content-Type: text/xml\n"
+
+        host, extra_headers, x509 = self.get_host_info(host)
+        if extra_headers:
+            request += "Authorization: %s\n" % (dict(extra_headers)["Authorization"],)
+
+        request += "\n" + request_body
+        response = HTTPCaller()(request, handle_errors=self.handleErrors)
+
+        errcode = response.getStatus()
+        errmsg = response.getStatusString()
+        # This is not the same way that the normal transport deals with the headers.
+        headers = response.getHeaders()
+
+        if errcode != 200:
+            raise xmlrpclib.ProtocolError(
+                host + handler,
+                errcode, errmsg,
+                headers
+                )
+
+        return self._parse_response(
+            StringIO.StringIO(response.getBody()), sock=None)
+
+
+def ServerProxy(uri, transport=ZopeTestTransport(), encoding=None,
+                verbose=0, allow_none=0, handleErrors=True):
+    """A factory that creates a server proxy using the ZopeTestTransport
+    by default.
+    
+    """
+    if isinstance(transport, ZopeTestTransport):
+        transport.handleErrors = handleErrors
+    return xmlrpclib.ServerProxy(uri, transport, encoding, verbose, allow_none)


Property changes on: grok/trunk/src/grok/ftests/xmlrpc_helper.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Modified: grok/trunk/src/grok/tests/test_grok.py
===================================================================
--- grok/trunk/src/grok/tests/test_grok.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/tests/test_grok.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -33,7 +33,7 @@
 def test_suite():
     suite = unittest.TestSuite()
     for name in ['adapter', 'error', 'view', 'security', 'scan',
-                 'event', 'zcml', 'static', 'utility']:
+                 'event', 'zcml', 'static', 'utility', 'xmlrpc']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Added: grok/trunk/src/grok/tests/xmlrpc/__init__.py
===================================================================
--- grok/trunk/src/grok/tests/xmlrpc/__init__.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/tests/xmlrpc/__init__.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -0,0 +1 @@
+# this is a package


Property changes on: grok/trunk/src/grok/tests/xmlrpc/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Added: grok/trunk/src/grok/tests/xmlrpc/nocontext.py
===================================================================
--- grok/trunk/src/grok/tests/xmlrpc/nocontext.py	2006-10-18 14:33:55 UTC (rev 70786)
+++ grok/trunk/src/grok/tests/xmlrpc/nocontext.py	2006-10-18 16:52:48 UTC (rev 70787)
@@ -0,0 +1,16 @@
+"""
+
+Context-determination follows the same rules as for adapters. We just check
+whether it's hooked up at all:
+
+  >>> grok.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: No module-level context for
+  <class 'grok.tests.xmlrpc.nocontext.HomeRPC'>, please use grok.context.
+
+"""
+import grok
+
+class HomeRPC(grok.XMLRPC):
+    pass


Property changes on: grok/trunk/src/grok/tests/xmlrpc/nocontext.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native



More information about the Checkins mailing list