Olemis Lang avatar Olemis Lang committed 935c332

Method object reuse and keyword args in call. All tests ... [ok]

Comments (0)

Files changed (3)

+
+# Including keyword args in Method class
+t0000/t0000-kwdargs-r7971.diff
+t0000/t0000-reuse-method-r7971.diff
 
 
 # http://trac-hacks.org/ticket/1055

t0000/t0000-kwdargs-r7971.diff

+Introducing keyword args in instances of Method class
+
+diff -r fa00f1619d65 trunk/setup.py
+--- a/trunk/setup.py	Fri May 21 12:35:35 2010 +0200
++++ b/trunk/setup.py	Fri Sep 10 23:09:17 2010 -0400
+@@ -19,7 +19,7 @@
+ 
+ setup(
+     name='TracXMLRPC',
+-    version='1.1.0',
++    version='1.1.1',
+     license='BSD',
+     author='Alec Thomas',
+     author_email='alec@swapoff.org',
+diff -r fa00f1619d65 trunk/tracrpc/api.py
+--- a/trunk/tracrpc/api.py	Fri May 21 12:35:35 2010 +0200
++++ b/trunk/tracrpc/api.py	Fri Sep 10 23:09:17 2010 -0400
+@@ -98,6 +98,7 @@
+ 
+         method  (MANDATORY): target method name (e.g. 'ticket.get')
+         params  (OPTIONAL) : a tuple containing input positional arguments
++        kparams (OPTIONAL) : a dictionary containing input keyword arguments
+         headers (OPTIONAL) : if the protocol supports custom headers set 
+                               by the client, then this value SHOULD be a 
+                               dictionary binding `header name` to `value`. 
+@@ -191,10 +192,11 @@
+         self.namespace = provider.xmlrpc_namespace()
+         self.namespace_description = inspect.getdoc(provider)
+ 
+-    def __call__(self, req, args):
++    def __call__(self, req, args, kwds=None):
+         if self.permission:
+             req.perm.assert_permission(self.permission)
+-        result = self.callable(req, *args)
++        kwds = kwds or {}
++        result = self.callable(req, *args, **kwds)
+         # If result is null, return a zero
+         if result is None:
+             result = 0
+diff -r fa00f1619d65 trunk/tracrpc/tests/api.py
+--- a/trunk/tracrpc/tests/api.py	Fri May 21 12:35:35 2010 +0200
++++ b/trunk/tracrpc/tests/api.py	Fri Sep 10 23:09:17 2010 -0400
+@@ -5,8 +5,9 @@
+ (c) 2009      ::: www.CodeResort.com - BV Network AS (simon-code@bvnetwork.no)
+ """
+ 
+-import os
++import os.path
+ import unittest
++import urllib
+ import urllib2
+ 
+ from tracrpc.tests import rpc_testenv, TracRpcTestCase
+@@ -14,14 +15,21 @@
+ from tracrpc.api import IRPCProtocol
+ 
+ from trac.core import *
+-from trac.test import Mock
+ 
+ class ProtocolProviderTestCase(TracRpcTestCase):
+ 
+     def setUp(self):
+         TracRpcTestCase.setUp(self)
++        # Make a new plugin 
++        self.pluginfile = os.path.join(rpc_testenv.tracdir, 'plugins', 'DummyProvider.py')
+ 
+     def tearDown(self):
++        if os.path.exists(self.pluginfile):
++            # Clean up so that provider don't affect further tests
++            os.unlink(self.pluginfile)
++            rpc_testenv.restart()
++        # Release some memory ???
++        self.pluginfile = None 
+         TracRpcTestCase.tearDown(self)
+ 
+     def test_invalid_content_type(self):
+@@ -47,9 +55,7 @@
+             self.fail("Expected urllib2.HTTPError")
+         except urllib2.HTTPError, e:
+             self.assertEquals(e.code, 415)
+-        # Make a new plugin 
+-        provider = os.path.join(rpc_testenv.tracdir, 'plugins', 'DummyProvider.py')
+-        open(provider, 'w').write(
++        open(self.pluginfile, 'w').write(
+             "from trac.core import *\n"
+             "from tracrpc.api import *\n"
+             "class DummyProvider(Component):\n"
+@@ -70,23 +76,75 @@
+             "        response = 'Got a result!'\n"
+             "        req.send(response, rpcreq['mimetype'], 200)\n")
+         rpc_testenv.restart()
++        req = urllib2.Request(rpc_testenv.url_anon,
++                    headers={'Content-Type': 'application/x-tracrpc-test'})
++        resp = urllib2.urlopen(req)
++        self.assertEquals(200, resp.code)
++        self.assertEquals("Got a result!", resp.read())
++        self.assertEquals(resp.headers['Content-Type'],
++                              'application/x-tracrpc-test;charset=utf-8')
++
++    def test_valid_kwdargs(self):
++        # Confirm the request won't work before adding plugin
++        req = urllib2.Request(rpc_testenv.url_anon,
++                        headers={'Content-Type': 'application/x-tracrpc-test'},
++                        data="Fail! No RPC for application/x-tracrpc-test")
+         try:
+-            req = urllib2.Request(rpc_testenv.url_anon,
+-                        headers={'Content-Type': 'application/x-tracrpc-test'})
+             resp = urllib2.urlopen(req)
+-            self.assertEquals(200, resp.code)
+-            self.assertEquals("Got a result!", resp.read())
+-            self.assertEquals(resp.headers['Content-Type'],
+-                                  'application/x-tracrpc-test;charset=utf-8')
+-        finally:
+-            # Clean up so that provider don't affect further tests
+-            os.unlink(provider)
+-            rpc_testenv.restart()
++            self.fail("Expected urllib2.HTTPError")
++        except urllib2.HTTPError, e:
++            self.assertEquals(e.code, 415)
++        open(self.pluginfile, 'w').write(
++            "from trac.core import *\n"
++            "from trac.web.api import IRequestFilter\n"
++            "from tracrpc.api import *\n"
++            "from tracrpc.web_ui import *\n"
++            "class DummyProvider(Component):\n"
++            "    implements(IRPCProtocol, IRequestFilter)\n"
++            "    def pre_process_request(self, req, handler):\n"
++            "        if handler is RPCWeb(self.env) :\n"
++            "            # Avoid XSRF check \n"
++            "            self.log.debug('Tweaking XSRF protection')\n"
++            "            req.args['__FORM_TOKEN'] = req.form_token\n"
++            "            req.incookie['trac_form_token'] = "
++            "                             req.outcookie['trac_form_token']\n"
++            "        return handler\n"
++            "    def post_process_request(self, req, template, "
++            "                             data, content_type):\n"
++            "        return template, data, content_type\n"
++            "    def rpc_info(self):\n"
++            "        return ('TEST-RPC', 'No Docs!')\n"
++            "    def rpc_match(self):\n"
++            "        yield ('rpc', 'application/x-www-form-urlencoded')\n"
++            "        yield ('rpc', 'application/x-tracrpc-test')\n"
++            "    def parse_rpc_request(self, req, content_type):\n"
++            "        return dict(method=req.args.pop('_function', None),"
++            "                    kparams=dict([k, v] "
++            "                                   for k,v in req.args.items()"
++            "                                   if k[0] != '_'))\n"
++            "    def send_rpc_error(self, req, e):\n"
++            "        rpcreq = req.rpc\n"
++            "        req.send_error(None, template='', content_type=rpcreq['mimetype'],\n"
++            "                       status=500, env=None, data='Test failure ')\n"
++            "    def send_rpc_result(self, req, result):\n"
++            "        rpcreq = req.rpc\n"
++            "        response = 'Got a result!'\n"
++            "        req.send(response, 'text/plain', 200)\n")
++        rpc_testenv.restart()
++        req = urllib2.Request(rpc_testenv.url_anon,
++                    headers={'Content-Type': 'application/x-www-form-urlencoded'},
++                    data=urllib.urlencode(
++                            {'_function' : 'system.methodHelp',
++                            'method' : 'system.methodHelp',})
++                    )
++        resp = urllib2.urlopen(req)
++        self.assertEquals(200, resp.code)
++        self.assertEquals("Got a result!", resp.read())
++        self.assertEquals(resp.headers['Content-Type'],
++                              'text/plain;charset=utf-8')
+ 
+     def test_general_provider_error(self):
+-        # Make a new plugin and restart server
+-        provider = os.path.join(rpc_testenv.tracdir, 'plugins', 'DummyProvider.py')
+-        open(provider, 'w').write(
++        open(self.pluginfile, 'w').write(
+             "from trac.core import *\n"
+             "from tracrpc.api import *\n"
+             "class DummyProvider(Component):\n"
+@@ -118,10 +176,6 @@
+             self.assertEquals(500, e.code)
+             self.assertEquals("No good.", e.fp.read())
+             self.assertTrue(e.hdrs['Content-Type'].startswith('text/plain'))
+-        finally:
+-            # Clean up so that provider don't affect further tests
+-            os.unlink(provider)
+-            rpc_testenv.restart()
+ 
+ def test_suite():
+     return unittest.makeSuite(ProtocolProviderTestCase)
+diff -r fa00f1619d65 trunk/tracrpc/web_ui.py
+--- a/trunk/tracrpc/web_ui.py	Fri May 21 12:35:35 2010 +0200
++++ b/trunk/tracrpc/web_ui.py	Fri Sep 10 23:09:17 2010 -0400
+@@ -54,13 +54,13 @@
+                 if req.path_info in ['/%s' % p_path, '/login/%s' % p_path]:
+                     must_handle_request = True
+                     if content_type.startswith(p_type):
+-                        req.args['protocol'] = protocol
++                        req.rpc_protocol = protocol
+                         return True
+         # No protocol call, need to handle for docs or error if handled path
+         return must_handle_request
+ 
+     def process_request(self, req):
+-        protocol = req.args.get('protocol', None)
++        protocol = getattr(req, 'rpc_protocol', None)
+         content_type = req.get_header('Content-Type') or 'text/html'
+         if protocol:
+             # Perform the method call
+@@ -151,10 +151,11 @@
+             if method_name is None :
+                 raise ProtocolException('Missing method name')
+             args = rpcreq.get('params') or []
++            kwds = rpcreq.get('kparams') or {}
+             self.log.debug("RPC(%s) call by '%s' %s", proto_id, \
+                                               req.authname, method_name)
+             try :
+-                result = (XMLRPCSystem(self.env).get_method(method_name)(req, args))[0]
++                result = (XMLRPCSystem(self.env).get_method(method_name)(req, args, kwds))[0]
+                 if isinstance(result, GeneratorType):
+                     result = list(result)
+             except (RPCError, PermissionError, ResourceNotFound), e:

t0000/t0000-reuse-method-r7971.diff

+Reuse method object if used in parse_rpc_request
+
+diff -r c0729ae7dd57 trunk/tracrpc/api.py
+--- a/trunk/tracrpc/api.py	Fri Sep 10 23:09:17 2010 -0400
++++ b/trunk/tracrpc/api.py	Sat Sep 11 00:10:34 2010 -0400
+@@ -96,20 +96,25 @@
+         RPC subsystem, will be protocol-specific, and SHOULD NOT be 
+         needed in order to invoke a given method.
+ 
+-        method  (MANDATORY): target method name (e.g. 'ticket.get')
+-        params  (OPTIONAL) : a tuple containing input positional arguments
+-        kparams (OPTIONAL) : a dictionary containing input keyword arguments
+-        headers (OPTIONAL) : if the protocol supports custom headers set 
+-                              by the client, then this value SHOULD be a 
+-                              dictionary binding `header name` to `value`. 
+-                              However, protocol handlers as well as target 
+-                              RPC methods *MUST (SHOULD ?) NOT* rely on 
+-                              specific values assigned to a particular 
+-                              header in order to send a response back 
+-                              to the client.
+-        mimetype           : request MIME-type. This value will be set
+-                              by core RPC components after calling
+-                              this method so, please, ignore
++        method   (MANDATORY) : target method name (e.g. 'ticket.get')
++        methodobj (OPTIONAL) : target method object if already instantiated  
++                                inside `parse_rpc_request`. This may be 
++                                useful for protocolos using method 
++                                signatures to decode RPC messages (e.g. 
++                                static-typed RPC protocols).
++        params    (OPTIONAL) : a tuple containing input positional arguments
++        kparams   (OPTIONAL) : a dictionary containing input keyword arguments
++        headers   (OPTIONAL) : if the protocol supports custom headers set 
++                                by the client, then this value SHOULD be a 
++                                dictionary binding `header name` to `value`. 
++                                However, protocol handlers as well as target 
++                                RPC methods *MUST (SHOULD ?) NOT* rely on 
++                                specific values assigned to a particular 
++                                header in order to send a response back 
++                                to the client.
++        mimetype             : request MIME-type. This value will be set
++                                by core RPC components after calling
++                                this method so, please, ignore
+ 
+         If the request cannot be parsed this method *MUST* raise 
+         an instance of `ProtocolException` optionally wrapping another 
+diff -r c0729ae7dd57 trunk/tracrpc/tests/api.py
+--- a/trunk/tracrpc/tests/api.py	Fri Sep 10 23:09:17 2010 -0400
++++ b/trunk/tracrpc/tests/api.py	Sat Sep 11 00:10:34 2010 -0400
+@@ -143,6 +143,60 @@
+         self.assertEquals(resp.headers['Content-Type'],
+                               'text/plain;charset=utf-8')
+ 
++    def test_methodobj_reuse(self):
++        # Confirm the request won't work before adding plugin
++        req = urllib2.Request(rpc_testenv.url_anon,
++                        headers={'Content-Type': 'application/x-tracrpc-test'},
++                        data="Fail! No RPC for application/x-tracrpc-test")
++        try:
++            resp = urllib2.urlopen(req)
++            self.fail("Expected urllib2.HTTPError")
++        except urllib2.HTTPError, e:
++            self.assertEquals(e.code, 415)
++        open(self.pluginfile, 'w').write(
++            "from trac.core import *\n"
++            "from tracrpc.api import *\n"
++            "class MethodCallTracker(Method):\n"
++            "    callcount = 0\n"
++            "    def __call__(self, req, args, kwds=None):\n"
++            "        self.callcount+= 1\n"
++            "        return Method.__call__(self, req, args, kwds)\n"
++            "class DummyProvider(Component):\n"
++            "    implements(IRPCProtocol)\n"
++            "    def rpc_info(self):\n"
++            "        return ('TEST-RPC', 'No Docs!')\n"
++            "    def rpc_match(self):\n"
++            "        yield ('rpc', 'application/x-tracrpc-test')\n"
++            "    def parse_rpc_request(self, req, content_type):\n"
++            "        method = XMLRPCSystem(self.env).get_method("
++            "                                   'system.getAPIVersion')\n"
++            "        method.__class__ = MethodCallTracker\n"
++            "        return {'method' : 'system.getAPIVersion',"
++            "                   'methodobj' : method}\n"
++            "        \n"
++            "    def send_rpc_error(self, req, e):\n"
++            "        rpcreq = req.rpc\n"
++            "        req.send_error(None, template='', content_type=rpcreq['mimetype'],\n"
++            "                       status=500, env=None, data='Test failure ')\n"
++            "    def send_rpc_result(self, req, result):\n"
++            "        rpcreq = req.rpc\n"
++            "        method = req.rpc.get('methodobj')\n"
++            "        if method is None:"
++            "            response = 'Method object missing !'\n"
++            "        elif not hasattr(method, 'callcount'):\n"
++            "            response = 'Callcount missing'\n"
++            "        else:\n"
++            "            response = 'Call count ' + str(method.callcount)\n"
++            "        req.send(response, 'text/plain', 200)\n")
++        rpc_testenv.restart()
++        req = urllib2.Request(rpc_testenv.url_anon,
++                    headers={'Content-Type': 'application/x-tracrpc-test'})
++        resp = urllib2.urlopen(req)
++        self.assertEquals(200, resp.code)
++        self.assertEquals("Call count 1", resp.read())
++        self.assertEquals(resp.headers['Content-Type'],
++                              'text/plain;charset=utf-8')
++
+     def test_general_provider_error(self):
+         open(self.pluginfile, 'w').write(
+             "from trac.core import *\n"
+diff -r c0729ae7dd57 trunk/tracrpc/web_ui.py
+--- a/trunk/tracrpc/web_ui.py	Fri Sep 10 23:09:17 2010 -0400
++++ b/trunk/tracrpc/web_ui.py	Sat Sep 11 00:10:34 2010 -0400
+@@ -155,7 +155,9 @@
+             self.log.debug("RPC(%s) call by '%s' %s", proto_id, \
+                                               req.authname, method_name)
+             try :
+-                result = (XMLRPCSystem(self.env).get_method(method_name)(req, args, kwds))[0]
++                method = rpcreq.get('methodobj') or \
++                         XMLRPCSystem(self.env).get_method(method_name)
++                result = method(req, args, kwds)[0]
+                 if isinstance(result, GeneratorType):
+                     result = list(result)
+             except (RPCError, PermissionError, ResourceNotFound), e:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.