[z3-checkins] r27069 - in z3/jsonserver/trunk: . tests

jwashin at codespeak.net jwashin at codespeak.net
Thu May 11 13:48:10 CEST 2006


Author: jwashin
Date: Thu May 11 13:48:07 2006
New Revision: 27069

Modified:
   z3/jsonserver/trunk/CHANGES.txt
   z3/jsonserver/trunk/VERSION.txt
   z3/jsonserver/trunk/jsoncomponent.py
   z3/jsonserver/trunk/jsonrpc.py
   z3/jsonserver/trunk/metaconfigure.py
   z3/jsonserver/trunk/tests/test_jsonrpcrequest.py
Log:
adjusted a few deprecated imports.  preliminary support for json-rpc 1.1


Modified: z3/jsonserver/trunk/CHANGES.txt
==============================================================================
--- z3/jsonserver/trunk/CHANGES.txt	(original)
+++ z3/jsonserver/trunk/CHANGES.txt	Thu May 11 13:48:07 2006
@@ -1,17 +1,20 @@
 #CHANGES.txt
 
-20051202 a bit of backward-compatibility with five:  
-    ++resource++ notation for the javascript.  updated to the available 
+20051202 a bit of backward-compatibility with five:
+    ++resource++ notation for the javascript.  updated to the available
     jsolait (2005-11-15.small)
 
-20051125 some work toward making json requests better zope citizens.  
+20051125 some work toward making json requests better zope citizens.
 Some work toward keyword parameter support.
-Some work toward making more information available in request: now 
-provides IBrowserApplicationRequest. This is experimental.  Let me 
+Some work toward making more information available in request: now
+provides IBrowserApplicationRequest. This is experimental.  Let me
 know what you think.
 
 20050921 Using the next beta of jsolait (20050914).  The init file is now
- jsolait.js instead of init.js.  jsolait installer adds init.js as a copy of jsolait.js
- for backwards compatibility.  We are now using the 3.1 ResourceDirectory,
- so the jsolait file structure does not need to be flattened. Upgrade to this 
- version using the installer is optional.  
+ jsolait.js instead of init.js.  jsolait installer adds init.js as a copy of
+ jsolait.js for backwards compatibility.  We are now using the 3.1
+ ResourceDirectory, so the jsolait file structure does not need to be flattened.
+ Upgrade to this version of jsolait using the installer is optional.
+
+20060511 Removed gzip support, since that can be done more elegantly by other
+ means.  Preliminary support for json-rpc 1.1.
\ No newline at end of file

Modified: z3/jsonserver/trunk/VERSION.txt
==============================================================================
--- z3/jsonserver/trunk/VERSION.txt	(original)
+++ z3/jsonserver/trunk/VERSION.txt	Thu May 11 13:48:07 2006
@@ -1 +1 @@
-jsonserver 3.2.2 svn
+jsonserver 3.3.0 svn

Modified: z3/jsonserver/trunk/jsoncomponent.py
==============================================================================
--- z3/jsonserver/trunk/jsoncomponent.py	(original)
+++ z3/jsonserver/trunk/jsoncomponent.py	Thu May 11 13:48:07 2006
@@ -17,6 +17,7 @@
 # jwashin 2005-07-27
 # 2005-10-09 updated to properly? handle unicode on the boundary
 # 2005-09-08 updated for modularity and IResult
+# 2006-05-11 allowed encoding param for reader
 
 import minjson as json
 from interfaces import IJSONReader, IJSONWriter
@@ -26,14 +27,14 @@
 class JSONReader(object):
     """component implementing JSON reading"""
     implements(IJSONReader)
-    
-    def read(self,aString, encoding='utf-8'):
+
+    def read(self,aString,encoding=None):
         return json.read(aString,encoding)
 
 
 class JSONWriter(object):
     """component implementing JSON writing"""
     implements(IJSONWriter)
-    
+
     def write(self,anObject):
         return json.write(anObject)

Modified: z3/jsonserver/trunk/jsonrpc.py
==============================================================================
--- z3/jsonserver/trunk/jsonrpc.py	(original)
+++ z3/jsonserver/trunk/jsonrpc.py	Thu May 11 13:48:07 2006
@@ -20,7 +20,7 @@
 #2005-09-08 updated to work with the new IResult idea (wsgi)
 #2005-10-09 unicode handling update
 #2006-03-09 enabled gzip compression for large responses
