[Checkins] SVN: z3c.jsonrpc/trunk/ Implemented JSON-RPC 2.0
specification. Use JSON-RPC 2.0 version as default.
Roger Ineichen
roger at projekt01.ch
Sat Aug 2 08:51:33 EDT 2008
Log message for revision 89216:
Implemented JSON-RPC 2.0 specification. Use JSON-RPC 2.0 version as default.
Changed:
U z3c.jsonrpc/trunk/CHANGES.txt
U z3c.jsonrpc/trunk/buildout.cfg
U z3c.jsonrpc/trunk/src/z3c/jsonrpc/README.txt
A z3c.jsonrpc/trunk/src/z3c/jsonrpc/exception.py
U z3c.jsonrpc/trunk/src/z3c/jsonrpc/publication.py
U z3c.jsonrpc/trunk/src/z3c/jsonrpc/publisher.py
U z3c.jsonrpc/trunk/src/z3c/jsonrpc/testing.py
U z3c.jsonrpc/trunk/src/z3c/jsonrpc/tests/test_request.py
-=-
Modified: z3c.jsonrpc/trunk/CHANGES.txt
===================================================================
--- z3c.jsonrpc/trunk/CHANGES.txt 2008-08-02 12:50:14 UTC (rev 89215)
+++ z3c.jsonrpc/trunk/CHANGES.txt 2008-08-02 12:51:33 UTC (rev 89216)
@@ -2,16 +2,23 @@
CHANGES
=======
-0.5.2 (unreleased)
-------------------
+Version 0.5.2dev (unreleased)
+-----------------------------
-- Make progress with JSON-RPC 2.0 sepcification implementation
+- Implemented JSON-RPC 2.0 specification. Use JSON-RPC 2.0 version as default.
+ Optional the version 1.0 and 1.1 can be set. See JSON-RPC 2.0 specification
+ for more information.
+- Added initial version of JSON-RPC exceptions.
+
+- Added explicit test cleanup since some zope testing change left over a global
+ adapter registry from old conections
+
- Removed unused dependency to z3c.layer in test setup
-0.5.1 (2008-01-24)
-------------------
+Version 0.5.1 (2008-01-24)
+--------------------------
- Improve meta-data.
@@ -19,7 +26,7 @@
reverted.
-0.5.0 (2008-01-21)
-------------------
+Version 0.5.0 (2008-01-21)
+--------------------------
- Initial Release
Modified: z3c.jsonrpc/trunk/buildout.cfg
===================================================================
--- z3c.jsonrpc/trunk/buildout.cfg 2008-08-02 12:50:14 UTC (rev 89215)
+++ z3c.jsonrpc/trunk/buildout.cfg 2008-08-02 12:51:33 UTC (rev 89216)
@@ -1,5 +1,6 @@
[buildout]
develop = .
+ ../z3c.json
parts = test checker coverage
find-links = http://pypi.python.org/simple/z3c.json/
Modified: z3c.jsonrpc/trunk/src/z3c/jsonrpc/README.txt
===================================================================
--- z3c.jsonrpc/trunk/src/z3c/jsonrpc/README.txt 2008-08-02 12:50:14 UTC (rev 89215)
+++ z3c.jsonrpc/trunk/src/z3c/jsonrpc/README.txt 2008-08-02 12:51:33 UTC (rev 89216)
@@ -95,10 +95,17 @@
... def greeting(self, name):
... return u"Hello %s" % name
...
- ... def kwarguments(self, prefix, foo=None, bar=None):
+ ... def mixedparams(self, prefix, bar=None, foo=None):
... # Note; keyword arguments can be found in request.form
- ... return u"%s %s %s" % (prefix, foo, bar)
+ ... return u"%s %s %s" % (prefix, bar, foo)
...
+ ... def kws(self, adam=None, foo=None, bar=None):
+ ... # Note; keyword arguments can be found in request.form
+ ... a = self.request.get('adam')
+ ... b = self.request.form.get('foo')
+ ... c = self.request.form.get('bar')
+ ... return u"%s %s %s" % (a, b, c)
+ ...
... def showId(self):
... return u"The json id is: %s" % self.request.jsonId
...
@@ -130,10 +137,17 @@
... def greeting(self, name):
... return u"Hello %s" % name
...
- ... def kwarguments(self, prefix, foo=None, bar=None):
+ ... def mixedparams(self, prefix, foo=None, bar=None):
... # Note; keyword arguments can be found in request.form
... return u"%s %s %s" % (prefix, foo, bar)
...
+ ... def kws(self, adam=None, foo=None, bar=None):
+ ... # Note; keyword arguments can be found in request.form
+ ... a = self.request.get('adam')
+ ... b = self.request.form.get('foo')
+ ... c = self.request.form.get('bar')
+ ... return u"%s %s %s" % (a, b, c)
+ ...
... def showId(self):
... return u"The json id is: %s" % self.request.jsonId
...
@@ -164,7 +178,7 @@
... for="custom.IDemoContent"
... class="custom.DemoView"
... permission="zope.Public"
- ... methods="hello greeting kwarguments showId forceValueError"
+ ... methods="hello greeting mixedparams kws showId forceValueError"
... layer="z3c.jsonrpc.testing.IJSONRPCTestSkin"
... />
... </configure>
@@ -188,7 +202,7 @@
... for="custom.IDemoContainer"
... class="custom.DemoContainerView"
... permission="zope.Public"
- ... methods="available greeting kwarguments showId forceValueError"
+ ... methods="available greeting mixedparams kws showId forceValueError"
... layer="z3c.jsonrpc.testing.IJSONRPCTestSkin"
... />
... </configure>
@@ -267,14 +281,21 @@
>>> proxy.greeting(u'Jessy')
u'Hello Jessy'
-Now let's make a remote procedure call with a kw arguments. Note that this
-key word arguments are stored in the request.form. But this doesn't change
-anything because this varaibles are also accessible like form variables e.g.
-self.request['foo'].Also note that we don't support the **kw signature:
+Note that this key word arguments are stored in the request.form. Important
+to know is that JSON-RPC does not support positional and named arguments in
+one method call. We are working on a solution for solve that restriction which
+hurts us as python developer.
- >>> proxy.kwarguments('Hello', foo=u'FOO', bar=u'BAR')
- u'Hello FOO BAR'
+ >>> proxy.mixedparams('Hello', foo=u'FOO', bar=u'BAR')
+ Traceback (most recent call last):
+ ...
+ ValueError: Mixing positional and named parameters in one call is not possible
+Let's call named arguments:
+
+ >>> proxy.kws(bar=u'BAR', foo=u'FOO')
+ u'None FOO BAR'
+
There is also an ``id`` in the json response. Let's use such a json request id
in our JSONRPCProxy:
@@ -297,7 +318,7 @@
and the error message is:
>>> proxy.error
- u'ValueError: Something was wrong in server method.'
+ {u'message': u'Invalid JSON-RPC', u'code': -32603, u'data': u'ValueError: Something was wrong in server method.'}
The error property gets reset on the next successfull call:
Added: z3c.jsonrpc/trunk/src/z3c/jsonrpc/exception.py
===================================================================
--- z3c.jsonrpc/trunk/src/z3c/jsonrpc/exception.py (rev 0)
+++ z3c.jsonrpc/trunk/src/z3c/jsonrpc/exception.py 2008-08-02 12:51:33 UTC (rev 89216)
@@ -0,0 +1,53 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+
+
+# The error codes used since JSON-RPC 2.0:
+#
+# code message Meaning
+# --------------------------------
+# -32700 Parse error. Invalid JSON. An error occurred on the server
+# while parsing the JSON text.
+# -32600 Invalid Request. The received JSON not a valid JSON-RPC Request.
+# -32601 Method not found. The requested remote-procedure does not exist,
+# is not available.
+# -32602 Invalid params. Invalid method parameters.
+# -32603 Internal error. Internal JSON-RPC error.
+# -32099..-32000 Server error. Reserved for implementation-defined server-errors.
+
+class JSONRPCException(Exception):
+ """Base class for JSON-RPC exception."""
+
+
+class ParseError(JSONRPCException):
+ """Invalid JSON. An error occurred on the server while parsing the JSON text."""
+
+
+class InvalidRequest(JSONRPCException):
+ """The received JSON not a valid JSON-RPC Request. """
+
+
+class MethodNotFound(JSONRPCException):
+ """The requested remote-procedure does not exist, is not available."""
+
+
+class InvalidParams(JSONRPCException):
+ """Invalid method parameters."""
+
+
+class InternalError(JSONRPCException):
+ """Internal JSON-RPC error."""
Property changes on: z3c.jsonrpc/trunk/src/z3c/jsonrpc/exception.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: z3c.jsonrpc/trunk/src/z3c/jsonrpc/publication.py
===================================================================
--- z3c.jsonrpc/trunk/src/z3c/jsonrpc/publication.py 2008-08-02 12:50:14 UTC (rev 89215)
+++ z3c.jsonrpc/trunk/src/z3c/jsonrpc/publication.py 2008-08-02 12:51:33 UTC (rev 89216)
@@ -18,7 +18,6 @@
import zope.interface
import zope.component
-
from zope.app.publication.http import BaseHTTPPublication
from zope.app.publication.interfaces import IRequestPublicationFactory
@@ -32,7 +31,6 @@
zope.interface.implements(interfaces.IJSONRPCPublication)
-
class JSONRPCFactory(object):
zope.interface.implements(IRequestPublicationFactory)
Modified: z3c.jsonrpc/trunk/src/z3c/jsonrpc/publisher.py
===================================================================
--- z3c.jsonrpc/trunk/src/z3c/jsonrpc/publisher.py 2008-08-02 12:50:14 UTC (rev 89215)
+++ z3c.jsonrpc/trunk/src/z3c/jsonrpc/publisher.py 2008-08-02 12:51:33 UTC (rev 89216)
@@ -35,6 +35,8 @@
from z3c.jsonrpc import interfaces
from z3c.jsonrpc.interfaces import JSON_CHARSETS
+JSON_RPC_VERSION = '2.0'
+
DEBUG = logging.DEBUG
logger = logging.getLogger()
@@ -75,9 +77,33 @@
class JSONRPCRequest(HTTPRequest):
- """JSON-RPC request implementation based on IHTTPRequest."""
+ """JSON-RPC request implementation based on IHTTPRequest.
+
+ This implementation supports the following JSON-RPC Specification versions:
+
+ - 1.0
+ - 1.1
+ - 2.0
+
+ Version 1.0 and 1.1 offers params as a list. This params get converted to
+ positional arguments if calling the JSON-RPC function.
+
+ The version 2.0 offers support for named key/value params. The important
+ thing to know is that this implementation will convert named params kwargs
+ to form paramters. This means the method doesn't get any key word argument.
+ The reason why I was choosing is the existing publisher implementation and
+ it's debugger integration. If someone likes to integrate **kwargs support,
+ take a look at the publisher.publish method and it's mapply function which
+ get wrapped by the Debugger class. I hope that's fine for now and I
+ recommend to avoid kwargs for JSON-RPC methods ;-)
+ The z3c.jsonrpcclient JavaScript method JSONRPCProxy converts a
+ typeof object as arguments[0] to named key/value pair arguments.
+
+ """
+
_jsonId = 'jsonrpc'
+ jsonVersion = JSON_RPC_VERSION
jsonId = None
zope.interface.implements(interfaces.IJSONRPCRequest,
@@ -121,17 +147,27 @@
# ensure unicode
if not isinstance(input, unicode):
input = self._decode(input)
- data = json.read(input)
+ try:
+ data = json.read(input)
+ except:
+ # catch any error since we don't know which library is used as
+ # parser
+ raise ParseError
+ # get the params
+ params = data['params']
if self.jsonId is None:
self.jsonId = data.get('id', self._jsonId)
- params = data['params']
- if isinstance(params, list):
- # json-rpc 1.0
+ # get the json version. The version 1.0 offers no version argument.
+ # The version 1.1 offers a version key and since version 2.0 the
+ # version is given with the ``jsonrpc`` key. Let's try to find the
+ # version for our request.
+ self.jsonVersion = data.get('version', self.jsonVersion)
+ self.jsonVersion = data.get('jsonrpc', self.jsonVersion)
+ if self.jsonVersion in ['1.0', '1.1']:
+ # json-rpc 1.0 and 1.1
args = params
- # now, look for keyword parameters, the old way
- kwargs = None
- notPositional = []
+ # version 1.0 and 1.1 uses a list of arguments
for arg in args:
if isinstance(arg, dict):
# set every dict key value as form items and support at
@@ -144,39 +180,75 @@
match = self._typeFormat.match(key, pos + 1)
if match is not None:
key, type_name = key[:pos], key[pos + 1:]
- if type_name == 'list':
+ if type_name == 'list' and not isinstance(d, list):
d = [d]
- if type_name == 'tuple':
+ if type_name == 'tuple' and not isinstance(d, tuple):
d = tuple(d)
self.form[key] = d
- elif isinstance(params, dict):
- # json-rpc 1.2
- # Note: the JSONRPCProxy uses allways a dict for params. This means
- # we only use this part for extract the data.
+
+ elif self.jsonVersion == '2.0':
+ # version 2.0 uses a list or a dict as params. Process the list
+ # params here. This params get used as positional arguments in the
+ # method call.
+ if isinstance(params, list):
+ args = params
+ # now, look for keyword parameters, the old way
+ for arg in args:
+ if isinstance(arg, dict):
+ # set every dict key value as form items and support at
+ # least ``:list`` and ``:tuple`` input field name postifx
+ # conversion.
+ for key, d in arg.items():
+ key = str(key)
+ pos = key.rfind(":")
+ if pos > 0:
+ match = self._typeFormat.match(key, pos + 1)
+ if match is not None:
+ key, type_name = key[:pos], key[pos + 1:]
+ if type_name == 'list' and not isinstance(d, list):
+ d = [d]
+ if type_name == 'tuple' and not isinstance(d, tuple):
+ d = tuple(d)
+ self.form[key] = d
- # Get the numeric params for positional params
- # This was proposed for json-rpc 1.1 but seems not get accepted.
- # The new 2.0 proposal only defines named paramters if they get
- # applied as key/value pair.
-
- # review and check this implementation after JSON-RPC 2.0 final
- temp_positional = []
- for key in params:
- if str(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]
+ elif isinstance(params, dict):
+ # process the key/value pair params. This arguments get stored
+ # in the request.form argument and we skip it from method calls.
+ # This means this library will not support key word arguments
+ # for method calls. It will instead store them in the form.
+ # This has two reasons.
+ # 1. Zope doesn't support kwargs in the publication
+ # implementation. It only supports positional arguments
+ # 2. The JSON-RPC specification doesn't allow to use positional
+ # and keyword arguments on one method call
+ # 3. Python doesn't allow to convert kwargs to positional
+ # arguments because a dict doesn't provide an order
+ # This means you should avoid to call a method with kwargs.
+ # just use positional arguments if possible. Or get them from
+ # directly from the request or request.form argument in your
+ # code. Let me know if this is a real problem for you and you
+ # like to implement a different kwarg handling. We have some
+ # ideas for add support for this.
+ args = params
+ # set every dict key value as form items and support at
+ # least ``:list`` and ``:tuple`` input field name postifx
+ # conversion.
+ for key, d in args.items():
+ key = str(key)
+ pos = key.rfind(":")
+ if pos > 0:
+ match = self._typeFormat.match(key, pos + 1)
+ if match is not None:
+ key, type_name = key[:pos], key[pos + 1:]
+ if type_name == 'list' and not isinstance(d, list):
+ d = [d]
+ if type_name == 'tuple' and not isinstance(d, tuple):
+ d = tuple(d)
+ self.form[key] = d
+ args = []
else:
- raise TypeError, 'Unsupported type for JSON-RPC "params" (%s)' \
- % type(params)
+ raise TypeError, 'Unsupported JSON-RPC version (%s)' % \
+ self.jsonVersion
self._args = tuple(args)
# make environment, cookies, etc., available to request.get()
super(JSONRPCRequest,self).processInputs()
@@ -208,7 +280,7 @@
return result
return super(JSONRPCRequest, self).get(key, default)
- def __getitem__(self,key):
+ def __getitem__(self, key):
return self.get(key)
@@ -219,26 +291,38 @@
def setResult(self, result):
"""The result dict contains the following key value pairs
+ The version 1.0 and 1.1 provides a response dict with the following
+ arguments:
+
id -- json request id
result -- result or null on error
error -- error or null if result is Ok
+ The version 2.0 provides a response dict with the following named
+ paramters:
+
+ jsonrpc -- jsonrpc version 2.0 or higher in future versions
+ id -- json request id
+ result -- result if no error is raised
+ error -- error if any given
+
"""
- id = self._request.jsonId
- if id is not None:
- result = premarshal(result)
- wrapper = {'id': id}
- wrapper['result'] = result
- wrapper['error'] = None
- json = zope.component.getUtility(IJSONWriter)
- encoding = getCharsetUsingRequest(self._request)
- result = json.write(wrapper)
- body = self._prepareResult(result)
- super(JSONRPCResponse,self).setResult(body)
- logger.log(DEBUG, "%s" % result)
+ jsonId = self._request.jsonId
+ jsonVersion = self._request.jsonVersion
+ result = premarshal(result)
+ if jsonVersion == 1.0:
+ wrapper = {'result': result, 'error': None, 'id': jsonId}
+ elif jsonVersion == 1.1:
+ wrapper = {'version': jsonVersion, 'result': result, 'error': None,
+ 'id': jsonId}
else:
- self.setStatus(204)
- super(JSONRPCResponse,self).setResult('')
+ wrapper = {'jsonrpc': jsonVersion, 'result': result, 'id': jsonId}
+ json = zope.component.getUtility(IJSONWriter)
+ encoding = getCharsetUsingRequest(self._request)
+ result = json.write(wrapper)
+ body = self._prepareResult(result)
+ super(JSONRPCResponse,self).setResult(body)
+ logger.log(DEBUG, "%s" % result)
def _prepareResult(self, result):
# we've asked json to return unicode; result should be unicode
@@ -269,9 +353,25 @@
exc_data.append( "** %s: %s" % exc_info[:2])
logger.log(logging.ERROR, "\n".join(exc_data))
s = '%s: %s' % (getattr(t, '__name__', t), value)
- wrapper = {'id': self._request.jsonId}
- wrapper['result'] = None
- wrapper['error'] = s
+ if self._request.jsonVersion == 1.0:
+ wrapper = {'result': None,
+ 'error': s,
+ 'id': self._request.jsonId,}
+ elif self._request.jsonVersion == 1.1:
+ wrapper = {'version': self._request.jsonVersion,
+ 'result': None,
+ 'error': s,
+ 'id': self._request.jsonId,}
+ else:
+ # TODO: implement better error handling, use the right error codes.
+ # see:
+ # http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal#error-object
+ wrapper = {'jsonrpc': self._request.jsonVersion,
+ 'error': {'code': -32603,
+ 'message': 'Invalid JSON-RPC',
+ 'data': s},
+ 'id': self._request.jsonId}
+
json = zope.component.getUtility(IJSONWriter)
result = json.write(wrapper)
body = self._prepareResult(result)
Modified: z3c.jsonrpc/trunk/src/z3c/jsonrpc/testing.py
===================================================================
--- z3c.jsonrpc/trunk/src/z3c/jsonrpc/testing.py 2008-08-02 12:50:14 UTC (rev 89215)
+++ z3c.jsonrpc/trunk/src/z3c/jsonrpc/testing.py 2008-08-02 12:51:33 UTC (rev 89216)
@@ -20,9 +20,9 @@
import persistent
import zope.interface
+import zope.testing.cleanup
from zope.testing import doctest
from zope.app.testing import functional
-from zope.app.testing.functional import HTTPCaller
from z3c.json.interfaces import IJSONReader
from z3c.json.converter import JSONReader
@@ -206,19 +206,15 @@
# Doctest setup
#
###############################################################################
-
-def FunctionalDocFileSuite(*paths, **kw):
+def _prepare_doctest_keywords(kw):
globs = kw.setdefault('globs', {})
globs['http'] = HTTPCaller()
globs['getRootFolder'] = functional.getRootFolder
globs['sync'] = functional.sync
- kw['package'] = doctest._normalize_module(kw.get('package'))
-
kwsetUp = kw.get('setUp')
def setUp(test):
functional.FunctionalTestSetup().setUp()
-
if kwsetUp is not None:
kwsetUp(test)
kw['setUp'] = setUp
@@ -231,11 +227,19 @@
kw['tearDown'] = tearDown
if 'optionflags' not in kw:
- kw['optionflags'] = (doctest.ELLIPSIS
+ old = doctest.set_unittest_reportflags(0)
+ doctest.set_unittest_reportflags(old)
+ kw['optionflags'] = (old
+ | doctest.ELLIPSIS
| doctest.REPORT_NDIFF
| doctest.NORMALIZE_WHITESPACE)
- suite = functional.FunctionalDocFileSuite(*paths, **kw)
+
+def FunctionalDocFileSuite(*paths, **kw):
+ # use our custom HTTPCaller and layer
+ kw['package'] = doctest._normalize_module(kw.get('package'))
+ _prepare_doctest_keywords(kw)
+ suite = doctest.DocFileSuite(*paths, **kw)
suite.layer = JSONRPCTestingLayer
return suite
@@ -290,11 +294,11 @@
#
###############################################################################
-
-
def setUp(test):
setUpTestAsModule(test, name='README')
def tearDown(test):
+ # ensure that we cleanup everything
+ zope.testing.cleanup.cleanUp()
tearDownTestAsModule(test)
Modified: z3c.jsonrpc/trunk/src/z3c/jsonrpc/tests/test_request.py
===================================================================
--- z3c.jsonrpc/trunk/src/z3c/jsonrpc/tests/test_request.py 2008-08-02 12:50:14 UTC (rev 89215)
+++ z3c.jsonrpc/trunk/src/z3c/jsonrpc/tests/test_request.py 2008-08-02 12:51:33 UTC (rev 89216)
@@ -32,12 +32,7 @@
require_docstrings = 0
- def getDefaultTraversal(self, request, ob):
- if hasattr(ob, 'browserDefault'):
- return ob.browserDefault(request)
- return ob, ()
-
class TestJSONRPCRequest(JSONRPCRequest, HTTPCharsets):
"""Make sure that our request also implements IHTTPCharsets, so that we do
not need to register any adapters."""
@@ -47,33 +42,18 @@
JSONRPCRequest.__init__(self, *args, **kw)
-class TestCall:
+class PositionalTestCall:
def __init__(self):
- self.body = '{"id":"httpReq","method":"action","params":[1]}'
+ self.body = '{"jsonrpc":"2.0","id":"httpReq","method":"positional","params":["aaa","bbb"]}'
self.headers = []
-jsonrpc_call = TestCall()
-
-
-class ParamTestCall:
+class NamedTestCall:
def __init__(self):
- self.body = '{"id":"httpReq","method":"keyworded","params":[{"kw1":"aaa"}]}'
+ self.body = '{"jsonrpc":"2.0","id":"httpReq","method":"named","params":{"kw1":"aaa","kw2":"bbb"}}'
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.
@@ -104,28 +84,36 @@
class Item(object):
def __call__(self, a, b):
- return "%s, %s" % (`a`, `b`)
+ return "%s, %s" % (a, b)
def doit(self, a, b):
return 'do something %s %s' % (a, b)
class View(object):
- def action(self, a, kw1=None):
- return "Parameter[type: %s; value: %s" %(
- type(a).__name__, `a`)
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
- def keyworded(self, a, kw1="spam"):
- return "kw1: [type: %s; value: %s]" %(
- type(kw1).__name__, `kw1`)
+ def positional(self, a, b):
+ return "Parameter: a; type: %s; value: %s" %(
+ type(a).__name__, a)
- def action1_1(self, a, kw1=None):
- return "Parameter[type: %s; value: %s" %(
- type(a).__name__, `a`)
+ def named(self, kw1=None, kw2=None):
+ kw1 = self.request.get('kw1', kw1)
+ kw2 = self.request.get('kw2', kw2)
+ return "Keyword: kw1; type: %s; value: %s] " \
+ "Keyword: kw2; type: %s; value: %s]" %(
+ type(kw1).__name__, kw1, type(kw2).__name__, kw2)
class Item2(object):
- view = View()
+ request = None
+
+ @property
+ def view(self):
+ return View(self, self.request)
+
self.app = AppRoot()
self.app.folder = Folder()
self.app.folder.item = Item()
@@ -137,7 +125,6 @@
env.update(extra_env)
if len(body.body):
env['CONTENT_LENGTH'] = str(len(body.body))
-
publication = Publication(self.app)
instream = StringIO(body.body)
request = TestJSONRPCRequest(instream, env)
@@ -146,42 +133,31 @@
def testProcessInput(self):
- req = self._createRequest({}, jsonrpc_call)
+ req = self._createRequest({}, PositionalTestCall())
+ self.app.folder.item2.request = req
req.processInputs()
- self.failUnlessEqual(req._args, (1,))
- self.failUnlessEqual(tuple(req._path_suffix), ('action',))
+ self.failUnlessEqual(req._args, (u'aaa', u'bbb'))
+ self.failUnlessEqual(tuple(req._path_suffix), ('positional',))
-
- def testTraversal(self):
- req = self._createRequest({}, jsonrpc_call)
+ def testPositional(self):
+ req = self._createRequest({}, PositionalTestCall())
+ self.app.folder.item2.request = req
req.processInputs()
action = req.traverse(self.app)
self.failUnlessEqual(action(*req._args),
- "Parameter[type: int; value: 1")
+ 'Parameter: a; type: unicode; value: aaa')
def testKeyword(self):
- req = self._createRequest({}, ParamTestCall())
+ req = self._createRequest({}, NamedTestCall())
+ self.app.folder.item2.request = req
req.processInputs()
action = req.traverse(self.app)
self.failUnlessEqual(action(*req._args, **req.form),
- "kw1: [type: unicode; value: u'aaa']")
+ u'Keyword: kw1; type: unicode; value: aaa] Keyword: kw2; type: unicode; value: bbb]')
- 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 = self._createRequest({}, PositionalTestCall())
+ self.app.folder.item2.request = req
req.processInputs()
self.failUnlessEqual(req['JSONRPC_MODE'],True)
More information about the Checkins
mailing list