[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