-#2006-04-27 updated to sync with z3 trunk changes jmw
+#2006-05-10 removed gzip compression and (prematurely) enabled json-rpc 1.1 jmw
 
 __docformat__ = 'restructuredtext'
 
@@ -29,23 +29,18 @@
     IJSONRPCRequest, IJSONReader, IJSONWriter
 from zope.interface import implements
 #from zope.publisher.http import IResult
-try:
-    from zope.location.location import Location
-except ImportError:
-    #deprecate this for 3.5
-    from zope.app.location.location import Location
+from zope.location.location import Location
 from zope.publisher.http import HTTPRequest, HTTPResponse, \
     getCharsetUsingRequest, DirectResult
 from zope.publisher.browser import BrowserRequest
 from zope.security.proxy import isinstance
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.interfaces.browser import IBrowserApplicationRequest
+from zope.component import getUtility
 try:
     from cStringIO import StringIO
 except ImportError:
     from StringIO import StringIO
-from zope.publisher.interfaces.browser import IBrowserRequest
-from zope.publisher.interfaces.browser import IBrowserApplicationRequest
-from zope.component import getUtility
-import gzip
 import traceback
 import logging
 
@@ -74,6 +69,9 @@
     def __call__(self):
         return self.__pub
 
+def intsort(item):
+    return int(item[0])
+
 class JSONRPCRequest(BrowserRequest):
     """a JSON-RPC Request
     modeled after zope.publisher.xmlrpc.XMLRPCRequest
@@ -106,9 +104,6 @@
         input = ''.join(input)
         #make it unicode; we are at the boundary
         input = self._decode(input)
-        #encoding = getCharsetUsingRequest(self)
-        #if not isinstance(input,unicode):
-        #    input = input.decode(encoding)
         data = json.read(input)
         if writeProfileData:
             infile = 'profiledata.js'
@@ -121,69 +116,57 @@
         # failure unless we split on '.' Why?
         function = functionstr.split('.')
         self.jsonID = data['id']
-        args = list(data['params'])
-        # now, look for keyword parameters
-        kwargs = None
-        notPositional = []
-        for k in args:
-            if isinstance(k,dict):
-                if k.has_key(keyword_key):
-                    if isinstance(k[keyword_key],dict):
-                        j = k[keyword_key]
-                        kwargs= j
-                        notPositional.append(k)
-        if notPositional:
-            for k in notPositional:
-                args.remove(k)
-        if kwargs:
-            for m in kwargs.keys():
-                self.form[str(m)] = kwargs[m]
+        params = data['params']
+        if isinstance(params,list):
+            args = params
+            # now, look for keyword parameters, the old way
+            kwargs = None
+            notPositional = []
+            for k in args:
+                if isinstance(k,dict):
+                    if k.has_key(keyword_key):
+                        if isinstance(k[keyword_key],dict):
+                            j = k[keyword_key]
+                            kwargs= j
+                            notPositional.append(k)
+            if notPositional:
+                for k in notPositional:
+                    args.remove(k)
+            if kwargs:
+                for m in kwargs.keys():
+                    self.form[str(m)] = kwargs[m]
+        elif isinstance(params,dict):
+            #json-rpc 1.1 (to be proposed)
+            #get the numeric params for positional params
+            temp_positional = []
+            for key in params:
+                if key.isdigit():
+                    temp_positional.append((key,params[key]))
+            temp_positional.sort(key=intsort)
+            args = []
+            #make args from positional args and remove them from params
+            for item in temp_positional:
+                args.append(item[1])
+                del params[item[0]]
+            #drop remaining named params into request.form
+            for named_param in params:
+                #named_param is unicode; python needs string for param names
+                self.form[str(named_param)] = params[named_param]
+        else:
+            raise TypeError, 'Unsupported type for JSON-RPC "params" (%s)' \
+                % type(params)
         self._args = tuple(args)
         #make environment,cookies, etc., available to request.get()
         super(JSONRPCRequest,self).processInputs()
         self._environ['JSONRPC_MODE'] = True
         if function:
             self.setPathSuffix(function)
-
     def traverse(self,object):
         return super(BrowserRequest,self).traverse(object)
 
     def __getitem__(self,key):
         return self.get(key)
 
-# IResult has gone PRIVATE; for we now will send a bytestring and set
-# charset.
-
-##class JSONResult(object):
-##    implements(IResult)
-##    def __init__(self,aString, encoding='utf-8'):
-##        #statements to help figure out Opera
-##        #encoding='utf-8'  #yields oriental charset, unparseable
-##        #encoding='utf-16' #yields something that looks like the right code,
-##        #    no trouble in gecko, but opera refuses to parse it
-##        #encoding = None is troublesome for gecko; only get '{'
-##        #encoding = 'iso-8859-1'
-##        try:
-##            s= aString.encode(encoding)
-##        except UnicodeEncodeError:
-##            s = aString
-##        self.body = [s]
-##        if encoding == 'utf-8':
-##            # don't need charset for utf-8; charset handling seems buggy on
-##            # some browsers, so best not to use unnecessarily
-##            self.headers = [('content-type',
-##            'application/x-javascript'),
-##            ('content-length',str(len(s)))]
-##        else:
-##            self.headers = [('content-type',
-##            'application/x-javascript;charset=%s' % encoding),
-##            ('content-length',str(len(s)))]
-####        else:
-####            self.body = [aString]
-####            self.headers = [('content-type','application/x-javascript'),
-####                ('content-length',str(len(aString)))]
-##
-
 class JSONRPCResponse(HTTPResponse):
     """JSON-RPC Response
     modeled after zope.publisher.xmlrpc.XMLRPCResponse
