Just for the note, if someone is interested, I've attached some module
based on 'repoze.bfg.xmlrpc' package to provide more convenient way
for creating XML-RPC services with repoze.bfg. Here it is, with
example in docstring.
"""Utilities for creating XML-RPC services.

This module extends 'repoze.bfg.xmlrpc' package. Simple usage:


    class MyService(Service):

        @method
        def my_method(self, a, b):
            return a + b

        class simple(Namespace):

            @method
            def another_method(self, a, b):
                return a * b

Class MyService is view class now and you can, for example, mount it with <rout
/> ZCML directive. Calss to service translates in the following way:

    - Call 'my_method' translates to MyService.my_method call.
    - call 'simple.my_method' translates to MyService.simple.another_method
      call.

If no method found for call, Fault object returns with
xmlrpclib.METHOD_NOT_FOUND code.
"""

import inspect
import xmlrpclib

from repoze.bfg.xmlrpc import parse_xmlrpc_request
from repoze.bfg.xmlrpc import xmlrpc_response

__all__ = ["Service",
           "Namespace",
           "method"]


class Namespace(object):
    """XML-RPC namespace object."""

    @classmethod
    def traverse(cls, parts):
        if not parts:
            raise xmlrpclib.Fault(
                xmlrpclib.METHOD_NOT_FOUND, "Method not found")

        current = parts.pop(0)
        if not hasattr(cls, current):
            raise xmlrpclib.Fault(
                xmlrpclib.METHOD_NOT_FOUND, "Method not found")

        next_obj = getattr(cls, current)
        if not hasattr(next_obj, "traverse"):
            raise xmlrpclib.Fault(
                xmlrpclib.METHOD_NOT_FOUND, "Method not found")

        return next_obj.traverse(parts)


class Service(Namespace):
    """XML-RPC service as view."""

    def __init__(self, context, request):
        self.context = context
        self.request = request

    def resolve(self, method):
        parts = method.split(".")
        return self.traverse(parts)

    def apply(self, handler, params):
        args, varargs, varkw, defaults = inspect.getargspec(handler)

        if varargs is None and not len(args) - 1 == len(params):
            raise xmlrpclib.Fault(
                xmlrpclib.INVALID_METHOD_PARAMS,
                "Params number must be equal to %d" % len(args))
        elif not varargs is None and len(params) < len(args):
            raise xmlrpclib.Fault(
                xmlrpclib.INVALID_METHOD_PARAMS,
                "Params number must be greater or equal to %d" % len(args))

        return handler(self, *params)

    def __call__(self):
        params, method = parse_xmlrpc_request(self.request)
        try:
            handler = self.resolve(method)
            value = self.apply(handler, params)
        except xmlrpclib.Fault, fault:
            value = fault
        return xmlrpc_response(value)


def method(func):
    def traverse(parts):
        if parts:
            raise xmlrpclib.Fault(
                xmlrpclib.METHOD_NOT_FOUND, "Method not found")
        return func
    func.traverse = traverse
    return func
_______________________________________________
Repoze-dev mailing list
Repoze-dev@lists.repoze.org
http://lists.repoze.org/listinfo/repoze-dev

Reply via email to