It look like there is no ready library with my requirements, so a ended up with own implementation:
class ApplicationError(Fault):
def __init__(self, exc_info):
Fault.__init__(self, xmlrpclib.APPLICATION_ERROR,
u'Application internal error')
class NotWellformedError(Fault):
def __init__(self, exc):
Fault.__init__(self, xmlrpclib.NOT_WELLFORMED_ERROR, str(exc))
class UnsupportedEncoding(Fault):
def __init__(self, exc):
Fault.__init__(self, xmlrpclib.UNSUPPORTED_ENCODING, str(exc))
# XXX INVALID_ENCODING_CHAR is masked by xmlrpclib, so the error code will be
# INVALID_XMLRPC.
class InvalidRequest(Fault):
def __init__(self, message):
ault.__init__(self, xmlrpclib.INVALID_XMLRPC, message)
class MethodNotFound(Fault):
def __init__(self, name):
Fault.__init__(self, xmlrpclib.METHOD_NOT_FOUND,
u'Method %r is not supported' % name)
class WrongMethodUsage(Fault):
def __init__(self, message):
Fault.__init__(self, xmlrpclib.INVALID_METHOD_PARAMS, message)
class WrongType(Fault):
def __init__(self, arg_name, type_name):
Fault.__init__(self, xmlrpclib.INVALID_METHOD_PARAMS,
u'Parameter %s must be %s' % (arg_name, type_name))
class XMLRPCDispatcher(SimpleXMLRPCDispatcher, XMLRPCDocGenerator):
server_name = server_title = 'Personalization center RPC interface'
server_documentation = 'Available methods'
def __init__(self, methods):
SimpleXMLRPCDispatcher.__init__(self, allow_none=True, encoding=None)
self.register_instance(methods)
self.register_multicall_functions()
#self.register_introspection_functions()
def _dispatch(self, method_name, args):
if self.funcs.has_key(method_name):
method = self.funcs[method_name]
else:
method = self.instance._getMethod(method_name)
arg_names, args_name, kwargs_name, defaults = \
inspect.getargspec(method)
assert arg_names[0]=='self'
arg_names = arg_names[1:]
n_args = len(args)
if not (args_name or defaults):
if n_args!=len(arg_names):
raise WrongMethodUsage(
u'Method %s takes exactly %d parameters (%d given)' % \
(method_name, len(arg_names), n_args))
else:
min_args = len(arg_names)-len(defaults)
if len(args)<min_args:
raise WrongMethodUsage(
u'Method %s requires at least %d parameters (%d given)' % \
(method_name, min_args, n_args))
if not args_name and n_args>len(arg_names):
raise WrongMethodUsage(
u'Method %s requires at most %d parameters (%d given)' % \
(method_name, len(arg_names), n_args))
try:
return method(*args)
except Fault:
raise
except:
logger.exception('Application internal error for %s%r',
method_name, args)
raise ApplicationError(sys.exc_info())
def dispatch(self, data):
try:
try:
args, method_name = xmlrpclib.loads(data)
except ExpatError, exc:
raise NotWellformedError(exc)
except LookupError, exc:
raise UnsupportedEncoding(exc)
except xmlrpclib.ResponseError:
raise InvalidRequest('Request structure is invalid')
method_name = method_name.encode('ascii', 'replace')
result = self._dispatch(method_name, args)
except Fault, exc:
logger.warning('Fault %s: %s', exc.faultCode, exc.faultString)
return xmlrpclib.dumps(exc)
else:
try:
return xmlrpclib.dumps((result,), methodresponse=1)
except:
logger.exception('Application internal error when marshalling'\
' result for %s%r', method_name, args)
return xmlrpclib.dumps(ApplicationError(sys.exc_info()))
class InterfaceMethods:
def _getMethod(self, name):
if name.startswith('_'):
raise MethodNotFound(name)
try:
method = getattr(self, name)
except AttributeError:
raise MethodNotFound(name)
if not inspect.ismethod(method):
raise MethodNotFound(name)
return method