@@ -222,31 +205,16 @@
             super(JSONRPCResponse,self).setResult('')
 
     def _prepareResult(self,result):
-        #we've asked json to return unicode.  result should be unicode
-
+        #we've asked json to return unicode; result should be unicode
         encoding = getCharsetUsingRequest(self._request) or 'utf-8'
+        #at outgoing boundary; encode it.
         if isinstance(result,unicode):
             body = result.encode(encoding)
             charset = encoding
         else:
             #something's wrong.  json did not return unicode.
-            raise AttributeError
-
-        #let's gzip compress it if it's big.
-        #thanks to Alan Kennedy http://www.xhaus.com/alan/python/httpcomp.html
-        compress_type = self._request.getHeader('Accept-Encoding', [])
-        bodyLength = len(body)
-        if 'gzip' in compress_type and bodyLength > compressionTrigger:
-            #using cStringIO, but OK, because we have a byte string here
-            zbuf = StringIO()
-            zfile = gzip.GzipFile(mode='wb', fileobj=zbuf,
-                    compresslevel=compressionLevel)
-            zfile.write(body)
-            zfile.close()
-            body = zbuf.getvalue()
-            #a = len(body)
-            #print "before %s after %s" % (bodyLength,a)
-            self.setHeader('content-encoding','gzip')
+            raise TypeError, "JSON did not return unicode (%s)" % type(result)
+        #we used to gzip compress here, but that should be decided elsewhere
         self.setHeader('content-type',"application/x-javascript;charset=%s" \
             % charset)
         return body
@@ -355,4 +323,3 @@
 
         super(TestRequest, self).__init__(
             body_instream, _testEnv, response)
-

Modified: z3/jsonserver/trunk/metaconfigure.py
==============================================================================
--- z3/jsonserver/trunk/metaconfigure.py	(original)
+++ z3/jsonserver/trunk/metaconfigure.py	Thu May 11 13:48:07 2006
@@ -17,7 +17,6 @@
 
 like zope.app.publisher.xmlrpc.metaconfigure
 
