summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgnowgi <nagarjun@gnowledge.org>2012-08-01 10:34:19 +0530
committergnowgi <nagarjun@gnowledge.org>2012-08-01 10:34:19 +0530
commit3c6b52086767a59b83c51f88ea95f75d08f9f0fa (patch)
tree0520350067344c5b83d78269d6c4a49c6d6aa294
parent8477fb1c14f7a862b6433af5e0f3f9a3dd7220c4 (diff)
parent5200a05c2ec637b338bf5e7adb2ba3ec4626928c (diff)
downloadgnowsys-3c6b52086767a59b83c51f88ea95f75d08f9f0fa.tar.gz
Merge branch 'master' of git.sv.gnu.org:/srv/git/gnowsys
-rw-r--r--demo/django_xmlrpc/__init__.py44
-rw-r--r--demo/django_xmlrpc/decorators.py175
-rw-r--r--demo/django_xmlrpc/dispatcher.py76
-rw-r--r--demo/django_xmlrpc/locale/fr/LC_MESSAGES/django.mobin0 -> 1030 bytes
-rw-r--r--demo/django_xmlrpc/locale/fr/LC_MESSAGES/django.po49
-rw-r--r--demo/django_xmlrpc/templates/xmlrpc_get.html26
-rw-r--r--demo/django_xmlrpc/views.py163
7 files changed, 533 insertions, 0 deletions
diff --git a/demo/django_xmlrpc/__init__.py b/demo/django_xmlrpc/__init__.py
new file mode 100644
index 0000000..1d58f71
--- /dev/null
+++ b/demo/django_xmlrpc/__init__.py
@@ -0,0 +1,44 @@
+"""__init__ module for the django_xmlrpc package
+
+Authors::
+ Graham Binns
+ Julien Fache
+
+Credit must go to Brendan W. McAdams <brendan.mcadams@thewintergrp.com>, who
+posted the original SimpleXMLRPCDispatcher to the Django wiki:
+http://code.djangoproject.com/wiki/XML-RPC
+
+New BSD License
+===============
+Copyright (c) 2007, Graham Binns http://launchpad.net/~codedragon
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the <ORGANIZATION> nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+VERSION = (0, 1, 1)
+__version__ = '.'.join(map(str, VERSION))
+
+from views import xmlrpcdispatcher
diff --git a/demo/django_xmlrpc/decorators.py b/demo/django_xmlrpc/decorators.py
new file mode 100644
index 0000000..4218a4f
--- /dev/null
+++ b/demo/django_xmlrpc/decorators.py
@@ -0,0 +1,175 @@
+"""Offers decorators to make the use of django_xmlrpc a great deal simpler
+
+Authors::
+ Graham Binns,
+ Reza Mohammadi
+
+Credit must go to Brendan W. McAdams <brendan.mcadams@thewintergrp.com>, who
+posted the original SimpleXMLRPCDispatcher to the Django wiki:
+http://code.djangoproject.com/wiki/XML-RPC
+
+New BSD License
+===============
+Copyright (c) 2007, Graham Binns http://launchpad.net/~codedragon
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the <ORGANIZATION> nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+from xmlrpclib import Fault
+from django.contrib.auth import authenticate
+from django.utils.translation import gettext as _
+
+
+# Some constants for your pleasure
+#XXX: Any standardization?
+AUTHENTICATION_FAILED_CODE = 81
+PERMISSION_DENIED_CODE = 82
+
+
+class AuthenticationFailedException(Fault):
+ """An XML-RPC fault to be raised when a permission_required authentication
+ check fails
+
+ Author
+ """
+ def __init__(self):
+ Fault.__init__(self, AUTHENTICATION_FAILED_CODE,
+ _('Username and/or password is incorrect'))
+
+
+class PermissionDeniedException(Fault):
+ """An XML-RPC fault to be raised when a permission_required permission
+ check fails
+ """
+ def __init__(self):
+ Fault.__init__(self, PERMISSION_DENIED_CODE, _('Permission denied'))
+
+
+def xmlrpc_method(returns='string', args=None, name=None):
+ """Adds a signature to an XML-RPC function and register
+ it with the dispatcher.
+
+ returns
+ The return type of the function. This can either be a string
+ description (e.g. 'string') or a type (e.g. str, bool) etc.
+
+ args
+ A list of the types of the arguments that the function accepts. These
+ can be strings or types or a mixture of the two e.g.
+ [str, bool, 'string']
+ """
+ # Args should be a list
+ if args is None:
+ args = []
+
+ def _xmlrpc_func(func):
+ """Inner function for XML-RPC method decoration. Adds a signature to
+ the method passed to it.
+
+ func
+ The function to add the signature to
+ """
+ # If name is not None, register the method with the dispatcher.
+ from django_xmlrpc.views import xmlrpcdispatcher
+ if name is not None:
+ xmlrpcdispatcher.register_function(func, name)
+
+ # Add a signature to the function
+ func._xmlrpc_signature = {
+ 'returns': returns,
+ 'args': args
+ }
+ return func
+
+ return _xmlrpc_func
+
+xmlrpc_func = xmlrpc_method
+
+
+# Don't use this decorator when your service is going to be
+# available in an unencrpted/untrusted network.
+# Configure HTTPS transport for your web server.
+def permission_required(perm=None):
+ """Decorator for authentication. Uses Django's built in authentication
+ framework to provide authenticated-only and permission-related access
+ to XML-RPC methods
+
+ perm
+ The permission (as a string) that the user must hold to be able to
+ call the function that is decorated with permission_required.
+ """
+ def _dec(func):
+ """An inner decorator. Adds the lookup code for the permission passed
+ in the outer method to the function passed to it.
+
+ func
+ The function to add the permission check to
+ """
+ def __authenticated_call(username, password, *args):
+ """Inner inner decorator. Adds username and password parameters to
+ a given XML-RPC function for authentication and permission
+ checking purposes and modifies the method signature appropriately
+
+ username
+ The username used for authentication
+
+ password
+ The password used for authentication
+ """
+ try:
+ user = authenticate(username=username, password=password)
+ if not user:
+ raise AuthenticationFailedException
+ if perm and not user.has_perm(perm):
+ raise PermissionDeniedException
+ except AuthenticationFailedException:
+ raise
+ except PermissionDeniedException:
+ raise
+ except:
+ raise AuthenticationFailedException
+ return func(user, *args)
+
+ # Update the function's XML-RPC signature, if the method has one
+ if hasattr(func, '_xmlrpc_signature'):
+ sig = func._xmlrpc_signature
+
+ # We just stick two string args on the front of sign['args'] to
+ # represent username and password
+ sig['args'] = (['string'] * 2) + sig['args']
+ __authenticated_call._xmlrpc_signature = sig
+
+ # Update the function's docstring
+ if func.__doc__:
+ __authenticated_call.__doc__ = func.__doc__ + \
+ "\nNote: Authentication is required."""
+ if perm:
+ __authenticated_call.__doc__ += ' this function requires ' \
+ + '"%s" permission.' % perm
+
+ return __authenticated_call
+
+ return _dec
diff --git a/demo/django_xmlrpc/dispatcher.py b/demo/django_xmlrpc/dispatcher.py
new file mode 100644
index 0000000..f401457
--- /dev/null
+++ b/demo/django_xmlrpc/dispatcher.py
@@ -0,0 +1,76 @@
+"""Offers a simple XML-RPC dispatcher for django_xmlrpc
+
+Author::
+ Graham Binns
+
+Credit must go to Brendan W. McAdams <brendan.mcadams@thewintergrp.com>, who
+posted the original SimpleXMLRPCDispatcher to the Django wiki:
+http://code.djangoproject.com/wiki/XML-RPC
+
+New BSD License
+===============
+Copyright (c) 2007, Graham Binns http://launchpad.net/~codedragon
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the <ORGANIZATION> nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+from inspect import getargspec
+from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
+from django.conf import settings
+
+
+# If we need to debug, now we know
+DEBUG = hasattr(settings, 'XMLRPC_DEBUG') and settings.XMLRPC_DEBUG
+
+
+class DjangoXMLRPCDispatcher(SimpleXMLRPCDispatcher):
+ """A simple XML-RPC dispatcher for Django.
+
+ Subclassess SimpleXMLRPCServer.SimpleXMLRPCDispatcher for the purpose of
+ overriding certain built-in methods (it's nicer than monkey-patching them,
+ that's for sure).
+ """
+
+ def system_methodSignature(self, method):
+ """Returns the signature details for a specified method
+
+ method
+ The name of the XML-RPC method to get the details for
+ """
+ # See if we can find the method in our funcs dict
+ # TODO: Handle this better: We really should return something more
+ # formal than an AttributeError
+ func = self.funcs[method]
+
+ try:
+ sig = func._xmlrpc_signature
+ except:
+ sig = {
+ 'returns': 'string',
+ 'args': ['string' for arg in getargspec(func)[0]],
+ }
+
+ return [sig['returns']] + sig['args']
diff --git a/demo/django_xmlrpc/locale/fr/LC_MESSAGES/django.mo b/demo/django_xmlrpc/locale/fr/LC_MESSAGES/django.mo
new file mode 100644
index 0000000..06035ed
--- /dev/null
+++ b/demo/django_xmlrpc/locale/fr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/demo/django_xmlrpc/locale/fr/LC_MESSAGES/django.po b/demo/django_xmlrpc/locale/fr/LC_MESSAGES/django.po
new file mode 100644
index 0000000..091e086
--- /dev/null
+++ b/demo/django_xmlrpc/locale/fr/LC_MESSAGES/django.po
@@ -0,0 +1,49 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: django-xmlrpc\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-07-31 15:33+0200\n"
+"PO-Revision-Date: 2010-07-31 15:50+0100\n"
+"Last-Translator: Fantomas <Fantomas42@gmail.com>\n"
+"Language-Team: Fantomas42 <fantomas42@gmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: French\n"
+"X-Poedit-Country: FRANCE\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#: decorators.py:60
+msgid "Username and/or password is incorrect"
+msgstr "Nom d'utilisateur et/ou mot de passe incorrect"
+
+#: decorators.py:68
+msgid "Permission denied"
+msgstr "Permission refusée"
+
+#: templates/xmlrpc_get.html:4
+#: templates/xmlrpc_get.html.py:7
+msgid "XML-RPC Service"
+msgstr "Service XML-RPC"
+
+#: templates/xmlrpc_get.html:9
+msgid "You need to invoke this service using an XML-RPC Client."
+msgstr "Vous devez invoquer ce service en utilisant un client XML-RPC."
+
+#: templates/xmlrpc_get.html:11
+msgid "The following methods are available :"
+msgstr "Les méthodes suivantes sont disponibles :"
+
+#: templates/xmlrpc_get.html:17
+msgid "Types of argument"
+msgstr "Types d'argument"
+
+#: templates/xmlrpc_get.html:19
+msgid "Type of return"
+msgstr "Type de retour"
+
diff --git a/demo/django_xmlrpc/templates/xmlrpc_get.html b/demo/django_xmlrpc/templates/xmlrpc_get.html
new file mode 100644
index 0000000..4c9fdfc
--- /dev/null
+++ b/demo/django_xmlrpc/templates/xmlrpc_get.html
@@ -0,0 +1,26 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block title %}{% trans "XML-RPC Service" %}{% endblock %}
+
+{% block content %}
+<h2>{% trans "XML-RPC Service" %}</h2>
+
+<p>{% trans "You need to invoke this service using an XML-RPC Client." %}</p>
+
+<h3>{% trans "The following methods are available :" %}</h3>
+
+{% for m in methods %}
+<div class="functions">
+ <h4>{{ m.0 }}</h4>
+ <div class="function_desc">
+ <strong>{% trans "Types of argument" %}{{ m.1.args|length|pluralize }} :</strong> {{ m.1.args }}
+ <br />
+ <strong>{% trans "Type of return" %} :</strong> {{ m.1.returns }}
+ <br />
+ <pre class="function_doc">{{ m.2 }}</pre>
+ </div>
+</div>
+{% endfor %}
+{% endblock %}
+
diff --git a/demo/django_xmlrpc/views.py b/demo/django_xmlrpc/views.py
new file mode 100644
index 0000000..4824d46
--- /dev/null
+++ b/demo/django_xmlrpc/views.py
@@ -0,0 +1,163 @@
+"""Uses SimpleXMLRPCServer's SimpleXMLRPCDispatcher to serve XML-RPC requests
+
+Authors::
+ Graham Binns
+ Reza Mohammadi
+ Julien Fache
+
+Credit must go to Brendan W. McAdams <brendan.mcadams@thewintergrp.com>, who
+posted the original SimpleXMLRPCDispatcher to the Django wiki:
+http://code.djangoproject.com/wiki/XML-RPC
+
+New BSD License
+===============
+Copyright (c) 2007, Graham Binns http://launchpad.net/~codedragon
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the <ORGANIZATION> nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+import sys
+
+import django
+from django.conf import settings
+from django.template import RequestContext
+from django.shortcuts import render_to_response
+from django.core.exceptions import ImproperlyConfigured
+from django.http import HttpResponse, HttpResponseServerError
+try:
+ from django.views.decorators.csrf import csrf_exempt
+except ImportError:
+ from django.contrib.csrf.middleware import csrf_exempt
+
+from dispatcher import DjangoXMLRPCDispatcher
+from decorators import xmlrpc_func
+
+
+# We create a local DEBUG variable from the data in settings.
+DEBUG = hasattr(settings, 'XMLRPC_DEBUG') and settings.XMLRPC_DEBUG
+
+# Declare xmlrpcdispatcher correctly depending on our python version
+if sys.version_info[:3] >= (2, 5,):
+ xmlrpcdispatcher = DjangoXMLRPCDispatcher(allow_none=True, encoding=None)
+else:
+ xmlrpcdispatcher = DjangoXMLRPCDispatcher()
+
+
+def request_datas(request):
+ if django.VERSION[1] > 3:
+ return request.body
+ return request.raw_post_data
+
+
+@xmlrpc_func(returns='string', args=['string'])
+def test_xmlrpc(text):
+ """Simply returns the args passed to it as a string"""
+ return "Here's a response! %s" % str(text)
+
+
+@csrf_exempt
+def handle_xmlrpc(request):
+ """Handles XML-RPC requests. All XML-RPC calls should be forwarded here
+
+ request
+ The HttpRequest object that carries the XML-RPC call. If this is a
+ GET request, nothing will happen (we only accept POST requests)
+ """
+ if request.method == "POST":
+ if DEBUG:
+ print request_datas(request)
+ try:
+ response = HttpResponse(content_type='text/xml')
+ response.write(
+ xmlrpcdispatcher._marshaled_dispatch(request_datas(request)))
+ if DEBUG:
+ print response
+ return response
+ except:
+ return HttpResponseServerError()
+ else:
+ methods = xmlrpcdispatcher.system_listMethods()
+ method_list = []
+
+ for method in methods:
+ sig_ = xmlrpcdispatcher.system_methodSignature(method)
+ sig = {
+ 'returns': sig_[0],
+ 'args': ", ".join(sig_[1:]),
+ }
+
+ # this just reads your docblock, so fill it in!
+ method_help = xmlrpcdispatcher.system_methodHelp(method)
+
+ method_list.append((method, sig, method_help))
+
+ if hasattr(settings, 'XMLRPC_GET_TEMPLATE'):
+ # This behaviour is deprecated
+ if settings.DEBUG:
+ print "Use of settings.XMLRPC_GET_TEMPLATE is deprecated " \
+ + "Please update your code to use django_xmlrpc/templates"
+ template = settings.XMLRPC_GET_TEMPLATE
+ else:
+ template = 'xmlrpc_get.html'
+ return render_to_response(template, {'methods': method_list},
+ context_instance=RequestContext(request))
+
+
+# Load up any methods that have been registered with the server in settings
+if hasattr(settings, 'XMLRPC_METHODS'):
+ for path, name in settings.XMLRPC_METHODS:
+ # if "path" is actually a function, just add it without fuss
+ if callable(path):
+ xmlrpcdispatcher.register_function(path, name)
+ continue
+
+ # Otherwise we try and find something that we can call
+ i = path.rfind('.')
+ module, attr = path[:i], path[i + 1:]
+
+ try:
+ mod = __import__(module, globals(), locals(), [attr])
+ except ImportError, ex:
+ raise ImproperlyConfigured("Error registering XML-RPC method: " \
+ + "module %s can't be imported" % module)
+
+ try:
+ func = getattr(mod, attr)
+ except AttributeError:
+ raise ImproperlyConfigured('Error registering XML-RPC method: ' \
+ + 'module %s doesn\'t define a method "%s"' % (module, attr))
+
+ if not callable(func):
+ raise ImproperlyConfigured('Error registering XML-RPC method: ' \
+ + '"%s" is not callable in module %s' % (attr, module))
+
+ xmlrpcdispatcher.register_function(func, name)
+
+
+# Finally, register the introspection and multicall methods with the XML-RPC
+# namespace
+xmlrpcdispatcher.register_introspection_functions()
+xmlrpcdispatcher.register_multicall_functions()