-Updated 2006-04-27 to sync with zope3 trunk jmw
 updated 2005-12-03 Roger Ineichen
 jwashin 2005-06-06
 """
@@ -28,7 +27,7 @@
 from interfaces import IJSONRPCRequest
 
 from zope.component.interface import provideInterface
-from zope.component.zcml import handler
+from zope.app.component.metaconfigure import handler
 from jsonrpc import MethodPublisher
 
 def view(_context, for_=None, interface=None, methods=None,
@@ -58,7 +57,8 @@
     # Make sure that the class inherits MethodPublisher, so that the views
     # have a location
     if class_ is None:
-        class_ = original_class = MethodPublisher
+        class_ = MethodPublisher
+        original_class = class_
     else:
         original_class = class_
         class_ = type(class_.__name__, (class_, MethodPublisher), {})
@@ -83,8 +83,8 @@
         _context.action(
             discriminator = ('view', for_, name, IJSONRPCRequest),
             callable = handler,
-            args = ('registerAdapter',
-                    class_, (for_, IJSONRPCRequest), Interface, name,
+            args = ('provideAdapter',
+                    (for_, IJSONRPCRequest), Interface, name, class_,
                     _context.info)
             )
     else:
@@ -101,8 +101,8 @@
             _context.action(
                 discriminator = ('view', for_, name, IJSONRPCRequest),
                 callable = handler,
-                args = ('registerAdapter',
-                        new_class, (for_, IJSONRPCRequest), Interface, name,
+                args = ('provideAdapter',
+                        (for_, IJSONRPCRequest), Interface, name, new_class,
                         _context.info)
                 )
 

Modified: z3/jsonserver/trunk/tests/test_jsonrpcrequest.py
==============================================================================
--- z3/jsonserver/trunk/tests/test_jsonrpcrequest.py	(original)
+++ z3/jsonserver/trunk/tests/test_jsonrpcrequest.py	Thu May 11 13:48:07 2006
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. 
+# Copyright (c) 2001 - 2005 Zope Corporation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -14,6 +14,8 @@
 """JSON-RPC Request Tests
 modified from zope/publisher/tests/test_xmlrpcrequest.py jwashin 2005-06-06
 """
+#2006-05-10 updated to test json-rpc1.1 jmw
+
 import unittest
 from StringIO import StringIO
 
@@ -55,6 +57,17 @@
         self.body = '{"id":"httpReq","method":"keyworded","params":[1,{"pythonKwMaRkEr":{"kw1":"aaa"}}]}'
         self.headers = []
 
+class Param1_1SpecTestCall1:
+    def __init__(self):
+        self.body = '{"id":"httpReq","method":"keyworded","params":{"1":1,"kw1":"aaa"}}'
+        self.headers = []
+
+class Param1_1SpecTestCall2:
+    def __init__(self):
+        self.body = '{"id":"httpReq","method":"action1_1","params":{"1":1,"kw1":"aaa"}}'
+        self.headers = []
+
+
 class JSONRPCTests(unittest.TestCase):
     """The only thing different to HTTP is the input processing; so there
        is no need to redo all the HTTP tests again.
@@ -92,14 +105,18 @@
 
         class View(object):
 
-            def action(self, a):
+            def action(self, a, kw1=None):
                 return "Parameter[type: %s; value: %s" %(
                     type(a).__name__, `a`)
-                    
+
             def keyworded(self, a, kw1="spam"):
                 return "kw1: [type: %s; value: %s]" %(
                     type(kw1).__name__, `kw1`)
-            
+
+            def action1_1(self, a, kw1=None):
+                return "Parameter[type: %s; value: %s" %(
+                    type(a).__name__, `a`)
+
         class Item2(object):
             view = View()
 
@@ -135,14 +152,28 @@
         action = req.traverse(self.app)
         self.failUnlessEqual(action(*req._args),
                              "Parameter[type: int; value: 1")
-                             
+
     def testKeyword(self):
         req = self._createRequest({}, ParamTestCall())
         req.processInputs()
         action = req.traverse(self.app)
         self.failUnlessEqual(action(*req._args, **req.form),
                              "kw1: [type: unicode; value: u'aaa']")
-                             
+
+    def test1_1spec_kw(self):
+        req = self._createRequest({}, Param1_1SpecTestCall1())
+        req.processInputs()
+        action = req.traverse(self.app)
+        self.failUnlessEqual(action(*req._args, **req.form),
+                             "kw1: [type: unicode; value: u'aaa']")
+
+    def test1_1spec2_p(self):
+        req = self._createRequest({}, Param1_1SpecTestCall2())
+        req.processInputs()
+        action = req.traverse(self.app)
+        self.failUnlessEqual(action(*req._args, **req.form),
+                             "Parameter[type: int; value: 1")
+
     def testJSONRPCMode(self):
         req = self._createRequest({}, jsonrpc_call)
         req.processInputs()


More information about the z3-checkins mailing list